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