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