Mon 16 Mar 11:09:06 CET 2026
This commit is contained in:
parent
5f8d72f1d2
commit
4b4274f9bd
245
src/net0.c
Normal file
245
src/net0.c
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
Very simple network module w/o routing and no output buffering supporting only one port per node.
|
||||
Only one message can be received (MSGCOMMAND, MSGPROGRAMx, MSGUSER) and is handled directly.
|
||||
Two input buffers: Code & Data
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "net.h"
|
||||
#include "printf.h"
|
||||
#include "log.h"
|
||||
#include "context.h"
|
||||
#include "event.h"
|
||||
|
||||
/* IO multiplexer provided by host application */
|
||||
extern int availbyte(int fd);
|
||||
extern char inbyte(int fd);
|
||||
extern int outbyte(int fd,char x);
|
||||
|
||||
#if HAS_NET>0 && HAS_NET_ROUTING == 0
|
||||
port_t *Port=NULL;
|
||||
|
||||
void NetInit(int (**handlers)(),port_t *P, char *buffer) {
|
||||
// shared buffer [rx|inp]
|
||||
if (!buffer) buffer = (char *)MEMALLOC(PORTRXBUFFERSIZE);
|
||||
// only one port, this buffer is shared by rx and input buffers
|
||||
if (!P) P = (port_t *)MEMALLOC(sizeof(port_t));
|
||||
// no tx buffer
|
||||
Port=P;
|
||||
memset(P,0,sizeof(port_t));
|
||||
log(LOGINFO,"NetInit P=$%x B=$%x\n",P,buffer);
|
||||
P->rxState=LSTART;
|
||||
if (handlers) {
|
||||
P->handlers=handlers;
|
||||
}
|
||||
P->rxBuffer=&buffer[0]; // low-water
|
||||
P->inputBuffer=&buffer[PORTRXBUFFERSIZE/2]; // high-water
|
||||
P->inputBottom=P->inputTop=PORTRXBUFFERSIZE/2-1;
|
||||
}
|
||||
|
||||
int PortReceiver() {
|
||||
int n=0;
|
||||
message_type_t t;
|
||||
port_t *P=Port;
|
||||
// Timeout handling
|
||||
int tm=MILLIS();
|
||||
if (P->rxCurrent && tm>P->rxLast+NETTIMEOUT) {
|
||||
// reset receiver
|
||||
P->rxTop=P->rxStart;
|
||||
P->rxState=LSTART;
|
||||
P->rxCurrent=0;
|
||||
}
|
||||
while (availbyte(P->rd)>0) {
|
||||
char ch=inbyte(P->rd);
|
||||
n++;
|
||||
#if DEBUG > 0
|
||||
log(LOGDEBUG1,"PortReceiver%d State=%d type=%d rx[%d:%d] '%c'\n",0,
|
||||
P->rxState,P->rxCurrent,P->rxTop,P->inputTop,ch=='\n'?'^':ch);
|
||||
#endif
|
||||
if (ch==0) return -1;
|
||||
switch (P->rxState) {
|
||||
case LSTART:
|
||||
t=-1;
|
||||
switch (ch) {
|
||||
case ']': t=MSGCOMMAND; break;
|
||||
case '[': t=MSGPROGRAM;
|
||||
// stop current program in context 0 (if any is running)?
|
||||
P->inputBottom=P->inputTop=PORTRXBUFFERSIZE/2-1; /*new prog: get full rx buffer space, stop VM */
|
||||
break;
|
||||
case '!': t=MSGDATA; break;
|
||||
case '$': t=MSGUSER; break;
|
||||
case '@': t=MSGNET; break;
|
||||
case '%': t=MSGEVENT; break;
|
||||
case '#': t=MSGCONSOLE; break;
|
||||
}
|
||||
if (t>=0) {
|
||||
P->rxCurrent=t;
|
||||
P->rxState=LPARSING;
|
||||
P->rxStart=P->rxTop;
|
||||
}
|
||||
break;
|
||||
case LPARSING:
|
||||
switch (ch) {
|
||||
case '[':
|
||||
switch (P->rxCurrent) {
|
||||
case MSGPROGRAM:
|
||||
if (P->rxBottom==P->rxTop) {
|
||||
// [[
|
||||
P->rxCurrent=MSGPROGRAMPART;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MSGCOMMAND:
|
||||
P->rxState=LEND;
|
||||
continue;
|
||||
}
|
||||
case ']':
|
||||
switch (P->rxCurrent) {
|
||||
case MSGPROGRAM:
|
||||
P->rxState=LEND;
|
||||
continue;
|
||||
break;
|
||||
case MSGPROGRAMPART:
|
||||
P->rxState=LPREEND; // wait for second ]
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
case '$':
|
||||
switch (P->rxCurrent) {
|
||||
case MSGUSER:
|
||||
P->rxState=LEND;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
switch (P->rxCurrent) {
|
||||
case MSGEVENT:
|
||||
P->rxState=LEND;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// store message body
|
||||
switch (P->rxCurrent) {
|
||||
case MSGUSER:
|
||||
// cyclic downwards
|
||||
P->inputBuffer[P->inputTop]=ch;
|
||||
RINGDECR(P->inputTop,PORTRXBUFFERSIZE/2);
|
||||
break;
|
||||
default:
|
||||
// all others (linear upwards, no ring logic needed)
|
||||
P->rxBuffer[P->rxTop++]=ch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LPREEND:
|
||||
// check for second delimiter char
|
||||
switch (P->rxCurrent) {
|
||||
case MSGPROGRAMPART:
|
||||
if (ch==']') {
|
||||
P->rxState=LEND;
|
||||
} else {
|
||||
// Error, reset receiver
|
||||
P->rxTop=P->rxStart;
|
||||
P->rxState=LSTART;
|
||||
P->rxCurrent=0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case LEND:
|
||||
Notify(NOTIFYMSG,P->rxCurrent,(void*)&P);
|
||||
if (ch!='\n') {
|
||||
// Error, reset receiver
|
||||
#if DEBUG > 0
|
||||
log(LOGDEBUG1,"PortReceiver%d No LEND msg(%d)\n",0,P->rxCurrent);
|
||||
#endif
|
||||
P->rxTop=P->rxStart;
|
||||
P->rxState=LSTART;
|
||||
P->rxCurrent=0;
|
||||
continue;
|
||||
} else {
|
||||
// process now, call handler if existing!
|
||||
switch (P->rxCurrent) {
|
||||
case MSGUSER:
|
||||
P->inputBuffer[P->inputTop]=ch;
|
||||
RINGDECR(P->inputTop,PORTRXBUFFERSIZE/2);
|
||||
break;
|
||||
default:
|
||||
P->rxBuffer[P->rxTop++]=0;
|
||||
}
|
||||
#if DEBUG > 0
|
||||
log(LOGDEBUG1,"PortReceiver%d LEND msg(%d)\n",0,P->rxCurrent);
|
||||
#endif
|
||||
if (P->handlers && P->handlers[P->rxCurrent])
|
||||
P->handlers[P->rxCurrent](P,P->rxCurrent);
|
||||
else {
|
||||
// reset buffer pointer
|
||||
P->rxTop=P->rxStart;
|
||||
log(LOGINFO,"PortReceiver%d No Handler for (%d)\n",0,P->rxCurrent);
|
||||
}
|
||||
}
|
||||
switch (P->rxCurrent) {
|
||||
case MSGUSER:
|
||||
// processed by VM program, ring buffer pointers are modified by ? operations (or VM reset)
|
||||
break;
|
||||
default:
|
||||
// store and process; TODO: delayed processing (e.g., incremental chunk compilations)
|
||||
// all others, already processed by handler
|
||||
P->rxStart=P->rxTop; // =P->rxBottom doen in handler
|
||||
break;
|
||||
}
|
||||
P->rxState=LSTART;
|
||||
P->rxCurrent=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n) P->rxLast=tm;
|
||||
return 0;
|
||||
}
|
||||
/***********
|
||||
VM program API
|
||||
***********/
|
||||
|
||||
/*
|
||||
Read one byte from input buffer redirected from (host) inbyte(-id) via (VM) INBYTE(id)
|
||||
*/
|
||||
int PortAvailByte(int id) {
|
||||
port_t *P=Port;
|
||||
#if DEBUG > 0
|
||||
log(LOGDEBUG2,"PortAvailByte(%d) bot=%d top=%d\n",id,P->inputBottom,P->inputTop);
|
||||
#endif
|
||||
return P->inputBottom!=P->inputTop;
|
||||
}
|
||||
|
||||
int PortInByte(int id) {
|
||||
port_t *P=Port;
|
||||
#if DEBUG > 0
|
||||
log(LOGDEBUG2,"PortInByte(%d) bot=%d top=%d byte='%c'\n",id,P->inputBottom,P->inputTop,P->inputBuffer[P->inputBottom]);
|
||||
#endif
|
||||
if (P->inputBottom==P->inputTop) return -1;
|
||||
char b=P->inputBuffer[P->inputBottom];
|
||||
RINGDECR(P->inputBottom,PORTRXBUFFERSIZE/2);
|
||||
if (P->inputBuffer[P->inputBottom]==EOM) {
|
||||
// skip EOM, point to next input message
|
||||
RINGDECR(P->inputBottom,PORTRXBUFFERSIZE/2);
|
||||
//if (P->inputBottom==P->inputTop)
|
||||
// P->inputBottom=P->inputTop=PORTRXBUFFERSIZE/2-1;
|
||||
// input buffer is empty, reset pointers to high water position
|
||||
// else
|
||||
}
|
||||
return b;
|
||||
}
|
||||
/*
|
||||
Write one byte to output port; either directly or buffered in tx buffer if port is busy (?can this happen here?);
|
||||
*/
|
||||
int PortOutByte(int od, char ch) {
|
||||
port_t *P=Port;
|
||||
outbyte(Port->wr,ch);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user