SerialComm/SIPR/Ideas (2005-12-20 11:14:21)

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.

Advantages of byte stuffing:

Disadvantage:

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; 
} 

2005.12.20 ESjaavik

The ECU can (and should) be the master. When you hook up the PC it checks and find that the new unit is a HMI (Human Machine Interface) unit, and ask it "What do you want from me?". Then the PC can give it commands in the reply telegram. The ECU remains the master, and as such have a better control that the HMI task is not interfering with ECU task(s). An HMI is actually by nature a peripheral task and not a control task, although we as humans do not like this way of thinking. So in industry where machine function goes before human emotion, the HMI is slave. I can supply documentation for the Cmd/Reply structure for such an industrial status+control panel if you want.


See also