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