1 /*
2  * Copyright 2012-2019, 2022-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 #include <sys/stat.h>
17 
18 #include <array>
19 #include <functional>
20 #include <string.h>
21 #include <list>
22 #include <map>
23 #include <mutex>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include <android-base/stringprintf.h>
28 #include <cutils/properties.h>
29 #include <log/log.h>
30 
31 #include <phNxpLog.h>
32 #include <phNxpUciHal.h>
33 #include <phNxpUciHal_Adaptation.h>
34 #include <phNxpUciHal_ext.h>
35 #include <phTmlUwb_spi.h>
36 
37 #include "hal_nxpuwb.h"
38 #include "phNxpConfig.h"
39 #include "phNxpUciHal_utils.h"
40 #include "sessionTrack.h"
41 
42 using namespace std;
43 using android::base::StringPrintf;
44 
45 /*********************** Global Variables *************************************/
46 /* UCI HAL Control structure */
47 phNxpUciHal_Control_t nxpucihal_ctrl;
48 
49 bool uwb_device_initialized = false;
50 bool uwb_get_platform_id = false;
51 uint32_t timeoutTimerId = 0;
52 char persistant_log_path[120];
53 constexpr long HAL_WRITE_TIMEOUT_MS = 1000;
54 /**************** local methods used in this file only ************************/
55 static void phNxpUciHal_write_complete(void* pContext, phTmlUwb_WriteTransactInfo* pInfo);
56 extern int phNxpUciHal_fw_download();
57 static void phNxpUciHal_getVersionInfo();
58 static tHAL_UWB_STATUS phNxpUciHal_sendCoreConfig(const uint8_t *p_cmd,
59                                                   long buffer_size);
60 
61 /*******************************************************************************
62  * RX packet handler
63  ******************************************************************************/
64 struct phNxpUciHal_RxHandler {
phNxpUciHal_RxHandlerphNxpUciHal_RxHandler65   phNxpUciHal_RxHandler(uint8_t mt, uint8_t gid, uint8_t oid,
66     bool run_once, RxHandlerCallback callback) :
67       mt(mt), gid(gid), oid(oid),
68       run_once(run_once),
69       callback(callback) { }
70 
71   // mt, gid, oid: packet type
72   uint8_t mt;
73   uint8_t gid;
74   uint8_t oid;
75   bool run_once;
76   RxHandlerCallback callback;
77 };
78 
79 static std::list<std::shared_ptr<phNxpUciHal_RxHandler>> rx_handlers;
80 static std::mutex rx_handlers_lock;
81 
phNxpUciHal_rx_handler_add(uint8_t mt,uint8_t gid,uint8_t oid,bool run_once,RxHandlerCallback callback)82 std::shared_ptr<phNxpUciHal_RxHandler> phNxpUciHal_rx_handler_add(
83   uint8_t mt, uint8_t gid, uint8_t oid,
84   bool run_once,
85   RxHandlerCallback callback)
86 {
87   auto handler = std::make_shared<phNxpUciHal_RxHandler>(
88     mt, gid, oid, run_once, callback);
89   std::lock_guard<std::mutex> guard(rx_handlers_lock);
90   rx_handlers.push_back(handler);
91   return handler;
92 }
93 
phNxpUciHal_rx_handler_del(std::shared_ptr<phNxpUciHal_RxHandler> handler)94 void phNxpUciHal_rx_handler_del(std::shared_ptr<phNxpUciHal_RxHandler> handler)
95 {
96   std::lock_guard<std::mutex> guard(rx_handlers_lock);
97   rx_handlers.remove(handler);
98 }
99 
100 // Returns true when this packet is handled by one of the handler.
phNxpUciHal_rx_handler_check(size_t packet_len,const uint8_t * packet)101 static bool phNxpUciHal_rx_handler_check(size_t packet_len, const uint8_t *packet)
102 {
103   const uint8_t mt = ((packet[0]) & UCI_MT_MASK) >> UCI_MT_SHIFT;
104   const uint8_t gid = packet[0] & UCI_GID_MASK;
105   const uint8_t oid = packet[1] & UCI_OID_MASK;
106   bool skip_packet = false;
107 
108   // Copy the whole list to allow rx handlers to call rx_handler_add().
109   std::list<std::shared_ptr<phNxpUciHal_RxHandler>> handlers;
110   {
111     std::lock_guard<std::mutex> guard(rx_handlers_lock);
112     handlers = rx_handlers;
113   }
114 
115   for (auto handler : handlers) {
116     if (mt == handler->mt && gid == handler->gid && oid == handler->oid) {
117       if (handler->callback(packet_len, packet)) {
118         skip_packet = true;
119       }
120     }
121   }
122 
123   std::lock_guard<std::mutex> guard(rx_handlers_lock);
124   rx_handlers.remove_if([mt, gid, oid](auto& handler) {
125     return mt == handler->mt && gid == handler->gid && oid == handler->oid && handler->run_once;
126   });
127 
128   return skip_packet;
129 }
130 
phNxpUciHal_rx_handler_destroy(void)131 static void phNxpUciHal_rx_handler_destroy(void)
132 {
133   std::lock_guard<std::mutex> guard(rx_handlers_lock);
134   rx_handlers.clear();
135 }
136 
137 /******************************************************************************
138  * Function         phNxpUciHal_client_thread
139  *
140  * Description      This function is a thread handler which handles all TML and
141  *                  UCI messages.
142  *
143  * Returns          void
144  *
145  ******************************************************************************/
phNxpUciHal_client_thread(phNxpUciHal_Control_t * p_nxpucihal_ctrl)146 static void phNxpUciHal_client_thread(phNxpUciHal_Control_t* p_nxpucihal_ctrl)
147 {
148   NXPLOG_UCIHAL_D("thread started");
149 
150   bool thread_running = true;
151 
152   while (thread_running) {
153     /* Fetch next message from the UWB stack message queue */
154     auto msg = p_nxpucihal_ctrl->gDrvCfg.pClientMq->recv();
155 
156     if (!thread_running) {
157       break;
158     }
159 
160     switch (msg->eMsgType) {
161       case PH_LIBUWB_DEFERREDCALL_MSG: {
162         phLibUwb_DeferredCall_t* deferCall = (phLibUwb_DeferredCall_t*)(msg->pMsgData);
163 
164         REENTRANCE_LOCK();
165         deferCall->pCallback(deferCall->pParameter);
166         REENTRANCE_UNLOCK();
167 
168         break;
169       }
170 
171       case UCI_HAL_OPEN_CPLT_MSG: {
172         REENTRANCE_LOCK();
173         if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
174           /* Send the event */
175           (*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_OPEN_CPLT_EVT,
176                                               HAL_UWB_STATUS_OK);
177         }
178         REENTRANCE_UNLOCK();
179         break;
180       }
181 
182       case UCI_HAL_CLOSE_CPLT_MSG: {
183         REENTRANCE_LOCK();
184         if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
185           /* Send the event */
186           (*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_CLOSE_CPLT_EVT,
187                                               HAL_UWB_STATUS_OK);
188         }
189         thread_running = false;
190         REENTRANCE_UNLOCK();
191         break;
192       }
193 
194       case UCI_HAL_INIT_CPLT_MSG: {
195         REENTRANCE_LOCK();
196         if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
197           /* Send the event */
198           (*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_INIT_CPLT_EVT,
199                                               HAL_UWB_STATUS_OK);
200         }
201         REENTRANCE_UNLOCK();
202         break;
203       }
204 
205       case UCI_HAL_ERROR_MSG: {
206         REENTRANCE_LOCK();
207         if (nxpucihal_ctrl.p_uwb_stack_cback != NULL) {
208           /* Send the event */
209           (*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_ERROR_EVT,
210                                               HAL_UWB_ERROR_EVT);
211         }
212         REENTRANCE_UNLOCK();
213         break;
214       }
215     }
216   }
217 
218   NXPLOG_UCIHAL_D("NxpUciHal thread stopped");
219 }
220 
221 /******************************************************************************
222  * Function         phNxpUciHal_parse
223  *
224  * Description      This function parses all the data passing through the HAL.
225  *
226  * Returns          It returns true if the incoming command to be skipped.
227  *
228  ******************************************************************************/
phNxpUciHal_parse(size_t * cmdlen,uint8_t * cmd)229 bool phNxpUciHal_parse(size_t* cmdlen, uint8_t* cmd)
230 {
231   bool ret = false;
232 
233   if ((*cmdlen) < UCI_MSG_HDR_SIZE) {
234     return false;
235   }
236 
237   const uint8_t mt = (cmd[0] &UCI_MT_MASK) >> UCI_MT_SHIFT;
238   const uint8_t gid = cmd[0] & UCI_GID_MASK;
239   const uint8_t oid = cmd[1] & UCI_OID_MASK;
240   if (mt != UCI_MT_CMD) {
241     return false;
242   }
243 
244   if ((gid == UCI_GID_ANDROID) && (oid == UCI_MSG_ANDROID_SET_COUNTRY_CODE)) {
245     char country_code[2];
246     if ((*cmdlen) == 6) {
247       country_code[0] = (char)cmd[4];
248       country_code[1] = (char)cmd[5];
249     } else {
250       NXPLOG_UCIHAL_E("Unexpected payload length for ANDROID_SET_COUNTRY_CODE, handle this with 00 country code");
251       country_code[0] = '0';
252       country_code[1] = '0';
253     }
254     phNxpUciHal_handle_set_country_code(country_code);
255     return true;
256   } else if ((gid == UCI_GID_PROPRIETARY_0x0F) && (oid == SET_VENDOR_SET_CALIBRATION)) {
257     if (cmd[UCI_MSG_HDR_SIZE + 1] == VENDOR_CALIB_PARAM_TX_POWER_PER_ANTENNA) {
258       // XXX: packet can be patched by here.
259       phNxpUciHal_handle_set_calibration(cmd, *cmdlen);
260     }
261   } else if ((gid == UCI_GID_SESSION_MANAGE) && (oid == UCI_MSG_SESSION_SET_APP_CONFIG)) {
262     // XXX: packet can be patched by here.
263     return phNxpUciHal_handle_set_app_config(cmdlen, cmd);
264   } else if ((gid == UCI_GID_SESSION_MANAGE) && (oid == UCI_MSG_SESSION_STATE_INIT)) {
265     SessionTrack_onSessionInit(*cmdlen, cmd);
266   } if (mt == UCI_MT_CMD && gid == UCI_GID_SESSION_CONTROL && oid == UCI_MSG_SESSION_START) {
267     SessionTrack_onSessionStart(*cmdlen, cmd);
268   }
269   return ret;
270 }
271 
272 /******************************************************************************
273  * Function         phNxpUciHal_open
274  *
275  * Description      This function is called by libuwb-uci during the
276  *                  initialization of the UWBC. It opens the physical connection
277  *                  with UWBC (SRXXX) and creates required client thread for
278  *                  operation.
279  *                  After open is complete, status is informed to libuwb-uci
280  *                  through callback function.
281  *
282  * Returns          This function return UWBSTATUS_SUCCES (0) in case of success
283  *                  In case of failure returns other failure value.
284  *
285  ******************************************************************************/
phNxpUciHal_open(uwb_stack_callback_t * p_cback,uwb_stack_data_callback_t * p_data_cback)286 tHAL_UWB_STATUS phNxpUciHal_open(uwb_stack_callback_t* p_cback, uwb_stack_data_callback_t* p_data_cback)
287 {
288   static const char uwb_dev_node[256] = "/dev/srxxx";
289   tHAL_UWB_STATUS wConfigStatus = UWBSTATUS_SUCCESS;
290 
291   if (nxpucihal_ctrl.halStatus == HAL_STATUS_OPEN) {
292     NXPLOG_UCIHAL_E("phNxpUciHal_open already open");
293     return UWBSTATUS_SUCCESS;
294   }
295 
296   NxpConfig_Init();
297 
298   /* initialize trace level */
299   phNxpLog_InitializeLogLevel();
300 
301   /*Create the timer for extns write response*/
302   timeoutTimerId = phOsalUwb_Timer_Create();
303 
304   if (!phNxpUciHal_init_monitor()) {
305     NXPLOG_UCIHAL_E("Init monitor failed");
306     return UWBSTATUS_FAILED;
307   }
308 
309   CONCURRENCY_LOCK();
310 
311   NXPLOG_UCIHAL_E("Assigning the default helios Node: %s", uwb_dev_node);
312   /* By default HAL status is HAL_STATUS_OPEN */
313   nxpucihal_ctrl.halStatus = HAL_STATUS_OPEN;
314 
315   nxpucihal_ctrl.p_uwb_stack_cback = p_cback;
316   nxpucihal_ctrl.p_uwb_stack_data_cback = p_data_cback;
317   nxpucihal_ctrl.fw_dwnld_mode = false;
318 
319   /* Configure hardware link */
320   nxpucihal_ctrl.gDrvCfg.pClientMq = std::make_shared<MessageQueue<phLibUwb_Message>>("Client");
321   nxpucihal_ctrl.gDrvCfg.nLinkType = ENUM_LINK_TYPE_SPI;
322 
323   // Default country code = '00'
324   nxpucihal_ctrl.country_code[0] = '0';
325   nxpucihal_ctrl.country_code[1] = '0';
326 
327   /* Initialize TML layer */
328   wConfigStatus = phTmlUwb_Init(uwb_dev_node, nxpucihal_ctrl.gDrvCfg.pClientMq);
329   if (wConfigStatus != UWBSTATUS_SUCCESS) {
330     NXPLOG_UCIHAL_E("phTmlUwb_Init Failed");
331     goto clean_and_return;
332   }
333 
334   /* Create the client thread */
335   nxpucihal_ctrl.client_thread =
336     std::thread{ &phNxpUciHal_client_thread, &nxpucihal_ctrl };
337 
338   nxpucihal_ctrl.halStatus = HAL_STATUS_OPEN;
339 
340   CONCURRENCY_UNLOCK();
341 
342   // Per-chip (SR1XX or SR200) implementation
343   nxpucihal_ctrl.uwb_chip = GetUwbChip();
344 
345   // Install rx packet handlers
346   phNxpUciHal_rx_handler_add(UCI_MT_RSP, UCI_GID_CORE, UCI_MSG_CORE_GET_CAPS_INFO,
347     false, phNxpUciHal_handle_get_caps_info);
348 
349   /* Call open complete */
350   phTmlUwb_DeferredCall(std::make_shared<phLibUwb_Message>(UCI_HAL_OPEN_CPLT_MSG));
351 
352   return UWBSTATUS_SUCCESS;
353 
354 clean_and_return:
355   CONCURRENCY_UNLOCK();
356 
357   /* Report error status */
358   (*nxpucihal_ctrl.p_uwb_stack_cback)(HAL_UWB_OPEN_CPLT_EVT, HAL_UWB_ERROR_EVT);
359 
360   nxpucihal_ctrl.p_uwb_stack_cback = NULL;
361   nxpucihal_ctrl.p_uwb_stack_data_cback = NULL;
362   phNxpUciHal_cleanup_monitor();
363   nxpucihal_ctrl.halStatus = HAL_STATUS_CLOSE;
364   return wConfigStatus;
365 }
366 
367 /******************************************************************************
368  * Function         phNxpUciHal_write
369  *
370  * Description      This function write the data to UWBC through physical
371  *                  interface (e.g. SPI) using the  driver interface.
372  *                  Before sending the data to UWBC, phNxpUciHal_write_ext
373  *                  is called to check if there is any extension processing
374  *                  is required for the UCI packet being sent out.
375  *
376  * Returns          It returns number of bytes successfully written to UWBC.
377  *
378  ******************************************************************************/
phNxpUciHal_write(size_t data_len,const uint8_t * p_data)379 int32_t phNxpUciHal_write(size_t data_len, const uint8_t* p_data) {
380   if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
381     return UWBSTATUS_FAILED;
382   }
383   SessionTrack_keepAlive();
384 
385   CONCURRENCY_LOCK();
386   auto status = phNxpUciHal_process_ext_cmd_rsp(data_len, p_data);
387   CONCURRENCY_UNLOCK();
388 
389   /* No data written */
390   return (status == UWBSTATUS_SUCCESS) ? data_len : 0;
391 }
392 
393 /******************************************************************************
394  * Function         phNxpUciHal_write_unlocked
395  *
396  * Description      This is the actual function which is being called by
397  *                  phNxpUciHal_write. This function writes the data to UWBC.
398  *                  It waits till write callback provide the result of write
399  *                  process.
400  *
401  * Returns          Status code.
402  *
403  ******************************************************************************/
phNxpUciHal_write_unlocked(size_t data_len,const uint8_t * p_data)404 tHAL_UWB_STATUS phNxpUciHal_write_unlocked(size_t data_len, const uint8_t* p_data) {
405   tHAL_UWB_STATUS status;
406 
407   if ((data_len > UCI_MAX_DATA_LEN) || (data_len < UCI_PKT_HDR_LEN)) {
408     NXPLOG_UCIHAL_E("Invalid data_len");
409     return UWBSTATUS_INVALID_PARAMETER;
410   }
411 
412   /* Create the local semaphore */
413   UciHalSemaphore cb_data;
414 
415   status = phTmlUwb_Write(p_data, data_len, phNxpUciHal_write_complete, &cb_data);
416 
417   if (status != UWBSTATUS_PENDING) {
418     return UWBSTATUS_FAILED;
419   }
420 
421   /* Wait for callback response */
422   if (cb_data.wait_timeout_msec(HAL_WRITE_TIMEOUT_MS)) {
423     NXPLOG_UCIHAL_E("write_unlocked semaphore error");
424     return UWBSTATUS_FAILED;
425   }
426 
427   return UWBSTATUS_SUCCESS;
428 }
429 
430 /******************************************************************************
431  * Function         phNxpUciHal_write_complete
432  *
433  * Description      This function handles write callback.
434  *
435  * Returns          void.
436  *
437  ******************************************************************************/
phNxpUciHal_write_complete(void * pContext,phTmlUwb_WriteTransactInfo * pInfo)438 static void phNxpUciHal_write_complete(void* pContext,
439                                        phTmlUwb_WriteTransactInfo* pInfo) {
440   UciHalSemaphore* p_cb_data = (UciHalSemaphore*)pContext;
441 
442   if (pInfo->wStatus == UWBSTATUS_SUCCESS) {
443     NXPLOG_UCIHAL_V("write successful status = 0x%x", pInfo->wStatus);
444   } else {
445     NXPLOG_UCIHAL_E("write error status = 0x%x", pInfo->wStatus);
446   }
447   p_cb_data->post(pInfo->wStatus);
448 }
449 
report_uci_message(const uint8_t * buffer,size_t len)450 void report_uci_message(const uint8_t* buffer, size_t len)
451 {
452   if ((nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) && (len <= UCI_MAX_PAYLOAD_LEN)) {
453     (*nxpucihal_ctrl.p_uwb_stack_data_cback)(len, buffer);
454   }
455 }
456 
handle_rx_packet(uint8_t * buffer,size_t length)457 static void handle_rx_packet(uint8_t *buffer, size_t length)
458 {
459   phNxpUciHal_print_packet(NXP_TML_UCI_RSP_NTF_UWBS_2_AP, buffer, length);
460 
461   uint8_t mt = ((buffer[0]) & UCI_MT_MASK) >> UCI_MT_SHIFT;
462   uint8_t gid = buffer[0] & UCI_GID_MASK;
463   uint8_t oid = buffer[1] & UCI_OID_MASK;
464   uint8_t pbf = (buffer[0] & UCI_PBF_MASK) >> UCI_PBF_SHIFT;
465 
466   bool isSkipPacket = false;
467 
468   if (phNxpUciHal_rx_handler_check(length, buffer)) {
469     isSkipPacket = true;
470   }
471 
472   if (mt == UCI_MT_NTF) {
473     if (!pbf && gid == UCI_GID_CORE && oid == UCI_MSG_CORE_GENERIC_ERROR_NTF) {
474       uint8_t status_code = buffer[UCI_RESPONSE_STATUS_OFFSET];
475 
476       if (status_code == UCI_STATUS_COMMAND_RETRY ||
477           status_code == UCI_STATUS_SYNTAX_ERROR) {
478         // Handle retransmissions
479         // TODO: Do not retransmit it when !nxpucihal_ctrl.hal_ext_enabled,
480         // Upper layer should take care of it.
481         isSkipPacket = true;
482         nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_COMMAND_RETRANSMIT);
483       } else if (status_code == UCI_STATUS_BUFFER_UNDERFLOW) {
484         if (nxpucihal_ctrl.hal_ext_enabled) {
485           NXPLOG_UCIHAL_E("Got Underflow error for ext cmd, retransmit");
486           isSkipPacket = true;
487           nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_COMMAND_RETRANSMIT);
488         } else {
489           // uci to handle retransmission
490           buffer[UCI_RESPONSE_STATUS_OFFSET] = UCI_STATUS_COMMAND_RETRY;
491           // TODO: Why this should be treated as fail? once we already patched
492           // the status code here. Write operation should be treated as success.
493           nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_FAILED);
494         }
495       } else {
496         // TODO: Why should we wake up the user thread here?
497         nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_FAILED);
498       }
499     }
500     // End of UCI_MT_NTF
501   } else if (mt == UCI_MT_RSP) {
502     if (nxpucihal_ctrl.hal_ext_enabled) {
503       isSkipPacket = true;
504 
505       if (pbf) {
506         /* XXX: fix the whole logic if this really happens */
507         NXPLOG_UCIHAL_E("FIXME: Fragmented packets received while processing internal commands!");
508       }
509 
510       uint8_t status_code = (length > UCI_RESPONSE_STATUS_OFFSET) ?
511         buffer[UCI_RESPONSE_STATUS_OFFSET] : UCI_STATUS_UNKNOWN;
512 
513       if (status_code == UCI_STATUS_OK) {
514         nxpucihal_ctrl.cmdrsp.Wakeup(gid, oid);
515       } else if ((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_SET_CONFIG)){
516         /* check if any configurations are not supported then ignore the
517           * UWBSTATUS_FEATURE_NOT_SUPPORTED status code*/
518         uint8_t status = phNxpUciHal_process_ext_rsp(length, buffer);
519         if (status == UWBSTATUS_SUCCESS) {
520           nxpucihal_ctrl.cmdrsp.Wakeup(gid, oid);
521         } else {
522           nxpucihal_ctrl.cmdrsp.WakeupError(status);
523         }
524       } else {
525         NXPLOG_UCIHAL_E("Got error status code(0x%x) from internal command.", status_code);
526         usleep(1);  // XXX: not sure if it's really needed
527         nxpucihal_ctrl.cmdrsp.WakeupError(UWBSTATUS_FAILED);
528       }
529     } else {
530       nxpucihal_ctrl.cmdrsp.Wakeup(gid, oid);
531     }
532   } // End of UCI_MT_RSP
533 
534   if (!isSkipPacket) {
535     /* Read successful, send the event to higher layer */
536     report_uci_message(buffer, length);
537   }
538 
539   /* Disable junk data check for each UCI packet*/
540   if(nxpucihal_ctrl.fw_dwnld_mode) {
541     if((gid == UCI_GID_CORE) && (oid == UCI_MSG_CORE_DEVICE_STATUS_NTF)){
542       nxpucihal_ctrl.fw_dwnld_mode = false;
543     }
544   }
545 }
546 
547 /******************************************************************************
548  * Function         phNxpUciHal_read_complete
549  *
550  * Description      This function is called whenever there is an UCI packet
551  *                  received from UWBC. It could be RSP or NTF packet. This
552  *                  function provide the received UCI packet to libuwb-uci
553  *                  using data callback of libuwb-uci.
554  *                  There is a pending read called from each
555  *                  phNxpUciHal_read_complete so each a packet received from
556  *                  UWBC can be provide to libuwb-uci.
557  *
558  * Returns          void.
559  *
560  ******************************************************************************/
phNxpUciHal_read_complete(void * pContext,phTmlUwb_ReadTransactInfo * pInfo)561 void phNxpUciHal_read_complete(void* pContext, phTmlUwb_ReadTransactInfo* pInfo)
562 {
563   UNUSED(pContext);
564 
565   if (pInfo->wStatus != UWBSTATUS_SUCCESS) {
566     NXPLOG_UCIHAL_E("read error status = 0x%x", pInfo->wStatus);
567     return;
568   }
569 
570   NXPLOG_UCIHAL_V("read successful status = 0x%x , total len = 0x%x",
571                   pInfo->wStatus, pInfo->wLength);
572 
573   for (int32_t index = 0; index < pInfo->wLength; )
574   {
575     uint8_t extBitSet = (pInfo->pBuff[index + EXTND_LEN_INDICATOR_OFFSET] & EXTND_LEN_INDICATOR_OFFSET_MASK);
576     int32_t length = pInfo->pBuff[index + NORMAL_MODE_LENGTH_OFFSET];
577     if (extBitSet || ((pInfo->pBuff[index] & UCI_MT_MASK) == 0x00)) {
578      length = (length << EXTENDED_MODE_LEN_SHIFT) | pInfo->pBuff[index + EXTENDED_MODE_LEN_OFFSET] ;
579     }
580     length += UCI_MSG_HDR_SIZE;
581 
582     if ((index + length) > pInfo->wLength) {
583       NXPLOG_UCIHAL_E("RX Packet misaligned! given length=%u, offset=%d, len=%d",
584         pInfo->wLength, index, length);
585       return;
586     }
587     handle_rx_packet(&pInfo->pBuff[index], length);
588 
589     index += length;
590   } //End of loop
591 }
592 
593 /******************************************************************************
594  * Function         phNxpUciHal_close
595  *
596  * Description      This function close the UWBC interface and free all
597  *                  resources.This is called by libuwb-uci on UWB service stop.
598  *
599  * Returns          Always return UWBSTATUS_SUCCESS (0).
600  *
601  ******************************************************************************/
phNxpUciHal_close()602 tHAL_UWB_STATUS phNxpUciHal_close() {
603   tHAL_UWB_STATUS status;
604   if (nxpucihal_ctrl.halStatus == HAL_STATUS_CLOSE) {
605     NXPLOG_UCIHAL_E("phNxpUciHal_close is already closed, ignoring close");
606     return UWBSTATUS_FAILED;
607   }
608 
609   uwb_device_initialized = false;
610 
611   CONCURRENCY_LOCK();
612 
613   SessionTrack_deinit();
614 
615   NXPLOG_UCIHAL_D("Terminating phNxpUciHal client thread...");
616   phTmlUwb_DeferredCall(std::make_shared<phLibUwb_Message>(UCI_HAL_CLOSE_CPLT_MSG));
617   nxpucihal_ctrl.client_thread.join();
618 
619   status = phTmlUwb_Shutdown();
620 
621   phNxpUciHal_rx_handler_destroy();
622 
623   nxpucihal_ctrl.halStatus = HAL_STATUS_CLOSE;
624 
625   CONCURRENCY_UNLOCK();
626 
627   nxpucihal_ctrl.uwb_chip.reset();
628 
629   phOsalUwb_Timer_Cleanup();
630 
631   phNxpUciHal_cleanup_monitor();
632 
633   NxpConfig_Deinit();
634 
635   NXPLOG_UCIHAL_D("phNxpUciHal_close completed");
636 
637   /* Return success always */
638   return UWBSTATUS_SUCCESS;
639 }
640 
641 /******************************************************************************
642  * Function         parseAntennaConfig
643  *
644  * Description      This function parse the antenna config and update required
645  *                  params
646  *
647  * Returns          void
648  *
649  ******************************************************************************/
parseAntennaConfig(const char * configName)650 static void parseAntennaConfig(const char *configName)
651 {
652   std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> buffer;
653   size_t retlen = 0;
654   int gotConfig = NxpConfig_GetByteArray(configName, buffer.data(), buffer.size(), &retlen);
655   if (gotConfig) {
656     if (retlen <= UCI_MSG_HDR_SIZE) {
657       NXPLOG_UCIHAL_E("parseAntennaConfig: %s is too short. Aborting.", configName);
658       return;
659     }
660   }
661   else
662   {
663     NXPLOG_UCIHAL_E("parseAntennaConfig: Failed to get '%s'. Aborting.", configName);
664     return;
665   }
666 
667   const uint16_t dataLength = retlen;
668   const uint8_t *data = buffer.data();
669 
670   uint8_t index = 1; // Excluding number of params
671   uint8_t tagId, subTagId;
672   int length;
673   while (index < dataLength) {
674     tagId = data[index++];
675     subTagId = data[index++];
676     length = data[index++];
677     if ((ANTENNA_RX_PAIR_DEFINE_TAG_ID == tagId) &&
678         (ANTENNA_RX_PAIR_DEFINE_SUB_TAG_ID == subTagId)) {
679       nxpucihal_ctrl.numberOfAntennaPairs = data[index];
680       NXPLOG_UCIHAL_D("numberOfAntennaPairs:%d", nxpucihal_ctrl.numberOfAntennaPairs);
681       break;
682     } else {
683       index = index + length;
684     }
685   }
686 }
687 
688 /******************************************************************************
689  * Function         phNxpUciHal_applyVendorConfig
690  *
691  * Description      This function applies the vendor config from config file
692  *
693  * Returns          status
694  *
695  ******************************************************************************/
phNxpUciHal_applyVendorConfig()696 tHAL_UWB_STATUS phNxpUciHal_applyVendorConfig()
697 {
698   std::vector<const char *> vendorParamNames;
699   std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> buffer;
700   size_t retlen = 0;
701   tHAL_UWB_STATUS status = UWBSTATUS_FAILED;
702 
703   // Base parameter names
704   if (nxpucihal_ctrl.fw_boot_mode == USER_FW_BOOT_MODE) {
705     vendorParamNames.push_back(NAME_UWB_USER_FW_BOOT_MODE_CONFIG);
706   }
707   vendorParamNames.push_back(NAME_NXP_UWB_EXTENDED_NTF_CONFIG);
708 
709   // Chip parameter names
710   const char *per_chip_param = NAME_UWB_CORE_EXT_DEVICE_DEFAULT_CONFIG;
711   if (nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxT) {
712     per_chip_param = NAME_UWB_CORE_EXT_DEVICE_SR1XX_T_CONFIG;
713   } else if (nxpucihal_ctrl.device_type == DEVICE_TYPE_SR1xxS) {
714     per_chip_param = NAME_UWB_CORE_EXT_DEVICE_SR1XX_S_CONFIG;
715   }
716 
717   if (NxpConfig_GetByteArray(per_chip_param, buffer.data(), buffer.size(),
718                              &retlen)) {
719     if (retlen > 0 && retlen < UCI_MAX_DATA_LEN) {
720       NXPLOG_UCIHAL_D("VendorConfig: apply %s", per_chip_param);
721       status = phNxpUciHal_sendCoreConfig(buffer.data(), retlen);
722       if (status != UWBSTATUS_SUCCESS) {
723         NXPLOG_UCIHAL_E("VendorConfig: failed to apply %s", per_chip_param);
724         return status;
725       }
726     }
727   }
728 
729   // Parse Antenna config from chip-parameter
730   parseAntennaConfig(per_chip_param);
731 
732   // Extra parameter names, XTAL, NXP_CORE_CONF_BLK[1..10]
733   vendorParamNames.push_back(NAME_NXP_UWB_XTAL_38MHZ_CONFIG);
734   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "1");
735   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "2");
736   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "3");
737   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "4");
738   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "5");
739   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "6");
740   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "7");
741   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "8");
742   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "9");
743   vendorParamNames.push_back(NAME_NXP_CORE_CONF_BLK "10");
744 
745   // Execute
746   for (const auto paramName : vendorParamNames) {
747     if (NxpConfig_GetByteArray(paramName, buffer.data(), buffer.size(), &retlen)) {
748       if (retlen > 0 && retlen < UCI_MAX_DATA_LEN) {
749         NXPLOG_UCIHAL_D("VendorConfig: apply %s", paramName);
750         status = phNxpUciHal_send_ext_cmd(retlen, buffer.data());
751         if (status != UWBSTATUS_SUCCESS) {
752           NXPLOG_UCIHAL_E("VendorConfig: failed to apply %s", paramName);
753           return status;
754         }
755       }
756     }
757   }
758 
759   // Low Power Mode
760   // TODO: remove this out, this can be move to Chip parameter names
761   uint8_t lowPowerMode = 0;
762   if (NxpConfig_GetNum(NAME_NXP_UWB_LOW_POWER_MODE, &lowPowerMode, sizeof(lowPowerMode))) {
763     NXPLOG_UCIHAL_D("VendorConfig: apply %s", NAME_NXP_UWB_LOW_POWER_MODE);
764 
765     // Core set config packet: GID=0x00 OID=0x04
766     const std::vector<uint8_t> packet(
767         {((UCI_MT_CMD << UCI_MT_SHIFT) | UCI_GID_CORE), UCI_MSG_CORE_SET_CONFIG,
768          0x00, 0x04, 0x01, LOW_POWER_MODE_TAG_ID, LOW_POWER_MODE_LENGTH,
769          lowPowerMode});
770 
771     if (phNxpUciHal_send_ext_cmd(packet.size(), packet.data()) != UWBSTATUS_SUCCESS) {
772       NXPLOG_UCIHAL_E("VendorConfig: failed to apply NAME_NXP_UWB_LOW_POWER_MODE");
773     }
774   }
775 
776   return UWBSTATUS_SUCCESS;
777 }
778 
779 /******************************************************************************
780  * Function         phNxpUciHal_uwb_reset
781  *
782  * Description      This function will send UWB reset command
783  *
784  * Returns          status
785  *
786  ******************************************************************************/
phNxpUciHal_uwb_reset()787 tHAL_UWB_STATUS phNxpUciHal_uwb_reset() {
788   tHAL_UWB_STATUS status;
789   uint8_t buffer[] = {0x20, 0x00, 0x00, 0x01, 0x00};
790   status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
791   if(status != UWBSTATUS_SUCCESS) {
792     return status;
793   }
794   return UWBSTATUS_SUCCESS;
795 }
796 
cacheDevInfoRsp()797 static bool cacheDevInfoRsp()
798 {
799   auto dev_info_cb = [](size_t packet_len, const uint8_t *packet) mutable -> bool {
800     if (packet_len < 5 || packet[UCI_RESPONSE_STATUS_OFFSET] != UWBSTATUS_SUCCESS) {
801       NXPLOG_UCIHAL_E("Failed to get valid CORE_DEVICE_INFO_RSP");
802       return true;
803     }
804     if (packet_len > sizeof(nxpucihal_ctrl.dev_info_resp)) {
805       NXPLOG_UCIHAL_E("FIXME: CORE_DEVICE_INFO_RSP buffer overflow!");
806       return true;
807     }
808 
809     // FIRA UCIv2.0 packet size = 14
810     // [13] = Vendor Specific Info Length
811     constexpr uint8_t firaDevInfoRspSize = 14;
812     constexpr uint8_t firaDevInfoVendorLenOffset = 13;
813 
814     if (packet_len < firaDevInfoRspSize) {
815       NXPLOG_UCIHAL_E("DEVICE_INFO_RSP packet size mismatched.");
816       return true;
817     }
818 
819     const uint8_t vendorSpecificLen = packet[firaDevInfoVendorLenOffset];
820     if (packet_len != (firaDevInfoRspSize + vendorSpecificLen)) {
821       NXPLOG_UCIHAL_E("DEVICE_INFO_RSP packet size mismatched.");
822     }
823 
824     for (uint8_t i = firaDevInfoRspSize; (i + 2) <= packet_len; ) {
825       uint8_t paramId = packet[i++];
826       uint8_t length = packet[i++];
827 
828       if (i + length > packet_len)
829         break;
830 
831       if (paramId == DEVICE_NAME_PARAM_ID && length >= 6) {
832         nxpucihal_ctrl.device_type = nxpucihal_ctrl.uwb_chip->get_device_type(&packet[i], length);
833       } else if (paramId == FW_VERSION_PARAM_ID && length >= 3) {
834         nxpucihal_ctrl.fw_version.major_version = packet[i];
835         nxpucihal_ctrl.fw_version.minor_version = packet[i + 1];
836         nxpucihal_ctrl.fw_version.rc_version = packet[i + 2];
837       } else if (paramId == FW_BOOT_MODE_PARAM_ID && length >= 1) {
838         nxpucihal_ctrl.fw_boot_mode = packet[i];
839       }
840       i += length;
841     }
842     memcpy(nxpucihal_ctrl.dev_info_resp, packet, packet_len);
843     nxpucihal_ctrl.isDevInfoCached = true;
844     NXPLOG_UCIHAL_D("Device Info cached.");
845     return true;
846   };
847 
848   nxpucihal_ctrl.isDevInfoCached = false;
849   UciHalRxHandler devInfoRspHandler(UCI_MT_RSP, UCI_GID_CORE, UCI_MSG_CORE_DEVICE_INFO, dev_info_cb);
850 
851   const uint8_t CoreGetDevInfoCmd[] = {(UCI_MT_CMD << UCI_MT_SHIFT) | UCI_GID_CORE, UCI_MSG_CORE_DEVICE_INFO, 0, 0};
852   tHAL_UWB_STATUS status = phNxpUciHal_send_ext_cmd(sizeof(CoreGetDevInfoCmd), CoreGetDevInfoCmd);
853   if (status != UWBSTATUS_SUCCESS) {
854     return false;
855   }
856   return true;
857 }
858 
859 /******************************************************************************
860  * Function         phNxpUciHal_init_hw
861  *
862  * Description      Init the chip.
863  *
864  * Returns          status
865  *
866  ******************************************************************************/
phNxpUciHal_init_hw()867 tHAL_UWB_STATUS phNxpUciHal_init_hw()
868 {
869   tHAL_UWB_STATUS status;
870 
871   if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
872     NXPLOG_UCIHAL_E("HAL not initialized");
873     return UWBSTATUS_FAILED;
874   }
875 
876   uwb_device_initialized = false;
877 
878   // Device Status Notification
879   UciHalSemaphore devStatusNtfWait;
880   uint8_t dev_status = UWB_DEVICE_ERROR;
881   auto dev_status_ntf_cb = [&dev_status, &devStatusNtfWait]
882       (size_t packet_len, const uint8_t *packet) mutable -> bool {
883     if (packet_len >= 5) {
884       dev_status = packet[UCI_RESPONSE_STATUS_OFFSET];
885       devStatusNtfWait.post();
886     }
887     return true;
888   };
889   UciHalRxHandler devStatusNtfHandler(UCI_MT_NTF, UCI_GID_CORE, UCI_MSG_CORE_DEVICE_STATUS_NTF,
890                                       dev_status_ntf_cb);
891 
892   // FW download and enter UCI operating mode
893   status = nxpucihal_ctrl.uwb_chip->chip_init();
894   if (status != UWBSTATUS_SUCCESS) {
895     return status;
896   }
897 
898   // Initiate UCI packet read
899   status = phTmlUwb_StartRead(&phNxpUciHal_read_complete, NULL);
900   if (status != UWBSTATUS_SUCCESS) {
901     NXPLOG_UCIHAL_E("read status error status = %x", status);
902     return status;
903   }
904 
905   // Wait for the first Device Status Notification
906   devStatusNtfWait.wait_timeout_msec(3000);
907   if(dev_status != UWB_DEVICE_INIT && dev_status != UWB_DEVICE_READY) {
908     NXPLOG_UCIHAL_E("First Device Status NTF was not received or it's invalid state. 0x%x", dev_status);
909     return UWBSTATUS_FAILED;
910   }
911 
912   // Set board-config and wait for Device Status Notification
913   status = phNxpUciHal_set_board_config();
914   if (status != UWBSTATUS_SUCCESS) {
915     NXPLOG_UCIHAL_E("%s: Set Board Config Failed", __func__);
916     return status;
917   }
918   devStatusNtfWait.wait_timeout_msec(3000);
919   if (dev_status != UWB_DEVICE_READY) {
920     NXPLOG_UCIHAL_E("Cannot receive UWB_DEVICE_READY");
921     return UWBSTATUS_FAILED;
922   }
923 
924   // Send SW reset and wait for Device Status Notification
925   dev_status = UWB_DEVICE_ERROR;
926   status = phNxpUciHal_uwb_reset();
927   if (status != UWBSTATUS_SUCCESS) {
928     NXPLOG_UCIHAL_E("%s: device reset Failed", __func__);
929     return status;
930   }
931   devStatusNtfWait.wait_timeout_msec(3000);
932   if(dev_status != UWB_DEVICE_READY) {
933     NXPLOG_UCIHAL_E("UWB_DEVICE_READY not received uwbc_device_state = %x", dev_status);
934     return UWBSTATUS_FAILED;
935   }
936 
937   // Cache CORE_GET_DEVICE_INFO
938   cacheDevInfoRsp();
939 
940   status = nxpucihal_ctrl.uwb_chip->core_init();
941   if (status != UWBSTATUS_SUCCESS) {
942     return status;
943   }
944 
945   status = phNxpUciHal_applyVendorConfig();
946   if (status != UWBSTATUS_SUCCESS) {
947     NXPLOG_UCIHAL_E("%s: Apply vendor Config Failed", __func__);
948     return status;
949   }
950   phNxpUciHal_extcal_handle_coreinit();
951 
952   uwb_device_initialized = true;
953   phNxpUciHal_getVersionInfo();
954 
955   return UWBSTATUS_SUCCESS;
956 }
957 
958 /******************************************************************************
959  * Function         phNxpUciHal_coreInitialization
960  *
961  * Description      This function performs core initialization
962  *
963  * Returns          status
964  *
965  ******************************************************************************/
phNxpUciHal_coreInitialization()966 tHAL_UWB_STATUS phNxpUciHal_coreInitialization()
967 {
968   tHAL_UWB_STATUS status = phNxpUciHal_init_hw();
969   if (status != UWBSTATUS_SUCCESS) {
970     phTmlUwb_DeferredCall(std::make_shared<phLibUwb_Message>(UCI_HAL_ERROR_MSG));
971     return status;
972   }
973 
974   SessionTrack_init();
975 
976   // report to upper-layer
977   phTmlUwb_DeferredCall(std::make_shared<phLibUwb_Message>(UCI_HAL_INIT_CPLT_MSG));
978 
979   constexpr uint8_t dev_ready_ntf[] = {0x60, 0x01, 0x00, 0x01, 0x01};
980   report_uci_message(dev_ready_ntf, sizeof(dev_ready_ntf));
981 
982   return UWBSTATUS_SUCCESS;
983 }
984 
985 /******************************************************************************
986  * Function         phNxpUciHal_sessionInitialization
987  *
988  * Description      This function performs session initialization
989  *
990  * Returns          status
991  *
992  ******************************************************************************/
phNxpUciHal_sessionInitialization(uint32_t sessionId)993 tHAL_UWB_STATUS phNxpUciHal_sessionInitialization(uint32_t sessionId) {
994   NXPLOG_UCIHAL_D(" %s: Enter", __func__);
995   tHAL_UWB_STATUS status = UWBSTATUS_SUCCESS;
996 
997   if (nxpucihal_ctrl.halStatus != HAL_STATUS_OPEN) {
998     NXPLOG_UCIHAL_E("HAL not initialized");
999     return UWBSTATUS_FAILED;
1000   }
1001   return status;
1002 }
1003 
1004 /******************************************************************************
1005  * Function         phNxpUciHal_GetMwVersion
1006  *
1007  * Description      This function gets the middleware version
1008  *
1009  * Returns          phNxpUciHal_MW_Version_t
1010  *
1011  ******************************************************************************/
phNxpUciHal_GetMwVersion()1012 phNxpUciHal_MW_Version_t phNxpUciHal_GetMwVersion() {
1013   phNxpUciHal_MW_Version_t mwVer;
1014   mwVer.validation = NXP_CHIP_SR100;
1015   mwVer.android_version = NXP_ANDROID_VERSION;
1016   NXPLOG_UCIHAL_D("0x%x:UWB MW Major Version:", UWB_NXP_MW_VERSION_MAJ);
1017   NXPLOG_UCIHAL_D("0x%x:UWB MW Minor Version:", UWB_NXP_MW_VERSION_MIN);
1018   mwVer.major_version = UWB_NXP_MW_VERSION_MAJ;
1019   mwVer.minor_version = UWB_NXP_MW_VERSION_MIN;
1020   mwVer.rc_version = UWB_NXP_ANDROID_MW_RC_VERSION;
1021   mwVer.mw_drop = UWB_NXP_ANDROID_MW_DROP_VERSION;
1022   return mwVer;
1023 }
1024 
1025 /******************************************************************************
1026  * Function         phNxpUciHal_getVersionInfo
1027  *
1028  * Description      This function request for version information
1029  *
1030  * Returns          void
1031  *
1032  ******************************************************************************/
phNxpUciHal_getVersionInfo()1033 void phNxpUciHal_getVersionInfo() {
1034   phNxpUciHal_MW_Version_t mwVersion = phNxpUciHal_GetMwVersion();
1035   if (mwVersion.rc_version) { /* for RC release*/
1036     ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x_RC%02x",
1037           mwVersion.major_version, mwVersion.minor_version,
1038           mwVersion.rc_version);
1039   } else if (mwVersion.mw_drop) { /* For Drops */
1040     ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x_DROP%02x",
1041           mwVersion.major_version, mwVersion.minor_version, mwVersion.mw_drop);
1042   } else { /* for Major Releases*/
1043     ALOGI("MW Version: UWB_SW_Android_U_HKY_D%02x.%02x",
1044           mwVersion.major_version, mwVersion.minor_version);
1045   }
1046 
1047   if (nxpucihal_ctrl.fw_version.rc_version) {
1048     ALOGI("FW Version: %02x.%02x_RC%02x", nxpucihal_ctrl.fw_version.major_version,
1049           nxpucihal_ctrl.fw_version.minor_version, nxpucihal_ctrl.fw_version.rc_version);
1050   } else {
1051     ALOGI("FW Version: %02x.%02x", nxpucihal_ctrl.fw_version.major_version,
1052           nxpucihal_ctrl.fw_version.minor_version);
1053   }
1054 }
1055 
1056 /******************************************************************************
1057  * Function         phNxpUciHal_sendCoreConfig
1058  *
1059  * Description      This function send set core config command in chunks when
1060  *                  config size greater than 255 bytes.
1061  *
1062  * Returns          status
1063  *
1064  ******************************************************************************/
phNxpUciHal_sendCoreConfig(const uint8_t * p_cmd,long buffer_size)1065 tHAL_UWB_STATUS phNxpUciHal_sendCoreConfig(const uint8_t *p_cmd,
1066                                            long buffer_size) {
1067   std::array<uint8_t, NXP_MAX_CONFIG_STRING_LEN> payload_data;
1068   tHAL_UWB_STATUS status = UWBSTATUS_FAILED;
1069   uint16_t i = 0;
1070 
1071   while (buffer_size > 0) {
1072     uint16_t chunk_size = (buffer_size <= UCI_MAX_CONFIG_PAYLOAD_LEN)
1073                               ? buffer_size
1074                               : UCI_MAX_CONFIG_PAYLOAD_LEN;
1075 
1076     payload_data[0] = (buffer_size <= UCI_MAX_CONFIG_PAYLOAD_LEN) ? 0x20 : 0x30;
1077     payload_data[1] = 0x04;
1078     payload_data[2] = 0x00;
1079     payload_data[3] = chunk_size;
1080 
1081     std::memcpy(&payload_data[UCI_PKT_HDR_LEN], &p_cmd[i], chunk_size);
1082 
1083     status = phNxpUciHal_send_ext_cmd(chunk_size + UCI_PKT_HDR_LEN,
1084                                       payload_data.data());
1085 
1086     i += chunk_size;
1087     buffer_size -= chunk_size;
1088   }
1089 
1090   return status;
1091 }
1092 
1093 /*******************************************************************************
1094  * Function      phNxpUciHal_send_dev_error_status_ntf
1095  *
1096  * Description   send device status notification. Upper layer might restart
1097  *               HAL service.
1098  *
1099  * Returns       void
1100  *
1101  ******************************************* ***********************************/
phNxpUciHal_send_dev_error_status_ntf()1102 void phNxpUciHal_send_dev_error_status_ntf()
1103 {
1104   NXPLOG_UCIHAL_D("phNxpUciHal_send_dev_error_status_ntf ");
1105   constexpr uint8_t rsp_data[5] = {0x60, 0x01, 0x00, 0x01, 0xFF};
1106   report_uci_message(rsp_data, sizeof(rsp_data));
1107 }
1108