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