feat(smartconfig): refactor smartconfig callback to use esp event

Consistent with esp-idf(branch: release/v4.2, commit id: c5bb6c4)
This commit is contained in:
chenwen
2020-10-20 16:57:54 +08:00
parent dda5062c80
commit d3a974f6f2
13 changed files with 339 additions and 296 deletions

View File

@ -0,0 +1,83 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <string.h>
#include "esp_log.h"
#include "esp_event_base.h"
#include "esp_private/wifi.h"
#include "esp_smartconfig.h"
#include "smartconfig_ack.h"
/* Smartconfig events definitions */
ESP_EVENT_DEFINE_BASE(SC_EVENT);
static const char* TAG = "smartconfig";
static void handler_got_ssid_passwd(void* arg, esp_event_base_t base, int32_t event_id, void* data)
{
smartconfig_event_got_ssid_pswd_t* evt = (smartconfig_event_got_ssid_pswd_t*)data;
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
uint8_t cellphone_ip[4];
esp_err_t err = ESP_OK;
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
memcpy(cellphone_ip, evt->cellphone_ip, sizeof(evt->cellphone_ip));
ESP_LOGD(TAG, "SSID:%s", ssid);
ESP_LOGD(TAG, "PASSWORD:%s", password);
ESP_LOGD(TAG, "Phone ip: %d.%d.%d.%d\n", cellphone_ip[0], cellphone_ip[1], cellphone_ip[2], cellphone_ip[3]);
err = sc_send_ack_start(evt->type, evt->token, evt->cellphone_ip);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Send smartconfig ACK error: %d", err);
}
}
esp_err_t esp_smartconfig_start(const smartconfig_start_config_t* config)
{
esp_err_t err = ESP_OK;
err = esp_event_handler_register(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd, NULL);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Register smartconfig default event handler fail!");
return err;
}
err = esp_smartconfig_internal_start(config);
if (err != ESP_OK) {
esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd);
}
return err;
}
esp_err_t esp_smartconfig_stop(void)
{
esp_err_t err = ESP_OK;
err = esp_smartconfig_internal_stop();
if (err == ESP_OK) {
sc_send_ack_stop();
esp_event_handler_unregister(SC_EVENT, SC_EVENT_GOT_SSID_PSWD, handler_got_ssid_passwd);
}
return err;
}

View File

@ -0,0 +1,221 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* After station connects to AP and gets IP address by smartconfig,
* it will use UDP to send 'ACK' to cellphone.
*/
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/socket.h>
#include <netdb.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tcpip_adapter.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_smartconfig.h"
#include "smartconfig_ack.h"
#define SC_ACK_TASK_PRIORITY 2 /*!< Priority of sending smartconfig ACK task */
#define SC_ACK_TASK_STACK_SIZE 2048 /*!< Stack size of sending smartconfig ACK task */
#define SC_ACK_TOUCH_SERVER_PORT 18266 /*!< ESP touch UDP port of server on cellphone */
#define SC_ACK_AIRKISS_SERVER_PORT 10000 /*!< Airkiss UDP port of server on cellphone */
#define SC_ACK_AIRKISS_DEVICE_PORT 10001 /*!< Airkiss UDP port of server on device */
#define SC_ACK_AIRKISS_TIMEOUT 1500 /*!< Airkiss read data timout millisecond */
#define SC_ACK_TOUCH_LEN 11 /*!< Length of ESP touch ACK context */
#define SC_ACK_AIRKISS_LEN 7 /*!< Length of Airkiss ACK context */
#define SC_ACK_MAX_COUNT 60 /*!< Maximum count of sending smartconfig ACK */
/**
* @brief Smartconfig parameters passed to sc_ack_send call.
*/
typedef struct sc_ack {
smartconfig_type_t type; /*!< Smartconfig type(ESPTouch or AirKiss) */
struct {
uint8_t token; /*!< Smartconfig token from the cellphone */
uint8_t mac[6]; /*!< MAC address of station */
uint8_t ip[4]; /*!< IP address of cellphone */
} ctx;
} sc_ack_t;
static const char* TAG = "smartconfig";
/* Flag to indicate sending smartconfig ACK or not. */
static bool s_sc_ack_send = false;
static int sc_ack_send_get_errno(int fd)
{
int sock_errno = 0;
u32_t optlen = sizeof(sock_errno);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
return sock_errno;
}
static void sc_ack_send_task(void* pvParameters)
{
sc_ack_t* ack = (sc_ack_t*)pvParameters;
tcpip_adapter_ip_info_t local_ip;
uint8_t remote_ip[4];
memset(remote_ip, 0xFF, sizeof(remote_ip));
int remote_port = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_SERVER_PORT : SC_ACK_AIRKISS_SERVER_PORT;
struct sockaddr_in server_addr;
socklen_t sin_size = sizeof(server_addr);
int send_sock = -1;
int optval = 1;
int sendlen;
int ack_len = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN;
uint8_t packet_count = 1;
int err;
int ret;
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
memcpy(&server_addr.sin_addr.s_addr, remote_ip, sizeof(remote_ip));
server_addr.sin_port = htons(remote_port);
esp_wifi_get_mac(WIFI_IF_STA, ack->ctx.mac);
vTaskDelay(200 / portTICK_RATE_MS);
while (s_sc_ack_send) {
/* Get local IP address of station */
ret = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &local_ip);
if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) {
/* If ESP touch, smartconfig ACK contains local IP address. */
if (ack->type == SC_TYPE_ESPTOUCH) {
memcpy(ack->ctx.ip, &local_ip.ip.addr, 4);
}
/* Create UDP socket. */
send_sock = socket(AF_INET, SOCK_DGRAM, 0);
if ((send_sock < LWIP_SOCKET_OFFSET) || (send_sock > (FD_SETSIZE - 1))) {
ESP_LOGE(TAG, "Creat udp socket failed");
goto _end;
}
setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optval, sizeof(int));
if (ack->type == SC_TYPE_AIRKISS) {
char data = 0;
struct sockaddr_in local_addr, from;
socklen_t sockadd_len = sizeof(struct sockaddr);
struct timeval timeout = {
SC_ACK_AIRKISS_TIMEOUT / 1000,
SC_ACK_AIRKISS_TIMEOUT % 1000 * 1000
};
bzero(&local_addr, sizeof(struct sockaddr_in));
bzero(&from, sizeof(struct sockaddr_in));
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = INADDR_ANY;
local_addr.sin_port = htons(SC_ACK_AIRKISS_DEVICE_PORT);
bind(send_sock, (struct sockaddr*)&local_addr, sockadd_len);
setsockopt(send_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
recvfrom(send_sock, &data, 1, 0, (struct sockaddr*)&from, &sockadd_len);
if (from.sin_addr.s_addr != INADDR_ANY) {
memcpy(remote_ip, &from.sin_addr, 4);
server_addr.sin_addr.s_addr = from.sin_addr.s_addr;
} else {
goto _end;
}
}
while (s_sc_ack_send) {
/* Send smartconfig ACK every 100ms. */
vTaskDelay(100 / portTICK_RATE_MS);
sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size);
if (sendlen > 0) {
/* Totally send 30 smartconfig ACKs. Then smartconfig is successful. */
if (packet_count++ >= SC_ACK_MAX_COUNT) {
esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY);
goto _end;
}
} else {
err = sc_ack_send_get_errno(send_sock);
if (err == ENOMEM || err == EAGAIN) {
ESP_LOGD(TAG, "send failed, errno %d", err);
continue;
}
ESP_LOGE(TAG, "send failed, errno %d", err);
goto _end;
}
}
} else {
vTaskDelay((portTickType)(200 / portTICK_RATE_MS));
}
}
_end:
if ((send_sock >= LWIP_SOCKET_OFFSET) && (send_sock <= (FD_SETSIZE - 1))) {
close(send_sock);
}
free(ack);
vTaskDelete(NULL);
}
esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t* cellphone_ip)
{
sc_ack_t* ack = NULL;
if (cellphone_ip == NULL) {
ESP_LOGE(TAG, "Cellphone IP address is NULL");
return ESP_ERR_INVALID_ARG;
}
ack = malloc(sizeof(sc_ack_t));
if (ack == NULL) {
ESP_LOGE(TAG, "ACK parameter malloc fail");
return ESP_ERR_NO_MEM;
}
ack->type = type;
ack->ctx.token = token;
memcpy(ack->ctx.ip, cellphone_ip, 4);
s_sc_ack_send = true;
if (xTaskCreate(sc_ack_send_task, "sc_ack_send_task", SC_ACK_TASK_STACK_SIZE, ack, SC_ACK_TASK_PRIORITY, NULL) != pdPASS) {
ESP_LOGE(TAG, "Create sending smartconfig ACK task fail");
free(ack);
return ESP_ERR_NO_MEM;
}
return ESP_OK;
}
void sc_send_ack_stop(void)
{
s_sc_ack_send = false;
}