SerialComm/SIPR/Ideas (2005-11-23 00:07:47)

How it is done in proven standard solutions

In an ideal world 2 layers are necessary. This (separation of 2 layers) is something that [modbus.org] [modbus protocol] gets perfectly right. No wonder modbus is the absolute market-leader protocol for the exact task that we are inventing our own for.

application layer is responsible for content dispatch (appPDU: which byte means what?)

network layer is responsible for framing and reliable communications (CRC)

Note that modbus solves some existing problems out of the box, in a standard way:

modbus shortcomings

The "wired in CRC", which is the violation of the 2-layer design (application + network, see above) is not a performance issue. It becomes a maintenance issue when we start support for CAN or MMC flash or other data carrier besides serial link. No question that we can solve it than though.

Comments From Alexander Guy:

I think that byte stuffing isn't something that should be overlooked. It's easy to implement, and with it and frame 'flags', frame synchronization becomes trivial. Rather than counting bytes based on the alleged size of the frame, the frame continues until the next flag is hit. If no flag is hit before the maximum buffer size is reached, it can be assumed that the frame was invalid and frame reading can be reset until the next flag.

A rough implementation of an input function is as follows. This is the same HDLC-like framing that PPP uses over 8-bit async serial links:

\\n
#define BYTE_FLAG    0x7e 
#define BYTE_ESCAPE  0x7d 
 
#define MAX_SIZE 80 
 
 
struct { 
        char rbuf[MAX_SIZE]; 
        int ridx; 
        enum { INVALID, NORMAL, ESCAPE } rstate; 
} commstate; 
 
void 
input_byte(char input) 
{ 
        int idx = commstate.ridx; 
 
        if (input == BYTE_FLAG) { 
                if ((commstate.rstate == NORMAL) && (idx > 0)) { 
                        /* XXX - Verify Checksum and Process Message Here */  
               } 
 
                commstate.ridx = 0; 
                commstate.rstate = NORMAL; 
 
                return; 
        } 
 
        if (commstate.rstate == INVALID) 
                return; 
 
        if (input == BYTE_ESCAPE) { 
                commstate.rstate = ESCAPE;       
                return; 
        } 
 
        if (commstate.rstate == ESCAPE) { 
                input ^= 0x20; 
                commstate.rstate = NORMAL; 
        } 
 
        commstate.rbuf[idx] = input; 
 
        /* XXX - You Can Update Checksum Here */ 
 
        idx++; 
 
        if (idx >= MAX_SIZE) { 
                idx = 0; 
                commstate.rstate = INVALID; 
        } 
 
        commstate.ridx = idx; 
 
        return; 
} 

See also