Protocomm : Added support for choice of transport - WiFi (SoftAP+HTTPD), BLE, Console (development friendly transport)
Co-Authored-By: Amey Inamdar <amey@espressif.com> Co-Authored-By: Anurag Kar <anurag.kar@espressif.com>
This commit is contained in:
parent
e94dffc9c5
commit
9428375368
|
@ -0,0 +1,25 @@
|
|||
set(COMPONENT_ADD_INCLUDEDIRS include/common
|
||||
include/security
|
||||
include/transports)
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS proto-c src/common src/simple_ble)
|
||||
set(COMPONENT_SRCS "src/common/protocomm.c"
|
||||
"src/security/security0.c"
|
||||
"src/security/security1.c"
|
||||
"proto-c/constants.pb-c.c"
|
||||
"proto-c/sec0.pb-c.c"
|
||||
"proto-c/sec1.pb-c.c"
|
||||
"proto-c/session.pb-c.c"
|
||||
"src/transports/protocomm_console.c"
|
||||
"src/transports/protocomm_httpd.c")
|
||||
|
||||
set(COMPONENT_PRIV_REQUIRES protobuf-c mbedtls console http_server bt)
|
||||
|
||||
if(CONFIG_BT_ENABLED)
|
||||
if(CONFIG_BLUEDROID_ENABLED)
|
||||
list(APPEND COMPONENT_SRCS
|
||||
"src/simple_ble/simple_ble.c"
|
||||
"src/transports/protocomm_ble.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
register_component()
|
|
@ -1,3 +1,7 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := include/common include/security proto-c
|
||||
COMPONENT_PRIV_INCLUDEDIRS := src/common
|
||||
COMPONENT_SRCDIRS := src/common src/security proto-c
|
||||
COMPONENT_ADD_INCLUDEDIRS := include/common include/security include/transports
|
||||
COMPONENT_PRIV_INCLUDEDIRS := proto-c src/common src/simple_ble
|
||||
COMPONENT_SRCDIRS := src/common src/security proto-c src/simple_ble src/transports
|
||||
|
||||
ifneq ($(filter y, $(CONFIG_BT_ENABLED) $(CONFIG_BLUEDROID_ENABLED)),y y)
|
||||
COMPONENT_OBJEXCLUDE := src/simple_ble/simple_ble.o src/transports/protocomm_ble.o
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
|
||||
/**
|
||||
* BLE device name cannot be larger than this value
|
||||
*/
|
||||
#define MAX_BLE_DEVNAME_LEN 13
|
||||
|
||||
/**
|
||||
* @brief This structure maps handler required by protocomm layer to
|
||||
* UUIDs which are used to uniquely identify BLE characteristics
|
||||
* from a smartphone or a similar client device.
|
||||
*/
|
||||
typedef struct name_uuid {
|
||||
/**
|
||||
* Name of the handler, which is passed to protocomm layer
|
||||
*/
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* UUID to be assigned to the BLE characteristic which is
|
||||
* mapped to the handler
|
||||
*/
|
||||
uint16_t uuid;
|
||||
} protocomm_ble_name_uuid_t;
|
||||
|
||||
/**
|
||||
* @brief Config parameters for protocomm BLE service
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* BLE device name being broadcast at the time of provisioning
|
||||
*/
|
||||
char device_name[MAX_BLE_DEVNAME_LEN];
|
||||
uint8_t service_uuid[16]; /*!< SSID of the provisioning service */
|
||||
ssize_t nu_lookup_count; /*!< Number of entries in the Name-UUID lookup table */
|
||||
|
||||
/**
|
||||
* Pointer to the Name-UUID lookup table
|
||||
*/
|
||||
protocomm_ble_name_uuid_t *nu_lookup;
|
||||
} protocomm_ble_config_t;
|
||||
|
||||
/**
|
||||
* @brief Start Bluetooth Low Energy based transport layer for provisioning
|
||||
*
|
||||
* Initialize and start required BLE service for provisioning. This includes
|
||||
* the initialization for characteristics/service for BLE.
|
||||
*
|
||||
* @param[in] pc Protocomm instance pointer obtained from protocomm_new()
|
||||
* @param[in] config Pointer to config structure for initialising BLE
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : if successful
|
||||
* - ESP_FAIL : Simple BLE start error
|
||||
* - ESP_ERR_NO_MEM : Error allocating memory for internal resources
|
||||
* - ESP_ERR_INVALID_STATE : Error in ble config
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
*/
|
||||
esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Stop Bluetooth Low Energy based transport layer for provisioning
|
||||
*
|
||||
* Stops service/task responsible for BLE based interactions for provisioning
|
||||
*
|
||||
* @note You might want to optionally reclaim memory from Bluetooth.
|
||||
* Refer to the documentation of `esp_bt_mem_release` in that case.
|
||||
*
|
||||
* @param[in] pc Same protocomm instance that was passed to protocomm_ble_start()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : For success or appropriate error code
|
||||
* - ESP_FAIL : Simple BLE stop error
|
||||
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance
|
||||
*/
|
||||
esp_err_t protocomm_ble_stop(protocomm_t *pc);
|
|
@ -0,0 +1,59 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
|
||||
#define PROTOCOMM_CONSOLE_DEFAULT_CONFIG() { \
|
||||
.stack_size = 4096, \
|
||||
.task_priority = tskIDLE_PRIORITY + 3, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Config parameters for protocomm console
|
||||
*/
|
||||
typedef struct {
|
||||
size_t stack_size; /*!< Stack size of console taks */
|
||||
unsigned task_priority; /*!< Priority of console task */
|
||||
} protocomm_console_config_t;
|
||||
|
||||
/**
|
||||
* @brief Start console based protocomm transport
|
||||
*
|
||||
* @note This is a singleton. ie. Protocomm can have multiple instances, but only
|
||||
* one instance can be bound to a console based transport layer.
|
||||
*
|
||||
* @param[in] pc Protocomm instance pointer obtained from protocomm_new()
|
||||
* @param[in] config Config param structure for protocomm console
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Server started succefully
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
|
||||
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance
|
||||
* - ESP_FAIL : Failed to start console thread
|
||||
*/
|
||||
esp_err_t protocomm_console_start(protocomm_t *pc, const protocomm_console_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Stop console protocomm transport
|
||||
*
|
||||
* @param[in] pc Same protocomm instance that was passed to protocomm_console_start()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Server stopped succefully
|
||||
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
|
||||
*/
|
||||
esp_err_t protocomm_console_stop(protocomm_t *pc);
|
|
@ -0,0 +1,73 @@
|
|||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
|
||||
#define PROTOCOMM_HTTPD_DEFAULT_CONFIG() { \
|
||||
.port = 80, \
|
||||
.stack_size = 4096, \
|
||||
.task_priority = tskIDLE_PRIORITY + 5, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Config parameters for protocomm HTTP server
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t port; /*!< Port on which the http server will listen */
|
||||
|
||||
/**
|
||||
* Stack size of server task, adjusted depending
|
||||
* upon stack usage of endpoint handler
|
||||
*/
|
||||
size_t stack_size;
|
||||
unsigned task_priority; /*!< Priority of server task */
|
||||
} protocomm_httpd_config_t;
|
||||
|
||||
/**
|
||||
* @brief Start HTTPD protocomm transport
|
||||
*
|
||||
* This API internally creates a framework to allow endpoint registration and security
|
||||
* configuration for the protocomm.
|
||||
*
|
||||
* @note This is a singleton. ie. Protocomm can have multiple instances, but only
|
||||
* one instance can be bound to an HTTP transport layer.
|
||||
*
|
||||
* @param[in] pc Protocomm instance pointer obtained from protocomm_new()
|
||||
* @param[in] config Pointer to config structure for initialising HTTP server
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Server started succefully
|
||||
* - ESP_ERR_INVALID_ARG : Null arguments
|
||||
* - ESP_ERR_NOT_SUPPORTED : Transport layer bound to another protocomm instance
|
||||
* - ESP_ERR_INVALID_STATE : Transport layer already bound to this protocomm instance
|
||||
* - ESP_ERR_NO_MEM : Memory allocation for server resource failed
|
||||
* - ESP_ERR_HTTPD_* : HTTP server error on start
|
||||
*/
|
||||
esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Stop HTTPD protocomm transport
|
||||
*
|
||||
* This API cleans up the HTTPD transport protocomm and frees all the handlers registered
|
||||
* with the protocomm.
|
||||
*
|
||||
* @param[in] pc Same protocomm instance that was passed to protocomm_httpd_start()
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Server stopped succefully
|
||||
* - ESP_ERR_INVALID_ARG : Null / incorrect protocomm instance pointer
|
||||
*/
|
||||
esp_err_t protocomm_httpd_stop(protocomm_t *pc);
|
|
@ -0,0 +1,268 @@
|
|||
// Copyright 2015-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.
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_bt.h>
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gatts_api.h>
|
||||
#include <esp_bt_main.h>
|
||||
#include <esp_gatt_common_api.h>
|
||||
|
||||
#include "simple_ble.h"
|
||||
|
||||
#define SIMPLE_BLE_MAX_GATT_TABLE_SIZE 20
|
||||
|
||||
static const char *TAG = "simple_ble";
|
||||
|
||||
static simple_ble_cfg_t *g_ble_cfg_p;
|
||||
static uint16_t g_gatt_table_map[SIMPLE_BLE_MAX_GATT_TABLE_SIZE];
|
||||
|
||||
uint16_t simple_ble_get_uuid(uint16_t handle)
|
||||
{
|
||||
uint16_t *uuid_ptr;
|
||||
|
||||
for (int i = 0; i < SIMPLE_BLE_MAX_GATT_TABLE_SIZE; i++) {
|
||||
if (g_gatt_table_map[i] == handle) {
|
||||
uuid_ptr = (uint16_t *) g_ble_cfg_p->gatt_db[i].att_desc.uuid_p;
|
||||
return *uuid_ptr;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void 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(&g_ble_cfg_p->adv_params);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t p_gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
static esp_gatt_if_t gatts_if = ESP_GATT_IF_NONE;
|
||||
esp_err_t ret;
|
||||
uint8_t service_instance_id = 0;
|
||||
if (event == ESP_GATTS_REG_EVT) {
|
||||
if (param->reg.status == ESP_GATT_OK) {
|
||||
gatts_if = p_gatts_if;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "reg app failed, app_id 0x0x%x, status %d",
|
||||
param->reg.app_id,
|
||||
param->reg.status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gatts_if != ESP_GATT_IF_NONE && gatts_if != p_gatts_if) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case ESP_GATTS_REG_EVT:
|
||||
ret = esp_ble_gatts_create_attr_tab(g_ble_cfg_p->gatt_db, gatts_if, g_ble_cfg_p->gatt_db_count, service_instance_id);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "create attr table failed, error code = 0x%x", ret);
|
||||
return;
|
||||
}
|
||||
ret = esp_ble_gap_set_device_name(g_ble_cfg_p->device_name);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "set device name failed, error code = 0x%x", ret);
|
||||
return;
|
||||
}
|
||||
ret = esp_ble_gap_config_adv_data(&g_ble_cfg_p->adv_data);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "config adv data failed, error code = 0x%x", ret);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_READ_EVT:
|
||||
g_ble_cfg_p->read_fn(event, gatts_if, param);
|
||||
break;
|
||||
case ESP_GATTS_WRITE_EVT:
|
||||
g_ble_cfg_p->write_fn(event, gatts_if, param);
|
||||
break;
|
||||
case ESP_GATTS_EXEC_WRITE_EVT:
|
||||
g_ble_cfg_p->exec_write_fn(event, gatts_if, param);
|
||||
break;
|
||||
case ESP_GATTS_MTU_EVT:
|
||||
ESP_LOGV(TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
|
||||
if (g_ble_cfg_p->set_mtu_fn) {
|
||||
g_ble_cfg_p->set_mtu_fn(event, gatts_if, param);
|
||||
}
|
||||
break;
|
||||
case ESP_GATTS_CONF_EVT:
|
||||
ESP_LOGD(TAG, "ESP_GATTS_CONF_EVT, status = %d", param->conf.status);
|
||||
break;
|
||||
case ESP_GATTS_START_EVT:
|
||||
ESP_LOGD(TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
|
||||
break;
|
||||
case ESP_GATTS_CONNECT_EVT:
|
||||
ESP_LOGD(TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
|
||||
g_ble_cfg_p->connect_fn(event, gatts_if, param);
|
||||
esp_ble_conn_update_params_t conn_params = {0};
|
||||
memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
|
||||
/* For the iOS system, please refer the official Apple documents about BLE connection parameters restrictions. */
|
||||
conn_params.latency = 0;
|
||||
conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
|
||||
conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
|
||||
conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
|
||||
esp_ble_gap_update_conn_params(&conn_params);
|
||||
break;
|
||||
case ESP_GATTS_DISCONNECT_EVT:
|
||||
ESP_LOGD(TAG, "ESP_GATTS_DISCONNECT_EVT, reason = %d", param->disconnect.reason);
|
||||
g_ble_cfg_p->disconnect_fn(event, gatts_if, param);
|
||||
esp_ble_gap_start_advertising(&g_ble_cfg_p->adv_params);
|
||||
break;
|
||||
case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
|
||||
if (param->add_attr_tab.status != ESP_GATT_OK) {
|
||||
ESP_LOGE(TAG, "creating the attribute table failed, error code=0x%x", param->add_attr_tab.status);
|
||||
} else if (param->add_attr_tab.num_handle != g_ble_cfg_p->gatt_db_count) {
|
||||
ESP_LOGE(TAG, "created attribute table abnormally ");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "created attribute table successfully, the number handle = %d", param->add_attr_tab.num_handle);
|
||||
memcpy(g_gatt_table_map, param->add_attr_tab.handles, param->add_attr_tab.num_handle * sizeof(g_gatt_table_map[0]));
|
||||
/* We assume, for now, that the first entry is always the index to the 'service' definition */
|
||||
esp_ble_gatts_start_service(g_gatt_table_map[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GATTS_STOP_EVT:
|
||||
case ESP_GATTS_OPEN_EVT:
|
||||
case ESP_GATTS_CANCEL_OPEN_EVT:
|
||||
case ESP_GATTS_CLOSE_EVT:
|
||||
case ESP_GATTS_LISTEN_EVT:
|
||||
case ESP_GATTS_CONGEST_EVT:
|
||||
case ESP_GATTS_UNREG_EVT:
|
||||
case ESP_GATTS_DELETE_EVT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
simple_ble_cfg_t *simple_ble_init()
|
||||
{
|
||||
simple_ble_cfg_t *ble_cfg_p = (simple_ble_cfg_t *) malloc(sizeof(simple_ble_cfg_t));
|
||||
if (ble_cfg_p == NULL) {
|
||||
ESP_LOGE(TAG, "No memory for simple_ble_cfg_t");
|
||||
return NULL;
|
||||
}
|
||||
return ble_cfg_p;
|
||||
}
|
||||
|
||||
esp_err_t simple_ble_deinit()
|
||||
{
|
||||
free(g_ble_cfg_p->gatt_db);
|
||||
free(g_ble_cfg_p);
|
||||
g_ble_cfg_p = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Expects the pointer stays valid throughout */
|
||||
esp_err_t simple_ble_start(simple_ble_cfg_t *cfg)
|
||||
{
|
||||
g_ble_cfg_p = cfg;
|
||||
ESP_LOGD(TAG, "Free mem at start of simple_ble_init %d", esp_get_free_heap_size());
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed %d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed %d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s init bluetooth failed %d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable bluetooth failed %d", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_ble_gatts_register_callback(gatts_profile_event_handler);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "gatts register error, error code = 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_register_callback(gap_event_handler);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "gap register error, error code = 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t app_id = 0x55;
|
||||
ret = esp_ble_gatts_app_register(app_id);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "gatts app register error, error code = 0x%x", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
|
||||
if (local_mtu_ret) {
|
||||
ESP_LOGE(TAG, "set local MTU failed, error code = 0x%x", local_mtu_ret);
|
||||
}
|
||||
ESP_LOGD(TAG, "Free mem at end of simple_ble_init %d", esp_get_free_heap_size());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t simple_ble_stop()
|
||||
{
|
||||
esp_err_t err;
|
||||
ESP_LOGD(TAG, "Free mem at start of simple_ble_stop %d", esp_get_free_heap_size());
|
||||
err = esp_bluedroid_disable();
|
||||
if (err != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGD(TAG, "esp_bluedroid_disable called successfully");
|
||||
err = esp_bluedroid_deinit();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
ESP_LOGD(TAG, "esp_bluedroid_deinit called successfully");
|
||||
err = esp_bt_controller_disable();
|
||||
if (err != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* The API `esp_bt_controller_deinit` will have to be removed when we add support for
|
||||
* `reset to provisioning`
|
||||
*/
|
||||
ESP_LOGD(TAG, "esp_bt_controller_disable called successfully");
|
||||
err = esp_bt_controller_deinit();
|
||||
if (err != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGD(TAG, "esp_bt_controller_deinit called successfully");
|
||||
|
||||
ESP_LOGD(TAG, "Free mem at end of simple_ble_stop %d", esp_get_free_heap_size());
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2015-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 _SIMPLE_BLE_
|
||||
#define _SIMPLE_BLE_
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <esp_gap_ble_api.h>
|
||||
#include <esp_gatts_api.h>
|
||||
|
||||
typedef void (simple_ble_cb_t)(esp_gatts_cb_event_t event, esp_gatt_if_t p_gatts_if, esp_ble_gatts_cb_param_t *param);
|
||||
|
||||
/**
|
||||
* This structure is populated with the details required
|
||||
* to create an instance of BLE easily. It requires function
|
||||
* pointers, advertising parameters and gatt description table
|
||||
*/
|
||||
typedef struct {
|
||||
/** Name to be displayed to devices scanning for ESP32 */
|
||||
const char *device_name;
|
||||
/** Advertising data content, according to "Supplement to the Bluetooth Core Specification" */
|
||||
esp_ble_adv_data_t adv_data;
|
||||
/** Parameters to configure the nature of advertising */
|
||||
esp_ble_adv_params_t adv_params;
|
||||
/** Descriptor table which consists the configuration required by services and characteristics */
|
||||
esp_gatts_attr_db_t *gatt_db;
|
||||
/** Number of entries in the gatt_db descriptor table */
|
||||
ssize_t gatt_db_count;
|
||||
/** BLE read callback */
|
||||
simple_ble_cb_t *read_fn;
|
||||
/** BLE write callback */
|
||||
simple_ble_cb_t *write_fn;
|
||||
/** BLE exec write callback */
|
||||
simple_ble_cb_t *exec_write_fn;
|
||||
/** Client disconnect callback */
|
||||
simple_ble_cb_t *disconnect_fn;
|
||||
/** Client connect callback */
|
||||
simple_ble_cb_t *connect_fn;
|
||||
/** MTU set callback */
|
||||
simple_ble_cb_t *set_mtu_fn;
|
||||
} simple_ble_cfg_t;
|
||||
|
||||
|
||||
/** Initialise a simple ble connection
|
||||
*
|
||||
* This function allocates memory and returns a pointer to the
|
||||
* configuration structure.
|
||||
*
|
||||
* @return simple_ble_cfg_t* Pointer to configuration structure
|
||||
*/
|
||||
simple_ble_cfg_t *simple_ble_init();
|
||||
|
||||
/** Deallocates memory
|
||||
*
|
||||
* This function deallocate memory of the configuration structure.
|
||||
*
|
||||
* @return ESP_OK
|
||||
*/
|
||||
esp_err_t simple_ble_deinit();
|
||||
|
||||
/** Starts BLE service
|
||||
*
|
||||
* This function makes calls to the GATT and GAP APIs
|
||||
* to initialize the BLE service as per parameters stored
|
||||
* in the config structure. At the end of this function,
|
||||
* one should be able to scan and connect to the ESP32 device
|
||||
* using BLE.
|
||||
* This API sets the MTU size to 500 (this is not part of the config structure)
|
||||
*
|
||||
* @return ESP_OK on success, and appropriate error code for failure
|
||||
*/
|
||||
esp_err_t simple_ble_start(simple_ble_cfg_t *cfg);
|
||||
|
||||
/** Stops the BLE service
|
||||
*
|
||||
* This API is called to stop the BLE service.
|
||||
* This includes calls to disable and deinit bluedroid and bt controller.
|
||||
*
|
||||
* @return ESP_OK on success, and appropriate error code for failure
|
||||
*/
|
||||
esp_err_t simple_ble_stop();
|
||||
|
||||
/** Convert handle to UUID of characteristic
|
||||
*
|
||||
* This function can be easily used to get the corresponding
|
||||
* UUID for a characteristic that has been created, and the one for
|
||||
* which we only have the handle for.
|
||||
*
|
||||
* @return uuid the UUID of the handle, -1 in case of invalid handle
|
||||
*/
|
||||
uint16_t simple_ble_get_uuid(uint16_t handle);
|
||||
|
||||
#endif /* _SIMPLE_BLE_ */
|
|
@ -0,0 +1,510 @@
|
|||
// 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.
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_gatt_common_api.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
|
||||
#include "protocomm_priv.h"
|
||||
#include "simple_ble.h"
|
||||
|
||||
#define CHAR_VAL_LEN_MAX (256 + 1)
|
||||
#define PREPARE_BUF_MAX_SIZE CHAR_VAL_LEN_MAX
|
||||
|
||||
static const char *TAG = "protocomm_ble";
|
||||
|
||||
/* BLE specific configuration parameters */
|
||||
const uint16_t GATTS_SERVICE_UUID_PROV = 0xFFFF;
|
||||
const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
|
||||
const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
|
||||
const uint8_t char_prop_read_write = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *prepare_buf;
|
||||
int prepare_len;
|
||||
uint16_t handle;
|
||||
} prepare_type_env_t;
|
||||
|
||||
static prepare_type_env_t prepare_write_env;
|
||||
|
||||
typedef struct _protocomm_ble {
|
||||
protocomm_t *pc_ble;
|
||||
protocomm_ble_name_uuid_t *g_nu_lookup;
|
||||
ssize_t g_nu_lookup_count;
|
||||
uint16_t gatt_mtu;
|
||||
} _protocomm_ble_internal_t;
|
||||
|
||||
static _protocomm_ble_internal_t *protoble_internal;
|
||||
|
||||
static esp_ble_adv_params_t adv_params = {
|
||||
.adv_int_min = 0x100,
|
||||
.adv_int_max = 0x100,
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
static char* protocomm_ble_device_name = NULL;
|
||||
|
||||
/* The length of adv data must be less than 31 bytes */
|
||||
static esp_ble_adv_data_t adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x100,
|
||||
.max_interval = 0x100,
|
||||
.appearance = ESP_BLE_APPEARANCE_UNKNOWN,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
.service_data_len = 0,
|
||||
.p_service_data = NULL,
|
||||
.service_uuid_len = 0,
|
||||
.p_service_uuid = NULL,
|
||||
.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
|
||||
};
|
||||
|
||||
static void hexdump(const char *msg, uint8_t *buf, int len)
|
||||
{
|
||||
ESP_LOGD(TAG, "%s:", msg);
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, len, ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
static const char *handle_to_handler(uint16_t handle)
|
||||
{
|
||||
uint16_t uuid = simple_ble_get_uuid(handle);
|
||||
for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
|
||||
if (protoble_internal->g_nu_lookup[i].uuid == uuid ) {
|
||||
return protoble_internal->g_nu_lookup[i].name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
static const uint8_t *read_buf = NULL;
|
||||
static uint16_t read_len = 0;
|
||||
esp_gatt_status_t status = ESP_OK;
|
||||
|
||||
ESP_LOGD(TAG, "Inside read w/ session - %d on param %d %d",
|
||||
param->read.conn_id, param->read.handle, read_len);
|
||||
if (!read_len) {
|
||||
ESP_LOGD(TAG, "Reading attr value first time");
|
||||
status = esp_ble_gatts_get_attr_value(param->read.handle, &read_len, &read_buf);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Subsequent read request for attr value");
|
||||
}
|
||||
|
||||
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *) malloc(sizeof(esp_gatt_rsp_t));
|
||||
if (gatt_rsp != NULL) {
|
||||
gatt_rsp->attr_value.len = MIN(read_len, (protoble_internal->gatt_mtu - 1));
|
||||
if (read_len && read_buf) {
|
||||
memcpy(gatt_rsp->attr_value.value,
|
||||
read_buf + param->read.offset,
|
||||
gatt_rsp->attr_value.len);
|
||||
}
|
||||
read_len -= gatt_rsp->attr_value.len;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s, malloc failed", __func__);
|
||||
return;
|
||||
}
|
||||
esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
|
||||
param->read.trans_id, status, gatt_rsp);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Send response error in read");
|
||||
}
|
||||
free(gatt_rsp);
|
||||
}
|
||||
|
||||
static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if,
|
||||
esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGD(TAG, "prepare write, handle = %d, value len = %d",
|
||||
param->write.handle, param->write.len);
|
||||
esp_gatt_status_t status = ESP_GATT_OK;
|
||||
if (prepare_write_env.prepare_buf == NULL) {
|
||||
prepare_write_env.prepare_buf = (uint8_t *) malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
|
||||
if (prepare_write_env.prepare_buf == NULL) {
|
||||
ESP_LOGE(TAG, "%s , failed tp allocate preparebuf", __func__);
|
||||
status = ESP_GATT_NO_RESOURCES;
|
||||
}
|
||||
/* prepare_write_env.prepare_len = 0; */
|
||||
} else {
|
||||
if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
|
||||
status = ESP_GATT_INVALID_OFFSET;
|
||||
} else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
|
||||
status = ESP_GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
}
|
||||
memcpy(prepare_write_env.prepare_buf + param->write.offset,
|
||||
param->write.value,
|
||||
param->write.len);
|
||||
prepare_write_env.prepare_len += param->write.len;
|
||||
prepare_write_env.handle = param->write.handle;
|
||||
if (param->write.need_rsp) {
|
||||
esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *) malloc(sizeof(esp_gatt_rsp_t));
|
||||
if (gatt_rsp != NULL) {
|
||||
gatt_rsp->attr_value.len = param->write.len;
|
||||
gatt_rsp->attr_value.handle = param->write.handle;
|
||||
gatt_rsp->attr_value.offset = param->write.offset;
|
||||
gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
|
||||
memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
|
||||
esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id,
|
||||
param->write.trans_id, status,
|
||||
gatt_rsp);
|
||||
if (response_err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Send response error in prep write");
|
||||
}
|
||||
free(gatt_rsp);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s, malloc failed", __func__);
|
||||
}
|
||||
}
|
||||
if (status != ESP_GATT_OK) {
|
||||
if (prepare_write_env.prepare_buf) {
|
||||
free(prepare_write_env.prepare_buf);
|
||||
prepare_write_env.prepare_buf = NULL;
|
||||
prepare_write_env.prepare_len = 0;
|
||||
}
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void transport_simple_ble_write(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
uint8_t *outbuf = NULL;
|
||||
ssize_t outlen = 0;
|
||||
esp_err_t ret;
|
||||
|
||||
ESP_LOGD(TAG, "Inside write with session - %d on attr handle - %d \nLen -%d IS Prep - %d",
|
||||
param->write.conn_id, param->write.handle, param->write.len, param->write.is_prep);
|
||||
|
||||
if (param->write.is_prep) {
|
||||
ret = prepare_write_event_env(gatts_if, param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error appending to prepare buffer");
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "is_prep not set");
|
||||
}
|
||||
|
||||
ret = protocomm_req_handle(protoble_internal->pc_ble,
|
||||
handle_to_handler(param->write.handle),
|
||||
param->exec_write.conn_id,
|
||||
param->write.value,
|
||||
param->write.len,
|
||||
&outbuf, &outlen);
|
||||
if (ret == ESP_OK) {
|
||||
ret = esp_ble_gatts_set_attr_value(param->write.handle, outlen, outbuf);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set the session attribute value");
|
||||
}
|
||||
ret = esp_ble_gatts_send_response(gatts_if, param->write.conn_id,
|
||||
param->write.trans_id, ESP_GATT_OK, NULL);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Send response error in write");
|
||||
}
|
||||
hexdump("Response from write", outbuf, outlen);
|
||||
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid content received, killing connection");
|
||||
esp_ble_gatts_close(gatts_if, param->write.conn_id);
|
||||
}
|
||||
if (outbuf) {
|
||||
free(outbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint8_t *outbuf = NULL;
|
||||
ssize_t outlen = 0;
|
||||
ESP_LOGD(TAG, "Inside exec_write w/ session - %d", param->exec_write.conn_id);
|
||||
|
||||
if ((param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC)
|
||||
&&
|
||||
prepare_write_env.prepare_buf) {
|
||||
err = protocomm_req_handle(protoble_internal->pc_ble,
|
||||
handle_to_handler(prepare_write_env.handle),
|
||||
param->exec_write.conn_id,
|
||||
prepare_write_env.prepare_buf,
|
||||
prepare_write_env.prepare_len,
|
||||
&outbuf, &outlen);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Invalid content received, killing connection");
|
||||
esp_ble_gatts_close(gatts_if, param->write.conn_id);
|
||||
} else {
|
||||
hexdump("Response from exec write", outbuf, outlen);
|
||||
esp_ble_gatts_set_attr_value(prepare_write_env.handle, outlen, outbuf);
|
||||
}
|
||||
}
|
||||
if (prepare_write_env.prepare_buf) {
|
||||
free(prepare_write_env.prepare_buf);
|
||||
prepare_write_env.prepare_buf = NULL;
|
||||
prepare_write_env.prepare_len = 0;
|
||||
}
|
||||
|
||||
err = esp_ble_gatts_send_response(gatts_if, param->exec_write.conn_id, param->exec_write.trans_id, ESP_GATT_OK, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Send response error in exec write");
|
||||
}
|
||||
if (outbuf) {
|
||||
free(outbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGV(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id);
|
||||
if (protoble_internal->pc_ble->sec &&
|
||||
protoble_internal->pc_ble->sec->close_transport_session) {
|
||||
ret = protoble_internal->pc_ble->sec->close_transport_session(param->disconnect.conn_id);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error closing the session after disconnect");
|
||||
}
|
||||
}
|
||||
protoble_internal->gatt_mtu = ESP_GATT_DEF_BLE_MTU_SIZE;
|
||||
}
|
||||
|
||||
static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ESP_LOGV(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id);
|
||||
if (protoble_internal->pc_ble->sec &&
|
||||
protoble_internal->pc_ble->sec->new_transport_session) {
|
||||
ret = protoble_internal->pc_ble->sec->new_transport_session(param->connect.conn_id);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "error creating the session");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transport_simple_ble_set_mtu(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
|
||||
{
|
||||
protoble_internal->gatt_mtu = param->mtu.mtu;
|
||||
return;
|
||||
}
|
||||
|
||||
static esp_err_t protocomm_ble_add_endpoint(const char *ep_name,
|
||||
protocomm_req_handler_t req_handler,
|
||||
void *priv_data)
|
||||
{
|
||||
/* Endpoint UUID already added when protocomm_ble_start() was called */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t protocomm_ble_remove_endpoint(const char *ep_name)
|
||||
{
|
||||
/* Endpoint UUID will be removed when protocomm_ble_stop() is called */
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t populate_gatt_db(esp_gatts_attr_db_t **gatt_db_generated)
|
||||
{
|
||||
int i;
|
||||
/* We need esp_gatts_attr_db_t of size 2 * number of handlers + 1 for service */
|
||||
ssize_t gatt_db_generated_entries = 2 * protoble_internal->g_nu_lookup_count + 1;
|
||||
|
||||
*gatt_db_generated = (esp_gatts_attr_db_t *) malloc(sizeof(esp_gatts_attr_db_t) *
|
||||
(gatt_db_generated_entries));
|
||||
if ((*gatt_db_generated) == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to assign memory to gatt_db");
|
||||
return -1;
|
||||
}
|
||||
/* Declare service */
|
||||
(*gatt_db_generated)[0].attr_control.auto_rsp = ESP_GATT_RSP_BY_APP;
|
||||
|
||||
(*gatt_db_generated)[0].att_desc.uuid_length = ESP_UUID_LEN_16;
|
||||
(*gatt_db_generated)[0].att_desc.uuid_p = (uint8_t *) &primary_service_uuid;
|
||||
(*gatt_db_generated)[0].att_desc.perm = ESP_GATT_PERM_READ;
|
||||
(*gatt_db_generated)[0].att_desc.max_length = sizeof(uint16_t);
|
||||
(*gatt_db_generated)[0].att_desc.length = sizeof(GATTS_SERVICE_UUID_PROV);
|
||||
(*gatt_db_generated)[0].att_desc.value = (uint8_t *) &GATTS_SERVICE_UUID_PROV;
|
||||
|
||||
/* Declare characteristics */
|
||||
for (i = 1 ; i < gatt_db_generated_entries ; i++) {
|
||||
(*gatt_db_generated)[i].attr_control.auto_rsp = ESP_GATT_RSP_BY_APP;
|
||||
|
||||
(*gatt_db_generated)[i].att_desc.uuid_length = ESP_UUID_LEN_16;
|
||||
(*gatt_db_generated)[i].att_desc.perm = ESP_GATT_PERM_READ |
|
||||
ESP_GATT_PERM_WRITE;
|
||||
|
||||
if (i % 2 == 1) { /* Char Declaration */
|
||||
(*gatt_db_generated)[i].att_desc.uuid_p = (uint8_t *) &character_declaration_uuid;
|
||||
(*gatt_db_generated)[i].att_desc.max_length = sizeof(uint8_t);
|
||||
(*gatt_db_generated)[i].att_desc.length = sizeof(uint8_t);
|
||||
(*gatt_db_generated)[i].att_desc.value = (uint8_t *) &char_prop_read_write;
|
||||
} else { /* Char Value */
|
||||
(*gatt_db_generated)[i].att_desc.uuid_p = (uint8_t *)&protoble_internal->g_nu_lookup[i / 2 - 1].uuid;
|
||||
(*gatt_db_generated)[i].att_desc.max_length = CHAR_VAL_LEN_MAX;
|
||||
(*gatt_db_generated)[i].att_desc.length = 0;
|
||||
(*gatt_db_generated)[i].att_desc.value = NULL;
|
||||
}
|
||||
}
|
||||
return gatt_db_generated_entries;
|
||||
}
|
||||
|
||||
static void protocomm_ble_cleanup(void)
|
||||
{
|
||||
if (protoble_internal) {
|
||||
if (protoble_internal->g_nu_lookup) {
|
||||
for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
|
||||
if (protoble_internal->g_nu_lookup[i].name) {
|
||||
free(protoble_internal->g_nu_lookup[i].name);
|
||||
}
|
||||
}
|
||||
free(protoble_internal->g_nu_lookup);
|
||||
}
|
||||
free(protoble_internal);
|
||||
protoble_internal = NULL;
|
||||
}
|
||||
if (protocomm_ble_device_name) {
|
||||
free(protocomm_ble_device_name);
|
||||
protocomm_ble_device_name = NULL;
|
||||
}
|
||||
if (adv_data.p_service_uuid) {
|
||||
free(adv_data.p_service_uuid);
|
||||
adv_data.p_service_uuid = NULL;
|
||||
adv_data.service_uuid_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config)
|
||||
{
|
||||
if (!pc || !config || !config->device_name || !config->nu_lookup) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (protoble_internal) {
|
||||
ESP_LOGE(TAG, "Protocomm BLE already started");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Store service UUID internally */
|
||||
adv_data.service_uuid_len = sizeof(config->service_uuid);
|
||||
adv_data.p_service_uuid = malloc(sizeof(config->service_uuid));
|
||||
if (adv_data.p_service_uuid == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for storing service UUID");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
memcpy(adv_data.p_service_uuid, config->service_uuid, adv_data.service_uuid_len);
|
||||
|
||||
/* Store BLE device name internally */
|
||||
protocomm_ble_device_name = strdup(config->device_name);
|
||||
if (protocomm_ble_device_name == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for storing BLE device name");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t));
|
||||
if (protoble_internal == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating internal protocomm structure");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
protoble_internal->g_nu_lookup_count = config->nu_lookup_count;
|
||||
protoble_internal->g_nu_lookup = malloc(config->nu_lookup_count * sizeof(protocomm_ble_name_uuid_t));
|
||||
if (protoble_internal->g_nu_lookup == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating internal name UUID table");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
|
||||
protoble_internal->g_nu_lookup[i].uuid = config->nu_lookup[i].uuid;
|
||||
protoble_internal->g_nu_lookup[i].name = strdup(config->nu_lookup[i].name);
|
||||
if (protoble_internal->g_nu_lookup[i].name == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating internal name UUID entry");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
}
|
||||
|
||||
pc->add_endpoint = protocomm_ble_add_endpoint;
|
||||
pc->remove_endpoint = protocomm_ble_remove_endpoint;
|
||||
protoble_internal->pc_ble = pc;
|
||||
protoble_internal->gatt_mtu = ESP_GATT_DEF_BLE_MTU_SIZE;
|
||||
|
||||
simple_ble_cfg_t *ble_config = simple_ble_init();
|
||||
if (ble_config == NULL) {
|
||||
ESP_LOGE(TAG, "Ran out of memory for BLE config");
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Set function pointers required for simple BLE layer */
|
||||
ble_config->read_fn = transport_simple_ble_read;
|
||||
ble_config->write_fn = transport_simple_ble_write;
|
||||
ble_config->exec_write_fn = transport_simple_ble_exec_write;
|
||||
ble_config->disconnect_fn = transport_simple_ble_disconnect;
|
||||
ble_config->connect_fn = transport_simple_ble_connect;
|
||||
ble_config->set_mtu_fn = transport_simple_ble_set_mtu;
|
||||
|
||||
/* Set parameters required for advertising */
|
||||
ble_config->adv_data = adv_data;
|
||||
ble_config->adv_params = adv_params;
|
||||
|
||||
ble_config->device_name = protocomm_ble_device_name;
|
||||
ble_config->gatt_db_count = populate_gatt_db(&ble_config->gatt_db);
|
||||
|
||||
if (ble_config->gatt_db_count == -1) {
|
||||
ESP_LOGE(TAG, "Invalid GATT database count");
|
||||
simple_ble_deinit();
|
||||
protocomm_ble_cleanup();
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
esp_err_t err = simple_ble_start(ble_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "simple_ble_start failed w/ error code 0x%x", err);
|
||||
simple_ble_deinit();
|
||||
protocomm_ble_cleanup();
|
||||
return err;
|
||||
}
|
||||
|
||||
prepare_write_env.prepare_buf = NULL;
|
||||
ESP_LOGV(TAG, "Waiting for client to connect ......");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t protocomm_ble_stop(protocomm_t *pc)
|
||||
{
|
||||
if ((pc != NULL) &&
|
||||
(protoble_internal != NULL ) &&
|
||||
(pc == protoble_internal->pc_ble)) {
|
||||
esp_err_t ret = ESP_OK;
|
||||
ret = simple_ble_stop();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "BLE stop failed");
|
||||
}
|
||||
simple_ble_deinit();
|
||||
protocomm_ble_cleanup();
|
||||
return ret;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
// 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.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_console.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <driver/uart.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
|
||||
#include "protocomm_priv.h"
|
||||
|
||||
static const char *TAG = "protocomm_console";
|
||||
|
||||
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
|
||||
static protocomm_t *pc_console = NULL; /* The global protocomm instance for console */
|
||||
static TaskHandle_t console_task = NULL;
|
||||
|
||||
esp_err_t protocomm_console_stop(protocomm_t *pc)
|
||||
{
|
||||
if (pc != pc_console) {
|
||||
ESP_LOGE(TAG, "Incorrect stop request");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stopping console...");
|
||||
xTaskNotifyGive(console_task);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static ssize_t hex2bin(const char *hexstr, uint8_t *bytes)
|
||||
{
|
||||
size_t hexstrLen = strlen(hexstr);
|
||||
ssize_t bytesLen = hexstrLen / 2;
|
||||
|
||||
int count = 0;
|
||||
const char *pos = hexstr;
|
||||
|
||||
for(count = 0; count < bytesLen; count++) {
|
||||
sscanf(pos, "%2hhx", &bytes[count]);
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
return bytesLen;
|
||||
}
|
||||
|
||||
static bool stopped(void)
|
||||
{
|
||||
uint32_t flag = 0;
|
||||
xTaskNotifyWait(0, 0, &flag, (TickType_t) 10/portTICK_RATE_MS);
|
||||
return (flag != 0);
|
||||
}
|
||||
|
||||
static void protocomm_console_task(void *arg)
|
||||
{
|
||||
int uart_num = (int) arg;
|
||||
uint8_t linebuf[256];
|
||||
int i, cmd_ret;
|
||||
esp_err_t ret;
|
||||
QueueHandle_t uart_queue;
|
||||
uart_event_t event;
|
||||
|
||||
ESP_LOGV(TAG, "Initialising UART on port %d", uart_num);
|
||||
uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0);
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = {
|
||||
.max_cmdline_args = 8,
|
||||
.max_cmdline_length = 256,
|
||||
};
|
||||
|
||||
esp_console_init(&console_config);
|
||||
esp_console_register_help_command();
|
||||
|
||||
while (!stopped()) {
|
||||
uart_write_bytes(uart_num, "\n>> ", 4);
|
||||
memset(linebuf, 0, sizeof(linebuf));
|
||||
i = 0;
|
||||
do {
|
||||
ret = xQueueReceive(uart_queue, (void * )&event, (TickType_t) 10/portTICK_RATE_MS);
|
||||
if (ret != pdPASS) {
|
||||
if (stopped()) {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (event.type == UART_DATA) {
|
||||
while (uart_read_bytes(uart_num, (uint8_t *) &linebuf[i], 1, 0)) {
|
||||
if (linebuf[i] == '\r') {
|
||||
uart_write_bytes(uart_num, "\r\n", 2);
|
||||
} else {
|
||||
uart_write_bytes(uart_num, (char *) &linebuf[i], 1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} while ((i < 255) && linebuf[i-1] != '\r');
|
||||
if (stopped()) {
|
||||
break;
|
||||
}
|
||||
ret = esp_console_run((char *) linebuf, &cmd_ret);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "Console dispatcher error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pc_console->sec && pc_console->sec->cleanup) {
|
||||
pc_console->sec->cleanup();
|
||||
}
|
||||
|
||||
pc_console = NULL;
|
||||
esp_console_deinit();
|
||||
|
||||
ESP_LOGI(TAG, "Console stopped");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static int common_cmd_handler(int argc, char** argv)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
uint32_t cur_session_id = atoi(argv[1]);
|
||||
|
||||
uint8_t *buf = (uint8_t *) malloc(strlen(argv[2]));
|
||||
uint8_t *outbuf;
|
||||
ssize_t outlen;
|
||||
ssize_t len = hex2bin(argv[2], buf);
|
||||
|
||||
if (cur_session_id != session_id) {
|
||||
if (pc_console->sec && pc_console->sec->new_transport_session) {
|
||||
ret = pc_console->sec->new_transport_session(cur_session_id);
|
||||
if (ret == ESP_OK) {
|
||||
session_id = cur_session_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = protocomm_req_handle(pc_console, argv[0], cur_session_id, buf, len, &outbuf, &outlen);
|
||||
free(buf);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
printf("\r\n");
|
||||
for (i = 0; i < outlen; i++) {
|
||||
printf("%02x", outbuf[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
|
||||
/* Transport is responsible for freeing the transmit buffer */
|
||||
free(outbuf);
|
||||
|
||||
return ESP_OK;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t protocomm_console_add_endpoint(const char *ep_name, protocomm_req_handler_t req_handler, void *priv_data)
|
||||
{
|
||||
(void) req_handler;
|
||||
(void) priv_data;
|
||||
|
||||
esp_err_t ret;
|
||||
esp_console_cmd_t cmd;
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
|
||||
cmd.command = ep_name;
|
||||
cmd.help = "";
|
||||
cmd.func = common_cmd_handler;
|
||||
|
||||
ret = esp_console_cmd_register(&cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t protocomm_console_remove_endpoint(const char *ep_name)
|
||||
{
|
||||
/* Command deletion happens internally in esp_console_deinit function */
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t protocomm_console_start(protocomm_t *pc, const protocomm_console_config_t *config)
|
||||
{
|
||||
if (pc == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (pc_console != NULL) {
|
||||
if (pc_console == pc) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
else {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (xTaskCreate(protocomm_console_task, "protocomm_console",
|
||||
config->stack_size, NULL, config->task_priority, &console_task) != pdPASS) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
pc->add_endpoint = protocomm_console_add_endpoint;
|
||||
pc->remove_endpoint = protocomm_console_remove_endpoint;
|
||||
pc_console = pc;
|
||||
return ESP_OK;
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
// 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.
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
|
||||
#include <http_server.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_httpd.h>
|
||||
|
||||
#include "protocomm_priv.h"
|
||||
|
||||
static const char *TAG = "protocomm_httpd";
|
||||
static protocomm_t *pc_httpd; /* The global protocomm instance for HTTPD */
|
||||
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
|
||||
|
||||
#define MAX_REQ_BODY_LEN 4096
|
||||
|
||||
static esp_err_t common_post_handler(httpd_req_t *req)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t *outbuf = NULL;
|
||||
char *req_body = NULL;
|
||||
const char *ep_name = NULL;
|
||||
ssize_t outlen;
|
||||
|
||||
int cur_session_id = httpd_req_to_sockfd(req);
|
||||
|
||||
if (cur_session_id != session_id) {
|
||||
/* Initialise new security session */
|
||||
if (session_id != PROTOCOMM_NO_SESSION_ID) {
|
||||
ESP_LOGV(TAG, "Closing session with ID: %d", session_id);
|
||||
/* Presently HTTP server doesn't support callback on socket closure so
|
||||
* previous session can only be closed when new session is requested */
|
||||
if (pc_httpd->sec && pc_httpd->sec->close_transport_session) {
|
||||
ret = pc_httpd->sec->close_transport_session(session_id);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to close session with ID: %d", session_id);
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
session_id = PROTOCOMM_NO_SESSION_ID;
|
||||
}
|
||||
if (pc_httpd->sec && pc_httpd->sec->new_transport_session) {
|
||||
ret = pc_httpd->sec->new_transport_session(cur_session_id);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to launch new session with ID: %d", cur_session_id);
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
session_id = cur_session_id;
|
||||
ESP_LOGV(TAG, "New session with ID: %d", cur_session_id);
|
||||
}
|
||||
|
||||
if (req->content_len <= 0) {
|
||||
ESP_LOGE(TAG, "Content length not found");
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
} else if (req->content_len > MAX_REQ_BODY_LEN) {
|
||||
ESP_LOGE(TAG, "Request content length should be less than 4kb");
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
req_body = (char *) malloc(req->content_len);
|
||||
if (!req_body) {
|
||||
ESP_LOGE(TAG, "Unable to allocate for request length %d", req->content_len);
|
||||
ret = ESP_ERR_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
size_t recv_size = 0;
|
||||
while (recv_size < req->content_len) {
|
||||
ret = httpd_req_recv(req, req_body + recv_size, req->content_len - recv_size);
|
||||
if (ret < 0) {
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
recv_size += ret;
|
||||
}
|
||||
|
||||
/* Extract the endpoint name from URI string of type "/ep_name" */
|
||||
ep_name = req->uri + 1;
|
||||
|
||||
ret = protocomm_req_handle(pc_httpd, ep_name, session_id,
|
||||
(uint8_t *)req_body, recv_size, &outbuf, &outlen);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Data handler failed");
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = httpd_resp_send(req, (char *)outbuf, outlen);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "HTTP send failed");
|
||||
ret = ESP_FAIL;
|
||||
goto out;
|
||||
}
|
||||
ret = ESP_OK;
|
||||
out:
|
||||
if (req_body) {
|
||||
free(req_body);
|
||||
}
|
||||
if (outbuf) {
|
||||
free(outbuf);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t protocomm_httpd_add_endpoint(const char *ep_name,
|
||||
protocomm_req_handler_t req_handler,
|
||||
void *priv_data)
|
||||
{
|
||||
if (pc_httpd == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Adding endpoint : %s", ep_name);
|
||||
|
||||
/* Construct URI name by prepending '/' to ep_name */
|
||||
char* ep_uri = calloc(1, strlen(ep_name) + 2);
|
||||
if (!ep_uri) {
|
||||
ESP_LOGE(TAG, "Malloc failed for ep uri");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Create URI handler structure */
|
||||
sprintf(ep_uri, "/%s", ep_name);
|
||||
httpd_uri_t config_handler = {
|
||||
.uri = ep_uri,
|
||||
.method = HTTP_POST,
|
||||
.handler = common_post_handler,
|
||||
.user_ctx = NULL
|
||||
};
|
||||
|
||||
/* Register URI handler */
|
||||
esp_err_t err;
|
||||
httpd_handle_t *server = (httpd_handle_t *) pc_httpd->priv;
|
||||
if ((err = httpd_register_uri_handler(*server, &config_handler)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Uri handler register failed: %s", esp_err_to_name(err));
|
||||
free(ep_uri);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
free(ep_uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t protocomm_httpd_remove_endpoint(const char *ep_name)
|
||||
{
|
||||
if (pc_httpd == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Removing endpoint : %s", ep_name);
|
||||
|
||||
/* Construct URI name by prepending '/' to ep_name */
|
||||
char* ep_uri = calloc(1, strlen(ep_name) + 2);
|
||||
if (!ep_uri) {
|
||||
ESP_LOGE(TAG, "Malloc failed for ep uri");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
sprintf(ep_uri, "/%s", ep_name);
|
||||
|
||||
/* Unregister URI handler */
|
||||
esp_err_t err;
|
||||
httpd_handle_t *server = (httpd_handle_t *) pc_httpd->priv;
|
||||
if ((err = httpd_unregister_uri_handler(*server, ep_uri, HTTP_POST)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Uri handler de-register failed: %s", esp_err_to_name(err));
|
||||
free(ep_uri);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
free(ep_uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t protocomm_httpd_start(protocomm_t *pc, const protocomm_httpd_config_t *config)
|
||||
{
|
||||
if (!pc || !config) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (pc_httpd) {
|
||||
if (pc == pc_httpd) {
|
||||
ESP_LOGE(TAG, "HTTP server already running for this protocomm instance");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
ESP_LOGE(TAG, "HTTP server started for another protocomm instance");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* Private data will point to the HTTP server handle */
|
||||
pc->priv = calloc(1, sizeof(httpd_handle_t));
|
||||
if (!pc->priv) {
|
||||
ESP_LOGE(TAG, "Malloc failed for HTTP server handle");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Configure the HTTP server */
|
||||
httpd_config_t server_config = HTTPD_DEFAULT_CONFIG();
|
||||
server_config.server_port = config->port;
|
||||
server_config.stack_size = config->stack_size;
|
||||
server_config.task_priority = config->task_priority;
|
||||
server_config.lru_purge_enable = true;
|
||||
server_config.max_open_sockets = 1;
|
||||
|
||||
esp_err_t err;
|
||||
if ((err = httpd_start((httpd_handle_t *)pc->priv, &server_config)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start http server: %s", esp_err_to_name(err));
|
||||
free(pc->priv);
|
||||
return err;
|
||||
}
|
||||
|
||||
pc->add_endpoint = protocomm_httpd_add_endpoint;
|
||||
pc->remove_endpoint = protocomm_httpd_remove_endpoint;
|
||||
pc_httpd = pc;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t protocomm_httpd_stop(protocomm_t *pc)
|
||||
{
|
||||
if ((pc != NULL) && (pc == pc_httpd)) {
|
||||
httpd_handle_t *server_handle = (httpd_handle_t *) pc_httpd->priv;
|
||||
httpd_stop(*server_handle);
|
||||
free(server_handle);
|
||||
pc_httpd->priv = NULL;
|
||||
pc_httpd = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
Loading…
Reference in New Issue