1 /*
2 * Copyright 2012-2020, 2024 NXP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <phNxpLog.h>
18 #include <phNxpUciHal_utils.h>
19 #include <phOsalUwb_Timer.h>
20 #include <phTmlUwb.h>
21 #include <phTmlUwb_spi.h>
22 #include <phNxpUciHal.h>
23 #include <errno.h>
24
25 extern phNxpUciHal_Control_t nxpucihal_ctrl;
26
27 /*
28 * Duration of Timer to wait after sending an Uci packet
29 */
30 #define PHTMLUWB_MAXTIME_RETRANSMIT (200U)
31 #define MAX_WRITE_RETRY_COUNT 0x03
32 /* Value to reset variables of TML */
33 #define PH_TMLUWB_RESET_VALUE (0x00)
34
35 /* Indicates a Initial or offset value */
36 #define PH_TMLUWB_VALUE_ONE (0x01)
37
38 namespace {
39
40 // Structure containing details related to read and write operations
41 struct phTmlUwb_ReadInfo {
42 volatile bool bThreadShouldStop;
43 volatile bool bThreadRunning;
44 uint8_t
45 bThreadBusy; /*Flag to indicate thread is busy on respective operation */
46 /* Transaction completion Callback function */
47 ReadCallback* pThread_Callback;
48 void* pContext; /*Context passed while invocation of operation */
49 uint8_t* pBuffer; /*Buffer passed while invocation of operation */
50 size_t wLength; /*Length of data read/written */
51 tHAL_UWB_STATUS wWorkStatus; /*Status of the transaction performed */
52 };
53
54 struct phTmlUwb_WriteInfo {
55 volatile bool bThreadShouldStop;
56 volatile bool bThreadRunning;
57 uint8_t
58 bThreadBusy; /*Flag to indicate thread is busy on respective operation */
59 /* Transaction completion Callback function */
60 WriteCallback* pThread_Callback;
61 void* pContext; /*Context passed while invocation of operation */
62 const uint8_t* pBuffer; /*Buffer passed while invocation of operation */
63 size_t wLength; /*Length of data read/written */
64 tHAL_UWB_STATUS wWorkStatus; /*Status of the transaction performed */
65 };
66
67 // Base Context Structure containing members required for entire session
68 struct phTmlUwb_Context {
69 pthread_t readerThread;
70 pthread_t writerThread;
71
72 phTmlUwb_ReadInfo tReadInfo; /*Pointer to Reader Thread Structure */
73 phTmlUwb_WriteInfo tWriteInfo; /*Pointer to Writer Thread Structure */
74 void* pDevHandle; /* Pointer to Device Handle */
75 std::shared_ptr<MessageQueue<phLibUwb_Message>> pClientMq; /* Pointer to Client thread message queue */
76 sem_t rxSemaphore;
77 sem_t txSemaphore; /* Lock/Acquire txRx Semaphore */
78
79 pthread_cond_t wait_busy_condition; /*Condition to wait reader thread*/
80 pthread_mutex_t wait_busy_lock; /*Condition lock to wait reader thread*/
81 volatile uint8_t wait_busy_flag; /*Condition flag to wait reader thread*/
82 volatile uint8_t gWriterCbflag; /* flag to indicate write callback message is pushed to
83 queue*/
84 };
85
86 std::unique_ptr<phTmlUwb_Context> gpphTmlUwb_Context;
87
88 } // namespace
89
90 /* Local Function prototypes */
91 static tHAL_UWB_STATUS phTmlUwb_StartWriterThread(void);
92 static void phTmlUwb_StopWriterThread(void);
93
94 static void phTmlUwb_CleanUp(void);
95 static void phTmlUwb_ReadDeferredCb(void* pParams);
96 static void phTmlUwb_WriteDeferredCb(void* pParams);
97 static void* phTmlUwb_TmlReaderThread(void* pParam);
98 static void* phTmlUwb_TmlWriterThread(void* pParam);
99
100 extern void setDeviceHandle(void* pDevHandle);
101
102 static void phTmlUwb_WaitWriteComplete(void);
103 static void phTmlUwb_SignalWriteComplete(void);
104 static int phTmlUwb_WaitReadInit(void);
105
106 /* Function definitions */
107
108 /*******************************************************************************
109 **
110 ** Function phTmlUwb_Init
111 **
112 ** Description Provides initialization of TML layer and hardware interface
113 ** Configures given hardware interface and sends handle to the
114 ** caller
115 **
116 ** Parameters pConfig - TML configuration details as provided by the upper
117 ** layer
118 **
119 ** Returns UWB status:
120 ** UWBSTATUS_SUCCESS - initialization successful
121 ** UWBSTATUS_INVALID_PARAMETER - at least one parameter is
122 ** invalid
123 ** UWBSTATUS_FAILED - initialization failed (for example,
124 ** unable to open hardware interface)
125 ** UWBSTATUS_INVALID_DEVICE - device has not been opened or has
126 ** been disconnected
127 **
128 *******************************************************************************/
phTmlUwb_Init(const char * pDevName,std::shared_ptr<MessageQueue<phLibUwb_Message>> pClientMq)129 tHAL_UWB_STATUS phTmlUwb_Init(const char* pDevName,
130 std::shared_ptr<MessageQueue<phLibUwb_Message>> pClientMq)
131 {
132 if (gpphTmlUwb_Context != nullptr) {
133 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_ALREADY_INITIALISED);
134 }
135
136 if (!pDevName || !pClientMq) {
137 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_INVALID_PARAMETER);
138 }
139
140 // Allocate memory for TML context
141 gpphTmlUwb_Context = std::make_unique<phTmlUwb_Context>();
142 if (gpphTmlUwb_Context == nullptr) {
143 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_FAILED);
144 }
145
146 // Open the device file to which data is read/written
147 tHAL_UWB_STATUS wInitStatus =
148 phTmlUwb_spi_open_and_configure(pDevName, &(gpphTmlUwb_Context->pDevHandle));
149 if (UWBSTATUS_SUCCESS != wInitStatus) {
150 gpphTmlUwb_Context->pDevHandle = NULL;
151 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_INVALID_DEVICE);
152 }
153
154 gpphTmlUwb_Context->tWriteInfo.bThreadBusy = false;
155 gpphTmlUwb_Context->pClientMq = pClientMq;
156
157 setDeviceHandle(gpphTmlUwb_Context->pDevHandle); // To set device handle for FW download usecase
158
159 if (sem_init(&gpphTmlUwb_Context->rxSemaphore, 0, 0)) {
160 return UWBSTATUS_FAILED;
161 }
162 if (sem_init(&gpphTmlUwb_Context->txSemaphore, 0, 0)) {
163 return UWBSTATUS_FAILED;
164 }
165 if(phTmlUwb_WaitReadInit()) {
166 return UWBSTATUS_FAILED;
167 }
168
169 // Start TML thread (to handle write and read operations)
170 if (UWBSTATUS_SUCCESS != phTmlUwb_StartWriterThread()) {
171 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_FAILED);
172 }
173
174 return UWBSTATUS_SUCCESS;
175 }
176
177 /*******************************************************************************
178 **
179 ** Function phTmlUwb_TmlReaderThread
180 **
181 ** Description Read the data from the lower layer driver
182 **
183 ** Parameters pParam - parameters for Writer thread function
184 **
185 ** Returns None
186 **
187 *******************************************************************************/
phTmlUwb_TmlReaderThread(void * pParam)188 static void* phTmlUwb_TmlReaderThread(void* pParam)
189 {
190 UNUSED(pParam);
191
192 /* Transaction info buffer to be passed to Callback Thread */
193 static phTmlUwb_ReadTransactInfo tTransactionInfo;
194 /* Structure containing Tml callback function and parameters to be invoked
195 by the callback thread */
196 static phLibUwb_DeferredCall_t tDeferredInfo;
197
198 gpphTmlUwb_Context->tReadInfo.bThreadRunning = true;
199 NXPLOG_TML_D("TmlReader: Thread Started");
200
201 /* Writer thread loop shall be running till shutdown is invoked */
202 while (!gpphTmlUwb_Context->tReadInfo.bThreadShouldStop) {
203 NXPLOG_TML_V("TmlReader: Running");
204 if(sem_wait(&gpphTmlUwb_Context->rxSemaphore)) {
205 NXPLOG_TML_E("TmlReader: Failed to wait rxSemaphore err=%d", errno);
206 break;
207 }
208
209 tHAL_UWB_STATUS wStatus = UWBSTATUS_SUCCESS;
210
211 /* Read the data from the file onto the buffer */
212 if (!gpphTmlUwb_Context->pDevHandle) {
213 NXPLOG_TML_E("TmlRead: invalid file handle");
214 break;
215 }
216
217 NXPLOG_TML_V("TmlReader: Invoking SPI Read");
218
219 uint8_t temp[UCI_MAX_DATA_LEN];
220 int dwNoBytesWrRd =
221 phTmlUwb_spi_read(gpphTmlUwb_Context->pDevHandle, temp, UCI_MAX_DATA_LEN);
222
223 if(gpphTmlUwb_Context->tReadInfo.bThreadShouldStop) {
224 break;
225 }
226
227 if (-1 == dwNoBytesWrRd) {
228 NXPLOG_TML_E("TmlReader: Error in SPI Read");
229 sem_post(&gpphTmlUwb_Context->rxSemaphore);
230 } else if (dwNoBytesWrRd > UCI_MAX_DATA_LEN) {
231 NXPLOG_TML_E("TmlReader: Numer of bytes read exceeds the limit");
232 sem_post(&gpphTmlUwb_Context->rxSemaphore);
233 } else if(0 == dwNoBytesWrRd) {
234 NXPLOG_TML_E("TmlReader: Empty packet Read, Ignore read and try new read");
235 sem_post(&gpphTmlUwb_Context->rxSemaphore);
236 } else {
237 memcpy(gpphTmlUwb_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
238
239 NXPLOG_TML_V("TmlReader: SPI Read successful");
240
241 /* Update the actual number of bytes read including header */
242 gpphTmlUwb_Context->tReadInfo.wLength = dwNoBytesWrRd;
243
244 dwNoBytesWrRd = PH_TMLUWB_RESET_VALUE;
245
246 NXPLOG_TML_V("TmlReader: Posting read message");
247
248 /* Fill the Transaction info structure to be passed to Callback
249 * Function */
250 tTransactionInfo.wStatus = wStatus;
251 tTransactionInfo.pBuff = gpphTmlUwb_Context->tReadInfo.pBuffer;
252 tTransactionInfo.wLength = gpphTmlUwb_Context->tReadInfo.wLength;
253
254 /* Read operation completed successfully. Post a Message onto Callback
255 * Thread*/
256 /* Prepare the message to be posted on User thread */
257 tDeferredInfo.pCallback = &phTmlUwb_ReadDeferredCb;
258 tDeferredInfo.pParameter = &tTransactionInfo;
259
260 /* TML reader writer callback synchronization mutex lock --- START */
261 if (pthread_mutex_lock(&gpphTmlUwb_Context->wait_busy_lock)) {
262 NXPLOG_TML_E("[%s] Mutex lock failed for wait_busy_lock at line: %d", __func__, __LINE__);
263 }
264
265 if ((gpphTmlUwb_Context->gWriterCbflag == false) &&
266 ((gpphTmlUwb_Context->tReadInfo.pBuffer[0] & 0x60) != 0x60)) {
267 phTmlUwb_WaitWriteComplete();
268 }
269 /* TML reader writer callback synchronization mutex lock --- END */
270 if (pthread_mutex_unlock(&gpphTmlUwb_Context->wait_busy_lock)) {
271 NXPLOG_TML_E("[%s] Mutex unlock failed for wait_busy_lock at line: %d", __func__, __LINE__);
272 }
273
274 auto msg = std::make_shared<phLibUwb_Message>(PH_LIBUWB_DEFERREDCALL_MSG, &tDeferredInfo);
275 phTmlUwb_DeferredCall(msg);
276 }
277 } /* End of While loop */
278
279 gpphTmlUwb_Context->tReadInfo.bThreadRunning = false;
280 NXPLOG_TML_D("Tml Reader: Thread stopped");
281
282 return NULL;
283 }
284
285 /*******************************************************************************
286 **
287 ** Function phTmlUwb_TmlWriterThread
288 **
289 ** Description Writes the requested data onto the lower layer driver
290 **
291 ** Parameters pParam - context provided by upper layer
292 **
293 ** Returns None
294 **
295 *******************************************************************************/
phTmlUwb_TmlWriterThread(void * pParam)296 static void* phTmlUwb_TmlWriterThread(void* pParam)
297 {
298 UNUSED(pParam);
299
300 /* Transaction info buffer to be passed to Callback Thread */
301 static phTmlUwb_WriteTransactInfo tTransactionInfo;
302 /* Structure containing Tml callback function and parameters to be invoked
303 by the callback thread */
304 static phLibUwb_DeferredCall_t tDeferredInfo;
305
306 gpphTmlUwb_Context->tWriteInfo.bThreadRunning = true;
307 NXPLOG_TML_D("TmlWriter: Thread Started");
308
309 /* Writer thread loop shall be running till shutdown is invoked */
310 while (!gpphTmlUwb_Context->tWriteInfo.bThreadShouldStop) {
311 NXPLOG_TML_V("TmlWriter: Running");
312 if (sem_wait(&gpphTmlUwb_Context->txSemaphore)) {
313 NXPLOG_TML_E("TmlWriter: Failed to wait txSemaphore, err=%d", errno);
314 break;
315 }
316
317 if (gpphTmlUwb_Context->tWriteInfo.bThreadShouldStop) {
318 break;
319 }
320
321 tHAL_UWB_STATUS wStatus = UWBSTATUS_SUCCESS;
322
323 if (!gpphTmlUwb_Context->pDevHandle) {
324 NXPLOG_TML_E("TmlWriter: invalid file handle");
325 break;
326 }
327
328 NXPLOG_TML_V("TmlWriter: Invoking SPI Write");
329
330 /* TML reader writer callback synchronization mutex lock --- START
331 */
332 if (pthread_mutex_lock(&gpphTmlUwb_Context->wait_busy_lock)) {
333 NXPLOG_TML_E("[%s] Mutex lock failed for wait_busy_lock at line: %d", __func__, __LINE__);
334 }
335 gpphTmlUwb_Context->gWriterCbflag = false;
336 int32_t dwNoBytesWrRd =
337 phTmlUwb_spi_write(gpphTmlUwb_Context->pDevHandle,
338 gpphTmlUwb_Context->tWriteInfo.pBuffer,
339 gpphTmlUwb_Context->tWriteInfo.wLength);
340 /* TML reader writer callback synchronization mutex lock --- END */
341 if (pthread_mutex_unlock(&gpphTmlUwb_Context->wait_busy_lock)) {
342 NXPLOG_TML_E("[%s] Mutex unlock failed for wait_busy_lock at line: %d", __func__, __LINE__);
343 }
344
345 /* Try SPI Write Five Times, if it fails :*/
346 if (-1 == dwNoBytesWrRd) {
347 NXPLOG_TML_E("TmlWriter: Error in SPI Write");
348 wStatus = PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_FAILED);
349 } else {
350 phNxpUciHal_print_packet(NXP_TML_UCI_CMD_AP_2_UWBS,
351 gpphTmlUwb_Context->tWriteInfo.pBuffer,
352 gpphTmlUwb_Context->tWriteInfo.wLength);
353 }
354 if (UWBSTATUS_SUCCESS == wStatus) {
355 NXPLOG_TML_V("TmlWriter: SPI Write successful");
356 dwNoBytesWrRd = PH_TMLUWB_VALUE_ONE;
357 }
358
359 NXPLOG_TML_V("TmlWriter: Posting write message");
360
361 /* Fill the Transaction info structure to be passed to Callback Function
362 */
363 tTransactionInfo.wStatus = wStatus;
364 tTransactionInfo.pBuff = gpphTmlUwb_Context->tWriteInfo.pBuffer;
365 tTransactionInfo.wLength = dwNoBytesWrRd;
366
367 /* Prepare the message to be posted on the User thread */
368 tDeferredInfo.pCallback = &phTmlUwb_WriteDeferredCb;
369 tDeferredInfo.pParameter = &tTransactionInfo;
370
371 auto msg = std::make_shared<phLibUwb_Message>(PH_LIBUWB_DEFERREDCALL_MSG, &tDeferredInfo);
372 phTmlUwb_DeferredCall(msg);
373
374 if (UWBSTATUS_SUCCESS == wStatus) {
375 /* TML reader writer callback synchronization mutex lock --- START
376 */
377 if (pthread_mutex_lock(&gpphTmlUwb_Context->wait_busy_lock)) {
378 NXPLOG_TML_E("[%s] Mutex lock failed for wait_busy_lock at line: %d", __func__, __LINE__);
379 }
380 gpphTmlUwb_Context->gWriterCbflag = true;
381 phTmlUwb_SignalWriteComplete();
382 /* TML reader writer callback synchronization mutex lock --- END */
383 if (pthread_mutex_unlock(&gpphTmlUwb_Context->wait_busy_lock)) {
384 NXPLOG_TML_E("[%s] Mutex unlock failed for wait_busy_lock at line: %d", __func__, __LINE__);
385 }
386 }
387 } /* End of While loop */
388
389 gpphTmlUwb_Context->tWriteInfo.bThreadRunning = false;
390 NXPLOG_TML_D("TmlWriter: Thread stopped");
391
392 return NULL;
393 }
394
395 /*******************************************************************************
396 **
397 ** Function phTmlUwb_CleanUp
398 **
399 ** Description Clears all handles opened during TML initialization
400 **
401 ** Parameters None
402 **
403 ** Returns None
404 **
405 *******************************************************************************/
phTmlUwb_CleanUp(void)406 static void phTmlUwb_CleanUp(void) {
407 if (gpphTmlUwb_Context == nullptr) {
408 return;
409 }
410
411 if (NULL != gpphTmlUwb_Context->pDevHandle) {
412 (void)phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, 0);
413 }
414
415 sem_destroy(&gpphTmlUwb_Context->rxSemaphore);
416 sem_destroy(&gpphTmlUwb_Context->txSemaphore);
417 if (pthread_mutex_destroy(&gpphTmlUwb_Context->wait_busy_lock)) {
418 NXPLOG_TML_E("[%s] Failed to destroy mutex 'wait_busy_lock' at line: %d", __func__, __LINE__);
419 }
420 if (pthread_cond_destroy(&gpphTmlUwb_Context->wait_busy_condition)) {
421 NXPLOG_TML_E("[%s] Failed to destroy conditional variable 'wait_busy_condition' at line: %d",
422 __func__, __LINE__);
423 }
424 phTmlUwb_spi_close(gpphTmlUwb_Context->pDevHandle);
425 gpphTmlUwb_Context->pDevHandle = NULL;
426
427 gpphTmlUwb_Context.reset();
428 }
429
430 /*******************************************************************************
431 **
432 ** Function phTmlUwb_Shutdown
433 **
434 ** Description Uninitializes TML layer and hardware interface
435 **
436 ** Parameters None
437 **
438 ** Returns UWB status:
439 ** UWBSTATUS_SUCCESS - TML configuration released successfully
440 ** UWBSTATUS_INVALID_PARAMETER - at least one parameter is
441 ** invalid
442 ** UWBSTATUS_FAILED - un-initialization failed (example: unable
443 ** to close interface)
444 **
445 *******************************************************************************/
phTmlUwb_Shutdown(void)446 tHAL_UWB_STATUS phTmlUwb_Shutdown(void)
447 {
448 if (!gpphTmlUwb_Context) {
449 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_NOT_INITIALISED);
450 }
451
452 // Abort io threads
453 phTmlUwb_StopRead();
454
455 phTmlUwb_StopWriterThread();
456
457 phTmlUwb_CleanUp();
458
459 return UWBSTATUS_SUCCESS;
460 }
461
462 /*******************************************************************************
463 **
464 ** Function phTmlUwb_Write
465 **
466 ** Description Asynchronously writes given data block to hardware
467 ** interface/driver. Enables writer thread if there are no
468 ** write requests pending. Returns successfully once writer
469 ** thread completes write operation. Notifies upper layer using
470 ** callback mechanism.
471 **
472 ** NOTE:
473 ** * it is important to post a message with id
474 ** PH_TMLUWB_WRITE_MESSAGE to IntegrationThread after data
475 ** has been written to SRxxx
476 ** * if CRC needs to be computed, then input buffer should be
477 ** capable to store two more bytes apart from length of
478 ** packet
479 **
480 ** Parameters pBuffer - data to be sent
481 ** wLength - length of data buffer
482 ** pTmlWriteComplete - pointer to the function to be invoked
483 ** upon completion
484 ** pContext - context provided by upper layer
485 **
486 ** Returns UWB status:
487 ** UWBSTATUS_PENDING - command is yet to be processed
488 ** UWBSTATUS_INVALID_PARAMETER - at least one parameter is
489 ** invalid
490 ** UWBSTATUS_BUSY - write request is already in progress
491 **
492 *******************************************************************************/
phTmlUwb_Write(const uint8_t * pBuffer,size_t wLength,WriteCallback pTmlWriteComplete,void * pContext)493 tHAL_UWB_STATUS phTmlUwb_Write(const uint8_t* pBuffer, size_t wLength,
494 WriteCallback pTmlWriteComplete,
495 void* pContext) {
496 tHAL_UWB_STATUS wWriteStatus;
497
498 /* Check whether TML is Initialized */
499
500 if (NULL != gpphTmlUwb_Context) {
501 if ((NULL != gpphTmlUwb_Context->pDevHandle) && (NULL != pBuffer) &&
502 (PH_TMLUWB_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
503 if (!gpphTmlUwb_Context->tWriteInfo.bThreadBusy) {
504 /* Setting the flag marks beginning of a Write Operation */
505 gpphTmlUwb_Context->tWriteInfo.bThreadBusy = true;
506 /* Copy the buffer, length and Callback function,
507 This shall be utilized while invoking the Callback function in thread
508 */
509 gpphTmlUwb_Context->tWriteInfo.pBuffer = pBuffer;
510 gpphTmlUwb_Context->tWriteInfo.wLength = wLength;
511 gpphTmlUwb_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
512 gpphTmlUwb_Context->tWriteInfo.pContext = pContext;
513
514 wWriteStatus = UWBSTATUS_PENDING;
515 /* Set event to invoke Writer Thread */
516 sem_post(&gpphTmlUwb_Context->txSemaphore);
517 } else {
518 wWriteStatus = PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_BUSY);
519 }
520 } else {
521 wWriteStatus = PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_INVALID_PARAMETER);
522 }
523 } else {
524 wWriteStatus = PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_NOT_INITIALISED);
525 }
526
527 return wWriteStatus;
528 }
529
530 /*******************************************************************************
531 **
532 ** Function phTmlUwb_Read
533 **
534 ** Description Asynchronously reads data from the driver
535 ** Number of bytes to be read and buffer are passed by upper
536 ** layer.
537 ** Enables reader thread if there are no read requests pending
538 ** Returns successfully once read operation is completed
539 ** Notifies upper layer using callback mechanism
540 **
541 ** Parameters pBuffer - location to send read data to the upper layer via
542 ** callback
543 ** wLength - length of read data buffer passed by upper layer
544 ** pTmlReadComplete - pointer to the function to be invoked
545 ** upon completion of read operation
546 ** pContext - context provided by upper layer
547 **
548 ** Returns UWB status:
549 ** UWBSTATUS_PENDING - command is yet to be processed
550 ** UWBSTATUS_INVALID_PARAMETER - at least one parameter is
551 ** invalid
552 ** UWBSTATUS_BUSY - read request is already in progress
553 **
554 *******************************************************************************/
phTmlUwb_StartRead(ReadCallback pTmlReadComplete,void * pContext)555 tHAL_UWB_STATUS phTmlUwb_StartRead(ReadCallback pTmlReadComplete, void* pContext)
556 {
557 // TODO: move this to gpphTmlUwb_Context
558 static uint8_t shared_rx_buffer[UCI_MAX_DATA_LEN];
559
560 /* Check whether TML is Initialized */
561 if (!gpphTmlUwb_Context || !gpphTmlUwb_Context->pDevHandle) {
562 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_NOT_INITIALISED);
563 }
564
565 if (!pTmlReadComplete) {
566 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_INVALID_PARAMETER);
567 }
568
569 if (gpphTmlUwb_Context->tReadInfo.bThreadRunning) {
570 return PHUWBSTVAL(CID_UWB_TML, UWBSTATUS_BUSY);
571 }
572
573 /* Setting the flag marks beginning of a Read Operation */
574 gpphTmlUwb_Context->tReadInfo.pBuffer = shared_rx_buffer;
575 gpphTmlUwb_Context->tReadInfo.wLength = sizeof(shared_rx_buffer);
576 gpphTmlUwb_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
577 gpphTmlUwb_Context->tReadInfo.pContext = pContext;
578
579 /* Set first event to invoke Reader Thread */
580 sem_post(&gpphTmlUwb_Context->rxSemaphore);
581
582 /* Create Reader threads */
583 gpphTmlUwb_Context->tReadInfo.bThreadShouldStop = false;
584 int ret = pthread_create(&gpphTmlUwb_Context->readerThread, NULL,
585 &phTmlUwb_TmlReaderThread, NULL);
586 if (ret) {
587 return UWBSTATUS_FAILED;
588 } else {
589 return UWBSTATUS_SUCCESS;
590 }
591 }
592
phTmlUwb_StopRead()593 void phTmlUwb_StopRead()
594 {
595 gpphTmlUwb_Context->tReadInfo.bThreadShouldStop = true;
596
597 if (gpphTmlUwb_Context->tReadInfo.bThreadRunning) {
598 // to wakeup from blocking read()
599 phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, ABORT_READ_PENDING);
600 sem_post(&gpphTmlUwb_Context->rxSemaphore);
601
602 if (pthread_join(gpphTmlUwb_Context->readerThread, NULL)) {
603 NXPLOG_TML_E("[%s] pthread_join failed for reader thread at line: %d ", __func__, __LINE__);
604 }
605 }
606 }
607
608 /*******************************************************************************
609 **
610 ** Function phTmlUwb_StartWriterThread
611 **
612 ** Description start writer thread
613 **
614 ** Parameters None
615 **
616 ** Returns UWB status:
617 ** UWBSTATUS_SUCCESS - threads initialized successfully
618 ** UWBSTATUS_FAILED - initialization failed due to system error
619 **
620 *******************************************************************************/
phTmlUwb_StartWriterThread(void)621 static tHAL_UWB_STATUS phTmlUwb_StartWriterThread(void)
622 {
623 int ret;
624
625 gpphTmlUwb_Context->tWriteInfo.bThreadShouldStop = false;
626
627 /*Start Writer Thread*/
628 ret = pthread_create(&gpphTmlUwb_Context->writerThread, NULL,
629 &phTmlUwb_TmlWriterThread, NULL);
630 if (ret) {
631 return UWBSTATUS_FAILED;
632 } else {
633 return UWBSTATUS_SUCCESS;
634 }
635 }
636
637
638 /*******************************************************************************
639 **
640 ** Function phTmlUwb_StopWriterThread
641 **
642 ** Description Stop writer thread
643 **
644 ** Parameters None
645 **
646 ** Returns None
647 **
648 *******************************************************************************/
phTmlUwb_StopWriterThread(void)649 static void phTmlUwb_StopWriterThread(void)
650 {
651 gpphTmlUwb_Context->tWriteInfo.bThreadBusy = false;
652 gpphTmlUwb_Context->tWriteInfo.bThreadShouldStop = true;
653
654 if (gpphTmlUwb_Context->tWriteInfo.bThreadRunning) {
655 sem_post(&gpphTmlUwb_Context->txSemaphore);
656
657 if (pthread_join(gpphTmlUwb_Context->writerThread, NULL)) {
658 NXPLOG_TML_E("[%s] pthread_join failed for writer thread at line: %d ", __func__, __LINE__);
659 }
660 }
661 }
662
663 /*******************************************************************************
664 **
665 ** Function phTmlUwb_DeferredCall
666 **
667 ** Description Posts message on upper layer thread
668 ** upon successful read or write operation
669 **
670 ** Parameters msg - message to be posted
671 **
672 ** Returns None
673 **
674 *******************************************************************************/
phTmlUwb_DeferredCall(std::shared_ptr<phLibUwb_Message> msg)675 void phTmlUwb_DeferredCall(std::shared_ptr<phLibUwb_Message> msg)
676 {
677 gpphTmlUwb_Context->pClientMq->send(msg);
678 }
679
680 /*******************************************************************************
681 **
682 ** Function phTmlUwb_ReadDeferredCb
683 **
684 ** Description Read thread call back function
685 **
686 ** Parameters pParams - context provided by upper layer
687 **
688 ** Returns None
689 **
690 *******************************************************************************/
phTmlUwb_ReadDeferredCb(void * pParams)691 static void phTmlUwb_ReadDeferredCb(void* pParams)
692 {
693 /* Transaction info buffer to be passed to Callback Function */
694 phTmlUwb_ReadTransactInfo* pTransactionInfo = (phTmlUwb_ReadTransactInfo*)pParams;
695
696 /* Reset the flag to accept another Read Request */
697 gpphTmlUwb_Context->tReadInfo.pThread_Callback(
698 gpphTmlUwb_Context->tReadInfo.pContext, pTransactionInfo);
699
700 sem_post(&gpphTmlUwb_Context->rxSemaphore);
701 }
702
703 /*******************************************************************************
704 **
705 ** Function phTmlUwb_WriteDeferredCb
706 **
707 ** Description Write thread call back function
708 **
709 ** Parameters pParams - context provided by upper layer
710 **
711 ** Returns None
712 **
713 *******************************************************************************/
phTmlUwb_WriteDeferredCb(void * pParams)714 static void phTmlUwb_WriteDeferredCb(void* pParams) {
715 /* Transaction info buffer to be passed to Callback Function */
716 phTmlUwb_WriteTransactInfo* pTransactionInfo = (phTmlUwb_WriteTransactInfo*)pParams;
717
718 /* Reset the flag to accept another Write Request */
719 gpphTmlUwb_Context->tWriteInfo.bThreadBusy = false;
720 gpphTmlUwb_Context->tWriteInfo.pThread_Callback(
721 gpphTmlUwb_Context->tWriteInfo.pContext, pTransactionInfo);
722
723 return;
724 }
725
726 /*******************************************************************************
727 **
728 ** Function phTmlUwb_WaitWriteComplete
729 **
730 ** Description wait function for reader thread
731 **
732 ** Parameters None
733 **
734 ** Returns None
735 **
736 *******************************************************************************/
phTmlUwb_WaitWriteComplete(void)737 static void phTmlUwb_WaitWriteComplete(void) {
738 int ret;
739 struct timespec absTimeout;
740 if (clock_gettime(CLOCK_MONOTONIC, &absTimeout) == -1) {
741 NXPLOG_TML_E("Reader Thread clock_gettime failed");
742 } else {
743 absTimeout.tv_sec += 1; /*1 second timeout*/
744 gpphTmlUwb_Context->wait_busy_flag = true;
745 NXPLOG_TML_D("phTmlUwb_WaitWriteComplete - enter");
746 ret = pthread_cond_timedwait(&gpphTmlUwb_Context->wait_busy_condition,
747 &gpphTmlUwb_Context->wait_busy_lock,
748 &absTimeout);
749 if ((ret != 0) && (ret != ETIMEDOUT)) {
750 NXPLOG_TML_E("Reader Thread wait failed");
751 }
752 NXPLOG_TML_D("phTmlUwb_WaitWriteComplete - exit");
753 }
754 }
755
756 /*******************************************************************************
757 **
758 ** Function phTmlUwb_SignalWriteComplete
759 **
760 ** Description function to invoke reader thread
761 **
762 ** Parameters None
763 **
764 ** Returns None
765 **
766 *******************************************************************************/
phTmlUwb_SignalWriteComplete(void)767 static void phTmlUwb_SignalWriteComplete(void) {
768 int ret;
769 if (gpphTmlUwb_Context->wait_busy_flag == true) {
770 NXPLOG_TML_D("phTmlUwb_SignalWriteComplete - enter");
771 gpphTmlUwb_Context->wait_busy_flag = false;
772 ret = pthread_cond_signal(&gpphTmlUwb_Context->wait_busy_condition);
773 if (ret) {
774 NXPLOG_TML_E(" phTmlUwb_SignalWriteComplete failed, error = 0x%X", ret);
775 }
776 NXPLOG_TML_D("phTmlUwb_SignalWriteComplete - exit");
777 }
778 }
779
780 /*******************************************************************************
781 **
782 ** Function phTmlUwb_WaitReadInit
783 **
784 ** Description init function for reader thread
785 **
786 ** Parameters None
787 **
788 ** Returns int
789 **
790 *******************************************************************************/
phTmlUwb_WaitReadInit(void)791 static int phTmlUwb_WaitReadInit(void) {
792 int ret;
793 pthread_condattr_t attr;
794 if (pthread_condattr_init(&attr)) {
795 NXPLOG_TML_E(" [%s] conditional attr init failed at line: %d", __func__, __LINE__);
796 }
797 if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
798 NXPLOG_TML_E(" [%s] conditional attr setClock failed at line: %d", __func__, __LINE__);
799 }
800 memset(&gpphTmlUwb_Context->wait_busy_condition, 0,
801 sizeof(gpphTmlUwb_Context->wait_busy_condition));
802 if (pthread_mutex_init(&gpphTmlUwb_Context->wait_busy_lock, NULL)) {
803 NXPLOG_TML_E(" [%s] mutex init failed for wait busy lock at line: %d", __func__, __LINE__);
804 }
805 ret = pthread_cond_init(&gpphTmlUwb_Context->wait_busy_condition, &attr);
806 if (ret) {
807 NXPLOG_TML_E("[%s] pthread_cond_init failed for wait_busy_condition at line: %d", __func__,
808 __LINE__);
809 }
810 return ret;
811 }
812
813 /*******************************************************************************
814 **
815 ** Function phTmlUwb_Chip_Reset
816 **
817 ** Description Invoke this API to Chip enable/Disable
818 **
819 ** Parameters None
820 **
821 ** Returns void
822 **
823 *******************************************************************************/
phTmlUwb_Chip_Reset(void)824 void phTmlUwb_Chip_Reset(void){
825 if (NULL != gpphTmlUwb_Context->pDevHandle) {
826 phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, 0);
827 usleep(1000);
828 phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, 1);
829 }
830 }
831
phTmlUwb_Suspend(void)832 void phTmlUwb_Suspend(void)
833 {
834 NXPLOG_TML_D("Suspend");
835 phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, PWR_SUSPEND);
836
837 }
838
phTmlUwb_Resume(void)839 void phTmlUwb_Resume(void)
840 {
841 NXPLOG_TML_D("Resume");
842 phTmlUwb_Spi_Ioctl(gpphTmlUwb_Context->pDevHandle, phTmlUwb_ControlCode_t::SetPower, PWR_RESUME);
843 }
844