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