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