SCOM Serial Communication Protocol  0.5.2
scom.c
Go to the documentation of this file.
1 
10 #define HAL_LOG_CHANNEL SCOM
11 
12 #include "hal.h"
13 #include "scom.h"
14 #include "scom_crc.h"
15 #include <string.h>
16 #include <stdbool.h>
17 
18 #ifndef SCOM_MAX_FRAME_REPEAT
19 #define SCOM_MAX_FRAME_REPEAT 2
21 #endif
22 
23 #ifndef SCOM_ACCESS_GUARD_TIMEOUT
24 
25 #define SCOM_ACCESS_GUARD_TIMEOUT 5000
26 #endif
27 
37 static uint32_t SCOM_GetDeltaTime(const uint32_t t1, const uint32_t t2);
38 
47 static void SCOM_ConnectivityCheck(SCOMDataLinkDesc* const scom);
48 
59 static void SCOM_ReceiverTimeOutCheck(SCOMDataLinkDesc* const scom);
60 
69 static uint8_t SCOM_GetNextFrameNumber(SCOMDataLinkDesc* const scom);
70 
79 static void SCOM_TransmitFrame(SCOMDataLink scom, SCOMFrameQueueItem *frameQueueItem);
80 
90 static void SCOM_WriteFrameToIODevice(SCOMDataLink scom, SCOMFrameQueueItem *frameQueueItem);
91 
103 static SCOMResult SCOM_RetransmitFrame(SCOMDataLink scom, SCOMFrameQueueItem *frameQueueItem);
104 
112 static SCOMResult SCOM_ReceiveFrame(SCOMDataLink scom);
113 
121 static void SCOM_ProcessReceivedFrame(SCOMDataLink scom);
122 
130 static void SCOM_SendACK(SCOMDataLink scom);
131 
139 static SCOMResult SCOM_ReceiveACK(SCOMDataLink scom);
140 
141 
142 
143 // -----------------------------------------------------------------------------
144 // SCOM_Create
145 // -----------------------------------------------------------------------------
147 #ifndef SCOM_DO_NOT_USE_HEAP
148  SCOMDataLinkDesc* const scom = (SCOMDataLinkDesc*)HEAP_Alloc(sizeof(SCOMDataLinkDesc));
149  if (scom != NULL) {
150  *scom = (SCOMDataLinkDesc){0};
151  return scom;
152  }
153 #endif
154  return NULL;
155 } /* SCOM_Create */
156 
157 
158 // -----------------------------------------------------------------------------
159 // SCOM_Destroy
160 // -----------------------------------------------------------------------------
161 void SCOM_Destroy(SCOMDataLinkDesc* const scom) {
162  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
163 #ifndef SCOM_DO_NOT_USE_HEAP
164  HEAP_Free(scom);
165 #endif
166  }
167 } /* SCOM_Destroy */
168 
169 
170 
171 // -----------------------------------------------------------------------------
172 // SCOM_CreateFrameBuffer
173 // -----------------------------------------------------------------------------
174 SCOMFrameBuffer* SCOM_CreateFrameBuffer(size_t rxBuffSize, size_t txBuffSize) {
175 #ifndef SCOM_DO_NOT_USE_HEAP
176 
177  typedef struct {
178  SCOMFrameQueueItem* pool;
179  SCOMFrameQueueItem* head;
180  size_t size;
181  OSMutex lock;
182  } SCOMFrameQueuePrivate;
183 
184  SCOMFrameBuffer *frameBuffer;
185  SCOMFrameQueuePrivate *rxQueuePool;
186  SCOMFrameQueuePrivate *txQueuePool;
187 
188  const size_t rxBuffSizeToAlloc = sizeof(SCOMFrameQueueItem) * rxBuffSize;
189  const size_t txBuffSizeToAlloc = sizeof(SCOMFrameQueueItem) * txBuffSize;
190  const size_t frameBuffSizeToAlloc = sizeof(SCOMFrameBuffer);
191 
192  uint8_t *allocatedDataPtr = (uint8_t*)HEAP_Alloc(rxBuffSizeToAlloc + txBuffSizeToAlloc + frameBuffSizeToAlloc);
193 
194  frameBuffer = (SCOMFrameBuffer*)allocatedDataPtr;
195 
196  allocatedDataPtr += frameBuffSizeToAlloc;
197 
198  rxQueuePool = (SCOMFrameQueuePrivate*)&frameBuffer->rxFrameQueue;
199  rxQueuePool->pool = (SCOMFrameQueueItem*)allocatedDataPtr;
200  rxQueuePool->size = rxBuffSize;
201 
202  allocatedDataPtr += rxBuffSizeToAlloc;
203 
204  txQueuePool = (SCOMFrameQueuePrivate*)&frameBuffer->txFrameQueue;
205  txQueuePool->pool = (SCOMFrameQueueItem*)allocatedDataPtr;
206  txQueuePool->size = txBuffSize;
207 
208  return frameBuffer;
209 #else
210  return NULL;
211 #endif
212 } /* SCOM_CreateFrameBuffer */
213 
214 
215 // -----------------------------------------------------------------------------
216 // SCOM_DestroyFrameBuffer
217 // -----------------------------------------------------------------------------
218 void SCOM_DestroyFrameBuffer(SCOMFrameBuffer* const frameBuffer) {
219  HAL_ASSERT_AND_EXECUTE(frameBuffer != NULL) {
220 #ifndef SCOM_DO_NOT_USE_HEAP
221  HEAP_Free(frameBuffer);
222 #endif
223  }
224 } /* SCOM_DestroyFrameBuffer */
225 
226 
227 // -----------------------------------------------------------------------------
228 // SCOM_Init
229 // -----------------------------------------------------------------------------
230 SCOMResult SCOM_Init(SCOMDataLink scom, IODevice iodevice, SCOMFrameBuffer *frameBuffer,
231  SCOMClockSource clockSource, uint32_t ackTimeout,
232  uint32_t deviceClass, uint8_t* deviceUID,
233  uint8_t numberOfServices, uint8_t* serviceIDs
234 )
235 {
236 #if defined SCOM_MAX_SERVICES && (SCOM_MAX_SERVICES > 0)
237  size_t serviceIndex;
238 #endif
239  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
240  HAL_ASSERT_AND_EXECUTE(iodevice != NULL) {
241  HAL_ASSERT_AND_EXECUTE(frameBuffer != NULL) {
242  HAL_ASSERT_AND_EXECUTE(clockSource != NULL) {
243  // todo critical section must be defined to avoid momentary undefined states
244  // clear the descriptor
245  *scom = (SCOMDataLinkDesc){0};
246 
247  scom->frameBuffer = frameBuffer; // bind transmit buffer
248  // initialize transmission queue
249  if (SCOMFrameQueue_Init(&scom->frameBuffer->txFrameQueue) == false) {
250  return SCOM_ERROR;
251  }
252  // initialize reception queue
253  if (SCOMFrameQueue_Init(&scom->frameBuffer->rxFrameQueue) == false) {
254  return SCOM_ERROR;
255  }
256 
257 
258 
259  scom->iodevice = iodevice; // bind IODevice object
260  scom->clockSource = clockSource; // bind clock source function
261  scom->timeout = ackTimeout; // save timeout
262  scom->lastFrameNumber = 0xFF;
263  scom->rxAck.frame.sync = 0xFF;
267 
268  scom->frameBeingTransmitted = NULL;
269 
270  // save identification data
271  scom->id.deviceClass = deviceClass;
272  if (deviceUID) {
273  memcpy(scom->id.deviceUID, deviceUID, sizeof(scom->id.deviceUID));
274  } else {
275  memset(scom->id.deviceUID, 0x00, sizeof(scom->id.deviceUID));
276  }
277  scom->id.version.verHi = SCOM_VER_HI;
278  scom->id.version.verLo = SCOM_VER_LO;
279 #ifdef SCOM_REVISION
281 #else
282  scom->id.version.revision = 0;
283 #endif
284  // save information about services
285  scom->serviceCount = 0;
286 #if defined SCOM_MAX_SERVICES && (SCOM_MAX_SERVICES > 0)
287 
288  if ((numberOfServices) && (serviceIDs)) {
289  // check if services fit into our list
290  HAL_ASSERT_AND_EXECUTE(numberOfServices <= SCOM_MAX_SERVICES) {
291  // save information about services
292  scom->serviceCount = numberOfServices;
293  memcpy(scom->id.serviceID, serviceIDs, numberOfServices);
294  // prepare service handler descriptors
295  for (serviceIndex = 0; serviceIndex < numberOfServices; serviceIndex++) {
296  scom->serviceHandler[serviceIndex].serviceID = serviceIDs[serviceIndex];
297  scom->serviceHandler[serviceIndex].handler = NULL;
298  }
299  }
300  }
301 #endif
302  // reset transmit counters
303  scom->txCounter = 0;
304  scom->multiCounter = 0;
305 
306  // reset connectivity check
307  scom->connectivityCheckPeriod = 0;
310  scom->lastConnectivityCheckTime = clockSource();
311 
312  // reset statistics
313  scom->stats.framesReceived = 0;
314  scom->stats.framesSent = 0;
315  scom->stats.retransmissionsReceived = 0;
316  scom->stats.retransmissionsSent = 0;
317 
318 #if SCOM_MAX_FRAME_FILTERS > 0
319  // Initialize frame filter list
320  LLST_Init(&scom->filters.list, scom->filters.pool, SCOM_MAX_FRAME_FILTERS);
321 #endif
322 
323 #if 1 == HAL_ENABLE_OS
324  // create guarding mutex
325  scom->accessGuard = OSMUTEX_Create();
326  if (!scom->accessGuard) {
327  return SCOM_ERROR;
328  }
329 #endif
330 
331  return SCOM_RESULT_OK;
332  }
333  }
334  }
335  }
336  return SCOM_ERROR;
337 } /* SCOM_Init */
338 
339 
340 // -----------------------------------------------------------------------------
341 // SCOM_Deinit
342 // -----------------------------------------------------------------------------
344  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
348 
349 #if 1 == HAL_ENABLE_OS
350  // Destroy guarding mutex
351  if (scom->accessGuard != NULL) {
352  OSMUTEX_Destroy(scom->accessGuard);
353  }
354 #endif
355  return SCOM_RESULT_OK;
356  }
357  return SCOM_RESULT_ERROR;
358 } /* SCOM_Deinit */
359 
360 // -----------------------------------------------------------------------------
361 // SCOM_InitAsMonitor
362 // -----------------------------------------------------------------------------
363 SCOMResult SCOM_InitAsMonitor(SCOMDataLink scom, IODevice iodevice, SCOMFrameBuffer *frameBuffer, SCOMClockSource clockSource, uint32_t ackTimeout) {
364  SCOMResult result = SCOM_Init(scom, iodevice, frameBuffer, clockSource, ackTimeout, 0, NULL, 0, NULL);
365  if (SCOM_RESULT_OK == result) {
366  // in monitor mode, sending ACKs is disabled
367  scom->monitorMode = true;
368  }
369  return result;
370 } /* SCOM_InitAsMonitor */
371 
372 
373 // -----------------------------------------------------------------------------
374 // SCOM_ProcThread
375 // -----------------------------------------------------------------------------
376 static int SCOM_ProcThread(void* param) {
377  SCOMDataLinkDesc* scom = (SCOMDataLinkDesc*)param;
378  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
379  while (true == OSTASK_IsAlive()) {
380  switch (SCOM_Proc(scom)) {
381  case SCOM_RESULT_OK:
382  // all OK!
383  break;
385  break;
387  break;
388  case SCOM_RESULT_ERROR:
389  break;
390  default:
391  break;
392  }
393  OS_Sleep(10);
394  }
395  }
396  return 0;
397 } /* SCOM_ProcThread */
398 
399 
400 // -----------------------------------------------------------------------------
401 // SCOM_RunProcessingThread
402 // -----------------------------------------------------------------------------
404  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
405 #if 1 == HAL_ENABLE_OS
406  // Create the thread
407  scom->procTask = OSTASK_Create(SCOM_ProcThread, HAL_OSTASK_JOINABLE | HAL_OSTASK_MORTAL, HAL_OSTASK_PRIORITY_NORMAL, 0, scom);
408  if(true == OSTASK_IsValid(scom->procTask)) {
409  return SCOM_RESULT_OK;
410  }
411 #endif
412  }
413  return SCOM_RESULT_ERROR;
414 } /* SCOM_RunProcessingThread */
415 
416 
417 // -----------------------------------------------------------------------------
418 // SCOM_StopProcessingThread
419 // -----------------------------------------------------------------------------
421  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
422 #if defined HAL_ENABLE_OS && (HAL_ENABLE_OS == 1)
423  // send the termination signal
424  OSTASK_Kill(scom->procTask);
425  // wait for the thread to finish
426  if (!OSTASK_Join(scom->procTask, 10000, NULL)) {
427  HAL_LOG_ERROR("Unable to stop SCOM processing thread");
428  }
429 #endif
430  }
431 } /* SCOM_StopProcessingThread */
432 
433 
434 // -----------------------------------------------------------------------------
435 // SCOM_EnableConnectivityCheck
436 // -----------------------------------------------------------------------------
437 SCOMResult SCOM_EnableConnectivityCheck(SCOMDataLinkDesc* const scom, const uint32_t checkPeriod) {
438  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
439  HAL_ASSERT_AND_EXECUTE(checkPeriod > 0) {
440  scom->connectivityCheckPeriod = checkPeriod;
441  return SCOM_RESULT_OK;
442  }
443  }
444  return SCOM_RESULT_ERROR;
445 } /* SCOM_EnableConnectivityCheck */
446 
447 // -----------------------------------------------------------------------------
448 // SCOM_DisableConnectivityCheck
449 // -----------------------------------------------------------------------------
451  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
452  scom->connectivityCheckPeriod = 0;
453  return SCOM_RESULT_OK;
454  }
455  return SCOM_RESULT_ERROR;
456 } /* SCOM_DisableConnectivityCheck */
457 
458 // -----------------------------------------------------------------------------
459 // SCOM_GetConnectionState
460 // -----------------------------------------------------------------------------
462  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
463 #if 1 == HAL_ENABLE_OS
464  // before we proceed, acquire mutex guarding access to the SCOM object
465  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
466  SCOMConnectionState state = scom->connectionState;
467  OSMUTEX_Give(scom->accessGuard);
468  return state;
469  }
470 #else
471  return scom->connectionState;
472 #endif
474  }
475  return SCOM_RESULT_ERROR;
476 } /* SCOM_GetConnectionState */
477 
478 
479 // -----------------------------------------------------------------------------
480 // SCOM_GetIODevice
481 // -----------------------------------------------------------------------------
482 IODevice SCOM_GetIODevice(const SCOMDataLinkDesc* const scom) {
483  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
484  return scom->iodevice;
485  }
486  return NULL;
487 } /* SCOM_GetIODevice */
488 
489 
490 // -----------------------------------------------------------------------------
491 // SCOM_SendFrame
492 // -----------------------------------------------------------------------------
493 SCOMResult SCOM_SendFrame(SCOMDataLinkDesc* const scom, uint8_t framePriority, uint8_t frameType, const void* frameData, uint8_t frameDataSize) {
494  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
495  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
496  HAL_ASSERT_AND_EXECUTE((frameData != NULL && frameDataSize > 0) || (NULL == frameData && 0 == frameDataSize)) {
497  SCOMFrameQueueItem* const frameQueueItem = SCOMFrameQueue_Lock(&scom->frameBuffer->txFrameQueue); // Find empty frame
498  if (frameQueueItem != NULL) {
499  SCOMFrame* const frame = &frameQueueItem->frame;
500 
501  frame->sof = SCOM_SOF_CHARACTER;
502  frame->type = frameType;
503  frame->null = 0;
504  //clear old settings
505  frame->ctrl = 0;
506  SCOMFrame_SetPriority(frame, framePriority);
507  frame->size = frameDataSize;
508  if(frameDataSize > 0){
509  memcpy(&frame->payload.singleframe.data, frameData, frameDataSize);
510  }
511  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
512  if (true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
513  return SCOM_RESULT_OK;
514  }
515  } else {
516  // report overload error
517  //SCOM_REPORT_ERROR(SCOM_ERR__TX_OVERLOAD);
519  }
520  }
521  }
522  }
523  return SCOM_RESULT_ERROR;
524 } /* SCOM_SendFrame */
525 
526 
527 // -----------------------------------------------------------------------------
528 // SCOM_SendFrameWithoutAck
529 // -----------------------------------------------------------------------------
530 SCOMResult SCOM_SendFrameWithoutAck(SCOMDataLink scom, uint8_t framePriority, uint8_t frameType, const void* frameData, uint8_t frameDataSize) {
531  SCOMResult result = SCOM_ERROR;
532  SCOMFrameQueueItem *frameQueueItem;
533  SCOMFrame *frame;
534 
535  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
536  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
537 
538  // find empty frame
539  frameQueueItem = SCOMFrameQueue_Lock(&scom->frameBuffer->txFrameQueue);
540 
541  if (frameQueueItem) {
542  frame = &frameQueueItem->frame;
543 
544  frame->sof = SCOM_SOF_CHARACTER;
545  frame->type = frameType;
546  frame->null = 0;
547  //clear old settings
548  frame->ctrl = 0;
549  SCOMFrame_SetPriority(frame, framePriority);
550  // NO ACK!
551  SCOMFrame_SetAcknowledgement(frame, false);
552  frame->size = frameDataSize;
553  if(frameDataSize){
554  memcpy(&frame->payload.singleframe.data, frameData, frameDataSize);
555  }
556  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
557  if (true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
558  result = SCOM_RESULT_OK;
559  }
560  } else {
561  // report overload error
562  //SCOM_REPORT_ERROR(SCOM_ERR__TX_OVERLOAD);
564  }
565  }
566  }
567  return result;
568 
569 } /* SCOM_SendFrameWithoutAck */
570 
571 // -----------------------------------------------------------------------------
572 // SCOM_SendMultiFrame
573 // -----------------------------------------------------------------------------
574 SCOMResult SCOM_SendMultiFrame(SCOMDataLink scom, uint8_t framePriority, uint8_t frameType,
575  const void* frameData, uint32_t frameDataSize, SCOMMultiFrameDesc* multiFrameDesc)
576 {
577  SCOMResult result = SCOM_ERROR;
578  SCOMFrameQueueItem *frameQueueItem;
579  SCOMFrame *frame;
580 
581  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
582  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
583  HAL_ASSERT_AND_EXECUTE(multiFrameDesc != NULL) {
584  // search for free slot in TX buffer
585  frameQueueItem = SCOMFrameQueue_Lock(&scom->frameBuffer->txFrameQueue);
586 
587  if (frameQueueItem) {
588  frame = &frameQueueItem->frame;
589 
590  frame->sof = SCOM_SOF_CHARACTER;
591  frame->type = frameType;
592  frame->null = 0;
593  //clear old settings and set multiframe id bit
595  SCOMFrame_SetPriority(frame, framePriority);
596  frame->payload.multiframe.offset = multiFrameDesc->progress;
597  frame->payload.multiframe.total_size = frameDataSize;
598 
599  if (0 == multiFrameDesc->multi_id) {
600  // this is the first frame of the new multiframe, increase the multi counter
601  scom->multiCounter++;
602  // make sure the counter is not 0 (it is used as an non-zero id)
603  if (0 == scom->multiCounter) {
604  scom->multiCounter = 1;
605  }
606  // assign id to the frame
607  frame->payload.multiframe.multi_id = scom->multiCounter;
608  // save id in a multiFrameDesc descriptor
609  multiFrameDesc->multi_id = scom->multiCounter;
610  } else {
611  // multi id already assigned
612  frame->payload.multiframe.multi_id = multiFrameDesc->multi_id;
613  }
614 
615  if ((frameData) && (frameDataSize)) {
616  // calculate data size for this part
617  uint32_t size = frameDataSize - multiFrameDesc->progress;
618  if (size > SCOMFrame_GetMaxMultiframePayloadSize()) {
619  size = SCOMFrame_GetMaxMultiframePayloadSize();
620  }
621 
622  frame->size = (uint8_t)size;
623  memcpy(frame->payload.multiframe.data, ((uint8_t *)frameData) + multiFrameDesc->progress, size);
624 
625  // update progress
626  multiFrameDesc->progress += size;
627  }
628 
629  // mark that the frame is ready to be sent
630  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
631 
632  if(true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
633  result= SCOM_RESULT_OK;
634  }
635  } else {
636  // no free frame available at this moment
638  }
639  }
640  }
641  }
642 
643  return result;
644 
645 } /* SCOM_SendMultiFrame */
646 
647 // -----------------------------------------------------------------------------
648 // SCOM_SendAllocatedMultiFrame
649 // -----------------------------------------------------------------------------
651 {
652  SCOMResult result = SCOM_ERROR;
653  SCOMFrameQueueItem *frameQueueItem;
654 
655  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
656  HAL_ASSERT_AND_EXECUTE(frame != NULL) {
657  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
658  HAL_ASSERT_AND_EXECUTE(multiFrameDesc != NULL) {
659  // retrieve the corresponding item
660  frameQueueItem = SCOMFrameQueue_GetItemByFrame(&scom->frameBuffer->txFrameQueue, frame);
661  if (frameQueueItem) {
663  frame->null = 0;
664  frame->sof = SCOM_SOF_CHARACTER;
665  frame->payload.multiframe.offset = multiFrameDesc->progress;
666 
667  if (0 == multiFrameDesc->multi_id) {
668  // this is the first frame of the new multiframe, increase the multi counter
669  scom->multiCounter++;
670  // make sure the counter is not 0 (it is used as an non-zero id)
671  if (0 == scom->multiCounter) {
672  scom->multiCounter = 1;
673  }
674  // assign id to the frame
675  frame->payload.multiframe.multi_id = scom->multiCounter;
676  // save id in a multiFrameDesc descriptor
677  multiFrameDesc->multi_id = scom->multiCounter;
678  } else {
679  // multi id already assigned
680  frame->payload.multiframe.multi_id = multiFrameDesc->multi_id;
681  }
682 
683  // update progress
684  multiFrameDesc->progress += frame->size;
685 
686  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
687  if(true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
688  result = SCOM_RESULT_OK;
689  }
690  } else {
691  result = SCOM_FRAME_NOT_IN_BUFFER;
692  }
693  }
694  }
695  }
696  }
697 
698  return result;
699 
700 } // SCOM_SendAlocatedMultiFrame
701 
702 
703 // -----------------------------------------------------------------------------
704 // SCOM_AllocFrame
705 // -----------------------------------------------------------------------------
707  SCOMResult result = SCOM_ERROR;
708 
709  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
710  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
711  HAL_ASSERT_AND_EXECUTE(framePtr != NULL) {
712 
713  // find and lock empty frame
715 
716  if (frameQueueItem) {
717  *framePtr = &frameQueueItem->frame;
718  result = SCOM_RESULT_OK;
719  } else {
720  // report overload error
721  result = SCOM_TX_FULL;
722  }
723  }
724  }
725  }
726 
727  return result;
728 
729 } /* SCOM_AllocFrame */
730 
731 
732 // -----------------------------------------------------------------------------
733 // SCOM_SendAllocatedFrame
734 // -----------------------------------------------------------------------------
736 {
737  SCOMResult result = SCOM_ERROR;
738  SCOMFrameQueueItem *frameQueueItem;
739 
740  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
741  HAL_ASSERT_AND_EXECUTE(frame != NULL) {
742  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
743  // retrieve the corresponding item
744  frameQueueItem = SCOMFrameQueue_GetItemByFrame(&scom->frameBuffer->txFrameQueue, frame);
745  if (frameQueueItem) {
746  frame->sof = SCOM_SOF_CHARACTER;
747  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
748  frame->null = 0;
749  if(true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
750  result = SCOM_RESULT_OK;
751  }
752  } else {
753  result = SCOM_FRAME_NOT_IN_BUFFER;
754  }
755  }
756  }
757  }
758 
759  return result;
760 } /* SCOM_SendAllocatedFrame */
761 
762 
763 // -----------------------------------------------------------------------------
764 // SCOM_SendAllocatedFrameWithoutACK
765 // -----------------------------------------------------------------------------
767 {
768  SCOMResult result = SCOM_ERROR;
769  SCOMFrameQueueItem *frameQueueItem;
770 
771  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
772  HAL_ASSERT_AND_EXECUTE(frame != NULL) {
773  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
774  // retrieve the corresponding item
775  frameQueueItem = SCOMFrameQueue_GetItemByFrame(&scom->frameBuffer->txFrameQueue, frame);
776  if (frameQueueItem) {
777  frame->sof = SCOM_SOF_CHARACTER;
778  frameQueueItem->state = SCOM_FRAME_TX_READY_FOR_SEND;
779  frame->null = 0;
780  // NO ACK!
781  SCOMFrame_SetAcknowledgement(frame, false);
782  if(true == SCOMFrameQueue_Insert(&scom->frameBuffer->txFrameQueue, frameQueueItem)) {
783  result = SCOM_RESULT_OK;
784  }
785  } else {
786  result = SCOM_FRAME_NOT_IN_BUFFER;
787  }
788  }
789  }
790  }
791 
792  return result;
793 } /* SCOM_SendAllocatedFrameWithoutACK */
794 
795 
796 
797 
798 
799 // -----------------------------------------------------------------------------
800 // SCOM_SetFrameReceptionHandlerFunc
801 // -----------------------------------------------------------------------------
803  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
804 #if 1 == HAL_ENABLE_OS
805  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
806  scom->receptionHandler = frameReceptionFunc;
807  OSMUTEX_Give(scom->accessGuard);
808  return SCOM_RESULT_OK;
809  }
810 #else
811  scom->receptionHandler = frameReceptionFunc;
812  return SCOM_RESULT_OK;
813 #endif
814  }
815  return SCOM_RESULT_ERROR;
816 } /* SCOM_SetFrameReceptionHandlerFunc */
817 
818 
819 // -----------------------------------------------------------------------------
820 // SCOM_SetAckReceptionHandlerFunc
821 // -----------------------------------------------------------------------------
823  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
824 #if 1 == HAL_ENABLE_OS
825  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
826  scom->ackHandler = ackReceptionFunc;
827  OSMUTEX_Give(scom->accessGuard);
828  return SCOM_RESULT_OK;
829  }
830 #else
831  scom->ackHandler = ackReceptionFunc;
832  return SCOM_RESULT_OK;
833 #endif
834  }
835  return SCOM_RESULT_ERROR;
836 } /* SCOM_SetAckReceptionHandlerFunc */
837 
838 // -----------------------------------------------------------------------------
839 // SCOM_SetServiceHandler
840 // -----------------------------------------------------------------------------
841 SCOMResult SCOM_SetServiceHandler(SCOMDataLink scom, uint8_t serviceID, SCOMServiceHandler serviceHandlerFunc) {
842 #if SCOM_MAX_SERVICES > 0
843  size_t i;
844  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
845  for (i = 0; i < SCOM_MAX_SERVICES; i++) {
846  if (scom->serviceHandler[i].serviceID == serviceID) {
847  scom->serviceHandler[i].handler = serviceHandlerFunc;
848  return SCOM_RESULT_OK;
849  }
850  }
851  }
852 #endif
853  return SCOM_RESULT_ERROR;
854 } /* SCOM_SetServiceHandler */
855 
856 // -----------------------------------------------------------------------------
857 // SCOM_Proc
858 // -----------------------------------------------------------------------------
860 {
861  uint8_t byte;
862  bool repeat;
863  SCOMResult result = SCOM_ERROR;
864  uint32_t current_time;
865  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
866 
867 #if defined HAL_ENABLE_OS && (HAL_ENABLE_OS == 1)
868  // before we proceed, acquire mutex guarding access to the SCOM object
869  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
870 #endif
871 
872  do {
873  repeat = false;
874  switch(scom->rxState) {
876  if(IODEV_Read(scom->iodevice, &byte, 1, 0) >= 1){
877  switch(byte){
879  scom->rxState = SCOM_RX_ACK;
880  repeat = true;
881  break;
882  case SCOM_SOF_CHARACTER:
883  scom->rxState = SCOM_RX_FRAME;
884  repeat = true;
885  break;
886  case 255: // received sync character
887  repeat = true;
888  break;
889  default:
890  break;
891  }
892  }
893  break;
894  case SCOM_RX_ACK:
895  switch(SCOM_ReceiveACK(scom)){
896  case SCOM_RESULT_OK:
897  if (scom->frameBeingTransmitted) {
899  scom->lastConnectivityCheckTime = scom->clockSource(); // recieved valid ACK so no need to ping
900  scom->receptionTime = scom->clockSource(); //we recieved valid frame, so update timeout counter
901  // this ACK was expected,
902  HAL_LOG_INFO("Received valid ACK");
904  scom->frameBeingTransmitted = NULL;
905  } else {
906  HAL_LOG_WARNING("Received weird ACK, type: %" PRIu8, scom->rxAck.frame.type);
907 
908  }
909  }
910  // reset the receiver
912  break;
913  case SCOM_ERROR:
914  // reset the receiver
916  break;
917  default:
918  break;
919  }
920  break;
921  case SCOM_RX_FRAME:
922  // try to receive the frame
923  switch(SCOM_ReceiveFrame(scom)){
924  case SCOM_RESULT_OK:
925  // frame was received successfully
926  scom->receptionTime = scom->clockSource();
927 
928  // check if the frame should be acknowledged
930  // prepare ack frame
934  }
935  // process received frame
936  SCOM_ProcessReceivedFrame(scom);
937 
938  // reset the receiver
940  if ((scom->stats.framesSent + scom->stats.framesReceived) % 100 == 0) {
941  HAL_LOG_DEBUG("Current stats: tx=%" PRIu32 ", rx=%" PRIu32 ", txret=%" PRIu32 "rxret=%" PRIu32, scom->stats.framesSent, scom->stats.framesReceived, scom->stats.retransmissionsSent, scom->stats.retransmissionsReceived);
942  }
943  break;
944  case SCOM_ERROR:
945  // there was an error, cancel the frame
947  HAL_LOG_ERROR("Error in receiving frame");
948 
949  break;
950  default:
951  break;
952  }
953  break;
954  default:
955  // reset the receiver
957  break;
958  }
959  } while(repeat);
960 
961  // This code is responsible for sending frame
962 
963  // if packet was received send ack
965  SCOM_SendACK(scom);
966  }
967 
968  // get current time
969  current_time = scom->clockSource();
970 
971  if (scom->frameBeingTransmitted) {
972  // there is a frame being currently transmitted
973  if(SCOM_GetDeltaTime(current_time, scom->sendTime) > scom->timeout){
974  // ACK timeout! Proceed with the retransmission
975  if (SCOM_COMMUNICATION_ERROR == SCOM_RetransmitFrame(scom, scom->frameBeingTransmitted)) {
976  // unable to send out frame, cancel (error should be already reported)
977  scom->frameBeingTransmitted = NULL;
978  }
979  }
980  } else {
982  if (scom->frameBeingTransmitted) {
984  // set frame number
985  SCOMFrame_SetFrameNumber(&(scom->frameBeingTransmitted->frame), SCOM_GetNextFrameNumber(scom));
986  // transmit the frame
987  SCOM_TransmitFrame(scom, scom->frameBeingTransmitted);
988  // check if the frame is acknowledged
990  // the frame is not acknowledged, this is it when it comes to sending it
992  scom->frameBeingTransmitted = NULL;
993  }
994 
995  // check if we need to print out statistics
996  if ((scom->stats.framesSent + scom->stats.framesReceived) % 100 == 0) {
997  HAL_LOG_DEBUG("Current stats: tx=%" PRIu32 ", rx=%" PRIu32 ", txret=%" PRIu32 "rxret=%" PRIu32, scom->stats.framesSent, scom->stats.framesReceived, scom->stats.retransmissionsSent, scom->stats.retransmissionsReceived);
998  }
999  } else {
1000  // frame not ready to be transmitted
1001  scom->frameBeingTransmitted = NULL;
1002  }
1003  }
1004  }
1005 
1006  // Run connectivity check (if needed)
1007  SCOM_ConnectivityCheck(scom);
1008 
1009  // Check receiver timeout
1010  SCOM_ReceiverTimeOutCheck(scom);
1011 
1012  // Check for synchronization error condition
1014  result = SCOM_SYNCHRONIZATION_ERROR;
1015  }
1016 
1017  // Check for broken connection condition
1018  if (scom->connectionState == SCOM_CONNECTION_BROKEN) {
1019  result = SCOM_COMMUNICATION_ERROR;
1020  }
1021 
1022 #if defined HAL_ENABLE_OS && (HAL_ENABLE_OS == 1)
1023 
1024  // release mutex guarding access to the SCOM object
1025  OSMUTEX_Give(scom->accessGuard);
1026  }
1027 
1028 #endif
1029 
1030  // else all OK!
1032  result = SCOM_RESULT_OK;
1033  }
1034 
1035  } // DIAG0_ASSERT_AND_EXECUTE(SCOM_DIAG_CHANNEL, scom)
1036 
1037  return result;
1038 
1039 } /* SCOM_Proc */
1040 
1041 // -----------------------------------------------------------------------------
1042 // SCOM_IsBusy
1043 // -----------------------------------------------------------------------------
1045  SCOMFrameQueueItem *frame;
1046  // check if there is frame currently being transmitted
1047  if(scom->frameBeingTransmitted != NULL) {
1048  return true;
1049  }
1050  // check if there are frames waiting to be sent
1052  if (frame) {
1053  if (frame->state == SCOM_FRAME_TX_SENT || frame->state == SCOM_FRAME_EMPTY) {
1054  return false;
1055  } else {
1056  return true;
1057  }
1058  }
1059  return false;
1060 } /* SCOM_IsBusy */
1061 
1062 // -----------------------------------------------------------------------------
1063 // SCOM_GetReceivedFrame
1064 // -----------------------------------------------------------------------------
1066 {
1067  SCOMFrameQueueItem* frameQueueItem;
1068 
1069  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1070  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
1071 
1072  frameQueueItem = SCOMFrameQueue_GetFirstInQueue(&scom->frameBuffer->rxFrameQueue);
1073  if (frameQueueItem) {
1074  return &frameQueueItem->frame;
1075  }
1076  }
1077  }
1078  return NULL;
1079 
1080 } /* SCOM_GetReceivedFrame */
1081 
1082 
1083 // -----------------------------------------------------------------------------
1084 // SCOM_UnlockFrame
1085 // -----------------------------------------------------------------------------
1087 {
1088  SCOMFrameQueueItem* frameQueueItem;
1089 
1090  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1091  HAL_ASSERT_AND_EXECUTE(scom->frameBuffer != NULL) {
1092  // probably, the frame is from the reception queue (most common case)
1093  frameQueueItem = SCOMFrameQueue_GetItemByFrame(&scom->frameBuffer->rxFrameQueue, frame);
1094  if (frameQueueItem) {
1095  SCOMFrameQueue_Unlock(&scom->frameBuffer->rxFrameQueue, frameQueueItem);
1096  } else {
1097  // maybe the frame is then from the transmission queue
1099  }
1100  }
1101  }
1102 
1103 } /* SCOM_UnlockFrame */
1104 
1105 
1106 // -----------------------------------------------------------------------------
1107 // SCOM_GetStatistics
1108 // -----------------------------------------------------------------------------
1110  SCOMStatistics result = {0};
1111  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1112 #if 1 == HAL_ENABLE_OS
1113  // before we proceed, acquire mutex guarding access to the SCOM object
1114  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
1115 #endif
1116  result = scom->stats; // copy statistics from SCOM descriptor
1117 
1118 #if 1 == HAL_ENABLE_OS
1119  OSMUTEX_Give(scom->accessGuard);
1120  }
1121 #endif
1122 
1123  }
1124  return result;
1125 } /* SCOM_GetStatistics */
1126 
1127 
1128 // -----------------------------------------------------------------------------
1129 // SCOM_ResetStatistics
1130 // -----------------------------------------------------------------------------
1132  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1133 #if 1 == HAL_ENABLE_OS
1134  // before we proceed, acquire mutex guarding access to the SCOM object
1135  HAL_ASSERT_AND_EXECUTE(0 == OSMUTEX_Take(scom->accessGuard, SCOM_ACCESS_GUARD_TIMEOUT)) {
1136 #endif
1137  scom->stats = (SCOMStatistics) {0};
1138 
1139 #if 1 == HAL_ENABLE_OS
1140  OSMUTEX_Give(scom->accessGuard);
1141  }
1142 #endif
1143  }
1144 } /* SCOM_ResetStatistics */
1145 
1146 
1147 // -----------------------------------------------------------------------------
1148 // SCOM_GetDeltaTime
1149 // -----------------------------------------------------------------------------
1150 static uint32_t SCOM_GetDeltaTime(const uint32_t t1, const uint32_t t2) {
1151  return (t1 >= t2) ? (t1 - t2) : (UINT32_MAX - t2 + t1);
1152 } /* SCOM_GetDeltaTime */
1153 
1154 
1155 // -----------------------------------------------------------------------------
1156 // SCOM_ConnectivityCheck
1157 // -----------------------------------------------------------------------------
1158 static void SCOM_ConnectivityCheck(SCOMDataLinkDesc* const scom) {
1159  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1160  if (scom->connectivityCheckPeriod > 0) {
1161  const uint32_t currentTime = scom->clockSource();
1162  if (SCOM_GetDeltaTime(currentTime, scom->lastConnectivityCheckTime) > scom->connectivityCheckPeriod) {
1163  // connectivity check is needed
1164  HAL_LOG_INFO("Connectivity check (PING) scheduled");
1165  SCOMResult result = SCOM_SendFrame(scom, 0, SCOM_FRAMETYPE_PING, NULL, 0);
1166  if(SCOM_RESULT_OK == result) {
1168  } else {
1169  HAL_LOG_ERROR("Unable to send PING. SCOMResult: %d", result);
1170  }
1171  scom->lastConnectivityCheckTime = currentTime;
1172  }
1173  }
1174  }
1175 } /* SCOM_ConnectivityCheck */
1176 
1177 // -----------------------------------------------------------------------------
1178 // SCOM_ReceiverTimeOutCheck
1179 // -----------------------------------------------------------------------------
1180 static void SCOM_ReceiverTimeOutCheck(SCOMDataLinkDesc* const scom) {
1181  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1182  const uint32_t currentTime = scom->clockSource();
1183  if (SCOM_GetDeltaTime(currentTime, scom->receptionTime) > ((SCOM_MAX_FRAME_REPEAT + 1 )* scom->timeout)) {
1184  scom->lastFrameCrc = 0;
1185  scom->lastFrameNumber = 0xFF;
1186  }
1187  }
1188 } /* SCOM_ReceiverTimeOutCheck */
1189 
1190 // -----------------------------------------------------------------------------
1191 // SCOM_GetNextFrameNumber
1192 // -----------------------------------------------------------------------------
1193 static uint8_t SCOM_GetNextFrameNumber(SCOMDataLinkDesc* const scom) {
1194  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1195  scom->txCounter++;
1197  scom->txCounter = 0;
1198  }
1199  return (uint8_t)scom->txCounter;
1200  }
1201  return -1;
1202 } /* SCOM_GetNextFrameNumber */
1203 
1204 
1205 // -----------------------------------------------------------------------------
1206 // SCOM_TransmitFrame
1207 // -----------------------------------------------------------------------------
1208 static void SCOM_TransmitFrame(SCOMDataLinkDesc* const scom, SCOMFrameQueueItem *frameQueueItem) {
1209  if(frameQueueItem != NULL) {
1210  // get the actual SCOM frame
1211  SCOMFrame* frame = &frameQueueItem->frame;
1212  HAL_LOG_INFO("Starting sending [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1213 
1214  // this is a new transmission, reset the retransmission counter
1215  scom->retransmissionCounter = 0;
1216  // calculate frame CRC
1217  frame->crc = SCOMFrame_CalculateCRC(frame);
1218  // write the frame to the IODevice (physically send the frame)
1219  SCOM_WriteFrameToIODevice(scom, frameQueueItem);
1220 
1221  // update statistics
1222  scom->stats.framesSent++;
1223  }
1224 } /* SCOM_TransmitFrame */
1225 
1226 
1227 // -----------------------------------------------------------------------------
1228 // SCOM_RetransmitFrame
1229 // -----------------------------------------------------------------------------
1230 static SCOMResult SCOM_RetransmitFrame(SCOMDataLinkDesc* const scom, SCOMFrameQueueItem* const frameQueueItem) {
1231  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1232  HAL_ASSERT_AND_EXECUTE(frameQueueItem != NULL) {
1233  // ACK timeout!
1235  // mark retransmission
1236  scom->retransmissionCounter++;
1237  HAL_LOG_WARNING("Retransmission of [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", (&(frameQueueItem->frame))->type, SCOMFrame_GetPriority(&frameQueueItem->frame), (&(frameQueueItem->frame))->size);
1238 
1239  // write the frame into the IODevice (physically send the frame)
1240  SCOM_WriteFrameToIODevice(scom, frameQueueItem);
1241 
1242  // update statistics
1243  scom->stats.retransmissionsSent++;
1244 
1245  return SCOM_RESULT_OK;
1246  } else {
1247  // connection is lost
1249  // unblock the transmitter
1250  scom->retransmissionCounter = 0;
1251  scom->lastFrameNumber = 0xff;
1252  // discard the frame
1253  SCOMFrameQueue_Unlock(&scom->frameBuffer->txFrameQueue, frameQueueItem);
1254  // report an error
1255  //SCOM_REPORT_ERROR(SCOM_ERR__COMMUNICATION_ERROR);
1256 
1257  return SCOM_COMMUNICATION_ERROR;
1258  }
1259  }
1260  }
1261  return SCOM_RESULT_ERROR;
1262 } /* SCOM_RetransmitFrame */
1263 
1264 
1265 // -----------------------------------------------------------------------------
1266 // SCOM_WriteFrameToIODevice
1267 // -----------------------------------------------------------------------------
1268 static void SCOM_WriteFrameToIODevice(SCOMDataLinkDesc* const scom, SCOMFrameQueueItem* const frameQueueItem) {
1269  // the frame is sent in two parts to omit null field in frame structure.
1270  const size_t firstPartSize = sizeof(frameQueueItem->frame.sync) + sizeof(frameQueueItem->frame.sof) + SCOMFrame_GetPacketControlSize() - sizeof(frameQueueItem->frame.crc);
1271  // mark transmission time
1272  scom->sendTime = scom->clockSource();
1273  // write the frame into IODevice
1274  IODEV_Write(scom->iodevice, &frameQueueItem->frame, firstPartSize, 0);
1275  //omit null field
1276  IODEV_Write(scom->iodevice, &frameQueueItem->frame.crc, SCOMFrame_GetTotalFrameSize(&frameQueueItem->frame) - firstPartSize, 0);
1277 
1278  // mark that the frame is now awaiting ACK
1279  frameQueueItem->state = SCOM_FRAME_TX_WAIT_FOR_ACK;
1280 } /* SCOM_WriteFrameToIODevice */
1281 
1282 
1283 // -----------------------------------------------------------------------------
1284 // SCOM_ReceiveFrame
1285 // -----------------------------------------------------------------------------
1286 static SCOMResult SCOM_ReceiveFrame(SCOMDataLink scom) {
1287  SCOMFrame *frame;
1288  size_t available_bytes;
1289  //
1290  if(scom->frameBeingReceived == NULL || scom->frameBeingReceived->state == SCOM_FRAME_RX_RECEIVED){
1292  if(scom->frameBeingReceived == NULL) {
1293  HAL_LOG_INFO("SCOMFrameQueue_Lock failed in SCOM_ReceiveFrame");
1294  return SCOM_ERROR;
1295  }
1296  }
1297 
1298  frame = &scom->frameBeingReceived->frame;
1299 
1300  //get available bytes count
1301  available_bytes = IODEV_GetReadCount(scom->iodevice);
1302 
1303  //read frame control bytes
1305  // calculate size of packet control fields
1306  const uint8_t packetControlSize = SCOMFrame_GetPacketControlSize();
1307 
1308  if (available_bytes >= packetControlSize) {
1309 #if true == SCOM_RECEIVED_FRAME_TIMESTAMP
1310  frame->received_timestamp = scom->clockSource();
1311 #endif
1312  // the frame is received in to parts to omit null field
1313  IODEV_Read(scom->iodevice, &frame->ctrl, packetControlSize - sizeof(frame->crc), 0);
1314  //omit null field
1315  IODEV_Read(scom->iodevice, &frame->crc, sizeof(frame->crc), 0);
1316  available_bytes -= packetControlSize;
1317  // mark that we started receiving frame
1319 #if defined SCOM_RECEPTION_TIMEOUT_AFTER_FRAME_START
1320  // mark time of the last character received
1321  scom->receptionStartTime = scom->clockSource();
1322 #endif
1323  }
1324  }
1325 
1326  //receive packet data fields or multiframe control fields and data
1328  // calculate number of bytes to read
1329  uint8_t size_to_read;
1330  if(SCOMFrame_IsMultiframe(frame)){
1331  size_to_read = frame->size + sizeof(frame->payload.multiframe.multi_id) + sizeof(frame->payload.multiframe.offset) + sizeof(frame->payload.multiframe.total_size);
1332  } else {
1333  size_to_read = frame->size;
1334  }
1335 
1336  if(available_bytes >= size_to_read) {
1337  if(size_to_read){
1338  IODEV_Read(scom->iodevice, &frame->payload.multiframe.multi_id, size_to_read, 0);
1339  }
1340 
1341  //check CRC
1342  if(SCOMFrame_CalculateCRC(frame) == frame->crc){
1343 
1344 #if defined SCOM_HANDICAP && (SCOM_HANDICAP > 0)
1345  static int handicap_count = 0;
1346 
1347  handicap_count++;
1348  if (handicap_count >= SCOM_HANDICAP) {
1349  handicap_count = 0;
1350 
1351  // simulate a situation when the CRC is not matching
1352  HAL_LOG_INFO("Frame discarded by implicit handicap [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1353 
1354  // received frame is discarded
1356  return SCOM_ERROR;
1357  }
1358 #endif
1359 
1360  // mark that the frame is received completely
1362  return SCOM_RESULT_OK;
1363  } else {
1364  HAL_LOG_INFO("Frame discarded due to CRC mismatch [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1365  // received frame is discarded
1367  return SCOM_ERROR;
1368  }
1369  } else {
1370 #if defined SCOM_RECEPTION_TIMEOUT_AFTER_FRAME_START
1371  // not enough bytes to read, we must check timeout to ensure that a pending frame is not blocking the reception
1372  if (SCOM_GetDeltaTime(scom->clockSource(), scom->receptionStartTime) > SCOM_RECEPTION_TIMEOUT_AFTER_FRAME_START) {
1373  // received frame is discarded
1375  HAL_LOG_INFO("Frame discarded due to timeout after start of reception [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1376 
1377  return SCOM_ERROR;
1378  }
1379 #endif
1380 
1381  }
1382  }
1383 
1384  return SCOM_NO_FRAME;
1385 
1386 } /* SCOM_ReceiveFrame */
1387 
1388 // -----------------------------------------------------------------------------
1389 // SCOM_ProcessReceivedFrame
1390 // -----------------------------------------------------------------------------
1391 static bool SCOM_ProcessServiceFrame(SCOMDataLinkDesc* const scom) {
1392 #if SCOM_MAX_SERVICES > 0
1393  size_t i;
1394  // try to find service handler matching the frame
1395  for (i = 0; i < SCOM_MAX_SERVICES; i++) {
1396  if (scom->serviceHandler[i].serviceID == scom->frameBeingReceived->frame.type) {
1397  // found serviceID, check if hanlder exists
1398  if (scom->serviceHandler[i].handler) {
1399  // handler exists - run it
1400  HAL_LOG_DEBUG("Found service frame handler for serviceID=%d. Executing.", scom->serviceHandler[i].serviceID);
1401  scom->serviceHandler[i].handler(scom, &scom->frameBeingReceived->frame);
1402  return true;
1403  } else {
1404  // service exists but without handler
1405  return false;
1406  }
1407  }
1408  }
1409 #endif
1410  return false;
1411 }
1412 
1413 // -----------------------------------------------------------------------------
1414 // SCOM_ProcessReceivedFrame
1415 // -----------------------------------------------------------------------------
1416 static void SCOM_ProcessReceivedFrame(SCOMDataLinkDesc* const scom) {
1417 
1418  SCOMFrame *frame;
1419  bool frameProcessed;
1420 
1421  // This function is called when a valid frame has been received.
1422  // The frame is stored in scom->frameBeingReceived
1423 
1424  frame = &scom->frameBeingReceived->frame;
1425 
1426  // Now we check, if this frame is not a retransmission, we already received.
1427  // Two things happen when a retransmission takes place:
1428  // 1. frame crc is same
1429  // 2. frame counter is not incremented
1430  if ((scom->lastFrameNumber == SCOMFrame_GetFrameNumber(frame) && (scom->lastFrameCrc == frame->crc))) {
1431  HAL_LOG_WARNING("Frame retransmission detected [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1432  // update statistics
1434 
1435  // this frame is discarded, as it was already received, unless we're in monitor mode
1436  if (scom->monitorMode) {
1437  // monitor mode
1438  if (scom->receptionHandler) {
1439  scom->receptionHandler(scom, &scom->frameBeingReceived->frame);
1440  }
1441  } else {
1442  HAL_LOG_WARNING("Frame discarded [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1444  }
1445  } else {
1446  // first occurrence of this frame
1448  scom->lastFrameCrc = frame->crc;
1449 
1450  // update statistics
1451  scom->stats.framesReceived++;
1452  if(true == SCOMFrame_IsMultiframe(frame)) {
1453  HAL_LOG_INFO("Multi-frame received [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 ", mid=%" PRIu32 ", offs=%" PRIu32 ", totl=%" PRIu32 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size, frame->payload.multiframe.multi_id, frame->payload.multiframe.offset, frame->payload.multiframe.total_size);
1454  } else {
1455  HAL_LOG_INFO("Frame received [type=%" PRIu8 ", prio=%" PRIu8 ", size=%" PRIu8 "]", frame->type, SCOMFrame_GetPriority(frame), frame->size);
1456  }
1457 
1458  frameProcessed = true;
1459  // handle PING, PONG and IDENTIFY packets automatically, unless SCOM runs in monitor mode
1460  if (scom->monitorMode == false) {
1461  SCOMResult tempResult;
1462  // not in monitor mode
1463  switch (frame->type) {
1464  case SCOM_FRAMETYPE_PING:
1466  // answer automatically with PONG, sending back our own connectivity counter
1467  tempResult = SCOM_SendFrame(scom, SCOMFrame_GetPriority(frame), SCOM_FRAMETYPE_PONG,
1468  (const void*)&(scom->connectivityCheckIncommingCounter), sizeof(scom->connectivityCheckIncommingCounter));
1469 
1470  if(SCOM_RESULT_OK != tempResult) {
1471  HAL_LOG_WARNING("Unable to send PONG, result code=%d", tempResult);
1473  } else {
1474  HAL_LOG_INFO("Sending PONG with outgoingCounter=%" PRIu32, scom->connectivityCheckIncommingCounter);
1475  }
1476 
1477  break;
1478  case SCOM_FRAMETYPE_PONG:
1479  if (scom->connectivityCheckOutgoingCounter != *((uint32_t*)frame->payload.singleframe.data)) {
1481  // report an error
1482  //SCOM_REPORT_ERROR(SCOM_ERR__SYNCHRONIZATION_ERROR);
1483  HAL_LOG_CRITICAL("SYNCHRONIZATION ERROR, got PONG with %" PRIu32 ", expected incommingCounter=%" PRIu32, *((uint32_t*)frame->payload.singleframe.data), scom->connectivityCheckOutgoingCounter);
1484  }
1485  break;
1487  // answer automatically to IDENTIFY request (request means zero-length frame data size)
1488  if (frame->size == 0) {
1489  // test for a possible loopback
1490  const SCOMFrameQueueItem* const loopbackFrame = SCOMFrameQueue_GetFirstInQueue(&scom->frameBuffer->txFrameQueue);
1491  if (loopbackFrame && loopbackFrame->state == SCOM_FRAME_TX_WAIT_FOR_ACK && loopbackFrame->frame.type == SCOM_FRAMETYPE_IDENTIFY) {
1492  // we're receiving an IDENTIFY request, but the same request was just sent and we're waiting for response
1493  // this most probably indicates a loopback connection
1494  HAL_LOG_WARNING("Detected loopback connection");
1495  } else {
1496  // answer to IDENTIFY request
1498 
1499  if(SCOM_RESULT_OK != tempResult) {
1500  HAL_LOG_ERROR("Unable to send IDENTIFY confirmation, result code=%d", tempResult);
1501  } else {
1502  HAL_LOG_INFO("IDENTIFY confirmation sent");
1503  }
1504  }
1505  } else {
1506  // got IDENTIFY response - this needs to be processed by application
1507  frameProcessed = false;
1508  }
1509  break;
1510  default:
1511  frameProcessed = false;
1512  break;
1513  } // switch
1514 
1515  //unlock frame if was processed
1516  if(frameProcessed == true){
1517  //SCOM_UnlockFrame(scom, scom->frameBeingReceived);
1519  }
1520  }
1521 
1522  if (frameProcessed == false) {
1523  // frame has not yet been processed
1524  // try to process the frame as service frame
1525  if (!SCOM_ProcessServiceFrame(scom)) {
1526  // if this is not a service frame, process it like an ordinary one
1527  if (scom->receptionHandler) {
1528  // there is a reception handler - execute it
1530  HAL_LOG_INFO("Frame was processed and stored in reception queue");
1531  if (scom->receptionHandler(scom, &scom->frameBeingReceived->frame) == true) {
1532  HAL_LOG_INFO("Frame was processed and deleted");
1535  }
1536  } else {
1537  HAL_LOG_WARNING("Frame was processed but storing it in reception queue failed");
1539  }
1540  } else {
1541  // no reception handler - store frame
1543  HAL_LOG_WARNING("Reception handler is missing. Frame stored in reception queue");
1544  } else {
1545  HAL_LOG_WARNING("Reception handler is missing. Storing frame in reception queue failed");
1547  }
1548  }
1549  }
1550  }
1551  // either way we're done with the frame
1552  scom->frameBeingReceived = NULL;
1553 
1554  }
1555 
1556 } /* SCOM_ProcessReceivedFrame */
1557 
1558 
1559 // -----------------------------------------------------------------------------
1560 // SCOM_SendACK
1561 // -----------------------------------------------------------------------------
1562 static void SCOM_SendACK(SCOMDataLinkDesc* const scom) {
1563  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1564  // write ACK packet to IODevice
1565  IODEV_Write(scom->iodevice, &scom->txAck.frame, sizeof(SCOMAckFrame), 0);
1566  // reset ACK state
1567  scom->txAck.state = SCOM_FRAME_EMPTY;
1568  }
1569 } /* SCOM_SendACK */
1570 
1571 
1572 // -----------------------------------------------------------------------------
1573 // SCOM_ReceiveACK
1574 // -----------------------------------------------------------------------------
1575 static SCOMResult SCOM_ReceiveACK(SCOMDataLinkDesc* const scom) {
1576  HAL_ASSERT_AND_EXECUTE(scom != NULL) {
1577  const uint8_t ackSize = sizeof(SCOMAckFrame) - sizeof(scom->rxAck.frame.sync) - sizeof(scom->rxAck.frame.soack);
1578  if (IODEV_GetReadCount(scom->iodevice) >= ackSize) {
1579  IODEV_Read(scom->iodevice, &scom->rxAck.frame.ctrl, ackSize, 0);
1581  }
1582  return SCOM_NO_FRAME;
1583  }
1584  return SCOM_RESULT_ERROR;
1585 } /* SCOM_ReceiveACK */
1586 
1587 
uint16_t SCOMAckFrame_CalculateCRC(const SCOMAckFrame *const ackFrame)
Definition of multiframe descriptor structure.
Definition: scom.h:247
Main API file.
uint32_t multi_id
Definition: scom.h:248
SCOMFrameQueue rxFrameQueue
descriptor of the frame queue used for receiving
Definition: scom.h:67
uint8_t null
TODO: XOR from sof, ctrl, type, size.
Definition: scom_frame.h:61
SCOMConnectionState SCOM_GetConnectionState(const SCOMDataLinkDesc *const scom)
Definition: scom.c:461
SCOMResult SCOM_SetFrameReceptionHandlerFunc(SCOMDataLinkDesc *const scom, SCOMFrameReceptionHandler frameReceptionFunc)
Definition: scom.c:802
uint8_t sync
synchronization field: always 0xFF
Packet type definition: IDENTIFY.
Definition: scom_frame.h:49
bool SCOMFrame_IsAcknowledged(const SCOMFrame *const frame)
Definition: scom_frame.c:221
SCOMFrameQueue txFrameQueue
descriptor of the frame queue used for sending
Definition: scom.h:65
struct HAL_PACKED SCOMAckFrame
Definition of an SCOM acknowledgment frame.
SCOMVersion version
SCOM version record.
Definition: scom.h:89
SCOM version record.
Definition: scom.h:81
SCOMResult SCOM_Deinit(SCOMDataLinkDesc *const scom)
Definition: scom.c:343
Descriptor of the SCOM statistics.
Definition: scom.h:122
#define SCOM_MAX_SERVICES
Definition: doxygen.h:644
#define SCOM_ACCESS_GUARD_TIMEOUT
Definition: scom.c:25
uint32_t progress
multiframe id
Definition: scom.h:249
#define SCOM_FRAME_CTRL_FRAME_NUMBER_MASK
Definition: scom_frame.h:39
#define SCOM_VER_LO
Definition: scom.h:13
SCOMResult SCOM_SendMultiFrame(SCOMDataLink scom, uint8_t framePriority, uint8_t frameType, const void *frameData, uint32_t frameDataSize, SCOMMultiFrameDesc *multiFrameDesc)
Definition: scom.c:574
SCOMResult SCOM_SendAllocatedFrameWithoutACK(SCOMDataLink scom, SCOMFrame *frame)
Definition: scom.c:766
bool SCOMAckFrame_Initialize(SCOMAckFrame *const ackFrame, const SCOMFrame *const frame)
SCOMResult SCOM_SendFrame(SCOMDataLinkDesc *const scom, uint8_t framePriority, uint8_t frameType, const void *frameData, uint8_t frameDataSize)
Definition: scom.c:493
void SCOM_DestroyFrameBuffer(SCOMFrameBuffer *const frameBuffer)
Definition: scom.c:218
#define SCOM_DEVICE_INFO_LEN
Definition: scom.h:97
bool SCOMFrame_SetPriority(SCOMFrame *const frame, const uint8_t priority)
Definition: scom_frame.c:67
uint8_t deviceUID[16]
Device unique identifier.
Definition: scom.h:91
Definition of a single SCOM frame queue item.
SCOMFrameQueueItem * SCOMFrameQueue_GetItemByFrame(const SCOMFrameQueue *frameQueue, const SCOMFrame *frame)
Start of frame character.
IODevice SCOM_GetIODevice(const SCOMDataLinkDesc *const scom)
Definition: scom.c:482
Definition of SCOM CRC functions.
uint32_t retransmissionsReceived
Number of retransmissions detected when receiving frames.
Definition: scom.h:130
bool SCOMFrame_SetAcknowledgement(SCOMFrame *const frame, const bool ack)
Definition: scom_frame.c:192
void(* SCOMAckReceptionHandler)(SCOMDataLink scom, uint8_t frame_type)
Definition: scom.h:205
SCOMDataLinkDesc * SCOM_Create(void)
Definition: scom.c:146
SCOMResult SCOM_AllocFrame(SCOMDataLink scom, SCOMFrame **framePtr)
Definition: scom.c:706
SCOMFrameBuffer * SCOM_CreateFrameBuffer(size_t rxBuffSize, size_t txBuffSize)
Definition: scom.c:174
uint8_t type
frame type field
uint32_t received_timestamp
time stamp of received frame - value should be set as soon as possible
Definition: scom_frame.h:93
SCOMConnectionState
Possible SCOM connection states.
Definition: scom.h:108
#define SCOM_FRAME_CTRL_MULTI_ID_MASK
Definition: scom_frame.h:42
#define SCOM_SOF_CHARACTER
Definition: scom_frame.h:38
uint8_t size
frame type field
Definition: scom_frame.h:59
struct HAL_PACKED::@1::@3 multiframe
payload definition for a multi frame
SCOMResult
Definition: scom.h:211
bool SCOM_IsBusy(SCOMDataLink scom)
Definition: scom.c:1044
uint8_t soack
start of ACK frame field
struct SCOMDataLinkDesc SCOMDataLinkDesc
SCOM Data Link descriptor.
SCOMResult SCOM_Proc(SCOMDataLink scom)
Definition: scom.c:859
bool(* SCOMFrameReceptionHandler)(SCOMDataLink scom, SCOMFrame *frame)
Definition: scom.h:202
bool SCOMFrameQueue_Delete(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
SCOMResult SCOM_EnableConnectivityCheck(SCOMDataLinkDesc *const scom, const uint32_t checkPeriod)
Definition: scom.c:437
uint32_t retransmissionsSent
Number of retransmissions needed when sending frames.
Definition: scom.h:128
uint32_t deviceClass
Device class.
Definition: scom.h:90
bool SCOMAckFrame_IsValidAck(const SCOMAckFrame *const ackFrame, const SCOMFrame *const frame)
SCOMResult SCOM_InitAsMonitor(SCOMDataLink scom, IODevice iodevice, SCOMFrameBuffer *frameBuffer, SCOMClockSource clockSource, uint32_t ackTimeout)
Definition: scom.c:363
SCOMAckFrame frame
Definition: scom.h:117
struct SCOMFrameQueueItem SCOMFrameQueueItem
Type representing a SCOM frame queue item.
uint8_t ctrl
frame control field
#define SCOM_REVISION
Definition: scom.h:15
SCOMFrameState state
SCOM frame state.
SCOMResult SCOM_Init(SCOMDataLink scom, IODevice iodevice, SCOMFrameBuffer *frameBuffer, SCOMClockSource clockSource, uint32_t ackTimeout, uint32_t deviceClass, uint8_t *deviceUID, uint8_t numberOfServices, uint8_t *serviceIDs)
Definition: scom.c:230
bool SCOMFrameQueue_Init(SCOMFrameQueue *frameQueue)
SCOMFrameQueueItem * SCOMFrameQueue_Lock(SCOMFrameQueue *frameQueue)
SCOMFrameState state
ACK frame.
Definition: scom.h:118
uint8_t SCOMFrame_GetPriority(const SCOMFrame *const frame)
Definition: scom_frame.c:82
void SCOM_StopProcessingThread(SCOMDataLink scom)
Definition: scom.c:420
Packet type definition: PING.
Definition: scom_frame.h:47
uint16_t crc
crc field
bool SCOMFrameQueue_Append(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
uint16_t SCOMFrame_CalculateCRC(const SCOMFrame *const frame)
Definition: scom_frame.c:234
uint16_t revision
protocol revision
Definition: scom.h:84
uint8_t SCOMFrame_GetFrameNumber(const SCOMFrame *const frame)
Definition: scom_frame.c:108
SCOMResult SCOM_SendFrameWithoutAck(SCOMDataLink scom, uint8_t framePriority, uint8_t frameType, const void *frameData, uint8_t frameDataSize)
Definition: scom.c:530
#define SCOM_VER_HI
Definition: scom.h:12
OSTime(* SCOMClockSource)(void)
Definition: scom.h:74
uint32_t framesReceived
Number of frames that were received since the SCOM connection was opened. In case of multi-frames...
Definition: scom.h:126
uint32_t framesSent
Number of frames that were sent since the SCOM connection was opened. In case of multi-frames, each sub-frame is counted.
Definition: scom.h:124
Packet type definition: PONG.
Definition: scom_frame.h:48
void SCOM_UnlockFrame(SCOMDataLink scom, SCOMFrame *frame)
Definition: scom.c:1086
SCOMResult SCOM_DisableConnectivityCheck(SCOMDataLinkDesc *const scom)
Definition: scom.c:450
SCOMStatistics SCOM_GetStatistics(const SCOMDataLinkDesc *const scom)
Definition: scom.c:1109
union HAL_PACKED::@1 payload
payload field
struct HAL_PACKED::@1::@2 singleframe
payload definition for a single frame
uint8_t verHi
version high number
Definition: scom.h:82
SCOMResult SCOM_SendAllocatedMultiFrame(SCOMDataLink scom, SCOMFrame *frame, SCOMMultiFrameDesc *multiFrameDesc)
Definition: scom.c:650
bool SCOMFrame_IsMultiframe(const SCOMFrame *const frame)
Definition: scom_frame.c:208
void SCOM_ResetStatistics(SCOMDataLinkDesc *const scom)
Definition: scom.c:1131
uint8_t sof
synchronization field: always 0xFF
Definition: scom_frame.h:56
SCOMFrameQueueItem *const pool
Frame pool items.
bool SCOMFrame_SetFrameNumber(SCOMFrame *const frame, const uint8_t number)
Definition: scom_frame.c:93
void SCOMFrameQueue_Unlock(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frameQueueItem)
void(* SCOMServiceHandler)(SCOMDataLinkDesc *scom, SCOMFrame *frame)
Definition: scom.h:208
void SCOM_Destroy(SCOMDataLinkDesc *const scom)
Definition: scom.c:161
SCOMFrame * SCOM_GetReceivedFrame(SCOMDataLink scom)
Definition: scom.c:1065
#define SCOM_MAX_FRAME_REPEAT
Maximum number of retransmissions, before communication error is raised.
Definition: scom.c:20
SCOMFrameQueueItem * SCOMFrameQueue_GetFirstInQueue(SCOMFrameQueue *frameQueue)
SCOMResult SCOM_SendAllocatedFrame(SCOMDataLink scom, SCOMFrame *frame)
Definition: scom.c:735
SCOMResult SCOM_RunProcessingThread(SCOMDataLinkDesc *const scom)
Definition: scom.c:403
Definition of the frame buffer used by SCOM.
Definition: scom.h:63
SCOMFrame frame
SCOM frame.
SCOMResult SCOM_SetAckReceptionHandlerFunc(SCOMDataLinkDesc *const scom, SCOMAckReceptionHandler ackReceptionFunc)
Definition: scom.c:822
uint16_t SCOMFrame_GetTotalFrameSize(const SCOMFrame *const frame)
Definition: scom_frame.c:20
bool SCOMFrameQueue_Insert(SCOMFrameQueue *frameQueue, SCOMFrameQueueItem *frame)
uint8_t verLo
version low number
Definition: scom.h:83
#define SCOM_MAX_FRAME_FILTERS
Definition: doxygen.h:652
SCOMResult SCOM_SetServiceHandler(SCOMDataLink scom, uint8_t serviceID, SCOMServiceHandler serviceHandlerFunc)
Definition: scom.c:841
void SCOMFrameQueue_Deinit(SCOMFrameQueue *frameQueue)