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