• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012-2020, 2023 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 #ifndef _PHNXPUCIHAL_UTILS_H_
18 #define _PHNXPUCIHAL_UTILS_H_
19 
20 #include <assert.h>
21 #include <pthread.h>
22 #include <semaphore.h>
23 #include <time.h>
24 
25 #include <cstring>
26 #include <bit>
27 #include <map>
28 #include <type_traits>
29 #include <vector>
30 
31 #include "phNxpLog.h"
32 #include "phUwbStatus.h"
33 
34 /********************* Definitions and structures *****************************/
35 
36 /* List structures */
37 struct listNode {
38   void* pData;
39   struct listNode* pNext;
40 };
41 
42 struct listHead {
43   struct listNode* pFirst;
44   pthread_mutex_t mutex;
45 };
46 
47 /* Which is the direction of UWB Packet.
48  *
49  * Used by the @ref phNxpUciHal_print_packet API.
50  */
51 enum phNxpUciHal_Pkt_Type {
52   NXP_TML_UCI_CMD_AP_2_UWBS,
53   NXP_TML_UCI_RSP_NTF_UWBS_2_AP,
54   NXP_TML_FW_DNLD_CMD_AP_2_UWBS,
55   NXP_TML_FW_DNLD_RSP_UWBS_2_AP,
56 };
57 
58 
59 /* Semaphore handling structure */
60 typedef struct phNxpUciHal_Sem {
61   /* Semaphore used to wait for callback */
62   sem_t sem;
63 
64   /* Used to store the status sent by the callback */
65   tHAL_UWB_STATUS status;
66 
67   /* Used to provide a local context to the callback */
68   void* pContext;
69 
70 } phNxpUciHal_Sem_t;
71 
72 /* Semaphore helper macros */
SEM_WAIT(phNxpUciHal_Sem_t * pCallbackData)73 static inline int SEM_WAIT(phNxpUciHal_Sem_t* pCallbackData)
74 {
75   return sem_wait(&pCallbackData->sem);
76 }
77 
SEM_POST(phNxpUciHal_Sem_t * pCallbackData)78 static inline int SEM_POST(phNxpUciHal_Sem_t* pCallbackData)
79 {
80   return sem_post(&pCallbackData->sem);
81 }
82 
83 /* Semaphore and mutex monitor */
84 typedef struct phNxpUciHal_Monitor {
85   /* Mutex protecting native library against reentrance */
86   pthread_mutex_t reentrance_mutex;
87 
88   /* Mutex protecting native library against concurrency */
89   pthread_mutex_t concurrency_mutex;
90 
91   /* List used to track pending semaphores waiting for callback */
92   struct listHead sem_list;
93 
94 } phNxpUciHal_Monitor_t;
95 
96 /************************ Exposed functions ***********************************/
97 /* List functions */
98 int listInit(struct listHead* pList);
99 int listDestroy(struct listHead* pList);
100 int listAdd(struct listHead* pList, void* pData);
101 int listRemove(struct listHead* pList, void* pData);
102 int listGetAndRemoveNext(struct listHead* pList, void** ppData);
103 void listDump(struct listHead* pList);
104 
105 /* NXP UCI HAL utility functions */
106 phNxpUciHal_Monitor_t* phNxpUciHal_init_monitor(void);
107 void phNxpUciHal_cleanup_monitor(void);
108 phNxpUciHal_Monitor_t* phNxpUciHal_get_monitor(void);
109 tHAL_UWB_STATUS phNxpUciHal_init_cb_data(phNxpUciHal_Sem_t* pCallbackData,
110                                    void* pContext);
111 
112 int phNxpUciHal_sem_timed_wait_msec(phNxpUciHal_Sem_t* pCallbackData, long msec);
113 
phNxpUciHal_sem_timed_wait_sec(phNxpUciHal_Sem_t * pCallbackData,time_t sec)114 static inline int phNxpUciHal_sem_timed_wait_sec(phNxpUciHal_Sem_t* pCallbackData, time_t sec)
115 {
116   return phNxpUciHal_sem_timed_wait_msec(pCallbackData, sec * 1000L);
117 }
118 
phNxpUciHal_sem_timed_wait(phNxpUciHal_Sem_t * pCallbackData)119 static inline int phNxpUciHal_sem_timed_wait(phNxpUciHal_Sem_t* pCallbackData)
120 {
121   /* default 1 second timeout*/
122   return phNxpUciHal_sem_timed_wait_msec(pCallbackData, 1000L);
123 }
124 
125 void phNxpUciHal_cleanup_cb_data(phNxpUciHal_Sem_t* pCallbackData);
126 void phNxpUciHal_releaseall_cb_data(void);
127 
128 // helper class for Semaphore
129 // phNxpUciHal_init_cb_data(), phNxpUciHal_cleanup_cb_data(),
130 // SEM_WAIT(), SEM_POST()
131 class UciHalSemaphore {
132 public:
UciHalSemaphore()133   UciHalSemaphore() {
134     phNxpUciHal_init_cb_data(&sem, NULL);
135   }
UciHalSemaphore(void * context)136   UciHalSemaphore(void *context) {
137     phNxpUciHal_init_cb_data(&sem, context);
138   }
~UciHalSemaphore()139   virtual ~UciHalSemaphore() {
140     phNxpUciHal_cleanup_cb_data(&sem);
141   }
wait()142   int wait() {
143     return sem_wait(&sem.sem);
144   }
wait_timeout_msec(long msec)145   int wait_timeout_msec(long msec) {
146     return phNxpUciHal_sem_timed_wait_msec(&sem, msec);
147   }
post()148   int post() {
149     return sem_post(&sem.sem);
150   }
post(tHAL_UWB_STATUS status)151   int post(tHAL_UWB_STATUS status) {
152     sem.status = status;
153     return sem_post(&sem.sem);
154   }
getStatus()155   tHAL_UWB_STATUS getStatus() {
156     return sem.status;
157   }
158 private:
159   phNxpUciHal_Sem_t sem;
160 };
161 
162 /*
163  * Print an UWB Packet.
164  *
165  * @param what The type and direction of packet
166  *
167  * @param p_data The packet to be printed/logged.
168  *
169  * @param len Tenth of the packet.
170  *
171  */
172 
173 void phNxpUciHal_print_packet(enum phNxpUciHal_Pkt_Type what, const uint8_t* p_data,
174                               uint16_t len);
175 void phNxpUciHal_emergency_recovery(void);
176 double phNxpUciHal_byteArrayToDouble(const uint8_t* p_data);
177 
178 template <typename T>
le_bytes_to_cpu(const uint8_t * p)179 static inline T le_bytes_to_cpu(const uint8_t *p)
180 {
181   static_assert(std::is_integral_v<T>, "bytes_to_cpu must be used with an integral type");
182   T val = 0;
183   if (std::endian::native == std::endian::little) {
184     std::memcpy(&val, p, sizeof(T));
185   } else {
186     size_t i = sizeof(T);
187     while (i--) {
188       val = (val << 8) | p[i];
189     }
190   }
191   return val;
192 }
193 
194 template <typename T>
cpu_to_le_bytes(uint8_t * p,const T num)195 static inline void cpu_to_le_bytes(uint8_t *p, const T num)
196 {
197   static_assert(std::is_integral_v<T>, "cpu_to_le_bytes must be used with an integral type");
198   T val = num;
199   if (std::endian::native == std::endian::little) {
200     std::memcpy(p, &val, sizeof(T));
201   } else {
202     for (size_t i = 0; i < sizeof(T); i++) {
203       p[i] = val & 0xff;
204       val = val >> 8;
205     }
206   }
207 }
208 
209 /* Lock unlock helper macros */
210 #define REENTRANCE_LOCK()        \
211   if (phNxpUciHal_get_monitor()) \
212   pthread_mutex_lock(&phNxpUciHal_get_monitor()->reentrance_mutex)
213 #define REENTRANCE_UNLOCK()      \
214   if (phNxpUciHal_get_monitor()) \
215   pthread_mutex_unlock(&phNxpUciHal_get_monitor()->reentrance_mutex)
216 #define CONCURRENCY_LOCK()       \
217   if (phNxpUciHal_get_monitor()) \
218   pthread_mutex_lock(&phNxpUciHal_get_monitor()->concurrency_mutex)
219 #define CONCURRENCY_UNLOCK()     \
220   if (phNxpUciHal_get_monitor()) \
221   pthread_mutex_unlock(&phNxpUciHal_get_monitor()->concurrency_mutex)
222 
223 // Decode bytes into map<key=T, val=LV>
224 std::map<uint16_t, std::vector<uint8_t>>
225 decodeTlvBytes(const std::vector<uint8_t> &ext_ids, const uint8_t *tlv_bytes, size_t tlv_len);
226 
227 // Encode map<key=T, val=LV> into TLV bytes
228 std::vector<uint8_t> encodeTlvBytes(const std::map<uint16_t, std::vector<uint8_t>> &tlvs);
229 
230 #endif /* _PHNXPUCIHAL_UTILS_H_ */
231