diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..a9fea54 --- /dev/null +++ b/src/net.h @@ -0,0 +1,200 @@ +#ifndef _NET_H +#define _NET_H +#if HAS_NET > 0 +/* + ==== Communication Ports ==== + Link: Connection between ports + + Logical/virtual ports are buffered async. IO devices: + - External access via buffers only, + - Internal reading and writing from physical serial channels in the background (via main IO loop). + Ports and links between ports operate message-based. VM send messages to port. + Serial Channel -> PortReceiver(L) -> AllocateMessage(M) -> Process(M) -> FinalizeMessage(M= + VM IN/OUT API via generic INBYTE/OUTBYTE passed to port InByte(M),OutByte(M) + Outgoing messages: PortOutByte -> AllocateMessage(M) -> PortRoute(P) + INBYTE/OUTBYTE: IO multiplexer: Real file desciptor IO and logical port access …(via port structures and buffers) +*/ + +#ifndef PORTBUFFERSIZE +#define PORTBUFFERSIZE 2048 +#endif + +#ifndef EOM +#define EOM '\n' +#endif + +// Maximal number of ports +#ifndef NUMPORTS +#define NUMPORTS 4 +#endif + +#ifndef NETTIMEOUT +// rx timeout in ms +#define NETTIMEOUT 200 +#endif + +#define RINGDECR(index,size) index=(index==0?size-1:index-1) +#define RINGINCR(index,size) index=((index+1)%size) +#define RINGLEN(start,end,size) end 0 + +/* + Message handled by ports (input as well as output), administrative message header stored in rx/tx buffers +*/ +typedef struct { + index_t type; //message_type_t + index_t start; + index_t end; // wrap around in ring buffer? + index_t port; +} message_t; + + +/* + Network module with extended routing, ingoing (rx) and outgoing (tx) messages are buffered. +*/ + + +/* + Network control message (prefix of another message or stand-alone) + It is directly mappend in rx/tx buffer (parsed in place( +*/ + +typedef enum { + NCMUP = 'u', + NCMDOWN = 'd', + NCMMULTICAST = 'm', + NCMUNICAST = '1', + NCMID = 'i', + NCMDELTA = 'D' +} control_type_t; + +/* + (Optional) Message prefix for routing + @u@ | @u,hopx,hopy@ + @d@ | @d,hopx,hopy@ + @D,dx,dy,dx0,dy0@ + @m,range@ + Some messages have default routing strategies: + !! => Up + [] => Down (always broadcast) + %% => Down (always broadcast) + ## => Up +*/ +#ifndef MAXNCMARGS +#define MAXNCMARGS 8 +#endif + +typedef struct __attribute__((packed)) { + char type; // control_type_t + int8_t narg; // number of args + int8_t args[MAXNCMARGS]; // dynamic array +} message_control_t; + +typedef struct { + /* linear buffer */ + char *rxBuffer; + /* ring buffer */ + char *txBuffer; + index_t rxBottom; + index_t rxTop; // points to next free message block + index_t txBottom; + index_t txTop; + char busy; + index_t rd; // unix: fd + index_t wr; // unix: fd + port_state_t state; // message parser state + message_t *rxCurrent; // currently processed (non-fixed) message + message_t *txCurrent; + int (**handlers)(); // int foo(port_t *,message_t *) + index_t index; +} port_t; + +extern port_t **Ports; +message_t *CurrentInputMessage[NUMPORTS]; // for PLX ? operator +message_t *CurrentOutputMessage[NUMPORTS]; // for PLX ! operator +int PortsDown[NUMPORTS],PortsUp[NUMPORTS]; // keep track for up and down ports + +/* if buffer==NULL the rx+tx buffer is allocated, else buffer=char[NUMPORTS*PORTBUFFERSIZE] */ +void NetInit(int (**handlers)(),port_t **ports, char *buffer); + +message_t *AllocateMessage(port_t *P,message_type_t t); +message_t *FinalizeMessage(message_t *m); +void FreeMessage(message_t *m); +#if HAS_NET_ROUTING > 0 +int NetControlMessage(port_t *P, char type,index_t a, index_t b); +#endif +int PortReceiver(port_t *L); +/* + Read one byte from message +*/ +int PortInByte(message_t *m); +/* + Add one byte to message +*/ +int PortOutByte(message_t *m, char ch); + +void PrintPortMessages(port_t *L); +#else /* ! HAS_NET_ROUTING: NET0 */ +/* net0: only 1 port */ +typedef struct { + /* shared buffer=[rxBuffer,inputBuffer] */ + /* linear buffer, grows to top */ + char *rxBuffer; // all messages not passed to the VM input layer + /* circular buffer, grows to bottom, wrap around at PORTBUFFERSIZE/2, reset to high water if top==bottom */ + char *inputBuffer; // all messages passed to the VM input layer + index_t rxBottom; + index_t rxTop; // points to next free byte + index_t rxStart; // begin of current message in buffer (rx/input) + int rxLast; // timestamp of last received char + index_t inputBottom; + index_t inputTop; // points to next free byte + message_type_t rxCurrent; // current received message + + char busy; + index_t rd; // unix: fd + index_t wr; // unix: fd + port_state_t rxState; // receiver message parser state + int (**handlers)(); // int foo(port_t *,message_type_t) +} port_t; + +extern port_t *Port; +/* if buffer==NULL the rx+in buffer is allocated, else buffer=char[NUMPORTS*PORTBUFFERSIZE] */ +void NetInit(int (**handlers)(),port_t *port, char *buffer); +int PortAvailByte(int id); +int PortInByte(int id); +int PortOutByte(int od, char ch); +int PortReceiver(); +#endif +#endif /* !HAS_NET */ +#endif /* _NET_H */