1 /***********************************************************************************************************
4 * DESCRIPTION: simple serial protocol - packet based serial transport layer.
6 * HISTORY: Created 1/1/2010
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)
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 ***********************************************************************************************************/
77 /** PRIVATE DEFINITIONS **/
78 #define SYNC 225 // Sync character used in Serial Protocol
79 #define ESC 224 // ESC character used in Serial Protocol
80 #define ESC_SYNC 1 // ESC_SYNC character used in Serial Protocol
81 #define ACK_BIT 0x80 // Ack bit, bit 7 of sequence number, 1 = Acknowledge, 0 =
83 // packet location definitions.
88 // Make larger sized integers from smaller sized integers
89 #define MAKEWORD16(ub, lb) ((uint16_t)0x0000 | ((uint16_t)(ub) << 8) | (uint16_t)(lb))
90 #define MAKEWORD32(uw, lw) ((uint32_t)(0x0UL | ((uint32_t)(uw) << 16) | (uint32_t)(lw)))
91 #define MAKEWORD32B(b3, b2, b1, b0) ((uint32_t)((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | ((uint32_t)(b0))
93 // Used to extract smaller integers from larger sized intergers
94 #define LOWERBYTE(w) (uint8_t)((w) & 0x00ff)
95 #define UPPERBYTE(w) (uint8_t)(((w) & 0xff00) >> 8)
96 #define UPPERWORD(lw) (uint16_t)(((lw) & 0xffff0000) >> 16)
97 #define LOWERWORD(lw) (uint16_t)((lw) & 0x0000ffff)
99 // Macros to operate on a target and bitmask.
100 #define CLEARBIT(a, b) ((a) = (a) & ~(b))
101 #define SETBIT(a, b) ((a) = (a) | (b))
102 #define TOGGLEBIT(a, b) ((a) = (a) ^ (b))
104 // test bit macros operate using a bit mask.
105 #define ISBITSET(a, b) (((a) & (b)) == (b) ? TRUE : FALSE)
106 #define ISBITCLEAR(a, b) ((~(a) & (b)) == (b) ? TRUE : FALSE)
108 /** PRIVATE FUNCTIONS **/
109 // static void sf_SendSynchPacket( Port_t *thisport );
110 static uint16_t sf_checksum(uint16_t crc
, uint8_t data
);
111 static void sf_write_byte(Port_t
*thisport
, uint8_t c
);
112 static void sf_SetSendTimeout(Port_t
*thisport
);
113 static uint16_t sf_CheckTimeout(Port_t
*thisport
);
114 static int16_t sf_DecodeState(Port_t
*thisport
, uint8_t c
);
115 static int16_t sf_ReceiveState(Port_t
*thisport
, uint8_t c
);
117 static void sf_SendPacket(Port_t
*thisport
);
118 static void sf_SendAckPacket(Port_t
*thisport
, uint8_t seqNumber
);
119 static void sf_MakePacket(uint8_t *buf
, const uint8_t *pdata
, uint16_t length
,
121 static int16_t sf_ReceivePacket(Port_t
*thisport
);
123 /* Flag bit masks...*/
124 #define SENT_SYNCH (0x01)
125 #define ACK_RECEIVED (0x02)
126 #define ACK_EXPECTED (0x04)
128 #define SSP_AWAITING_ACK 0
133 static const uint16_t CRC_TABLE
[] = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301,
134 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0,0x0780, 0xC741, 0x0500, 0xC5C1,
135 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80,0xCD41, 0x0F00, 0xCFC1, 0xCE81,
136 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40,0xC901, 0x09C0, 0x0880, 0xC841,
137 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00,0xDBC1, 0xDA81, 0x1A40, 0x1E00,
138 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0,0x1C80, 0xDC41, 0x1400, 0xD4C1,
139 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680,0xD641, 0xD201, 0x12C0, 0x1380,
140 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,0xF001, 0x30C0, 0x3180, 0xF141,
141 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600,0xF6C1, 0xF781, 0x3740, 0xF501,
142 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1,0xFD81, 0x3D40, 0xFF01, 0x3FC0,
143 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80,0xFB41, 0x3900, 0xF9C1, 0xF881,
144 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940,0xEB01, 0x2BC0, 0x2A80, 0xEA41,
145 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00,0xEDC1, 0xEC81, 0x2C40, 0xE401,
146 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1,0xE681, 0x2640, 0x2200, 0xE2C1,
147 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080,0xE041, 0xA001, 0x60C0, 0x6180,
148 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,0x6600, 0xA6C1, 0xA781, 0x6740,
149 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00,0xACC1, 0xAD81, 0x6D40, 0xAF01,
150 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0,0x6B80, 0xAB41, 0x6900, 0xA9C1,
151 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981,0x7940, 0xBB01, 0x7BC0, 0x7A80,
152 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41,0x7D00, 0xBDC1, 0xBC81, 0x7C40,
153 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700,0xB7C1, 0xB681, 0x7640, 0x7200,
154 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0,0x7080, 0xB041, 0x5000, 0x90C1,
155 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280,0x9241, 0x9601, 0x56C0, 0x5780,
156 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,0x9C01, 0x5CC0, 0x5D80, 0x9D41,
157 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00,0x9AC1, 0x9B81, 0x5B40, 0x9901,
158 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0,0x4980, 0x8941, 0x4B00, 0x8BC1,
159 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81,0x4F40, 0x8D01, 0x4DC0, 0x4C80,
160 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540,0x8701, 0x47C0, 0x4680, 0x8641,
161 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100,0x81C1, 0x8081, 0x4040 };
163 /** EXTERNAL DATA **/
165 /** EXTERNAL FUNCTIONS **/
167 /** VERIFICATION FUNCTIONS **/
169 /***********************************************************************************************************/
172 * \brief Initializes the communication port for use
173 * \param thisport = pointer to port structure to initialize
174 * \param info = config struct with default values.
178 * Must be called before calling the Send or REceive process functions.
181 void ssp_Init(Port_t
*thisport
, const PortConfig_t
*const info
)
183 thisport
->pfCallBack
= info
->pfCallBack
;
184 thisport
->pfSerialRead
= info
->pfSerialRead
;
185 thisport
->pfSerialWrite
= info
->pfSerialWrite
;
186 thisport
->pfGetTime
= info
->pfGetTime
;
188 thisport
->maxRetryCount
= info
->max_retry
;
189 thisport
->timeoutLen
= info
->timeoutLen
;
190 thisport
->txBufSize
= info
->txBufSize
;
191 thisport
->rxBufSize
= info
->rxBufSize
;
192 thisport
->txBuf
= info
->txBuf
;
193 thisport
->rxBuf
= info
->rxBuf
;
194 thisport
->retryCount
= 0;
195 thisport
->sendSynch
= FALSE
; // TRUE;
196 thisport
->rxSeqNo
= 255;
197 thisport
->txSeqNo
= 255;
198 thisport
->SendState
= SSP_IDLE
;
202 * \brief Runs the send process, checks for receipt of ack, timeouts and resends if needed.
203 * \param thisport = which port to use
204 * \return SSP_TX_WAITING - waiting for a valid ACK to arrive
205 * \return SSP_TX_TIMEOUT - failed to receive a valid ACK in the timeout period, after retrying.
206 * \return SSP_TX_IDLE - not expecting a ACK packet (no current transmissions in progress)
207 * \return SSP_TX_ACKED - valid ACK received before timeout period.
212 int16_t ssp_SendProcess(Port_t
*thisport
)
214 int16_t value
= SSP_TX_WAITING
;
216 if (thisport
->SendState
== SSP_AWAITING_ACK
) {
217 if (sf_CheckTimeout(thisport
) == TRUE
) {
218 if (thisport
->retryCount
< thisport
->maxRetryCount
) {
220 sf_SendPacket(thisport
);
221 sf_SetSendTimeout(thisport
);
222 value
= SSP_TX_WAITING
;
224 // Give up, # of trys has exceded the limit
225 value
= SSP_TX_TIMEOUT
;
226 CLEARBIT(thisport
->flags
, ACK_RECEIVED
);
227 thisport
->SendState
= SSP_IDLE
;
230 value
= SSP_TX_WAITING
;
232 } else if (thisport
->SendState
== SSP_ACKED
) {
233 SETBIT(thisport
->flags
, ACK_RECEIVED
);
234 value
= SSP_TX_ACKED
;
235 thisport
->SendState
= SSP_IDLE
;
237 thisport
->SendState
= SSP_IDLE
;
244 * \brief Runs the receive process. fetches a byte at a time and runs the byte through the protocol receive state machine.
245 * \param thisport - which port to use.
246 * \return receive status.
251 int16_t ssp_ReceiveProcess(Port_t
*thisport
)
254 int16_t packet_status
= SSP_RX_IDLE
;
257 b
= thisport
->pfSerialRead(); // attempt to read a char from the serial buffer
259 packet_status
= sf_ReceiveState(thisport
, b
); // process the newly received byte in the receive state machine
261 // keep going until either we received a full packet or there are no more bytes to process
262 } while (packet_status
!= SSP_RX_COMPLETE
&& b
!= -1);
263 return packet_status
;
267 * \brief processes a single byte through the receive state machine.
268 * \param thisport = which port to use
269 * \return current receive status
275 int16_t ssp_ReceiveByte(Port_t
*thisport
)
278 int16_t packet_status
= SSP_RX_IDLE
;
280 b
= thisport
->pfSerialRead();
282 packet_status
= sf_ReceiveState(thisport
, b
);
284 return packet_status
;
288 * \brief Sends a data packet and blocks until timeout or ack is received.
289 * \param thisport = which port to use
290 * \param data = pointer to data to send
291 * \param length = number of data bytes to send. Must be less than 254
292 * \return true = ack was received within number of retries
293 * \return false = ack was not received.
298 uint16_t ssp_SendDataBlock(Port_t
*thisport
, uint8_t *data
, uint16_t length
)
300 int16_t packet_status
= SSP_TX_WAITING
;
302 packet_status
= ssp_SendData(thisport
, data
, length
); // send the data
303 while (packet_status
== SSP_TX_WAITING
) { // check the status
304 (void)ssp_ReceiveProcess(thisport
); // process any bytes received.
305 packet_status
= ssp_SendProcess(thisport
); // check the send status
307 return packet_status
== SSP_TX_ACKED
; // figure out what happened to the packet
311 * \brief sends a chunk of data and does not block
312 * \param thisport = which port to use
313 * \param data = pointer to data to send
314 * \param length = number of bytes to send
315 * \return SSP_TX_BUFOVERRUN = tried to send too much data
316 * \return SSP_TX_WAITING = data sent and waiting for an ack to arrive
317 * \return SSP_TX_BUSY = a packet has already been sent, but not yet acked
322 int16_t ssp_SendData(Port_t
*thisport
, const uint8_t *data
,
323 const uint16_t length
)
325 int16_t value
= SSP_TX_WAITING
;
327 if ((length
+ 2) > thisport
->txBufSize
) {
328 // TRYING to send too much data.
329 value
= SSP_TX_BUFOVERRUN
;
330 } else if (thisport
->SendState
== SSP_IDLE
) {
332 if (thisport
->sendSynch
== TRUE
) {
333 sf_SendSynchPacket(thisport
);
339 // TODO this method could allow a task/user to start a synchronisation step if a zero is mistakenly passed to this function.
340 // 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
341 // that must be called before calling this function.
342 // we are attempting to send a synch packet
343 thisport
->txSeqNo
= 0; // make this zero to cause the other end to re-synch with us
344 SETBIT(thisport
->flags
, SENT_SYNCH
);
346 // we are sending a data packet
347 CLEARBIT(thisport
->txSeqNo
, ACK_BIT
); // make sure we are not sending a ACK packet
348 thisport
->txSeqNo
++; // update the sequence number.
349 if (thisport
->txSeqNo
> 0x7F) { // check for sequence number rollover
350 thisport
->txSeqNo
= 1; // if we do have rollover then reset to 1 not zero,
351 // zero is reserviced for synchronization requests
356 CLEARBIT(thisport
->txSeqNo
, ACK_BIT
); // make sure we are not sending a ACK packet
357 thisport
->txSeqNo
++; // update the sequence number.
358 if (thisport
->txSeqNo
> 0x7F) { // check for sequence number rollover
359 thisport
->txSeqNo
= 1; // if we do have rollover then reset to 1 not zero,
360 // zero is reserved for synchronization requests
362 #endif /* ifdef SYNCH_SEND */
363 CLEARBIT(thisport
->flags
, ACK_RECEIVED
);
364 thisport
->SendState
= SSP_AWAITING_ACK
;
365 value
= SSP_TX_WAITING
;
366 thisport
->retryCount
= 0; // zero out the retry counter for this transmission
367 sf_MakePacket(thisport
->txBuf
, data
, length
, thisport
->txSeqNo
);
368 sf_SendPacket(thisport
); // punch out the packet to the serial port
369 sf_SetSendTimeout(thisport
); // do the timeout values
371 // error we are already sending a packet. Need to wait for the current packet to be acked or timeout.
378 * \brief Attempts to synchronize the sequence numbers with the other end of the connectin.
379 * \param thisport = which port to use
380 * \return true = success
381 * \return false = failed to receive an ACK to our synch request
384 * A. send a packet with a sequence number equal to zero
385 * B. if timed out then:
386 * send synch packet again
387 * increment try counter
388 * if number of tries exceed maximum try limit then exit
391 uint16_t ssp_Synchronise(Port_t
*thisport
)
393 int16_t packet_status
;
395 #ifndef USE_SENDPACKET_DATA
396 thisport
->txSeqNo
= 0; // make this zero to cause the other end to re-synch with us
397 SETBIT(thisport
->flags
, SENT_SYNCH
);
398 // TODO - should this be using ssp_SendPacketData()??
399 sf_MakePacket(thisport
->txBuf
, NULL
, 0, thisport
->txSeqNo
); // construct the packet
400 sf_SendPacket(thisport
);
401 sf_SetSendTimeout(thisport
);
402 thisport
->SendState
= SSP_AWAITING_ACK
;
403 packet_status
= SSP_TX_WAITING
;
405 packet_status
= ssp_SendData(thisport
, NULL
, 0);
407 while (packet_status
== SSP_TX_WAITING
) { // we loop until we time out.
408 (void)ssp_ReceiveProcess(thisport
); // do the receive process
409 packet_status
= ssp_SendProcess(thisport
); // do the send process
411 thisport
->sendSynch
= FALSE
;
412 return packet_status
== SSP_TX_ACKED
;
416 * \brief sends out a preformatted packet for a give port
417 * \param thisport = which port to use.
421 * Packet should be formed through the use of sf_MakePacket before calling this function.
423 static void sf_SendPacket(Port_t
*thisport
)
425 // add 3 to packet data length for: 1 length + 2 CRC (packet overhead)
426 uint8_t packetLen
= thisport
->txBuf
[LENGTH
] + 3;
428 // use the raw serial write function so the SYNC byte does not get 'escaped'
429 thisport
->pfSerialWrite(SYNC
);
430 for (uint8_t x
= 0; x
< packetLen
; x
++) {
431 sf_write_byte(thisport
, thisport
->txBuf
[x
]);
433 thisport
->retryCount
++;
437 * \brief converts data to transport layer protocol packet format.
438 * \param txbuf = buffer to use when forming the packet
439 * \param pdata = pointer to data to use
440 * \param length = number of bytes to use
441 * \param seqNo = sequence number of this packet
445 * 1. This function does not try to interpret ACK or SYNCH packets. This should
446 * be done by the caller of this function.
447 * 2. This function will attempt to format all data upto the size of the tx buffer.
448 * Any extra data beyond that will be ignored.
449 * 3. TODO: Should this function return an error if data length to be sent is greater th tx buffer size?
452 void sf_MakePacket(uint8_t *txBuf
, const uint8_t *pdata
, uint16_t length
,
455 uint16_t crc
= 0xffff;
459 // add 1 for the seq. number
460 txBuf
[LENGTH
] = length
+ 1;
461 txBuf
[SEQNUM
] = seqNo
;
462 crc
= sf_checksum(crc
, seqNo
);
464 length
= length
+ 2; // add two for the length and seqno bytes which are added before the loop.
465 for (bufPos
= 2; bufPos
< length
; bufPos
++) {
468 crc
= sf_checksum(crc
, b
); // update CRC value
470 txBuf
[bufPos
++] = LOWERBYTE(crc
);
471 txBuf
[bufPos
] = UPPERBYTE(crc
);
475 * \brief sends out an ack packet to given sequence number
476 * \param thisport = which port to use
477 * \param seqNumber = sequence number of the packet we would like to ack
484 static void sf_SendAckPacket(Port_t
*thisport
, uint8_t seqNumber
)
486 uint8_t AckSeqNumber
= SETBIT(seqNumber
, ACK_BIT
);
488 // create the packet, note we pass AckSequenceNumber directly
489 sf_MakePacket(thisport
->txBuf
, NULL
, 0, AckSeqNumber
);
490 sf_SendPacket(thisport
);
491 // we don't set the timeout for an ACK because we don't ACK our ACKs in this protocol
495 * \brief writes a byte out the output channel. Adds escape byte where needed
496 * \param thisport = which port to use
497 * \param c = byte to send
503 static void sf_write_byte(Port_t
*thisport
, uint8_t c
)
505 if (c
== SYNC
) { // check for SYNC byte
506 thisport
->pfSerialWrite(ESC
); // since we are not starting a packet we must ESCAPE the SYNCH byte
507 thisport
->pfSerialWrite(ESC_SYNC
); // now send the escaped synch char
508 } else if (c
== ESC
) { // Check for ESC character
509 thisport
->pfSerialWrite(ESC
); // if it is, we need to send it twice
510 thisport
->pfSerialWrite(ESC
);
512 thisport
->pfSerialWrite(c
); // otherwise write the byte to serial port
516 /************************************************************************************************************
518 * NAME: uint16_t ssp_crc16( uint16_t crc, uint16_t data )
519 * DESCRIPTION: Uses crc_table to calculate new crc
522 * arg2: data - byte to calculate into CRC
526 *************************************************************************************************************/
528 * \brief calculates the new CRC value for 'data'
529 * \param crc = current CRC value
530 * \param data = new byte
531 * \return updated CRC value
537 static uint16_t sf_checksum(uint16_t crc
, uint8_t data
)
540 return (crc
>> 8) ^ CRC_TABLE
[(crc
^ data
) & 0x00FF];
543 uint8_t cka
= crc
& 0xff;
544 uint8_t ckb
= (crc
>> 8) & 0xff;
547 return cka
| ckb
<< 8;
553 * \brief sets the timeout for the given packet
554 * \param thisport = which port to use
561 static void sf_SetSendTimeout(Port_t
*thisport
)
565 timeout
= thisport
->pfGetTime() + thisport
->timeoutLen
;
566 thisport
->timeout
= timeout
;
570 * \brief checks to see if a timeout occured
571 * \param thisport = which port to use
572 * \return true = a timeout has occurred
573 * \return false = has not timed out
578 static uint16_t sf_CheckTimeout(Port_t
*thisport
)
580 uint16_t retval
= FALSE
;
581 uint32_t current_time
;
583 current_time
= thisport
->pfGetTime();
584 if (current_time
> thisport
->timeout
) {
590 /****************************************************************************
591 * NAME: sf_ReceiveState
592 * DESC: Implements the receive state handling code for escaped and unescaped data
593 * ARGS: thisport - which port to operate on
598 * 1. change from using pointer to functions.
599 ****************************************************************************/
601 * \brief implements the receive state handling code for escaped and unescaped data
602 * \param thisport = which port to use
603 * \param c = byte to process through the receive state machine
604 * \return receive status
609 static int16_t sf_ReceiveState(Port_t
*thisport
, uint8_t c
)
611 int16_t retval
= SSP_RX_RECEIVING
;
613 switch (thisport
->InputState
) {
614 case state_unescaped_e
:
616 thisport
->DecodeState
= decode_len1_e
;
617 } else if (c
== ESC
) {
618 thisport
->InputState
= state_escaped_e
;
620 retval
= sf_DecodeState(thisport
, c
);
622 break; // end of unescaped state.
623 case state_escaped_e
:
624 thisport
->InputState
= state_unescaped_e
;
626 thisport
->DecodeState
= decode_len1_e
;
627 } else if (c
== ESC_SYNC
) {
628 retval
= sf_DecodeState(thisport
, SYNC
);
630 retval
= sf_DecodeState(thisport
, c
);
632 break; // end of the escaped state.
639 /****************************************************************************
640 * NAME: sf_DecodeState
641 * DESC: Implements the receive state finite state machine
642 * ARGS: thisport - which port to operate on
647 * 1. change from using pointer to functions.
648 ****************************************************************************/
651 * \brief implements the receiving decoding state machine
652 * \param thisport = which port to use
653 * \param c = byte to process
654 * \return receive status
659 static int16_t sf_DecodeState(Port_t
*thisport
, uint8_t c
)
663 switch (thisport
->DecodeState
) {
665 // 'c' is ignored in this state as the only way to leave the idle state is
666 // recognition of the SYNC byte in the sf_ReceiveState function.
667 retval
= SSP_RX_IDLE
;
670 thisport
->rxBuf
[LENGTH
] = c
;
671 thisport
->rxBufLen
= c
;
672 if (thisport
->rxBufLen
<= thisport
->rxBufSize
) {
673 thisport
->DecodeState
= decode_seqNo_e
;
674 retval
= SSP_RX_RECEIVING
;
676 thisport
->DecodeState
= decode_idle_e
;
677 retval
= SSP_RX_IDLE
;
681 thisport
->rxBuf
[SEQNUM
] = c
;
682 thisport
->crc
= 0xffff;
683 thisport
->rxBufLen
--; // subtract 1 for the seq. no.
684 thisport
->rxBufPos
= 2;
686 thisport
->crc
= sf_checksum(thisport
->crc
, c
);
687 if (thisport
->rxBufLen
> 0) {
688 thisport
->DecodeState
= decode_data_e
;
690 thisport
->DecodeState
= decode_crc1_e
;
692 retval
= SSP_RX_RECEIVING
;
695 thisport
->rxBuf
[(thisport
->rxBufPos
)++] = c
;
696 thisport
->crc
= sf_checksum(thisport
->crc
, c
);
697 if (thisport
->rxBufPos
== (thisport
->rxBufLen
+ 2)) {
698 thisport
->DecodeState
= decode_crc1_e
;
700 retval
= SSP_RX_RECEIVING
;
703 thisport
->crc
= sf_checksum(thisport
->crc
, c
);
704 thisport
->DecodeState
= decode_crc2_e
;
705 retval
= SSP_RX_RECEIVING
;
708 thisport
->DecodeState
= decode_idle_e
;
709 // verify the CRC value for the packet
710 if (sf_checksum(thisport
->crc
, c
) == 0) {
711 // TODO shouldn't the return value of sf_ReceivePacket() be checked?
712 sf_ReceivePacket(thisport
);
713 retval
= SSP_RX_COMPLETE
;
716 retval
= SSP_RX_IDLE
;
720 thisport
->DecodeState
= decode_idle_e
; // unknown state so reset to idle state and wait for the next start of a packet.
721 retval
= SSP_RX_IDLE
;
727 /************************************************************************************************************
729 * NAME: int16_t sf_ReceivePacket( )
730 * DESCRIPTION: Receive one packet, assumed that data is in rec.buff[]
732 * RETURN: 0 . no new packet was received, could be ack or same packet
733 * 1 . new packet received
735 * SSP_PACKET_COMPLETE
739 *************************************************************************************************************/
741 * \brief receive one packet. calls the callback function if needed.
742 * \param thisport = which port to use
743 * \return true = valid data packet received.
744 * \return false = otherwise
748 * Created: Oct 7, 2010 12:07:22 AM by joe
751 static int16_t sf_ReceivePacket(Port_t
*thisport
)
753 int16_t value
= FALSE
;
755 if (ISBITSET(thisport
->rxBuf
[SEQNUM
], ACK_BIT
)) {
756 // Received an ACK packet, need to check if it matches the previous sent packet
757 if ((thisport
->rxBuf
[SEQNUM
] & 0x7F) == (thisport
->txSeqNo
& 0x7f)) {
758 // It matches the last packet sent by us
759 SETBIT(thisport
->txSeqNo
, ACK_BIT
);
760 thisport
->SendState
= SSP_ACKED
;
764 // else ignore the ACK packet
766 // Received a 'data' packet, figure out what type of packet we received...
767 if (thisport
->rxBuf
[SEQNUM
] == 0) {
768 // Synchronize sequence number with host
770 thisport
->sendSynch
= TRUE
;
772 sf_SendAckPacket(thisport
, thisport
->rxBuf
[SEQNUM
]);
773 thisport
->rxSeqNo
= 0;
775 } else if (thisport
->rxBuf
[SEQNUM
] == thisport
->rxSeqNo
) {
776 // Already seen this packet, just ack it, don't act on the packet.
777 sf_SendAckPacket(thisport
, thisport
->rxBuf
[SEQNUM
]);
781 thisport
->rxSeqNo
= thisport
->rxBuf
[SEQNUM
];
782 // Let the application do something with the data/packet.
783 if (thisport
->pfCallBack
!= NULL
) {
784 // skip the first two bytes (length and seq. no.) in the buffer.
785 thisport
->pfCallBack(&(thisport
->rxBuf
[2]), thisport
->rxBufLen
);
787 // after we send the ACK, it is possible for the host to send a new packet.
788 // Thus the application needs to copy the data and reset the receive buffer
789 // inside of thisport->pfCallBack()
790 sf_SendAckPacket(thisport
, thisport
->rxBuf
[SEQNUM
]);