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