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