Add Wechat APP example

- Split process to core 1
- Use BluFi
- Use MDNS
- Manage Face id with name
pull/55/head
XiaochaoGONG 2019-03-20 19:52:36 +08:00
parent 123ce3b040
commit e26281edbc
21 changed files with 2784 additions and 2 deletions

@ -1 +1 @@
Subproject commit 07e9bab3fae52c927991bf884a62534555b48260
Subproject commit b45ecf2e3df66e7536b6ae470cfa65e099c2ee22

@ -1 +1 @@
Subproject commit 165a47fe6a7c76daf23fa40512ae4a90a994e938
Subproject commit 113629b1cf8769f65c09db0c3577a597e652860b

View File

@ -0,0 +1,12 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := recognition_wechat
SOLUTION_PATH ?= $(abspath $(shell pwd))/../../..
include $(SOLUTION_PATH)/components/component_conf.mk
include $(IDF_PATH)/make/project.mk

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,108 @@
// Copyright 2015-2016 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 _WECHAT_BLUFI_H_
#define _WECHAT_BLUFI_H_
#include "esp_wifi.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
/* nvs typedef */
#define USERDATANAMESPACE "userdata"
#define NVS_KEY_WIFI_SSID_PASS "ssid_pass"
#define NVS_KEY_RESTART_COUNT "restart_cou"
#define WIFI_SSID_PASS_SIZE (32+64)
#define BLUFI_EXAMPLE_TAG "ESP32_BLUFI"
#define BLUFI_DEVICE_NAME "BLUFI_DEVICE_ESP_WHO1"
#define DEFAULT_SSID "ESP_Who_Wechat"
#define DEFAULT_PWD "12345678"
#define MAX_STA_CONN 2
#define NOTICE_MDNS_HOSTNAME "notice-mDNS"
#define NOTICE_MDNS_INSTANCE "notice with ESP-WHO"
#define NOTICE_MDNS_SERVICE_TYPE "_notice_service"
#define NOTICE_MDNS_PROTO "_tcp"
#define TCP_DEFAULT_PORT 8899
#define UDP_NOTICE_PORT 7899
#define DEFAULT_PKTSIZE 135
#define WIFI_IP4_CONNECTED_BIT BIT0
#define WIFI_IP6_CONNECTED_BIT BIT1
#define ESPTOUCH_DONE_BIT BIT2
#define WIFI_LIST_NUM 10
#define RESTART_TIMEOUT_MS (5000)
#define WIFI_CONFIG_TIMEOUT (3 * 60 * 1000)
#define NOTICE_UDP_BUF_SIZE (64)
#define NOTICE_UDP_RETRY_COUNT (3)
#define BLUFI_INFO(fmt, ...) ESP_LOGI(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__)
#define BLUFI_ERROR(fmt, ...) ESP_LOGE(BLUFI_EXAMPLE_TAG, fmt, ##__VA_ARGS__)
/**
* @brief wifi_info_erase
*/
esp_err_t wifi_info_erase(const char *key);
/**
* @brief load_info_nvs
*/
esp_err_t load_info_nvs(char *key, void *value, size_t len);
/**
* @brief save_info_nvs
*/
esp_err_t save_info_nvs(char *key, void *value, size_t len);
/**
* @brief wifi mdns udp
*/
void blufi_main();
/**
* @brief wifi initialise for Software AP + Sta
*/
void wifi_init_ap_sta();
/**
* @brief IP
*/
void wait_net_connected();
/**
* @brief
*/
void enter_blufi_config_wifi();
void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free);
int blufi_aes_encrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len);
int blufi_security_init(void);
void blufi_security_deinit(void);
#endif

View File

@ -0,0 +1,957 @@
// Copyright 2015-2016 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.
/* C Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* FreeRTOS Includes */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
/* ESP32 Includes */
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "nvs_flash.h"
#include "mdns.h"
/* Bluetooth Includes */
#include "esp_blufi_api.h"
#include "esp_bt_defs.h"
#include "esp_gap_ble_api.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
/* wechat Includes */
#include "wechat_blufi.h"
static uint8_t ble_service_uuid128[32] = {
/* LSB <--------------------------------------------------------------------------------> MSB */
//first uuid, 16bit, [12],[13] is the value
0xfb,
0x34,
0x9b,
0x5f,
0x80,
0x00,
0x00,
0x80,
0x00,
0x10,
0x00,
0x00,
0xFF,
0xFF,
0x00,
0x00,
};
//static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56};
static esp_ble_adv_data_t ble_adv_data = {
.set_scan_rsp = false,
.include_name = true,
.include_txpower = true,
.min_interval = 0x100,
.max_interval = 0x100,
.appearance = 0x00,
.manufacturer_len = 0,
.p_manufacturer_data = NULL,
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = 16,
.p_service_uuid = ble_service_uuid128,
.flag = 0x6,
};
static esp_ble_adv_params_t ble_adv_params = {
.adv_int_min = 0x100,
.adv_int_max = 0x100,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
//.peer_addr =
//.peer_addr_type =
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};
wifi_config_t sta_config = {0};
wifi_config_t ap_config = {0};
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
const int CONNECTED_BIT = BIT0;
/* store the station info for send back to phone */
static bool gl_sta_connected = false;
static uint8_t gl_sta_bssid[6];
static uint8_t gl_sta_ssid[32];
static int gl_sta_ssid_len;
/* connect infor*/
static uint8_t server_if;
static uint16_t conn_id;
static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
void enter_blufi_config_wifi();
void wifi_connect_succuess();
/**
* @brief wifi_info_erase
*/
esp_err_t wifi_info_erase(const char *key)
{
esp_err_t ret = ESP_OK;
nvs_handle handle = 0;
ret = nvs_open(USERDATANAMESPACE, NVS_READWRITE, &handle);
if (ret != ESP_OK) {
ESP_LOGE("nvs", "unable to open NVS namespace, errcode is %d\n", ret);
return ESP_FAIL;
}
/**
* @brief If key is USERDATANAMESPACE, erase all info in USERDATANAMESPACE
*/
if (!strcmp(key, USERDATANAMESPACE)) {
ret = nvs_erase_all(handle);
} else {
ret = nvs_erase_key(handle, key);
}
nvs_commit(handle);
if (handle > 0) {
nvs_close(handle);
}
return ESP_OK;
}
/**
* @brief load_info_nvs
*/
esp_err_t load_info_nvs(char *key, void *value, size_t len)
{
esp_err_t err;
nvs_handle handle = 0;
size_t length = len;
err = nvs_open(USERDATANAMESPACE, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE("nvs", "unable to open NVS namespace, errcode is %d\n", err);
return ESP_FAIL;
}
if (value == NULL) {
ESP_LOGE("nvs", "value NVS_ERR_PARAMETER_NULL\n");
return ESP_FAIL;
}
err = nvs_get_blob(handle, key, value, &length);
if (err != ESP_OK) {
ESP_LOGE("load_info_nvs", "load_info_nvs\n");
return err;
}
if (handle > 0) {
nvs_close(handle);
}
return ESP_OK;
}
/**
* @brief save_info_nvs
*/
esp_err_t save_info_nvs(char *key, void *value, size_t len)
{
esp_err_t err;
nvs_handle handle = 0;
size_t length = len;
err = nvs_open(USERDATANAMESPACE, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE("nvs", "unable to open NVS namespace, errcode is %d\n", err);
return ESP_FAIL;
}
if (value == NULL) {
ESP_LOGE("nvs", "value NVS_ERR_PARAMETER_NULL\n");
return ESP_FAIL;
}
err = nvs_set_blob(handle, key, value, length);
if (err == ESP_OK) {
ESP_LOGI("save_info_nvs", "save_info_nvs\n");
}
nvs_commit(handle);
if (handle > 0) {
nvs_close(handle);
}
return err;
}
/**
* @brief IP
*/
void wait_net_connected()
{
xEventGroupWaitBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT, false, true, portMAX_DELAY);
// xEventGroupWaitBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT | WIFI_IP6_CONNECTED_BIT, false, true, portMAX_DELAY);
}
/**
* @brief wifi
*/
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
wifi_mode_t mode;
static uint8_t connect_try_count = 0;
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
ESP_LOGI("event_handler", "SYSTEM_EVENT_STA_START\n");
if (strlen((char *)sta_config.sta.ssid) != 0 && strlen((char *)sta_config.sta.password) != 0) {
ESP_ERROR_CHECK(esp_wifi_connect());
}
break;
case SYSTEM_EVENT_STA_STOP:
ESP_LOGI("event_handler", "SYSTEM_EVENT_STA_STOP\n");
break;
case SYSTEM_EVENT_STA_CONNECTED:
ESP_LOGI("event_handler", "SYSTEM_EVENT_STA_CONNECTED\n");
gl_sta_connected = true;
connect_try_count = 0;
memcpy(gl_sta_bssid, event->event_info.connected.bssid, 6);
memcpy(gl_sta_ssid, event->event_info.connected.ssid, event->event_info.connected.ssid_len);
gl_sta_ssid_len = event->event_info.connected.ssid_len;
save_info_nvs(NVS_KEY_WIFI_SSID_PASS, (void *)(sta_config.sta.ssid), WIFI_SSID_PASS_SIZE);
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGI("event_handler", "SYSTEM_EVENT_STA_DISCONNECTED\n");
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
if (connect_try_count++ > 5 && connect_try_count < 10) {
// connect_try_count = 0;
esp_wifi_get_mode(&mode);
if (esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL) != ESP_OK) {
ESP_LOGI("blufi","esp_fail\n");
}
} else {
gl_sta_connected = false;
memset(gl_sta_ssid, 0, 32);
memset(gl_sta_bssid, 0, 6);
gl_sta_ssid_len = 0;
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT | WIFI_IP6_CONNECTED_BIT);
}
break;
case SYSTEM_EVENT_STA_GOT_IP: {
esp_blufi_extra_info_t info;
ESP_LOGI("event_handler", "SYSTEM_EVENT_STA_GOT_IP\n");
ESP_LOGI("event_handler", "got ip4:%s\n", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
xEventGroupSetBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT);
esp_wifi_get_mode(&mode);
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
wifi_connect_succuess();
break;
}
case SYSTEM_EVENT_AP_STA_GOT_IP6:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_STA_GOT_IP6\n");
ESP_LOGI("event_handler", "got ip6:%s\n", ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip));
xEventGroupSetBits(wifi_event_group, WIFI_IP6_CONNECTED_BIT);
break;
case SYSTEM_EVENT_AP_START:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_START\n");
esp_wifi_get_mode(&mode);
/* TODO: get config or information of softap, then set to report extra_info */
if (gl_sta_connected) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, NULL);
} else {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL);
}
break;
case SYSTEM_EVENT_AP_STOP:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_STOP\n");
break;
case SYSTEM_EVENT_AP_STAIPASSIGNED:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_STAIPASSIGNED\n");
break;
case SYSTEM_EVENT_AP_STACONNECTED:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_STACONNECTED\n");
ESP_LOGI("event_handler", "station:" MACSTR " join,AID=%d\n",
MAC2STR(event->event_info.sta_connected.mac),
event->event_info.sta_connected.aid);
xEventGroupSetBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT);
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
ESP_LOGI("event_handler", "SYSTEM_EVENT_AP_STADISCONNECTED\n");
ESP_LOGI("event_handler", "station:" MACSTR "leave,AID=%d\n",
MAC2STR(event->event_info.sta_disconnected.mac),
event->event_info.sta_disconnected.aid);
xEventGroupClearBits(wifi_event_group, WIFI_IP4_CONNECTED_BIT);
break;
case SYSTEM_EVENT_SCAN_DONE: {
uint16_t apCount = 0;
esp_wifi_scan_get_ap_num(&apCount);
if (apCount == 0) {
BLUFI_INFO("Nothing AP found");
break;
}
wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
if (!ap_list) {
BLUFI_ERROR("malloc error, ap_list is NULL");
break;
}
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
esp_blufi_ap_record_t *blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));
if (!blufi_ap_list) {
if (ap_list) {
free(ap_list);
}
BLUFI_ERROR("malloc error, blufi_ap_list is NULL");
break;
}
for (int i = 0; i < apCount; ++i) {
blufi_ap_list[i].rssi = ap_list[i].rssi;
memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
}
esp_blufi_send_wifi_list(apCount, blufi_ap_list);
esp_wifi_scan_stop();
free(ap_list);
free(blufi_ap_list);
break;
}
default:
break;
}
#ifdef USE_MDNS
mdns_handle_system_event(ctx, event);
#endif
return ESP_OK;
}
// wifi initialise for Software AP + Sta
void wifi_init_ap_sta()
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t ap_wifi_config = {
.ap = {
.ssid = DEFAULT_SSID,
.ssid_len = 0,
.max_connection = MAX_STA_CONN,
.password = DEFAULT_PWD,
.authmode = WIFI_AUTH_WPA_WPA2_PSK
},
};
// memcpy(sta_config.sta.ssid, sta_wifi_config.sta.ssid, WIFI_SSID_MAX_SIZE);
// memcpy(sta_config.sta.password, sta_wifi_config.sta.password, WIFI_SSID_PASS_SIZE);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_APSTA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &ap_wifi_config));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &sta_config));
ESP_ERROR_CHECK(esp_wifi_start());
if (strlen((char *)sta_config.sta.ssid) == 0 && strlen((char *)sta_config.sta.password) == 0) {
enter_blufi_config_wifi();
}
ESP_LOGI("wifi_init_ap_sta", "AP SSID:%s, password:%s; Station SSID:%s, pass:%s\n",
DEFAULT_SSID, DEFAULT_PWD, sta_config.sta.ssid, sta_config.sta.password);
}
/**
* @brief blufi
*/
static esp_blufi_callbacks_t blufi_callbacks = {
.event_cb = blufi_event_callback,
.negotiate_data_handler = blufi_dh_negotiate_data_handler,
.encrypt_func = blufi_aes_encrypt,
.decrypt_func = blufi_aes_decrypt,
.checksum_func = blufi_crc_checksum,
};
/**
* @brief blufi
*/
static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
/* actually, should post to blufi_task handle the procedure,
* now, as a example, we do it more simply */
switch (event) {
case ESP_BLUFI_EVENT_INIT_FINISH:
BLUFI_INFO("BLUFI init finish\n");
esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);
esp_ble_gap_config_adv_data(&ble_adv_data);
break;
case ESP_BLUFI_EVENT_DEINIT_FINISH:
BLUFI_INFO("BLUFI deinit finish\n");
break;
case ESP_BLUFI_EVENT_BLE_CONNECT:
BLUFI_INFO("BLUFI ble connect\n");
server_if = param->connect.server_if;
conn_id = param->connect.conn_id;
esp_ble_gap_stop_advertising();
blufi_security_init();
break;
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
BLUFI_INFO("BLUFI ble disconnect\n");
vTaskDelay(200 / portTICK_PERIOD_MS);
blufi_security_deinit();
esp_ble_gap_start_advertising(&ble_adv_params);
break;
case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
ESP_ERROR_CHECK(esp_wifi_set_mode(param->wifi_mode.op_mode));
break;
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
BLUFI_INFO("BLUFI requset wifi connect to AP\n");
/* there is no wifi callback when the device has already connected to this wifi
so disconnect wifi before connection.
*/
esp_wifi_disconnect();
esp_wifi_connect();
break;
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
BLUFI_INFO("BLUFI requset wifi disconnect from AP\n");
esp_wifi_disconnect();
break;
case ESP_BLUFI_EVENT_REPORT_ERROR:
BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state);
esp_blufi_send_error_info(param->report_error.state);
break;
case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {
wifi_mode_t mode;
esp_blufi_extra_info_t info;
esp_wifi_get_mode(&mode);
if (gl_sta_connected) {
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
} else {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL);
}
BLUFI_INFO("BLUFI get wifi status from AP\n");
break;
}
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
BLUFI_INFO("blufi close a gatt connection");
vTaskDelay(200 / portTICK_PERIOD_MS);
esp_blufi_close(server_if, conn_id);
break;
case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
BLUFI_INFO("ESP_BLUFI_EVENT_DEAUTHENTICATE_STA\n");
/* TODO */
break;
case ESP_BLUFI_EVENT_RECV_STA_BSSID:
memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
sta_config.sta.bssid_set = 1;
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_SSID:
strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len);
ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0';
ap_config.ap.ssid_len = param->softap_ssid.ssid_len;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len);
ap_config.ap.password[param->softap_passwd.passwd_len] = '\0';
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
if (param->softap_max_conn_num.max_conn_num > 4) {
return;
}
ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) {
return;
}
ap_config.ap.authmode = param->softap_auth_mode.auth_mode;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
if (param->softap_channel.channel > 13) {
return;
}
ap_config.ap.channel = param->softap_channel.channel;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel);
break;
case ESP_BLUFI_EVENT_GET_WIFI_LIST: {
wifi_scan_config_t scanConf = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.show_hidden = false
};
ESP_ERROR_CHECK(esp_wifi_scan_start(&scanConf, true));
BLUFI_INFO("ESP_BLUFI_EVENT_GET_WIFI_LIST\n");
break;
}
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
BLUFI_INFO("Recv Custom Data %d\n", param->custom_data.data_len);
esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
if (strcmp("restart", (char *)param->custom_data.data)) {
esp_restart();
}
break;
case ESP_BLUFI_EVENT_RECV_USERNAME:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CA_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
/* Not handle currently */
break;
;
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
/* Not handle currently */
break;
default:
break;
}
}
/**
* @brief gap
*/
static void ble_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
switch (event) {
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
esp_ble_gap_start_advertising(&ble_adv_params);
break;
default:
break;
}
}
/**
* @brief
*/
static esp_err_t bluetooth_init()
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
BLUFI_ERROR("%s initialize bt controller failed: %s\n", __func__, esp_err_to_name(ret));
return ret;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
BLUFI_ERROR("%s enable bt controller failed: %s\n", __func__, esp_err_to_name(ret));
return ret;
}
ret = esp_bluedroid_init();
if (ret) {
BLUFI_ERROR("%s init bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return ret;
}
ret = esp_bluedroid_enable();
if (ret) {
BLUFI_ERROR("%s init bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
return ret;
}
BLUFI_INFO("BD ADDR: " ESP_BD_ADDR_STR "\n", ESP_BD_ADDR_HEX(esp_bt_dev_get_address()));
BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version());
ret = esp_ble_gap_register_callback(ble_gap_event_handler);
if (ret) {
BLUFI_ERROR("%s gap register failed, error code = %x\n", __func__, ret);
return ret;
}
ret = esp_blufi_register_callbacks(&blufi_callbacks);
if (ret) {
BLUFI_ERROR("%s blufi register failed, error code = %x\n", __func__, ret);
return ret;
}
ret = esp_blufi_profile_init();
if (ret) {
BLUFI_ERROR("%s blufi profile init failed, error code = %x\n", __func__, ret);
return ret;
}
return ret;
}
/**
* @brief
*/
static bool blufi_init = true;
static void blufi_deinitialize()
{
if (blufi_init) {
blufi_init = false;
ESP_ERROR_CHECK(esp_blufi_profile_deinit());
ESP_ERROR_CHECK(esp_bluedroid_disable());
ESP_ERROR_CHECK(esp_bluedroid_deinit());
ESP_ERROR_CHECK(esp_bt_controller_disable());
ESP_ERROR_CHECK(esp_bt_controller_deinit());
BLUFI_INFO("blufi_deinitialize\n");
}
// ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BTDM));
}
/**
* @brief
*/
static void blufi_initialize()
{
if (!blufi_init) {
blufi_init = true;
// initialise blutooth
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
ESP_ERROR_CHECK(esp_bluedroid_init());
ESP_ERROR_CHECK(esp_bluedroid_enable());
ESP_ERROR_CHECK(esp_blufi_profile_init());
BLUFI_INFO("blufi_initialize\n");
}
}
// wifi config timer
TimerHandle_t wifi_config_timer;
static bool wifi_configing = false;
/**
* @brief wifi
*/
void wifi_connect_succuess()
{
}
/**
* @brief
*/
void wifi_config_timer_callback(void *arg)
{
if (wifi_configing == true){
wifi_configing = false;
// if (connnected) {
// } else {
// }
BLUFI_ERROR("wifi_config_timer_callback out\n");
// de-initialise blufi
blufi_deinitialize();
xTimerDelete(wifi_config_timer, portMAX_DELAY);
}
}
/**
* @brief
*/
void enter_blufi_config_wifi()
{
if (wifi_configing == false) {
wifi_configing = true;
// initialise blufi
blufi_initialize();
// start timer for 1 minute
wifi_config_timer = xTimerCreate(
"wifi_config_timer",
WIFI_CONFIG_TIMEOUT / portTICK_PERIOD_MS, //period time
pdFALSE, //auto load
(void *)NULL, //timer parameter
wifi_config_timer_callback); //timer callback
xTimerStart(wifi_config_timer, portMAX_DELAY);
} else {
xTimerReset(wifi_config_timer, portMAX_DELAY);
}
}
/**
* @brief udp server
*/
static int notice_udp_server_create()
{
esp_err_t ret = ESP_OK;
int sockfd = 0;
struct sockaddr_in server_addr = {
.sin_family = AF_INET,
.sin_port = htons(UDP_NOTICE_PORT),
.sin_addr.s_addr = htonl(INADDR_ANY),
};
retry:
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
goto ERR_EXIT;
}
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (sockfd < 0) {
goto ERR_EXIT;
}
struct timeval socket_timeout = {0, 100 * 1000};
ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(struct timeval));
if (sockfd < 0) {
goto ERR_EXIT;
}
ESP_LOGD("udp notice", "create udp server, port: %d, sockfd: %d", UDP_NOTICE_PORT, sockfd);
return sockfd;
ERR_EXIT:
if (sockfd != -1) {
ret = close(sockfd);
if (ret != ESP_OK) {
ESP_LOGD("udp notice", "close fail, ret: %d", ret);
}
}
goto retry;
return -1;
}
/**
* @brief udp
*/
static void notice_udp_task(void *arg)
{
uint8_t root_mac[6] = {0};
char *udp_server_buf = malloc(NOTICE_UDP_BUF_SIZE);
struct sockaddr_in from_addr = {0};
socklen_t from_addr_len = sizeof(struct sockaddr_in);
// wait network connected
wait_net_connected();
int udp_server_sockfd = notice_udp_server_create();
if (udp_server_sockfd == -1) {
ESP_LOGE("notice udp", "Failed to create UDP notification service");
vTaskDelete(NULL);
return ;
}
ESP_ERROR_CHECK(esp_wifi_get_mac(ESP_IF_WIFI_STA, root_mac));
while(1){
memset(udp_server_buf, 0, NOTICE_UDP_BUF_SIZE);
if (recvfrom(udp_server_sockfd, udp_server_buf, NOTICE_UDP_BUF_SIZE,
0, (struct sockaddr *)&from_addr, (socklen_t *)&from_addr_len) > 0) {
ESP_LOGD("udp notice task", "Mlink notice udp recvfrom, sockfd: %d, port: %d, ip: %s, udp_server_buf: %s",
udp_server_sockfd, ntohs(((struct sockaddr_in *)&from_addr)->sin_port),
inet_ntoa(((struct sockaddr_in *)&from_addr)->sin_addr), udp_server_buf);
if (strcmp(udp_server_buf, "Are You ESP_Who_Wechat Device?")) {
continue;
}
sprintf(udp_server_buf, "WeChat MAC:%02x%02x%02x%02x%02x%02x TCP:%d",
MAC2STR(root_mac), TCP_DEFAULT_PORT);
ESP_LOGD("udp notice task", "Mlink notice udp sendto, sockfd: %d, data: %s", udp_server_sockfd, udp_server_buf);
for (int i = 0, delay_time_ms = 0; i < NOTICE_UDP_RETRY_COUNT; ++i, delay_time_ms += delay_time_ms) {
vTaskDelay(delay_time_ms);
delay_time_ms = (i == 0) ? (10 / portTICK_RATE_MS) : delay_time_ms;
if (sendto(udp_server_sockfd, udp_server_buf, strlen(udp_server_buf),
0, (struct sockaddr *)&from_addr, from_addr_len) <= 0) {
ESP_LOGW("udp notice task", "Mlink notice udp sendto, errno: %d, errno_str: %s", errno, strerror(errno));
break;
}
}
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
// mDNS initialise
static void initialise_mdns(void)
{
int ret = 0;
uint8_t retry_count = 30;
uint8_t root_mac[6] = {0};
char mac_str[16] = {0};
// wait network connected
wait_net_connected();
//initialize mDNS
ESP_ERROR_CHECK(mdns_init());
//set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK(mdns_hostname_set(NOTICE_MDNS_HOSTNAME));
//set default mDNS instance name
ESP_ERROR_CHECK(mdns_instance_name_set(NOTICE_MDNS_INSTANCE));
mdns_txt_item_t mdns_txt_data[] = {
{"esp-who", "WeChat"},
{"mac", mac_str},
};
ESP_ERROR_CHECK(esp_wifi_get_mac(ESP_IF_WIFI_STA, root_mac));
sprintf(mac_str, "%02x%02x%02x%02x%02x%02x", MAC2STR(root_mac));
do {
//initialize MDNS service
ret = mdns_service_add(NOTICE_MDNS_INSTANCE, NOTICE_MDNS_SERVICE_TYPE, NOTICE_MDNS_PROTO, TCP_DEFAULT_PORT,
mdns_txt_data, sizeof(mdns_txt_data) / sizeof(mdns_txt_item_t));
if (ret != 0) {
vTaskDelay(100 / portTICK_RATE_MS);
}
} while (ret != 0 && retry_count--);
}
/**
* @brief mdns udp
*/
static void initialise_notice()
{
// initialise mdns
initialise_mdns();
// initialise udp notice service
xTaskCreatePinnedToCore(notice_udp_task, "notice_udp", 3 * 1024, NULL, 4, NULL, 1);
}
/**
* @brief wifi mdns udp
*/
void blufi_main()
{
// initialise blutooth
ESP_ERROR_CHECK(bluetooth_init());
// de-initialise blufi
blufi_deinitialize();
// load wifi ssid passwd
load_info_nvs(NVS_KEY_WIFI_SSID_PASS, (void *)(sta_config.sta.ssid), WIFI_SSID_PASS_SIZE);
// initialise wifi
wifi_init_ap_sta();
// initialise notice service
initialise_notice();
}

View File

@ -0,0 +1,235 @@
// Copyright 2015-2016 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.
/* C Includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* FreeRTOS Includes */
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
/* ESP32 Includes */
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
/* Blutooth Includes */
#include "esp_blufi_api.h"
#include "esp_bt_defs.h"
#include "esp_gap_ble_api.h"
#include "esp_bt_main.h"
/* TLS Includes */
#include "mbedtls/aes.h"
#include "mbedtls/dhm.h"
#include "mbedtls/md5.h"
#include "rom/crc.h"
/* wechat Includes */
#include "wechat_blufi.h"
/*
The SEC_TYPE_xxx is for self-defined packet data type in the procedure of "BLUFI negotiate key"
If user use other negotiation procedure to exchange(or generate) key, should redefine the type by yourself.
*/
#define SEC_TYPE_DH_PARAM_LEN 0x00
#define SEC_TYPE_DH_PARAM_DATA 0x01
#define SEC_TYPE_DH_P 0x02
#define SEC_TYPE_DH_G 0x03
#define SEC_TYPE_DH_PUBLIC 0x04
struct blufi_security {
#define DH_SELF_PUB_KEY_LEN 128
#define DH_SELF_PUB_KEY_BIT_LEN (DH_SELF_PUB_KEY_LEN * 8)
uint8_t self_public_key[DH_SELF_PUB_KEY_LEN];
#define SHARE_KEY_LEN 128
#define SHARE_KEY_BIT_LEN (SHARE_KEY_LEN * 8)
uint8_t share_key[SHARE_KEY_LEN];
size_t share_len;
#define PSK_LEN 16
uint8_t psk[PSK_LEN];
uint8_t *dh_param;
int dh_param_len;
uint8_t iv[16];
mbedtls_dhm_context dhm;
mbedtls_aes_context aes;
};
static struct blufi_security *blufi_sec;
extern void btc_blufi_report_error(esp_blufi_error_state_t state);
static int myrand(void *rng_state, unsigned char *output, size_t len)
{
size_t i;
for (i = 0; i < len; ++i) {
output[i] = esp_random();
}
return (0);
}
void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free)
{
int ret;
uint8_t type = data[0];
if (blufi_sec == NULL) {
BLUFI_ERROR("BLUFI Security is not initialized");
btc_blufi_report_error(ESP_BLUFI_INIT_SECURITY_ERROR);
return;
}
switch (type) {
case SEC_TYPE_DH_PARAM_LEN:
blufi_sec->dh_param_len = ((data[1] << 8) | data[2]);
if (blufi_sec->dh_param) {
free(blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
}
blufi_sec->dh_param = (uint8_t *)malloc(blufi_sec->dh_param_len);
if (blufi_sec->dh_param == NULL) {
btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR);
BLUFI_ERROR("%s, malloc failed\n", __func__);
return;
}
break;
case SEC_TYPE_DH_PARAM_DATA: {
if (blufi_sec->dh_param == NULL) {
BLUFI_ERROR("%s, blufi_sec->dh_param == NULL\n", __func__);
btc_blufi_report_error(ESP_BLUFI_DH_PARAM_ERROR);
return;
}
uint8_t *param = blufi_sec->dh_param;
memcpy(blufi_sec->dh_param, &data[1], blufi_sec->dh_param_len);
ret = mbedtls_dhm_read_params(&blufi_sec->dhm, &param, &param[blufi_sec->dh_param_len]);
if (ret) {
BLUFI_ERROR("%s read param failed %d\n", __func__, ret);
btc_blufi_report_error(ESP_BLUFI_READ_PARAM_ERROR);
return;
}
free(blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
ret = mbedtls_dhm_make_public(&blufi_sec->dhm, (int)mbedtls_mpi_size(&blufi_sec->dhm.P), blufi_sec->self_public_key, blufi_sec->dhm.len, myrand, NULL);
if (ret) {
BLUFI_ERROR("%s make public failed %d\n", __func__, ret);
btc_blufi_report_error(ESP_BLUFI_MAKE_PUBLIC_ERROR);
return;
}
mbedtls_dhm_calc_secret(&blufi_sec->dhm,
blufi_sec->share_key,
SHARE_KEY_BIT_LEN,
&blufi_sec->share_len,
NULL, NULL);
mbedtls_md5(blufi_sec->share_key, blufi_sec->share_len, blufi_sec->psk);
mbedtls_aes_setkey_enc(&blufi_sec->aes, blufi_sec->psk, 128);
/* alloc output data */
*output_data = &blufi_sec->self_public_key[0];
*output_len = blufi_sec->dhm.len;
*need_free = false;
}
break;
case SEC_TYPE_DH_P:
break;
case SEC_TYPE_DH_G:
break;
case SEC_TYPE_DH_PUBLIC:
break;
}
}
int blufi_aes_encrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len)
{
int ret;
size_t iv_offset = 0;
uint8_t iv0[16];
memcpy(iv0, blufi_sec->iv, sizeof(blufi_sec->iv));
iv0[0] = iv8; /* set iv8 as the iv0[0] */
ret = mbedtls_aes_crypt_cfb128(&blufi_sec->aes, MBEDTLS_AES_ENCRYPT, crypt_len, &iv_offset, iv0, crypt_data, crypt_data);
if (ret) {
return -1;
}
return crypt_len;
}
int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len)
{
int ret;
size_t iv_offset = 0;
uint8_t iv0[16];
memcpy(iv0, blufi_sec->iv, sizeof(blufi_sec->iv));
iv0[0] = iv8; /* set iv8 as the iv0[0] */
ret = mbedtls_aes_crypt_cfb128(&blufi_sec->aes, MBEDTLS_AES_DECRYPT, crypt_len, &iv_offset, iv0, crypt_data, crypt_data);
if (ret) {
return -1;
}
return crypt_len;
}
uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len)
{
/* This iv8 ignore, not used */
return crc16_be(0, data, len);
}
esp_err_t blufi_security_init(void)
{
blufi_sec = (struct blufi_security *)malloc(sizeof(struct blufi_security));
if (blufi_sec == NULL) {
return ESP_FAIL;
}
memset(blufi_sec, 0x0, sizeof(struct blufi_security));
mbedtls_dhm_init(&blufi_sec->dhm);
mbedtls_aes_init(&blufi_sec->aes);
memset(blufi_sec->iv, 0x0, 16);
return 0;
}
void blufi_security_deinit(void)
{
if (blufi_sec == NULL) {
return;
}
if (blufi_sec->dh_param) {
free(blufi_sec->dh_param);
blufi_sec->dh_param = NULL;
}
mbedtls_dhm_free(&blufi_sec->dhm);
mbedtls_aes_free(&blufi_sec->aes);
memset(blufi_sec, 0x0, sizeof(struct blufi_security));
free(blufi_sec);
blufi_sec = NULL;
}

View File

@ -0,0 +1,24 @@
menu "Example Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default ""
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default ""
help
WiFi password (WPA or WPA2) for the example to use.
config MAX_STA_CONN
int "Maximal STA connections"
default 1
help
Max number of the STA connects to AP.
config SERVER_IP
string "IP address of server"
default "192.168.4.1"
endmenu

View File

@ -0,0 +1,73 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, 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.
*/
#include "app_camera.h"
static const char *TAG = "app_camera";
void app_camera_init()
{
/* IO13, IO14 is designed for JTAG by default,
* to use it as generalized input,
* firstly declair it as pullup input */
gpio_config_t conf;
conf.mode = GPIO_MODE_INPUT;
conf.pull_up_en = GPIO_PULLUP_ENABLE;
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
conf.intr_type = GPIO_INTR_DISABLE;
conf.pin_bit_mask = 1LL << 13;
gpio_config(&conf);
conf.pin_bit_mask = 1LL << 14;
gpio_config(&conf);
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.xclk_freq_hz = XCLK_FREQ;
config.pixel_format = CAMERA_PIXEL_FORMAT;
config.frame_size = CAMERA_FRAME_SIZE;
config.jpeg_quality = 10;
config.fb_count = 2;
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
return;
}
}

View File

@ -0,0 +1,121 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, 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.
*/
#include "esp_log.h"
#include "app_httpserver.h"
#include "fd_forward.h"
#include "image_util.h"
#include "app_main.h"
static const char *TAG = "app_process";
face_id_name_list st_face_list = {0};
static dl_matrix3du_t *aligned_face = NULL;
extern QueueHandle_t gpst_input_image;
extern QueueHandle_t gpst_output;
static inline mtmn_config_t app_mtmn_config()
{
mtmn_config_t mtmn_config;
mtmn_config.min_face = 80;
mtmn_config.pyramid = 0.7;
mtmn_config.p_threshold.score = 0.6;
mtmn_config.p_threshold.nms = 0.7;
mtmn_config.p_threshold.candidate_number = 100;
mtmn_config.r_threshold.score = 0.6;
mtmn_config.r_threshold.nms = 0.7;
mtmn_config.r_threshold.candidate_number = 4;
mtmn_config.o_threshold.score = 0.6;
mtmn_config.o_threshold.nms = 0.4;
mtmn_config.o_threshold.candidate_number = 1;
return mtmn_config;
}
static inline box_array_t *do_detection(camera_fb_t *fb, dl_matrix3du_t *image_mat, mtmn_config_t *mtmn_config)
{
if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_mat->item))
{
ESP_LOGW(TAG, "fmt2rgb888 failed");
return NULL;
}
box_array_t *net_boxes = face_detect(image_mat, mtmn_config);
return net_boxes;
}
void task_process(void *arg)
{
camera_fb_t * fb = NULL;
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, 320, 240, 3);
if (!image_matrix)
{
ESP_LOGE(TAG, "dl_matrix3du_alloc failed");
return;
}
mtmn_config_t mtmn_config = app_mtmn_config();
http_img_process_result out_res = {0};
//out_res.lock = xSemaphoreCreateBinary();
out_res.image = image_matrix->item;
while (1)
{
xQueueReceive(gpst_input_image, &fb, portMAX_DELAY);
//xSemaphoreTake(out_res.lock, portMAX_DELAY);
out_res.net_boxes = NULL;
out_res.face_id = NULL;
out_res.net_boxes = do_detection(fb, image_matrix, &mtmn_config);
if (out_res.net_boxes)
{
if (g_state == START_DETECT)
{
xQueueSend(gpst_output, &out_res, portMAX_DELAY);
continue;
}
// Get face ID
if (align_face(out_res.net_boxes, image_matrix, aligned_face) == ESP_OK)
{
out_res.face_id = get_face_id(aligned_face);
}
}
xQueueSend(gpst_output, &out_res, portMAX_DELAY);
}
dl_matrix3du_free(image_matrix);
}
void app_facenet_main()
{
face_id_name_init(&st_face_list, FACE_ID_SAVE_NUMBER, ENROLL_CONFIRM_TIMES);
aligned_face = dl_matrix3du_alloc(1, FACE_WIDTH, FACE_HEIGHT, 3);
read_face_id_from_flash_with_name(&st_face_list);
xTaskCreatePinnedToCore(task_process, "process", 4 * 1024, NULL, 5, NULL, 1);
}

View File

@ -0,0 +1,616 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, 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.
*/
#include "app_httpserver.h"
#include "esp_log.h"
#include "image_util.h"
#include "fb_gfx.h"
#include "app_main.h"
static const char *TAG = "app_httpserver";
#define FACE_COLOR_WHITE 0x00FFFFFF
#define FACE_COLOR_BLACK 0x00000000
#define FACE_COLOR_RED 0x000000FF
#define FACE_COLOR_GREEN 0x0000FF00
#define FACE_COLOR_BLUE 0x00FF0000
#define FACE_COLOR_YELLOW (FACE_COLOR_RED | FACE_COLOR_GREEN)
#define FACE_COLOR_CYAN (FACE_COLOR_BLUE | FACE_COLOR_GREEN)
#define FACE_COLOR_PURPLE (FACE_COLOR_BLUE | FACE_COLOR_RED)
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
extern face_id_name_list st_face_list;
static int8_t g_is_enrolling = 0;
static int8_t g_stop_stream = 0;
static int8_t g_detection_enabled = 0;
static int8_t g_recognition_enabled = 0;
typedef struct
{
char enroll_name[ENROLL_NAME_LEN];
} httpd_resp_value;
httpd_resp_value st_name;
QueueHandle_t gpst_input_image = NULL;
QueueHandle_t gpst_output = NULL;
// Profiling
static int64_t fr_start = 0;
static int64_t fr_ready = 0;
static int64_t fr_face = 0;
static int64_t fr_recognize = 0;
static int64_t fr_encode = 0;
//static void oneshot_timer_callback(void* arg);
char *number_suffix(int32_t number)
{
uint8_t n = number % 10;
if (n == 0)
return "zero";
else if (n == 1)
return "st";
else if (n == 2)
return "nd";
else if (n == 3)
return "rd";
else
return "th";
}
static void rgb_print(void *image, int w, int h, uint32_t color, const char * str){
fb_data_t fb;
fb.width = w;
fb.height = h;
fb.data = image;
fb.bytes_per_pixel = 3;
fb.format = FB_BGR888;
fb_gfx_print(&fb, (fb.width - (strlen(str) * 14)) / 2, 10, color, str);
}
static int rgb_printf(void *image, int w, int h, uint32_t color, const char *format, ...)
{
char loc_buf[64];
char * temp = loc_buf;
int len;
va_list arg;
va_list copy;
va_start(arg, format);
va_copy(copy, arg);
len = vsnprintf(loc_buf, sizeof(loc_buf), format, arg);
va_end(copy);
if(len >= sizeof(loc_buf)){
temp = (char*)malloc(len+1);
if(temp == NULL) {
return 0;
}
}
vsnprintf(temp, len+1, format, arg);
va_end(arg);
rgb_print(image, w, h, color, temp);
if(len > 64){
free(temp);
}
return len;
}
static void draw_face_boxes(void *image, int width, int height, box_array_t *boxes){
int x, y, w, h, i;
uint32_t color = FACE_COLOR_YELLOW;
fb_data_t fb;
fb.width = width;
fb.height = height;
fb.data = image;
fb.bytes_per_pixel = 3;
fb.format = FB_BGR888;
for (i = 0; i < boxes->len; i++){
// rectangle box
x = (int)boxes->box[i].box_p[0];
y = (int)boxes->box[i].box_p[1];
w = (int)boxes->box[i].box_p[2] - x + 1;
h = (int)boxes->box[i].box_p[3] - y + 1;
fb_gfx_drawFastHLine(&fb, x, y, w, color);
fb_gfx_drawFastHLine(&fb, x, y+h-1, w, color);
fb_gfx_drawFastVLine(&fb, x, y, h, color);
fb_gfx_drawFastVLine(&fb, x+w-1, y, h, color);
#if 0
// landmark
int x0, y0, j;
for (j = 0; j < 10; j+=2) {
x0 = (int)boxes->landmark[i].landmark_p[j];
y0 = (int)boxes->landmark[i].landmark_p[j+1];
fb_gfx_fillRect(&fb, x0, y0, 3, 3, color);
}
#endif
}
}
static inline int do_enrollment(face_id_name_list *face_list, dl_matrix3d_t *new_id)
{
ESP_LOGD(TAG, "START ENROLLING");
int left_sample_face = enroll_face_id_to_flash_with_name(face_list, new_id, st_name.enroll_name);
ESP_LOGD(TAG, "Face ID %s Enrollment: Taken the %d%s sample",
face_list->tail->id_name,
ENROLL_CONFIRM_TIMES - left_sample_face,
number_suffix(ENROLL_CONFIRM_TIMES - left_sample_face));
gpio_set_level(GPIO_LED_RED, 0);
return left_sample_face;
}
esp_err_t facenet_stream_handler(httpd_req_t *req)
{
esp_err_t res = ESP_OK;
g_state = START_STREAM;
g_stop_stream = 0;
camera_fb_t * fb = NULL;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
http_img_process_result out_res = {0};
static int64_t last_frame = 0;
if(!last_frame) {
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
ESP_LOGI(TAG, "Get count %d\n", st_face_list.count);
while(true)
{
// update fsm state
if (g_stop_stream)
{
g_stop_stream = 0;
httpd_resp_send_404(req);
break;
}
else if (g_is_enrolling)
{
g_state = START_ENROLL;
}
else if (g_recognition_enabled && (st_face_list.count > 0))
{
g_state = START_RECOGNITION;
}
else if (g_detection_enabled)
{
g_state = START_DETECT;
}
else
{
g_state = START_STREAM;
}
ESP_LOGD(TAG, "State: %d, count:%d", g_state, st_face_list.count);
// exec event
fb = esp_camera_fb_get();
if (!fb)
{
ESP_LOGE(TAG, "Camera capture failed");
res = ESP_FAIL;
break;
}
if (g_state == START_STREAM)
{
_jpg_buf = fb->buf;
_jpg_buf_len = fb->len;
goto http_response;
}
fr_start = esp_timer_get_time();
fr_ready = fr_start;
fr_face = fr_start;
fr_encode = fr_start;
fr_recognize = fr_start;
xQueueSend(gpst_input_image, &fb, portMAX_DELAY);
xQueueReceive(gpst_output, &out_res, portMAX_DELAY);
fr_recognize = fr_face;
if (out_res.net_boxes)
{
draw_face_boxes(out_res.image, fb->width, fb->height, out_res.net_boxes);
free(out_res.net_boxes->box);
free(out_res.net_boxes->landmark);
free(out_res.net_boxes);
if (out_res.face_id)
{
if (g_state == START_ENROLL)
{
int left_sample_face = do_enrollment(&st_face_list, out_res.face_id);
rgb_print(out_res.image, fb->width, fb->height, FACE_COLOR_YELLOW, "START ENROLLING");
rgb_printf(out_res.image, fb->width, fb->height, FACE_COLOR_CYAN, "\nThe %u%s sample",
ENROLL_CONFIRM_TIMES - left_sample_face,
number_suffix(ENROLL_CONFIRM_TIMES - left_sample_face));
if (left_sample_face == 0)
{
ESP_LOGI(TAG, "Enrolled Face ID: %s", st_face_list.tail->id_name);
rgb_printf(out_res.image, fb->width, fb->height, FACE_COLOR_CYAN, "\n\nFace ID: %s", st_face_list.tail->id_name);
g_is_enrolling = 0;
g_state = START_RECOGNITION;
}
}
else
{
face_id_node *f = recognize_face_with_name(&st_face_list, out_res.face_id);
if (f)
{
gpio_set_level(GPIO_LED_RED, 1);
rgb_printf(out_res.image, fb->width, fb->height, FACE_COLOR_GREEN, "Hello %s", f->id_name);
}
else
{
rgb_print(out_res.image, fb->width, fb->height, FACE_COLOR_RED, "\nWHO?");
}
} // START_ENROLL
dl_matrix3d_free(out_res.face_id);
}
//xSemaphoreGive(out_res.lock);
if(!fmt2jpg(out_res.image, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len))
{
ESP_LOGE(TAG, "fmt2jpg failed");
}
esp_camera_fb_return(fb);
fb = NULL;
}
else
{
_jpg_buf = fb->buf;
_jpg_buf_len = fb->len;
}
fr_encode = esp_timer_get_time();
http_response:
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
int64_t fr_end = esp_timer_get_time();
int64_t ready_time = (fr_ready - fr_start)/1000;
int64_t face_time = (fr_face - fr_ready)/1000;
int64_t recognize_time = (fr_recognize - fr_face)/1000;
int64_t encode_time = (fr_encode - fr_recognize)/1000;
int64_t process_time = (fr_encode - fr_start)/1000;
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps), %u+%u+%u+%u=%u",
(uint32_t)(_jpg_buf_len/1024),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
(uint32_t)ready_time, (uint32_t)face_time, (uint32_t)recognize_time, (uint32_t)encode_time, (uint32_t)process_time);
}
last_frame = 0;
g_state = WAIT_FOR_CONNECT;
return ESP_OK;
}
httpd_uri_t _face_stream_handler = {
.uri = "/stream",
.method = HTTP_GET,
.handler = facenet_stream_handler,
.user_ctx = NULL
};
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[32] = {0,};
char value[FACE_ID_SAVE_NUMBER * ENROLL_NAME_LEN] = {0,};
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
} else {
free(buf);
httpd_resp_send_404(req);
return ESP_FAIL;
}
free(buf);
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
int val = atoi(value);
ESP_LOGI(TAG, "%s = %d", variable, val);
sensor_t * s = esp_camera_sensor_get();
int res = 0;
if(!strcmp(variable, "framesize")) {
if(s->pixformat == PIXFORMAT_JPEG) res = s->set_framesize(s, (framesize_t)val);
}
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
else if(!strcmp(variable, "saturation")) res = s->set_saturation(s, val);
else if(!strcmp(variable, "gainceiling")) res = s->set_gainceiling(s, (gainceiling_t)val);
else if(!strcmp(variable, "colorbar")) res = s->set_colorbar(s, val);
else if(!strcmp(variable, "awb")) res = s->set_whitebal(s, val);
else if(!strcmp(variable, "agc")) res = s->set_gain_ctrl(s, val);
else if(!strcmp(variable, "aec")) res = s->set_exposure_ctrl(s, val);
else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
else if(!strcmp(variable, "awb_gain")) res = s->set_awb_gain(s, val);
else if(!strcmp(variable, "agc_gain")) res = s->set_agc_gain(s, val);
else if(!strcmp(variable, "aec_value")) res = s->set_aec_value(s, val);
else if(!strcmp(variable, "aec2")) res = s->set_aec2(s, val);
else if(!strcmp(variable, "dcw")) res = s->set_dcw(s, val);
else if(!strcmp(variable, "bpc")) res = s->set_bpc(s, val);
else if(!strcmp(variable, "wpc")) res = s->set_wpc(s, val);
else if(!strcmp(variable, "raw_gma")) res = s->set_raw_gma(s, val);
else if(!strcmp(variable, "lenc")) res = s->set_lenc(s, val);
else if(!strcmp(variable, "special_effect")) res = s->set_special_effect(s, val);
else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val);
else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val);
else if(!strcmp(variable, "stop_stream")) g_stop_stream = 1;
else if(!strcmp(variable, "face_detect")) {
g_detection_enabled = val;
if(!g_detection_enabled) {
g_recognition_enabled = 0;
g_is_enrolling = 0;
}
}
else if(!strcmp(variable, "face_enroll"))
{
if (!g_is_enrolling && g_recognition_enabled)
{
memcpy(st_name.enroll_name, value, strlen(value) + 1);
g_is_enrolling = 1;
}
}
else if(!strcmp(variable, "face_delete"))
{
// ["aaa","bbb"]
char delete_name[ENROLL_NAME_LEN * FACE_ID_SAVE_NUMBER];
uint8_t len = strlen(value) - strlen("%5b%22") - strlen("%22%5d");
memcpy(delete_name, value + strlen("%5b%22"), len);
delete_name[len] = 0;
char *p = delete_name;
char *q = NULL;
do
{
q = strstr(p, "%22%2C%22");
if (!q)
break;
p[q - p] = 0;
int8_t left = delete_face_id_in_flash_with_name(&st_face_list, p);
if (left > 0)
ESP_LOGW(TAG, "%s ID Delete", p);
p = q + 9;
q = strstr(p, "%22%2C%22");
} while (q);
int8_t left = delete_face_id_in_flash_with_name(&st_face_list, p);
if (left > 0)
ESP_LOGW(TAG, "%s ID Delete", p);
}
else if(!strcmp(variable, "delete_all"))
{
delete_face_all_in_flash_with_name(&st_face_list);
}
else if(!strcmp(variable, "face_recognize")) {
g_recognition_enabled = val;
if(g_recognition_enabled){
g_detection_enabled = val;
}
}
else if(!strcmp(variable, "get_id")) {
static char id_json[1024];
char *p = id_json;
*p++ = '{';
p += sprintf(p, "\"len\":%d,", st_face_list.count);
p += sprintf(p, "\"list\":[");
face_id_node *head = st_face_list.head;
for (int i = 0; i < st_face_list.count; i++)
{
p += sprintf(p, "\"%s\",", head->id_name);
head = head->next;
}
if (st_face_list.count)
p--;
*p++ = ']';
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, id_json, strlen(id_json));
}
else {
res = -1;
}
if(res){
return httpd_resp_send_500(req);
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
httpd_uri_t cmd_uri = {
.uri = "/control",
.method = HTTP_GET,
.handler = cmd_handler,
.user_ctx = NULL
};
httpd_handle_t camera_httpd = NULL;
static esp_err_t status_handler(httpd_req_t *req){
static char json_response[1024];
sensor_t * s = esp_camera_sensor_get();
char * p = json_response;
*p++ = '{';
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"saturation\":%d,", s->status.saturation);
p+=sprintf(p, "\"special_effect\":%u,", s->status.special_effect);
p+=sprintf(p, "\"wb_mode\":%u,", s->status.wb_mode);
p+=sprintf(p, "\"awb\":%u,", s->status.awb);
p+=sprintf(p, "\"awb_gain\":%u,", s->status.awb_gain);
p+=sprintf(p, "\"aec\":%u,", s->status.aec);
p+=sprintf(p, "\"aec2\":%u,", s->status.aec2);
p+=sprintf(p, "\"ae_level\":%d,", s->status.ae_level);
p+=sprintf(p, "\"aec_value\":%u,", s->status.aec_value);
p+=sprintf(p, "\"agc\":%u,", s->status.agc);
p+=sprintf(p, "\"agc_gain\":%u,", s->status.agc_gain);
p+=sprintf(p, "\"gainceiling\":%u,", s->status.gainceiling);
p+=sprintf(p, "\"bpc\":%u,", s->status.bpc);
p+=sprintf(p, "\"wpc\":%u,", s->status.wpc);
p+=sprintf(p, "\"raw_gma\":%u,", s->status.raw_gma);
p+=sprintf(p, "\"lenc\":%u,", s->status.lenc);
p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
p+=sprintf(p, "\"dcw\":%u,", s->status.dcw);
p+=sprintf(p, "\"colorbar\":%u", s->status.colorbar);
p+=sprintf(p, ",\"face_detect\":%u", g_detection_enabled);
p+=sprintf(p, ",\"face_enroll\":%u,", g_is_enrolling);
p+=sprintf(p, "\"face_recognize\":%u", g_recognition_enabled);
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, strlen(json_response));
}
httpd_uri_t status_uri = {
.uri = "/status",
.method = HTTP_GET,
.handler = status_handler,
.user_ctx = NULL
};
#if 0
const esp_timer_create_args_t oneshot_timer_args = {
.callback = &oneshot_timer_callback,
/* argument specified here will be passed to timer callback function */
.name = "one-shot"
};
esp_timer_handle_t oneshot_timer;
static void oneshot_timer_callback(void* arg)
{
if(g_state != START_ENROLL)
g_is_enrolling = 1;
}
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
esp_err_t err = esp_timer_start_once(oneshot_timer, 500000);
if(err == ESP_ERR_INVALID_STATE)
{
ESP_ERROR_CHECK(esp_timer_stop(oneshot_timer));
g_is_enrolling = 0;
g_is_deleting = 1;
gpio_set_level(GPIO_LED_WHITE, 0);
}
}
#endif
void app_httpserver_init ()
{
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.stack_size = 4096 * 2;
#if 0
ESP_ERROR_CHECK(esp_timer_create(&oneshot_timer_args, &oneshot_timer));
gpio_config_t io_conf = {0};
io_conf.mode = GPIO_MODE_INPUT;
io_conf.intr_type = GPIO_PIN_INTR_POSEDGE;
io_conf.pin_bit_mask = 1LL << GPIO_BUTTON;
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&io_conf);
gpio_isr_handler_add(GPIO_BUTTON, gpio_isr_handler, NULL);
#endif
gpst_input_image = xQueueCreate(1, sizeof(void *));
gpst_output = xQueueCreate(1, sizeof(http_img_process_result));
if (httpd_start(&camera_httpd, &config) == ESP_OK)
{
httpd_register_uri_handler(camera_httpd, &cmd_uri);
httpd_register_uri_handler(camera_httpd, &status_uri);
}
config.server_port += 1;
config.ctrl_port += 1;
if (httpd_start(&camera_httpd, &config) == ESP_OK)
{
httpd_register_uri_handler(camera_httpd, &_face_stream_handler);
}
}

View File

@ -0,0 +1,174 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, 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.
*/
#include "app_main.h"
#include "esp_partition.h"
#include "wechat_blufi.h"
void gpio_led_init()
{
gpio_config_t gpio_conf;
gpio_conf.mode = GPIO_MODE_OUTPUT;
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_conf.intr_type = GPIO_INTR_DISABLE;
gpio_conf.pin_bit_mask = 1LL << GPIO_LED_RED;
gpio_config(&gpio_conf);
gpio_conf.pin_bit_mask = 1LL << GPIO_LED_WHITE;
gpio_config(&gpio_conf);
}
void led_task(void *arg)
{
while(1)
{
switch (g_state)
{
case WAIT_FOR_WAKEUP:
gpio_set_level(GPIO_LED_RED, 1);
gpio_set_level(GPIO_LED_WHITE, 0);
break;
case WAIT_FOR_CONNECT:
gpio_set_level(GPIO_LED_WHITE, 0);
gpio_set_level(GPIO_LED_RED, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_LED_RED, 0);
break;
case START_DETECT:
case START_RECOGNITION:
gpio_set_level(GPIO_LED_WHITE, 1);
gpio_set_level(GPIO_LED_RED, 0);
break;
case START_ENROLL:
gpio_set_level(GPIO_LED_WHITE, 1);
gpio_set_level(GPIO_LED_RED, 1);
break;
default:
gpio_set_level(GPIO_LED_WHITE, 1);
gpio_set_level(GPIO_LED_RED, 0);
break;
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
en_fsm_state g_state = WAIT_FOR_WAKEUP;
static void restart_count_erase_timercb(void *timer)
{
if (!xTimerStop(timer, portMAX_DELAY)) {
ESP_LOGD("esp-eye", "xTimerStop timer: %p", timer);
}
if (!xTimerDelete(timer, portMAX_DELAY)) {
ESP_LOGD("esp-eye", "xTimerDelete timer: %p", timer);
}
wifi_info_erase(NVS_KEY_RESTART_COUNT);
ESP_LOGI("esp-eye", "Erase restart count");
}
static int restart_count_get()
{
esp_err_t ret = ESP_OK;
TimerHandle_t timer = NULL;
uint32_t restart_count = 0;
/**< If the device restarts within the instruction time,
the event_mdoe value will be incremented by one */
load_info_nvs(NVS_KEY_RESTART_COUNT, &restart_count, sizeof(uint32_t));
restart_count++;
ret = save_info_nvs(NVS_KEY_RESTART_COUNT, &restart_count, sizeof(uint32_t));
if (ret != ESP_OK) {
ESP_LOGE("size_info_nvs", "size_info_nvs\n");
return ret;
}
timer = xTimerCreate("restart_count_erase", RESTART_TIMEOUT_MS / portTICK_RATE_MS,
false, NULL, restart_count_erase_timercb);
xTimerStart(timer, 0);
return restart_count;
}
void printTask(void *arg)
{
#define BUF_SIZE 1 * 1024
char *tasklist = malloc(BUF_SIZE);
while (1) {
memset(tasklist, 0, BUF_SIZE);
vTaskGetRunTimeStats(tasklist);
printf("Running tasks CPU usage: \n %s\r\n", (char *)tasklist);
printf("RAM size: %dKB, with PSRAM: %dKB\n", heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL) / 1024, heap_caps_get_free_size(MALLOC_CAP_8BIT));
vTaskDelay(5000 / portTICK_RATE_MS);
}
free(tasklist);
}
void app_facenet_main();
void app_main()
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Compatible V3.1. NVS format has been changed between v3.1 and v3.2 to support longer blob values.
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
if (restart_count_get() > 3) {
ESP_LOGI("esp-eye", "Erase information saved in flash");
wifi_info_erase(USERDATANAMESPACE);
}
gpio_led_init();
app_camera_init();
xTaskCreatePinnedToCore(&led_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL, 0);
g_state = WAIT_FOR_CONNECT;
ESP_LOGI("esp-eye", "Version "VERSION);
// app_wifi_init();
// wifi init and blufi
blufi_main();
// wait for network connected
wait_net_connected();
app_facenet_main();
app_httpserver_init();
printf("Mem availabe after: %d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL));
ESP_LOGI("esp-eye", "Version "VERSION" success");
//xTaskCreatePinnedToCore(&printTask, "printTask", 2*1024, NULL, 5, NULL, 1);
}

View File

@ -0,0 +1,182 @@
/* ESPRESSIF MIT License
*
* Copyright (c) 2018 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on all ESPRESSIF SYSTEMS products, 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.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "app_wifi.h"
static const char *TAG = "app_wifi";
#define EXAMPLE_ESP_WIFI_MODE_AP 1 //TRUE:AP FALSE:STA
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_MAX_STA_CONN CONFIG_MAX_STA_CONN
#define EXAMPLE_IP_ADDR CONFIG_SERVER_IP
static esp_err_t event_handler(void *ctx, system_event_t *event)
{/*{{{*/
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
ESP_LOGI(TAG, "got ip:%s",
ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
break;
case SYSTEM_EVENT_AP_STACONNECTED:
ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d",
MAC2STR(event->event_info.sta_connected.mac),
event->event_info.sta_connected.aid);
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
ESP_LOGI(TAG, "station:" MACSTR " leave, AID=%d",
MAC2STR(event->event_info.sta_disconnected.mac),
event->event_info.sta_disconnected.aid);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
esp_wifi_connect();
break;
default:
break;
}
return ESP_OK;
}/*}}}*/
#if EXAMPLE_ESP_WIFI_MODE_AP
static void wifi_init_softap()
{
tcpip_adapter_init();
if (strcmp(EXAMPLE_IP_ADDR, "192.168.4.1"))
{
int a, b, c, d;
sscanf(EXAMPLE_IP_ADDR, "%d.%d.%d.%d", &a, &b, &c, &d);
tcpip_adapter_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, a, b, c, d);
IP4_ADDR(&ip_info.gw, a, b, c, d);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(tcpip_adapter_dhcps_stop(WIFI_IF_AP));
ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(WIFI_IF_AP, &ip_info));
ESP_ERROR_CHECK(tcpip_adapter_dhcps_start(WIFI_IF_AP));
}
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
uint8_t mac[6];
ESP_ERROR_CHECK(esp_wifi_get_mac(ESP_IF_WIFI_AP, mac));
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
if (strlen(EXAMPLE_ESP_WIFI_SSID) == 0)
{
snprintf((char *)wifi_config.ap.ssid, 32, "esp-eye-%x%x", mac[4], mac[5]);
}
else
{
memcpy(wifi_config.ap.ssid, EXAMPLE_ESP_WIFI_SSID, sizeof(EXAMPLE_ESP_WIFI_SSID));
}
memcpy(wifi_config.ap.password, EXAMPLE_ESP_WIFI_PASS, sizeof(EXAMPLE_ESP_WIFI_PASS));
wifi_config.ap.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID);
wifi_config.ap.max_connection = EXAMPLE_MAX_STA_CONN;
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
esp_wifi_set_ps(WIFI_PS_NONE);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
wifi_config.ap.ssid, EXAMPLE_ESP_WIFI_PASS);
char buf[80];
sprintf(buf, "SSID:%s", wifi_config.ap.ssid);
sprintf(buf, "PASSWORD:%s", wifi_config.ap.password);
}
#else
static void wifi_init_sta()
{
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
wifi_config_t wifi_config = {0};
memset(&wifi_config, 0, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, EXAMPLE_ESP_WIFI_SSID, sizeof(EXAMPLE_ESP_WIFI_SSID));
memcpy(wifi_config.sta.password, EXAMPLE_ESP_WIFI_PASS, sizeof(EXAMPLE_ESP_WIFI_PASS));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", wifi_config.sta.ssid, wifi_config.sta.password);
char buf[80];
sprintf(buf, "SSID:%s", wifi_config.sta.ssid);
sprintf(buf, "PASSWORD:%s", wifi_config.sta.password);
}
#endif
void app_wifi_init ()
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
#if EXAMPLE_ESP_WIFI_MODE_AP
ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
wifi_init_softap();
#else
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
#endif /*EXAMPLE_ESP_WIFI_MODE_AP*/
}

View File

@ -0,0 +1,9 @@
#
# Main Makefile. This is basically the same as a component makefile.
#
# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default,
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#

View File

@ -0,0 +1,77 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products 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 _APP_CAMERA_H_
#define _APP_CAMERA_H_
#include "esp_log.h"
#include "esp_system.h"
#include "esp_camera.h"
/**
* PIXFORMAT_RGB565, // 2BPP/RGB565
* PIXFORMAT_YUV422, // 2BPP/YUV422
* PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
* PIXFORMAT_JPEG, // JPEG/COMPRESSED
* PIXFORMAT_RGB888, // 3BPP/RGB888
*/
#define CAMERA_PIXEL_FORMAT PIXFORMAT_JPEG
/*
* FRAMESIZE_QQVGA, // 160x120
* FRAMESIZE_QQVGA2, // 128x160
* FRAMESIZE_QCIF, // 176x144
* FRAMESIZE_HQVGA, // 240x176
* FRAMESIZE_QVGA, // 320x240
* FRAMESIZE_CIF, // 400x296
* FRAMESIZE_VGA, // 640x480
* FRAMESIZE_SVGA, // 800x600
* FRAMESIZE_XGA, // 1024x768
* FRAMESIZE_SXGA, // 1280x1024
* FRAMESIZE_UXGA, // 1600x1200
*/
#define CAMERA_FRAME_SIZE FRAMESIZE_QVGA
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 4
#define SIOD_GPIO_NUM 18
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 36
#define Y8_GPIO_NUM 37
#define Y7_GPIO_NUM 38
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 35
#define Y4_GPIO_NUM 14
#define Y3_GPIO_NUM 13
#define Y2_GPIO_NUM 34
#define VSYNC_GPIO_NUM 5
#define HREF_GPIO_NUM 27
#define PCLK_GPIO_NUM 25
#define XCLK_FREQ 20000000
void app_camera_init();
#endif

View File

@ -0,0 +1,55 @@
/*
* ESPRESSIF MIT License
*
* Copyright (c) 2017 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS products 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 _APP_FACENET_H_
#define _APP_FACENET_H_
#if __cplusplus
extern "C" {
#endif
#include "esp_http_server.h"
#include "app_camera.h"
#include "fr_forward.h"
#include "fr_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#define ENROLL_CONFIRM_TIMES 3
#define FACE_ID_SAVE_NUMBER 10
#define ENROLL_NAME_LEN 16
typedef struct
{
void *image;
box_array_t *net_boxes;
void *face_id;
SemaphoreHandle_t lock;
} http_img_process_result;
void app_httpserver_init ();
#if __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,21 @@
#include "app_camera.h"
#include "app_httpserver.h"
#include "app_wifi.h"
#define VERSION "0.9.2"
#define GPIO_LED_RED 21
#define GPIO_LED_WHITE 22
#define GPIO_BUTTON 15
typedef enum
{
WAIT_FOR_WAKEUP,
WAIT_FOR_CONNECT,
START_STREAM,
START_DETECT,
START_RECOGNITION,
START_ENROLL,
} en_fsm_state;
extern en_fsm_state g_state;

View File

@ -0,0 +1,6 @@
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
extern EventGroupHandle_t g_wifi_event_group;
void app_wifi_init();

View File

@ -0,0 +1,6 @@
# Espressif ESP32 Partition Table
# Name, Type, SubType, Offset, Size
factory, app, factory, 0x010000, 3M
nvs, data, nvs, 0x310000, 16K
fr, 32, 32, 0x320000, 128K
1 # Espressif ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size
3 factory, app, factory, 0x010000, 3M
4 nvs, data, nvs, 0x310000, 16K
5 fr, 32, 32, 0x320000, 128K

View File

@ -0,0 +1,97 @@
CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0"
CONFIG_ESPTOOLPY_BAUD_115200B=
CONFIG_ESPTOOLPY_BAUD_230400B=
CONFIG_ESPTOOLPY_BAUD_921600B=y
CONFIG_ESPTOOLPY_BAUD_2MB=
CONFIG_ESPTOOLPY_BAUD_OTHER=
CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
CONFIG_ESPTOOLPY_BAUD=921600
CONFIG_ESPTOOLPY_COMPRESSED=y
CONFIG_FLASHMODE_QIO=y
CONFIG_FLASHMODE_QOUT=
CONFIG_FLASHMODE_DIO=
CONFIG_FLASHMODE_DOUT=
CONFIG_ESPTOOLPY_FLASHMODE="dio"
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ_40M=
CONFIG_ESPTOOLPY_FLASHFREQ_26M=
CONFIG_ESPTOOLPY_FLASHFREQ_20M=
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
CONFIG_ESPTOOLPY_FLASHSIZE_1MB=
CONFIG_ESPTOOLPY_FLASHSIZE_2MB=
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
CONFIG_ESPTOOLPY_BEFORE_RESET=y
CONFIG_ESPTOOLPY_BEFORE_NORESET=
CONFIG_ESPTOOLPY_BEFORE="default_reset"
CONFIG_ESPTOOLPY_AFTER_RESET=y
CONFIG_ESPTOOLPY_AFTER_NORESET=
CONFIG_ESPTOOLPY_AFTER="hard_reset"
CONFIG_MONITOR_BAUD_9600B=
CONFIG_MONITOR_BAUD_57600B=
CONFIG_MONITOR_BAUD_115200B=y
CONFIG_MONITOR_BAUD_230400B=
CONFIG_MONITOR_BAUD_921600B=
CONFIG_MONITOR_BAUD_2MB=
CONFIG_MONITOR_BAUD_OTHER=
CONFIG_MONITOR_BAUD_OTHER_VAL=115200
CONFIG_MONITOR_BAUD=115200
#
# Partition Table
#
CONFIG_PARTITION_TABLE_SINGLE_APP=
CONFIG_PARTITION_TABLE_TWO_OTA=
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
#
# Camera configuration
#
CONFIG_ENABLE_TEST_PATTERN=
CONFIG_OV2640_SUPPORT=y
CONFIG_OV7725_SUPPORT=
#
# ESP32-specific
#
CONFIG_ESP32_DEFAULT_CPU_FREQ_80=
CONFIG_ESP32_DEFAULT_CPU_FREQ_160=
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_TYPE_AUTO=y
CONFIG_SPIRAM_TYPE_ESPPSRAM32=
CONFIG_SPIRAM_TYPE_ESPPSRAM64=
CONFIG_SPIRAM_SIZE=-1
CONFIG_SPIRAM_SPEED_40M=
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_CACHE_WORKAROUND=y
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=3096
CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST=
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=
CONFIG_SPIRAM_OCCUPY_HSPI_HOST=
CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y
CONFIG_TASK_WDT=
CONFIG_BT_ENABLED=y