1 /*
2 * Copyright 2012-2019, 2022-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 #include <sys/stat.h>
17
18 #include <atomic>
19 #include <bitset>
20 #include <limits>
21 #include <map>
22 #include <optional>
23 #include <span>
24 #include <vector>
25
26 #include <cutils/properties.h>
27
28 #include "phNxpConfig.h"
29 #include "phNxpLog.h"
30 #include "phNxpUciHal.h"
31 #include "phNxpUciHal_ext.h"
32 #include "phNxpUciHal_utils.h"
33 #include "phTmlUwb.h"
34 #include "phUwbCommon.h"
35 #include "sessionTrack.h"
36
37 /* Timeout value to wait for response from DEVICE_TYPE_SR1xx */
38 #define MAX_COMMAND_RETRY_COUNT 5
39 #define HAL_EXTNS_WRITE_RSP_TIMEOUT_MS 100
40 #define HAL_HW_RESET_NTF_TIMEOUT 10000 /* 10 sec wait */
41
42 /******************* Global variables *****************************************/
43 extern phNxpUciHal_Control_t nxpucihal_ctrl;
44
45 static std::vector<uint8_t> gtx_power;
46
47 /************** HAL extension functions ***************************************/
48 static bool phNxpUciHal_is_retry_not_required(uint8_t uci_octet0);
49 static void phNxpUciHal_clear_thermal_error_status();
50 static void phNxpUciHal_hw_reset_ntf_timeout_cb(uint32_t timerId,
51 void *pContext);
52
53 /******************************************************************************
54 * Function phNxpUciHal_process_ext_cmd_rsp
55 *
56 * Description This function process the extension command response. It
57 * also checks the received response to expected response.
58 *
59 * Returns returns UWBSTATUS_SUCCESS if response is as expected else
60 * returns failure.
61 *
62 ******************************************************************************/
phNxpUciHal_process_ext_cmd_rsp(size_t cmd_len,const uint8_t * p_cmd)63 tHAL_UWB_STATUS phNxpUciHal_process_ext_cmd_rsp(size_t cmd_len,
64 const uint8_t *p_cmd) {
65 if (cmd_len > UCI_MAX_DATA_LEN) {
66 NXPLOG_UCIHAL_E("Packet size is too big to send: %u.", cmd_len);
67 return UWBSTATUS_FAILED;
68 }
69 if (cmd_len < 1) {
70 return UWBSTATUS_FAILED;
71 }
72
73
74 // PBF=1 or DATA packet: don't check RSP
75 // upper-layer should handle the case of UWBSTATUS_COMMAND_RETRANSMIT && isRetryNotRequired
76 if (phNxpUciHal_is_retry_not_required(p_cmd[0]) ||
77 cmd_len < UCI_MSG_HDR_SIZE) {
78 return phNxpUciHal_write_unlocked(cmd_len, p_cmd);
79 }
80
81 const uint8_t mt = (p_cmd[0] & UCI_MT_MASK) >> UCI_MT_SHIFT;
82 const uint8_t gid = p_cmd[0] & UCI_GID_MASK;
83 const uint8_t oid = p_cmd[1] & UCI_OID_MASK;
84
85 // Create local copy of cmd_data
86 uint8_t cmd[UCI_MAX_DATA_LEN];
87 memcpy(cmd, p_cmd, cmd_len);
88
89 /* Vendor Specific Parsing logic */
90 if (phNxpUciHal_parse(&cmd_len, cmd)) {
91 return UWBSTATUS_SUCCESS;
92 }
93
94 tHAL_UWB_STATUS status = UWBSTATUS_FAILED;
95 int nr_retries = 0;
96 int nr_timedout = 0;
97
98 while(nr_retries < MAX_COMMAND_RETRY_COUNT) {
99 nxpucihal_ctrl.cmdrsp.StartCmd(gid, oid);
100 status = phNxpUciHal_write_unlocked(cmd_len, cmd);
101
102 if (status != UWBSTATUS_SUCCESS) {
103 NXPLOG_UCIHAL_D("phNxpUciHal_write failed for hal ext");
104 nxpucihal_ctrl.cmdrsp.Cancel();
105 return status;
106 }
107
108 // Wait for rsp
109 status = nxpucihal_ctrl.cmdrsp.Wait(HAL_EXTNS_WRITE_RSP_TIMEOUT_MS);
110
111 if (status == UWBSTATUS_RESPONSE_TIMEOUT) {
112 nr_timedout++;
113 nr_retries++;
114 } else if (status == UWBSTATUS_COMMAND_RETRANSMIT) {
115 // TODO: Do not retransmit CMD by here when !nxpucihal_ctrl.hal_ext_enabled,
116 // Upper layer should take care of it.
117 nr_retries++;
118 } else {
119 break;
120 }
121 }
122
123 if (nr_retries >= MAX_COMMAND_RETRY_COUNT) {
124 NXPLOG_UCIHAL_E("Failed to process cmd/rsp 0x%x", status);
125 phNxpUciHal_send_dev_error_status_ntf();
126 return UWBSTATUS_FAILED;
127 }
128
129 if (nr_timedout > 0) {
130 NXPLOG_UCIHAL_E("Warning: CMD/RSP retried %d times (timeout:%d)\n",
131 nr_retries, nr_timedout);
132 }
133
134 return status;
135 }
136
137 /******************************************************************************
138 * Function phNxpUciHal_send_ext_cmd
139 *
140 * Description This function send the extension command to UWBC. No
141 * response is checked by this function but it waits for
142 * the response to come.
143 *
144 * Returns Returns UWBSTATUS_SUCCESS if sending cmd is successful and
145 * response is received.
146 *
147 ******************************************************************************/
phNxpUciHal_send_ext_cmd(size_t cmd_len,const uint8_t * p_cmd)148 tHAL_UWB_STATUS phNxpUciHal_send_ext_cmd(size_t cmd_len, const uint8_t* p_cmd) {
149 if (cmd_len >= UCI_MAX_DATA_LEN) {
150 return UWBSTATUS_FAILED;
151 }
152
153 HAL_ENABLE_EXT();
154 tHAL_UWB_STATUS status = phNxpUciHal_process_ext_cmd_rsp(cmd_len, p_cmd);
155 HAL_DISABLE_EXT();
156
157 return status;
158 }
159
160 /******************************************************************************
161 * Function phNxpUciHal_set_board_config
162 *
163 * Description This function is called to set the board varaint config
164 * Returns return 0 on success and -1 on fail, On success
165 * update the acutual state of operation in arg pointer
166 *
167 ******************************************************************************/
phNxpUciHal_set_board_config()168 tHAL_UWB_STATUS phNxpUciHal_set_board_config() {
169 uint8_t buffer[6] = {0x2E,0x00,0x00,0x02,0x01,0x01};
170
171 uint8_t boardConfig = NxpConfig_GetNum<uint8_t>(NAME_UWB_BOARD_VARIANT_CONFIG).value_or(0);
172 uint8_t boardVersion = NxpConfig_GetNum<uint8_t>(NAME_UWB_BOARD_VARIANT_VERSION).value_or(0);
173
174 NXPLOG_UCIHAL_D("Board variant config: config=0x%x, version=0x%x", boardConfig, boardVersion);
175
176 buffer[4] = boardConfig;
177 buffer[5] = boardVersion;
178
179 return phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
180 }
181
182 /*******************************************************************************
183 **
184 ** Function phNxpUciHal_process_ext_rsp
185 **
186 ** Description Process extension function response
187 **
188 ** Returns UWBSTATUS_SUCCESS if success
189 **
190 *******************************************************************************/
phNxpUciHal_process_ext_rsp(size_t rsp_len,uint8_t * p_buff)191 tHAL_UWB_STATUS phNxpUciHal_process_ext_rsp(size_t rsp_len, uint8_t* p_buff){
192 tHAL_UWB_STATUS status;
193 int NumOfTlv, index;
194 uint8_t paramId, extParamId, IdStatus;
195 index = UCI_NTF_PAYLOAD_OFFSET; // index for payload start
196 status = p_buff[index++];
197 if(status == UCI_STATUS_OK){
198 NXPLOG_UCIHAL_D("%s: status success %d", __func__, status);
199 return UWBSTATUS_SUCCESS;
200 }
201 NumOfTlv = p_buff[index++];
202 while (index < rsp_len) {
203 paramId = p_buff[index++];
204 if(paramId == EXTENDED_DEVICE_CONFIG_ID) {
205 extParamId = p_buff[index++];
206 IdStatus = p_buff[index++];
207
208 switch(extParamId) {
209 case UCI_EXT_PARAM_DELAY_CALIBRATION_VALUE:
210 case UCI_EXT_PARAM_AOA_CALIBRATION_CTRL:
211 case UCI_EXT_PARAM_DPD_WAKEUP_SRC:
212 case UCI_EXT_PARAM_WTX_COUNT_CONFIG:
213 case UCI_EXT_PARAM_DPD_ENTRY_TIMEOUT:
214 case UCI_EXT_PARAM_WIFI_COEX_FEATURE:
215 case UCI_EXT_PARAM_TX_BASE_BAND_CONFIG:
216 case UCI_EXT_PARAM_DDFS_TONE_CONFIG:
217 case UCI_EXT_PARAM_TX_PULSE_SHAPE_CONFIG:
218 case UCI_EXT_PARAM_CLK_CONFIG_CTRL:
219 if(IdStatus == UCI_STATUS_FEATURE_NOT_SUPPORTED){
220 NXPLOG_UCIHAL_E("%s: Vendor config param: %x %x is Not Supported", __func__, paramId, extParamId);
221 status = UWBSTATUS_SUCCESS;
222 } else {
223 status = UWBSTATUS_FAILED;
224 return status;
225 }
226 break;
227 default:
228 NXPLOG_UCIHAL_D("%s: Vendor param ID: %x", __func__, extParamId);
229 break;
230 }
231 } else {
232 IdStatus = p_buff[index++];
233 switch(paramId) {
234 case UCI_PARAM_ID_LOW_POWER_MODE:
235 if(IdStatus == UCI_STATUS_FEATURE_NOT_SUPPORTED){
236 NXPLOG_UCIHAL_E("%s: Generic config param: %x is Not Supported", __func__, paramId);
237 status = UWBSTATUS_SUCCESS;
238 } else {
239 status = UWBSTATUS_FAILED;
240 return status;
241 }
242 break;
243 default:
244 NXPLOG_UCIHAL_D("%s: Generic param ID: %x", __func__, paramId);
245 break;
246 }
247 }
248 }
249 NXPLOG_UCIHAL_D("%s: exit %d", __func__, status);
250 return status;
251 }
252
253 /*******************************************************************************
254 * Function phNxpUciHal_resetRuntimeSettings
255 *
256 * Description reset per-country code settigs to default
257 *
258 *******************************************************************************/
phNxpUciHal_resetRuntimeSettings(void)259 static void phNxpUciHal_resetRuntimeSettings(void)
260 {
261 phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
262 rt_set->uwb_enable = true;
263 rt_set->restricted_channel_mask = 0;
264 rt_set->tx_power_offset = 0;
265 }
266
267 /*******************************************************************************
268 * Function phNxpUciHal_applyCountryCaps
269 *
270 * Description Update runtime settings with given COUNTRY_CODE_CAPS byte array
271 *
272 * Returns void
273 *
274 *******************************************************************************/
phNxpUciHal_applyCountryCaps(const char country_code[2],const uint8_t * cc_resp,uint32_t cc_resp_len)275 static void phNxpUciHal_applyCountryCaps(const char country_code[2],
276 const uint8_t *cc_resp, uint32_t cc_resp_len)
277 {
278 phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
279
280 uint16_t idx = 1; // first byte = number countries
281 bool country_code_found = false;
282
283 while (idx < cc_resp_len) {
284 uint8_t tag = cc_resp[idx++];
285 uint8_t len = cc_resp[idx++];
286
287 if (country_code_found) {
288 switch (tag) {
289 case UWB_ENABLE_TAG:
290 if (len == 1) {
291 rt_set->uwb_enable = cc_resp[idx];
292 NXPLOG_UCIHAL_D("CountryCaps uwb_enable = %u", cc_resp[idx]);
293 }
294 break;
295 case CHANNEL_5_TAG:
296 if (len == 1 && !cc_resp[idx]) {
297 rt_set->restricted_channel_mask |= 1<< 5;
298 NXPLOG_UCIHAL_D("CountryCaps channel 5 support = %u", cc_resp[idx]);
299 }
300 break;
301 case CHANNEL_9_TAG:
302 if (len == 1 && !cc_resp[idx]) {
303 rt_set->restricted_channel_mask |= 1<< 9;
304 NXPLOG_UCIHAL_D("CountryCaps channel 9 support = %u", cc_resp[idx]);
305 }
306 break;
307 case TX_POWER_TAG:
308 if (len == 2) {
309 rt_set->tx_power_offset = (short)((cc_resp[idx + 0]) | (((cc_resp[idx + 1]) << RMS_TX_POWER_SHIFT) & 0xFF00));
310 NXPLOG_UCIHAL_D("CountryCaps tx_power_offset = %d", rt_set->tx_power_offset);
311 }
312 break;
313 default:
314 break;
315 }
316 }
317 if (tag == COUNTRY_CODE_TAG) {
318 country_code_found = (cc_resp[idx + 0] == country_code[0]) && (cc_resp[idx + 1] == country_code[1]);
319 }
320 idx += len;
321 }
322 }
323
324 /*******************************************************************************
325 * Function phNxpUciHal_is_retry_not_required
326 *
327 * Description UCI command retry check
328 *
329 * Returns true/false
330 *
331 *******************************************************************************/
phNxpUciHal_is_retry_not_required(uint8_t uci_octet0)332 static bool phNxpUciHal_is_retry_not_required(uint8_t uci_octet0) {
333 bool isRetryRequired = false, isChained_cmd = false, isData_Msg = false;
334 isChained_cmd = (bool)((uci_octet0 & UCI_PBF_ST_CONT) >> UCI_PBF_SHIFT);
335 isData_Msg = ((uci_octet0 & UCI_MT_MASK) >> UCI_MT_SHIFT) == UCI_MT_DATA;
336 isRetryRequired = isChained_cmd | isData_Msg;
337 return isRetryRequired;
338 }
339
340 // TODO: remove this out
341 /******************************************************************************
342 * Function CountryCodeCapsGenTxPowerPacket
343 *
344 * Description This function makes tx antenna power calibration command
345 * with gtx_power[] + tx_power_offset
346 *
347 * Returns true if packet has been updated
348 *
349 ******************************************************************************/
CountryCodeCapsGenTxPowerPacket(uint8_t * packet,size_t packet_len)350 static bool CountryCodeCapsGenTxPowerPacket(uint8_t *packet, size_t packet_len)
351 {
352 phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
353
354 if (rt_set->tx_power_offset == 0)
355 return false;
356
357 if (gtx_power.empty())
358 return false;
359
360 if (gtx_power.size() != packet_len)
361 return false;
362
363 size_t gtx_power_len = gtx_power.size();
364 memcpy(packet, gtx_power.data(), gtx_power_len);
365 uint8_t index = UCI_MSG_HDR_SIZE + 2; // channel + Tag
366
367 // Length
368 if (index > gtx_power_len) {
369 NXPLOG_UCIHAL_E("Upper-layer calibration command for tx_power is invalid.");
370 return false;
371 }
372 if (!packet[index] || (packet[index] + index) > gtx_power_len) {
373 NXPLOG_UCIHAL_E("Upper-layer calibration command for tx_power is invalid.");
374 return false;
375 }
376 index++;
377
378 // Value[0] = Number of antennas
379 uint8_t num_of_antennas = packet[index++];
380
381 while (num_of_antennas--) {
382 // each entry = { antenna-id(1) + peak_tx(2) + id_rms(2) }
383 if ((index + 5) < gtx_power_len) {
384 NXPLOG_UCIHAL_E("Upper-layer calibration command for tx_power is invalid.");
385 return false;
386 }
387
388 index += 3; // antenna Id(1) + Peak Tx(2)
389
390 // Adjust id_rms part
391 long tx_power_long = packet[index] | ((packet[index + 1] << RMS_TX_POWER_SHIFT) & 0xFF00);
392 tx_power_long += rt_set->tx_power_offset;
393
394 if (tx_power_long < 0)
395 tx_power_long = 0;
396
397 uint16_t tx_power_u16 = (uint16_t)tx_power_long;
398 packet[index++] = tx_power_u16 & 0xff;
399 packet[index++] = tx_power_u16 >> RMS_TX_POWER_SHIFT;
400 }
401
402 return true;
403 }
404
405 // TODO: remove this out
406 /*******************************************************************************
407 * Function phNxpUciHal_handle_set_calibration
408 *
409 * Description Remembers SET_VENDOR_SET_CALIBRATION_CMD packet
410 *
411 * Returns void
412 *
413 *******************************************************************************/
phNxpUciHal_handle_set_calibration(uint8_t * p_data,size_t data_len)414 void phNxpUciHal_handle_set_calibration(uint8_t *p_data, size_t data_len)
415 {
416 // Only saves the SET_CALIBRATION_CMD from upper-layer
417 if (nxpucihal_ctrl.hal_ext_enabled) {
418 return;
419 }
420
421 // SET_DEVICE_CALIBRATION_CMD Packet format: Channel(1) + TLV
422 if (data_len < 6) {
423 return;
424 }
425 const uint8_t channel = p_data[UCI_MSG_HDR_SIZE + 0];
426 const uint8_t tag = p_data[UCI_MSG_HDR_SIZE + 1];
427 if (tag != NXP_PARAM_ID_TX_POWER_PER_ANTENNA) {
428 return;
429 }
430
431 phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
432
433 // RMS Tx power -> Octet [4, 5] in calib data
434 NXPLOG_UCIHAL_D("phNxpUciHal_handle_set_calibration channel=%u tx_power_offset=%d", channel, rt_set->tx_power_offset);
435
436 // Backup the packet to gtx_power[]
437 gtx_power = std::move(std::vector<uint8_t> {p_data, p_data + data_len});
438
439 // Patch SET_CALIBRATION_CMD per gtx_power + tx_power_offset
440 CountryCodeCapsGenTxPowerPacket(p_data, data_len);
441 }
442
443 /******************************************************************************
444 * Function CountryCodeCapsApplyTxPower
445 *
446 * Description This function sets the TX power from COUNTRY_CODE_CAPS
447 *
448 * Returns false if no tx_power_offset or no Upper-layer Calibration cmd was given
449 * true if it was successfully applied.
450 *
451 ******************************************************************************/
CountryCodeCapsApplyTxPower(void)452 static bool CountryCodeCapsApplyTxPower(void)
453 {
454 if (gtx_power.empty())
455 return false;
456
457 // use whole packet as-is from upper-layer command (gtx_power[])
458 std::vector<uint8_t> packet(gtx_power.size());
459 size_t packet_size = 0;
460 if (!CountryCodeCapsGenTxPowerPacket(packet.data(), packet.size()))
461 return false;
462
463 tHAL_UWB_STATUS status = phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
464 if (status != UWBSTATUS_SUCCESS) {
465 NXPLOG_UCIHAL_D("%s: send failed", __func__);
466 }
467
468 gtx_power.clear();
469
470 return true;
471 }
472
extcal_do_xtal(void)473 static void extcal_do_xtal(void)
474 {
475 // RF_CLK_ACCURACY_CALIB (otp supported)
476 // parameters: cal.otp.xtal=0|1, cal.xtal=X
477 constexpr std::string_view kConfKeyOtp = "cal.otp.xtal"; // as-if, safe to use data() for c-string.
478 constexpr std::string_view kConfKeyXtal = "cal.xtal";
479
480 uint8_t xtal_data[32];
481 size_t xtal_data_len = 0;
482 bool xtal_otp_provided = false;
483
484 // Reads xtal calibration from OTP.
485 bool use_otp_xtal = NxpConfig_GetBool(kConfKeyOtp).value_or(false);
486 if (use_otp_xtal) {
487 tHAL_UWB_STATUS status = nxpucihal_ctrl.uwb_chip->read_otp(
488 EXTCAL_PARAM_CLK_ACCURACY, xtal_data, sizeof(xtal_data), &xtal_data_len);
489 xtal_otp_provided = status == UWBSTATUS_SUCCESS && xtal_data_len > 0;
490 }
491
492 // Reads xtal calibration from configuration file.
493 if (!xtal_otp_provided) {
494 if (use_otp_xtal) {
495 NXPLOG_UCIHAL_W("%s is set but cannot read it from otp, fallback to config.", kConfKeyOtp.data());
496 }
497 size_t retlen = 0;
498 auto res = NxpConfig_GetByteArray(kConfKeyXtal);
499 if (!res.has_value()) {
500 NXPLOG_UCIHAL_E("Failed to get clock calibration data: %s is not provided.", kConfKeyXtal.data());
501 return;
502 }
503 std::span<const uint8_t> data = *res;
504 if (data.empty() || data.size() > sizeof(xtal_data)) {
505 NXPLOG_UCIHAL_E("Failed to get clock calibration data: cannot parse %s", kConfKeyXtal.data());
506 return;
507 }
508 memcpy(xtal_data, data.data(), data.size());
509 xtal_data_len = data.size();
510 }
511
512 NXPLOG_UCIHAL_D("Apply CLK_ACCURARY (len=%zu, from-otp=%c)", xtal_data_len, xtal_otp_provided ? 'y' : 'n');
513
514 tHAL_UWB_STATUS ret =
515 nxpucihal_ctrl.uwb_chip->apply_calibration(
516 EXTCAL_PARAM_CLK_ACCURACY, 0, xtal_data, xtal_data_len);
517 if (ret != UWBSTATUS_SUCCESS) {
518 NXPLOG_UCIHAL_E("Failed to apply CLK_ACCURACY.");
519 }
520 }
521
522 // Returns a pair of limit values <lower limit, upper limit>
extcal_get_ant_delay_limits(uint8_t ant_id,uint8_t ch)523 static std::pair<uint16_t, uint16_t> extcal_get_ant_delay_limits(uint8_t ant_id, uint8_t ch)
524 {
525 constexpr uint16_t def_lower_limit = std::numeric_limits<uint16_t>::min();
526 constexpr uint16_t def_upper_limit = std::numeric_limits<uint16_t>::max();
527
528 const std::string key_lower_limit = std::format("cal.ant{}.ch{}.ant_delay.lower_limit", ant_id, ch);
529 const std::string key_upper_limit = std::format("cal.ant{}.ch{}.ant_delay.upper_limit", ant_id, ch);
530
531 uint16_t lower_limit = NxpConfig_GetNum<uint16_t>(
532 key_lower_limit, /*include_factory=*/false).value_or(def_lower_limit);
533 uint16_t upper_limit = NxpConfig_GetNum<uint16_t>(
534 key_upper_limit, /*include_factory=*/false).value_or(def_upper_limit);
535
536 return std::make_pair(lower_limit, upper_limit);
537 }
538
extcal_do_ant_delay_ch(const std::bitset<8> rx_antenna_mask,uint8_t ch)539 static void extcal_do_ant_delay_ch(const std::bitset<8> rx_antenna_mask, uint8_t ch)
540 {
541 std::vector<uint8_t> entries;
542 uint8_t n_entries = 0;
543
544 for (auto i = 0; i < rx_antenna_mask.size(); i++) {
545 if (!rx_antenna_mask.test(i)) { continue; }
546
547 const uint8_t ant_id = i + 1;
548
549 const std::string key_ant_delay = std::format("cal.ant{}.ch{}.ant_delay", ant_id, ch);
550 const std::string key_force_version = key_ant_delay + ".force_version";
551
552 std::optional<uint16_t> delay_value;
553
554 // 1) try cal.ant{N}.ch{N}.ant_delay.force_value.{N}
555 std::optional<uint16_t> force_version = NxpConfig_GetNum<uint16_t>(key_force_version);
556 if (force_version.has_value()) {
557 const std::string key_force_value = key_ant_delay + std::format(".force_value.{}", *force_version);
558 delay_value = NxpConfig_GetNum<uint16_t>(key_force_value);
559 if (delay_value.has_value()) {
560 NXPLOG_UCIHAL_D("Apply RX_ANT_DELAY_CALIB %s = %u", key_force_value.c_str(), *delay_value);
561 }
562 }
563
564 // 2) try cal.ant{N}.ch{N}.ant_delay
565 if (!delay_value.has_value()) {
566 delay_value = NxpConfig_GetNum<uint16_t>(key_ant_delay);
567 if (delay_value.has_value()) {
568 NXPLOG_UCIHAL_D("Apply RX_ANT_DELAY_CALIB: %s = %u", key_ant_delay.c_str(), *delay_value);
569 }
570 }
571
572 if (!delay_value.has_value()) {
573 NXPLOG_UCIHAL_V("%s was not provided from configuration files.", key_ant_delay.c_str());
574 return;
575 }
576
577 // clamping
578 uint16_t clamped_delay = *delay_value;
579 std::pair<uint16_t, uint16_t> limits = extcal_get_ant_delay_limits(ant_id, ch);
580 if (clamped_delay < limits.first) { clamped_delay = limits.first; }
581 if (clamped_delay > limits.second) { clamped_delay = limits.second; }
582
583 if (clamped_delay != delay_value) {
584 NXPLOG_UCIHAL_W("Clamping %s to %u", key_ant_delay.c_str(), clamped_delay);
585 }
586
587 entries.push_back(ant_id);
588 // Little Endian
589 entries.push_back(clamped_delay & 0xff);
590 entries.push_back(clamped_delay >> 8);
591 n_entries++;
592 }
593
594 if (!n_entries) { return; }
595
596 entries.insert(entries.begin(), n_entries);
597 tHAL_UWB_STATUS ret = nxpucihal_ctrl.uwb_chip->apply_calibration(EXTCAL_PARAM_RX_ANT_DELAY, ch, entries.data(), entries.size());
598 if (ret != UWBSTATUS_SUCCESS) {
599 // TODO: halt the chip when this failed.
600 NXPLOG_UCIHAL_E("Failed to apply RX_ANT_DELAY for channel %u", ch);
601 }
602 }
603
extcal_do_ant_delay(void)604 static void extcal_do_ant_delay(void)
605 {
606 const std::bitset<8> rx_antenna_mask(nxpucihal_ctrl.cal_rx_antenna_mask);
607 if (rx_antenna_mask.none()) {
608 NXPLOG_UCIHAL_E("No rx_antenna_mask defined by configuration file. Please check your configurations files (and HAL codes).")
609 return;
610 }
611
612 const uint8_t *cal_channels = NULL;
613 uint8_t nr_cal_channels = 0;
614 nxpucihal_ctrl.uwb_chip->get_supported_channels(&cal_channels, &nr_cal_channels);
615
616 // RX_ANT_DELAY_CALIB
617 // parameter: cal.ant<N>.ch<N>.ant_delay=X
618 // N(1) + N * {AntennaID(1), Rxdelay(Q14.2)}
619 for (int i = 0; i < nr_cal_channels; i++) {
620 extcal_do_ant_delay_ch(rx_antenna_mask, cal_channels[i]);
621 }
622 }
623
extcal_do_tx_power(void)624 static void extcal_do_tx_power(void)
625 {
626 std::bitset<8> tx_antenna_mask(nxpucihal_ctrl.cal_tx_antenna_mask);
627 const uint8_t n_tx_antennas = tx_antenna_mask.size();
628
629 const uint8_t *cal_channels = NULL;
630 uint8_t nr_cal_channels = 0;
631 nxpucihal_ctrl.uwb_chip->get_supported_channels(&cal_channels, &nr_cal_channels);
632
633 // TX_POWER
634 // parameter: cal.ant<N>.ch<N>.tx_power={...}
635 if (n_tx_antennas) {
636 for (int i = 0; i < nr_cal_channels; i++) {
637 uint8_t ch = cal_channels[i];
638 std::vector<uint8_t> entries;
639 uint8_t n_entries = 0;
640
641 for (auto i = 0; i < n_tx_antennas; i++) {
642 if (!tx_antenna_mask[i])
643 continue;
644
645 const uint8_t ant_id = i + 1;
646
647 std::string key = std::format("cal.ant{}.ch{}.tx_power", ant_id, ch);
648 std::optional<std::span<const uint8_t>> res = NxpConfig_GetByteArray(key);
649 if (!res.has_value()) {
650 continue;
651 }
652 std::span<const uint8_t> pkt = *res;
653 NXPLOG_UCIHAL_D("Apply TX_POWER: %s = { %zu bytes }", key.c_str(), (*res).size());
654 entries.push_back(ant_id);
655 entries.insert(entries.end(), pkt.begin(), pkt.end());
656 n_entries++;
657 }
658
659 if (!n_entries)
660 continue;
661
662 entries.insert(entries.begin(), n_entries);
663 tHAL_UWB_STATUS ret = nxpucihal_ctrl.uwb_chip->apply_calibration(EXTCAL_PARAM_TX_POWER, ch, entries.data(), entries.size());
664 if (ret != UWBSTATUS_SUCCESS) {
665 NXPLOG_UCIHAL_E("Failed to apply TX_POWER for channel %u", ch);
666 }
667 }
668 }
669 }
670
extcal_do_tx_pulse_shape(void)671 static void extcal_do_tx_pulse_shape(void)
672 {
673 std::optional<std::span<const uint8_t>> res = NxpConfig_GetByteArray("cal.tx_pulse_shape");
674 if (res.has_value()) {
675 NXPLOG_UCIHAL_D("Apply TX_PULSE_SHAPE: data = { %zu bytes }", (*res).size());
676
677 tHAL_UWB_STATUS ret = nxpucihal_ctrl.uwb_chip->apply_calibration(
678 EXTCAL_PARAM_TX_PULSE_SHAPE, /*ch=*/0, (*res).data(), (*res).size());
679 if (ret != UWBSTATUS_SUCCESS) {
680 NXPLOG_UCIHAL_E("Failed to apply TX_PULSE_SHAPE.");
681 }
682 }
683 }
684
extcal_do_tx_base_band(void)685 static void extcal_do_tx_base_band(void)
686 {
687 // TX_BASE_BAND_CONTROL, DDFS_TONE_CONFIG
688 // parameters: cal.ddfs_enable=1|0, cal.dc_suppress=1|0, ddfs_tone_config={...}
689 bool ddfs_enable = NxpConfig_GetBool("cal.ddfs_enable").value_or(false);
690 bool dc_suppress = NxpConfig_GetBool("cal.dc_suppress").value_or(false);
691
692 // DDFS_TONE_CONFIG
693 if (ddfs_enable) {
694 std::optional<std::span<const uint8_t>> ddfs_tone = NxpConfig_GetByteArray("cal.ddfs_tone_config");
695 if (!ddfs_tone.has_value()) {
696 NXPLOG_UCIHAL_E("cal.ddfs_tone_config is not supplied while cal.ddfs_enable=1, ddfs was not enabled.");
697 ddfs_enable = 0;
698 } else {
699 NXPLOG_UCIHAL_D("Apply DDFS_TONE_CONFIG: ddfs_tone_config = { %zu bytes }", (*ddfs_tone).size());
700
701 tHAL_UWB_STATUS ret = nxpucihal_ctrl.uwb_chip->apply_calibration(EXTCAL_PARAM_DDFS_TONE_CONFIG,
702 /*ch=*/0, (*ddfs_tone).data(), (*ddfs_tone).size());
703 if (ret != UWBSTATUS_SUCCESS) {
704 NXPLOG_UCIHAL_E("Failed to apply DDFS_TONE_CONFIG, ddfs was not enabled.");
705 ddfs_enable = 0;
706 }
707 }
708 }
709
710 // TX_BASE_BAND_CONTROL
711 uint8_t flag = 0;
712 if (ddfs_enable) { flag |= 0x01; }
713 if (dc_suppress) { flag |= 0x02; }
714 tHAL_UWB_STATUS ret = nxpucihal_ctrl.uwb_chip->apply_calibration(EXTCAL_PARAM_TX_BASE_BAND_CONTROL,
715 /*ch=*/0, &flag, 1);
716 if (ret) {
717 NXPLOG_UCIHAL_E("Failed to apply TX_BASE_BAND_CONTROL");
718 }
719 }
720
721 /******************************************************************************
722 * Function phNxpUciHal_extcal_handle_coreinit
723 *
724 * Description Apply additional core device settings
725 *
726 * Returns void.
727 *
728 ******************************************************************************/
phNxpUciHal_extcal_handle_coreinit(void)729 void phNxpUciHal_extcal_handle_coreinit(void)
730 {
731 // read rx_aantenna_mask, tx_antenna_mask
732 auto res = NxpConfig_GetNum<uint8_t>("cal.rx_antenna_mask");
733 if (!res.has_value()) {
734 NXPLOG_UCIHAL_W("cal.tx_antenna_mask is not specified, use default value.");
735 }
736 nxpucihal_ctrl.cal_rx_antenna_mask = res.value_or(0x01);
737
738 res = NxpConfig_GetNum<uint8_t>("cal.tx_antenna_mask");
739 if (!res.has_value()) {
740 NXPLOG_UCIHAL_W("cal.tx_antenna_mask is not specified, use default value.");
741 }
742 nxpucihal_ctrl.cal_tx_antenna_mask = res.value_or(0x01);
743
744 NXPLOG_UCIHAL_D("tx_antenna_mask=0x%x, rx_antenna_mask=0x%x",
745 nxpucihal_ctrl.cal_tx_antenna_mask, nxpucihal_ctrl.cal_rx_antenna_mask);
746
747 extcal_do_xtal();
748 extcal_do_ant_delay();
749 }
750
apply_per_country_calibrations(void)751 void apply_per_country_calibrations(void)
752 {
753 // TX-POWER can be provided by
754 // 1) COUNTRY_CODE_CAPS with offset values.
755 // 2) Extra calibration files with absolute tx power values
756 // only one should be applied if both were provided by platform
757 if (!CountryCodeCapsApplyTxPower()) {
758 extcal_do_tx_power();
759 }
760
761 // These are only available from extra calibration files
762 extcal_do_tx_pulse_shape();
763 extcal_do_tx_base_band();
764
765 }
766
767 /******************************************************************************
768 * Function phNxpUciHal_handle_set_country_code
769 *
770 * Description Apply per-country settings
771 *
772 * Returns void.
773 *
774 ******************************************************************************/
phNxpUciHal_handle_set_country_code(const char country_code[2])775 void phNxpUciHal_handle_set_country_code(const char country_code[2])
776 {
777 NXPLOG_UCIHAL_D("Apply country code %c%c", country_code[0], country_code[1]);
778
779 phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
780
781 if (!is_valid_country_code(country_code)) {
782 NXPLOG_UCIHAL_D("Country code %c%c is invalid, UWB should be disabled", country_code[0], country_code[1]);
783 phNxpUciHal_resetRuntimeSettings();
784 rt_set->uwb_enable = false;
785 } else if (!(nxpucihal_ctrl.country_code[0] == country_code[0] &&
786 nxpucihal_ctrl.country_code[1] == country_code[1])) {
787
788 nxpucihal_ctrl.country_code[0] = country_code[0];
789 nxpucihal_ctrl.country_code[1] = country_code[1];
790 NxpConfig_SetCountryCode(country_code);
791 phNxpUciHal_resetRuntimeSettings();
792
793 // Load ExtraCal restrictions
794 uint16_t mask = NxpConfig_GetNum<uint16_t>("cal.restricted_channels").value_or(0);
795 if (mask != 0) {
796 NXPLOG_UCIHAL_D("Restriction flag, restricted channel mask=0x%x", mask);
797 rt_set->restricted_channel_mask = mask;
798 }
799
800 if (NxpConfig_GetBool("cal.uwb_disable").value_or(false)) {
801 NXPLOG_UCIHAL_D("Restriction flag, uwb_disable set");
802 rt_set->uwb_enable = 0;
803 }
804
805 // Apply COUNTRY_CODE_CAPS
806 std::optional<std::span<const uint8_t>> cc_caps =
807 NxpConfig_GetByteArray(NAME_NXP_UWB_COUNTRY_CODE_CAPS);
808 if (cc_caps.has_value()) {
809 NXPLOG_UCIHAL_D("COUNTRY_CODE_CAPS is provided.");
810 phNxpUciHal_applyCountryCaps(country_code, (*cc_caps).data(), (*cc_caps).size());
811 }
812
813 // Check country code validity
814 if (!is_valid_country_code(country_code) && rt_set->uwb_enable) {
815 NXPLOG_UCIHAL_E("UWB is not disabled by configuration files with invalid country code %c%c,"
816 " forcing it disabled", country_code[0], country_code[1]);
817 rt_set->uwb_enable = false;
818 }
819
820 // Apply per-country calibration, it's handled by SessionTrack
821 SessionTrack_onCountryCodeChanged();
822 } else {
823 NXPLOG_UCIHAL_D("Country code %c%c: not changed, keep same configuration.",
824 country_code[0], country_code[1]);
825 }
826
827 // send country code response to upper layer
828 if (rt_set->uwb_enable) {
829 constexpr uint8_t rsp_data[5] = {
830 0x4c, 0x01, 0x00, 0x01, UWBSTATUS_SUCCESS };
831 report_uci_message(rsp_data, sizeof(rsp_data));
832 } else {
833 constexpr uint8_t rsp_data[5] = {
834 0x4c, 0x01, 0x00, 0x01, UCI_STATUS_CODE_ANDROID_REGULATION_UWB_OFF };
835 report_uci_message(rsp_data, sizeof(rsp_data));
836 }
837 }
838
839 // TODO: support fragmented packets
840 /*************************************************************************************
841 * Function phNxpUciHal_handle_set_app_config
842 *
843 * Description Handle SESSION_SET_APP_CONFIG_CMD packet,
844 * remove unsupported parameters
845 *
846 * Returns true : SESSION_SET_APP_CONFIG_CMD/RSP was handled by this function
847 * false : This packet should go to chip
848 *
849 *************************************************************************************/
phNxpUciHal_handle_set_app_config(size_t * data_len,uint8_t * p_data)850 bool phNxpUciHal_handle_set_app_config(size_t *data_len, uint8_t *p_data)
851 {
852 const phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
853 // Android vendor specific app configs not supported by FW
854 const uint8_t tags_to_del[] = {
855 UCI_PARAM_ID_TX_ADAPTIVE_PAYLOAD_POWER,
856 UCI_PARAM_ID_AOA_AZIMUTH_MEASUREMENTS,
857 UCI_PARAM_ID_AOA_ELEVATION_MEASUREMENTS,
858 UCI_PARAM_ID_RANGE_MEASUREMENTS
859 };
860
861 // check basic validity
862 size_t payload_len = (p_data[UCI_CMD_LENGTH_PARAM_BYTE1] & 0xFF) |
863 ((p_data[UCI_CMD_LENGTH_PARAM_BYTE2] & 0xFF) << 8);
864 if (payload_len != (*data_len - UCI_MSG_HDR_SIZE)) {
865 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD: payload length mismatch");
866 return false;
867 }
868 if (!p_data[UCI_CMD_NUM_CONFIG_PARAM_BYTE]) {
869 return false;
870 }
871
872 uint32_t session_handle = le_bytes_to_cpu<uint32_t>(&p_data[UCI_MSG_SESSION_SET_APP_CONFIG_HANDLE_OFFSET]);
873 uint8_t ch = 0;
874
875 // Create local copy of cmd_data for data manipulation
876 uint8_t uciCmd[UCI_MAX_DATA_LEN];
877 size_t packet_len = *data_len;
878 if (sizeof(uciCmd) < packet_len) {
879 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD packet size %u is too big to handle, skip patching.", packet_len);
880 return false;
881 }
882 // 9 = Header 4 + SessionID 4 + NumOfConfigs 1
883 uint8_t i = 9, j = 9;
884 uint8_t nr_deleted = 0, bytes_deleted = 0;
885 memcpy(uciCmd, p_data, i);
886
887 while (i < packet_len) {
888 if ( (i + 2) >= packet_len) {
889 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD parse error at %u", i);
890 return false;
891 }
892
893 // All parameters should have 1 byte tag
894 uint8_t tlv_tag = p_data[i + 0];
895 uint8_t tlv_len = p_data[i + 1];
896 uint8_t param_len = 2 + tlv_len;
897 if ((i + param_len) > packet_len) {
898 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD parse error at %u", i);
899 }
900
901 // check restricted channel
902 if (tlv_tag == UCI_PARAM_ID_CHANNEL_NUMBER && tlv_len == 1) {
903 ch = p_data[i + 2];
904
905 if (((ch == CHANNEL_NUM_5) && (rt_set->restricted_channel_mask & (1 << 5))) ||
906 ((ch == CHANNEL_NUM_9) && (rt_set->restricted_channel_mask & (1 << 9)))) {
907 phNxpUciHal_print_packet(NXP_TML_UCI_CMD_AP_2_UWBS, p_data, packet_len);
908 NXPLOG_UCIHAL_D("Country code blocked channel %u", ch);
909
910 // send setAppConfig response with UCI_STATUS_CODE_ANDROID_REGULATION_UWB_OFF response
911 uint8_t rsp_data[] = { 0x41, 0x03, 0x04, 0x04,
912 UCI_STATUS_FAILED, 0x01, tlv_tag, UCI_STATUS_CODE_ANDROID_REGULATION_UWB_OFF
913 };
914 report_uci_message(rsp_data, sizeof(rsp_data));
915 return true;
916 }
917 }
918
919 // remove unsupported parameters
920 if (std::find(std::begin(tags_to_del), std::end(tags_to_del), tlv_tag) == std::end(tags_to_del)) {
921 memcpy(&uciCmd[j], &p_data[i], param_len);
922 j += param_len;
923 } else {
924 NXPLOG_UCIHAL_D("Removed param payload with Tag ID:0x%02x", tlv_tag);
925 nr_deleted++;
926 bytes_deleted += param_len;
927 }
928 i += param_len;
929 }
930 if (nr_deleted) {
931 phNxpUciHal_print_packet(NXP_TML_UCI_CMD_AP_2_UWBS, p_data, packet_len);
932
933 // uci number of config params update
934 if (uciCmd[UCI_CMD_NUM_CONFIG_PARAM_BYTE] < nr_deleted) {
935 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD cannot parse packet: wrong nr_parameters");
936 return false;
937 }
938 uciCmd[UCI_CMD_NUM_CONFIG_PARAM_BYTE] -= nr_deleted;
939
940 // uci command length update
941 if (packet_len < (UCI_MSG_HDR_SIZE + bytes_deleted)) {
942 NXPLOG_UCIHAL_E("SESSION_SET_APP_CONFIG_CMD cannot parse packet: underflow");
943 return false;
944 }
945 packet_len -= bytes_deleted;
946 payload_len = packet_len - UCI_MSG_HDR_SIZE;
947 uciCmd[UCI_CMD_LENGTH_PARAM_BYTE2] = (payload_len & 0xFF00) >> 8;
948 uciCmd[UCI_CMD_LENGTH_PARAM_BYTE1] = (payload_len & 0xFF);
949
950 // Swap
951 memcpy(p_data, uciCmd, packet_len);
952 *data_len = packet_len;
953 }
954
955 SessionTrack_onAppConfig(session_handle, ch);
956
957 return false;
958 }
959
phNxpUciHal_handle_get_caps_info(size_t data_len,const uint8_t * p_data)960 bool phNxpUciHal_handle_get_caps_info(size_t data_len, const uint8_t *p_data)
961 {
962 if (data_len < UCI_MSG_CORE_GET_CAPS_INFO_NR_OFFSET)
963 return false;
964
965 uint8_t status = p_data[UCI_RESPONSE_STATUS_OFFSET];
966 uint8_t nr = p_data[UCI_MSG_CORE_GET_CAPS_INFO_NR_OFFSET];
967 if (status != UWBSTATUS_SUCCESS || nr < 1)
968 return false;
969
970 auto tlvs = decodeTlvBytes({0xe0, 0xe1, 0xe2, 0xe3}, &p_data[UCI_MSG_CORE_GET_CAPS_INFO_TLV_OFFSET], data_len - UCI_MSG_CORE_GET_CAPS_INFO_TLV_OFFSET);
971 if (tlvs.size() != nr) {
972 NXPLOG_UCIHAL_E("Failed to parse DevCaps %zu != %u", tlvs.size(), nr);
973 }
974
975 // Remove all NXP vendor specific parameters
976 for (auto it = tlvs.begin(); it != tlvs.end();) {
977 if (it->first > 0xff)
978 it = tlvs.erase(it);
979 else
980 it++;
981 }
982
983 // Override AOA_SUPPORT_TAG_ID
984 auto it = tlvs.find(AOA_SUPPORT_TAG_ID);
985 if (it != tlvs.end()) {
986 if (nxpucihal_ctrl.numberOfAntennaPairs == 1) {
987 it->second = std::vector<uint8_t>{0x01};
988 } else if (nxpucihal_ctrl.numberOfAntennaPairs > 1) {
989 it->second = std::vector<uint8_t>{0x05};
990 } else {
991 it->second = std::vector<uint8_t>{0x00};
992 }
993 }
994
995 // Byteorder of CCC_SUPPORTED_PROTOCOL_VERSIONS_ID
996 it = tlvs.find(CCC_SUPPORTED_PROTOCOL_VERSIONS_ID);
997 if (it != tlvs.end() && it->second.size() == 2) {
998 std::swap(it->second[0], it->second[1]);
999 }
1000
1001 // Append UWB_VENDOR_CAPABILITY from configuration files
1002 std::optional<std::span<const uint8_t>> vcaps =
1003 NxpConfig_GetByteArray(NAME_UWB_VENDOR_CAPABILITY);
1004 if (vcaps.has_value()) {
1005 auto vendorTlvs = decodeTlvBytes(/*ext_ids=*/{}, (*vcaps).data(), (*vcaps).size());
1006 for (auto const& [key, val] : vendorTlvs) {
1007 tlvs[key] = val;
1008 }
1009 }
1010
1011 // Apply restrictions
1012 const phNxpUciHal_Runtime_Settings_t *rt_set = &nxpucihal_ctrl.rt_settings;
1013
1014 uint8_t fira_channels = 0xff;
1015 if (rt_set->restricted_channel_mask & (1 << 5))
1016 fira_channels &= CHANNEL_5_MASK;
1017 if (rt_set->restricted_channel_mask & (1 << 9))
1018 fira_channels &= CHANNEL_9_MASK;
1019
1020 uint8_t ccc_channels = 0;
1021 if (!(rt_set->restricted_channel_mask & (1 << 5)))
1022 ccc_channels |= 0x01;
1023 if (!(rt_set->restricted_channel_mask & (1 << 9)))
1024 ccc_channels |= 0x02;
1025
1026 tlvs[UWB_CHANNELS] = std::vector{fira_channels};
1027 tlvs[CCC_UWB_CHANNELS] = std::vector{ccc_channels};
1028
1029 // Convert it back to raw packet bytes
1030 uint8_t packet[256];
1031
1032 // header
1033 memcpy(packet, p_data, UCI_MSG_HDR_SIZE);
1034 // status
1035 packet[UCI_RESPONSE_STATUS_OFFSET] = UWBSTATUS_SUCCESS;
1036 // nr
1037 packet[UCI_MSG_CORE_GET_CAPS_INFO_NR_OFFSET] = tlvs.size();
1038
1039 // tlvs
1040 auto tlv_bytes = encodeTlvBytes(tlvs);
1041 if ((tlv_bytes.size() + UCI_MSG_CORE_GET_CAPS_INFO_TLV_OFFSET) > sizeof(packet)) {
1042 NXPLOG_UCIHAL_E("DevCaps overflow!");
1043 return false;
1044 } else {
1045 uint8_t packet_len = UCI_MSG_CORE_GET_CAPS_INFO_TLV_OFFSET + tlv_bytes.size();
1046 packet[UCI_PAYLOAD_LENGTH_OFFSET] = packet_len - UCI_MSG_HDR_SIZE;
1047 memcpy(&packet[UCI_MSG_CORE_GET_CAPS_INFO_TLV_OFFSET], tlv_bytes.data(), tlv_bytes.size());
1048
1049 phNxpUciHal_print_packet(NXP_TML_UCI_RSP_NTF_UWBS_2_AP, packet, packet_len);
1050
1051 report_uci_message(packet, packet_len);
1052 // skip the incoming packet as we have send the modified response
1053 // already
1054 return true;
1055 }
1056 }
1057