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