sbgEComProtocol.c
Go to the documentation of this file.
1 #include "sbgEComProtocol.h"
2 #include <crc/sbgCrc.h>
3 
4 //----------------------------------------------------------------------//
5 //- Communication protocol operations -//
6 //----------------------------------------------------------------------//
7 
15 {
16  SbgErrorCode errorCode = SBG_NO_ERROR;
17 
18  //
19  // Check input parameters
20  //
21  SBG_ASSERT(pHandle);
22  SBG_ASSERT(pInterface);
23 
24  //
25  // Initialize the created protocol handle
26  //
27  pHandle->pLinkedInterface = pInterface;
28  pHandle->rxBufferSize = 0;
29 
30  return errorCode;
31 }
32 
39 {
40  //
41  // Check input arguments
42  //
43  SBG_ASSERT(pHandle);
44 
45  //
46  // Reset all members to zero
47  //
48  pHandle->pLinkedInterface = NULL;
49  pHandle->rxBufferSize = 0;
50 
51  //
52  // Don't have to do anything
53  //
54  return SBG_NO_ERROR;
55 }
56 
66 SbgErrorCode sbgEComProtocolSend(SbgEComProtocol *pHandle, uint8 msgClass, uint8 msg, const void *pData, size_t size)
67 {
68  SbgErrorCode errorCode = SBG_NO_ERROR;
69  uint8 outputBuffer[SBG_ECOM_MAX_BUFFER_SIZE];
70  SbgStreamBuffer outputStream;
71  uint16 frameCrc;
72 
73  //
74  // Check input arguments
75  //
76  SBG_ASSERT(pHandle);
77 
78  if ( (size <= SBG_ECOM_MAX_PAYLOAD_SIZE) && ( ((size > 0) && (pData)) || (size == 0) ) )
79  {
80  //
81  // Create a stream buffer to write the frame
82  //
83  sbgStreamBufferInitForWrite(&outputStream, outputBuffer, sizeof(outputBuffer));
84 
85  //
86  // Write the header
87  //
90 
91  //
92  // Write the message ID and class
93  //
94  sbgStreamBufferWriteUint8LE(&outputStream, msg);
95  sbgStreamBufferWriteUint8LE(&outputStream, msgClass);
96 
97  //
98  // Write the length field
99  //
100  sbgStreamBufferWriteUint16LE(&outputStream, (uint16)size);
101 
102  //
103  // Write the payload part
104  //
105  sbgStreamBufferWriteBuffer(&outputStream, pData, size);
106 
107  //
108  // Compute the CRC, we skip the two sync chars
109  //
110  frameCrc = sbgCrc16Compute(((uint8*)sbgStreamBufferGetLinkedBuffer(&outputStream)) + 2, sbgStreamBufferGetLength(&outputStream) - 2);
111 
112  //
113  // Write the CRC
114  //
115  sbgStreamBufferWriteUint16LE(&outputStream, frameCrc);
116 
117  //
118  // Write ETX char
119  //
121 
122  //
123  // The frame has been generated so send it
124  //
125  errorCode = sbgInterfaceWrite(pHandle->pLinkedInterface, sbgStreamBufferGetLinkedBuffer(&outputStream), sbgStreamBufferGetLength(&outputStream));
126  }
127  else
128  {
129  //
130  // Invalid input parameters
131  //
132  errorCode = SBG_INVALID_PARAMETER;
133  }
134 
135  return errorCode;
136 }
137 
152 SbgErrorCode sbgEComProtocolReceive(SbgEComProtocol *pHandle, uint8 *pMsgClass, uint8 *pMsg, void *pData, size_t *pSize, size_t maxSize)
153 {
154  SbgErrorCode errorCode = SBG_NOT_READY;
155  SbgStreamBuffer inputStream;
156  bool syncFound;
157  size_t payloadSize = 0;
158  uint16 frameCrc;
159  uint16 computedCrc;
160  size_t i;
161  size_t numBytesRead;
162  uint8 receivedMsgClass;
163  uint8 receivedMsg;
164  size_t payloadOffset;
165 
166  //
167  // Check input arguments
168  //
169  SBG_ASSERT(pHandle);
170 
171  //
172  // Set the return size to 0 in order to avoid possible bugs
173  //
174  if (pSize)
175  {
176  *pSize = 0;
177  }
178 
179  //
180  // Check if we can receive some new data (the receive buffer isn't full)
181  //
182  if (pHandle->rxBufferSize < SBG_ECOM_MAX_BUFFER_SIZE)
183  {
184  //
185  // First try to read as much data as we can
186  //
187  if (sbgInterfaceRead(pHandle->pLinkedInterface, pHandle->rxBuffer + pHandle->rxBufferSize, &numBytesRead, SBG_ECOM_MAX_BUFFER_SIZE - pHandle->rxBufferSize) == SBG_NO_ERROR)
188  {
189  //
190  // No error during reading so increment the number of bytes stored in the rx buffer
191  //
192  pHandle->rxBufferSize += numBytesRead;
193  }
194  }
195 
196  //
197  // We have read all available data and stored them into the rx buffer
198  // We will try to process all received data until we have found a valid frame.
199  //
200  while (pHandle->rxBufferSize > 0)
201  {
202  //
203  // For now, we haven't found any start of frame
204  //
205  syncFound = FALSE;
206 
207  //
208  // To find a valid start of frame we need at least 2 bytes in the reception buffer
209  //
210  if (pHandle->rxBufferSize >= 2)
211  {
212  //
213  // Try to find a valid start of frame by looking for SYNC_1 and SYNC_2 chars
214  //
215  for (i = 0; i < pHandle->rxBufferSize-1; i++)
216  {
217  //
218  // A valid start of frame should begin with SYNC and when STX chars
219  //
220  if ( (pHandle->rxBuffer[i] == SBG_ECOM_SYNC_1) && (pHandle->rxBuffer[i+1] == SBG_ECOM_SYNC_2) )
221  {
222  //
223  // We have found the sync char, test if we have dummy bytes at the begining of the frame
224  //
225  if (i > 0)
226  {
227  //
228  // Remove all dumy received bytes before the begining of the frame
229  //
230  memmove(pHandle->rxBuffer, pHandle->rxBuffer+i, pHandle->rxBufferSize-i);
231  pHandle->rxBufferSize = pHandle->rxBufferSize-i;
232  }
233 
234  //
235  // The sync has been found
236  //
237  syncFound = TRUE;
238  break;
239  }
240  }
241  }
242 
243  //
244  // Check if a valid start of frame has been found
245  //
246  if (syncFound)
247  {
248  //
249  // A valid start of frame has been found, try to extract the frame if we have at least a whole frame.
250  //
251  if (pHandle->rxBufferSize < 8)
252  {
253  //
254  // Don't have enough data for a valid frame
255  //
256  return SBG_NOT_READY;
257  }
258 
259  //
260  // Initialize an input stream buffer to parse the received frame
261  //
262  sbgStreamBufferInitForRead(&inputStream, pHandle->rxBuffer, pHandle->rxBufferSize);
263 
264  //
265  // Skip both the Sync 1 and Sync 2 chars
266  //
267  sbgStreamBufferSeek(&inputStream, sizeof(uint8)*2, SB_SEEK_CUR_INC);
268 
269  //
270  // Read the command
271  //
272  receivedMsg = sbgStreamBufferReadUint8LE(&inputStream);
273  receivedMsgClass = sbgStreamBufferReadUint8LE(&inputStream);
274 
275  //
276  // Read the payload size
277  //
278  payloadSize = (uint16)sbgStreamBufferReadUint16LE(&inputStream);
279 
280  //
281  // Check that the payload size is valid
282  //
283  if (payloadSize <= SBG_ECOM_MAX_PAYLOAD_SIZE)
284  {
285  //
286  // Check if we have received the whole frame
287  //
288  if (pHandle->rxBufferSize < payloadSize+9)
289  {
290  //
291  // Don't have received the whole frame
292  //
293  return SBG_NOT_READY;
294  }
295 
296  //
297  // We should have the whole frame so for now, skip the payload part but before store the current cursor
298  //
299  payloadOffset = sbgStreamBufferTell(&inputStream);
300  sbgStreamBufferSeek(&inputStream, payloadSize, SB_SEEK_CUR_INC);
301 
302  //
303  // Read the frame CRC
304  //
305  frameCrc = sbgStreamBufferReadUint16LE(&inputStream);
306 
307  //
308  // Read and test the frame ETX
309  //
310  if (sbgStreamBufferReadUint8(&inputStream) == SBG_ECOM_ETX)
311  {
312  //
313  // Go back at the beginning of the payload part
314  //
315  sbgStreamBufferSeek(&inputStream, payloadOffset, SB_SEEK_SET);
316 
317  //
318  // We have a frame so return the received command if needed even if the CRC is still not validated
319  //
320  if (pMsg)
321  {
322  *pMsg = receivedMsg;
323  }
324  if (pMsgClass)
325  {
326  *pMsgClass = receivedMsgClass;
327  }
328 
329  //
330  // Compute the CRC of the received frame (Skip SYNC 1 and SYNC 2 chars)
331  //
332  computedCrc = sbgCrc16Compute(((uint8*)sbgStreamBufferGetLinkedBuffer(&inputStream)) + 2, payloadSize + 4);
333 
334  //
335  // Check if the received frame has a valid CRC
336  //
337  if (frameCrc == computedCrc)
338  {
339  //
340  // Extract the payload if needed
341  //
342  if (payloadSize > 0)
343  {
344  //
345  // Check if input parameters are valid
346  //
347  if ( (pData) && (pSize) )
348  {
349  //
350  // Check if we have enough space to store the payload
351  //
352  if (payloadSize <= maxSize)
353  {
354  //
355  // Copy the payload and return the payload size
356  //
357  *pSize = payloadSize;
358  memcpy(pData, sbgStreamBufferGetCursor(&inputStream), payloadSize);
359  errorCode = SBG_NO_ERROR;
360  }
361  else
362  {
363  //
364  // Not enough space to store the payload, we will just drop the received data
365  //
366  errorCode = SBG_BUFFER_OVERFLOW;
367  }
368  }
369  else
370  {
371  errorCode = SBG_NULL_POINTER;
372  }
373  }
374  else
375  {
376  //
377  // No payload but the frame has been read successfully
378  //
379  errorCode = SBG_NO_ERROR;
380  }
381  }
382  else
383  {
384  //
385  // We have an invalid frame CRC and we will directly return this error
386  //
387  errorCode = SBG_INVALID_CRC;
388  }
389 
390  //
391  // We have read a whole valid frame so remove it from the buffer
392  // First, test if the reception buffer contains more than just the current frame
393  //
394  if (pHandle->rxBufferSize > payloadSize+9)
395  {
396  //
397  // We remove the read frame but we keep the remaining data
398  //
399  pHandle->rxBufferSize = pHandle->rxBufferSize-(payloadSize+9);
400  memmove(pHandle->rxBuffer, pHandle->rxBuffer+payloadSize+9, pHandle->rxBufferSize);
401  }
402  else
403  {
404  //
405  // We have parsed the whole received buffer so just empty it
406  //
407  pHandle->rxBufferSize = 0;
408  }
409 
410  //
411  // We have at least found a complete frame
412  //
413  return errorCode;
414  }
415  }
416 
417  //
418  // Frame size invalid or the found frame is invalid so we should have incorrectly detected a start of frame.
419  // Remove the SYNC 1 and SYNC 2 chars to retry to find a new frame
420  //
421  pHandle->rxBufferSize -= 2;
422  memmove(pHandle->rxBuffer, pHandle->rxBuffer+2, pHandle->rxBufferSize);
423  }
424  else
425  {
426  //
427  // Unable to find a valid start of frame so check if the last byte is a SYNC char in order to keep it for next time
428  //
429  if (pHandle->rxBuffer[pHandle->rxBufferSize-1] == SBG_ECOM_SYNC_1)
430  {
431  //
432  // Report the SYNC char and discard all other bytes in the buffer
433  //
434  pHandle->rxBuffer[0] = SBG_ECOM_SYNC_1;
435  pHandle->rxBufferSize = 1;
436  }
437  else
438  {
439  //
440  // Discard the whole buffer
441  //
442  pHandle->rxBufferSize = 0;
443  }
444 
445  //
446  // Unable to find a frame
447  //
448  return SBG_NOT_READY;
449  }
450  }
451 
452  //
453  // The whole buffer has been paresed and no valid frame has been found
454  //
455  return SBG_NOT_READY;
456 }
457 
458 //----------------------------------------------------------------------//
459 //- Frame generation to stream buffer -//
460 //----------------------------------------------------------------------//
461 
473 {
474  //
475  // Check input arguments
476  //
477  SBG_ASSERT(pOutputStream);
478 
479  //
480  // Go to the beginning of the stream to ease frame size computation
481  //
482  sbgStreamBufferSeek(pOutputStream, 0, SB_SEEK_SET);
483 
484  //
485  // Write the header
486  //
489 
490  //
491  // Write the message ID and class
492  //
493  sbgStreamBufferWriteUint8LE(pOutputStream, msg);
494  sbgStreamBufferWriteUint8LE(pOutputStream, msgClass);
495 
496  //
497  // For now, we don't know the payload size so skip it
498  //
499  return sbgStreamBufferSeek(pOutputStream, sizeof(uint16), SB_SEEK_CUR_INC);
500 }
501 
508 {
509  SbgErrorCode errorCode;
510  size_t payloadSize;
511  size_t currentPos;
512  uint16 frameCrc;
513 
514  //
515  // Check input arguments
516  //
517  SBG_ASSERT(pOutputStream);
518 
519  //
520  // Test if any error has occurred on the stream first
521  //
522  errorCode = sbgStreamBufferGetLastError(pOutputStream);
523 
524  //
525  // Is the stream buffer error free ?
526  //
527  if (errorCode == SBG_NO_ERROR)
528  {
529  //
530  // Compute the payload size (written data minus the header)
531  //
532  payloadSize = sbgStreamBufferGetLength(pOutputStream) - 6;
533 
534  //
535  // Test that the payload size is valid
536  //
537  if (payloadSize <= SBG_ECOM_MAX_PAYLOAD_SIZE)
538  {
539  //
540  // Backup the current cursor position
541  //
542  currentPos = sbgStreamBufferTell(pOutputStream);
543 
544  //
545  // Goto the payload size field
546  //
547  sbgStreamBufferSeek(pOutputStream, 4, SB_SEEK_SET);
548 
549  //
550  // Write the payload size
551  //
552  sbgStreamBufferWriteUint16LE(pOutputStream, (uint16)payloadSize);
553 
554  //
555  // Go back to the previous position
556  //
557  sbgStreamBufferSeek(pOutputStream, currentPos, SB_SEEK_SET);
558 
559  //
560  // Compute the 16 bits CRC on the whole frame except Sync 1 and Sync 2
561  //
562  frameCrc = sbgCrc16Compute((uint8*)sbgStreamBufferGetLinkedBuffer(pOutputStream) + 2, payloadSize + 4);
563 
564  //
565  // Append the CRC
566  //
567  sbgStreamBufferWriteUint16LE(pOutputStream, frameCrc);
568 
569  //
570  // Append the ETX
571  //
572  errorCode = sbgStreamBufferWriteUint8LE(pOutputStream, SBG_ECOM_ETX);
573  }
574  else
575  {
576  //
577  // Invalid payload size
578  //
579  errorCode = SBG_BUFFER_OVERFLOW;
580  }
581  }
582  else
583  {
584  //
585  // Notify error
586  //
587  SBG_LOG_ERROR(errorCode, "Unable to finalize frame because of an error on Stream Buffer");
588  }
589 
590  return errorCode;
591 }
SbgInterface * pLinkedInterface
SBG_INLINE SbgErrorCode sbgStreamBufferInitForRead(SbgStreamBuffer *pHandle, const void *pLinkedBuffer, size_t bufferSize)
SBG_INLINE SbgErrorCode sbgStreamBufferSeek(SbgStreamBuffer *pHandle, size_t offset, SbgSBSeekOrigin origin)
SbgErrorCode sbgEComFinalizeFrameGeneration(SbgStreamBuffer *pOutputStream)
#define SBG_ECOM_ETX
#define TRUE
Definition: sbgDefines.h:39
SBG_INLINE uint16 sbgStreamBufferReadUint16LE(SbgStreamBuffer *pHandle)
uint16 sbgCrc16Compute(const void *pData, size_t dataSize)
Definition: sbgCrc.c:243
SBG_INLINE SbgErrorCode sbgStreamBufferInitForWrite(SbgStreamBuffer *pHandle, void *pLinkedBuffer, size_t bufferSize)
SbgErrorCode sbgEComProtocolInit(SbgEComProtocol *pHandle, SbgInterface *pInterface)
uint8 rxBuffer[SBG_ECOM_MAX_BUFFER_SIZE]
#define SBG_ECOM_SYNC_1
SBG_INLINE SbgErrorCode sbgInterfaceWrite(SbgInterface *pHandle, const void *pBuffer, size_t bytesToWrite)
Definition: sbgInterface.h:190
SbgErrorCode sbgEComProtocolSend(SbgEComProtocol *pHandle, uint8 msgClass, uint8 msg, const void *pData, size_t size)
#define sbgStreamBufferWriteUint8LE
SBG_INLINE void * sbgStreamBufferGetLinkedBuffer(SbgStreamBuffer *pHandle)
SbgErrorCode sbgEComProtocolReceive(SbgEComProtocol *pHandle, uint8 *pMsgClass, uint8 *pMsg, void *pData, size_t *pSize, size_t maxSize)
#define NULL
Definition: sbgDefines.h:43
SBG_INLINE SbgErrorCode sbgStreamBufferWriteBuffer(SbgStreamBuffer *pHandle, const void *pBuffer, size_t numBytesToWrite)
SBG_INLINE size_t sbgStreamBufferTell(SbgStreamBuffer *pHandle)
SBG_INLINE SbgErrorCode sbgStreamBufferWriteUint16LE(SbgStreamBuffer *pHandle, uint16 value)
#define sbgStreamBufferReadUint8LE
SbgErrorCode sbgEComStartFrameGeneration(SbgStreamBuffer *pOutputStream, uint8 msgClass, uint8 msg)
This file provides CRC-32 and CRC-16 methods.
SBG_INLINE SbgErrorCode sbgInterfaceRead(SbgInterface *pHandle, void *pBuffer, size_t *pReadBytes, size_t bytesToRead)
Definition: sbgInterface.h:212
unsigned char uint8
Definition: sbgTypes.h:56
#define SBG_ASSERT(expression)
Definition: sbgDebug.h:52
SBG_INLINE size_t sbgStreamBufferGetLength(SbgStreamBuffer *pHandle)
SBG_INLINE uint8 sbgStreamBufferReadUint8(SbgStreamBuffer *pHandle)
#define SBG_LOG_ERROR(errorCode, format,...)
Definition: sbgDebug.h:63
#define FALSE
Definition: sbgDefines.h:35
SbgErrorCode sbgEComProtocolClose(SbgEComProtocol *pHandle)
unsigned short uint16
Definition: sbgTypes.h:57
Implementation of the Ekinox binary communication protocol. You can access low-level communication w...
SBG_INLINE void * sbgStreamBufferGetCursor(SbgStreamBuffer *pHandle)
#define SBG_ECOM_MAX_PAYLOAD_SIZE
enum _SbgErrorCode SbgErrorCode
#define SBG_ECOM_SYNC_2
SBG_INLINE SbgErrorCode sbgStreamBufferGetLastError(SbgStreamBuffer *pHandle)
#define SBG_ECOM_MAX_BUFFER_SIZE


sbg_driver
Author(s):
autogenerated on Sun Jan 27 2019 03:42:20