1 /** ----------------------------------------------------------------------
2  *
3  * Copyright (C) 2016 ST Microelectronics S.A.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *
18  ----------------------------------------------------------------------*/
19 #define LOG_TAG "NfcHal"
20 
21 #include <hardware/nfc.h>
22 #include <pthread.h>
23 #include <semaphore.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "android_logmsg.h"
27 #include "halcore_private.h"
28 
29 extern int I2cWriteCmd(const uint8_t* x, size_t len);
30 extern void DispHal(const char* title, const void* data, size_t length);
31 
32 extern uint32_t ScrProtocolTraceFlag;  // = SCR_PROTO_TRACE_ALL;
33 
34 // HAL WRAPPER
35 static void HalStopTimer(HalInstance* inst);
36 
37 typedef struct {
38   struct nfc_nci_device nci_device;  // nci_device must be first struct member
39   // below declarations are private variables within HAL
40   nfc_stack_callback_t* p_cback;
41   nfc_stack_data_callback_t* p_data_cback;
42   HALHANDLE hHAL;
43 } st21nfc_dev_t;  // beware, is a duplication of structure in nfc_nci_st21nfc.c
44 
45 /**************************************************************************************************
46  *
47  *                                      Private API Declaration
48  *
49  **************************************************************************************************/
50 
51 static void* HalWorkerThread(void* arg);
52 static inline int sem_wait_nointr(sem_t* sem);
53 
54 static void HalOnNewUpstreamFrame(HalInstance* inst, const uint8_t* data,
55                                   size_t length);
56 static void HalTriggerNextDsPacket(HalInstance* inst);
57 static bool HalEnqueueThreadMessage(HalInstance* inst, ThreadMesssage* msg);
58 static bool HalDequeueThreadMessage(HalInstance* inst, ThreadMesssage* msg);
59 static HalBuffer* HalAllocBuffer(HalInstance* inst);
60 static HalBuffer* HalFreeBuffer(HalInstance* inst, HalBuffer* b);
61 static uint32_t HalSemWait(sem_t* pSemaphore, uint32_t timeout);
62 
63 /**************************************************************************************************
64  *
65  *                                      Public API Entry-Points
66  *
67  **************************************************************************************************/
68 
69 /**
70  * Callback of HAL Core protocol layer.
71  * Invoked by HAL worker thread according to if message is received from NCI
72  * stack or posted by
73  * I2C worker thread.
74  * <p>@param context NFC callbacks for control/data
75  * @param event Next HAL state machine action (send msg to I2C layer or report
76  * data/control/error
77  * to NFC task)
78  * @param length Configure if debug and trace allowed, trace level
79  */
HalCoreCallback(void * context,uint32_t event,const void * d,size_t length)80 void HalCoreCallback(void* context, uint32_t event, const void* d,
81                      size_t length) {
82   const uint8_t* data = (const uint8_t*)d;
83   uint8_t cmd = 'W';
84 
85   st21nfc_dev_t* dev = (st21nfc_dev_t*)context;
86 
87   switch (event) {
88     case HAL_EVENT_DSWRITE:
89       STLOG_HAL_V("!! got event HAL_EVENT_DSWRITE for %zu bytes\n", length);
90       DispHal("TX DATA", (data), length);
91 
92       // Send write command to IO thread
93       cmd = 'W';
94       I2cWriteCmd(&cmd, sizeof(cmd));
95       I2cWriteCmd((const uint8_t*)&length, sizeof(length));
96       I2cWriteCmd(data, length);
97       break;
98 
99     case HAL_EVENT_DATAIND:
100       STLOG_HAL_V("!! got event HAL_EVENT_DATAIND for %zu bytes\n", length);
101 
102       if ((length >= 3) && (data[2] != (length - 3))) {
103         STLOG_HAL_W(
104             "length is illogical. Header length is %d, packet length %zu\n",
105             data[2], length);
106       }
107 
108       dev->p_data_cback(length, (uint8_t*)data);
109       break;
110 
111     case HAL_EVENT_ERROR:
112       STLOG_HAL_E("!! got event HAL_EVENT_ERROR\n");
113       DispHal("Received unexpected HAL message !!!", data, length);
114       break;
115 
116     case HAL_EVENT_LINKLOST:
117       STLOG_HAL_E("!! got event HAL_EVENT_LINKLOST or HAL_EVENT_ERROR\n");
118 
119       dev->p_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_ERR_CMD_TIMEOUT);
120 
121       // Write terminate command
122       cmd = 'X';
123       I2cWriteCmd(&cmd, sizeof(cmd));
124       break;
125 
126     case HAL_EVENT_TIMER_TIMEOUT:
127       STLOG_HAL_D("!! got event HAL_EVENT_TIMER_TIMEOUT \n");
128       dev->p_cback(HAL_WRAPPER_TIMEOUT_EVT, HAL_NFC_STATUS_OK);
129       break;
130   }
131 }
132 
133 /**
134  * Connection to the HAL Core layer.
135  * Set-up HAL context and create HAL worker thread.
136  * <p>@param context NFC NCI device context, NFC callbacks for control/data, HAL
137  * handle
138  * @param callback HAL callback function pointer
139  * @param flags Configure if debug and trace allowed, trace level
140  */
HalCreate(void * context,HAL_CALLBACK callback,uint32_t flags)141 HALHANDLE HalCreate(void* context, HAL_CALLBACK callback, uint32_t flags) {
142   /*   bool halTraceMask = true;
143 
144      if (flags & HAL_FLAG_NO_DEBUG) {
145          halTraceMask = false;
146      }
147  */
148   STLOG_HAL_V("HalCreate enter\n");
149 
150   HalInstance* inst = (HalInstance*)calloc(1, sizeof(HalInstance));
151 
152   if (!inst) {
153     STLOG_HAL_E("!out of memory\n");
154     return NULL;
155   }
156 
157   // We need a semaphore to wakeup our protocol thread
158   if (0 != sem_init(&inst->semaphore, 0, 0)) {
159     STLOG_HAL_E("!sem_init failed\n");
160     free(inst);
161     return NULL;
162   }
163 
164   // We need a semaphore to manage buffers
165   if (0 != sem_init(&inst->bufferResourceSem, 0, NUM_BUFFERS)) {
166     STLOG_HAL_E("!sem_init failed\n");
167     sem_destroy(&inst->semaphore);
168     free(inst);
169     return NULL;
170   }
171 
172   // We need a semaphore to block upstream data indications
173   if (0 != sem_init(&inst->upstreamBlock, 0, 0)) {
174     STLOG_HAL_E("!sem_init failed\n");
175     sem_destroy(&inst->semaphore);
176     sem_destroy(&inst->bufferResourceSem);
177     free(inst);
178     return NULL;
179   }
180 
181   // Initialize remaining data-members
182   inst->context = context;
183   inst->callback = callback;
184   inst->flags = flags;
185   inst->freeBufferList = 0;
186   inst->pendingNciList = 0;
187   inst->nciBuffer = 0;
188   inst->ringReadPos = 0;
189   inst->ringWritePos = 0;
190   inst->timeout = HAL_SLEEP_TIMER_DURATION;
191 
192   inst->bufferData = (HalBuffer*)calloc(NUM_BUFFERS, sizeof(HalBuffer));
193   if (!inst->bufferData) {
194     STLOG_HAL_E("!failed to allocate memory\n");
195     sem_destroy(&inst->semaphore);
196     sem_destroy(&inst->bufferResourceSem);
197     sem_destroy(&inst->upstreamBlock);
198     free(inst);
199     return NULL;
200   }
201 
202   // Concatenate the buffers into a linked list for easy access
203   size_t i;
204   for (i = 0; i < NUM_BUFFERS; i++) {
205     HalBuffer* b = &inst->bufferData[i];
206     b->next = inst->freeBufferList;
207     inst->freeBufferList = b;
208   }
209 
210   if (0 != pthread_mutex_init(&inst->hMutex, 0)) {
211     STLOG_HAL_E("!failed to initialize Mutex \n");
212     sem_destroy(&inst->semaphore);
213     sem_destroy(&inst->bufferResourceSem);
214     sem_destroy(&inst->upstreamBlock);
215     free(inst->bufferData);
216     free(inst);
217     return NULL;
218   }
219 
220   // Spawn the thread
221   if (0 != pthread_create(&inst->thread, NULL, HalWorkerThread, inst)) {
222     STLOG_HAL_E("!failed to spawn workerthread \n");
223     sem_destroy(&inst->semaphore);
224     sem_destroy(&inst->bufferResourceSem);
225     sem_destroy(&inst->upstreamBlock);
226     pthread_mutex_destroy(&inst->hMutex);
227     free(inst->bufferData);
228     free(inst);
229     return NULL;
230   }
231 
232   STLOG_HAL_V("HalCreate exit\n");
233   return (HALHANDLE)inst;
234 }
235 
236 /**
237  * Disconnection of the HAL protocol layer.
238  * Send message to stop the HAL worker thread and wait for it to finish. Free
239  * resources.
240  * @param hHAL HAL handle
241  */
HalDestroy(HALHANDLE hHAL)242 void HalDestroy(HALHANDLE hHAL) {
243   HalInstance* inst = (HalInstance*)hHAL;
244   // Tell the thread that we want to finish
245   ThreadMesssage msg;
246   msg.command = MSG_EXIT_REQUEST;
247   msg.payload = 0;
248   msg.length = 0;
249 
250   HalEnqueueThreadMessage(inst, &msg);
251 
252   // Wait for thread to finish
253   pthread_join(inst->thread, NULL);
254 
255   // Cleanup and exit
256   sem_destroy(&inst->semaphore);
257   sem_destroy(&inst->upstreamBlock);
258   sem_destroy(&inst->bufferResourceSem);
259   pthread_mutex_destroy(&inst->hMutex);
260 
261   // Free resources
262   free(inst->bufferData);
263   free(inst);
264 
265   STLOG_HAL_V("HalDestroy done\n");
266 }
267 
268 /**
269  * Send an NCI message downstream to HAL protocol layer (DH->NFCC transfer).
270  * Block if more than NUM_BUFFERS (10) transfers are outstanding, otherwise will
271  * return immediately.
272  * @param hHAL HAL handle
273  * @param data Data message
274  * @param size Message size
HalSendDownstream(HALHANDLE hHAL,const uint8_t * data,size_t size)275  */ bool HalSendDownstream(HALHANDLE hHAL, const uint8_t* data, size_t size)
276 {
277   // Send an NCI frame downstream. will
278   HalInstance* inst = (HalInstance*)hHAL;
279 
280   if ((size <= MAX_BUFFER_SIZE) && (size > 0)) {
281     ThreadMesssage msg;
282     HalBuffer* b = HalAllocBuffer(inst);
283 
284     if (!b) {
285       // Should never be reachable
286       return false;
287     }
288 
289     memcpy(b->data, data, size);
290     b->length = size;
291 
292     msg.command = MSG_TX_DATA;
293     msg.payload = 0;
294     msg.length = 0;
295     msg.buffer = b;
296 
297     return HalEnqueueThreadMessage(inst, &msg);
298 
299   } else {
300     STLOG_HAL_E("HalSendDownstream size to large %zu instead of %d\n", size,
301                 MAX_BUFFER_SIZE);
302     return false;
303   }
304 }
305 
306 // HAL WRAPPER
307 /**
308  * Send an NCI message downstream to HAL protocol layer (DH->NFCC transfer).
309  * Block if more than NUM_BUFFERS (10) transfers are outstanding, otherwise will
310  * return immediately.
311  * @param hHAL HAL handle
312  * @param data Data message
313  * @param size Message size
314  */
HalSendDownstreamTimer(HALHANDLE hHAL,const uint8_t * data,size_t size,uint32_t duration)315 bool HalSendDownstreamTimer(HALHANDLE hHAL, const uint8_t* data, size_t size,
316                             uint32_t duration) {
317   // Send an NCI frame downstream. will
318   HalInstance* inst = (HalInstance*)hHAL;
319 
320   if ((size <= MAX_BUFFER_SIZE) && (size > 0)) {
321     ThreadMesssage msg;
322     HalBuffer* b = HalAllocBuffer(inst);
323 
324     if (!b) {
325       // Should never be reachable
326       return false;
327     }
328 
329     memcpy(b->data, data, size);
330     b->length = size;
331 
332     msg.command = MSG_TX_DATA_TIMER_START;
333     msg.payload = 0;
334     msg.length = duration;
335     msg.buffer = b;
336 
337     return HalEnqueueThreadMessage(inst, &msg);
338 
339   } else {
340     STLOG_HAL_E("HalSendDownstreamTimer size to large %zu instead of %d\n",
341                 size, MAX_BUFFER_SIZE);
342     return false;
343   }
344 }
345 
HalSendDownstreamTimer(HALHANDLE hHAL,uint32_t duration)346 bool HalSendDownstreamTimer(HALHANDLE hHAL, uint32_t duration) {
347   HalInstance* inst = (HalInstance*)hHAL;
348 
349   ThreadMesssage msg;
350 
351   msg.command = MSG_TIMER_START;
352   msg.payload = 0;
353   msg.length = duration;
354   msg.buffer = NULL;
355 
356   return HalEnqueueThreadMessage(inst, &msg);
357 }
358 /**
359  * Send an NCI message downstream to HAL protocol layer (DH->NFCC transfer).
360  * Block if more than NUM_BUFFERS (10) transfers are outstanding, otherwise will
361  * return immediately.
362  * @param hHAL HAL handle
363  * @param data Data message
364  * @param size Message size
365  */
HalSendDownstreamStopTimer(HALHANDLE hHAL)366 bool HalSendDownstreamStopTimer(HALHANDLE hHAL) {
367   // Send an NCI frame downstream. will
368   HalInstance* inst = (HalInstance*)hHAL;
369 
370   HalStopTimer(inst);
371   return 1;
372 }
373 
374 /**
375  * Send an NCI message upstream to NFC NCI layer (NFCC->DH transfer).
376  * @param hHAL HAL handle
377  * @param data Data message
378  * @param size Message size
379  */
HalSendUpstream(HALHANDLE hHAL,const uint8_t * data,size_t size)380 bool HalSendUpstream(HALHANDLE hHAL, const uint8_t* data, size_t size) {
381   HalInstance* inst = (HalInstance*)hHAL;
382   if ((size <= MAX_BUFFER_SIZE) && (size > 0)) {
383     ThreadMesssage msg;
384     msg.command = MSG_RX_DATA;
385     msg.payload = data;
386     msg.length = size;
387 
388     if (HalEnqueueThreadMessage(inst, &msg)) {
389       // Block until the protocol has taken a copy of the data
390       sem_wait_nointr(&inst->upstreamBlock);
391       return true;
392     }
393     return false;
394   } else {
395     STLOG_HAL_E("HalSendUpstream size to large %zu instead of %d\n", size,
396                 MAX_BUFFER_SIZE);
397     return false;
398   }
399 }
400 
401 /**************************************************************************************************
402  *
403  *                                      Private API Definition
404  *
405  **************************************************************************************************/
406 /*
407  * Get current time stamp
408  */
HalGetTimestamp(void)409 struct timespec HalGetTimestamp(void) {
410   struct timespec tm;
411   clock_gettime(CLOCK_REALTIME, &tm);
412   return tm;
413 }
414 
HalTimeDiffInMs(struct timespec start,struct timespec end)415 int HalTimeDiffInMs(struct timespec start, struct timespec end) {
416   struct timespec temp;
417   if ((end.tv_nsec - start.tv_nsec) < 0) {
418     temp.tv_sec = end.tv_sec - start.tv_sec - 1;
419     temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
420   } else {
421     temp.tv_sec = end.tv_sec - start.tv_sec;
422     temp.tv_nsec = end.tv_nsec - start.tv_nsec;
423   }
424 
425   return (temp.tv_nsec / 1000000) + (temp.tv_sec * 1000);
426 }
427 
428 /**
429  * Determine the next shortest sleep to fulfill the pending timer requirements.
430  * @param inst HAL instance
431  * @param now timespec structure for time definition
432  */
HalCalcSemWaitingTime(HalInstance * inst,struct timespec * now)433 static uint32_t HalCalcSemWaitingTime(HalInstance* inst, struct timespec* now) {
434   // Default to infinite wait time
435   uint32_t result = OS_SYNC_INFINITE;
436 
437   if (inst->timer.active) {
438     int delta =
439         inst->timer.duration - HalTimeDiffInMs(inst->timer.startTime, *now);
440 
441     if (delta < 0) {
442       // If we have a timer that has already expired, pick a zero wait time
443       result = 0;
444 
445     } else if ((uint32_t)delta < result) {
446       // Smaller time difference? If so take it
447       result = delta;
448     }
449   }
450 
451   if (result != OS_SYNC_INFINITE) {
452     // Add one millisecond on top of that, so the waiting semaphore will time
453     // out just a moment
454     // after the timer should expire
455     result += 1;
456   }
457 
458   return result;
459 }
460 
461 /**************************************************************************************************
462  *
463  *                                     Timer Management
464  *
465  **************************************************************************************************/
466 
HalStopTimer(HalInstance * inst)467 static void HalStopTimer(HalInstance* inst) {
468   inst->timer.active = false;
469   STLOG_HAL_D("HalStopTimer \n");
470 }
471 
HalStartTimer(HalInstance * inst,uint32_t duration)472 static void HalStartTimer(HalInstance* inst, uint32_t duration) {
473   STLOG_HAL_D("HalStartTimer \n");
474   inst->timer.startTime = HalGetTimestamp();
475   inst->timer.active = true;
476   inst->timer.duration = duration;
477 }
478 
479 /**************************************************************************************************
480  *
481  *                                     Thread Message Queue
482  *
483  **************************************************************************************************/
484 
485 /**
486  * Write message pointer to small ring buffer for queuing HAL messages.
487  * @param inst HAL instance
488  * @param msg Message to send
489  * @return true if message properly copied in ring buffer
490  */
HalEnqueueThreadMessage(HalInstance * inst,ThreadMesssage * msg)491 static bool HalEnqueueThreadMessage(HalInstance* inst, ThreadMesssage* msg) {
492   // Put a message to the queue
493   int nextWriteSlot;
494   bool result = true;
495 
496   pthread_mutex_lock(&inst->hMutex);
497 
498   nextWriteSlot = inst->ringWritePos + 1;
499 
500   if (nextWriteSlot == HAL_QUEUE_MAX) {
501     nextWriteSlot = 0;
502   }
503 
504   // Check that we don't overflow the queue entries
505   if (nextWriteSlot == inst->ringReadPos) {
506     STLOG_HAL_E("HAL thread message ring: RNR (implement me!!)");
507     result = false;
508   }
509 
510   if (result) {
511     // inst->ring[nextWriteSlot] = *msg;
512     memcpy(&(inst->ring[nextWriteSlot]), msg, sizeof(ThreadMesssage));
513     inst->ringWritePos = nextWriteSlot;
514   }
515 
516   pthread_mutex_unlock(&inst->hMutex);
517 
518   if (result) {
519     sem_post(&inst->semaphore);
520   }
521 
522   return result;
523 }
524 
525 /**
526  * Remove message pointer from stored ring buffer.
527  * @param inst HAL instance
528  * @param msg Message received
529  * @return true if there is a new message to pull, false otherwise.
530  */
HalDequeueThreadMessage(HalInstance * inst,ThreadMesssage * msg)531 static bool HalDequeueThreadMessage(HalInstance* inst, ThreadMesssage* msg) {
532   int nextCmdIndex;
533   bool result = true;
534   // New data available
535   pthread_mutex_lock(&inst->hMutex);
536 
537   // Get new timer read index
538   nextCmdIndex = inst->ringReadPos + 1;
539 
540   if (nextCmdIndex == HAL_QUEUE_MAX) {
541     nextCmdIndex = 0;
542   }
543   // check if ring buffer is empty
544   if (inst->ringReadPos == inst->ringWritePos) {
545     STLOG_HAL_E("HAL thread message ring: already read last valid data");
546     result = false;
547   }
548 
549   // Get new element from ringbuffer
550   if (result) {
551     memcpy(msg, &(inst->ring[nextCmdIndex]), sizeof(ThreadMesssage));
552     inst->ringReadPos = nextCmdIndex;
553   }
554 
555   pthread_mutex_unlock(&inst->hMutex);
556 
557   return result;
558 }
559 
560 /**************************************************************************************************
561  *
562  *                                     Buffer/Memory Management
563  *
564  **************************************************************************************************/
565 
566 /**
567  * Allocate buffer from pre-allocated pool.
568  * @param inst HAL instance
569  * @return Pointer to allocated HAL buffer
570  */
HalAllocBuffer(HalInstance * inst)571 static HalBuffer* HalAllocBuffer(HalInstance* inst) {
572   HalBuffer* b;
573 
574   // Wait until we have a buffer resource
575   sem_wait_nointr(&inst->bufferResourceSem);
576 
577   pthread_mutex_lock(&inst->hMutex);
578 
579   b = inst->freeBufferList;
580   if (b) {
581     inst->freeBufferList = b->next;
582     b->next = 0;
583   }
584 
585   pthread_mutex_unlock(&inst->hMutex);
586 
587   if (!b) {
588     STLOG_HAL_E(
589         "! unable to allocate buffer resource."
590         "check bufferResourceSem\n");
591   }
592 
593   return b;
594 }
595 
596 /**
597  * Return buffer to pool.
598  * @param inst HAL instance
599  * @param b Pointer of HAL buffer to free
600  * @return Pointer of freed HAL buffer
601  */
HalFreeBuffer(HalInstance * inst,HalBuffer * b)602 static HalBuffer* HalFreeBuffer(HalInstance* inst, HalBuffer* b) {
603   pthread_mutex_lock(&inst->hMutex);
604 
605   b->next = inst->freeBufferList;
606   inst->freeBufferList = b;
607 
608   pthread_mutex_unlock(&inst->hMutex);
609 
610   // Unblock treads waiting for a buffer
611   sem_post(&inst->bufferResourceSem);
612 
613   return b;
614 }
615 
616 /**************************************************************************************************
617  *
618  *                                     State Machine
619  *
620  **************************************************************************************************/
621 
622 /**
623  * Event handler for HAL message
624  * @param inst HAL instance
625  * @param e HAL event
626  */
Hal_event_handler(HalInstance * inst,HalEvent e)627 static void Hal_event_handler(HalInstance* inst, HalEvent e) {
628   switch (e) {
629     case EVT_RX_DATA: {
630       // New data packet arrived
631       const uint8_t* nciData;
632       size_t nciLength;
633 
634       // Extract raw NCI data from frame
635       nciData = inst->lastUsFrame;
636       nciLength = inst->lastUsFrameSize;
637 
638       // Pass received raw NCI data to stack
639       inst->callback(inst->context, HAL_EVENT_DATAIND, nciData, nciLength);
640     } break;
641 
642     case EVT_TX_DATA:
643       // NCI data arrived from stack
644       // Send data
645       inst->callback(inst->context, HAL_EVENT_DSWRITE, inst->nciBuffer->data,
646                      inst->nciBuffer->length);
647 
648       // Free the buffer
649       HalFreeBuffer(inst, inst->nciBuffer);
650       inst->nciBuffer = 0;
651       break;
652 
653     // HAL WRAPPER
654     case EVT_TIMER:
655       inst->callback(inst->context, HAL_EVENT_TIMER_TIMEOUT, NULL, 0);
656       break;
657   }
658 }
659 
660 /**************************************************************************************************
661  *
662  *                                     HAL Worker Thread
663  *
664  **************************************************************************************************/
665 
666 /**
667  * HAL worker thread to serialize all actions into a single thread.
668  * RX/TX/TIMER are dispatched from here.
669  * @param arg HAL instance arguments
670  */
HalWorkerThread(void * arg)671 static void* HalWorkerThread(void* arg) {
672   HalInstance* inst = (HalInstance*)arg;
673   inst->exitRequest = false;
674 
675   STLOG_HAL_V("thread running\n");
676 
677   while (!inst->exitRequest) {
678     struct timespec now = HalGetTimestamp();
679     uint32_t waitResult =
680         HalSemWait(&inst->semaphore, HalCalcSemWaitingTime(inst, &now));
681 
682     switch (waitResult) {
683       case OS_SYNC_TIMEOUT: {
684         // One or more times have expired
685         STLOG_HAL_W("OS_SYNC_TIMEOUT\n");
686         now = HalGetTimestamp();
687         // Data frame
688         Hal_event_handler(inst, EVT_TIMER);
689       } break;
690 
691       case OS_SYNC_RELEASED: {
692         // A message arrived
693         ThreadMesssage msg;
694 
695         if (HalDequeueThreadMessage(inst, &msg)) {
696           switch (msg.command) {
697             case MSG_EXIT_REQUEST:
698 
699               STLOG_HAL_V("received exit request from upper layer\n");
700               inst->exitRequest = true;
701               break;
702 
703             case MSG_TX_DATA:
704               STLOG_HAL_V("received new NCI data from stack\n");
705 
706               // Attack to end of list
707               if (!inst->pendingNciList) {
708                 inst->pendingNciList = msg.buffer;
709                 inst->pendingNciList->next = 0;
710               } else {
711                 // Find last element of the list. b->next is zero for this
712                 // element
713                 HalBuffer* b;
714                 for (b = inst->pendingNciList; b->next; b = b->next) {
715                 };
716 
717                 // Concatenate to list
718                 b->next = msg.buffer;
719                 msg.buffer->next = 0;
720               }
721 
722               // Start transmitting if we're in the correct state
723               HalTriggerNextDsPacket(inst);
724               break;
725 
726             // HAL WRAPPER
727             case MSG_TX_DATA_TIMER_START:
728               STLOG_HAL_V(
729                   "received new NCI data from stack, need timer start\n");
730 
731               // Attack to end of list
732               if (!inst->pendingNciList) {
733                 inst->pendingNciList = msg.buffer;
734                 inst->pendingNciList->next = 0;
735               } else {
736                 // Find last element of the list. b->next is zero for this
737                 // element
738                 HalBuffer* b;
739                 for (b = inst->pendingNciList; b->next; b = b->next) {
740                 };
741 
742                 // Concatenate to list
743                 b->next = msg.buffer;
744                 msg.buffer->next = 0;
745               }
746 
747               // Start timer
748               HalStartTimer(inst, msg.length);
749 
750               // Start transmitting if we're in the correct state
751               HalTriggerNextDsPacket(inst);
752               break;
753 
754             case MSG_RX_DATA:
755               STLOG_HAL_V("received new data from CLF\n");
756               HalOnNewUpstreamFrame(inst, (unsigned char*)msg.payload,
757                                     msg.length);
758               break;
759 
760             case MSG_TIMER_START:
761               // Start timer
762               HalStartTimer(inst, msg.length);
763               STLOG_HAL_D("MSG_TIMER_START \n");
764               break;
765             default:
766               STLOG_HAL_E("!received unkown thread message?\n");
767               break;
768           }
769         } else {
770           STLOG_HAL_E("!got wakeup in workerthread, but no message here? ?\n");
771         }
772       } break;
773 
774       case OS_SYNC_FAILED:
775 
776         STLOG_HAL_E(
777             "!Something went horribly wrong.. The semaphore wait function "
778             "failed\n");
779         inst->exitRequest = true;
780         break;
781     }
782   }
783 
784   STLOG_HAL_D("thread about to exit\n");
785   return NULL;
786 }
787 
788 /**************************************************************************************************
789  *
790  *                                     Misc. Functions
791  *
792  **************************************************************************************************/
793 /**
794  *  helper to make sem_t interrupt safe
795  * @param sem_t  semaphore
796  * @return sem_wait return value.
797  */
798 
sem_wait_nointr(sem_t * sem)799 static inline int sem_wait_nointr(sem_t* sem) {
800   while (sem_wait(sem))
801     if (errno == EINTR)
802       errno = 0;
803     else
804       return -1;
805   return 0;
806 }
807 
808 /**
809  * Handle RX frames here first in HAL context.
810  * @param inst HAL instance
811  * @param data HAL data received from I2C worker thread
812  * @param length Size of HAL data
813  */
HalOnNewUpstreamFrame(HalInstance * inst,const uint8_t * data,size_t length)814 static void HalOnNewUpstreamFrame(HalInstance* inst, const uint8_t* data,
815                                   size_t length) {
816   memcpy(inst->lastUsFrame, data, length);
817   inst->lastUsFrameSize = length;
818 
819   // Data frame
820   Hal_event_handler(inst, EVT_RX_DATA);
821   // Allow the I2C thread to get the next message (if done early, it may
822   // overwrite before handled)
823   sem_post(&inst->upstreamBlock);
824 }
825 
826 /**
827  * Send out the next queued up buffer for TX if any.
828  * @param inst HAL instance
829  */
HalTriggerNextDsPacket(HalInstance * inst)830 static void HalTriggerNextDsPacket(HalInstance* inst) {
831   // Check if we have something to transmit downstream
832   HalBuffer* b = inst->pendingNciList;
833 
834   if (b) {
835     // Get the buffer from the pending list
836     inst->pendingNciList = b->next;
837     inst->nciBuffer = b;
838 
839     STLOG_HAL_V("trigger transport of next NCI data downstream\n");
840     // Process the new nci frame
841     Hal_event_handler(inst, EVT_TX_DATA);
842 
843   } else {
844     STLOG_HAL_V("no new NCI data to transmit, enter wait..\n");
845   }
846 }
847 
848 /*
849  * Wait for given semaphore signaling a specific time or ever
850  * param sem_t * pSemaphore
851  * param uint32_t timeout
852  * return uint32_t
853  */
HalSemWait(sem_t * pSemaphore,uint32_t timeout)854 static uint32_t HalSemWait(sem_t* pSemaphore, uint32_t timeout) {
855   uint32_t result = OS_SYNC_RELEASED;
856   bool gotResult = false;
857 
858   if (timeout == OS_SYNC_INFINITE) {
859     while (!gotResult) {
860       if (sem_wait(pSemaphore) == -1) {
861         int e = errno;
862         char msg[200];
863 
864         if (e == EINTR) {
865           STLOG_HAL_W(
866               "! semaphore (infin) wait interrupted by system signal. re-enter "
867               "wait");
868           continue;
869         }
870 
871         strerror_r(e, msg, sizeof(msg) - 1);
872         STLOG_HAL_E("! semaphore (infin) wait failed. sem=0x%p, %s", pSemaphore,
873                     msg);
874         gotResult = true;
875         result = OS_SYNC_FAILED;
876       } else {
877         gotResult = true;
878       }
879     };
880   } else {
881     struct timespec tm;
882     long oneSecInNs = (int)1e9;
883 
884     clock_gettime(CLOCK_REALTIME, &tm);
885 
886     /* add timeout (can't overflow): */
887     tm.tv_sec += (timeout / 1000);
888     tm.tv_nsec += ((timeout % 1000) * 1000000);
889 
890     /* make sure nanoseconds are below a million */
891     if (tm.tv_nsec >= oneSecInNs) {
892       tm.tv_sec++;
893       tm.tv_nsec -= oneSecInNs;
894     }
895 
896     while (!gotResult) {
897       if (sem_timedwait(pSemaphore, &tm) == -1) {
898         int e = errno;
899 
900         if (e == EINTR) {
901           /* interrupted by signal? repeat sem_wait again */
902           continue;
903         }
904 
905         if (e == ETIMEDOUT) {
906           result = OS_SYNC_TIMEOUT;
907           gotResult = true;
908         } else {
909           result = OS_SYNC_FAILED;
910           gotResult = true;
911         }
912       } else {
913         gotResult = true;
914       }
915     }
916   }
917   return result;
918 }
919