• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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