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