1 /*
2 * Copyright (c) 2021 Chipsea Technologies (Shenzhen) Corp., Ltd. All rights reserved.
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 #include "wifi_host.h"
17 #include "netdb.h"
18 #include "wifi_host_config.h"
19 #include "wifi_host_cntrl.h"
20 #include "wifi_nx_msg_tx.h"
21 #include "wlan_if.h"
22 #include "sleep_api.h"
23 #if PLF_BLE_STACK
24 #include "app_smartconfig.h"
25 #include "ble_task.h"
26 #endif
27 #define TEST_SCAN 0
28 #define TRACE_APP(...) do {} while (0)
29
30 /**
31 *******************************************************************************
32 * @defgroup BLE_SMARTCONFIG_WIFI_EXAMPLE
33 * @ingroup FHOST
34 * @{
35 *
36 * This module contains code of an example application.\n
37 * Each application needs to define a few mandatory functions:
38 * - fhost_application_init: Called during firmware intialization to prepare
39 * the application task.\n
40 * In this example the function creates a single task.
41 *
42 * - fhost_config_get_next_item: Used by control task to retrieve runtime
43 * configuration of the wifi firmware.\n
44 * In this example the configuration is read from variable @ref example_config
45 *
46 * This example application is very basic:
47 * - First it enable ble advertising
48 * When host receiver adv packets, connect to ble device, send ssid/pw to it
49 * - Then it connect to an Access Point
50 * Then a DHCP procedure is started to retrieve an IP address.
51 * When DHCP done, it send wifi connect state to host through ble
52 *
53 *******************************************************************************
54 */
55
56 #define TEST_CONNECT 0
57
58 /// Link parameters
59 static struct fhost_cntrl_link *cntrl_link;
60
61 #if TEST_CONNECT
example_connect_website()62 static int example_connect_website()
63 {
64 char host[] = "api.forismatic.com";
65 char query[] = "\
66 GET /api/1.0/?method=getQuote&format=text&lang=en HTTP/1.1\r\n\
67 Host: api.forismatic.com\r\n\
68 \r\n";
69 char *resp_buf = NULL;
70 char *resp_ptr;
71 int resp_buf_len = 1024;
72 struct addrinfo hints;
73 struct addrinfo *res = NULL;
74 int sock = -1;
75 int to_sent, sent, bytes, resp_len;
76
77 resp_buf = rtos_malloc(resp_buf_len);
78 if (!resp_buf)
79 return -1;
80
81 hints.ai_family = AF_INET;
82 hints.ai_socktype = SOCK_STREAM;
83 hints.ai_protocol = 0;
84 hints.ai_flags = AI_NUMERICSERV;
85
86 if (getaddrinfo(host, "80", &hints, &res))
87 {
88 return -1;
89 }
90 else
91 {
92 // create socket
93 sock = socket(AF_INET, SOCK_STREAM, 0);
94 if (sock < 0)
95 goto error;
96
97 // and it to the host address
98 if (connect(sock, res->ai_addr, res->ai_addrlen) < 0)
99 goto error;
100
101 freeaddrinfo(res);
102 res = NULL;
103 }
104
105 // Send the query
106 sent = 0;
107 to_sent = strlen(query);
108 while (to_sent > sent)
109 {
110 bytes = send(sock, &query[sent], to_sent - sent, 0);
111 if (bytes < 0)
112 goto error;
113 sent += bytes;
114 }
115
116 // Receive the response
117 bytes = recv(sock, resp_buf, resp_buf_len, 0);
118 if (bytes < 0)
119 goto error;
120 resp_len = bytes;
121
122
123 // Extract quote from the response
124 resp_ptr = strstr(resp_buf, "\r\n");
125 if (!resp_ptr)
126 {
127 goto invalid_response;
128 }
129 else if (strncmp(&resp_ptr[-2], "OK", 2))
130 {
131 resp_ptr[0] = '\0';
132 TRACE_APP(ERR, "%s", TR_STR_8(resp_buf));
133 goto invalid_response;
134 }
135 else
136 {
137 char *quote_len_str;
138 int quote_len;
139 resp_ptr = strstr(resp_buf, "\r\n\r\n");
140 if (!resp_ptr)
141 goto invalid_response;
142
143 resp_ptr += 4;
144 quote_len_str = resp_ptr;
145 resp_ptr = strstr(resp_ptr, "\r\n");
146 resp_ptr[0] = '\0';
147 resp_ptr += 2;
148 quote_len = strtol(quote_len_str, NULL, 16);
149
150 // If quote is too long to fit in resp_buff, truncate it
151 if (quote_len - 1> resp_buf_len)
152 quote_len = resp_buf_len - 1;
153
154 resp_len -= (resp_ptr - resp_buf);
155 memmove(resp_buf, resp_ptr, resp_len);
156 quote_len -= resp_len;
157
158 if (quote_len > 0)
159 {
160 bytes = recv(sock, &resp_buf[resp_len], quote_len, MSG_DONTWAIT);
161 if (bytes >= 0)
162 resp_len += bytes;
163 }
164 resp_buf[resp_len] = '\0';
165
166 TRACE_APP(INF, "quote received: %s", TR_STR_8(resp_buf));
167 dbg("%s", resp_buf);
168 }
169
170 invalid_response:
171 // flush socket
172 while (bytes > 0)
173 bytes = recv(sock, resp_buf, resp_buf_len, MSG_DONTWAIT);
174
175 rtos_free(resp_buf);
176 close(sock);
177 return 0;
178
179 error:
180 TRACE_APP(ERR, "Connection to website failed");
181 if (resp_buf)
182 rtos_free(resp_buf);
183
184 if (sock > 0)
185 close(sock);
186
187 if (res)
188 freeaddrinfo(res);
189
190 return -1;
191 }
192 #endif /* TEST_CONNECT */
193
194 #if PLF_BLE_STACK
195 rtos_semaphore ble_smartconfig_sema;
196 static struct ble_smartconfig ble_smartconfig_result;
197 #define APP_SUCCESS_RSP ("successful")
198 #define APP_FAILED_RSP ("failed")
199 #define HOST_RSP ("disconnect")
200 #define HOST_RSP_LEN sizeof(HOST_RSP)
201
ble_smartconfig_ap_info_received(uint8_t * data,uint32_t length)202 void ble_smartconfig_ap_info_received(uint8_t* data, uint32_t length)
203 {
204 int i = 0;
205 uint8_t index = 0;
206 int ret = 0;
207 uint8_t rsp[20];
208
209 dbg("%s recv ap info %d\r\n", __func__, length);
210
211 for (i = 0; i < length; i++) {
212 if (data[i] == '\n') {
213 memcpy(&ble_smartconfig_result.ssid[0], &data[0], i);
214 index = i + 1;
215 break;
216 }
217 }
218
219 for (i = index; i < length; i++) {
220 memcpy(&ble_smartconfig_result.pwd[0], &data[index], length - index);
221 }
222
223 dbg("ssid %s\r\n", ble_smartconfig_result.ssid);
224 dbg("pwd %s\r\n", ble_smartconfig_result.pwd);
225 rtos_semaphore_signal(ble_smartconfig_sema, true);
226
227 return;
228 ret = wlan_start_sta((uint8_t *)ble_smartconfig_result.ssid, (uint8_t *)ble_smartconfig_result.pwd, 0);
229 if (ret == 0) {
230 dbg("connect success\r\n");
231 #if TEST_CONNECT
232 example_connect_website();
233 #endif
234 memcpy(&rsp[0], APP_SUCCESS_RSP, sizeof(APP_SUCCESS_RSP));
235 app_smartconfig_send_rsp(rsp, sizeof(APP_SUCCESS_RSP));
236 } else {
237 dbg("connect fail %d\r\n", ret);
238 memcpy(&rsp[0], APP_FAILED_RSP, sizeof(APP_FAILED_RSP));
239 app_smartconfig_send_rsp(rsp, sizeof(APP_FAILED_RSP));
240 }
241 }
242
ble_smartconfig_state_info_received(uint8_t * data,uint32_t length)243 void ble_smartconfig_state_info_received(uint8_t* data, uint32_t length)
244 {
245 if (memcmp(data, HOST_RSP, HOST_RSP_LEN) == 0) {
246 dbg("disconnect\r\n");
247 ble_task_deinit();
248 }
249 }
250
sta_do_connect()251 void sta_do_connect()
252 {
253 int ret = 0;
254 uint8_t rsp[20];
255 dbg("wlan_start_sta start\r\n");
256 ret = wlan_start_sta((uint8_t *)ble_smartconfig_result.ssid, (uint8_t *)ble_smartconfig_result.pwd, 0);
257 dbg("wlan_start_sta end\r\n");
258 if (ret == 0) {
259 dbg("connect success\r\n");
260 memcpy(&rsp[0], APP_SUCCESS_RSP, sizeof(APP_SUCCESS_RSP));
261 app_smartconfig_send_rsp(rsp, sizeof(APP_SUCCESS_RSP));
262 #if TEST_CONNECT
263 example_connect_website();
264 #endif
265 } else {
266 dbg("connect fail %d\r\n", ret);
267 memcpy(&rsp[0], APP_FAILED_RSP, sizeof(APP_FAILED_RSP));
268 app_smartconfig_send_rsp(rsp, sizeof(APP_FAILED_RSP));
269 }
270 }
271 #endif
272 /*
273 * Entry point of this example application
274 */
RTOS_TASK_FCT(blewifi_smartconfig_example_task)275 static RTOS_TASK_FCT(blewifi_smartconfig_example_task)
276 {
277 #if PLF_BLE_STACK
278 //ble_task_init();
279 app_smartconfig_register_ap_info_cb(ble_smartconfig_ap_info_received);
280 app_smartconfig_register_state_info_cb(ble_smartconfig_state_info_received);
281 int ret = rtos_semaphore_create(&ble_smartconfig_sema, 1, 0);
282 if (ret) {
283 dbg("sema create fail: %d\r\n", ret);
284 }
285 #endif
286 #if TEST_SCAN
287 int nb_res;
288 struct mac_scan_result result;
289 ipc_host_cntrl_start();
290
291 cntrl_link = fhost_cntrl_cfgrwnx_link_open();
292 if (cntrl_link == NULL) {
293 dbg(D_ERR "Failed to open link with control task\n");
294 ASSERT_ERR(0);
295 }
296 // Reset STA interface (this will end previous wpa_supplicant task)
297 if (fhost_set_vif_type(cntrl_link, 0, VIF_UNKNOWN, false) ||
298 fhost_set_vif_type(cntrl_link, 0, VIF_STA, false)) {
299
300 fhost_cntrl_cfgrwnx_link_close(cntrl_link);
301 return;
302 }
303
304 nb_res = fhost_scan(cntrl_link, 0, NULL);
305 dbg("Got %d scan results\n", nb_res);
306
307 nb_res = 0;
308 while(fhost_get_scan_results(cntrl_link, nb_res++, 1, &result)) {
309 result.ssid.array[result.ssid.length] = '\0'; // set ssid string ending
310 dbg("(%3d dBm) CH=%3d BSSID=%02x:%02x:%02x:%02x:%02x:%02x SSID=%s\n",
311 (int8_t)result.rssi, phy_freq_to_channel(result.chan->band, result.chan->freq),
312 ((uint8_t *)result.bssid.array)[0], ((uint8_t *)result.bssid.array)[1],
313 ((uint8_t *)result.bssid.array)[2], ((uint8_t *)result.bssid.array)[3],
314 ((uint8_t *)result.bssid.array)[4], ((uint8_t *)result.bssid.array)[5],
315 (char *)result.ssid.array);
316 }
317
318 fhost_cntrl_cfgrwnx_link_close(cntrl_link);
319 #endif
320 #if PLF_BLE_STACK
321 dbg("wait for connect...smartconfig\r\n");
322 rtos_semaphore_wait(ble_smartconfig_sema, -1);
323 sta_do_connect();
324 #endif
325 while (1) {
326 }
327 //#else
328 //#error "invalid test"
329 //#endif
330
331 rtos_task_delete(NULL);
332 }
333
334 /******************************************************************************
335 * Fhost FW interfaces:
336 * These are the functions required by the fhost FW that are specific to the
337 * final application.
338 *****************************************************************************/
339 /*
340 * fhost_application_init: Must initialize the minimum for the application to
341 * start.
342 * In this example only create a new task with the entry point set to the
343 * 'fhost_example_task'. The rest on the initialization will be done in this
344 * function.
345 */
346 #if CFG_APP_BLESMARTCONFIGWIFI
fhost_application_init(void)347 int fhost_application_init(void)
348 {
349 if (rtos_task_create(blewifi_smartconfig_example_task, "Example task", APPLICATION_TASK,
350 2048, NULL, RTOS_TASK_PRIORITY(1), NULL))
351 return 1;
352
353 return 0;
354 }
355 #endif
356