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 #include "phNxpUciHal_ext.h"
19 #include "phNxpUwbCalib.h"
20 #include "phUwbStatus.h"
21
22 //
23 // SR1XX Device Calibrations:
24 //
25 // Based on NXP SR1xx UCI v2.0.5
26 // current HAL impl only supports "xtal" read from otp
27 // others should be existed in .conf files
28
sr1xx_set_calibration(uint8_t channel,const std::vector<uint8_t> & tlv)29 static tHAL_UWB_STATUS sr1xx_set_calibration(uint8_t channel, const std::vector<uint8_t> &tlv)
30 {
31 // SET_CALIBRATION_CMD header: GID=0xF OID=0x21
32 std::vector<uint8_t> packet({ (0x20 | UCI_GID_PROPRIETARY_0X0F), UCI_MSG_SET_DEVICE_CALIBRATION, 0x00, 0x00});
33
34 // use 9 for channel-independent parameters
35 if (!channel) {
36 channel = 9;
37 }
38 packet.push_back(channel);
39 packet.insert(packet.end(), tlv.begin(), tlv.end());
40 packet[3] = packet.size() - 4;
41 return phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
42 }
43
sr1xx_set_conf(const std::vector<uint8_t> & tlv)44 static tHAL_UWB_STATUS sr1xx_set_conf(const std::vector<uint8_t> &tlv)
45 {
46 // SET_CALIBRATION_CMD header: GID=0xF OID=0x21
47 std::vector<uint8_t> packet({ (0x20 | UCI_GID_CORE), UCI_MSG_CORE_SET_CONFIG, 0x00, 0x00});
48 packet.push_back(1); // number of parameters
49 packet.insert(packet.end(), tlv.begin(), tlv.end());
50 packet[3] = packet.size() - 4;
51 return phNxpUciHal_send_ext_cmd(packet.size(), packet.data());
52 }
53
sr1xx_apply_calibration(extcal_param_id_t id,const uint8_t ch,const uint8_t * data,size_t data_len)54 tHAL_UWB_STATUS sr1xx_apply_calibration(extcal_param_id_t id, const uint8_t ch, const uint8_t *data, size_t data_len)
55 {
56 // Device Calibration
57 const uint8_t UCI_PARAM_ID_RF_CLK_ACCURACY_CALIB = 0x01;
58 const uint8_t UCI_PARAM_ID_RX_ANT_DELAY_CALIB = 0x02;
59 const uint8_t UCI_PARAM_ID_TX_POWER_PER_ANTENNA = 0x04;
60
61 // Device Configurations
62 const uint16_t UCI_PARAM_ID_TX_BASE_BAND_CONFIG = 0xe426;
63 const uint16_t UCI_PARAM_ID_DDFS_TONE_CONFIG = 0xe427;
64 const uint16_t UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG = 0xe428;
65
66 switch (id) {
67 case EXTCAL_PARAM_CLK_ACCURACY:
68 {
69 if (data_len != 6) {
70 return UWBSTATUS_FAILED;
71 }
72
73 std::vector<uint8_t> tlv;
74 // Tag
75 tlv.push_back(UCI_PARAM_ID_RF_CLK_ACCURACY_CALIB);
76 // Length
77 tlv.push_back((uint8_t)data_len + 1);
78 // Value
79 tlv.push_back(3); // number of register (must be 0x03)
80 tlv.insert(tlv.end(), data, data + data_len);
81
82 return sr1xx_set_calibration(ch, tlv);
83 }
84 case EXTCAL_PARAM_RX_ANT_DELAY:
85 {
86 // [0] = number of entries
87 // {
88 // [0] = rx antenna id
89 // [1,2] = rx delay
90 // }
91 if (!ch || data_len < 1 || !data[0] || (data[0] * 3) != (data_len - 1)) {
92 return UWBSTATUS_FAILED;
93 }
94
95 std::vector<uint8_t> tlv;
96 // Tag
97 tlv.push_back(UCI_PARAM_ID_RX_ANT_DELAY_CALIB);
98 // Length
99 tlv.push_back((uint8_t)data_len);
100 // Value
101 tlv.insert(tlv.end(), data, data + data_len);
102
103 return sr1xx_set_calibration(ch, tlv);
104 }
105 case EXTCAL_PARAM_TX_POWER:
106 {
107 if (!ch || data_len < 1 || !data[0] || (data[0] * 5) != (data_len - 1)) {
108 return UWBSTATUS_FAILED;
109 }
110
111 std::vector<uint8_t> tlv;
112 // Tag
113 tlv.push_back(UCI_PARAM_ID_TX_POWER_PER_ANTENNA);
114 // Length
115 tlv.push_back((uint8_t)data_len);
116 // Value
117 tlv.insert(tlv.end(), data, data + data_len);
118
119 return sr1xx_set_calibration(ch, tlv);
120 }
121 case EXTCAL_PARAM_TX_BASE_BAND_CONTROL:
122 {
123 if (data_len != 1) {
124 return UWBSTATUS_FAILED;
125 }
126
127 std::vector<uint8_t> tlv;
128 // Tag
129 tlv.push_back(UCI_PARAM_ID_TX_BASE_BAND_CONFIG >> 8);
130 tlv.push_back(UCI_PARAM_ID_TX_BASE_BAND_CONFIG & 0xff);
131 // Length
132 tlv.push_back(1);
133 // Value
134 tlv.push_back(data[0]);
135
136 return sr1xx_set_conf(tlv);
137 }
138 case EXTCAL_PARAM_DDFS_TONE_CONFIG:
139 {
140 if (!data_len) {
141 return UWBSTATUS_FAILED;
142 }
143
144 std::vector<uint8_t> tlv;
145 // Tag
146 tlv.push_back(UCI_PARAM_ID_DDFS_TONE_CONFIG >> 8);
147 tlv.push_back(UCI_PARAM_ID_DDFS_TONE_CONFIG & 0xff);
148 // Length
149 tlv.push_back(data_len);
150 // Value
151 tlv.insert(tlv.end(), data, data + data_len);
152
153 return sr1xx_set_conf(tlv);
154 }
155 case EXTCAL_PARAM_TX_PULSE_SHAPE:
156 {
157 if (!data_len) {
158 return UWBSTATUS_FAILED;
159 }
160
161 std::vector<uint8_t> tlv;
162 // Tag
163 tlv.push_back(UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG >> 8);
164 tlv.push_back(UCI_PARAM_ID_TX_PULSE_SHAPE_CONFIG & 0xff);
165 // Length
166 tlv.push_back(data_len);
167 // Value
168 tlv.insert(tlv.end(), data, data + data_len);
169
170 return sr1xx_set_conf(tlv);
171 }
172 default:
173 NXPLOG_UCIHAL_E("Unsupported parameter: 0x%x", id);
174 return UWBSTATUS_FAILED;
175 }
176 }
177