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