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