Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / ground / gcs / src / plugins / uploader / SSP / qssp.cpp
blob7381791c61898c0755f014924ace91270855a3cb
1 /**
2 ******************************************************************************
4 * @file qssp.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @addtogroup GCSPlugins GCS Plugins
8 * @{
9 * @addtogroup Uploader Serial and USB Uploader Plugin
10 * @{
11 * @brief The USB and Serial protocol uploader plugin
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "qssp.h"
30 #include <QDebug>
32 #include <stdint.h>
33 #include <string.h>
34 #include <stdio.h>
36 /** PRIVATE DEFINITIONS **/
37 #define SYNC 225 // Sync character used in Serial Protocol
38 #define ESC 224 // ESC character used in Serial Protocol
39 #define ESC_SYNC 1 // ESC_SYNC character used in Serial Protocol
40 #define ACK_BIT 0x80 // Ack bit, bit 7 of sequence number, 1 = Acknowledge, 0 =
41 // new packet
42 // packet location definitions.
43 #define LENGTH 0
44 #define SEQNUM 1
45 #define DATA 2
48 // Make larger sized integers from smaller sized integers
49 #define MAKEWORD16(ub, lb) ((uint16_t)0x0000 | ((uint16_t)(ub) << 8) | (uint16_t)(lb))
50 #define MAKEWORD32(uw, lw) ((uint32_t)(0x0UL | ((uint32_t)(uw) << 16) | (uint32_t)(lw)))
51 #define MAKEWORD32B(b3, b2, b1, b0) ((uint32_t)((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | ((uint32_t)(b0)))
54 // Used to extract smaller integers from larger sized intergers
55 #define LOWERBYTE(w) (uint8_t)((w) & 0x00ff)
56 #define UPPERBYTE(w) (uint8_t)(((w) & 0xff00) >> 8)
57 #define UPPERWORD(lw) (uint16_t)(((lw) & 0xffff0000) >> 16)
58 #define LOWERWORD(lw) (uint16_t)((lw) & 0x0000ffff)
60 // Macros to operate on a target and bitmask.
61 #define CLEARBIT(a, b) ((a) = (a) & ~(b))
62 #define SETBIT(a, b) ((a) = (a) | (b))
63 #define TOGGLEBIT(a, b) ((a) = (a) ^ (b))
65 // test bit macros operate using a bit mask.
66 #define ISBITSET(a, b) (((a) & (b)) == (b) ? TRUE : FALSE)
67 #define ISBITCLEAR(a, b) ((~(a) & (b)) == (b) ? TRUE : FALSE)
70 /* Flag bit masks...*/
71 #define SENT_SYNCH (0x01)
72 #define ACK_RECEIVED (0x02)
73 #define ACK_EXPECTED (0x04)
75 #define SSP_AWAITING_ACK 0
76 #define SSP_ACKED 1
77 #define SSP_IDLE 2
79 /** PRIVATE DATA **/
80 static const uint16_t CRC_TABLE[] = {
81 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
82 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
83 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
84 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
85 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
86 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
87 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
88 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
89 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
90 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
91 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
92 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
93 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
94 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
95 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
96 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
97 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
98 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
99 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
100 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
101 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
102 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
103 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
104 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
105 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
106 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
107 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
108 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
109 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
110 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
111 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
112 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
115 /** EXTERNAL DATA **/
117 /** EXTERNAL FUNCTIONS **/
119 /** VERIFICATION FUNCTIONS **/
122 /***********************************************************************************************************/
125 * \brief Initializes the communication port for use
126 * \param thisport = pointer to port structure to initialize
127 * \param info = config struct with default values.
128 * \return None.
130 * \note
131 * Must be called before calling the Send or REceive process functions.
134 void qssp::ssp_Init(const PortConfig_t *const info)
136 thisport->maxRetryCount = info->max_retry;
137 thisport->timeoutLen = info->timeoutLen;
138 thisport->txBufSize = info->txBufSize;
139 thisport->rxBufSize = info->rxBufSize;
140 thisport->txBuf = info->txBuf;
141 thisport->rxBuf = info->rxBuf;
142 thisport->retryCount = 0;
143 thisport->sendSynch = FALSE; // TRUE;
144 thisport->rxSeqNo = 255;
145 thisport->txSeqNo = 255;
146 thisport->SendState = SSP_IDLE;
147 thisport->inputState = (ReceiveState)0;
148 thisport->decodeState = (DecodeState)0;
149 thisport->TxError = 0;
150 thisport->RxError = 0;
151 thisport->txSeqNo = 0;
152 thisport->rxSeqNo = 0;
156 * \brief Runs the send process, checks for receipt of ack, timeouts and resends if needed.
157 * \param thisport = which port to use
158 * \return SSP_TX_WAITING - waiting for a valid ACK to arrive
159 * \return SSP_TX_TIMEOUT - failed to receive a valid ACK in the timeout period, after retrying.
160 * \return SSP_TX_IDLE - not expecting a ACK packet (no current transmissions in progress)
161 * \return SSP_TX_ACKED - valid ACK received before timeout period.
163 * \note
166 int16_t qssp::ssp_SendProcess()
168 int16_t value = SSP_TX_WAITING;
170 if (thisport->SendState == SSP_AWAITING_ACK) {
171 if (sf_CheckTimeout() == TRUE) {
172 if (thisport->retryCount < thisport->maxRetryCount) {
173 // Try again
174 sf_SendPacket();
175 sf_SetSendTimeout();
176 value = SSP_TX_WAITING;
177 } else {
178 // Give up, # of tries has exceeded the limit
179 value = SSP_TX_TIMEOUT;
180 CLEARBIT(thisport->flags, ACK_RECEIVED);
181 thisport->SendState = SSP_IDLE;
182 if (debug) {
183 qDebug() << "Send TimeOut!";
186 } else {
187 value = SSP_TX_WAITING;
189 } else if (thisport->SendState == SSP_ACKED) {
190 SETBIT(thisport->flags, ACK_RECEIVED);
191 value = SSP_TX_ACKED;
192 thisport->SendState = SSP_IDLE;
193 } else {
194 thisport->SendState = SSP_IDLE;
195 value = SSP_TX_IDLE;
197 return value;
201 * \brief Runs the receive process. fetches a byte at a time and runs the byte through the protocol receive state machine.
202 * \param thisport - which port to use.
203 * \return receive status.
205 * \note
208 int16_t qssp::ssp_ReceiveProcess()
210 int16_t b;
211 int16_t packet_status = SSP_RX_IDLE;
213 do {
214 b = thisport->pfSerialRead(); // attempt to read a char from the serial buffer
215 if (b != -1) {
216 packet_status = sf_ReceiveState(b); // process the newly received byte in the receive state machine
218 // keep going until either we received a full packet or there are no more bytes to process
219 } while (packet_status != SSP_RX_COMPLETE && b != -1);
221 return packet_status;
225 * \brief processes a single byte through the receive state machine.
226 * \param thisport = which port to use
227 * \return current receive status
229 * \note
233 int16_t qssp::ssp_ReceiveByte()
235 int16_t b;
236 int16_t packet_status = SSP_RX_IDLE;
238 b = thisport->pfSerialRead();
239 if (b != -1) {
240 packet_status = sf_ReceiveState(b);
242 return packet_status;
246 * \brief Sends a data packet and blocks until timeout or ack is received.
247 * \param thisport = which port to use
248 * \param data = pointer to data to send
249 * \param length = number of data bytes to send. Must be less than 254
250 * \return true = ack was received within number of retries
251 * \return false = ack was not received.
253 * \note
256 uint16_t qssp::ssp_SendDataBlock(uint8_t *data, uint16_t length)
258 int16_t packet_status = SSP_TX_WAITING;
259 uint16_t retval = FALSE;
261 packet_status = ssp_SendData(data, length); // send the data
262 // TODO the loop is non blocking and will spin as fast as the CPU allows
263 while (packet_status == SSP_TX_WAITING) { // check the status
264 (void)ssp_ReceiveProcess(); // process any bytes received.
265 packet_status = ssp_SendProcess(); // check the send status
267 if (packet_status == SSP_TX_ACKED) { // figure out what happened to the packet
268 retval = TRUE;
269 } else {
270 retval = FALSE;
272 return retval;
276 * \brief sends a chunk of data and does not block
277 * \param thisport = which port to use
278 * \param data = pointer to data to send
279 * \param length = number of bytes to send
280 * \return SSP_TX_BUFOVERRUN = tried to send too much data
281 * \return SSP_TX_WAITING = data sent and waiting for an ack to arrive
282 * \return SSP_TX_BUSY = a packet has already been sent, but not yet acked
284 * \note
287 int16_t qssp::ssp_SendData(const uint8_t *data, const uint16_t length)
289 int16_t value = SSP_TX_WAITING;
291 if ((length + 2) > thisport->txBufSize) {
292 // TRYING to send too much data.
293 value = SSP_TX_BUFOVERRUN;
294 } else if (thisport->SendState == SSP_IDLE) {
295 #ifdef ACTIVE_SYNCH
296 if (thisport->sendSynch == TRUE) {
297 sf_SendSynchPacket();
299 #endif
301 #ifdef SYNCH_SEND
302 if (length == 0) {
303 // TODO this method could allow a task/user to start a synchronisation step if a zero is mistakenly passed to this function.
304 // 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
305 // that must be called before calling this function.
306 // we are attempting to send a synch packet
307 thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
308 SETBIT(thisport->flags, SENT_SYNCH);
309 } else {
310 // we are sending a data packet
311 CLEARBIT(thisport->txSeqNo, ACK_BIT); // make sure we are not sending a ACK packet
312 thisport->txSeqNo++; // update the sequence number.
313 if (thisport->txSeqNo > 0x7F) { // check for sequence number rollover
314 thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
315 // zero is reserviced for synchronization requests
319 #else
320 CLEARBIT(thisport->txSeqNo, ACK_BIT); // make sure we are not sending a ACK packet
321 thisport->txSeqNo++; // update the sequence number.
322 if (thisport->txSeqNo > 0x7F) { // check for sequence number rollover
323 thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
324 // zero is reserved for synchronization requests
326 #endif // ifdef SYNCH_SEND
327 CLEARBIT(thisport->flags, ACK_RECEIVED);
328 thisport->SendState = SSP_AWAITING_ACK;
329 value = SSP_TX_WAITING;
330 thisport->retryCount = 0; // zero out the retry counter for this transmission
331 sf_MakePacket(thisport->txBuf, data, length, thisport->txSeqNo);
332 sf_SendPacket(); // punch out the packet to the serial port
333 sf_SetSendTimeout(); // do the timeout values
334 if (debug) {
335 qDebug() << "Sent DATA PACKET:" << thisport->txSeqNo;
337 } else {
338 // error we are already sending a packet. Need to wait for the current packet to be acked or timeout.
339 value = SSP_TX_BUSY;
340 if (debug) {
341 qDebug() << "Error sending TX was busy";
344 return value;
348 * \brief Attempts to synchronize the sequence numbers with the other end of the connection.
349 * \param thisport = which port to use
350 * \return true = success
351 * \return false = failed to receive an ACK to our synch request
353 * \note
354 * A. send a packet with a sequence number equal to zero
355 * B. if timed out then:
356 * send synch packet again
357 * increment try counter
358 * if number of tries exceed maximum try limit then exit
359 * C. goto A
361 uint16_t qssp::ssp_Synchronise()
363 int16_t packet_status;
364 uint16_t retval = FALSE;
366 #ifndef USE_SENDPACKET_DATA
367 thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
368 SETBIT(thisport->flags, SENT_SYNCH);
369 // TODO - should this be using ssp_SendPacketData()??
370 sf_MakePacket(thisport->txBuf, NULL, 0, thisport->txSeqNo); // construct the packet
371 sf_SendPacket();
372 sf_SetSendTimeout();
373 thisport->SendState = SSP_AWAITING_ACK;
374 packet_status = SSP_TX_WAITING;
375 #else
376 packet_status = ssp_SendData(NULL, 0);
377 #endif
378 while (packet_status == SSP_TX_WAITING) { // we loop until we time out.
379 ssp_ReceiveProcess(); // do the receive process
380 packet_status = ssp_SendProcess(); // do the send process
382 thisport->sendSynch = FALSE;
383 switch (packet_status) {
384 case SSP_TX_ACKED:
385 retval = TRUE;
386 break;
387 case SSP_TX_BUSY: // intentional fall through.
388 case SSP_TX_TIMEOUT: // intentional fall through.
389 case SSP_TX_BUFOVERRUN:
390 retval = FALSE;
391 break;
392 default:
393 retval = FALSE;
394 break;
396 return retval;
401 * \brief sends out a preformatted packet for a give port
402 * \param thisport = which port to use.
403 * \return none.
405 * \note
406 * Packet should be formed through the use of sf_MakePacket before calling this function.
408 void qssp::sf_SendPacket()
410 // add 3 to packet data length for: 1 length + 2 CRC (packet overhead)
411 uint8_t packetLen = thisport->txBuf[LENGTH] + 3;
413 // use the raw serial write function so the SYNC byte does not get 'escaped'
414 thisport->pfSerialWrite(SYNC);
415 for (uint8_t x = 0; x < packetLen; x++) {
416 sf_write_byte(thisport->txBuf[x]);
418 thisport->retryCount++;
422 * \brief converts data to transport layer protocol packet format.
423 * \param txbuf = buffer to use when forming the packet
424 * \param pdata = pointer to data to use
425 * \param length = number of bytes to use
426 * \param seqNo = sequence number of this packet
427 * \return none.
429 * \note
430 * 1. This function does not try to interpret ACK or SYNCH packets. This should
431 * be done by the caller of this function.
432 * 2. This function will attempt to format all data upto the size of the tx buffer.
433 * Any extra data beyond that will be ignored.
434 * 3. TODO: Should this function return an error if data length to be sent is greater th tx buffer size?
437 void qssp::sf_MakePacket(uint8_t *txBuf, const uint8_t *pdata, uint16_t length, uint8_t seqNo)
439 uint16_t crc = 0xffff;
440 uint16_t bufPos = 0;
441 uint8_t b;
443 // add 1 for the seq. number
444 txBuf[LENGTH] = length + 1;
445 txBuf[SEQNUM] = seqNo;
446 crc = sf_crc16(crc, seqNo);
448 length = length + 2; // add two for the length and seqno bytes which are added before the loop.
449 for (bufPos = 2; bufPos < length; bufPos++) {
450 b = *pdata++;
451 txBuf[bufPos] = b;
452 crc = sf_crc16(crc, b); // update CRC value
454 txBuf[bufPos++] = LOWERBYTE(crc);
455 txBuf[bufPos] = UPPERBYTE(crc);
459 * \brief sends out an ack packet to given sequence number
460 * \param thisport = which port to use
461 * \param seqNumber = sequence number of the packet we would like to ack
462 * \return none.
464 * \note
468 void qssp::sf_SendAckPacket(uint8_t seqNumber)
470 uint8_t AckSeqNumber = SETBIT(seqNumber, ACK_BIT);
472 // create the packet, note we pass AckSequenceNumber directly
473 sf_MakePacket(thisport->txBuf, NULL, 0, AckSeqNumber);
474 sf_SendPacket();
475 if (debug) {
476 qDebug() << "Sent ACK PACKET:" << seqNumber;
478 // we don't set the timeout for an ACK because we don't ACK our ACKs in this protocol
482 * \brief writes a byte out the output channel. Adds escape byte where needed
483 * \param thisport = which port to use
484 * \param c = byte to send
485 * \return none.
487 * \note
490 void qssp::sf_write_byte(uint8_t c)
492 if (c == SYNC) { // check for SYNC byte
493 thisport->pfSerialWrite(ESC); // since we are not starting a packet we must ESCAPE the SYNCH byte
494 thisport->pfSerialWrite(ESC_SYNC); // now send the escaped synch char
495 } else if (c == ESC) { // Check for ESC character
496 thisport->pfSerialWrite(ESC); // if it is, we need to send it twice
497 thisport->pfSerialWrite(ESC);
498 } else {
499 thisport->pfSerialWrite(c); // otherwise write the byte to serial port
503 /************************************************************************************************************
505 * NAME: uint16_t ssp_crc16( uint16_t crc, uint16_t data )
506 * DESCRIPTION: Uses crc_table to calculate new crc
507 * ARGUMENTS:
508 * arg1: crc
509 * arg2: data - byte to calculate into CRC
510 * RETURN: New crc
511 * CREATED: 5/8/02
513 *************************************************************************************************************/
515 * \brief calculates the new CRC value for 'data'
516 * \param crc = current CRC value
517 * \param data = new byte
518 * \return updated CRC value
520 * \note
524 uint16_t qssp::sf_crc16(uint16_t crc, uint8_t data)
526 #ifdef SPP_USES_CRC
527 return (crc >> 8) ^ CRC_TABLE[(crc ^ data) & 0x00FF];
529 #else
530 uint8_t cka = crc & 0xff;
531 uint8_t ckb = (crc >> 8) & 0xff;
532 cka += data;
533 ckb += cka;
534 return cka | ckb << 8;
536 #endif
540 * \brief sets the timeout for the given packet
541 * \param thisport = which port to use
542 * \return none.
544 * \note
548 void qssp::sf_SetSendTimeout()
550 uint32_t timeout;
552 timeout = thisport->pfGetTime() + thisport->timeoutLen;
553 thisport->timeout = timeout;
557 * \brief checks to see if a timeout occured
558 * \param thisport = which port to use
559 * \return true = a timeout has occurred
560 * \return false = has not timed out
562 * \note
565 uint16_t qssp::sf_CheckTimeout()
567 uint16_t retval = FALSE;
568 uint32_t current_time;
570 current_time = thisport->pfGetTime();
571 if (current_time > thisport->timeout) {
572 retval = TRUE;
574 if (retval) {
575 if (debug) {
576 qDebug() << "timeout " << current_time << thisport->timeout;
579 return retval;
583 /****************************************************************************
584 * NAME: sf_ReceiveState
585 * DESC: Implements the receive state handling code for escaped and unescaped data
586 * ARGS: thisport - which port to operate on
587 * c - incoming byte
588 * RETURN:
589 * CREATED:
590 * NOTES:
591 * 1. change from using pointer to functions.
592 ****************************************************************************/
594 * \brief implements the receive state handling code for escaped and unescaped data
595 * \param thisport = which port to use
596 * \param c = byte to process through the receive state machine
597 * \return receive status
599 * \note
602 int16_t qssp::sf_ReceiveState(uint8_t c)
604 int16_t retval = SSP_RX_RECEIVING;
606 switch (thisport->inputState) {
607 case state_unescaped_e:
608 if (c == SYNC) {
609 thisport->decodeState = decode_len1_e;
610 } else if (c == ESC) {
611 thisport->inputState = state_escaped_e;
612 } else {
613 retval = sf_DecodeState(c);
615 break; // end of unescaped state.
616 case state_escaped_e:
617 thisport->inputState = state_unescaped_e;
618 if (c == SYNC) {
619 thisport->decodeState = decode_len1_e;
620 } else if (c == ESC_SYNC) {
621 retval = sf_DecodeState(SYNC);
622 } else {
623 retval = sf_DecodeState(c);
625 break; // end of the escaped state.
626 default:
627 break;
629 return retval;
632 /****************************************************************************
633 * NAME: sf_DecodeState
634 * DESC: Implements the receive state finite state machine
635 * ARGS: thisport - which port to operate on
636 * c - incoming byte
637 * RETURN:
638 * CREATED:
639 * NOTES:
640 * 1. change from using pointer to functions.
641 ****************************************************************************/
644 * \brief implements the receiving decoding state machine
645 * \param thisport = which port to use
646 * \param c = byte to process
647 * \return receive status
649 * \note
652 int16_t qssp::sf_DecodeState(uint8_t c)
654 int16_t retval;
656 switch (thisport->decodeState) {
657 case decode_idle_e:
658 // 'c' is ignored in this state as the only way to leave the idle state is
659 // recognition of the SYNC byte in the sf_ReceiveState function.
660 retval = SSP_RX_IDLE;
661 break;
662 case decode_len1_e:
663 if (c == 0) {
664 thisport->decodeState = decode_idle_e;
665 thisport->RxError++;
666 retval = SSP_RX_IDLE;
667 break;
669 thisport->rxBuf[LENGTH] = c;
670 thisport->rxBufLen = c;
671 if (thisport->rxBufLen <= thisport->rxBufSize) {
672 thisport->decodeState = decode_seqNo_e;
673 retval = SSP_RX_RECEIVING;
674 } else {
675 thisport->decodeState = decode_idle_e;
676 retval = SSP_RX_IDLE;
678 break;
679 case decode_seqNo_e:
680 thisport->rxBuf[SEQNUM] = c;
681 thisport->crc = 0xffff;
682 thisport->rxBufLen--; // subtract 1 for the seq. no.
683 thisport->rxBufPos = 2;
685 thisport->crc = sf_crc16(thisport->crc, c);
686 if (thisport->rxBufLen > 0) {
687 thisport->decodeState = decode_data_e;
688 } else {
689 thisport->decodeState = decode_crc1_e;
691 retval = SSP_RX_RECEIVING;
692 break;
693 case decode_data_e:
694 thisport->rxBuf[(thisport->rxBufPos)++] = c;
695 thisport->crc = sf_crc16(thisport->crc, c);
696 if (thisport->rxBufPos == (thisport->rxBufLen + 2)) {
697 thisport->decodeState = decode_crc1_e;
699 retval = SSP_RX_RECEIVING;
700 break;
701 case decode_crc1_e:
702 thisport->crc = sf_crc16(thisport->crc, c);
703 thisport->decodeState = decode_crc2_e;
704 retval = SSP_RX_RECEIVING;
705 break;
706 case decode_crc2_e:
707 thisport->decodeState = decode_idle_e;
708 // verify the CRC value for the packet
709 if (sf_crc16(thisport->crc, c) == 0) {
710 // TODO shouldn't the return value of sf_ReceivePacket() be checked?
711 sf_ReceivePacket();
712 retval = SSP_RX_COMPLETE;
713 } else {
714 thisport->RxError++;
715 retval = SSP_RX_IDLE;
717 break;
718 default:
719 thisport->decodeState = decode_idle_e; // unknown state so reset to idle state and wait for the next start of a packet.
720 retval = SSP_RX_IDLE;
721 break;
723 return retval;
726 /************************************************************************************************************
728 * NAME: int16_t sf_ReceivePacket( )
729 * DESCRIPTION: Receive one packet, assumed that data is in rec.buff[]
730 * ARGUMENTS:
731 * RETURN: 0 . no new packet was received, could be ack or same packet
732 * 1 . new packet received
733 * SSP_PACKET_?
734 * SSP_PACKET_COMPLETE
735 * SSP_PACKET_ACK
736 * CREATED: 5/8/02
738 *************************************************************************************************************/
740 * \brief receive one packet. calls the callback function if needed.
741 * \param thisport = which port to use
742 * \return true = valid data packet received.
743 * \return false = otherwise
745 * \note
747 * Created: Oct 7, 2010 12:07:22 AM by joe
750 int16_t qssp::sf_ReceivePacket()
752 int16_t value = FALSE;
754 if (ISBITSET(thisport->rxBuf[SEQNUM], ACK_BIT)) {
755 // Received an ACK packet, need to check if it matches the previous sent packet
756 if ((thisport->rxBuf[SEQNUM] & 0x7F) == (thisport->txSeqNo & 0x7f)) {
757 // It matches the last packet sent by us
758 SETBIT(thisport->txSeqNo, ACK_BIT);
759 thisport->SendState = SSP_ACKED;
760 value = FALSE;
761 if (debug) {
762 qDebug() << "Received ACK:" << (thisport->txSeqNo & 0x7F);
765 // else ignore the ACK packet
766 } else {
767 // Received a 'data' packet, figure out what type of packet we received...
768 if (thisport->rxBuf[SEQNUM] == 0) {
769 if (debug) {
770 qDebug() << "Received SYNC Request";
772 // Synchronize sequence number with host
773 #ifdef ACTIVE_SYNCH
774 thisport->sendSynch = TRUE;
775 #endif
776 sf_SendAckPacket(thisport->rxBuf[SEQNUM]);
777 thisport->rxSeqNo = 0;
778 value = FALSE;
779 } else if (thisport->rxBuf[SEQNUM] == thisport->rxSeqNo) {
780 // Already seen this packet, just ack it, don't act on the packet.
781 sf_SendAckPacket(thisport->rxBuf[SEQNUM]);
782 value = FALSE;
783 } else {
784 // New Packet
785 thisport->rxSeqNo = thisport->rxBuf[SEQNUM];
786 // Let the application do something with the data/packet.
788 // skip the first two bytes (length and seq. no.) in the buffer.
789 if (debug) {
790 qDebug() << "Received DATA PACKET seq=" << thisport->rxSeqNo << "Data=" << (uint8_t)thisport->rxBuf[2] << (uint8_t)thisport->rxBuf[3] << (uint8_t)thisport->rxBuf[4];
792 pfCallBack(&(thisport->rxBuf[2]), thisport->rxBufLen);
794 // after we send the ACK, it is possible for the host to send a new packet.
795 // Thus the application needs to copy the data and reset the receive buffer
796 // inside of thisport->pfCallBack()
797 sf_SendAckPacket(thisport->rxBuf[SEQNUM]);
798 value = TRUE;
801 return value;
804 qssp::qssp(port *info, bool debug) : debug(debug)
806 thisport = info;
807 thisport->maxRetryCount = info->max_retry;
808 thisport->timeoutLen = info->timeoutLen;
809 thisport->txBufSize = info->txBufSize;
810 thisport->rxBufSize = info->rxBufSize;
811 thisport->txBuf = info->txBuf;
812 thisport->rxBuf = info->rxBuf;
813 thisport->retryCount = 0;
814 thisport->sendSynch = FALSE; // TRUE;
815 thisport->rxSeqNo = 255;
816 thisport->txSeqNo = 255;
817 thisport->SendState = SSP_IDLE;
818 thisport->inputState = (ReceiveState)0;
819 thisport->decodeState = (DecodeState)0;
820 thisport->TxError = 0;
821 thisport->RxError = 0;
822 thisport->txSeqNo = 0;
823 thisport->rxSeqNo = 0;
826 void qssp::pfCallBack(uint8_t *buf, uint16_t size)
828 Q_UNUSED(size);
830 if (debug) {
831 qDebug() << "receive callback" << buf[0] << buf[1] << buf[2] << buf[3] << buf[4];