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