1 /**
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifdef SUPPORT_AUDIO_LIEYIN_TOOL
17 #include <stdint.h>
18 #include "common_def.h"
19 #include <string.h>
20 #include <strings.h>
21 #include "securec.h"
22 #include "debug_print.h"
23 #include "audio_crc16.h"
24 #include "audio_lieyin.h"
25
26 #define LIEYIN_ADAPT_AT_CMD_R "CRXXAT^AUDIO"
27 #define LIEYIN_ADAPT_AT_CMD_L "CLXXAT^AUDIO"
28 #define LIEYIN_MODULE_NAME "cc0402"
29 #define LIEYIN_CHAR_MAX_LENGTH 16
30 #define BYTE_MASK 0xff
31 #define BIT_SHIFT_8 8
32 #define BIT_SHIFT_16 16
33 #define BIT_SHIFT_24 24
34
35 typedef uint32_t (*lieyin_func_callback)(uint8_t *para, uint32_t len);
36 typedef struct {
37 char *func_name;
38 lieyin_func_callback callback;
39 bool is_bin;
40 } lieyin_cmd_process_t;
41
42 typedef struct {
43 uint8_t tag;
44 uint8_t resp; // for ux handle flag
45 uint8_t src;
46 uint8_t dst;
47 uint16_t len;
48 } pkt_header_t;
49
50 typedef enum {
51 CMD_WRITE_DATA_OK = 0,
52 CMD_WRITE_DATA_CRC_ERROR,
53 CMD_WRITE_DATA_WRITE_FAIL,
54 CMD_MALLOC_MEM_FAIL,
55 } audio_cmd_ret_code_t;
56
57 static uint32_t cc0402_write_bin(uint8_t *para, uint32_t len);
58 static uint32_t cc0402_read_bin(uint8_t *para, uint32_t len);
59
60 static const lieyin_cmd_process_t g_cc0402_cmds[] = {
61 {"write_bin", cc0402_write_bin, true},
62 {"read_bin", cc0402_read_bin, true},
63 };
64
audio_cmd_feedback(uint8_t * para,uint16_t len)65 static void audio_cmd_feedback(uint8_t *para, uint16_t len)
66 {
67 if (para == NULL) {
68 PRINT("[AudioCmdBinFeedback] para is NULL");
69 return;
70 }
71
72 uint16_t data_crc = checksum_crc16(0, para, len);
73 char feedback_lead[] = "ASK";
74 uint16_t send_len = len + sizeof(pkt_header_t) + strlen(feedback_lead) + sizeof(data_crc);
75 uint8_t *send_buf;
76
77 send_buf = (uint8_t *)malloc(send_len);
78 if (send_buf == NULL) {
79 PRINT("[AudioCmdBinFeedback] malloc is failed");
80 return;
81 }
82
83 pkt_header_t *header = (pkt_header_t *)send_buf;
84 uint8_t *ptr_send = send_buf;
85
86 header->resp = 1;
87 header->tag = 0;
88 header->dst = 'R'; // right earphone
89 header->src = 'C'; // PC End
90 header->len = len + strlen(feedback_lead);
91
92 ptr_send += sizeof(pkt_header_t);
93 if (memcpy_s(ptr_send, strlen(feedback_lead), feedback_lead, strlen(feedback_lead)) != EOK) {
94 PRINT("[AudioCmdBinFeedback] memcpy_s is failed");
95 free(send_buf);
96 return;
97 }
98
99 ptr_send += strlen(feedback_lead);
100 if (memcpy_s(ptr_send, len, para, len) != EOK) {
101 PRINT("[AudioCmdBinFeedback] memcpy_s is failed");
102 free(send_buf);
103 return;
104 }
105
106 ptr_send += len;
107 if (memcpy_s(ptr_send, sizeof(data_crc), (uint8_t *)&data_crc, sizeof(data_crc)) != EOK) {
108 PRINT("[AudioCmdBinFeedback] memcpy_s is failed");
109 free(send_buf);
110 return;
111 }
112
113 uapi_uart_write(TEST_SUITE_UART_BUS, send_buf, send_len, 0);
114 uapi_uart_write(TEST_SUITE_UART_BUS, '\r', 1, 0);
115 uapi_uart_write(TEST_SUITE_UART_BUS, '\n', 1, 0);
116 }
117
cc0402_write_bin(uint8_t * para,uint32_t len)118 static uint32_t cc0402_write_bin(uint8_t *para, uint32_t len)
119 {
120 if (para == NULL || len < (sizeof(uint32_t) + sizeof(uint8_t))) {
121 PRINT("err param len=%d\r\nFAILED", len);
122 return 0;
123 }
124
125 uint8_t *ptr = para;
126 uint32_t address;
127 uint8_t *data = ptr + sizeof(address);
128 uint16_t data_len = 0;
129 uint8_t feedback_ret = CMD_WRITE_DATA_OK;
130
131 data_len = len - sizeof(address);
132
133 if (data_len == 0 || data_len > 450) { /* 450: short cmd max data len */
134 PRINT("err param len=%d, data_len=%u\r\nFAILED", len, data_len);
135 return 0;
136 }
137
138 address = ((*(ptr + 0x3)) << BIT_SHIFT_24) + ((*(ptr + 0x2)) << BIT_SHIFT_16) +
139 ((*(ptr + 1)) << BIT_SHIFT_8) + (*ptr);
140
141 /* to write bin */
142 /* send feedback */
143 audio_cmd_feedback(&feedback_ret, sizeof(feedback_ret));
144 return 1;
145 }
146
cc0402_read_bin(uint8_t * para,uint32_t len)147 static uint32_t cc0402_read_bin(uint8_t *para, uint32_t len)
148 {
149 if (para == NULL || len < (sizeof(uint32_t) + sizeof(uint16_t))) {
150 PRINT("err param len=%d\r\nFAILED", len);
151 return 0;
152 }
153
154 uint8_t *ptr = para;
155 uint32_t address;
156 uint16_t data_len;
157 uint8_t feedback_ret = CMD_WRITE_DATA_OK;
158 uint8_t *send_buf = NULL;
159
160 address = ((*(ptr + 0x3)) << BIT_SHIFT_24) + ((*(ptr + 0x2)) << BIT_SHIFT_16) +
161 ((*(ptr + 1)) << BIT_SHIFT_8) + (*ptr);
162 ptr += sizeof(address);
163 data_len = ((*(ptr + 1)) << BIT_SHIFT_8) + (*ptr);
164
165 send_buf = malloc(data_len + sizeof(feedback_ret));
166 if (send_buf == NULL) {
167 PRINT("[Cc0401ReadBin]malloc fail!\r\n");
168 return 0;
169 }
170
171 /* read to send_buf + sizeof(feedback_ret), mocked */
172 for (uint32_t i = 0; i < data_len; i++) {
173 send_buf[sizeof(feedback_ret) + i] = (uint8_t)i;
174 }
175
176 send_buf[0] = feedback_ret;
177 audio_cmd_feedback(send_buf, data_len + sizeof(feedback_ret));
178
179 return 1;
180 }
181
lieyin_cmd_argument_get(char * argument,const char * string,char split_char)182 static uint8_t lieyin_cmd_argument_get(char *argument, const char *string, char split_char)
183 {
184 uint8_t i = 0;
185 uint16_t index = 0;
186 while (string[index] != 0) {
187 if (string[index] == split_char || (i == LIEYIN_CHAR_MAX_LENGTH - 1)) {
188 break; /* we have found the first element */
189 }
190 argument[index] = string[index];
191 i++;
192 index++;
193 }
194 argument[index] = '\0';
195 return i;
196 }
197
lieyin_command_proc_bin(uint8_t * para,uint32_t length,lieyin_func_callback callback)198 static int32_t lieyin_command_proc_bin(uint8_t *para, uint32_t length, lieyin_func_callback callback)
199 {
200 uint8_t *ptr = para;
201 uint8_t *cmd_data;
202 errno_t ret;
203 uint16_t data_len, data_crc, crc_check;
204
205 data_len = ((*(ptr + 1)) << BIT_SHIFT_8) + (*ptr);
206 ptr += sizeof(data_len);
207
208 cmd_data = (uint8_t *)malloc(data_len);
209 if (cmd_data == NULL) {
210 PRINT("[AudioCmdProcBin] malloc fail! cmdDatalen:%d", data_len);
211 return -1;
212 }
213
214 ret = memcpy_s(cmd_data, data_len, ptr, data_len);
215 if (ret != EOK) {
216 free(cmd_data);
217 return -1;
218 }
219
220 ptr += data_len;
221 data_crc = ((*(ptr + 1)) << BIT_SHIFT_8) + (*ptr) ;
222
223 crc_check = checksum_crc16(0, (uint8_t *)cmd_data, data_len);
224 #ifdef AUDIO_LIEYIN_DEBUG
225 PRINT("[AudioCmdProcBin] cmdDatalen:%d data_crc:0x%x crc_check:0x%x\r\n", data_len, data_crc, crc_check);
226 #endif
227 if (crc_check != data_crc) {
228 PRINT("[AudioCmdProcBin] crc check is failed, rec_len=0x%x, len_val=0x%x, cal_crc=0x%x, rec_crc=0x%x",
229 length - sizeof(data_len) - sizeof(data_crc), data_len, crc_check, data_crc);
230 free(cmd_data);
231 return -1;
232 }
233
234 if (callback != NULL) {
235 callback(cmd_data, data_len);
236 }
237
238 free(cmd_data);
239 return 0;
240 }
241
audio_lieyin_command_execute(char * module,char * func,char * para,uint32_t length)242 void audio_lieyin_command_execute(char *module, char *func, char *para, uint32_t length)
243 {
244 if (strcasecmp(module, LIEYIN_MODULE_NAME) != 0) {
245 return;
246 }
247
248 for (uint32_t i = 0; i < (sizeof(g_cc0402_cmds) / sizeof(lieyin_cmd_process_t)); i++) {
249 if (strcasecmp(func, g_cc0402_cmds[i].func_name) == 0) {
250 if (g_cc0402_cmds[i].is_bin) {
251 (void)lieyin_command_proc_bin((uint8_t *)para, length, g_cc0402_cmds[i].callback);
252 } else {
253 g_cc0402_cmds[i].callback((uint8_t *)para, length);
254 }
255 }
256 }
257 }
258
audio_lieyin_command_receive(char * buf,uint32_t length)259 void audio_lieyin_command_receive(char *buf, uint32_t length)
260 {
261 char first_argument[LIEYIN_CHAR_MAX_LENGTH] = { 0 };
262 char module[LIEYIN_CHAR_MAX_LENGTH] = { 0 };
263 char func_name[LIEYIN_CHAR_MAX_LENGTH] = { 0 };
264 uint8_t argument_length;
265 char *current_cmd = buf;
266 uint32_t remain_len = length;
267
268 argument_length = lieyin_cmd_argument_get(first_argument, current_cmd, '=');
269 #ifdef AUDIO_LIEYIN_DEBUG
270 PRINT("= argument:%d\r\n", argument_length);
271 #endif
272 /* if it is empty just return */
273 if (argument_length == 0 || (argument_length + 1 >= remain_len)) {
274 return; /* EARLY RETURN */
275 }
276 current_cmd += argument_length + 1;
277 remain_len -= argument_length + 1;
278
279 argument_length = lieyin_cmd_argument_get(module, current_cmd, ',');
280 #ifdef AUDIO_LIEYIN_DEBUG
281 PRINT(",1 argument:%d\r\n", argument_length);
282 #endif
283 if (argument_length == 0 || (argument_length + 1 >= remain_len)) {
284 return; /* EARLY RETURN */
285 }
286 current_cmd += argument_length + 1;
287 remain_len -= argument_length + 1;
288
289 argument_length = lieyin_cmd_argument_get(func_name, current_cmd, ',');
290 #ifdef AUDIO_LIEYIN_DEBUG
291 PRINT(",2 argument:%d\r\n", argument_length);
292 #endif
293 if (argument_length == 0 || (argument_length + 1 > remain_len)) {
294 return; /* EARLY RETURN */
295 }
296 current_cmd += argument_length + 1;
297 remain_len -= argument_length + 1;
298 #ifdef AUDIO_LIEYIN_DEBUG
299 PRINT("param len:%d\r\n", remain_len);
300 #endif
301
302 if ((strcasecmp(first_argument, LIEYIN_ADAPT_AT_CMD_R) == 0) ||
303 (strcasecmp(first_argument, LIEYIN_ADAPT_AT_CMD_L) == 0)) {
304 audio_lieyin_command_execute(module, func_name, current_cmd, remain_len);
305 }
306 }
307 #endif