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