SerialComm/SIPR/Ideas (2005-11-23 18:41:54)

Lately there has been much thought about networking

Since we must support CAN in very near future, some design decisions are simply answered for us (fortunately without any bad compromise). Therefore the device and information addressing is basically solved. Framing is almost trivial.

Main work targets the problem that arises only when using UART instead of real CAN:

Discussion moved to http://wiki.x-dsl.hu/cgi-bin/w/telemetry.cgi?UartPacketComm . Discussion below is history

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.

Alexander Guy thinks 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 (and verifying checksum) 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