/*! \file stxetx.c \brief STX/ETX Packet Protocol Implementation Library. */ //***************************************************************************** // // File Name : 'stxetx.c' // Title : STX/ETX Packet Protocol Implementation Library // Author : Pascal Stang - Copyright (C) 2002 // Created : 10/9/2002 // Revised : 6/30/2003 // Version : 0.1 // Target MCU : any // Editor Tabs : 4 // // Description : This library provides a set of functions needed to send and // receive STX/ETX packets. STX/ETX is a simple packet protocol that can // be wrapped around user data for one or more of the following reasons: // // 1. packetization is needed // - Using packets can be helpful if your data naturally forms // little "bunches" or if different types of data must be sent // over the same channel (a serial cable, for example). If your // data forms "bunches", you can send user data inside STX/ETX // packets with a predetermined structure, like an array of A/D // conversion results. If you need a way to tell the receiver // what kind of data you're sending, you can use the TYPE field // in the STX/ETX packet. // 2. error checking is needed // - STX/ETX packets will add a checksum to your data. This // allows the receiver to verify that data was received correctly // and is error-free. Packets which are corrupted in transmission // and fail the the checksum test are automatically discarded. // Error checking is especially useful when the data transmission // channel is unreliable or noisy (examples: radio, infrared, long // cables, etc) // // STX/ETX packets have the following structure: // // [STX][status][type][length][user data...][checksum][ETX] // // All fields are 1 byte except for user data which may be 0-255 bytes. // Uppercase fields are constant (STX=0x02, ETX=0x03), lowercase fields // vary. The length field is the number of bytes in the user data area. // The checksum is the 8-bit sum of all bytes between but not including // STX/ETX. // // This code is distributed under the GNU Public License // which can be found at http://www.gnu.org/licenses/gpl.txt // //***************************************************************************** #include "global.h" #include "stxetx.h" //#include "rprintf.h" // function pointer to data output routine static void (*stxetxDataOut)(unsigned char data); // received packet data buffer unsigned char stxetxRxPacket[STXETX_MAXRXPACKETSIZE]; // functions // Initialize STX/ETX packet protocol library void stxetxInit(void (*dataout_func)(unsigned char data)) { stxetxDataOut = dataout_func; } // Send/Create STX/ETX packet void stxetxSend(unsigned char status, unsigned char type, unsigned char datalength, unsigned char* dataptr) { unsigned char checksum = 0; unsigned short i; // write packet header stxetxDataOut(STX); stxetxDataOut(status); stxetxDataOut(type); stxetxDataOut(datalength); // update checksum checksum += status + type + datalength; // copy data into packet for(i = 0; i < datalength; i++) { stxetxDataOut(*dataptr); checksum += *dataptr; dataptr++; } // write packet trailer stxetxDataOut(checksum); stxetxDataOut(ETX); } // process buffer containing STX/ETX packets unsigned char stxetxProcess(cBuffer* rxBuffer) { unsigned char foundpacket = FALSE; unsigned short i; unsigned char length, checksum; //unsigned char type; // process the buffer // go through buffer looking for packets // the STX must be located at least STXETX_HEADERLENGTH+STXETX_TRAILERLENGTH from end // otherwise we must not have a complete packet while( rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+(u16)STXETX_TRAILERLENGTH) ) { // look for a potential start of packet if(bufferGetAtIndex(rxBuffer, 0) == STX) { // if this is a start, then get the length length = bufferGetAtIndex(rxBuffer, STXETX_LENGTHOFFSET); // now we must have at least STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH in buffer to continue if(rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH)) { // check to see if ETX is in the right position if(bufferGetAtIndex(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH-1) == ETX) { // found potential packet // test checksum checksum = 0; // sum data between STX and ETX, not including checksum itself // (u16) casting needed to avoid unsigned/signed mismatch for(i = 0; i<((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH-(u16)STXETX_NOETXSTXCHECKSUM); i++) { checksum += bufferGetAtIndex(rxBuffer, i+STXETX_STATUSOFFSET); } // compare checksums if(checksum == bufferGetAtIndex(rxBuffer, STXETX_CHECKSUMOFFSET+length)) { //we have a packet! foundpacket = TRUE; // copy data to buffer // (don't copy STX, ETX, or CHECKSUM) for(i = 0; i < ((u16)STXETX_HEADERLENGTH+length-1); i++) { stxetxRxPacket[i] = bufferGetAtIndex(rxBuffer, i+1); } // debug //rprintf("STXETX Received packet type: 0x%x\n", bufferGetAtIndex(rxBuffer, STXETX_TYPEOFFSET)); // dump this packet from the bufferDumpFromFront(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH); // done with this processing session break; } else { // checksum bad //rprintf("STXETX Received packet with bad checksum\r\n"); // for now, we dump these // dump this STX bufferGetFromFront(rxBuffer); } } else { // no ETX or ETX in wrong position // dump this STX bufferGetFromFront(rxBuffer); } } else { // not enough data in buffer to decode pending packet // wait until next time break; } } else { // this is not a start, dump it bufferGetFromFront(rxBuffer); } } // check if receive buffer is full with no packets decoding // (ie. deadlocked on garbage data or packet that exceeds buffer size) if(!bufferIsNotFull(rxBuffer)) { // dump receive buffer contents to relieve deadlock bufferFlush(rxBuffer); } return foundpacket; } unsigned char stxetxGetRxPacketStatus(void) { // return the packet's status // (subtract 1 from the offset because the STX has already been discarded) return stxetxRxPacket[STXETX_STATUSOFFSET-1]; } unsigned char stxetxGetRxPacketType(void) { // return the packet's type // (subtract 1 from the offset because the STX has already been discarded) return stxetxRxPacket[STXETX_TYPEOFFSET-1]; } unsigned char stxetxGetRxPacketDatalength(void) { // return the packet's datalength // (subtract 1 from the offset because the STX has already been discarded) return stxetxRxPacket[STXETX_LENGTHOFFSET-1]; } unsigned char* stxetxGetRxPacketData(void) { // return a pointer to the packet's data payload // (subtract 1 from the offset because the STX has already been discarded) return stxetxRxPacket+STXETX_DATAOFFSET-1; }