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