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. \n
14 *
15 * Description: Provides at channel source \n
16 */
17
18 #include <stdbool.h>
19 #include "at_base.h"
20 #include "at_msg.h"
21 #include "at_channel.h"
22
23 #define AT_FLAG_LENGTH 2
24
25 typedef struct {
26 at_channel_state_t state;
27 at_write_func_t write_func;
28 uint32_t len;
29 uint8_t* data;
30 } at_channel_t;
31
32 static at_channel_t g_channel_entry[AT_MAX_PORT_NUMBER] = {0};
33
uapi_at_channel_write_register(at_channel_id_t id,at_write_func_t func)34 errcode_t uapi_at_channel_write_register(at_channel_id_t id, at_write_func_t func)
35 {
36 if (id >= AT_MAX_PORT_NUMBER || func == NULL) {
37 return ERRCODE_INVALID_PARAM;
38 }
39 g_channel_entry[id].write_func = func;
40 return ERRCODE_SUCC;
41 }
42
at_channel_check_and_enable(void)43 void at_channel_check_and_enable(void)
44 {
45 for (uint16_t id = 0; id < AT_MAX_PORT_NUMBER; id++) {
46 if (g_channel_entry[id].state != AT_CHANNEL_UNINITIALIZED) {
47 continue;
48 }
49
50 if (g_channel_entry[id].write_func == NULL) {
51 continue;
52 }
53
54 g_channel_entry[id].state = AT_CHANNEL_FREE;
55 }
56 }
57
at_channel_get_write_func(at_channel_id_t id)58 at_write_func_t at_channel_get_write_func(at_channel_id_t id)
59 {
60 if (g_channel_entry[id].state == AT_CHANNEL_UNINITIALIZED) {
61 return NULL;
62 }
63 return g_channel_entry[id].write_func;
64 }
65
at_channel_get_data(at_channel_id_t id)66 uint8_t* at_channel_get_data(at_channel_id_t id)
67 {
68 return g_channel_entry[id].data;
69 }
70
at_channel_set_state(at_channel_id_t id,at_channel_state_t state)71 void at_channel_set_state(at_channel_id_t id, at_channel_state_t state)
72 {
73 g_channel_entry[id].state = state;
74 }
75
at_channel_data_reset(at_channel_id_t id)76 void at_channel_data_reset(at_channel_id_t id)
77 {
78 if (g_channel_entry[id].data != NULL) {
79 at_free(g_channel_entry[id].data);
80 g_channel_entry[id].data = NULL;
81 }
82 g_channel_entry[id].len = 0;
83 g_channel_entry[id].state = AT_CHANNEL_FREE;
84 }
85
at_channel_data_wait_interactivity(at_channel_id_t id)86 void at_channel_data_wait_interactivity(at_channel_id_t id)
87 {
88 g_channel_entry[id].state = AT_CHANNEL_INTERACTIVITY;
89 }
90
at_is_channel_block(at_channel_id_t id)91 static bool at_is_channel_block(at_channel_id_t id)
92 {
93 if (g_channel_entry[id].state == AT_CHANNEL_BLOCK ||
94 g_channel_entry[id].state == AT_CHANNEL_UNINITIALIZED) {
95 return true;
96 }
97 return false;
98 }
99
at_channel_is_data_integrated(at_channel_id_t id)100 static bool at_channel_is_data_integrated(at_channel_id_t id)
101 {
102 for (uint32_t index = 1; index < g_channel_entry[id].len; index++) {
103 if (g_channel_entry[id].data[index] == '\r' ||
104 g_channel_entry[id].data[index] == '\n') {
105 g_channel_entry[id].data[index] = '\0';
106 return true;
107 }
108 }
109 return false;
110 }
111
at_channel_del_invalid_data(at_channel_id_t id,uint32_t index)112 static void at_channel_del_invalid_data(at_channel_id_t id, uint32_t index)
113 {
114 if (memmove_s(g_channel_entry[id].data, AT_CMD_MAX_LENGTH,
115 g_channel_entry[id].data + index, AT_CMD_MAX_LENGTH - index) != EOK) {
116 return;
117 }
118 g_channel_entry[id].len -= index;
119 }
120
at_channel_cmd_head_check(at_channel_id_t id)121 static bool at_channel_cmd_head_check(at_channel_id_t id)
122 {
123 uint32_t index;
124 for (index = 0; index < g_channel_entry[id].len - 1; index++) {
125 if (((g_channel_entry[id].data[index] == 'a') || (g_channel_entry[id].data[index] == 'A')) &&
126 ((g_channel_entry[id].data[index + 1] == 't') || (g_channel_entry[id].data[index + 1] == 'T'))) {
127 at_channel_del_invalid_data(id, index);
128 return true;
129 }
130 }
131
132 if (g_channel_entry[id].data[index] == 'a' || g_channel_entry[id].data[index] == 'A') {
133 at_channel_del_invalid_data(id, index);
134 } else {
135 at_channel_data_reset(id);
136 }
137
138 return false;
139 }
140
at_channel_send_msg(at_msg_type_t type,at_channel_id_t id)141 static errcode_t at_channel_send_msg(at_msg_type_t type, at_channel_id_t id)
142 {
143 at_msg_block_t msg;
144 msg.type = type;
145 msg.sub_msg.cmd.channel_id = id;
146 msg.sub_msg.cmd.len = (uint16_t)g_channel_entry[id].len;
147
148 return at_msg_send(&msg);
149 }
150
at_channel_cmd_handle(at_channel_id_t id)151 static errcode_t at_channel_cmd_handle(at_channel_id_t id)
152 {
153 errcode_t ret;
154
155 if (at_channel_cmd_head_check(id) != true) {
156 return ERRCODE_SUCC;
157 }
158
159 if (at_channel_is_data_integrated(id) != true) {
160 return ERRCODE_SUCC;
161 }
162
163 at_channel_del_invalid_data(id, AT_FLAG_LENGTH);
164 if (g_channel_entry[id].data[0] == '\0') {
165 g_channel_entry[id].write_func(AT_RESPONSE_OK);
166 return ERRCODE_SUCC;
167 }
168
169 g_channel_entry[id].state = AT_CHANNEL_BLOCK;
170 ret = at_channel_send_msg(AT_CMD_MSG, id);
171 if (ret != ERRCODE_SUCC) {
172 at_channel_data_reset(id);
173 g_channel_entry[id].state = AT_CHANNEL_FREE;
174 }
175 return ret;
176 }
177
at_channel_interactivity_handle(at_channel_id_t id)178 static errcode_t at_channel_interactivity_handle(at_channel_id_t id)
179 {
180 if (at_channel_is_data_integrated(id) != true) {
181 return ERRCODE_SUCC;
182 }
183
184 g_channel_entry[id].state = AT_CHANNEL_BLOCK;
185 return at_channel_send_msg(AT_CMD_INTERACTIVITY_MSG, id);
186 }
187
at_channel_data_handle(at_channel_id_t id)188 static errcode_t at_channel_data_handle(at_channel_id_t id)
189 {
190 if (g_channel_entry[id].state == AT_CHANNEL_FREE) {
191 return at_channel_cmd_handle(id);
192 } else {
193 return at_channel_interactivity_handle(id);
194 }
195 }
196
at_channel_prepare(at_channel_id_t id)197 static errcode_t at_channel_prepare(at_channel_id_t id)
198 {
199 if (at_is_channel_block(id) == true) {
200 return ERRCODE_AT_CHANNEL_BUSY;
201 }
202
203 if (g_channel_entry[id].data == NULL) {
204 g_channel_entry[id].data = at_malloc(AT_CMD_MAX_LENGTH);
205 if (g_channel_entry[id].data == NULL) {
206 return ERRCODE_MALLOC;
207 }
208 memset_s(g_channel_entry[id].data, AT_CMD_MAX_LENGTH, 0, AT_CMD_MAX_LENGTH);
209 }
210
211 return ERRCODE_SUCC;
212 }
213
at_channel_data_add(at_channel_id_t id,uint8_t * data,uint32_t len)214 static errcode_t at_channel_data_add(at_channel_id_t id, uint8_t* data, uint32_t len)
215 {
216 if (g_channel_entry[id].len + len > AT_CMD_MAX_LENGTH) {
217 at_channel_data_reset(id);
218 return ERRCODE_AT_CMD_TOO_LONG;
219 }
220
221 if (memcpy_s(g_channel_entry[id].data + g_channel_entry[id].len,
222 len, data, len) != AT_RET_OK) {
223 at_channel_data_reset(id);
224 return ERRCODE_MEMCPY;
225 }
226 g_channel_entry[id].len += len;
227
228 return ERRCODE_SUCC;
229 }
230
uapi_at_channel_data_recv(at_channel_id_t id,uint8_t * data,uint32_t len)231 errcode_t uapi_at_channel_data_recv(at_channel_id_t id, uint8_t* data, uint32_t len)
232 {
233 if (id >= AT_MAX_PORT_NUMBER || data == NULL || len == 0) {
234 return ERRCODE_INVALID_PARAM;
235 }
236
237 errcode_t err_ret = at_channel_prepare(id);
238 if (err_ret != ERRCODE_SUCC) {
239 return err_ret;
240 }
241
242 err_ret = at_channel_data_add(id, data, len);
243 if (err_ret != ERRCODE_SUCC) {
244 return err_ret;
245 }
246
247 return at_channel_data_handle(id);
248 }
249