• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <optional>
2 #include <string_view>
3 #include <vector>
4 
5 #include "NxpUwbChip.h"
6 #include "phNxpConfig.h"
7 #include "phNxpUciHal.h"
8 #include "phNxpUciHal_ext.h"
9 #include "phNxpUciHal_utils.h"
10 #include "phUwbStatus.h"
11 #include "phUwbTypes.h"
12 #include "phNxpUwbCalib.h"
13 #include "uci_defs.h"
14 
15 #define UCI_MSG_UWB_ESE_BINDING_LEN                   11
16 #define UCI_MSG_UWB_ESE_BINDING_OFFSET_COUNT          5
17 #define UCI_MSG_UWB_ESE_BINDING_OFFSET_BINDING_STATE  6
18 
19 extern phNxpUciHal_Control_t nxpucihal_ctrl;
20 
report_binding_status(uint8_t binding_status)21 static void report_binding_status(uint8_t binding_status)
22 {
23   // BINDING_STATUS_NTF
24   uint8_t data_len = 5;
25   uint8_t buffer[5];
26   buffer[0] = 0x6E;
27   buffer[1] = 0x06;
28   buffer[2] = 0x00;
29   buffer[3] = 0x01;
30   buffer[4] = binding_status;
31   if (nxpucihal_ctrl.p_uwb_stack_data_cback != NULL) {
32     (*nxpucihal_ctrl.p_uwb_stack_data_cback)(data_len, buffer);
33   }
34 }
35 
36 /******************************************************************************
37  * Function         otp_read_data
38  *
39  * Description      Read OTP calibration data
40  *
41  * Returns          true on success
42  *
43  ******************************************************************************/
otp_read_data(const uint8_t channel,const uint8_t param_id,uint8_t * buffer,size_t len)44 static bool otp_read_data(const uint8_t channel, const uint8_t param_id, uint8_t *buffer, size_t len)
45 {
46   phNxpUciHal_Sem_t calib_data_ntf_wait;
47   phNxpUciHal_init_cb_data(&calib_data_ntf_wait);
48 
49   // NXP_READ_CALIB_DATA_NTF
50   bool received = false;
51   auto read_calib_ntf_cb =
52   [&] (size_t packet_len, const uint8_t *packet) mutable -> bool
53   {
54     // READ_CALIB_DATA_NTF: status(1), length-of-payload(1), payload(N)
55     const uint8_t plen = packet[3]; // payload-length
56     const uint8_t *p = &packet[4];  // payload
57 
58     if (plen < 2) {
59       NXPLOG_UCIHAL_E("Otp read: bad payload length %u", plen);
60     } else if (p[0] != UCI_STATUS_OK) {
61       NXPLOG_UCIHAL_E("Otp read: bad status=0x%x", packet[4]);
62     } else if (p[1] != len) {
63       NXPLOG_UCIHAL_E("Otp read: size mismatch %u (expected %zu for param 0x%x)",
64         p[1], len, param_id);
65     } else {
66       memcpy(buffer, &p[2], len);
67       received = true;
68       SEM_POST(&calib_data_ntf_wait);
69     }
70     return true;
71   };
72   auto handler = phNxpUciHal_rx_handler_add(
73       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0A, UCI_MSG_READ_CALIB_DATA,
74       true, read_calib_ntf_cb);
75 
76 
77   // READ_CALIB_DATA_CMD
78   std::vector<uint8_t> packet{(UCI_MT_CMD << UCI_MT_SHIFT) | UCI_GID_PROPRIETARY_0X0A, UCI_MSG_READ_CALIB_DATA, 0x00, 0x03};
79   packet.push_back(channel);
80   packet.push_back(0x01);      // OTP read option
81   packet.push_back(param_id);
82 
83   tHAL_UWB_STATUS status = phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
84   if (status != UWBSTATUS_SUCCESS) {
85     goto fail_otp_read_data;
86   }
87 
88   phNxpUciHal_sem_timed_wait_sec(&calib_data_ntf_wait, 3);
89   if (!received) {
90     goto fail_otp_read_data;
91   }
92 
93   phNxpUciHal_cleanup_cb_data(&calib_data_ntf_wait);
94   return true;
95 
96 fail_otp_read_data:
97   phNxpUciHal_cleanup_cb_data(&calib_data_ntf_wait);
98   NXPLOG_UCIHAL_E("Failed to read OTP data id=%u", param_id);
99   return false;
100 }
101 
sr1xx_read_otp(extcal_param_id_t id,uint8_t * data,size_t data_len,size_t * retlen)102 static tHAL_UWB_STATUS sr1xx_read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen)
103 {
104   switch(id) {
105   case EXTCAL_PARAM_CLK_ACCURACY:
106     {
107       const size_t param_len = 6;
108       uint8_t otp_xtal_data[3];
109 
110       if (data_len < param_len) {
111         NXPLOG_UCIHAL_E("Requested RF_CLK_ACCURACY_CALIB with %zu bytes (expected >= %zu)", data_len, param_len);
112         return UWBSTATUS_FAILED;
113       }
114       if (!otp_read_data(0x09, OTP_ID_XTAL_CAP_GM_CTRL, otp_xtal_data, sizeof(otp_xtal_data))) {
115         NXPLOG_UCIHAL_E("Failed to read OTP XTAL_CAP_GM_CTRL");
116         return UWBSTATUS_FAILED;
117       }
118       memset(data, 0, param_len);
119       // convert OTP_ID_XTAL_CAP_GM_CTRL to EXTCAL_PARAM_RX_ANT_DELAY
120       data[0] = otp_xtal_data[0]; // cap1
121       data[2] = otp_xtal_data[1]; // cap2
122       data[4] = otp_xtal_data[2]; // gm_current_control (default: 0x30)
123       *retlen = param_len;
124       return UWBSTATUS_SUCCESS;
125     }
126     break;
127   default:
128     NXPLOG_UCIHAL_E("Unsupported otp parameter %d", id);
129     return UWBSTATUS_FAILED;
130   }
131 }
132 
133 //
134 // SR1XX Error handlers (Thermal Runaway, LOW VBATT)
135 //
136 
sr1xx_handle_device_error()137 static void sr1xx_handle_device_error()
138 {
139  /* Send FW crash NTF to upper layer for triggering MW recovery */
140   phNxpUciHal_send_dev_error_status_ntf();
141 }
142 
sr1xx_clear_device_error()143 static void sr1xx_clear_device_error()
144 {
145 }
146 
147 //
148 // SE binding
149 //
150 
151 // Temporarily disable DPD for binding, vendor config should re-enable it
sr1xx_disable_dpd()152 static tHAL_UWB_STATUS sr1xx_disable_dpd()
153 {
154   uint8_t buffer[] = {0x20, 0x04, 0x00, 0x04, 0x01, 0x01, 0x01, 0x00};
155   return phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
156 }
157 
158 /******************************************************************************
159  * Function         sr1xx_do_bind
160  *
161  * Description      Sends UWB_ESE_BINDING_CMD and returns
162  *                  updated binding status and remaining UWBS binding count
163  *
164  * Returns          status
165  *
166  ******************************************************************************/
sr1xx_do_bind(uint8_t * binding_status,uint8_t * remain_count)167 static tHAL_UWB_STATUS sr1xx_do_bind(uint8_t *binding_status, uint8_t *remain_count)
168 {
169   tHAL_UWB_STATUS status;
170 
171   // register rx handler for UWB_ESE_BINDING_NTF
172   phNxpUciHal_Sem_t binding_ntf_wait;
173   phNxpUciHal_init_cb_data(&binding_ntf_wait);
174 
175   auto binding_ntf_cb =
176     [&](size_t packet_len, const uint8_t *packet) mutable -> bool
177   {
178       if (packet_len == UCI_MSG_UWB_ESE_BINDING_LEN) {
179         uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
180         if (status != UWBSTATUS_SUCCESS) {
181           NXPLOG_UCIHAL_E("UWB_ESE_BINDING_NTF: Binding failed, status=0x%x", status);
182         }
183         *binding_status = packet[UCI_MSG_UWB_ESE_BINDING_OFFSET_BINDING_STATE];
184         *remain_count = packet[UCI_MSG_UWB_ESE_BINDING_OFFSET_COUNT];
185         NXPLOG_UCIHAL_D("Received UWB_ESE_BINDING_NTF, status=0x%x, binding_state=0x%x, count=%u",
186           status, *binding_status, *remain_count);
187         SEM_POST(&binding_ntf_wait);
188       } else {
189         NXPLOG_UCIHAL_E("UWB_ESE_BINDING_NTF: packet length mismatched %zu", packet_len);
190       }
191       return true;
192   };
193   auto handler = phNxpUciHal_rx_handler_add(
194       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0F, UCI_MSG_UWB_ESE_BINDING,
195       true, binding_ntf_cb);
196 
197   // UWB_ESE_BINDING_CMD
198   uint8_t buffer[] = {0x2F, 0x31, 0x00, 0x00};
199   status = phNxpUciHal_send_ext_cmd(sizeof(buffer), buffer);
200   if (status != UWBSTATUS_SUCCESS) {
201     NXPLOG_UCIHAL_E("Failed to send UWB_ESE_BINDING_CMD");
202     goto exit_do_bind;
203   }
204 
205   if (phNxpUciHal_sem_timed_wait(&binding_ntf_wait) ||
206       binding_ntf_wait.status != UWBSTATUS_SUCCESS) {
207     NXPLOG_UCIHAL_E("Failed to retrieve UWB_ESE_BINDING_NTF");
208     goto exit_do_bind;
209   }
210 
211   status = UWBSTATUS_SUCCESS;
212 
213 exit_do_bind:
214   phNxpUciHal_rx_handler_del(handler);
215   phNxpUciHal_cleanup_cb_data(&binding_ntf_wait);
216   return status;
217 }
218 
219 /******************************************************************************
220  * Function         sr1xx_check_binding_status
221  *
222  * Description      Send UWB_ESE_BINDING_CHECK_CMD and returns updated binding status
223  *
224  * Returns          status
225  *
226  ******************************************************************************/
sr1xx_check_binding_status(uint8_t * binding_status)227 static tHAL_UWB_STATUS sr1xx_check_binding_status(uint8_t *binding_status)
228 {
229   tHAL_UWB_STATUS status;
230   *binding_status = UWB_DEVICE_UNKNOWN;
231 
232   // register rx handler for UWB_ESE_BINDING_CHECK_NTF
233   uint8_t binding_status_got = UWB_DEVICE_UNKNOWN;
234   phNxpUciHal_Sem_t binding_check_ntf_wait;
235   phNxpUciHal_init_cb_data(&binding_check_ntf_wait);
236   auto binding_check_ntf_cb = [&](size_t packet_len, const uint8_t *packet) mutable -> bool {
237     if (packet_len >= UCI_RESPONSE_STATUS_OFFSET) {
238       binding_status_got = packet[UCI_RESPONSE_STATUS_OFFSET];
239       NXPLOG_UCIHAL_D("Received UWB_ESE_BINDING_CHECK_NTF, binding_status=0x%x", binding_status_got);
240       SEM_POST(&binding_check_ntf_wait);
241     }
242     return true;
243   };
244   auto handler = phNxpUciHal_rx_handler_add(
245       UCI_MT_NTF, UCI_GID_PROPRIETARY_0X0F, UCI_MSG_UWB_ESE_BINDING_CHECK,
246       true, binding_check_ntf_cb);
247 
248   // UWB_ESE_BINDING_CHECK_CMD
249   uint8_t lock_cmd[] = {0x2F, 0x32, 0x00, 0x00};
250   status = phNxpUciHal_send_ext_cmd(sizeof(lock_cmd), lock_cmd);
251   if (status != UWBSTATUS_SUCCESS) {
252     goto exit_check_binding_status;
253   }
254 
255   if (phNxpUciHal_sem_timed_wait(&binding_check_ntf_wait) ||
256       binding_check_ntf_wait.status != UWBSTATUS_SUCCESS) {
257     NXPLOG_UCIHAL_E("Failed to retrieve UWB_ESE_BINDING_CHECK_NTF");
258     goto exit_check_binding_status;
259   }
260 
261   *binding_status = binding_status_got;
262   status = UWBSTATUS_SUCCESS;
263 
264 exit_check_binding_status:
265   phNxpUciHal_rx_handler_del(handler);
266   phNxpUciHal_cleanup_cb_data(&binding_check_ntf_wait);
267   return status;
268 }
269 
270 // Group Delay Compensation, if any
271 // SR1XX needs this, because it has
272 // different handling during calibration with D48/D49 vs D50
sr1xx_extra_group_delay(const uint8_t ch)273 static int16_t sr1xx_extra_group_delay(const uint8_t ch)
274 {
275   int16_t required_compensation = 0;
276 
277   /* Calibrated with D4X and we are on D5X or later */
278   bool is_calibrated_with_d4x = false;
279 
280   std::optional<std::string_view> res = NxpConfig_GetStr("cal.fw_version");
281 
282   if (res.has_value()) {
283     std::string_view fw_version = *res;
284     // Conf file has entry of `cal.fw_version`
285     is_calibrated_with_d4x =
286       fw_version.starts_with("48.") || fw_version.starts_with("49.");
287   }
288   else
289   {
290     NXPLOG_UCIHAL_W("Could not get cal.fw_version. Assuming D48 used for calibration.");
291     is_calibrated_with_d4x = true;
292   }
293 
294   if (is_calibrated_with_d4x) {
295     if (nxpucihal_ctrl.fw_version.major_version >= 0x50) {
296       required_compensation += (7*4); /*< 7 CM offset required... */
297     }
298     else
299     {
300       /* Running with D49. For testing purpose. +7cm Not needed */
301     }
302 
303     // Calibrated with D49
304     // Required extra negative offset, Channel specific, but antenna agnostic.
305     char key[32];
306     std::snprintf(key, sizeof(key), "cal.ch%u.extra_d49_offset_n", ch);
307     uint16_t cal_chx_extra_d49_offset_n = NxpConfig_GetNum<uint16_t>(key).value_or(0);
308     required_compensation -= cal_chx_extra_d49_offset_n;
309   }
310   else
311   {
312     // calibrated with D50 or later.
313     // No compensation.
314   }
315 
316   /* Its Q14.2 format, Actual CM impact is //4  */
317   return required_compensation;
318 }
319 
320 class NxpUwbChipHbciModule final : public NxpUwbChip {
321 public:
322   NxpUwbChipHbciModule();
323   virtual ~NxpUwbChipHbciModule();
324 
325   tHAL_UWB_STATUS chip_init();
326   tHAL_UWB_STATUS core_init();
327   device_type_t get_device_type(const uint8_t *param, size_t param_len);
328   tHAL_UWB_STATUS read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen);
329   tHAL_UWB_STATUS apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len);
330   tHAL_UWB_STATUS get_supported_channels(const uint8_t **cal_channels, uint8_t *nr);
331 
332   void suspend() override;
333   void resume() override;
334 
335 private:
336   tHAL_UWB_STATUS check_binding();
337   bool onDeviceStatusNtf(size_t packet_len, const uint8_t* packet);
338   bool onGenericErrorNtf(size_t packet_len, const uint8_t* packet);
339   bool onBindingStatusNtf(size_t packet_len, const uint8_t* packet);
340 
341 private:
342   UciHalRxHandler deviceStatusNtfHandler_;
343   UciHalRxHandler genericErrorNtfHandler_;
344   UciHalRxHandler bindingStatusNtfHandler_;
345   UciHalSemaphore bindingStatusNtfWait_;
346   uint8_t bindingStatus_;
347 };
348 
NxpUwbChipHbciModule()349 NxpUwbChipHbciModule::NxpUwbChipHbciModule() :
350   bindingStatus_(UWB_DEVICE_UNKNOWN)
351 {
352 }
353 
~NxpUwbChipHbciModule()354 NxpUwbChipHbciModule::~NxpUwbChipHbciModule()
355 {
356 }
357 
onDeviceStatusNtf(size_t packet_len,const uint8_t * packet)358 bool NxpUwbChipHbciModule::onDeviceStatusNtf(size_t packet_len, const uint8_t* packet)
359 {
360   if(packet_len > UCI_RESPONSE_STATUS_OFFSET) {
361     uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
362     if (status == UCI_STATUS_HW_RESET) {
363       sr1xx_clear_device_error();
364     }
365   }
366   return false;
367 }
368 
onGenericErrorNtf(size_t packet_len,const uint8_t * packet)369 bool NxpUwbChipHbciModule::onGenericErrorNtf(size_t packet_len, const uint8_t* packet)
370 {
371   if(packet_len > UCI_RESPONSE_STATUS_OFFSET) {
372     uint8_t status = packet[UCI_RESPONSE_STATUS_OFFSET];
373     if ( status == UCI_STATUS_THERMAL_RUNAWAY || status == UCI_STATUS_LOW_VBAT) {
374       sr1xx_handle_device_error();
375       return true;
376     }
377   }
378   return false;
379 }
380 
onBindingStatusNtf(size_t packet_len,const uint8_t * packet)381 bool NxpUwbChipHbciModule::onBindingStatusNtf(size_t packet_len, const uint8_t* packet)
382 {
383   if (packet_len > UCI_RESPONSE_STATUS_OFFSET) {
384     bindingStatus_ = packet[UCI_RESPONSE_STATUS_OFFSET];
385     NXPLOG_UCIHAL_D("BINDING_STATUS_NTF: 0x%x", bindingStatus_);
386     bindingStatusNtfWait_.post(UWBSTATUS_SUCCESS);
387   }
388   return true;
389 }
390 
check_binding()391 tHAL_UWB_STATUS NxpUwbChipHbciModule::check_binding()
392 {
393   // Wait for Binding status notification
394   if (bindingStatusNtfWait_.getStatus() != UWBSTATUS_SUCCESS) {
395     bindingStatusNtfWait_.wait_timeout_msec(3000);
396   }
397   if (bindingStatusNtfWait_.getStatus() != UWBSTATUS_SUCCESS) {
398     NXPLOG_UCIHAL_E("Binding status notification timeout");
399 
400     // Stop HAL init when it didn't receive the binding notification.
401     // or if it's not user mode fw, just continue
402     if (nxpucihal_ctrl.fw_boot_mode == USER_FW_BOOT_MODE)
403       return UWBSTATUS_FAILED;
404     else
405       return UWBSTATUS_SUCCESS;
406   }
407 
408   bool isBindingLockingAllowed =
409     NxpConfig_GetBool(NAME_UWB_BINDING_LOCKING_ALLOWED).value_or(false);
410   if (!isBindingLockingAllowed) {
411     return UWBSTATUS_SUCCESS;
412   }
413 
414   NXPLOG_UCIHAL_E("Current binding status: 0x%x", bindingStatus_);
415 
416   switch (bindingStatus_) {
417     case UWB_DEVICE_UNKNOWN:
418       // Treat 'UNKNOWN' state as 'NOT_BOUND'
419       NXPLOG_UCIHAL_E("Unknown binding status, proceed binding.");
420       [[fallthrough]];
421     case UWB_DEVICE_NOT_BOUND:
422     {
423       sr1xx_disable_dpd();
424 
425       // perform bind
426       uint8_t remaining_count = 0;
427       tHAL_UWB_STATUS status = sr1xx_do_bind(&bindingStatus_, &remaining_count);
428       if (status != UWBSTATUS_SUCCESS) {
429         return status;
430       }
431 
432       // perform lock
433       if (bindingStatus_ == UWB_DEVICE_BOUND_UNLOCKED && remaining_count < 3) {
434         status = sr1xx_check_binding_status(&bindingStatus_);
435         if (status != UWBSTATUS_SUCCESS) {
436           return status;
437         }
438       }
439     }
440     break;
441   case UWB_DEVICE_BOUND_UNLOCKED:
442     {
443       sr1xx_disable_dpd();
444 
445       // perform lock
446       tHAL_UWB_STATUS status = sr1xx_check_binding_status(&bindingStatus_);
447       if (status != UWBSTATUS_SUCCESS) {
448         // Sending originial binding status notification to upper layer
449         // XXX: Why?
450         report_binding_status(bindingStatus_);
451       }
452     }
453     break;
454 
455   case UWB_DEVICE_BOUND_LOCKED:
456     // do nothing
457     break;
458 
459   default:
460     NXPLOG_UCIHAL_E("Unknown binding status: 0x%x", bindingStatus_);
461     return UWBSTATUS_FAILED;
462   }
463 
464   return UWBSTATUS_SUCCESS;
465 }
466 
467 extern int phNxpUciHal_fw_download();
468 
chip_init()469 tHAL_UWB_STATUS NxpUwbChipHbciModule::chip_init()
470 {
471   tHAL_UWB_STATUS status;
472 
473   // system in FW download mode
474   // This will be cleared on first Device Status NTF
475   nxpucihal_ctrl.fw_dwnld_mode = true;
476 
477   NXPLOG_UCIHAL_D("Start SR1XX FW download");
478 
479   for (int i = 0; i < 5; i++) {
480     phTmlUwb_Chip_Reset();
481 
482     status = phNxpUciHal_fw_download();
483 
484     if (status == UWBSTATUS_SUCCESS) {
485       NXPLOG_UCIHAL_D("Complete SR1XX FW download");
486       break;
487     } else if(status == UWBSTATUS_FILE_NOT_FOUND) {
488       NXPLOG_UCIHAL_E("FW file Not found.");
489       break;
490     } else {
491       NXPLOG_UCIHAL_E("FW download failed, status= 0x%x, retry.", status);
492     }
493   }
494 
495   // register device status ntf handler
496   deviceStatusNtfHandler_ = UciHalRxHandler(
497       UCI_MT_NTF, UCI_GID_CORE, UCI_MSG_CORE_DEVICE_STATUS_NTF,
498       std::bind(&NxpUwbChipHbciModule::onDeviceStatusNtf, this, std::placeholders::_1, std::placeholders::_2)
499   );
500 
501   // register device error ntf handler
502   genericErrorNtfHandler_ = UciHalRxHandler(
503     UCI_MT_NTF, UCI_GID_CORE, UCI_MSG_CORE_GENERIC_ERROR_NTF,
504     std::bind(&NxpUwbChipHbciModule::onGenericErrorNtf, this, std::placeholders::_1, std::placeholders::_2)
505   );
506 
507   // register binding status ntf handler
508   bindingStatusNtfHandler_ = UciHalRxHandler(
509       UCI_MT_NTF, UCI_GID_PROPRIETARY, UCI_MSG_BINDING_STATUS_NTF,
510       std::bind(&NxpUwbChipHbciModule::onBindingStatusNtf, this, std::placeholders::_1, std::placeholders::_2)
511   );
512 
513   return status;
514 }
515 
core_init()516 tHAL_UWB_STATUS NxpUwbChipHbciModule::core_init()
517 {
518   return check_binding();
519 }
520 
get_device_type(const uint8_t * param,size_t param_len)521 device_type_t NxpUwbChipHbciModule::get_device_type(const uint8_t *param, size_t param_len)
522 {
523   // 'SR100S' or 'SR1..T'
524   if (param_len >= 6) {
525     const uint8_t marker = param[5];
526     if (marker == 'S')
527       return DEVICE_TYPE_SR1xxS;
528     else if (marker == 'T')
529       return DEVICE_TYPE_SR1xxT;
530   }
531   return DEVICE_TYPE_UNKNOWN;
532 }
533 
read_otp(extcal_param_id_t id,uint8_t * data,size_t data_len,size_t * retlen)534 tHAL_UWB_STATUS NxpUwbChipHbciModule::read_otp(extcal_param_id_t id, uint8_t *data, size_t data_len, size_t *retlen)
535 {
536   return sr1xx_read_otp(id, data, data_len, retlen);
537 }
538 
sr1xx_apply_calibration_ant_delay(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)539 tHAL_UWB_STATUS sr1xx_apply_calibration_ant_delay(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len) {
540 
541   std::vector<uint8_t> patched_data;
542   std::copy(&data[0], &data[data_len], std::back_inserter(patched_data));
543 
544   const int16_t delay_compensation = sr1xx_extra_group_delay(ch);
545   const uint8_t nr_entries = patched_data[0];
546   for (uint8_t i = 0; i < nr_entries; i++) {
547     // Android ABI & UCI both are Little endian
548     int32_t rx_delay32 = patched_data[2 + i * 3] | (patched_data[3 + i * 3] << 8);
549     if ( 0 != delay_compensation ) {
550       NXPLOG_UCIHAL_D("RX_ANT_DELAY_CALIB: Extra compensation '%d'", delay_compensation);
551       rx_delay32 += delay_compensation;
552     }
553 
554     // clamp to 0 ~ 0xffff
555     if (rx_delay32 >= 0xFFFF) {
556       rx_delay32 = 0xFFFF;
557     } else if (rx_delay32 < 0) {
558       rx_delay32 = 0;
559     }
560 
561     const uint16_t rx_delay = rx_delay32;
562     patched_data[2 + i * 3] = rx_delay & 0xff;
563     patched_data[3 + i * 3] = rx_delay >> 8;
564   }
565   return sr1xx_apply_calibration(id, ch, patched_data.data(), data_len);
566 }
567 
apply_calibration(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)568 tHAL_UWB_STATUS NxpUwbChipHbciModule::apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len)
569 {
570   if (id == EXTCAL_PARAM_RX_ANT_DELAY) {
571     return sr1xx_apply_calibration_ant_delay(id, ch, data, data_len);
572   }
573   else
574   {
575     return sr1xx_apply_calibration(id, ch, data, data_len);
576   }
577 }
578 
579 tHAL_UWB_STATUS
get_supported_channels(const uint8_t ** cal_channels,uint8_t * nr)580 NxpUwbChipHbciModule::get_supported_channels(const uint8_t **cal_channels, uint8_t *nr)
581 {
582   static const uint8_t sr100_cal_channels[] = {5, 6, 8, 9};
583   *cal_channels = sr100_cal_channels;
584   *nr = std::size(sr100_cal_channels);
585   return UWBSTATUS_SUCCESS;
586 }
587 
suspend()588 void NxpUwbChipHbciModule::suspend()
589 {
590   phTmlUwb_Suspend();
591 }
592 
resume()593 void NxpUwbChipHbciModule::resume()
594 {
595   phTmlUwb_Resume();
596 }
597 
GetUwbChip()598 std::unique_ptr<NxpUwbChip> GetUwbChip()
599 {
600   return std::make_unique<NxpUwbChipHbciModule>();
601 }
602