1 /*
2  * Copyright 2021-2023 NXP
3  * Copyright 2024 Google
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 
19 #include "phNxpUwbCalib.h"
20 #include "phUwbStatus.h"
21 #include "phNxpUciHal_ext.h"
22 
23 /* SR1XX is same as SR2XX */
24 static tHAL_UWB_STATUS sr1xx_apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len);
25 static tHAL_UWB_STATUS sr1xx_set_conf(const std::vector<uint8_t> &tlv);
26 static tHAL_UWB_STATUS sr1xx_set_calibration(uint8_t channel, const std::vector<uint8_t> &tlv);
27 
28 
phNxpUwbCalib_apply_calibration(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)29 tHAL_UWB_STATUS phNxpUwbCalib_apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len) {
30   return sr1xx_apply_calibration(id, ch, data, data_len);
31 }
32 
33 //
34 // SR1XX Device Calibrations:
35 //
36 // Based on NXP SR1xx UCI v2.0.5
37 // current HAL impl only supports "xtal" read from otp
38 // others should be existed in .conf files
39 
sr1xx_set_calibration(uint8_t channel,const std::vector<uint8_t> & tlv)40 static tHAL_UWB_STATUS sr1xx_set_calibration(uint8_t channel, const std::vector<uint8_t> &tlv)
41 {
42   // SET_CALIBRATION_CMD header: GID=0xF OID=0x21
43   std::vector<uint8_t> packet({ (0x20 | UCI_GID_PROPRIETARY_0X0F), UCI_MSG_SET_DEVICE_CALIBRATION, 0x00, 0x00});
44 
45   // use 9 for channel-independent parameters
46   if (!channel) {
47     channel = 9;
48   }
49   packet.push_back(channel);
50   packet.insert(packet.end(), tlv.begin(), tlv.end());
51   packet[3] = packet.size() - 4;
52   return phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
53 }
54 
sr1xx_set_conf(const std::vector<uint8_t> & tlv)55 static tHAL_UWB_STATUS sr1xx_set_conf(const std::vector<uint8_t> &tlv)
56 {
57   // SET_CALIBRATION_CMD header: GID=0xF OID=0x21
58   std::vector<uint8_t> packet({ (0x20 | UCI_GID_CORE), UCI_MSG_CORE_SET_CONFIG, 0x00, 0x00});
59   packet.push_back(1);  // number of parameters
60   packet.insert(packet.end(), tlv.begin(), tlv.end());
61   packet[3] = packet.size() - 4;
62   return phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
63 }
64 
sr1xx_apply_calibration(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)65 static tHAL_UWB_STATUS sr1xx_apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len)
66 {
67   // Device Calibration
68   const uint8_t UCI_PARAM_ID_RF_CLK_ACCURACY_CALIB    = 0x01;
69   const uint8_t UCI_PARAM_ID_RX_ANT_DELAY_CALIB       = 0x02;
70   const uint8_t UCI_PARAM_ID_TX_POWER_PER_ANTENNA     = 0x04;
71 
72   // Device Configurations
73   const uint16_t UCI_PARAM_ID_TX_BASE_BAND_CONFIG     = 0xe426;
74   const uint16_t UCI_PARAM_ID_DDFS_TONE_CONFIG        = 0xe427;
75   const uint16_t UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG   = 0xe428;
76 
77   switch (id) {
78   case EXTCAL_PARAM_CLK_ACCURACY:
79     {
80       if (data_len != 6) {
81         return UWBSTATUS_FAILED;
82       }
83 
84       std::vector<uint8_t> tlv;
85       // Tag
86       tlv.push_back(UCI_PARAM_ID_RF_CLK_ACCURACY_CALIB);
87       // Length
88       tlv.push_back((uint8_t)data_len + 1);
89       // Value
90       tlv.push_back(3); // number of register (must be 0x03)
91       tlv.insert(tlv.end(), data, data + data_len);
92 
93       return sr1xx_set_calibration(ch, tlv);
94     }
95   case EXTCAL_PARAM_RX_ANT_DELAY:
96     {
97       if (!ch || data_len < 1 || !data[0] || (data[0] * 3) != (data_len - 1)) {
98         return UWBSTATUS_FAILED;
99       }
100 
101       std::vector<uint8_t> tlv;
102       // Tag
103       tlv.push_back(UCI_PARAM_ID_RX_ANT_DELAY_CALIB);
104       // Length
105       tlv.push_back((uint8_t)data_len);
106       // Value
107       tlv.insert(tlv.end(), data, data + data_len);
108 
109       return sr1xx_set_calibration(ch, tlv);
110     }
111   case EXTCAL_PARAM_TX_POWER:
112     {
113       if (!ch || data_len < 1 || !data[0] || (data[0] * 5) != (data_len - 1)) {
114         return UWBSTATUS_FAILED;
115       }
116 
117       std::vector<uint8_t> tlv;
118       // Tag
119       tlv.push_back(UCI_PARAM_ID_TX_POWER_PER_ANTENNA);
120       // Length
121       tlv.push_back((uint8_t)data_len);
122       // Value
123       tlv.insert(tlv.end(), data, data + data_len);
124 
125       return sr1xx_set_calibration(ch, tlv);
126     }
127   case EXTCAL_PARAM_TX_BASE_BAND_CONTROL:
128     {
129       if (data_len != 1) {
130         return UWBSTATUS_FAILED;
131       }
132 
133       std::vector<uint8_t> tlv;
134       // Tag
135       tlv.push_back(UCI_PARAM_ID_TX_BASE_BAND_CONFIG >> 8);
136       tlv.push_back(UCI_PARAM_ID_TX_BASE_BAND_CONFIG & 0xff);
137       // Length
138       tlv.push_back(1);
139       // Value
140       tlv.push_back(data[0]);
141 
142       return sr1xx_set_conf(tlv);
143     }
144   case EXTCAL_PARAM_DDFS_TONE_CONFIG:
145     {
146       if (!data_len) {
147         return UWBSTATUS_FAILED;
148       }
149 
150       std::vector<uint8_t> tlv;
151       // Tag
152       tlv.push_back(UCI_PARAM_ID_DDFS_TONE_CONFIG >> 8);
153       tlv.push_back(UCI_PARAM_ID_DDFS_TONE_CONFIG & 0xff);
154       // Length
155       tlv.push_back(data_len);
156       // Value
157       tlv.insert(tlv.end(), data, data + data_len);
158 
159       return sr1xx_set_conf(tlv);
160     }
161   case EXTCAL_PARAM_TX_PULSE_SHAPE:
162     {
163       if (!data_len) {
164         return UWBSTATUS_FAILED;
165       }
166 
167       std::vector<uint8_t> tlv;
168       // Tag
169       tlv.push_back(UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG >> 8);
170       tlv.push_back(UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG & 0xff);
171       // Length
172       tlv.push_back(data_len);
173       // Value
174       tlv.insert(tlv.end(), data, data + data_len);
175 
176       return sr1xx_set_conf(tlv);
177     }
178   default:
179     NXPLOG_UCIHAL_E("Unsupported parameter: 0x%x", id);
180     return UWBSTATUS_FAILED;
181   }
182 }
183