feat(smartconfig_ack): Add smartconfig_ack components

This commit is contained in:
Zhang Jun Hao
2018-07-13 11:14:56 +08:00
parent e1115626bb
commit 6461d43d37
5 changed files with 354 additions and 168 deletions

View File

@ -0,0 +1,121 @@
// 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.
#ifndef __ESP_SMARTCONFIG_H__
#define __ESP_SMARTCONFIG_H__
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
SC_STATUS_WAIT = 0, /**< Waiting to start connect */
SC_STATUS_FIND_CHANNEL, /**< Finding target channel */
SC_STATUS_GETTING_SSID_PSWD, /**< Getting SSID and password of target AP */
SC_STATUS_LINK, /**< Connecting to target AP */
SC_STATUS_LINK_OVER, /**< Connected to AP successfully */
} smartconfig_status_t;
typedef enum {
SC_TYPE_ESPTOUCH = 0, /**< protocol: ESPTouch */
SC_TYPE_AIRKISS, /**< protocol: AirKiss */
SC_TYPE_ESPTOUCH_AIRKISS, /**< protocol: ESPTouch and AirKiss */
} smartconfig_type_t;
/**
* @brief The callback of SmartConfig, executed when smart-config status changed.
*
* @param status Status of SmartConfig:
* - SC_STATUS_GETTING_SSID_PSWD : pdata is a pointer of smartconfig_type_t, means config type.
* - SC_STATUS_LINK : pdata is a pointer of struct station_config.
* - SC_STATUS_LINK_OVER : pdata is a pointer of phone's IP address(4 bytes) if pdata unequal NULL.
* - otherwise : parameter void *pdata is NULL.
* @param pdata According to the different status have different values.
*
*/
typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata);
/**
* @brief Get the version of SmartConfig.
*
* @return
* - SmartConfig version const char.
*/
const char *esp_smartconfig_get_version(void);
/**
* @brief Start SmartConfig, config ESP device to connect AP. You need to broadcast information by phone APP.
* Device sniffer special packets from the air that containing SSID and password of target AP.
*
* @attention 1. This API can be called in station or softAP-station mode.
* @attention 2. Can not call esp_smartconfig_start twice before it finish, please call
* esp_smartconfig_stop first.
*
* @param cb SmartConfig callback function.
* @param ... log 1: UART output logs; 0: UART only outputs the result.
*
* @return
* - ESP_OK: succeed
* - others: fail
*/
esp_err_t esp_smartconfig_start(sc_callback_t cb, ...);
/**
* @brief Stop SmartConfig, free the buffer taken by esp_smartconfig_start.
*
* @attention Whether connect to AP succeed or not, this API should be called to free
* memory taken by smartconfig_start.
*
* @return
* - ESP_OK: succeed
* - others: fail
*/
esp_err_t esp_smartconfig_stop(void);
/**
* @brief Set timeout of SmartConfig process.
*
* @attention Timing starts from SC_STATUS_FIND_CHANNEL status. SmartConfig will restart if timeout.
*
* @param time_s range 15s~255s, offset:45s.
*
* @return
* - ESP_OK: succeed
* - others: fail
*/
esp_err_t esptouch_set_timeout(uint8_t time_s);
/**
* @brief Set protocol type of SmartConfig.
*
* @attention If users need to set the SmartConfig type, please set it before calling
* esp_smartconfig_start.
*
* @param type Choose from the smartconfig_type_t.
*
* @return
* - ESP_OK: succeed
* - others: fail
*/
esp_err_t esp_smartconfig_set_type(smartconfig_type_t type);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,168 +0,0 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __SMARTCONFIG_H__
#define __SMARTCONFIG_H__
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup WiFi_APIs WiFi Related APIs
* @brief WiFi APIs
*/
/** @addtogroup WiFi_APIs
* @{
*/
/** \defgroup Smartconfig_APIs Smartconfig APIs
* @brief SmartConfig APIs
*
* SmartConfig can only be enabled in station only mode.
* Please make sure the target AP is enabled before enable SmartConfig.
*
*/
/** @addtogroup Smartconfig_APIs
* @{
*/
typedef enum {
SC_STATUS_WAIT = 0, /**< waiting, do not start connection in this phase */
SC_STATUS_FIND_CHANNEL, /**< find target channel, start connection by APP in this phase */
SC_STATUS_GETTING_SSID_PSWD, /**< getting SSID and password of target AP */
SC_STATUS_LINK, /**< connecting to target AP */
SC_STATUS_LINK_OVER, /**< got IP, connect to AP successfully */
} sc_status;
typedef enum {
SC_TYPE_ESPTOUCH = 0, /**< protocol: ESPTouch */
SC_TYPE_AIRKISS, /**< protocol: AirKiss */
SC_TYPE_ESPTOUCH_AIRKISS, /**< protocol: ESPTouch and AirKiss */
} sc_type;
/**
* @brief The callback of SmartConfig, executed when smart-config status changed.
*
* @param sc_status status : status of SmartConfig:
* - if status == SC_STATUS_GETTING_SSID_PSWD, parameter void *pdata is a pointer
of sc_type, means SmartConfig type: AirKiss or ESP-TOUCH.
* - if status == SC_STATUS_LINK, parameter void *pdata is a pointer of struct station_config;
* - if status == SC_STATUS_LINK_OVER, parameter void *pdata is a pointer of mobile
* phone's IP address, 4 bytes. This is only available in ESPTOUCH, otherwise,
* it is NULL.
* - otherwise, parameter void *pdata is NULL.
* @param void *pdata : data of SmartConfig
*
* @return null
*/
typedef void (*sc_callback_t)(sc_status status, void *pdata);
/**
* @brief Get the version of SmartConfig.
*
* @param null
*
* @return SmartConfig version
*/
const char *smartconfig_get_version(void);
/**
* @brief Start SmartConfig mode.
*
* Start SmartConfig mode, to connect ESP8266 station to AP, by sniffing
* for special packets from the air, containing SSID and password of desired AP.
* You need to broadcast the SSID and password (e.g. from mobile device or computer)
* with the SSID and password encoded.
*
* @attention 1. This api can only be called in station mode.
* @attention 2. During SmartConfig, ESP8266 station and soft-AP are disabled.
* @attention 3. Can not call smartconfig_start twice before it finish, please call
* smartconfig_stop first.
* @attention 4. Don't call any other APIs during SmartConfig, please call smartconfig_stop first.
*
* @param sc_callback_t cb : SmartConfig callback; executed when SmartConfig status changed;
* @param uint8 log : 1, UART output logs; otherwise, UART only outputs the result.
*
* @return true : succeed
* @return false : fail
*/
bool smartconfig_start(sc_callback_t cb, ...);
/**
* @brief Stop SmartConfig, free the buffer taken by smartconfig_start.
*
* @attention Whether connect to AP succeed or not, this API should be called to free
* memory taken by smartconfig_start.
*
* @param null
*
* @return true : succeed
* @return false : fail
*/
bool smartconfig_stop(void);
/**
* @brief Set timeout of SmartConfig.
*
* @attention SmartConfig timeout start at SC_STATUS_FIND_CHANNEL, SmartConfig will
* restart if timeout.
*
* @param uint8 time_s : range 15s~255s, offset:45s.
*
* @return true : succeed
* @return false : fail
*/
bool esptouch_set_timeout(uint8_t time_s);
/**
* @brief Set protocol type of SmartConfig.
*
* @attention If users need to set the SmartConfig type, please set it before calling
* smartconfig_start.
*
* @param sc_type type : AirKiss, ESP-TOUCH or both.
*
* @return true : succeed
* @return false : fail
*/
bool smartconfig_set_type(sc_type type);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,2 @@
#
# Component Makefile

View File

@ -0,0 +1,74 @@
// 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.
#ifndef SMARTCONFIG_ACK_H
#define SMARTCONFIG_ACK_H
#ifdef __cplusplus
extern "C" {
#endif
#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_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 30 /*!< Maximum count of sending smartconfig ACK */
/**
* @brief Smartconfig ACK type.
*/
typedef enum {
SC_ACK_TYPE_ESPTOUCH = 0, /*!< ESP touch ACK type */
SC_ACK_TYPE_AIRKISS, /*!< Airkiss ACK type */
} sc_ack_type_t;
/**
* @brief Smartconfig parameters passed to sc_ack_send call.
*/
typedef struct sc_ack {
sc_ack_type_t type; /*!< Smartconfig ACK type */
uint8_t *link_flag; /*!< Smartconfig link flag */
sc_callback_t cb; /*!< Smartconfig callback function */
struct {
uint8_t token; /*!< Smartconfig token to be sent */
uint8_t mac[6]; /*!< MAC address of station */
uint8_t ip[4]; /*!< IP address of cellphone */
} ctx;
} sc_ack_t;
/**
* @brief Send smartconfig ACK to cellphone.
*
* @attention The API is only used in libsmartconfig.a.
*
* @param param: smartconfig parameters;
*/
void sc_ack_send(sc_ack_t *param);
/**
* @brief Stop sending smartconfig ACK to cellphone.
*
* @attention The API is only used in libsmartconfig.a.
*/
void sc_ack_send_stop(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,157 @@
// 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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/sockets.h"
#include "tcpip_adapter.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_smartconfig.h"
#include "smartconfig_ack.h"
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 = ack->ctx.ip;
int remote_port = (ack->type == SC_ACK_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_ACK_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;
server_addr.sin_addr.s_addr = inet_addr((const char*)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_ACK_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));
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) {
if (ack->link_flag) {
*ack->link_flag = 1;
}
if (ack->cb) {
ack->cb(SC_STATUS_LINK_OVER, remote_ip);
}
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)(100 / portTICK_RATE_MS));
}
}
_end:
if ((send_sock >= LWIP_SOCKET_OFFSET) && (send_sock <= (FD_SETSIZE - 1))) {
close(send_sock);
}
free(ack);
vTaskDelete(NULL);
}
void sc_ack_send(sc_ack_t *param)
{
sc_ack_t *ack = NULL;
if (param == NULL) {
ESP_LOGE(TAG, "Smart config ack parameter error");
return;
}
ack = malloc(sizeof(sc_ack_t));
if (ack == NULL) {
ESP_LOGE(TAG, "Smart config ack parameter malloc fail");
return;
}
memcpy(ack, param, sizeof(sc_ack_t));
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);
}
}
void sc_ack_send_stop(void)
{
s_sc_ack_send = false;
}