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