| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 6 | kaklik | /*! \file stxetx.c \brief STX/ETX Packet Protocol Implementation Library. */ |
| 2 | //***************************************************************************** |
||
| 3 | // |
||
| 4 | // File Name : 'stxetx.c' |
||
| 5 | // Title : STX/ETX Packet Protocol Implementation Library |
||
| 6 | // Author : Pascal Stang - Copyright (C) 2002 |
||
| 7 | // Created : 10/9/2002 |
||
| 8 | // Revised : 6/30/2003 |
||
| 9 | // Version : 0.1 |
||
| 10 | // Target MCU : any |
||
| 11 | // Editor Tabs : 4 |
||
| 12 | // |
||
| 13 | // Description : This library provides a set of functions needed to send and |
||
| 14 | // receive STX/ETX packets. STX/ETX is a simple packet protocol that can |
||
| 15 | // be wrapped around user data for one or more of the following reasons: |
||
| 16 | // |
||
| 17 | // 1. packetization is needed |
||
| 18 | // - Using packets can be helpful if your data naturally forms |
||
| 19 | // little "bunches" or if different types of data must be sent |
||
| 20 | // over the same channel (a serial cable, for example). If your |
||
| 21 | // data forms "bunches", you can send user data inside STX/ETX |
||
| 22 | // packets with a predetermined structure, like an array of A/D |
||
| 23 | // conversion results. If you need a way to tell the receiver |
||
| 24 | // what kind of data you're sending, you can use the TYPE field |
||
| 25 | // in the STX/ETX packet. |
||
| 26 | // 2. error checking is needed |
||
| 27 | // - STX/ETX packets will add a checksum to your data. This |
||
| 28 | // allows the receiver to verify that data was received correctly |
||
| 29 | // and is error-free. Packets which are corrupted in transmission |
||
| 30 | // and fail the the checksum test are automatically discarded. |
||
| 31 | // Error checking is especially useful when the data transmission |
||
| 32 | // channel is unreliable or noisy (examples: radio, infrared, long |
||
| 33 | // cables, etc) |
||
| 34 | // |
||
| 35 | // STX/ETX packets have the following structure: |
||
| 36 | // |
||
| 37 | // [STX][status][type][length][user data...][checksum][ETX] |
||
| 38 | // |
||
| 39 | // All fields are 1 byte except for user data which may be 0-255 bytes. |
||
| 40 | // Uppercase fields are constant (STX=0x02, ETX=0x03), lowercase fields |
||
| 41 | // vary. The length field is the number of bytes in the user data area. |
||
| 42 | // The checksum is the 8-bit sum of all bytes between but not including |
||
| 43 | // STX/ETX. |
||
| 44 | // |
||
| 45 | // This code is distributed under the GNU Public License |
||
| 46 | // which can be found at http://www.gnu.org/licenses/gpl.txt |
||
| 47 | // |
||
| 48 | //***************************************************************************** |
||
| 49 | |||
| 50 | #include "global.h" |
||
| 51 | #include "stxetx.h" |
||
| 52 | //#include "rprintf.h" |
||
| 53 | |||
| 54 | // function pointer to data output routine |
||
| 55 | static void (*stxetxDataOut)(unsigned char data); |
||
| 56 | |||
| 57 | // received packet data buffer |
||
| 58 | unsigned char stxetxRxPacket[STXETX_MAXRXPACKETSIZE]; |
||
| 59 | |||
| 60 | // functions |
||
| 61 | |||
| 62 | |||
| 63 | // Initialize STX/ETX packet protocol library |
||
| 64 | void stxetxInit(void (*dataout_func)(unsigned char data)) |
||
| 65 | { |
||
| 66 | stxetxDataOut = dataout_func; |
||
| 67 | } |
||
| 68 | |||
| 69 | // Send/Create STX/ETX packet |
||
| 70 | void stxetxSend(unsigned char status, unsigned char type, unsigned char datalength, unsigned char* dataptr) |
||
| 71 | { |
||
| 72 | unsigned char checksum = 0; |
||
| 73 | unsigned short i; |
||
| 74 | |||
| 75 | // write packet header |
||
| 76 | stxetxDataOut(STX); |
||
| 77 | stxetxDataOut(status); |
||
| 78 | stxetxDataOut(type); |
||
| 79 | stxetxDataOut(datalength); |
||
| 80 | // update checksum |
||
| 81 | checksum += status + type + datalength; |
||
| 82 | // copy data into packet |
||
| 83 | for(i = 0; i < datalength; i++) |
||
| 84 | { |
||
| 85 | stxetxDataOut(*dataptr); |
||
| 86 | checksum += *dataptr; |
||
| 87 | dataptr++; |
||
| 88 | } |
||
| 89 | // write packet trailer |
||
| 90 | stxetxDataOut(checksum); |
||
| 91 | stxetxDataOut(ETX); |
||
| 92 | } |
||
| 93 | |||
| 94 | // process buffer containing STX/ETX packets |
||
| 95 | unsigned char stxetxProcess(cBuffer* rxBuffer) |
||
| 96 | { |
||
| 97 | unsigned char foundpacket = FALSE; |
||
| 98 | unsigned short i; |
||
| 99 | unsigned char length, checksum; |
||
| 100 | //unsigned char type; |
||
| 101 | |||
| 102 | // process the buffer |
||
| 103 | // go through buffer looking for packets |
||
| 104 | // the STX must be located at least STXETX_HEADERLENGTH+STXETX_TRAILERLENGTH from end |
||
| 105 | // otherwise we must not have a complete packet |
||
| 106 | while( rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+(u16)STXETX_TRAILERLENGTH) ) |
||
| 107 | { |
||
| 108 | // look for a potential start of packet |
||
| 109 | if(bufferGetAtIndex(rxBuffer, 0) == STX) |
||
| 110 | { |
||
| 111 | // if this is a start, then get the length |
||
| 112 | length = bufferGetAtIndex(rxBuffer, STXETX_LENGTHOFFSET); |
||
| 113 | |||
| 114 | // now we must have at least STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH in buffer to continue |
||
| 115 | if(rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH)) |
||
| 116 | { |
||
| 117 | // check to see if ETX is in the right position |
||
| 118 | if(bufferGetAtIndex(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH-1) == ETX) |
||
| 119 | { |
||
| 120 | // found potential packet |
||
| 121 | // test checksum |
||
| 122 | checksum = 0; |
||
| 123 | // sum data between STX and ETX, not including checksum itself |
||
| 124 | // (u16) casting needed to avoid unsigned/signed mismatch |
||
| 125 | for(i = 0; i<((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH-(u16)STXETX_NOETXSTXCHECKSUM); i++) |
||
| 126 | { |
||
| 127 | checksum += bufferGetAtIndex(rxBuffer, i+STXETX_STATUSOFFSET); |
||
| 128 | } |
||
| 129 | // compare checksums |
||
| 130 | if(checksum == bufferGetAtIndex(rxBuffer, STXETX_CHECKSUMOFFSET+length)) |
||
| 131 | { |
||
| 132 | //we have a packet! |
||
| 133 | foundpacket = TRUE; |
||
| 134 | |||
| 135 | // copy data to buffer |
||
| 136 | // (don't copy STX, ETX, or CHECKSUM) |
||
| 137 | for(i = 0; i < ((u16)STXETX_HEADERLENGTH+length-1); i++) |
||
| 138 | { |
||
| 139 | stxetxRxPacket[i] = bufferGetAtIndex(rxBuffer, i+1); |
||
| 140 | } |
||
| 141 | |||
| 142 | // debug |
||
| 143 | //rprintf("STXETX Received packet type: 0x%x\n", bufferGetAtIndex(rxBuffer, STXETX_TYPEOFFSET)); |
||
| 144 | |||
| 145 | // dump this packet from the |
||
| 146 | bufferDumpFromFront(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH); |
||
| 147 | |||
| 148 | // done with this processing session |
||
| 149 | break; |
||
| 150 | } |
||
| 151 | else |
||
| 152 | { |
||
| 153 | // checksum bad |
||
| 154 | //rprintf("STXETX Received packet with bad checksum\r\n"); |
||
| 155 | // for now, we dump these |
||
| 156 | // dump this STX |
||
| 157 | bufferGetFromFront(rxBuffer); |
||
| 158 | } |
||
| 159 | } |
||
| 160 | else |
||
| 161 | { |
||
| 162 | // no ETX or ETX in wrong position |
||
| 163 | // dump this STX |
||
| 164 | bufferGetFromFront(rxBuffer); |
||
| 165 | } |
||
| 166 | } |
||
| 167 | else |
||
| 168 | { |
||
| 169 | // not enough data in buffer to decode pending packet |
||
| 170 | // wait until next time |
||
| 171 | break; |
||
| 172 | } |
||
| 173 | } |
||
| 174 | else |
||
| 175 | { |
||
| 176 | // this is not a start, dump it |
||
| 177 | bufferGetFromFront(rxBuffer); |
||
| 178 | } |
||
| 179 | } |
||
| 180 | |||
| 181 | // check if receive buffer is full with no packets decoding |
||
| 182 | // (ie. deadlocked on garbage data or packet that exceeds buffer size) |
||
| 183 | if(!bufferIsNotFull(rxBuffer)) |
||
| 184 | { |
||
| 185 | // dump receive buffer contents to relieve deadlock |
||
| 186 | bufferFlush(rxBuffer); |
||
| 187 | } |
||
| 188 | |||
| 189 | return foundpacket; |
||
| 190 | } |
||
| 191 | |||
| 192 | unsigned char stxetxGetRxPacketStatus(void) |
||
| 193 | { |
||
| 194 | // return the packet's status |
||
| 195 | // (subtract 1 from the offset because the STX has already been discarded) |
||
| 196 | return stxetxRxPacket[STXETX_STATUSOFFSET-1]; |
||
| 197 | } |
||
| 198 | |||
| 199 | unsigned char stxetxGetRxPacketType(void) |
||
| 200 | { |
||
| 201 | // return the packet's type |
||
| 202 | // (subtract 1 from the offset because the STX has already been discarded) |
||
| 203 | return stxetxRxPacket[STXETX_TYPEOFFSET-1]; |
||
| 204 | } |
||
| 205 | |||
| 206 | unsigned char stxetxGetRxPacketDatalength(void) |
||
| 207 | { |
||
| 208 | // return the packet's datalength |
||
| 209 | // (subtract 1 from the offset because the STX has already been discarded) |
||
| 210 | return stxetxRxPacket[STXETX_LENGTHOFFSET-1]; |
||
| 211 | } |
||
| 212 | |||
| 213 | unsigned char* stxetxGetRxPacketData(void) |
||
| 214 | { |
||
| 215 | // return a pointer to the packet's data payload |
||
| 216 | // (subtract 1 from the offset because the STX has already been discarded) |
||
| 217 | return stxetxRxPacket+STXETX_DATAOFFSET-1; |
||
| 218 | } |
Powered by WebSVN v2.8.3