00001 /*! \file stxetx.c \brief STX/ETX Packet Protocol Implementation Library. */ 00002 //***************************************************************************** 00003 // 00004 // File Name : 'stxetx.c' 00005 // Title : STX/ETX Packet Protocol Implementation Library 00006 // Author : Pascal Stang - Copyright (C) 2002 00007 // Created : 10/9/2002 00008 // Revised : 6/30/2003 00009 // Version : 0.1 00010 // Target MCU : any 00011 // Editor Tabs : 4 00012 // 00013 // Description : This library provides a set of functions needed to send and 00014 // receive STX/ETX packets. STX/ETX is a simple packet protocol that can 00015 // be wrapped around user data for one or more of the following reasons: 00016 // 00017 // 1. packetization is needed 00018 // - Using packets can be helpful if your data naturally forms 00019 // little "bunches" or if different types of data must be sent 00020 // over the same channel (a serial cable, for example). If your 00021 // data forms "bunches", you can send user data inside STX/ETX 00022 // packets with a predetermined structure, like an array of A/D 00023 // conversion results. If you need a way to tell the receiver 00024 // what kind of data you're sending, you can use the TYPE field 00025 // in the STX/ETX packet. 00026 // 2. error checking is needed 00027 // - STX/ETX packets will add a checksum to your data. This 00028 // allows the receiver to verify that data was received correctly 00029 // and is error-free. Packets which are corrupted in transmission 00030 // and fail the the checksum test are automatically discarded. 00031 // Error checking is especially useful when the data transmission 00032 // channel is unreliable or noisy (examples: radio, infrared, long 00033 // cables, etc) 00034 // 00035 // STX/ETX packets have the following structure: 00036 // 00037 // [STX][status][type][length][user data...][checksum][ETX] 00038 // 00039 // All fields are 1 byte except for user data which may be 0-255 bytes. 00040 // Uppercase fields are constant (STX=0x02, ETX=0x03), lowercase fields 00041 // vary. The length field is the number of bytes in the user data area. 00042 // The checksum is the 8-bit sum of all bytes between but not including 00043 // STX/ETX. 00044 // 00045 // This code is distributed under the GNU Public License 00046 // which can be found at http://www.gnu.org/licenses/gpl.txt 00047 // 00048 //***************************************************************************** 00049 00050 #include "global.h" 00051 #include "stxetx.h" 00052 //#include "rprintf.h" 00053 00054 // function pointer to data output routine 00055 static void (*stxetxDataOut)(unsigned char data); 00056 00057 // received packet data buffer 00058 unsigned char stxetxRxPacket[STXETX_MAXRXPACKETSIZE]; 00059 00060 // functions 00061 00062 00063 // Initialize STX/ETX packet protocol library 00064 void stxetxInit(void (*dataout_func)(unsigned char data)) 00065 { 00066 stxetxDataOut = dataout_func; 00067 } 00068 00069 // Send/Create STX/ETX packet 00070 void stxetxSend(unsigned char status, unsigned char type, unsigned char datalength, unsigned char* dataptr) 00071 { 00072 unsigned char checksum = 0; 00073 unsigned short i; 00074 00075 // write packet header 00076 stxetxDataOut(STX); 00077 stxetxDataOut(status); 00078 stxetxDataOut(type); 00079 stxetxDataOut(datalength); 00080 // update checksum 00081 checksum += status + type + datalength; 00082 // copy data into packet 00083 for(i = 0; i < datalength; i++) 00084 { 00085 stxetxDataOut(*dataptr); 00086 checksum += *dataptr; 00087 dataptr++; 00088 } 00089 // write packet trailer 00090 stxetxDataOut(checksum); 00091 stxetxDataOut(ETX); 00092 } 00093 00094 // process buffer containing STX/ETX packets 00095 unsigned char stxetxProcess(cBuffer* rxBuffer) 00096 { 00097 unsigned char foundpacket = FALSE; 00098 unsigned short i; 00099 unsigned char length, checksum; 00100 //unsigned char type; 00101 00102 // process the buffer 00103 // go through buffer looking for packets 00104 // the STX must be located at least STXETX_HEADERLENGTH+STXETX_TRAILERLENGTH from end 00105 // otherwise we must not have a complete packet 00106 while( rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+(u16)STXETX_TRAILERLENGTH) ) 00107 { 00108 // look for a potential start of packet 00109 if(bufferGetAtIndex(rxBuffer, 0) == STX) 00110 { 00111 // if this is a start, then get the length 00112 length = bufferGetAtIndex(rxBuffer, STXETX_LENGTHOFFSET); 00113 00114 // now we must have at least STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH in buffer to continue 00115 if(rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH)) 00116 { 00117 // check to see if ETX is in the right position 00118 if(bufferGetAtIndex(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH-1) == ETX) 00119 { 00120 // found potential packet 00121 // test checksum 00122 checksum = 0; 00123 // sum data between STX and ETX, not including checksum itself 00124 // (u16) casting needed to avoid unsigned/signed mismatch 00125 for(i = 0; i<((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH-(u16)STXETX_NOETXSTXCHECKSUM); i++) 00126 { 00127 checksum += bufferGetAtIndex(rxBuffer, i+STXETX_STATUSOFFSET); 00128 } 00129 // compare checksums 00130 if(checksum == bufferGetAtIndex(rxBuffer, STXETX_CHECKSUMOFFSET+length)) 00131 { 00132 //we have a packet! 00133 foundpacket = TRUE; 00134 00135 // copy data to buffer 00136 // (don't copy STX, ETX, or CHECKSUM) 00137 for(i = 0; i < ((u16)STXETX_HEADERLENGTH+length-1); i++) 00138 { 00139 stxetxRxPacket[i] = bufferGetAtIndex(rxBuffer, i+1); 00140 } 00141 00142 // debug 00143 //rprintf("STXETX Received packet type: 0x%x\n", bufferGetAtIndex(rxBuffer, STXETX_TYPEOFFSET)); 00144 00145 // dump this packet from the 00146 bufferDumpFromFront(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH); 00147 00148 // done with this processing session 00149 break; 00150 } 00151 else 00152 { 00153 // checksum bad 00154 //rprintf("STXETX Received packet with bad checksum\r\n"); 00155 // for now, we dump these 00156 // dump this STX 00157 bufferGetFromFront(rxBuffer); 00158 } 00159 } 00160 else 00161 { 00162 // no ETX or ETX in wrong position 00163 // dump this STX 00164 bufferGetFromFront(rxBuffer); 00165 } 00166 } 00167 else 00168 { 00169 // not enough data in buffer to decode pending packet 00170 // wait until next time 00171 break; 00172 } 00173 } 00174 else 00175 { 00176 // this is not a start, dump it 00177 bufferGetFromFront(rxBuffer); 00178 } 00179 } 00180 00181 // check if receive buffer is full with no packets decoding 00182 // (ie. deadlocked on garbage data or packet that exceeds buffer size) 00183 if(!bufferIsNotFull(rxBuffer)) 00184 { 00185 // dump receive buffer contents to relieve deadlock 00186 bufferFlush(rxBuffer); 00187 } 00188 00189 return foundpacket; 00190 } 00191 00192 unsigned char stxetxGetRxPacketStatus(void) 00193 { 00194 // return the packet's status 00195 // (subtract 1 from the offset because the STX has already been discarded) 00196 return stxetxRxPacket[STXETX_STATUSOFFSET-1]; 00197 } 00198 00199 unsigned char stxetxGetRxPacketType(void) 00200 { 00201 // return the packet's type 00202 // (subtract 1 from the offset because the STX has already been discarded) 00203 return stxetxRxPacket[STXETX_TYPEOFFSET-1]; 00204 } 00205 00206 unsigned char stxetxGetRxPacketDatalength(void) 00207 { 00208 // return the packet's datalength 00209 // (subtract 1 from the offset because the STX has already been discarded) 00210 return stxetxRxPacket[STXETX_LENGTHOFFSET-1]; 00211 } 00212 00213 unsigned char* stxetxGetRxPacketData(void) 00214 { 00215 // return a pointer to the packet's data payload 00216 // (subtract 1 from the offset because the STX has already been discarded) 00217 return stxetxRxPacket+STXETX_DATAOFFSET-1; 00218 }