Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / experimental / USB_UPLOAD_TOOL / SSP / ssp.cpp
blob03d6dc89f7b7cf42d1010065c7352791c7dd1d24
1 /***********************************************************************************************************
3 * NAME: ssp.c
4 * DESCRIPTION: simple serial protocol - packet based serial transport layer.
5 * AUTHOR: Joe Hlebasko
6 * HISTORY: Created 1/1/2010
8 * Packet Formats
9 * Format:
10 * +------+----+------+---------------------------+--------+
11 * | 225 | L1 | S# | App Data (0-254 bytes) | CRC 16 |
12 * +------+----+------+---------------------------+--------+
14 * 225 = sync byte, indicates start of a packet
15 * L1 = 1 byte for size of data payload. (sequence number is part of data payload.)
16 * S# = 1 byte for sequence number.
17 * Seq of 0 = seq # synchronise request, forces other end to reset receive sequence number to 1.
18 * sender of synchronise request will reset the tx seq number to 1
19 * Seq # of 1..127 = normal data packets. Sequence number is incremented by for each transmitted
20 * packet. Rolls over from 127 to 1.
21 * if most sig. bit is set then the packet is an ACK packet of data packet sequence number of the
22 * lower 7 bits (1..127)
23 * App Data may contain 0..254 bytes. The sequence number is consider part of the payload.
24 * CRC 16 - 16 bits of CRC values of Sequence # and data bytes.
26 * Protocol has two types of packets: data and ack packets. ACK packets have the most sig. bit set in the
27 * sequence number, this implies that valid sequence numbers are 1..127
29 * This protocol uses the concept of sequences numbers to determine if a given packet has been received. This
30 * requires both devices to be able to synchronize sequence numbers. This is accomplished by sending a packet
31 * length 1 and sequence number = 0. The receive then resets it's transmit sequence number to 1.
33 * ACTIVE_SYNCH is a version that will automatically send a synch request if it receives a synch packet. Only
34 * one device in the communication should do otherwise you end up with an endless loops of synchronization.
35 * Right now each side needs to manually issues a synch request.
37 * This protocol is best used in cases where one device is the master and the other is the slave, or a don't
38 * speak unless spoken to type of approach.
40 * The following are items are required to initialize a port for communications:
41 * 1. The number attempts for each packet
42 * 2. time to wait for an ack.
43 * 3. pointer to buffer to be used for receiving.
44 * 4. pointer to a buffer to be used for transmission
45 * 5. length of each buffer (rx and tx)
46 * 6. Four functions:
47 * 1. write byte = writes a byte out the serial port (or other comm device)
48 * 2. read byte = retrieves a byte from the serial port. Returns -1 if a byte is not available
49 * 3. callback = function to call when a valid data packet has been received. This function is responsible
50 * to do what needs to be done with the data when it is received. The primary mission of this function
51 * should be to copy the data to a private buffer out of the working receive buffer to prevent overrun.
52 * processing should be kept to a minimum.
53 * 4. get time = function should return the current time. Note that time units are not specified it just
54 * needs to be some measure of time that increments as time passes by. The timeout values for a given
55 * port should the units used/returned by the get time function.
57 * All of the state information of a communication port is contained in a Port_t structure. This allows this
58 * module to operature on multiple communication ports with a single code base.
60 * The ssp_ReceiveProcess and ssp_SendProcess functions need to be called to process data through the
61 * respective state machines. Typical implementation would have a serial ISR to pull bytes out of the UART
62 * and place into a circular buffer. The serial read function would then pull bytes out this buffer
63 * processing. The TX side has the write function placing bytes into a circular buffer with the TX ISR
64 * pulling bytes out of the buffer and putting into the UART. It is possible to run the receive process from
65 * the receive ISR but care must be taken on processing data when it is received to avoid holding up the ISR
66 * and sending ACK packets from the receive ISR.
68 ***********************************************************************************************************/
70 /** INCLUDE FILES **/
73 #include <stdint.h>
74 #include <string.h>
75 #include <stdio.h>
77 #include "ssp.h"
79 /** PRIVATE DEFINITIONS **/
80 #define SYNC 225 // Sync character used in Serial Protocol
81 #define ESC 224 // ESC character used in Serial Protocol
82 #define ESC_SYNC 1 // ESC_SYNC character used in Serial Protocol
83 #define ACK_BIT 0x80 // Ack bit, bit 7 of sequence number, 1 = Acknowledge, 0 =
84 // new packet
85 // packet location definitions.
86 #define LENGTH 0
87 #define SEQNUM 1
88 #define DATA 2
91 // Make larger sized integers from smaller sized integers
92 #define MAKEWORD16(ub, lb) ((uint16_t)0x0000 | ((uint16_t)(ub) << 8) | (uint16_t)(lb))
93 #define MAKEWORD32(uw, lw) ((uint32_t)(0x0UL | ((uint32_t)(uw) << 16) | (uint32_t)(lw)))
94 #define MAKEWORD32B(b3, b2, b1, b0) ((uint32_t)((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | ((uint32_t)(b0)))
97 // Used to extract smaller integers from larger sized intergers
98 #define LOWERBYTE(w) (uint8_t)((w) & 0x00ff)
99 #define UPPERBYTE(w) (uint8_t)(((w) & 0xff00) >> 8)
100 #define UPPERWORD(lw) (uint16_t)(((lw) & 0xffff0000) >> 16)
101 #define LOWERWORD(lw) (uint16_t)((lw) & 0x0000ffff)
103 // Macros to operate on a target and bitmask.
104 #define CLEARBIT(a, b) ((a) = (a) & ~(b))
105 #define SETBIT(a, b) ((a) = (a) | (b))
106 #define TOGGLEBIT(a, b) ((a) = (a) ^ (b))
108 // test bit macros operate using a bit mask.
109 #define ISBITSET(a, b) (((a) & (b)) == (b) ? TRUE : FALSE)
110 #define ISBITCLEAR(a, b) ((~(a) & (b)) == (b) ? TRUE : FALSE)
112 /** PRIVATE FUNCTIONS **/
113 // static void sf_SendSynchPacket( Port_t *thisport );
114 static uint16_t sf_crc16(uint16_t crc, uint8_t data);
115 static void sf_write_byte(Port_t *thisport, uint8_t c);
116 static void sf_SetSendTimeout(Port_t *thisport);
117 static uint16_t sf_CheckTimeout(Port_t *thisport);
118 static int16_t sf_DecodeState(Port_t *thisport, uint8_t c);
119 static int16_t sf_ReceiveState(Port_t *thisport, uint8_t c);
121 static void sf_SendPacket(Port_t *thisport);
122 static void sf_SendAckPacket(Port_t *thisport, uint8_t seqNumber);
123 static void sf_MakePacket(uint8_t *buf, const uint8_t *pdata, uint16_t length, uint8_t seqNo);
124 static int16_t sf_ReceivePacket(Port_t *thisport);
126 /* Flag bit masks...*/
127 #define SENT_SYNCH (0x01)
128 #define ACK_RECEIVED (0x02)
129 #define ACK_EXPECTED (0x04)
131 #define SSP_AWAITING_ACK 0
132 #define SSP_ACKED 1
133 #define SSP_IDLE 2
135 /** PRIVATE DATA **/
136 static const uint16_t CRC_TABLE[] = {
137 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
138 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
139 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
140 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
141 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
142 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
143 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
144 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
145 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
146 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
147 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
148 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
149 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
150 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
151 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
152 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
153 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
154 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
155 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
156 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
157 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
158 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
159 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
160 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
161 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
162 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
163 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
164 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
165 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
166 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
167 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
168 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
171 /** EXTERNAL DATA **/
173 /** EXTERNAL FUNCTIONS **/
175 /** VERIFICATION FUNCTIONS **/
178 /***********************************************************************************************************/
181 * \brief Initializes the communication port for use
182 * \param thisport = pointer to port structure to initialize
183 * \param info = config struct with default values.
184 * \return None.
186 * \note
187 * Must be called before calling the Send or REceive process functions.
190 void ssp_Init(Port_t *thisport, const PortConfig_t *const info)
192 thisport->pfCallBack = info->pfCallBack;
193 thisport->pfSerialRead = info->pfSerialRead;
194 thisport->pfSerialWrite = info->pfSerialWrite;
195 thisport->pfGetTime = info->pfGetTime;
197 thisport->maxRetryCount = info->max_retry;
198 thisport->timeoutLen = info->timeoutLen;
199 thisport->txBufSize = info->txBufSize;
200 thisport->rxBufSize = info->rxBufSize;
201 thisport->txBuf = info->txBuf;
202 thisport->rxBuf = info->rxBuf;
203 thisport->retryCount = 0;
204 thisport->sendSynch = FALSE; // TRUE;
205 thisport->rxSeqNo = 255;
206 thisport->txSeqNo = 255;
207 thisport->SendState = SSP_IDLE;
211 * \brief Runs the send process, checks for receipt of ack, timeouts and resends if needed.
212 * \param thisport = which port to use
213 * \return SSP_TX_WAITING - waiting for a valid ACK to arrive
214 * \return SSP_TX_TIMEOUT - failed to receive a valid ACK in the timeout period, after retrying.
215 * \return SSP_TX_IDLE - not expecting a ACK packet (no current transmissions in progress)
216 * \return SSP_TX_ACKED - valid ACK received before timeout period.
218 * \note
221 int16_t ssp_SendProcess(Port_t *thisport)
223 int16_t value = SSP_TX_WAITING;
225 if (thisport->SendState == SSP_AWAITING_ACK) {
226 if (sf_CheckTimeout(thisport) == TRUE) {
227 if (thisport->retryCount < thisport->maxRetryCount) {
228 // Try again
229 sf_SendPacket(thisport);
230 sf_SetSendTimeout(thisport);
231 value = SSP_TX_WAITING;
232 } else {
233 // Give up, # of trys has exceded the limit
234 value = SSP_TX_TIMEOUT;
235 CLEARBIT(thisport->flags, ACK_RECEIVED);
236 thisport->SendState = SSP_IDLE;
238 } else {
239 value = SSP_TX_WAITING;
241 } else if (thisport->SendState == SSP_ACKED) {
242 SETBIT(thisport->flags, ACK_RECEIVED);
243 value = SSP_TX_ACKED;
244 thisport->SendState = SSP_IDLE;
245 } else {
246 thisport->SendState = SSP_IDLE;
247 value = SSP_TX_IDLE;
249 return value;
253 * \brief Runs the receive process. fetches a byte at a time and runs the byte through the protocol receive state machine.
254 * \param thisport - which port to use.
255 * \return receive status.
257 * \note
260 int16_t ssp_ReceiveProcess(Port_t *thisport)
262 int16_t b;
263 int16_t packet_status = SSP_RX_IDLE;
265 do {
266 b = thisport->pfSerialRead(); // attempt to read a char from the serial buffer
267 if (b != -1) {
268 packet_status = sf_ReceiveState(thisport, b); // process the newly received byte in the receive state machine
270 // keep going until either we received a full packet or there are no more bytes to process
271 } while (packet_status != SSP_RX_COMPLETE && b != -1);
272 return packet_status;
276 * \brief processes a single byte through the receive state machine.
277 * \param thisport = which port to use
278 * \return current receive status
280 * \note
284 int16_t ssp_ReceiveByte(Port_t *thisport)
286 int16_t b;
287 int16_t packet_status = SSP_RX_IDLE;
289 b = thisport->pfSerialRead();
290 if (b != -1) {
291 packet_status = sf_ReceiveState(thisport, b);
293 return packet_status;
297 * \brief Sends a data packet and blocks until timeout or ack is received.
298 * \param thisport = which port to use
299 * \param data = pointer to data to send
300 * \param length = number of data bytes to send. Must be less than 254
301 * \return true = ack was received within number of retries
302 * \return false = ack was not received.
304 * \note
307 uint16_t ssp_SendDataBlock(Port_t *thisport, uint8_t *data, uint16_t length)
309 int16_t packet_status = SSP_TX_WAITING;
310 uint16_t retval = FALSE;
312 packet_status = ssp_SendData(thisport, data, length); // send the data
313 while (packet_status == SSP_TX_WAITING) { // check the status
314 (void)ssp_ReceiveProcess(thisport); // process any bytes received.
315 packet_status = ssp_SendProcess(thisport); // check the send status
317 if (packet_status == SSP_TX_ACKED) { // figure out what happened to the packet
318 retval = TRUE;
319 } else {
320 retval = FALSE;
322 return retval;
326 * \brief sends a chunk of data and does not block
327 * \param thisport = which port to use
328 * \param data = pointer to data to send
329 * \param length = number of bytes to send
330 * \return SSP_TX_BUFOVERRUN = tried to send too much data
331 * \return SSP_TX_WAITING = data sent and waiting for an ack to arrive
332 * \return SSP_TX_BUSY = a packet has already been sent, but not yet acked
334 * \note
337 int16_t ssp_SendData(Port_t *thisport, const uint8_t *data, const uint16_t length)
339 int16_t value = SSP_TX_WAITING;
341 if ((length + 2) > thisport->txBufSize) {
342 // TRYING to send too much data.
343 value = SSP_TX_BUFOVERRUN;
344 } else if (thisport->SendState == SSP_IDLE) {
345 #ifdef ACTIVE_SYNCH
346 if (thisport->sendSynch == TRUE) {
347 sf_SendSynchPacket(thisport);
349 #endif
351 #ifdef SYNCH_SEND
352 if (length == 0) {
353 // TODO this method could allow a task/user to start a synchronisation step if a zero is mistakenly passed to this function.
354 // could add a check for a NULL data pointer, or use some sort of static flag that can only be accessed by a static function
355 // that must be called before calling this function.
356 // we are attempting to send a synch packet
357 thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
358 SETBIT(thisport->flags, SENT_SYNCH);
359 } else {
360 // we are sending a data packet
361 CLEARBIT(thisport->txSeqNo, ACK_BIT); // make sure we are not sending a ACK packet
362 thisport->txSeqNo++; // update the sequence number.
363 if (thisport->txSeqNo > 0x7F) { // check for sequence number rollover
364 thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
365 // zero is reserviced for synchronization requests
369 #else
370 CLEARBIT(thisport->txSeqNo, ACK_BIT); // make sure we are not sending a ACK packet
371 thisport->txSeqNo++; // update the sequence number.
372 if (thisport->txSeqNo > 0x7F) { // check for sequence number rollover
373 thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
374 // zero is reserved for synchronization requests
376 #endif // ifdef SYNCH_SEND
377 CLEARBIT(thisport->flags, ACK_RECEIVED);
378 thisport->SendState = SSP_AWAITING_ACK;
379 value = SSP_TX_WAITING;
380 thisport->retryCount = 0; // zero out the retry counter for this transmission
381 sf_MakePacket(thisport->txBuf, data, length, thisport->txSeqNo);
382 sf_SendPacket(thisport); // punch out the packet to the serial port
383 sf_SetSendTimeout(thisport); // do the timeout values
384 } else {
385 // error we are already sending a packet. Need to wait for the current packet to be acked or timeout.
386 value = SSP_TX_BUSY;
388 return value;
392 * \brief Attempts to synchronize the sequence numbers with the other end of the connectin.
393 * \param thisport = which port to use
394 * \return true = success
395 * \return false = failed to receive an ACK to our synch request
397 * \note
398 * A. send a packet with a sequence number equal to zero
399 * B. if timed out then:
400 * send synch packet again
401 * increment try counter
402 * if number of tries exceed maximum try limit then exit
403 * C. goto A
405 uint16_t ssp_Synchronise(Port_t *thisport)
407 int16_t packet_status;
408 uint16_t retval = FALSE;
410 #ifndef USE_SENDPACKET_DATA
411 thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
412 SETBIT(thisport->flags, SENT_SYNCH);
413 // TODO - should this be using ssp_SendPacketData()??
414 sf_MakePacket(thisport->txBuf, NULL, 0, thisport->txSeqNo); // construct the packet
415 sf_SendPacket(thisport);
416 sf_SetSendTimeout(thisport);
417 thisport->SendState = SSP_AWAITING_ACK;
418 packet_status = SSP_TX_WAITING;
419 #else
420 packet_status = ssp_SendData(thisport, NULL, 0);
421 #endif
422 while (packet_status == SSP_TX_WAITING) { // we loop until we time out.
423 (void)ssp_ReceiveProcess(thisport); // do the receive process
424 packet_status = ssp_SendProcess(thisport); // do the send process
426 thisport->sendSynch = FALSE;
427 switch (packet_status) {
428 case SSP_TX_ACKED:
429 retval = TRUE;
430 break;
431 case SSP_TX_BUSY: // intentional fall through.
432 case SSP_TX_TIMEOUT: // intentional fall through.
433 case SSP_TX_BUFOVERRUN:
434 retval = FALSE;
435 break;
436 default:
437 retval = FALSE;
438 break;
441 return retval;
446 * \brief sends out a preformatted packet for a give port
447 * \param thisport = which port to use.
448 * \return none.
450 * \note
451 * Packet should be formed through the use of sf_MakePacket before calling this function.
453 static void sf_SendPacket(Port_t *thisport)
455 // add 3 to packet data length for: 1 length + 2 CRC (packet overhead)
456 uint8_t packetLen = thisport->txBuf[LENGTH] + 3;
458 // use the raw serial write function so the SYNC byte does not get 'escaped'
459 thisport->pfSerialWrite(SYNC);
460 for (uint8_t x = 0; x < packetLen; x++) {
461 sf_write_byte(thisport, thisport->txBuf[x]);
463 thisport->retryCount++;
468 * \brief converts data to transport layer protocol packet format.
469 * \param txbuf = buffer to use when forming the packet
470 * \param pdata = pointer to data to use
471 * \param length = number of bytes to use
472 * \param seqNo = sequence number of this packet
473 * \return none.
475 * \note
476 * 1. This function does not try to interpret ACK or SYNCH packets. This should
477 * be done by the caller of this function.
478 * 2. This function will attempt to format all data upto the size of the tx buffer.
479 * Any extra data beyond that will be ignored.
480 * 3. TODO: Should this function return an error if data length to be sent is greater th tx buffer size?
483 void sf_MakePacket(uint8_t *txBuf, const uint8_t *pdata, uint16_t length, uint8_t seqNo)
485 uint16_t crc = 0xffff;
486 uint16_t bufPos = 0;
487 uint8_t b;
489 // add 1 for the seq. number
490 txBuf[LENGTH] = length + 1;
491 txBuf[SEQNUM] = seqNo;
492 crc = sf_crc16(crc, seqNo);
494 length = length + 2; // add two for the length and seqno bytes which are added before the loop.
495 for (bufPos = 2; bufPos < length; bufPos++) {
496 b = *pdata++;
497 txBuf[bufPos] = b;
498 crc = sf_crc16(crc, b); // update CRC value
500 txBuf[bufPos++] = LOWERBYTE(crc);
501 txBuf[bufPos] = UPPERBYTE(crc);
505 * \brief sends out an ack packet to given sequence number
506 * \param thisport = which port to use
507 * \param seqNumber = sequence number of the packet we would like to ack
508 * \return none.
510 * \note
514 static void sf_SendAckPacket(Port_t *thisport, uint8_t seqNumber)
516 uint8_t AckSeqNumber = SETBIT(seqNumber, ACK_BIT);
518 // create the packet, note we pass AckSequenceNumber directly
519 sf_MakePacket(thisport->txBuf, NULL, 0, AckSeqNumber);
520 sf_SendPacket(thisport);
521 // we don't set the timeout for an ACK because we don't ACK our ACKs in this protocol
525 * \brief writes a byte out the output channel. Adds escape byte where needed
526 * \param thisport = which port to use
527 * \param c = byte to send
528 * \return none.
530 * \note
533 static void sf_write_byte(Port_t *thisport, uint8_t c)
535 if (c == SYNC) { // check for SYNC byte
536 thisport->pfSerialWrite(ESC); // since we are not starting a packet we must ESCAPE the SYNCH byte
537 thisport->pfSerialWrite(ESC_SYNC); // now send the escaped synch char
538 } else if (c == ESC) { // Check for ESC character
539 thisport->pfSerialWrite(ESC); // if it is, we need to send it twice
540 thisport->pfSerialWrite(ESC);
541 } else {
542 thisport->pfSerialWrite(c); // otherwise write the byte to serial port
546 /************************************************************************************************************
548 * NAME: uint16_t ssp_crc16( uint16_t crc, uint16_t data )
549 * DESCRIPTION: Uses crc_table to calculate new crc
550 * ARGUMENTS:
551 * arg1: crc
552 * arg2: data - byte to calculate into CRC
553 * RETURN: New crc
554 * CREATED: 5/8/02
556 *************************************************************************************************************/
558 * \brief calculates the new CRC value for 'data'
559 * \param crc = current CRC value
560 * \param data = new byte
561 * \return updated CRC value
563 * \note
567 static uint16_t sf_crc16(uint16_t crc, uint8_t data)
569 return (crc >> 8) ^ CRC_TABLE[(crc ^ data) & 0x00FF];
574 * \brief sets the timeout for the given packet
575 * \param thisport = which port to use
576 * \return none.
578 * \note
582 static void sf_SetSendTimeout(Port_t *thisport)
584 uint32_t timeout;
586 timeout = thisport->pfGetTime() + thisport->timeoutLen;
587 thisport->timeout = timeout;
591 * \brief checks to see if a timeout occured
592 * \param thisport = which port to use
593 * \return true = a timeout has occurred
594 * \return false = has not timed out
596 * \note
599 static uint16_t sf_CheckTimeout(Port_t *thisport)
601 uint16_t retval = FALSE;
602 uint32_t current_time;
604 current_time = thisport->pfGetTime();
605 if (current_time > thisport->timeout) {
606 retval = TRUE;
608 return retval;
612 /****************************************************************************
613 * NAME: sf_ReceiveState
614 * DESC: Implements the receive state handling code for escaped and unescaped data
615 * ARGS: thisport - which port to operate on
616 * c - incoming byte
617 * RETURN:
618 * CREATED:
619 * NOTES:
620 * 1. change from using pointer to functions.
621 ****************************************************************************/
623 * \brief implements the receive state handling code for escaped and unescaped data
624 * \param thisport = which port to use
625 * \param c = byte to process through the receive state machine
626 * \return receive status
628 * \note
631 static int16_t sf_ReceiveState(Port_t *thisport, uint8_t c)
633 int16_t retval = SSP_RX_RECEIVING;
635 switch (thisport->InputState) {
636 case state_unescaped_e:
637 if (c == SYNC) {
638 thisport->DecodeState = decode_len1_e;
639 } else if (c == ESC) {
640 thisport->InputState = state_escaped_e;
641 } else {
642 retval = sf_DecodeState(thisport, c);
644 break; // end of unescaped state.
645 case state_escaped_e:
646 thisport->InputState = state_unescaped_e;
647 if (c == SYNC) {
648 thisport->DecodeState = decode_len1_e;
649 } else if (c == ESC_SYNC) {
650 retval = sf_DecodeState(thisport, SYNC);
651 } else {
652 retval = sf_DecodeState(thisport, c);
654 break; // end of the escaped state.
655 default:
656 break;
658 return retval;
661 /****************************************************************************
662 * NAME: sf_DecodeState
663 * DESC: Implements the receive state finite state machine
664 * ARGS: thisport - which port to operate on
665 * c - incoming byte
666 * RETURN:
667 * CREATED:
668 * NOTES:
669 * 1. change from using pointer to functions.
670 ****************************************************************************/
673 * \brief implements the receiving decoding state machine
674 * \param thisport = which port to use
675 * \param c = byte to process
676 * \return receive status
678 * \note
681 static int16_t sf_DecodeState(Port_t *thisport, uint8_t c)
683 int16_t retval;
685 switch (thisport->DecodeState) {
686 case decode_idle_e:
687 // 'c' is ignored in this state as the only way to leave the idle state is
688 // recognition of the SYNC byte in the sf_ReceiveState function.
689 retval = SSP_RX_IDLE;
690 break;
691 case decode_len1_e:
692 thisport->rxBuf[LENGTH] = c;
693 thisport->rxBufLen = c;
694 if (thisport->rxBufLen <= thisport->rxBufSize) {
695 thisport->DecodeState = decode_seqNo_e;
696 retval = SSP_RX_RECEIVING;
697 } else {
698 thisport->DecodeState = decode_idle_e;
699 retval = SSP_RX_IDLE;
701 break;
702 case decode_seqNo_e:
703 thisport->rxBuf[SEQNUM] = c;
704 thisport->crc = 0xffff;
705 thisport->rxBufLen--; // subtract 1 for the seq. no.
706 thisport->rxBufPos = 2;
708 thisport->crc = sf_crc16(thisport->crc, c);
709 if (thisport->rxBufLen > 0) {
710 thisport->DecodeState = decode_data_e;
711 } else {
712 thisport->DecodeState = decode_crc1_e;
714 retval = SSP_RX_RECEIVING;
715 break;
716 case decode_data_e:
717 thisport->rxBuf[(thisport->rxBufPos)++] = c;
718 thisport->crc = sf_crc16(thisport->crc, c);
719 if (thisport->rxBufPos == (thisport->rxBufLen + 2)) {
720 thisport->DecodeState = decode_crc1_e;
722 retval = SSP_RX_RECEIVING;
723 break;
724 case decode_crc1_e:
725 thisport->crc = sf_crc16(thisport->crc, c);
726 thisport->DecodeState = decode_crc2_e;
727 retval = SSP_RX_RECEIVING;
728 break;
729 case decode_crc2_e:
730 thisport->DecodeState = decode_idle_e;
731 // verify the CRC value for the packet
732 if (sf_crc16(thisport->crc, c) == 0) {
733 // TODO shouldn't the return value of sf_ReceivePacket() be checked?
734 sf_ReceivePacket(thisport);
735 retval = SSP_RX_COMPLETE;
736 } else {
737 thisport->RxError++;
738 retval = SSP_RX_IDLE;
740 break;
741 default:
742 thisport->DecodeState = decode_idle_e; // unknown state so reset to idle state and wait for the next start of a packet.
743 retval = SSP_RX_IDLE;
744 break;
746 return retval;
749 /************************************************************************************************************
751 * NAME: int16_t sf_ReceivePacket( )
752 * DESCRIPTION: Receive one packet, assumed that data is in rec.buff[]
753 * ARGUMENTS:
754 * RETURN: 0 . no new packet was received, could be ack or same packet
755 * 1 . new packet received
756 * SSP_PACKET_?
757 * SSP_PACKET_COMPLETE
758 * SSP_PACKET_ACK
759 * CREATED: 5/8/02
761 *************************************************************************************************************/
763 * \brief receive one packet. calls the callback function if needed.
764 * \param thisport = which port to use
765 * \return true = valid data packet received.
766 * \return false = otherwise
768 * \note
770 * Created: Oct 7, 2010 12:07:22 AM by joe
773 static int16_t sf_ReceivePacket(Port_t *thisport)
775 int16_t value = FALSE;
777 if (ISBITSET(thisport->rxBuf[SEQNUM], ACK_BIT)) {
778 // Received an ACK packet, need to check if it matches the previous sent packet
779 if ((thisport->rxBuf[SEQNUM] & 0x7F) == (thisport->txSeqNo & 0x7f)) {
780 // It matches the last packet sent by us
781 SETBIT(thisport->txSeqNo, ACK_BIT);
782 thisport->SendState = SSP_ACKED;
783 value = FALSE;
785 // else ignore the ACK packet
786 } else {
787 // Received a 'data' packet, figure out what type of packet we received...
788 if (thisport->rxBuf[SEQNUM] == 0) {
789 // Synchronize sequence number with host
790 #ifdef ACTIVE_SYNCH
791 thisport->sendSynch = TRUE;
792 #endif
793 sf_SendAckPacket(thisport, thisport->rxBuf[SEQNUM]);
794 thisport->rxSeqNo = 0;
795 value = FALSE;
796 } else if (thisport->rxBuf[SEQNUM] == thisport->rxSeqNo) {
797 // Already seen this packet, just ack it, don't act on the packet.
798 sf_SendAckPacket(thisport, thisport->rxBuf[SEQNUM]);
799 value = FALSE;
800 } else {
801 // New Packet
802 thisport->rxSeqNo = thisport->rxBuf[SEQNUM];
803 // Let the application do something with the data/packet.
804 if (thisport->pfCallBack != NULL) {
805 // skip the first two bytes (length and seq. no.) in the buffer.
806 thisport->pfCallBack(&(thisport->rxBuf[2]), thisport->rxBufLen);
808 // after we send the ACK, it is possible for the host to send a new packet.
809 // Thus the application needs to copy the data and reset the receive buffer
810 // inside of thisport->pfCallBack()
811 sf_SendAckPacket(thisport, thisport->rxBuf[SEQNUM]);
812 value = TRUE;
815 return value;