ESP Local Control Feature Added

List of changes:
* New component esp_local_ctrl added
* Example added under examples/protocols/esp_local_ctrl
* Documentation added under protocols/esp_local_ctrl
* Demo client side app esp_local_ctrl.py added under examples/protocols/esp_local_ctrl/scripts
* protocomm_ble : protocomm_ble_config_t given struct name for allowing forward declaration
* esp_prov/transport_softap renamed to transport_http
* transport_http module supports verification of server certificate
* transport_http module performs name resolution before connection
This commit is contained in:
Anurag Kar 2019-06-26 01:03:55 +05:30
parent 240192f9fa
commit b75f8b1b20
39 changed files with 4700 additions and 6 deletions

View file

@ -160,4 +160,5 @@ exclude =
components/wifi_provisioning/python/wifi_scan_pb2.py,
components/wifi_provisioning/python/wifi_config_pb2.py,
components/wifi_provisioning/python/wifi_constants_pb2.py,
components/esp_local_ctrl/python/esp_local_ctrl_pb2.py,
examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py,

View file

@ -0,0 +1,23 @@
set(include_dirs include)
set(priv_include_dirs proto-c src ../protocomm/proto-c)
set(srcs "src/esp_local_ctrl.c"
"src/esp_local_ctrl_handler.c"
"proto-c/esp_local_ctrl.pb-c.c")
if(CONFIG_ESP_HTTPS_SERVER_ENABLE)
list(APPEND srcs
"src/esp_local_ctrl_transport_httpd.c")
endif()
if(CONFIG_BT_ENABLED)
if(CONFIG_BT_BLUEDROID_ENABLED)
list(APPEND srcs
"src/esp_local_ctrl_transport_ble.c")
endif()
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
REQUIRES protocomm esp_https_server
PRIV_REQUIRES protobuf-c mdns)

View file

@ -0,0 +1,11 @@
COMPONENT_SRCDIRS := src proto-c
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/
ifndef CONFIG_BT_BLUEDROID_ENABLED
COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_ble.o
endif
ifndef CONFIG_ESP_HTTPS_SERVER_ENABLE
COMPONENT_OBJEXCLUDE += src/esp_local_ctrl_transport_httpd.o
endif

View file

@ -0,0 +1,339 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <protocomm.h>
/**
* @brief Property description data structure, which is to be populated
* and passed to the `esp_local_ctrl_add_property()` function
*
* Once a property is added, its structure is available for read-only access
* inside `get_prop_values()` and `set_prop_values()` handlers.
*/
typedef struct esp_local_ctrl_prop {
/**
* Unique name of property
*/
char *name;
/**
* Type of property. This may be set to application defined enums
*/
uint32_t type;
/**
* Size of the property value, which:
* - if zero, the property can have values of variable size
* - if non-zero, the property can have values of fixed size only,
* therefore, checks are performed internally by esp_local_ctrl
* when setting the value of such a property
*/
size_t size;
/**
* Flags set for this property. This could be a bit field.
* A flag may indicate property behavior, e.g. read-only / constant
*/
uint32_t flags;
/**
* Pointer to some context data relevant for this property. This will
* be available for use inside the `get_prop_values` and `set_prop_values`
* handlers as a part of this property structure. When set, this is valid
* throughout the lifetime of a property, till either the property is
* removed or the esp_local_ctrl service is stopped.
*/
void *ctx;
/**
* Function used by esp_local_ctrl to internally free the property
* context when `esp_local_ctrl_remove_property()` or
* `esp_local_ctrl_stop()` is called.
*/
void (*ctx_free_fn)(void *ctx);
} esp_local_ctrl_prop_t;
/**
* @brief Property value data structure. This gets passed to the
* `get_prop_values()` and `set_prop_values()` handlers for
* the purpose of retrieving or setting the present value
* of a property.
*/
typedef struct esp_local_ctrl_prop_val {
/**
* Pointer to memory holding property value
*/
void *data;
/**
* Size of property value
*/
size_t size;
/**
* This may be set by the application in `get_prop_values()` handler
* to tell `esp_local_ctrl` to call this function on the data pointer
* above, for freeing its resources after sending the `get_prop_values`
* response.
*/
void (*free_fn)(void *data);
} esp_local_ctrl_prop_val_t;
/**
* @brief Handlers for receiving and responding to local
* control commands for getting and setting properties.
*/
typedef struct esp_local_ctrl_handlers {
/**
* @brief Handler function to be implemented for retrieving current
* values of properties
*
* @note If any of the properties have fixed sizes, the size field of
* corresponding element in `prop_values` need to be set
*
* @param[in] props_count Total elements in the props array
* @param[in] props Array of properties, the current values for which
* have been requested by the client
* @param[out] prop_values Array of empty property values, the elements of
* which need to be populated with the current values
* of those properties specified by props argument
* @param[in] usr_ctx This provides value of the `usr_ctx` field of
* `esp_local_ctrl_handlers_t` structure
*
* @return Returning different error codes will convey the corresponding
* protocol level errors to the client :
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : InvalidArgument
* - ESP_ERR_INVALID_STATE : InvalidProto
* - All other error codes : InternalError
*/
esp_err_t (*get_prop_values)(size_t props_count,
const esp_local_ctrl_prop_t props[],
esp_local_ctrl_prop_val_t prop_values[],
void *usr_ctx);
/**
* @brief Handler function to be implemented for changing values of properties
*
* @note If any of the properties have variable sizes, the size field
* of the corresponding element in `prop_values` must be checked
* explicitly before making any assumptions on the size.
*
* @param[in] props_count Total elements in the props array
* @param[in] props Array of properties, the values for which the
* client requests to change
* @param[in] prop_values Array of property values, the elements of which
* need to be used for updating those properties
* specified by props argument
* @param[in] usr_ctx This provides value of the `usr_ctx` field of
* `esp_local_ctrl_handlers_t` structure
*
* @return Returning different error codes will convey the corresponding
* protocol level errors to the client :
* - ESP_OK : Success
* - ESP_ERR_INVALID_ARG : InvalidArgument
* - ESP_ERR_INVALID_STATE : InvalidProto
* - All other error codes : InternalError
*/
esp_err_t (*set_prop_values)(size_t props_count,
const esp_local_ctrl_prop_t props[],
const esp_local_ctrl_prop_val_t prop_values[],
void *usr_ctx);
/**
* Context pointer to be passed to above handler functions upon invocation.
* This is different from the property level context, as this is valid
* throughout the lifetime of the `esp_local_ctrl` service, and freed only
* when the service is stopped.
*/
void *usr_ctx;
/**
* Pointer to function which will be internally invoked on `usr_ctx` for
* freeing the context resources when `esp_local_ctrl_stop()` is called.
*/
void (*usr_ctx_free_fn)(void *usr_ctx);
} esp_local_ctrl_handlers_t;
/**
* @brief Transport mode (BLE / HTTPD) over which the service will be provided
*
* This is forward declaration of a private structure, implemented internally
* by `esp_local_ctrl`.
*/
typedef struct esp_local_ctrl_transport esp_local_ctrl_transport_t;
/**
* @brief Function for obtaining BLE transport mode
*/
const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble();
/**
* @brief Function for obtaining HTTPD transport mode
*/
const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd();
#define ESP_LOCAL_CTRL_TRANSPORT_BLE esp_local_ctrl_get_transport_ble()
#define ESP_LOCAL_CTRL_TRANSPORT_HTTPD esp_local_ctrl_get_transport_httpd()
/**
* @brief Configuration for transport mode BLE
*
* This is a forward declaration for `protocomm_ble_config_t`.
* To use this, application must set CONFIG_BT_BLUEDROID_ENABLED
* and include `protocomm_ble.h`.
*/
typedef struct protocomm_ble_config esp_local_ctrl_transport_config_ble_t;
/**
* @brief Configuration for transport mode HTTPD
*
* This is a forward declaration for `httpd_ssl_config_t`.
* To use this, application must set CONFIG_ESP_HTTPS_SERVER_ENABLE
* and include `esp_https_server.h`
*/
typedef struct httpd_ssl_config esp_local_ctrl_transport_config_httpd_t;
/**
* @brief Transport mode (BLE / HTTPD) configuration
*/
typedef union {
/**
* This is same as `protocomm_ble_config_t`. See `protocomm_ble.h` for
* available configuration parameters.
*/
esp_local_ctrl_transport_config_ble_t *ble;
/**
* This is same as `httpd_ssl_config_t`. See `esp_https_server.h` for
* available configuration parameters.
*/
esp_local_ctrl_transport_config_httpd_t *httpd;
} esp_local_ctrl_transport_config_t;
/**
* @brief Configuration structure to pass to `esp_local_ctrl_start()`
*/
typedef struct esp_local_ctrl_config {
/**
* Transport layer over which service will be provided
*/
const esp_local_ctrl_transport_t *transport;
/**
* Transport layer over which service will be provided
*/
esp_local_ctrl_transport_config_t transport_config;
/**
* Register handlers for responding to get/set requests on properties
*/
esp_local_ctrl_handlers_t handlers;
/**
* This limits the number of properties that are available at a time
*/
size_t max_properties;
} esp_local_ctrl_config_t;
/**
* @brief Start local control service
*
* @param[in] config Pointer to configuration structure
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config);
/**
* @brief Stop local control service
*/
esp_err_t esp_local_ctrl_stop(void);
/**
* @brief Add a new property
*
* This adds a new property and allocates internal resources for it.
* The total number of properties that could be added is limited by
* configuration option `max_properties`
*
* @param[in] prop Property description structure
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop);
/**
* @brief Remove a property
*
* This finds a property by name, and releases the internal resources
* which are associated with it.
*
* @param[in] name Name of the property to remove
*
* @return
* - ESP_OK : Success
* - ESP_ERR_NOT_FOUND : Failure
*/
esp_err_t esp_local_ctrl_remove_property(const char *name);
/**
* @brief Get property description structure by name
*
* This API may be used to get a property's context structure
* `esp_local_ctrl_prop_t` when its name is known
*
* @param[in] name Name of the property to find
*
* @return
* - Pointer to property
* - NULL if not found
*/
const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name);
/**
* @brief Register protocomm handler for a custom endpoint
*
* This API can be called by the application to register a protocomm handler
* for an endpoint after the local control service has started.
*
* @note In case of BLE transport the names and uuids of all custom
* endpoints must be provided beforehand as a part of the `protocomm_ble_config_t`
* structure set in `esp_local_ctrl_config_t`, and passed to `esp_local_ctrl_start()`.
*
* @param[in] ep_name Name of the endpoint
* @param[in] handler Endpoint handler function
* @param[in] user_ctx User data
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_set_handler(const char *ep_name,
protocomm_req_handler_t handler,
void *user_ctx);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,942 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: esp_local_ctrl.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "esp_local_ctrl.pb-c.h"
void cmd_get_property_count__init
(CmdGetPropertyCount *message)
{
static const CmdGetPropertyCount init_value = CMD_GET_PROPERTY_COUNT__INIT;
*message = init_value;
}
size_t cmd_get_property_count__get_packed_size
(const CmdGetPropertyCount *message)
{
assert(message->base.descriptor == &cmd_get_property_count__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_get_property_count__pack
(const CmdGetPropertyCount *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_get_property_count__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_get_property_count__pack_to_buffer
(const CmdGetPropertyCount *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_get_property_count__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdGetPropertyCount *
cmd_get_property_count__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdGetPropertyCount *)
protobuf_c_message_unpack (&cmd_get_property_count__descriptor,
allocator, len, data);
}
void cmd_get_property_count__free_unpacked
(CmdGetPropertyCount *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_get_property_count__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_get_property_count__init
(RespGetPropertyCount *message)
{
static const RespGetPropertyCount init_value = RESP_GET_PROPERTY_COUNT__INIT;
*message = init_value;
}
size_t resp_get_property_count__get_packed_size
(const RespGetPropertyCount *message)
{
assert(message->base.descriptor == &resp_get_property_count__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_get_property_count__pack
(const RespGetPropertyCount *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_get_property_count__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_get_property_count__pack_to_buffer
(const RespGetPropertyCount *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_get_property_count__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespGetPropertyCount *
resp_get_property_count__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespGetPropertyCount *)
protobuf_c_message_unpack (&resp_get_property_count__descriptor,
allocator, len, data);
}
void resp_get_property_count__free_unpacked
(RespGetPropertyCount *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_get_property_count__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void property_info__init
(PropertyInfo *message)
{
static const PropertyInfo init_value = PROPERTY_INFO__INIT;
*message = init_value;
}
size_t property_info__get_packed_size
(const PropertyInfo *message)
{
assert(message->base.descriptor == &property_info__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t property_info__pack
(const PropertyInfo *message,
uint8_t *out)
{
assert(message->base.descriptor == &property_info__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t property_info__pack_to_buffer
(const PropertyInfo *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &property_info__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
PropertyInfo *
property_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (PropertyInfo *)
protobuf_c_message_unpack (&property_info__descriptor,
allocator, len, data);
}
void property_info__free_unpacked
(PropertyInfo *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &property_info__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void cmd_get_property_values__init
(CmdGetPropertyValues *message)
{
static const CmdGetPropertyValues init_value = CMD_GET_PROPERTY_VALUES__INIT;
*message = init_value;
}
size_t cmd_get_property_values__get_packed_size
(const CmdGetPropertyValues *message)
{
assert(message->base.descriptor == &cmd_get_property_values__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_get_property_values__pack
(const CmdGetPropertyValues *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_get_property_values__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_get_property_values__pack_to_buffer
(const CmdGetPropertyValues *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_get_property_values__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdGetPropertyValues *
cmd_get_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdGetPropertyValues *)
protobuf_c_message_unpack (&cmd_get_property_values__descriptor,
allocator, len, data);
}
void cmd_get_property_values__free_unpacked
(CmdGetPropertyValues *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_get_property_values__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_get_property_values__init
(RespGetPropertyValues *message)
{
static const RespGetPropertyValues init_value = RESP_GET_PROPERTY_VALUES__INIT;
*message = init_value;
}
size_t resp_get_property_values__get_packed_size
(const RespGetPropertyValues *message)
{
assert(message->base.descriptor == &resp_get_property_values__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_get_property_values__pack
(const RespGetPropertyValues *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_get_property_values__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_get_property_values__pack_to_buffer
(const RespGetPropertyValues *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_get_property_values__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespGetPropertyValues *
resp_get_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespGetPropertyValues *)
protobuf_c_message_unpack (&resp_get_property_values__descriptor,
allocator, len, data);
}
void resp_get_property_values__free_unpacked
(RespGetPropertyValues *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_get_property_values__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void property_value__init
(PropertyValue *message)
{
static const PropertyValue init_value = PROPERTY_VALUE__INIT;
*message = init_value;
}
size_t property_value__get_packed_size
(const PropertyValue *message)
{
assert(message->base.descriptor == &property_value__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t property_value__pack
(const PropertyValue *message,
uint8_t *out)
{
assert(message->base.descriptor == &property_value__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t property_value__pack_to_buffer
(const PropertyValue *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &property_value__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
PropertyValue *
property_value__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (PropertyValue *)
protobuf_c_message_unpack (&property_value__descriptor,
allocator, len, data);
}
void property_value__free_unpacked
(PropertyValue *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &property_value__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void cmd_set_property_values__init
(CmdSetPropertyValues *message)
{
static const CmdSetPropertyValues init_value = CMD_SET_PROPERTY_VALUES__INIT;
*message = init_value;
}
size_t cmd_set_property_values__get_packed_size
(const CmdSetPropertyValues *message)
{
assert(message->base.descriptor == &cmd_set_property_values__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t cmd_set_property_values__pack
(const CmdSetPropertyValues *message,
uint8_t *out)
{
assert(message->base.descriptor == &cmd_set_property_values__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t cmd_set_property_values__pack_to_buffer
(const CmdSetPropertyValues *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &cmd_set_property_values__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
CmdSetPropertyValues *
cmd_set_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (CmdSetPropertyValues *)
protobuf_c_message_unpack (&cmd_set_property_values__descriptor,
allocator, len, data);
}
void cmd_set_property_values__free_unpacked
(CmdSetPropertyValues *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &cmd_set_property_values__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void resp_set_property_values__init
(RespSetPropertyValues *message)
{
static const RespSetPropertyValues init_value = RESP_SET_PROPERTY_VALUES__INIT;
*message = init_value;
}
size_t resp_set_property_values__get_packed_size
(const RespSetPropertyValues *message)
{
assert(message->base.descriptor == &resp_set_property_values__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t resp_set_property_values__pack
(const RespSetPropertyValues *message,
uint8_t *out)
{
assert(message->base.descriptor == &resp_set_property_values__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t resp_set_property_values__pack_to_buffer
(const RespSetPropertyValues *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &resp_set_property_values__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
RespSetPropertyValues *
resp_set_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (RespSetPropertyValues *)
protobuf_c_message_unpack (&resp_set_property_values__descriptor,
allocator, len, data);
}
void resp_set_property_values__free_unpacked
(RespSetPropertyValues *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &resp_set_property_values__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void local_ctrl_message__init
(LocalCtrlMessage *message)
{
static const LocalCtrlMessage init_value = LOCAL_CTRL_MESSAGE__INIT;
*message = init_value;
}
size_t local_ctrl_message__get_packed_size
(const LocalCtrlMessage *message)
{
assert(message->base.descriptor == &local_ctrl_message__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t local_ctrl_message__pack
(const LocalCtrlMessage *message,
uint8_t *out)
{
assert(message->base.descriptor == &local_ctrl_message__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t local_ctrl_message__pack_to_buffer
(const LocalCtrlMessage *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &local_ctrl_message__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
LocalCtrlMessage *
local_ctrl_message__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (LocalCtrlMessage *)
protobuf_c_message_unpack (&local_ctrl_message__descriptor,
allocator, len, data);
}
void local_ctrl_message__free_unpacked
(LocalCtrlMessage *message,
ProtobufCAllocator *allocator)
{
if(!message)
return;
assert(message->base.descriptor == &local_ctrl_message__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
#define cmd_get_property_count__field_descriptors NULL
#define cmd_get_property_count__field_indices_by_name NULL
#define cmd_get_property_count__number_ranges NULL
const ProtobufCMessageDescriptor cmd_get_property_count__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdGetPropertyCount",
"CmdGetPropertyCount",
"CmdGetPropertyCount",
"",
sizeof(CmdGetPropertyCount),
0,
cmd_get_property_count__field_descriptors,
cmd_get_property_count__field_indices_by_name,
0, cmd_get_property_count__number_ranges,
(ProtobufCMessageInit) cmd_get_property_count__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor resp_get_property_count__field_descriptors[2] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(RespGetPropertyCount, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"count",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(RespGetPropertyCount, count),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned resp_get_property_count__field_indices_by_name[] = {
1, /* field[1] = count */
0, /* field[0] = status */
};
static const ProtobufCIntRange resp_get_property_count__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor resp_get_property_count__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespGetPropertyCount",
"RespGetPropertyCount",
"RespGetPropertyCount",
"",
sizeof(RespGetPropertyCount),
2,
resp_get_property_count__field_descriptors,
resp_get_property_count__field_indices_by_name,
1, resp_get_property_count__number_ranges,
(ProtobufCMessageInit) resp_get_property_count__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor property_info__field_descriptors[5] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(PropertyInfo, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"name",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_STRING,
0, /* quantifier_offset */
offsetof(PropertyInfo, name),
NULL,
&protobuf_c_empty_string,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"type",
3,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(PropertyInfo, type),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"flags",
4,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(PropertyInfo, flags),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"value",
5,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(PropertyInfo, value),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned property_info__field_indices_by_name[] = {
3, /* field[3] = flags */
1, /* field[1] = name */
0, /* field[0] = status */
2, /* field[2] = type */
4, /* field[4] = value */
};
static const ProtobufCIntRange property_info__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 5 }
};
const ProtobufCMessageDescriptor property_info__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"PropertyInfo",
"PropertyInfo",
"PropertyInfo",
"",
sizeof(PropertyInfo),
5,
property_info__field_descriptors,
property_info__field_indices_by_name,
1, property_info__number_ranges,
(ProtobufCMessageInit) property_info__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor cmd_get_property_values__field_descriptors[1] =
{
{
"indices",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_UINT32,
offsetof(CmdGetPropertyValues, n_indices),
offsetof(CmdGetPropertyValues, indices),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned cmd_get_property_values__field_indices_by_name[] = {
0, /* field[0] = indices */
};
static const ProtobufCIntRange cmd_get_property_values__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor cmd_get_property_values__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdGetPropertyValues",
"CmdGetPropertyValues",
"CmdGetPropertyValues",
"",
sizeof(CmdGetPropertyValues),
1,
cmd_get_property_values__field_descriptors,
cmd_get_property_values__field_indices_by_name,
1, cmd_get_property_values__number_ranges,
(ProtobufCMessageInit) cmd_get_property_values__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor resp_get_property_values__field_descriptors[2] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(RespGetPropertyValues, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"props",
2,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(RespGetPropertyValues, n_props),
offsetof(RespGetPropertyValues, props),
&property_info__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned resp_get_property_values__field_indices_by_name[] = {
1, /* field[1] = props */
0, /* field[0] = status */
};
static const ProtobufCIntRange resp_get_property_values__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor resp_get_property_values__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespGetPropertyValues",
"RespGetPropertyValues",
"RespGetPropertyValues",
"",
sizeof(RespGetPropertyValues),
2,
resp_get_property_values__field_descriptors,
resp_get_property_values__field_indices_by_name,
1, resp_get_property_values__number_ranges,
(ProtobufCMessageInit) resp_get_property_values__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor property_value__field_descriptors[2] =
{
{
"index",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_UINT32,
0, /* quantifier_offset */
offsetof(PropertyValue, index),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"value",
2,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_BYTES,
0, /* quantifier_offset */
offsetof(PropertyValue, value),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned property_value__field_indices_by_name[] = {
0, /* field[0] = index */
1, /* field[1] = value */
};
static const ProtobufCIntRange property_value__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor property_value__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"PropertyValue",
"PropertyValue",
"PropertyValue",
"",
sizeof(PropertyValue),
2,
property_value__field_descriptors,
property_value__field_indices_by_name,
1, property_value__number_ranges,
(ProtobufCMessageInit) property_value__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor cmd_set_property_values__field_descriptors[1] =
{
{
"props",
1,
PROTOBUF_C_LABEL_REPEATED,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(CmdSetPropertyValues, n_props),
offsetof(CmdSetPropertyValues, props),
&property_value__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned cmd_set_property_values__field_indices_by_name[] = {
0, /* field[0] = props */
};
static const ProtobufCIntRange cmd_set_property_values__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor cmd_set_property_values__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"CmdSetPropertyValues",
"CmdSetPropertyValues",
"CmdSetPropertyValues",
"",
sizeof(CmdSetPropertyValues),
1,
cmd_set_property_values__field_descriptors,
cmd_set_property_values__field_indices_by_name,
1, cmd_set_property_values__number_ranges,
(ProtobufCMessageInit) cmd_set_property_values__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor resp_set_property_values__field_descriptors[1] =
{
{
"status",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(RespSetPropertyValues, status),
&status__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned resp_set_property_values__field_indices_by_name[] = {
0, /* field[0] = status */
};
static const ProtobufCIntRange resp_set_property_values__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 1 }
};
const ProtobufCMessageDescriptor resp_set_property_values__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"RespSetPropertyValues",
"RespSetPropertyValues",
"RespSetPropertyValues",
"",
sizeof(RespSetPropertyValues),
1,
resp_set_property_values__field_descriptors,
resp_set_property_values__field_indices_by_name,
1, resp_set_property_values__number_ranges,
(ProtobufCMessageInit) resp_set_property_values__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor local_ctrl_message__field_descriptors[7] =
{
{
"msg",
1,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_ENUM,
0, /* quantifier_offset */
offsetof(LocalCtrlMessage, msg),
&local_ctrl_msg_type__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_get_prop_count",
10,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, cmd_get_prop_count),
&cmd_get_property_count__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_get_prop_count",
11,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, resp_get_prop_count),
&resp_get_property_count__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_get_prop_vals",
12,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, cmd_get_prop_vals),
&cmd_get_property_values__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_get_prop_vals",
13,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, resp_get_prop_vals),
&resp_get_property_values__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"cmd_set_prop_vals",
14,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, cmd_set_prop_vals),
&cmd_set_property_values__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"resp_set_prop_vals",
15,
PROTOBUF_C_LABEL_NONE,
PROTOBUF_C_TYPE_MESSAGE,
offsetof(LocalCtrlMessage, payload_case),
offsetof(LocalCtrlMessage, resp_set_prop_vals),
&resp_set_property_values__descriptor,
NULL,
0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned local_ctrl_message__field_indices_by_name[] = {
1, /* field[1] = cmd_get_prop_count */
3, /* field[3] = cmd_get_prop_vals */
5, /* field[5] = cmd_set_prop_vals */
0, /* field[0] = msg */
2, /* field[2] = resp_get_prop_count */
4, /* field[4] = resp_get_prop_vals */
6, /* field[6] = resp_set_prop_vals */
};
static const ProtobufCIntRange local_ctrl_message__number_ranges[2 + 1] =
{
{ 1, 0 },
{ 10, 1 },
{ 0, 7 }
};
const ProtobufCMessageDescriptor local_ctrl_message__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"LocalCtrlMessage",
"LocalCtrlMessage",
"LocalCtrlMessage",
"",
sizeof(LocalCtrlMessage),
7,
local_ctrl_message__field_descriptors,
local_ctrl_message__field_indices_by_name,
2, local_ctrl_message__number_ranges,
(ProtobufCMessageInit) local_ctrl_message__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCEnumValue local_ctrl_msg_type__enum_values_by_number[6] =
{
{ "TypeCmdGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount", 0 },
{ "TypeRespGetPropertyCount", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount", 1 },
{ "TypeCmdGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues", 4 },
{ "TypeRespGetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues", 5 },
{ "TypeCmdSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues", 6 },
{ "TypeRespSetPropertyValues", "LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues", 7 },
};
static const ProtobufCIntRange local_ctrl_msg_type__value_ranges[] = {
{0, 0},{4, 2},{0, 6}
};
static const ProtobufCEnumValueIndex local_ctrl_msg_type__enum_values_by_name[6] =
{
{ "TypeCmdGetPropertyCount", 0 },
{ "TypeCmdGetPropertyValues", 2 },
{ "TypeCmdSetPropertyValues", 4 },
{ "TypeRespGetPropertyCount", 1 },
{ "TypeRespGetPropertyValues", 3 },
{ "TypeRespSetPropertyValues", 5 },
};
const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor =
{
PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC,
"LocalCtrlMsgType",
"LocalCtrlMsgType",
"LocalCtrlMsgType",
"",
6,
local_ctrl_msg_type__enum_values_by_number,
6,
local_ctrl_msg_type__enum_values_by_name,
2,
local_ctrl_msg_type__value_ranges,
NULL,NULL,NULL,NULL /* reserved[1234] */
};

View file

@ -0,0 +1,383 @@
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: esp_local_ctrl.proto */
#ifndef PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED
#define PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED
#include <protobuf-c/protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1003000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1003001 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
#include "constants.pb-c.h"
typedef struct _CmdGetPropertyCount CmdGetPropertyCount;
typedef struct _RespGetPropertyCount RespGetPropertyCount;
typedef struct _PropertyInfo PropertyInfo;
typedef struct _CmdGetPropertyValues CmdGetPropertyValues;
typedef struct _RespGetPropertyValues RespGetPropertyValues;
typedef struct _PropertyValue PropertyValue;
typedef struct _CmdSetPropertyValues CmdSetPropertyValues;
typedef struct _RespSetPropertyValues RespSetPropertyValues;
typedef struct _LocalCtrlMessage LocalCtrlMessage;
/* --- enums --- */
typedef enum _LocalCtrlMsgType {
LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount = 0,
LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount = 1,
LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues = 4,
LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues = 5,
LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues = 6,
LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues = 7
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MSG_TYPE)
} LocalCtrlMsgType;
/* --- messages --- */
struct _CmdGetPropertyCount
{
ProtobufCMessage base;
};
#define CMD_GET_PROPERTY_COUNT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_count__descriptor) \
}
struct _RespGetPropertyCount
{
ProtobufCMessage base;
Status status;
uint32_t count;
};
#define RESP_GET_PROPERTY_COUNT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_get_property_count__descriptor) \
, STATUS__Success, 0 }
struct _PropertyInfo
{
ProtobufCMessage base;
Status status;
char *name;
uint32_t type;
uint32_t flags;
ProtobufCBinaryData value;
};
#define PROPERTY_INFO__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&property_info__descriptor) \
, STATUS__Success, (char *)protobuf_c_empty_string, 0, 0, {0,NULL} }
struct _CmdGetPropertyValues
{
ProtobufCMessage base;
size_t n_indices;
uint32_t *indices;
};
#define CMD_GET_PROPERTY_VALUES__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_get_property_values__descriptor) \
, 0,NULL }
struct _RespGetPropertyValues
{
ProtobufCMessage base;
Status status;
size_t n_props;
PropertyInfo **props;
};
#define RESP_GET_PROPERTY_VALUES__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_get_property_values__descriptor) \
, STATUS__Success, 0,NULL }
struct _PropertyValue
{
ProtobufCMessage base;
uint32_t index;
ProtobufCBinaryData value;
};
#define PROPERTY_VALUE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&property_value__descriptor) \
, 0, {0,NULL} }
struct _CmdSetPropertyValues
{
ProtobufCMessage base;
size_t n_props;
PropertyValue **props;
};
#define CMD_SET_PROPERTY_VALUES__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&cmd_set_property_values__descriptor) \
, 0,NULL }
struct _RespSetPropertyValues
{
ProtobufCMessage base;
Status status;
};
#define RESP_SET_PROPERTY_VALUES__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&resp_set_property_values__descriptor) \
, STATUS__Success }
typedef enum {
LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET = 0,
LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_COUNT = 10,
LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT = 11,
LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_GET_PROP_VALS = 12,
LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS = 13,
LOCAL_CTRL_MESSAGE__PAYLOAD_CMD_SET_PROP_VALS = 14,
LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS = 15
PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(LOCAL_CTRL_MESSAGE__PAYLOAD)
} LocalCtrlMessage__PayloadCase;
struct _LocalCtrlMessage
{
ProtobufCMessage base;
LocalCtrlMsgType msg;
LocalCtrlMessage__PayloadCase payload_case;
union {
CmdGetPropertyCount *cmd_get_prop_count;
RespGetPropertyCount *resp_get_prop_count;
CmdGetPropertyValues *cmd_get_prop_vals;
RespGetPropertyValues *resp_get_prop_vals;
CmdSetPropertyValues *cmd_set_prop_vals;
RespSetPropertyValues *resp_set_prop_vals;
};
};
#define LOCAL_CTRL_MESSAGE__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&local_ctrl_message__descriptor) \
, LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount, LOCAL_CTRL_MESSAGE__PAYLOAD__NOT_SET, {0} }
/* CmdGetPropertyCount methods */
void cmd_get_property_count__init
(CmdGetPropertyCount *message);
size_t cmd_get_property_count__get_packed_size
(const CmdGetPropertyCount *message);
size_t cmd_get_property_count__pack
(const CmdGetPropertyCount *message,
uint8_t *out);
size_t cmd_get_property_count__pack_to_buffer
(const CmdGetPropertyCount *message,
ProtobufCBuffer *buffer);
CmdGetPropertyCount *
cmd_get_property_count__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_get_property_count__free_unpacked
(CmdGetPropertyCount *message,
ProtobufCAllocator *allocator);
/* RespGetPropertyCount methods */
void resp_get_property_count__init
(RespGetPropertyCount *message);
size_t resp_get_property_count__get_packed_size
(const RespGetPropertyCount *message);
size_t resp_get_property_count__pack
(const RespGetPropertyCount *message,
uint8_t *out);
size_t resp_get_property_count__pack_to_buffer
(const RespGetPropertyCount *message,
ProtobufCBuffer *buffer);
RespGetPropertyCount *
resp_get_property_count__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_get_property_count__free_unpacked
(RespGetPropertyCount *message,
ProtobufCAllocator *allocator);
/* PropertyInfo methods */
void property_info__init
(PropertyInfo *message);
size_t property_info__get_packed_size
(const PropertyInfo *message);
size_t property_info__pack
(const PropertyInfo *message,
uint8_t *out);
size_t property_info__pack_to_buffer
(const PropertyInfo *message,
ProtobufCBuffer *buffer);
PropertyInfo *
property_info__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void property_info__free_unpacked
(PropertyInfo *message,
ProtobufCAllocator *allocator);
/* CmdGetPropertyValues methods */
void cmd_get_property_values__init
(CmdGetPropertyValues *message);
size_t cmd_get_property_values__get_packed_size
(const CmdGetPropertyValues *message);
size_t cmd_get_property_values__pack
(const CmdGetPropertyValues *message,
uint8_t *out);
size_t cmd_get_property_values__pack_to_buffer
(const CmdGetPropertyValues *message,
ProtobufCBuffer *buffer);
CmdGetPropertyValues *
cmd_get_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_get_property_values__free_unpacked
(CmdGetPropertyValues *message,
ProtobufCAllocator *allocator);
/* RespGetPropertyValues methods */
void resp_get_property_values__init
(RespGetPropertyValues *message);
size_t resp_get_property_values__get_packed_size
(const RespGetPropertyValues *message);
size_t resp_get_property_values__pack
(const RespGetPropertyValues *message,
uint8_t *out);
size_t resp_get_property_values__pack_to_buffer
(const RespGetPropertyValues *message,
ProtobufCBuffer *buffer);
RespGetPropertyValues *
resp_get_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_get_property_values__free_unpacked
(RespGetPropertyValues *message,
ProtobufCAllocator *allocator);
/* PropertyValue methods */
void property_value__init
(PropertyValue *message);
size_t property_value__get_packed_size
(const PropertyValue *message);
size_t property_value__pack
(const PropertyValue *message,
uint8_t *out);
size_t property_value__pack_to_buffer
(const PropertyValue *message,
ProtobufCBuffer *buffer);
PropertyValue *
property_value__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void property_value__free_unpacked
(PropertyValue *message,
ProtobufCAllocator *allocator);
/* CmdSetPropertyValues methods */
void cmd_set_property_values__init
(CmdSetPropertyValues *message);
size_t cmd_set_property_values__get_packed_size
(const CmdSetPropertyValues *message);
size_t cmd_set_property_values__pack
(const CmdSetPropertyValues *message,
uint8_t *out);
size_t cmd_set_property_values__pack_to_buffer
(const CmdSetPropertyValues *message,
ProtobufCBuffer *buffer);
CmdSetPropertyValues *
cmd_set_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void cmd_set_property_values__free_unpacked
(CmdSetPropertyValues *message,
ProtobufCAllocator *allocator);
/* RespSetPropertyValues methods */
void resp_set_property_values__init
(RespSetPropertyValues *message);
size_t resp_set_property_values__get_packed_size
(const RespSetPropertyValues *message);
size_t resp_set_property_values__pack
(const RespSetPropertyValues *message,
uint8_t *out);
size_t resp_set_property_values__pack_to_buffer
(const RespSetPropertyValues *message,
ProtobufCBuffer *buffer);
RespSetPropertyValues *
resp_set_property_values__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void resp_set_property_values__free_unpacked
(RespSetPropertyValues *message,
ProtobufCAllocator *allocator);
/* LocalCtrlMessage methods */
void local_ctrl_message__init
(LocalCtrlMessage *message);
size_t local_ctrl_message__get_packed_size
(const LocalCtrlMessage *message);
size_t local_ctrl_message__pack
(const LocalCtrlMessage *message,
uint8_t *out);
size_t local_ctrl_message__pack_to_buffer
(const LocalCtrlMessage *message,
ProtobufCBuffer *buffer);
LocalCtrlMessage *
local_ctrl_message__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void local_ctrl_message__free_unpacked
(LocalCtrlMessage *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*CmdGetPropertyCount_Closure)
(const CmdGetPropertyCount *message,
void *closure_data);
typedef void (*RespGetPropertyCount_Closure)
(const RespGetPropertyCount *message,
void *closure_data);
typedef void (*PropertyInfo_Closure)
(const PropertyInfo *message,
void *closure_data);
typedef void (*CmdGetPropertyValues_Closure)
(const CmdGetPropertyValues *message,
void *closure_data);
typedef void (*RespGetPropertyValues_Closure)
(const RespGetPropertyValues *message,
void *closure_data);
typedef void (*PropertyValue_Closure)
(const PropertyValue *message,
void *closure_data);
typedef void (*CmdSetPropertyValues_Closure)
(const CmdSetPropertyValues *message,
void *closure_data);
typedef void (*RespSetPropertyValues_Closure)
(const RespSetPropertyValues *message,
void *closure_data);
typedef void (*LocalCtrlMessage_Closure)
(const LocalCtrlMessage *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCEnumDescriptor local_ctrl_msg_type__descriptor;
extern const ProtobufCMessageDescriptor cmd_get_property_count__descriptor;
extern const ProtobufCMessageDescriptor resp_get_property_count__descriptor;
extern const ProtobufCMessageDescriptor property_info__descriptor;
extern const ProtobufCMessageDescriptor cmd_get_property_values__descriptor;
extern const ProtobufCMessageDescriptor resp_get_property_values__descriptor;
extern const ProtobufCMessageDescriptor property_value__descriptor;
extern const ProtobufCMessageDescriptor cmd_set_property_values__descriptor;
extern const ProtobufCMessageDescriptor resp_set_property_values__descriptor;
extern const ProtobufCMessageDescriptor local_ctrl_message__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_esp_5flocal_5fctrl_2eproto__INCLUDED */

View file

@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.5)
set(PROTO_COMPILER "protoc")
set(PROTO_C_COMPILER "protoc-c")
set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c")
set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python")
set(PROTOCOMM_INCL_PATH "${CMAKE_CURRENT_LIST_DIR}/../../protocomm/proto")
file(GLOB PROTO_FILES
LIST_DIRECTORIES false
RELATIVE ${CMAKE_CURRENT_LIST_DIR}
"*.proto")
add_custom_target(c_proto
COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES}
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
add_custom_target(python_proto
COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . -I ${PROTOCOMM_INCL_PATH} ${PROTO_FILES}
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
add_custom_target(proto ALL
DEPENDS c_proto python_proto
VERBATIM
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)

View file

@ -0,0 +1,25 @@
# Protobuf files for defining ESP Local Control message structures
The proto files under this directory are used by esp_local_ctrl for defining protobuf messages which are sent and received over protocomm transport layer. These proto files cannot be used directly and have to be compiled into C and Python files. The generated C files are used by esp_local_ctrl itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to esp_local_ctrl service running on a device.
Note : These proto files are not automatically compiled during the build process.
# Compilation
Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python` directories, and thus running `cmake` / `make` (and installing the Protobuf compilers) is optional.
If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly.
## Step 1 (Only for cmake)
When using cmake, first create a build directory and call cmake from inside:
```
mkdir build
cd build
cmake ..
```
## Step 2
Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `components/esp_local_ctrl/proto-c` and `components/esp_local_ctrl/python`

View file

@ -0,0 +1,62 @@
syntax = "proto3";
import "constants.proto";
message CmdGetPropertyCount {
}
message RespGetPropertyCount {
Status status = 1;
uint32 count = 2;
}
message PropertyInfo {
Status status = 1;
string name = 2;
uint32 type = 3;
uint32 flags = 4;
bytes value = 5;
}
message CmdGetPropertyValues {
repeated uint32 indices = 1;
}
message RespGetPropertyValues {
Status status = 1;
repeated PropertyInfo props = 2;
}
message PropertyValue {
uint32 index = 1;
bytes value = 2;
}
message CmdSetPropertyValues {
repeated PropertyValue props = 1;
}
message RespSetPropertyValues {
Status status = 1;
}
enum LocalCtrlMsgType {
TypeCmdGetPropertyCount = 0;
TypeRespGetPropertyCount = 1;
TypeCmdGetPropertyValues = 4;
TypeRespGetPropertyValues = 5;
TypeCmdSetPropertyValues = 6;
TypeRespSetPropertyValues = 7;
}
message LocalCtrlMessage {
LocalCtrlMsgType msg = 1;
oneof payload {
CmdGetPropertyCount cmd_get_prop_count = 10;
RespGetPropertyCount resp_get_prop_count = 11;
CmdGetPropertyValues cmd_get_prop_vals = 12;
RespGetPropertyValues resp_get_prop_vals = 13;
CmdSetPropertyValues cmd_set_prop_vals = 14;
RespSetPropertyValues resp_set_prop_vals = 15;
}
}

View file

@ -0,0 +1,7 @@
all: c_proto python_proto
c_proto: *.proto
@protoc-c --c_out=../proto-c/ -I . -I ../../protocomm/proto/ *.proto
python_proto: *.proto
@protoc --python_out=../python/ -I . -I ../../protocomm/proto/ *.proto

View file

@ -0,0 +1,549 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: esp_local_ctrl.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf.internal import enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
import constants_pb2 as constants__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
name='esp_local_ctrl.proto',
package='',
syntax='proto3',
serialized_options=None,
serialized_pb=_b('\n\x14\x65sp_local_ctrl.proto\x1a\x0f\x63onstants.proto\"\x15\n\x13\x43mdGetPropertyCount\">\n\x14RespGetPropertyCount\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"a\n\x0cPropertyInfo\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\r\x12\r\n\x05\x66lags\x18\x04 \x01(\r\x12\r\n\x05value\x18\x05 \x01(\x0c\"\'\n\x14\x43mdGetPropertyValues\x12\x0f\n\x07indices\x18\x01 \x03(\r\"N\n\x15RespGetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\x12\x1c\n\x05props\x18\x02 \x03(\x0b\x32\r.PropertyInfo\"-\n\rPropertyValue\x12\r\n\x05index\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x0c\"5\n\x14\x43mdSetPropertyValues\x12\x1d\n\x05props\x18\x01 \x03(\x0b\x32\x0e.PropertyValue\"0\n\x15RespSetPropertyValues\x12\x17\n\x06status\x18\x01 \x01(\x0e\x32\x07.Status\"\xfb\x02\n\x10LocalCtrlMessage\x12\x1e\n\x03msg\x18\x01 \x01(\x0e\x32\x11.LocalCtrlMsgType\x12\x32\n\x12\x63md_get_prop_count\x18\n \x01(\x0b\x32\x14.CmdGetPropertyCountH\x00\x12\x34\n\x13resp_get_prop_count\x18\x0b \x01(\x0b\x32\x15.RespGetPropertyCountH\x00\x12\x32\n\x11\x63md_get_prop_vals\x18\x0c \x01(\x0b\x32\x15.CmdGetPropertyValuesH\x00\x12\x34\n\x12resp_get_prop_vals\x18\r \x01(\x0b\x32\x16.RespGetPropertyValuesH\x00\x12\x32\n\x11\x63md_set_prop_vals\x18\x0e \x01(\x0b\x32\x15.CmdSetPropertyValuesH\x00\x12\x34\n\x12resp_set_prop_vals\x18\x0f \x01(\x0b\x32\x16.RespSetPropertyValuesH\x00\x42\t\n\x07payload*\xc7\x01\n\x10LocalCtrlMsgType\x12\x1b\n\x17TypeCmdGetPropertyCount\x10\x00\x12\x1c\n\x18TypeRespGetPropertyCount\x10\x01\x12\x1c\n\x18TypeCmdGetPropertyValues\x10\x04\x12\x1d\n\x19TypeRespGetPropertyValues\x10\x05\x12\x1c\n\x18TypeCmdSetPropertyValues\x10\x06\x12\x1d\n\x19TypeRespSetPropertyValues\x10\x07\x62\x06proto3')
,
dependencies=[constants__pb2.DESCRIPTOR,])
_LOCALCTRLMSGTYPE = _descriptor.EnumDescriptor(
name='LocalCtrlMsgType',
full_name='LocalCtrlMsgType',
filename=None,
file=DESCRIPTOR,
values=[
_descriptor.EnumValueDescriptor(
name='TypeCmdGetPropertyCount', index=0, number=0,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespGetPropertyCount', index=1, number=1,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeCmdGetPropertyValues', index=2, number=4,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespGetPropertyValues', index=3, number=5,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeCmdSetPropertyValues', index=4, number=6,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='TypeRespSetPropertyValues', index=5, number=7,
serialized_options=None,
type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=883,
serialized_end=1082,
)
_sym_db.RegisterEnumDescriptor(_LOCALCTRLMSGTYPE)
LocalCtrlMsgType = enum_type_wrapper.EnumTypeWrapper(_LOCALCTRLMSGTYPE)
TypeCmdGetPropertyCount = 0
TypeRespGetPropertyCount = 1
TypeCmdGetPropertyValues = 4
TypeRespGetPropertyValues = 5
TypeCmdSetPropertyValues = 6
TypeRespSetPropertyValues = 7
_CMDGETPROPERTYCOUNT = _descriptor.Descriptor(
name='CmdGetPropertyCount',
full_name='CmdGetPropertyCount',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=41,
serialized_end=62,
)
_RESPGETPROPERTYCOUNT = _descriptor.Descriptor(
name='RespGetPropertyCount',
full_name='RespGetPropertyCount',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='status', full_name='RespGetPropertyCount.status', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='count', full_name='RespGetPropertyCount.count', index=1,
number=2, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=64,
serialized_end=126,
)
_PROPERTYINFO = _descriptor.Descriptor(
name='PropertyInfo',
full_name='PropertyInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='status', full_name='PropertyInfo.status', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='name', full_name='PropertyInfo.name', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='type', full_name='PropertyInfo.type', index=2,
number=3, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='flags', full_name='PropertyInfo.flags', index=3,
number=4, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='value', full_name='PropertyInfo.value', index=4,
number=5, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=128,
serialized_end=225,
)
_CMDGETPROPERTYVALUES = _descriptor.Descriptor(
name='CmdGetPropertyValues',
full_name='CmdGetPropertyValues',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='indices', full_name='CmdGetPropertyValues.indices', index=0,
number=1, type=13, cpp_type=3, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=227,
serialized_end=266,
)
_RESPGETPROPERTYVALUES = _descriptor.Descriptor(
name='RespGetPropertyValues',
full_name='RespGetPropertyValues',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='status', full_name='RespGetPropertyValues.status', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='props', full_name='RespGetPropertyValues.props', index=1,
number=2, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=268,
serialized_end=346,
)
_PROPERTYVALUE = _descriptor.Descriptor(
name='PropertyValue',
full_name='PropertyValue',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='index', full_name='PropertyValue.index', index=0,
number=1, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='value', full_name='PropertyValue.value', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=348,
serialized_end=393,
)
_CMDSETPROPERTYVALUES = _descriptor.Descriptor(
name='CmdSetPropertyValues',
full_name='CmdSetPropertyValues',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='props', full_name='CmdSetPropertyValues.props', index=0,
number=1, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=395,
serialized_end=448,
)
_RESPSETPROPERTYVALUES = _descriptor.Descriptor(
name='RespSetPropertyValues',
full_name='RespSetPropertyValues',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='status', full_name='RespSetPropertyValues.status', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=450,
serialized_end=498,
)
_LOCALCTRLMESSAGE = _descriptor.Descriptor(
name='LocalCtrlMessage',
full_name='LocalCtrlMessage',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='msg', full_name='LocalCtrlMessage.msg', index=0,
number=1, type=14, cpp_type=8, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_get_prop_count', full_name='LocalCtrlMessage.cmd_get_prop_count', index=1,
number=10, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_get_prop_count', full_name='LocalCtrlMessage.resp_get_prop_count', index=2,
number=11, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_get_prop_vals', full_name='LocalCtrlMessage.cmd_get_prop_vals', index=3,
number=12, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_get_prop_vals', full_name='LocalCtrlMessage.resp_get_prop_vals', index=4,
number=13, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='cmd_set_prop_vals', full_name='LocalCtrlMessage.cmd_set_prop_vals', index=5,
number=14, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='resp_set_prop_vals', full_name='LocalCtrlMessage.resp_set_prop_vals', index=6,
number=15, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
_descriptor.OneofDescriptor(
name='payload', full_name='LocalCtrlMessage.payload',
index=0, containing_type=None, fields=[]),
],
serialized_start=501,
serialized_end=880,
)
_RESPGETPROPERTYCOUNT.fields_by_name['status'].enum_type = constants__pb2._STATUS
_PROPERTYINFO.fields_by_name['status'].enum_type = constants__pb2._STATUS
_RESPGETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS
_RESPGETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYINFO
_CMDSETPROPERTYVALUES.fields_by_name['props'].message_type = _PROPERTYVALUE
_RESPSETPROPERTYVALUES.fields_by_name['status'].enum_type = constants__pb2._STATUS
_LOCALCTRLMESSAGE.fields_by_name['msg'].enum_type = _LOCALCTRLMSGTYPE
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].message_type = _CMDGETPROPERTYCOUNT
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].message_type = _RESPGETPROPERTYCOUNT
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].message_type = _CMDGETPROPERTYVALUES
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].message_type = _RESPGETPROPERTYVALUES
_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].message_type = _CMDSETPROPERTYVALUES
_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].message_type = _RESPSETPROPERTYVALUES
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'])
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'])
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_count'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'])
_LOCALCTRLMESSAGE.fields_by_name['cmd_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'])
_LOCALCTRLMESSAGE.fields_by_name['resp_get_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'])
_LOCALCTRLMESSAGE.fields_by_name['cmd_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
_LOCALCTRLMESSAGE.oneofs_by_name['payload'].fields.append(
_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'])
_LOCALCTRLMESSAGE.fields_by_name['resp_set_prop_vals'].containing_oneof = _LOCALCTRLMESSAGE.oneofs_by_name['payload']
DESCRIPTOR.message_types_by_name['CmdGetPropertyCount'] = _CMDGETPROPERTYCOUNT
DESCRIPTOR.message_types_by_name['RespGetPropertyCount'] = _RESPGETPROPERTYCOUNT
DESCRIPTOR.message_types_by_name['PropertyInfo'] = _PROPERTYINFO
DESCRIPTOR.message_types_by_name['CmdGetPropertyValues'] = _CMDGETPROPERTYVALUES
DESCRIPTOR.message_types_by_name['RespGetPropertyValues'] = _RESPGETPROPERTYVALUES
DESCRIPTOR.message_types_by_name['PropertyValue'] = _PROPERTYVALUE
DESCRIPTOR.message_types_by_name['CmdSetPropertyValues'] = _CMDSETPROPERTYVALUES
DESCRIPTOR.message_types_by_name['RespSetPropertyValues'] = _RESPSETPROPERTYVALUES
DESCRIPTOR.message_types_by_name['LocalCtrlMessage'] = _LOCALCTRLMESSAGE
DESCRIPTOR.enum_types_by_name['LocalCtrlMsgType'] = _LOCALCTRLMSGTYPE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
CmdGetPropertyCount = _reflection.GeneratedProtocolMessageType('CmdGetPropertyCount', (_message.Message,), dict(
DESCRIPTOR = _CMDGETPROPERTYCOUNT,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:CmdGetPropertyCount)
))
_sym_db.RegisterMessage(CmdGetPropertyCount)
RespGetPropertyCount = _reflection.GeneratedProtocolMessageType('RespGetPropertyCount', (_message.Message,), dict(
DESCRIPTOR = _RESPGETPROPERTYCOUNT,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:RespGetPropertyCount)
))
_sym_db.RegisterMessage(RespGetPropertyCount)
PropertyInfo = _reflection.GeneratedProtocolMessageType('PropertyInfo', (_message.Message,), dict(
DESCRIPTOR = _PROPERTYINFO,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:PropertyInfo)
))
_sym_db.RegisterMessage(PropertyInfo)
CmdGetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdGetPropertyValues', (_message.Message,), dict(
DESCRIPTOR = _CMDGETPROPERTYVALUES,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:CmdGetPropertyValues)
))
_sym_db.RegisterMessage(CmdGetPropertyValues)
RespGetPropertyValues = _reflection.GeneratedProtocolMessageType('RespGetPropertyValues', (_message.Message,), dict(
DESCRIPTOR = _RESPGETPROPERTYVALUES,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:RespGetPropertyValues)
))
_sym_db.RegisterMessage(RespGetPropertyValues)
PropertyValue = _reflection.GeneratedProtocolMessageType('PropertyValue', (_message.Message,), dict(
DESCRIPTOR = _PROPERTYVALUE,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:PropertyValue)
))
_sym_db.RegisterMessage(PropertyValue)
CmdSetPropertyValues = _reflection.GeneratedProtocolMessageType('CmdSetPropertyValues', (_message.Message,), dict(
DESCRIPTOR = _CMDSETPROPERTYVALUES,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:CmdSetPropertyValues)
))
_sym_db.RegisterMessage(CmdSetPropertyValues)
RespSetPropertyValues = _reflection.GeneratedProtocolMessageType('RespSetPropertyValues', (_message.Message,), dict(
DESCRIPTOR = _RESPSETPROPERTYVALUES,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:RespSetPropertyValues)
))
_sym_db.RegisterMessage(RespSetPropertyValues)
LocalCtrlMessage = _reflection.GeneratedProtocolMessageType('LocalCtrlMessage', (_message.Message,), dict(
DESCRIPTOR = _LOCALCTRLMESSAGE,
__module__ = 'esp_local_ctrl_pb2'
# @@protoc_insertion_point(class_scope:LocalCtrlMessage)
))
_sym_db.RegisterMessage(LocalCtrlMessage)
# @@protoc_insertion_point(module_scope)

View file

@ -0,0 +1,417 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include <protocomm.h>
#include <protocomm_security0.h>
#include <esp_local_ctrl.h>
#include "esp_local_ctrl_priv.h"
#include "esp_local_ctrl.pb-c.h"
#define ESP_LOCAL_CTRL_VERSION "v1.0"
struct inst_ctx {
protocomm_t *pc;
esp_local_ctrl_config_t config;
esp_local_ctrl_prop_t **props;
size_t props_count;
};
struct inst_ctx *local_ctrl_inst_ctx;
static const char *TAG = "esp_local_ctrl";
esp_err_t esp_local_ctrl_start(const esp_local_ctrl_config_t *config)
{
esp_err_t ret;
if (!config) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}
if (!config->transport) {
ESP_LOGE(TAG, "No transport provided");
return ESP_ERR_INVALID_ARG;
}
if (config->max_properties == 0) {
ESP_LOGE(TAG, "max_properties must be greater than 0");
return ESP_ERR_INVALID_ARG;
}
if (!config->handlers.get_prop_values ||
!config->handlers.set_prop_values) {
ESP_LOGE(TAG, "Handlers cannot be null");
return ESP_ERR_INVALID_ARG;
}
if (local_ctrl_inst_ctx) {
ESP_LOGW(TAG, "Service already active");
return ESP_ERR_INVALID_STATE;
}
local_ctrl_inst_ctx = calloc(1, sizeof(struct inst_ctx));
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Failed to allocate memory for instance");
return ESP_ERR_NO_MEM;
}
memcpy(&local_ctrl_inst_ctx->config, config, sizeof(local_ctrl_inst_ctx->config));
local_ctrl_inst_ctx->props = calloc(local_ctrl_inst_ctx->config.max_properties,
sizeof(esp_local_ctrl_prop_t *));
if (!local_ctrl_inst_ctx->props) {
ESP_LOGE(TAG, "Failed to allocate memory for properties");
free(local_ctrl_inst_ctx);
local_ctrl_inst_ctx = NULL;
return ESP_ERR_NO_MEM;
}
/* Since the config structure will be different for different transport modes, each transport may
* implement a `copy_config()` function, which accepts a configuration structure as input and
* creates a copy of that, which can be kept in the context structure of the `esp_local_ctrl` instance.
* This copy can be later be freed using `free_config()` */
if (config->transport->copy_config) {
ret = config->transport->copy_config(&local_ctrl_inst_ctx->config.transport_config,
&config->transport_config);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}
}
/* For a selected transport mode, endpoints may need to be declared prior to starting the
* `esp_local_ctrl` service, e.g. in case of BLE. By declaration it means that the transport layer
* allocates some resources for an endpoint, and later, after service has started, a handler
* is assigned for that endpoint */
if (config->transport->declare_ep) {
/* UUIDs are 16bit unique IDs for each endpoint. This may or may not be relevant for
* a chosen transport. We reserve all values from FF50 to FFFF for the internal endpoints.
* The remaining endpoints can be used by the application for its own custom endpoints */
uint16_t start_uuid = 0xFF50;
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/version", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/session", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}
ret = config->transport->declare_ep(&local_ctrl_inst_ctx->config.transport_config,
"esp_local_ctrl/control", start_uuid++);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}
}
local_ctrl_inst_ctx->pc = protocomm_new();
if (!local_ctrl_inst_ctx->pc) {
ESP_LOGE(TAG, "Failed to create new protocomm instance");
esp_local_ctrl_stop();
return ESP_FAIL;
}
if (config->transport->start_service) {
ret = config->transport->start_service(local_ctrl_inst_ctx->pc,
&local_ctrl_inst_ctx->config.transport_config);
if (ret != ESP_OK) {
esp_local_ctrl_stop();
return ret;
}
}
ret = protocomm_set_version(local_ctrl_inst_ctx->pc, "esp_local_ctrl/version",
ESP_LOCAL_CTRL_VERSION);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set version endpoint");
esp_local_ctrl_stop();
return ret;
}
ret = protocomm_set_security(local_ctrl_inst_ctx->pc, "esp_local_ctrl/session",
&protocomm_security0, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set session endpoint");
esp_local_ctrl_stop();
return ret;
}
ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, "esp_local_ctrl/control",
esp_local_ctrl_data_handler, NULL);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set control endpoint");
esp_local_ctrl_stop();
return ret;
}
return ESP_OK;
}
esp_err_t esp_local_ctrl_stop(void)
{
if (local_ctrl_inst_ctx) {
if (local_ctrl_inst_ctx->config.transport->free_config) {
local_ctrl_inst_ctx->config.transport->free_config(&local_ctrl_inst_ctx->config.transport_config);
}
if (local_ctrl_inst_ctx->pc) {
if (local_ctrl_inst_ctx->config.transport->stop_service) {
local_ctrl_inst_ctx->config.transport->stop_service(local_ctrl_inst_ctx->pc);
}
protocomm_delete(local_ctrl_inst_ctx->pc);
}
if (local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn) {
local_ctrl_inst_ctx->config.handlers.usr_ctx_free_fn(
local_ctrl_inst_ctx->config.handlers.usr_ctx);
}
/* Iterate through all properties one by one and free them */
for (uint32_t i = 0; i < local_ctrl_inst_ctx->config.max_properties; i++) {
if (local_ctrl_inst_ctx->props[i] == NULL) {
continue;
}
/* Release memory allocated for property data */
free(local_ctrl_inst_ctx->props[i]->name);
if (local_ctrl_inst_ctx->props[i]->ctx_free_fn) {
local_ctrl_inst_ctx->props[i]->ctx_free_fn(local_ctrl_inst_ctx->props[i]->ctx);
}
free(local_ctrl_inst_ctx->props[i]);
}
free(local_ctrl_inst_ctx->props);
free(local_ctrl_inst_ctx);
local_ctrl_inst_ctx = NULL;
}
return ESP_OK;
}
static int esp_local_ctrl_get_property_index(const char *name)
{
if (!local_ctrl_inst_ctx || !name) {
return -1;
}
/* Iterate through all properties one by one
* and find the one with matching name */
for (uint32_t i = 0; i < local_ctrl_inst_ctx->props_count; i++) {
if (strcmp(local_ctrl_inst_ctx->props[i]->name, name) == 0) {
return i;
}
}
return -1;
}
esp_err_t esp_local_ctrl_add_property(const esp_local_ctrl_prop_t *prop)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}
if (!prop || !prop->name) {
return ESP_ERR_INVALID_ARG;
}
if (esp_local_ctrl_get_property_index(prop->name) >= 0) {
ESP_LOGE(TAG, "Property with name %s exists", prop->name);
return ESP_ERR_INVALID_STATE;
}
if (local_ctrl_inst_ctx->config.max_properties
== local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Max properties limit reached. Cannot add property %s", prop->name);
return ESP_ERR_NO_MEM;
}
uint32_t i = local_ctrl_inst_ctx->props_count;
local_ctrl_inst_ctx->props[i] = calloc(1, sizeof(esp_local_ctrl_prop_t));
if (!local_ctrl_inst_ctx->props[i]) {
ESP_LOGE(TAG, "Failed to allocate memory for new property %s", prop->name);
return ESP_ERR_NO_MEM;
}
local_ctrl_inst_ctx->props[i]->name = strdup(prop->name);
if (!local_ctrl_inst_ctx->props[i]->name) {
ESP_LOGE(TAG, "Failed to allocate memory for property data %s", prop->name);
free(local_ctrl_inst_ctx->props[i]);
local_ctrl_inst_ctx->props[i] = NULL;
return ESP_ERR_NO_MEM;
}
local_ctrl_inst_ctx->props[i]->type = prop->type;
local_ctrl_inst_ctx->props[i]->size = prop->size;
local_ctrl_inst_ctx->props[i]->flags = prop->flags;
local_ctrl_inst_ctx->props[i]->ctx = prop->ctx;
local_ctrl_inst_ctx->props[i]->ctx_free_fn = prop->ctx_free_fn;
local_ctrl_inst_ctx->props_count++;
return ESP_OK;
}
esp_err_t esp_local_ctrl_remove_property(const char *name)
{
int idx = esp_local_ctrl_get_property_index(name);
if (idx < 0) {
ESP_LOGE(TAG, "Property %s not found", name);
return ESP_ERR_NOT_FOUND;
}
/* Release memory allocated for property data */
if (local_ctrl_inst_ctx->props[idx]->ctx_free_fn) {
local_ctrl_inst_ctx->props[idx]->ctx_free_fn(
local_ctrl_inst_ctx->props[idx]->ctx);
}
free(local_ctrl_inst_ctx->props[idx]->name);
free(local_ctrl_inst_ctx->props[idx]);
local_ctrl_inst_ctx->props[idx++] = NULL;
/* Move the following properties forward, so that there is
* no empty space between two properties */
for (uint32_t i = idx; i < local_ctrl_inst_ctx->props_count; i++) {
if (local_ctrl_inst_ctx->props[i] == NULL) {
break;
}
local_ctrl_inst_ctx->props[i-1] = local_ctrl_inst_ctx->props[i];
}
local_ctrl_inst_ctx->props_count--;
return ESP_OK;
}
const esp_local_ctrl_prop_t *esp_local_ctrl_get_property(const char *name)
{
int idx = esp_local_ctrl_get_property_index(name);
if (idx < 0) {
ESP_LOGE(TAG, "Property %s not found", name);
return NULL;
}
return local_ctrl_inst_ctx->props[idx];
}
esp_err_t esp_local_ctrl_get_prop_count(size_t *count)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}
if (!count) {
return ESP_ERR_INVALID_ARG;
}
*count = local_ctrl_inst_ctx->props_count;
return ESP_OK;
}
esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices,
esp_local_ctrl_prop_t *props,
esp_local_ctrl_prop_val_t *values)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}
if (!indices || !props || !values) {
return ESP_ERR_INVALID_ARG;
}
/* Convert indices to names */
for (size_t i = 0; i < total_indices; i++) {
if (indices[i] >= local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Invalid property index %d", indices[i]);
return ESP_ERR_INVALID_ARG;
}
props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name;
props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type;
props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags;
props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx;
}
esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers;
esp_err_t ret = h->get_prop_values(total_indices, props, values, h->usr_ctx);
/* Properties with fixed sizes need to be checked */
for (size_t i = 0; i < total_indices; i++) {
if (local_ctrl_inst_ctx->props[indices[i]]->size != 0) {
values[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
}
}
return ret;
}
esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices,
const esp_local_ctrl_prop_val_t *values)
{
if (!local_ctrl_inst_ctx) {
ESP_LOGE(TAG, "Service not running");
return ESP_ERR_INVALID_STATE;
}
if (!indices || !values) {
return ESP_ERR_INVALID_ARG;
}
esp_local_ctrl_prop_t *props = calloc(total_indices,
sizeof(esp_local_ctrl_prop_t));
if (!props) {
ESP_LOGE(TAG, "Unable to allocate memory for properties array");
return ESP_ERR_NO_MEM;
}
for (size_t i = 0; i < total_indices; i++) {
if (indices[i] >= local_ctrl_inst_ctx->props_count) {
ESP_LOGE(TAG, "Invalid property index %d", indices[i]);
free(props);
return ESP_ERR_INVALID_ARG;
}
/* Properties with fixed sizes need to be checked */
if ((local_ctrl_inst_ctx->props[indices[i]]->size != values[i].size) &&
(local_ctrl_inst_ctx->props[indices[i]]->size != 0)) {
ESP_LOGE(TAG, "Invalid property size %d. Expected %d",
values[i].size, local_ctrl_inst_ctx->props[indices[i]]->size);
free(props);
return ESP_ERR_INVALID_ARG;
}
props[i].name = local_ctrl_inst_ctx->props[indices[i]]->name;
props[i].type = local_ctrl_inst_ctx->props[indices[i]]->type;
props[i].flags = local_ctrl_inst_ctx->props[indices[i]]->flags;
props[i].size = local_ctrl_inst_ctx->props[indices[i]]->size;
props[i].ctx = local_ctrl_inst_ctx->props[indices[i]]->ctx;
}
esp_local_ctrl_handlers_t *h = &local_ctrl_inst_ctx->config.handlers;
esp_err_t ret = h->set_prop_values(total_indices, props, values, h->usr_ctx);
free(props);
return ret;
}
esp_err_t esp_local_ctrl_set_handler(const char *ep_name,
protocomm_req_handler_t handler,
void *priv_data)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
if (local_ctrl_inst_ctx) {
ret = protocomm_add_endpoint(local_ctrl_inst_ctx->pc, ep_name,
handler, priv_data);
}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to register endpoint handler");
}
return ret;
}

View file

@ -0,0 +1,298 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include "esp_local_ctrl.h"
#include "esp_local_ctrl_priv.h"
#include "esp_local_ctrl.pb-c.h"
#define SAFE_ALLOCATION(type, var) \
type *var = (type *) malloc(sizeof(type)); \
if (!var) { \
ESP_LOGE(TAG, "Error allocating memory"); \
return ESP_ERR_NO_MEM; \
}
static const char* TAG = "esp_local_ctrl_handler";
typedef struct esp_local_ctrl_cmd {
int cmd_num;
esp_err_t (*command_handler)(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx);
} esp_local_ctrl_cmd_t;
static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx);
static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx);
static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx);
static esp_local_ctrl_cmd_t cmd_table[] = {
{
.cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyCount,
.command_handler = cmd_get_prop_count_handler
},
{
.cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdGetPropertyValues,
.command_handler = cmd_get_prop_vals_handler
},
{
.cmd_num = LOCAL_CTRL_MSG_TYPE__TypeCmdSetPropertyValues,
.command_handler = cmd_set_prop_vals_handler
}
};
static uint16_t err_to_status(esp_err_t err)
{
uint16_t status;
switch (err) {
case ESP_OK:
status = STATUS__Success;
break;
case ESP_ERR_INVALID_ARG:
status = STATUS__InvalidArgument;
break;
case ESP_ERR_INVALID_STATE:
status = STATUS__InvalidProto;
break;
default:
status = STATUS__InternalError;
}
return status;
}
static esp_err_t cmd_get_prop_count_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx)
{
SAFE_ALLOCATION(RespGetPropertyCount, resp_payload);
resp_get_property_count__init(resp_payload);
size_t prop_count = 0;
resp_payload->status = err_to_status(esp_local_ctrl_get_prop_count(&prop_count));
resp_payload->count = prop_count;
resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_COUNT;
resp->resp_get_prop_count = resp_payload;
ESP_LOGD(TAG, "Got properties count %d", prop_count);
return ESP_OK;
}
typedef void (*prop_val_free_fn_t)(void *val);
static esp_err_t cmd_get_prop_vals_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx)
{
SAFE_ALLOCATION(RespGetPropertyValues, resp_payload);
resp_get_property_values__init(resp_payload);
esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_get_prop_vals->n_indices,
sizeof(esp_local_ctrl_prop_val_t));
esp_local_ctrl_prop_t *descs = calloc(req->cmd_get_prop_vals->n_indices,
sizeof(esp_local_ctrl_prop_t));
prop_val_free_fn_t *free_fns = calloc(req->cmd_get_prop_vals->n_indices,
sizeof(prop_val_free_fn_t));
resp_payload->props = calloc(req->cmd_get_prop_vals->n_indices,
sizeof(PropertyInfo *));
if (!vals || !descs || !free_fns || !resp_payload->props) {
ESP_LOGE(TAG, "Failed to allocate memory for getting values");
free(vals);
free(descs);
free(free_fns);
free(resp_payload->props);
free(resp_payload);
return ESP_ERR_NO_MEM;
}
esp_err_t ret = esp_local_ctrl_get_prop_values(req->cmd_get_prop_vals->n_indices,
req->cmd_get_prop_vals->indices,
descs, vals);
resp_payload->status = err_to_status(ret);
if (ret == ESP_OK) {
resp_payload->n_props = 0;
for (size_t i = 0; i < req->cmd_get_prop_vals->n_indices; i++) {
resp_payload->props[i] = malloc(sizeof(PropertyInfo));
if (!resp_payload->props[i]) {
resp_payload->status = STATUS__InternalError;
break;
}
resp_payload->n_props++;
property_info__init(resp_payload->props[i]);
resp_payload->props[i]->name = descs[i].name;
resp_payload->props[i]->type = descs[i].type;
resp_payload->props[i]->flags = descs[i].flags;
resp_payload->props[i]->value.data = vals[i].data;
resp_payload->props[i]->value.len = vals[i].size;
free_fns[i] = vals[i].free_fn;
}
}
resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_GET_PROP_VALS;
resp->resp_get_prop_vals = resp_payload;
(*ctx) = (void *)free_fns;
free(vals);
free(descs);
/* Unless it's a fatal error, always return ESP_OK, otherwise
* the underlying connection will be closed by protocomm */
return ESP_OK;
}
static esp_err_t cmd_set_prop_vals_handler(LocalCtrlMessage *req,
LocalCtrlMessage *resp, void **ctx)
{
SAFE_ALLOCATION(RespSetPropertyValues, resp_payload);
resp_set_property_values__init(resp_payload);
uint32_t *idxs = calloc(req->cmd_set_prop_vals->n_props, sizeof(uint32_t));
esp_local_ctrl_prop_val_t *vals = calloc(req->cmd_set_prop_vals->n_props,
sizeof(esp_local_ctrl_prop_val_t));
if (!idxs || !vals) {
ESP_LOGE(TAG, "Failed to allocate memory for setting values");
free(idxs);
free(vals);
return ESP_ERR_NO_MEM;
}
for (size_t i = 0; i < req->cmd_set_prop_vals->n_props; i++) {
idxs[i] = req->cmd_set_prop_vals->props[i]->index;
vals[i].data = req->cmd_set_prop_vals->props[i]->value.data;
vals[i].size = req->cmd_set_prop_vals->props[i]->value.len;
}
esp_err_t ret = esp_local_ctrl_set_prop_values(req->cmd_set_prop_vals->n_props,
idxs, vals);
resp_payload->status = err_to_status(ret);
resp->payload_case = LOCAL_CTRL_MESSAGE__PAYLOAD_RESP_SET_PROP_VALS;
resp->resp_set_prop_vals = resp_payload;
free(idxs);
free(vals);
/* Unless it's a fatal error, always return ESP_OK, otherwise
* the underlying connection will be closed by protocomm */
return ESP_OK;
}
static int lookup_cmd_handler(int cmd_id)
{
int i;
for (i = 0; i < sizeof(cmd_table)/sizeof(esp_local_ctrl_cmd_t); i++) {
if (cmd_table[i].cmd_num == cmd_id) {
return i;
}
}
return -1;
}
static void esp_local_ctrl_command_cleanup(LocalCtrlMessage *resp, void **ctx)
{
if (!resp) {
return;
}
switch (resp->msg) {
case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyCount:
free(resp->resp_get_prop_count);
break;
case LOCAL_CTRL_MSG_TYPE__TypeRespGetPropertyValues: {
if (resp->resp_get_prop_vals) {
prop_val_free_fn_t *free_fns = (prop_val_free_fn_t *)(*ctx);
for (size_t i = 0; i < resp->resp_get_prop_vals->n_props; i++) {
if (free_fns[i]) {
free_fns[i](resp->resp_get_prop_vals->props[i]->value.data);
}
free(resp->resp_get_prop_vals->props[i]);
}
free(free_fns);
free(resp->resp_get_prop_vals->props);
free(resp->resp_get_prop_vals);
}
}
break;
case LOCAL_CTRL_MSG_TYPE__TypeRespSetPropertyValues:
free(resp->resp_set_prop_vals);
break;
default:
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
}
return;
}
static esp_err_t esp_local_ctrl_command_dispatcher(LocalCtrlMessage *req,
LocalCtrlMessage *resp,
void **ctx)
{
int cmd_index = lookup_cmd_handler(req->msg);
if (cmd_index < 0) {
ESP_LOGE(TAG, "Invalid command handler lookup");
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = cmd_table[cmd_index].command_handler(req, resp, ctx);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Error executing command handler");
return ret;
}
return ESP_OK;
}
esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
{
void *temp_ctx = NULL;
LocalCtrlMessage *req = local_ctrl_message__unpack(NULL, inlen, inbuf);
if (!req) {
ESP_LOGE(TAG, "Unable to unpack payload data");
return ESP_ERR_INVALID_ARG;
}
LocalCtrlMessage resp;
local_ctrl_message__init(&resp);
resp.msg = req->msg + 1; /* Response is request + 1 */
esp_err_t ret = esp_local_ctrl_command_dispatcher(req, &resp, &temp_ctx);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "command dispatcher failed");
esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
local_ctrl_message__free_unpacked(req, NULL);
return ESP_FAIL;
}
local_ctrl_message__free_unpacked(req, NULL);
*outlen = local_ctrl_message__get_packed_size(&resp);
if (*outlen <= 0) {
ESP_LOGE(TAG, "Invalid encoding for response");
esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
return ESP_FAIL;
}
*outbuf = (uint8_t *) malloc(*outlen);
if (!*outbuf) {
ESP_LOGE(TAG, "System out of memory");
esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
return ESP_ERR_NO_MEM;
}
local_ctrl_message__pack(&resp, *outbuf);
esp_local_ctrl_command_cleanup(&resp, &temp_ctx);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, *outbuf, *outlen, ESP_LOG_DEBUG);
return ESP_OK;
}

View file

@ -0,0 +1,153 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <esp_err.h>
#include <protocomm.h>
#include <esp_local_ctrl.h>
/**
* @brief `esp_local_ctrl` transport specific structure
*
* Every supported transport layer should have the following functions
* implemented for starting, stopping and configuring a protocomm service
*/
struct esp_local_ctrl_transport {
/**
* Handler for starting a protocomm service as per specified configuration
*/
esp_err_t (*start_service) (protocomm_t *pc,
const esp_local_ctrl_transport_config_t *config);
/**
* Handler for stopping a protocomm service
*/
void (*stop_service) (protocomm_t *pc);
/**
* Handler for creating a copy of the transport specific configuration
*/
esp_err_t (*copy_config) (esp_local_ctrl_transport_config_t *dest_config,
const esp_local_ctrl_transport_config_t *src_config);
/**
* Handler for allocating resources corresponding to a protocomm endpoint.
* Usually when adding a new endpoint `protocomm_endpoint_add()` API is used,
* but the transport layer may need to perform resource allocation for
* each endpoint, prior to starting the protocomm instance. This handler
* is useful in that case, as it is called before `start_service()`.
*/
esp_err_t (*declare_ep) (esp_local_ctrl_transport_config_t *config,
const char *ep_name, uint16_t ep_uuid);
/**
* Handler for freeing a transport specific configuration
*/
void (*free_config) (esp_local_ctrl_transport_config_t *config);
};
/**
* @brief Protocomm handler for `esp_local_ctrl`
*
* This is the handler which is responsible for processing incoming requests
* over a protocomm channel, then invokes one of the following functions
* depending upon the request type:
* - `esp_local_ctrl_get_prop_count()`
* - `esp_local_ctrl_get_prop_values()`
* -` esp_local_ctrl_set_prop_values()`
* The output of the above functions are used to form the response messages
* corresponding to request types. The formed response messages are packed and
* sent back via the protocomm channel.
*
* @param[in] session_id A number to identify an ongoing session between
* device and client
* @param[in] inbuf Buffer which holds serialized / packed request data
* @param[in] inlen Length of input buffer
* @param[out] outbuf Buffer which holds serialized / packed response data
* @param[out] outlen Length of output buffer
* @param[in] priv_data Private data associated with `esp_local_ctrl` endpoint
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
uint8_t **outbuf, ssize_t *outlen, void *priv_data);
/**
* @brief Use this for obtaining total number of properties registered
* with `esp_local_ctrl` service
*
* @param[out] count Pointer to variable where the result is to be stored
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_get_prop_count(size_t *count);
/**
* @brief Get descriptions and values of multiple properties at the same time.
* The properties are requested by indices. This internally calls the
* `get_prop_values` handler specified in the `esp_local_ctrl_handlers_t`
* structure. Since `get_prop_values` accepts property structure, the
* indices are first converted to the corresponding `esp_local_ctrl_prop_t`
* internally.
*
* @param[in] total_indices The number of elements in the `indices` array argument
* @param[in] indices An array of indices, that specify which properties to get
* @param[out] props A pre-allocated array of empty property structures, elements of
* which are to be populated with names, types and flags of those
* properties which correspond to the provided indices
* @param[out] values A pre-allocated array of empty value structures, elements of
* which are to be populated with values and sizes of those
* properties which correspond to the provided indices
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_get_prop_values(size_t total_indices, uint32_t *indices,
esp_local_ctrl_prop_t *props,
esp_local_ctrl_prop_val_t *values);
/**
* @brief Set values of multiple properties at the same time. The properties to
* set are specified by indices. This internally calls the `set_prop_values`
* handler specified in the `esp_local_ctrl_handlers_t` structure. Since
* `set_prop_values` accepts property structures, the indices are first
* converted to the corresponding `esp_local_ctrl_prop_t` internally.
*
* @param[in] total_indices The number of elements in the `indices` array argument
* @param[in] indices An array of indices, that specify which properties to set
* @param[in] values A array of values. Every value should have the correct
* size, if it is for setting a fixed size property, else
* error will be generated and none of the properties will
* be set to any of the given values
*
* @return
* - ESP_OK : Success
* - ESP_FAIL : Failure
*/
esp_err_t esp_local_ctrl_set_prop_values(size_t total_indices, uint32_t *indices,
const esp_local_ctrl_prop_val_t *values);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,140 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include <protocomm_ble.h>
#include <esp_local_ctrl.h>
#include "esp_local_ctrl_priv.h"
#define LOCAL_CTRL_VERSION "v1.0"
static const char *TAG = "esp_local_ctrl_transport_ble";
static esp_err_t start_ble_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config)
{
if (!config || !config->ble) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}
return protocomm_ble_start(pc, config->ble);
}
static void stop_ble_transport(protocomm_t *pc)
{
protocomm_ble_stop(pc);
}
static esp_err_t copy_ble_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config)
{
if (!dest_config || !src_config || !src_config->ble) {
ESP_LOGE(TAG, "NULL arguments provided");
return ESP_ERR_INVALID_ARG;
}
dest_config->ble = calloc(1, sizeof(protocomm_ble_config_t));
if (!dest_config->ble) {
ESP_LOGE(TAG, "Failed to allocate memory for BLE transport config");
return ESP_ERR_NO_MEM;
}
/* Copy BLE device name */
memcpy(dest_config->ble->device_name,
src_config->ble->device_name,
sizeof(src_config->ble->device_name));
/* Copy Service UUID */
memcpy(dest_config->ble->service_uuid,
src_config->ble->service_uuid,
sizeof(src_config->ble->service_uuid));
dest_config->ble->nu_lookup_count = 0;
if (src_config->ble->nu_lookup_count) {
/* Copy any provided name-uuid lookup table */
dest_config->ble->nu_lookup = calloc(src_config->ble->nu_lookup_count,
sizeof(protocomm_ble_name_uuid_t));
if (!dest_config->ble->nu_lookup) {
ESP_LOGE(TAG, "Failed to allocate memory for BLE characteristic names");
free(dest_config->ble);
return ESP_ERR_NO_MEM;
}
for (uint16_t i = 0; i < src_config->ble->nu_lookup_count; i++) {
dest_config->ble->nu_lookup[i].uuid = src_config->ble->nu_lookup[i].uuid;
if (!src_config->ble->nu_lookup[i].name) {
ESP_LOGE(TAG, "Endpoint name cannot be null");
return ESP_ERR_INVALID_ARG;
}
dest_config->ble->nu_lookup[i].name = strdup(src_config->ble->nu_lookup[i].name);
if (!dest_config->ble->nu_lookup[i].name) {
ESP_LOGE(TAG, "Failed to allocate memory for endpoint name");
return ESP_ERR_NO_MEM;
}
dest_config->ble->nu_lookup_count++;
}
}
return ESP_OK;
}
static esp_err_t declare_endpoint(esp_local_ctrl_transport_config_t *config, const char *ep_name, uint16_t ep_uuid)
{
if (!config || !config->ble) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}
protocomm_ble_name_uuid_t *nu_lookup = realloc(config->ble->nu_lookup,
(config->ble->nu_lookup_count + 1)
* sizeof(protocomm_ble_name_uuid_t));
if (!nu_lookup) {
ESP_LOGE(TAG, "Failed to allocate memory for new endpoint entry");
return ESP_ERR_NO_MEM;
}
config->ble->nu_lookup = nu_lookup;
nu_lookup[config->ble->nu_lookup_count].uuid = ep_uuid;
nu_lookup[config->ble->nu_lookup_count].name = strdup(ep_name);
if (!nu_lookup[config->ble->nu_lookup_count].name) {
ESP_LOGE(TAG, "Failed to allocate memory for new endpoint name");
return ESP_ERR_NO_MEM;
}
config->ble->nu_lookup_count++;
return ESP_OK;
}
static void free_config(esp_local_ctrl_transport_config_t *config)
{
if (config && config->ble) {
for (unsigned int i = 0; i < config->ble->nu_lookup_count; i++) {
free((void*) config->ble->nu_lookup[i].name);
}
free(config->ble->nu_lookup);
free(config->ble);
config->ble = NULL;
}
}
const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_ble(void)
{
static const esp_local_ctrl_transport_t tp = {
.start_service = start_ble_transport,
.stop_service = stop_ble_transport,
.copy_config = copy_ble_config,
.declare_ep = declare_endpoint,
.free_config = free_config
};
return &tp;
};

View file

@ -0,0 +1,128 @@
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include <esp_err.h>
#include <esp_log.h>
#include <mdns.h>
#include <protocomm_httpd.h>
#include <esp_local_ctrl.h>
#include <esp_https_server.h>
#include "esp_local_ctrl_priv.h"
#define LOCAL_CTRL_VERSION "v1.0"
static const char *TAG = "esp_local_ctrl_transport_httpd";
static httpd_handle_t server_handle = NULL;
static esp_err_t start_httpd_transport(protocomm_t *pc, const esp_local_ctrl_transport_config_t *config)
{
if (!config || !config->httpd) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}
/* Extract configured port */
uint16_t port = (
config->httpd->transport_mode == HTTPD_SSL_TRANSPORT_SECURE ?
config->httpd->port_secure :
config->httpd->port_insecure
);
esp_err_t err = mdns_service_add("Local Control Service", "_esp_local_ctrl",
"_tcp", port, NULL, 0);
if (err != ESP_OK) {
/* mDNS is not mandatory for provisioning to work,
* so print warning and return without failure */
ESP_LOGW(TAG, "Error adding mDNS service! Check if mDNS is running");
} else {
/* Information to identify the roles of the various
* protocomm endpoint URIs provided by the service */
err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp",
"version_endpoint", "/esp_local_ctrl/version");
err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp",
"session_endpoint", "/esp_local_ctrl/session");
err |= mdns_service_txt_item_set("_esp_local_ctrl", "_tcp",
"control_endpoint", "/esp_local_ctrl/control");
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error adding mDNS service text item");
}
}
err = httpd_ssl_start(&server_handle, config->httpd);
if (ESP_OK != err) {
ESP_LOGE(TAG, "Error starting HTTPS service!");
mdns_service_remove("_esp_local_ctrl", "_tcp");
return err;
}
protocomm_httpd_config_t pc_conf = {
.ext_handle_provided = true,
.data = {
.handle = &server_handle
}
};
return protocomm_httpd_start(pc, &pc_conf);
}
static void stop_httpd_transport(protocomm_t *pc)
{
mdns_service_remove("_esp_local_ctrl", "_tcp");
protocomm_httpd_stop(pc);
httpd_ssl_stop(server_handle);
server_handle = NULL;
}
static esp_err_t copy_httpd_config(esp_local_ctrl_transport_config_t *dest_config, const esp_local_ctrl_transport_config_t *src_config)
{
if (!dest_config || !src_config || !src_config->httpd) {
ESP_LOGE(TAG, "NULL configuration provided");
return ESP_ERR_INVALID_ARG;
}
dest_config->httpd = calloc(1, sizeof(httpd_ssl_config_t));
if (!dest_config->httpd) {
ESP_LOGE(TAG, "Failed to allocate memory for HTTPD transport config");
return ESP_ERR_NO_MEM;
}
memcpy(dest_config->httpd,
src_config->httpd,
sizeof(httpd_ssl_config_t));
return ESP_OK;
}
static void free_config(esp_local_ctrl_transport_config_t *config)
{
if (config && config->httpd) {
free(config->httpd);
config->httpd = NULL;
}
}
const esp_local_ctrl_transport_t *esp_local_ctrl_get_transport_httpd(void)
{
static const esp_local_ctrl_transport_t tp = {
.start_service = start_httpd_transport,
.stop_service = stop_httpd_transport,
.copy_config = copy_httpd_config,
.declare_ep = NULL,
.free_config = free_config
};
return &tp;
};

View file

@ -48,7 +48,7 @@ typedef struct name_uuid {
/**
* @brief Config parameters for protocomm BLE service
*/
typedef struct {
typedef struct protocomm_ble_config {
/**
* BLE device name being broadcast at the time of provisioning
*/

View file

@ -107,8 +107,11 @@ INPUT = \
../../components/mdns/include/mdns.h \
../../components/esp_http_client/include/esp_http_client.h \
../../components/esp_websocket_client/include/esp_websocket_client.h \
## HTTP / HTTPS Server
../../components/esp_http_server/include/esp_http_server.h \
../../components/esp_https_server/include/esp_https_server.h \
## ESP Local Ctrl
../../components/esp_local_ctrl/include/esp_local_ctrl.h \
##
## Provisioning - API Reference
##

View file

@ -0,0 +1,206 @@
ESP Local Control
=================
Overview
--------
ESP Local Control (**esp_local_ctrl**) component in ESP-IDF provides capability to control an ESP device over Wi-Fi + HTTPS or BLE. It provides access to application defined **properties** that are available for reading / writing via a set of configurable handlers.
Initialization of the **esp_local_ctrl** service over BLE transport is performed as follows:
.. highlight:: c
::
esp_local_ctrl_config_t config = {
.transport = ESP_LOCAL_CTRL_TRANSPORT_BLE,
.transport_config = {
.ble = & (protocomm_ble_config_t) {
.device_name = SERVICE_NAME,
.service_uuid = {
/* LSB <---------------------------------------
* ---------------------------------------> MSB */
0x21, 0xd5, 0x3b, 0x8d, 0xbd, 0x75, 0x68, 0x8a,
0xb4, 0x42, 0xeb, 0x31, 0x4a, 0x1e, 0x98, 0x3d
}
}
},
.handlers = {
/* User defined handler functions */
.get_prop_values = get_property_values,
.set_prop_values = set_property_values,
.usr_ctx = NULL,
.usr_ctx_free_fn = NULL
},
/* Maximum number of properties that may be set */
.max_properties = 10
};
/* Start esp_local_ctrl service */
ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Similarly for HTTPS transport:
.. highlight:: c
::
/* Set the configuration */
httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT();
/* Load server certificate */
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
https_conf.cacert_pem = cacert_pem_start;
https_conf.cacert_len = cacert_pem_end - cacert_pem_start;
/* Load server private key */
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
https_conf.prvtkey_pem = prvtkey_pem_start;
https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
esp_local_ctrl_config_t config = {
.transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD,
.transport_config = {
.httpd = &https_conf
},
.handlers = {
/* User defined handler functions */
.get_prop_values = get_property_values,
.set_prop_values = set_property_values,
.usr_ctx = NULL,
.usr_ctx_free_fn = NULL
},
/* Maximum number of properties that may be set */
.max_properties = 10
};
/* Start esp_local_ctrl service */
ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
Creating a property
===================
Now that we know how to start the **esp_local_ctrl** service, let's add a property to it. Each property must have a unique `name` (string), a `type` (e.g. enum), `flags` (bit fields) and `size`.
The `size` is to be kept 0, if we want our property value to be of variable length (e.g. if its a string or bytestream). For fixed length property value data-types, like int, float, etc., setting the `size` field to the right value, helps **esp_local_ctrl** to perform internal checks on arguments received with write requests.
The interpretation of `type` and `flags` fields is totally upto the application, hence they may be used as enumerations, bitfields, or even simple integers. One way is to use `type` values to classify properties, while `flags` to specify characteristics of a property.
Here is an example property which is to function as a timestamp. It is assumed that the application defines `TYPE_TIMESTAMP` and `READONLY`, which are used for setting the `type` and `flags` fields here.
.. highlight:: c
::
/* Create a timestamp property */
esp_local_ctrl_prop_t timestamp = {
.name = "timestamp",
.type = TYPE_TIMESTAMP,
.size = sizeof(int32_t),
.flags = READONLY,
.ctx = func_get_time,
.ctx_free_fn = NULL
};
/* Now register the property */
esp_local_ctrl_add_property(&timestamp);
Also notice that there is a ctx field, which is set to point to some custom `func_get_time()`. This can be used inside the property get / set handlers to retrieve timestamp.
Here is an example of `get_prop_values()` handler, which is used for retrieving the timestamp.
.. highlight:: c
::
static esp_err_t get_property_values(size_t props_count,
const esp_local_ctrl_prop_t *props,
esp_local_ctrl_prop_val_t *prop_values,
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
ESP_LOGI(TAG, "Reading %s", props[i].name);
if (props[i].type == TYPE_TIMESTAMP) {
/* Obtain the timer function from ctx */
int32_t (*func_get_time)(void) = props[i].ctx;
/* Use static variable for saving the value.
* This is essential because the value has to be
* valid even after this function returns.
* Alternative is to use dynamic allocation
* and set the free_fn field */
static int32_t ts = func_get_time();
prop_values[i].data = &ts;
}
}
return ESP_OK;
}
Here is an example of `set_prop_values()` handler. Notice how we restrict from writing to read-only properties.
.. highlight:: c
::
static esp_err_t set_property_values(size_t props_count,
const esp_local_ctrl_prop_t *props,
const esp_local_ctrl_prop_val_t *prop_values,
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
if (props[i].flags & READONLY) {
ESP_LOGE(TAG, "Cannot write to read-only property %s", props[i].name);
return ESP_ERR_INVALID_ARG;
} else {
ESP_LOGI(TAG, "Setting %s", props[i].name);
/* For keeping it simple, lets only log the incoming data */
ESP_LOG_BUFFER_HEX_LEVEL(TAG, prop_values[i].data,
prop_values[i].size, ESP_LOG_INFO);
}
}
return ESP_OK;
}
For complete example see :example:`protocols/esp_local_ctrl`
Client Side Implementation
==========================
The client side implementation will have establish a protocomm session with the device first, over the supported mode of transport, and then send and receive protobuf messages understood by the **esp_local_ctrl** service. The service will translate these messages into requests and then call the appropriate handlers (set / get). Then, the generated response for each handler is again packed into a protobuf message and transmitted back to the client.
See below the various protobuf messages understood by the **esp_local_ctrl** service:
1. `get_prop_count` : This should simply return the total number of properties supported by the service
2. `get_prop_values` : This accepts an array of indices and should return the information (name, type, flags) and values of the properties corresponding to those indices
3. `set_prop_values` : This accepts an array of indices and an array of new values, which are used for setting the values of the properties corresponding to the indices
Note that indices may or may not be the same for a property, across multiple sessions. Therefore, the client must only use the names of the properties to uniquely identify them. So, every time a new session is established, the client should first call `get_prop_count` and then `get_prop_values`, hence form an index to name mapping for all properties. Now when calling `set_prop_values` for a set of properties, it must first convert the names to indexes, using the created mapping. As emphasized earlier, the client must refresh the index to name mapping every time a new session is established with the same device.
The various protocomm endpoints provided by **esp_local_ctrl** are listed below:
.. list-table:: Endpoints provided by ESP Local Control
:widths: 10 25 50
:header-rows: 1
* - Endpoint Name (BLE + GATT Server)
- URI (HTTPS Server + mDNS)
- Description
* - esp_local_ctrl/version
- https://<mdns-hostname>.local/esp_local_ctrl/version
- Endpoint used for retrieving version string
* - esp_local_ctrl/control
- https://<mdns-hostname>.local/esp_local_ctrl/control
- Endpoint used for sending / receiving control messages
API Reference
-------------
.. include:: /_build/inc/esp_local_ctrl.inc

View file

@ -14,6 +14,7 @@ Application Protocols
ASIO <asio>
ESP-MQTT <mqtt>
Modbus <modbus>
Local Control <esp_local_ctrl>
Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples.

View file

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/protocols/esp_local_ctrl.rst

View file

@ -14,6 +14,7 @@
ASIO <asio>
ESP-MQTT <mqtt>
Modbus slave <modbus>
Local Control <esp_local_ctrl>
此 API 部分的示例代码在 ESP-IDF 示例工程的 :example:`protocols` 目录下提供。

View file

@ -0,0 +1,10 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_local_ctrl)

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := esp_local_ctrl
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,93 @@
# ESP Local Control using HTTPS server
This example creates a `esp_local_ctrl` service over HTTPS transport, for securely controlling the device over local network. In this case the device name is resolved through `mDNS`, which in this example is `my_esp_ctrl_device.local`.
See the `esp_local_ctrl` component documentation for details.
Before using the example, run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details.
## Client Side Implementation
A python test script `scripts/esp_local_ctrl.py` has been provided for as a client side application for controlling the device over the same Wi-Fi network. The script relies on a pre-generated `main/certs/rootCA.pem` to verify the server certificate. The server side private key and certificate can also be found under `main/certs`, namely `prvtkey.pem` and `cacert.pem`.
After configuring the Wi-Fi, flashing and booting the device, run:
```
python scripts/esp_local_ctrl.py
```
Sample output:
```
python2 scripts/esp_local_ctrl.py
==== Acquiring properties information ====
==== Acquired properties information ====
==== Available Properties ====
S.N. Name Type Flags Value
[ 1] timestamp (us) TIME(us) Read-Only 168561481
[ 2] property1 INT32 123456
[ 3] property2 BOOLEAN Read-Only True
[ 4] property3 STRING
Select properties to set (0 to re-read, 'q' to quit) : 0
==== Available Properties ====
S.N. Name Type Flags Value
[ 1] timestamp (us) TIME(us) Read-Only 22380117
[ 2] property1 INT32 123456
[ 3] property2 BOOLEAN Read-Only False
[ 4] property3 STRING
Select properties to set (0 to re-read, 'q' to quit) : 2,4
Enter value to set for property (property1) : -5555
Enter value to set for property (property3) : hello world!
==== Available Properties ====
S.N. Name Type Flags Value
[ 1] timestamp (us) TIME(us) Read-Only 55110859
[ 2] property1 INT32 -5555
[ 3] property2 BOOLEAN Read-Only False
[ 4] property3 STRING hello world!
Select properties to set (0 to re-read, 'q' to quit) : q
Quitting...
```
The script also allows to connect over BLE, and provide a custom service name. To display the list of supported parameters, run:
```
python scripts/esp_local_ctrl.py --help
```
## Certificates
You can generate a new server certificate using the OpenSSL command line tool.
For the purpose of this example, lets generate a rootCA, which we will use to sign the server certificates and which the client will use to verify the server certificate during SSL handshake. You will need to set a password for encrypting the generated `rootkey.pem`.
```
openssl req -new -x509 -subj "/CN=root" -days 3650 -sha256 -out rootCA.pem -keyout rootkey.pem
```
Now generate a certificate signing request for the server, along with its private key `prvtkey.pem`.
```
openssl req -newkey rsa:2048 -nodes -keyout prvtkey.pem -days 3650 -out server.csr -subj "/CN=my_esp_ctrl_device.local"
```
Now use the previously generated rootCA to process the server's certificate signing request, and generate a signed certificate `cacert.pem`. The password set for encrypting `rootkey.pem` earlier, has to be entered during this step.
```
openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootkey.pem -CAcreateserial -out cacert.pem -days 500 -sha256
```
Now that we have `rootCA.pem`, `cacert.pem` and `prvtkey.pem`, copy these into main/certs. Note that only the server related files (`cacert.pem` and `prvtkey.pem`) are embedded into the firmware.
Expiry time and metadata fields can be adjusted in the invocation.
Please see the `openssl` man pages (man `openssl-req`) for more details.
It is **strongly recommended** to not reuse the example certificate in your application;
it is included only for demonstration.

View file

@ -0,0 +1,8 @@
set(COMPONENT_SRCS "app_main.c" "esp_local_ctrl_service.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
set(COMPONENT_EMBED_TXTFILES
"certs/cacert.pem"
"certs/prvtkey.pem")
register_component()

View file

@ -0,0 +1,20 @@
menu "Example Configuration"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu

View file

@ -0,0 +1,111 @@
/* Local Ctrl Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#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.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
/* The examples use WiFi configuration that you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_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 WIFI_CONNECTED_BIT = BIT0;
static const char *TAG = "local_ctrl_example";
static int s_retry_num = 0;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:%s",
ip4addr_ntoa(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta()
{
s_wifi_event_group = xEventGroupCreate();
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_ESP_WIFI_SSID,
.password = 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, "wifi_init_sta finished.");
ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}
/* Function responsible for configuring and starting the esp_local_ctrl service.
* See local_ctrl_service.c for implementation */
extern void start_esp_local_ctrl_service(void);
void app_main()
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
start_esp_local_ctrl_service();
}

View file

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICuTCCAaECFFnose4o8INWoH5BA5TOCz2e9zAOMA0GCSqGSIb3DQEBCwUAMA8x
DTALBgNVBAMMBHJvb3QwHhcNMTkwNjI1MTkyMTU4WhcNMjAxMTA2MTkyMTU4WjAj
MSEwHwYDVQQDDBhteV9lc3BfY3RybF9kZXZpY2UubG9jYWwwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDY2B46AdNfrJRGgHy7cECmEMxOWn8CvygC2g77
Gog/DWxkqaEksBJt8qQcqGLumv+HfXE4erNPGU+RTNal+zMXHliIMVi2IiVw5uuC
Tze7cK28HDvC5noED/TWGSJIaCQAUP/GdE0sqCJ1O7W0IhrZBjsmen4d0nPrInCz
X9YDOfaWxdwnBJ3q0+7ZTSWETbDrKUJ0tgPe6m96j/zRYCtCo2Dpu/pZvPyIvXwT
zt6enB8cwDtk35KwOrscAJGNqkCRyKaNvOSuHv9/02vpzwqk/J6JbIcXFVNuYSPg
0wb0iltMqn0IwC3KyaI9gBg0VexMeOhFV/gRt8dvEYehtTB7AgMBAAEwDQYJKoZI
hvcNAQELBQADggEBAFnKbunoBvKun4hJV4sp0ztDKpjOJevsQp3X36egm4NGCpEj
cdHxEmAvmeiu/12C6OfvFmZ/QiqNmp2gihpy4DiuxWnI+iC9JjfYuWTsKj+xcVkw
4IvGZbFtE9YW+XwNWqXPi1urVk9wKpZmCWpWgFWnLwPgIQs16+y3+CQF3vefX9Iy
aqmYrTYkBpLEXRjYJeU253mvN6FXQgOoPuld1Ph+IO+DUEJr+zeM88xkmjAo37ej
VkCMXA5HqdT64HuZC1RnnbpP76assgFW2oTycG28jzHSYjuK2q1PIoZtzpW8Sv7i
jn17E6ryf24r1DVkQByR54rvzl6Qu3M8TJe6EYI=
-----END CERTIFICATE-----

View file

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDY2B46AdNfrJRG
gHy7cECmEMxOWn8CvygC2g77Gog/DWxkqaEksBJt8qQcqGLumv+HfXE4erNPGU+R
TNal+zMXHliIMVi2IiVw5uuCTze7cK28HDvC5noED/TWGSJIaCQAUP/GdE0sqCJ1
O7W0IhrZBjsmen4d0nPrInCzX9YDOfaWxdwnBJ3q0+7ZTSWETbDrKUJ0tgPe6m96
j/zRYCtCo2Dpu/pZvPyIvXwTzt6enB8cwDtk35KwOrscAJGNqkCRyKaNvOSuHv9/
02vpzwqk/J6JbIcXFVNuYSPg0wb0iltMqn0IwC3KyaI9gBg0VexMeOhFV/gRt8dv
EYehtTB7AgMBAAECggEBAJSvM6Kgp9fdVNo2tdAsOxfjQsOjB53RhtTVwhnpamyZ
fq5TJZwrYqejDWZdC2ECRJ4ZpG2OrK5a85T0s+Whpbl/ZEMWWvaf2T5eCDQUr2lF
7MqkLVIJiLaKXl4DY990EONqpsbj7hrluqLZ61B1ZiVTQXGz4g/+wt8CgXZtCyiv
7XOTTmQueugq4f54JBX5isdB7/xLaXV3kycaEK1b6ZVFYB3ii5IKKsX7RK/ksA6O
fRrQ8702prqphPfbjZ9wPHif/zLiyiF2FG6OX1Y3aZe1npRsvuH2c3M2h+HGAQUR
3lDxMTNbsE8E+XKZFVAVdMqot2RfxENSHoJHcp1R2YECgYEA9qe1+eOZKd0w5lC1
PuG6FLAAbK1nuv/ovESEHtILTLFkMijgAqcWjtp1klS86IBJLnjv+GYxZu2n1WI9
QLnh++NNTjRGCMM2Adf5SBJ/5F85rpgzz7Yur1guqkUQx/2dmErOaWQ4IO304VlM
vrJB8+XmAiysEgJOkK0Mx8xRVcECgYEA4Q9GBADLryvwjisp/PdTRXOvd7pJRGH3
SdC1k/nBsmpmbouc0ihqzOiiN0kUjE2yLSlhwxxWBJqNSzOk9z5/LB4TNRqH9gCL
rUN67FgzwR5H70OblWpcjWRurFq34+ZWEmCG+1qUwZMT7dYe4CiDYnVjcwfUpQwN
qRpjeMLDrTsCgYEAgo1CRIGzD/WDbGRLinzvgQOnNd6SiOfqx7t8MtP6Jx29as83
wi+uQO5gTJONaYJ9OZvJaDCu9UvVCZx1z0yT0D7/K+V/LCQm8dLenscr6jR802y7
/7TuAOEr0fO8bh5Oy8zMc/wXuVY5xwz9EfJH9lA47e23JdESxIDTwuziIAECgYEA
qKQdPtqpxbUTKDTH3bomN6CcFwcL56XQ+wrdROidb+eyoZsUA5YtkSWwh+TG9Osz
XAvqKZ2OBx0YSwWD05CNEq3mjqA2yOtXvpkV/wuInGjoVi0+5BMzDu/2zkecC7WJ
QXP7MVWKqhJfmJQdxrIU4S49OvDfMl15zwDrEI5AugkCgYBn5+/KvrA8GGWD9p1r
qwjoojGBvCJn1Kj/s+IQYePYeiRe6/eSPGFHRyON9aMGjZmeiqyBA4bW71Wf8Rs1
X5LSwZhJpCTjO4B92w40u0r86Jxmp5Wz+zHUeM3mO2E6lAF+15YjhxpMT0YOmHFE
+oKD8U6dMjkTqntavBauz8M8fQ==
-----END PRIVATE KEY-----

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIC/zCCAeegAwIBAgIUH0R6q5vbgMnMZgD5r4xSu+WhSMwwDQYJKoZIhvcNAQEL
BQAwDzENMAsGA1UEAwwEcm9vdDAeFw0xOTA2MjUxOTIxNDVaFw0yOTA2MjIxOTIx
NDVaMA8xDTALBgNVBAMMBHJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDGDetEF+4HEOU5uoxvHsYAksmpF1tjw/M+aKtyGuTWInJPDJ3YjjjnF7hb
ylx5W7Qj4O4N+TmqYkwA4ztq2CXSmX1uc7OOfxU/wED663NoC2P1Mw0fI5fX2518
WdJeQilYymIOilmdtNqU9ad/3RdSZg+fxL5z9MTidHlUyzJG5LlO1cDiYRRURj9S
Fc2wWEUCETGA78ADCxKsdf2gBZDcZo/PHNXZc7fi2K18T5UmkRd50aoSLWUNY5tT
4DsyL19PUJCmtwcoLMT3p3kmepN4C0JByOxWceIvlAbq7+L3zMURWfpBcIqxXvEP
Y/JXw7GCfTJgjUz1IoHVz/ERNtrnAgMBAAGjUzBRMB0GA1UdDgQWBBSaztoCfcw+
mBrfMXLCBU8mOyj2BTAfBgNVHSMEGDAWgBSaztoCfcw+mBrfMXLCBU8mOyj2BTAP
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCSgkWG4QAblyxXN/R5
tNLKbzQIbaMj8uXSdcVtNHrNfydA0Sq2M8w7mT7N2axiMAusN3fhgztQvkWCvKdy
ou++NpFBb11+QJ2chgatLtoR7QPQ2TVlTUObAh2ZSt1jDOqvGQynbYqJ+9N6BKpK
S8faScaWP78J02TSMiNIvh8iYukZPMdCyJaHw2x0PtCRYVBSlFIwC5dn/sIJgyrV
g8RAlnsKTCQC3X20AQ851aID6JXDIaTn9pn9PN0XJC+iButpLZM4ZHHZpBtSQZ+d
6lD0tvS8bysCEkamDMt3z8/ncsytAS08VoFqwXdY3EXF8T+sKSi7+ACJXE/kivwu
8jvm
-----END CERTIFICATE-----

View file

@ -0,0 +1,7 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
COMPONENT_EMBED_TXTFILES := certs/cacert.pem
COMPONENT_EMBED_TXTFILES += certs/prvtkey.pem

View file

@ -0,0 +1,274 @@
/* Local Ctrl Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdlib.h>
#include <stdint.h>
#include <sys/param.h>
#include <string.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <mdns.h>
#include <esp_log.h>
#include <esp_timer.h>
#include <esp_local_ctrl.h>
#include <esp_https_server.h>
static const char *TAG = "control";
#define SERVICE_NAME "my_esp_ctrl_device"
/* Custom allowed property types */
enum property_types {
PROP_TYPE_TIMESTAMP = 0,
PROP_TYPE_INT32,
PROP_TYPE_BOOLEAN,
PROP_TYPE_STRING,
};
/* Custom flags that can be set for a property */
enum property_flags {
PROP_FLAG_READONLY = (1 << 0)
};
/********* Handler functions for responding to control requests / commands *********/
static esp_err_t get_property_values(size_t props_count,
const esp_local_ctrl_prop_t props[],
esp_local_ctrl_prop_val_t prop_values[],
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
ESP_LOGI(TAG, "Reading property : %s", props[i].name);
/* For the purpose of this example, to keep things simple
* we have set the context pointer of each property to
* point to its value (except for timestamp) */
switch (props[i].type) {
case PROP_TYPE_INT32:
case PROP_TYPE_BOOLEAN:
/* No need to set size for these types as sizes where
* specified when declaring the properties, unlike for
* string type. */
prop_values[i].data = props[i].ctx;
break;
case PROP_TYPE_TIMESTAMP: {
/* Get the time stamp */
static int64_t ts = 0;
ts = esp_timer_get_time();
/* Set the current time. Since this is statically
* allocated, we don't need to provide a free_fn */
prop_values[i].data = &ts;
break;
}
case PROP_TYPE_STRING: {
char **prop3_value = (char **) props[i].ctx;
if (*prop3_value == NULL) {
prop_values[i].size = 0;
prop_values[i].data = NULL;
} else {
/* We could try dynamically allocating the output value,
* and it should get freed automatically after use, as
* `esp_local_ctrl` internally calls the provided `free_fn` */
prop_values[i].size = strlen(*prop3_value);
prop_values[i].data = strdup(*prop3_value);
if (!prop_values[i].data) {
return ESP_ERR_NO_MEM;
}
prop_values[i].free_fn = free;
}
}
default:
break;
}
}
return ESP_OK;
}
static esp_err_t set_property_values(size_t props_count,
const esp_local_ctrl_prop_t props[],
const esp_local_ctrl_prop_val_t prop_values[],
void *usr_ctx)
{
for (uint32_t i = 0; i < props_count; i++) {
/* Cannot set the value of a read-only property */
if (props[i].flags & PROP_FLAG_READONLY) {
ESP_LOGE(TAG, "%s is read-only", props[i].name);
return ESP_ERR_INVALID_ARG;
}
/* For the purpose of this example, to keep things simple
* we have set the context pointer of each property to
* point to its value (except for timestamp) */
switch (props[i].type) {
case PROP_TYPE_STRING: {
/* Free the previously set string */
char **prop3_value = (char **) props[i].ctx;
free(*prop3_value);
*prop3_value = NULL;
/* Copy the input string */
if (prop_values[i].size) {
*prop3_value = strndup((const char *)prop_values[i].data, prop_values[i].size);
if (*prop3_value == NULL) {
return ESP_ERR_NO_MEM;
}
ESP_LOGI(TAG, "Setting %s value to %s", props[i].name, (const char*)*prop3_value);
}
}
break;
case PROP_TYPE_INT32: {
const int32_t *new_value = (const int32_t *) prop_values[i].data;
ESP_LOGI(TAG, "Setting %s value to %d", props[i].name, *new_value);
memcpy(props[i].ctx, new_value, sizeof(int32_t));
}
break;
case PROP_TYPE_BOOLEAN: {
const bool *value = (const bool *) prop_values[i].data;
ESP_LOGI(TAG, "Setting %s value to %d", props[i].name, *value);
memcpy(props[i].ctx, value, sizeof(bool));
}
break;
default:
break;
}
}
return ESP_OK;
}
/******************************************************************************/
/* A custom free_fn to free a pointer to a string as
* well as the string being pointed to */
static void free_str(void *arg)
{
char **ptr_to_strptr = (char **)arg;
if (ptr_to_strptr) {
free(*ptr_to_strptr);
free(ptr_to_strptr);
}
}
/* Function used by app_main to start the esp_local_ctrl service */
void start_esp_local_ctrl_service(void)
{
/* Set the configuration */
httpd_ssl_config_t https_conf = HTTPD_SSL_CONFIG_DEFAULT();
/* Load server certificate */
extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end");
https_conf.cacert_pem = cacert_pem_start;
https_conf.cacert_len = cacert_pem_end - cacert_pem_start;
/* Load server private key */
extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end");
https_conf.prvtkey_pem = prvtkey_pem_start;
https_conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;
esp_local_ctrl_config_t config = {
.transport = ESP_LOCAL_CTRL_TRANSPORT_HTTPD,
.transport_config = {
.httpd = &https_conf
},
.handlers = {
/* User defined handler functions */
.get_prop_values = get_property_values,
.set_prop_values = set_property_values,
.usr_ctx = NULL,
.usr_ctx_free_fn = NULL
},
/* Maximum number of properties that may be set */
.max_properties = 10
};
mdns_init();
mdns_hostname_set(SERVICE_NAME);
/* Start esp_local_ctrl service */
ESP_ERROR_CHECK(esp_local_ctrl_start(&config));
ESP_LOGI(TAG, "esp_local_ctrl service started with name : %s", SERVICE_NAME);
/* Create a timestamp property. The client should see this as a read-only property.
* Property value is fetched using `esp_timer_get_time()` in the `get_prop_values`
* handler */
esp_local_ctrl_prop_t timestamp = {
.name = "timestamp (us)",
.type = PROP_TYPE_TIMESTAMP,
.size = sizeof(int64_t),
.flags = PROP_FLAG_READONLY,
.ctx = NULL,
.ctx_free_fn = NULL
};
/* Create a writable integer property. Use dynamically allocated memory
* for storing its value and pass it as context, so that it can be accessed
* inside the set / get handlers. */
int32_t *prop1_value = malloc(sizeof(int32_t));
assert(prop1_value != NULL);
/* Initialize the property value */
*prop1_value = 123456789;
/* Populate the property structure accordingly. Since, we would want the memory
* occupied by the property value to be freed automatically upon call to
* `esp_local_ctrl_stop()` or `esp_local_ctrl_remove_property()`, the `ctx_free_fn`
* field will need to be set with the appropriate de-allocation function,
* which in this case is simply `free()` */
esp_local_ctrl_prop_t property1 = {
.name = "property1",
.type = PROP_TYPE_INT32,
.size = sizeof(int32_t),
.flags = 0,
.ctx = prop1_value,
.ctx_free_fn = free
};
/* Create another read-only property. Just for demonstration, we use statically
* allocated value. No `ctx_free_fn` needs to be set for this */
static bool prop2_value = false;
esp_local_ctrl_prop_t property2 = {
.name = "property2",
.type = PROP_TYPE_BOOLEAN,
.size = sizeof(bool),
.flags = PROP_FLAG_READONLY,
.ctx = &prop2_value,
.ctx_free_fn = NULL
};
/* Create a variable sized property. Its context is a pointer for storing the
* pointer to a dynamically allocate string, therefore it will require a
* customized free function `free_str()` */
char **prop3_value = calloc(1, sizeof(char *));
assert(prop3_value != NULL);
esp_local_ctrl_prop_t property3 = {
.name = "property3",
.type = PROP_TYPE_STRING,
.size = 0, // When zero, this is assumed to be of variable size
.flags = 0,
.ctx = prop3_value,
.ctx_free_fn = free_str
};
/* Now register the properties */
ESP_ERROR_CHECK(esp_local_ctrl_add_property(&timestamp));
ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property1));
ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property2));
ESP_ERROR_CHECK(esp_local_ctrl_add_property(&property3));
/* Just for fun, let us keep toggling the value
* of the boolean property2, every 1 second */
while (1) {
vTaskDelay(1000 / portTICK_RATE_MS);
prop2_value = !prop2_value;
}
}

View file

@ -0,0 +1,273 @@
#!/usr/bin/env python
#
# 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.
#
from __future__ import print_function
from future.utils import tobytes
from builtins import input
import os
import sys
import struct
import argparse
import proto
try:
import esp_prov
except ImportError:
idf_path = os.environ['IDF_PATH']
sys.path.insert(1, idf_path + "/tools/esp_prov")
import esp_prov
# Set this to true to allow exceptions to be thrown
config_throw_except = False
# Property types enum
PROP_TYPE_TIMESTAMP = 0
PROP_TYPE_INT32 = 1
PROP_TYPE_BOOLEAN = 2
PROP_TYPE_STRING = 3
# Property flags enum
PROP_FLAG_READONLY = (1 << 0)
def prop_typestr(prop):
if prop["type"] == PROP_TYPE_TIMESTAMP:
return "TIME(us)"
elif prop["type"] == PROP_TYPE_INT32:
return "INT32"
elif prop["type"] == PROP_TYPE_BOOLEAN:
return "BOOLEAN"
elif prop["type"] == PROP_TYPE_STRING:
return "STRING"
return "UNKNOWN"
def encode_prop_value(prop, value):
try:
if prop["type"] == PROP_TYPE_TIMESTAMP:
return struct.pack('q', value)
elif prop["type"] == PROP_TYPE_INT32:
return struct.pack('i', value)
elif prop["type"] == PROP_TYPE_BOOLEAN:
return struct.pack('?', value)
elif prop["type"] == PROP_TYPE_STRING:
return tobytes(value)
return value
except struct.error as e:
print(e)
return None
def decode_prop_value(prop, value):
try:
if prop["type"] == PROP_TYPE_TIMESTAMP:
return struct.unpack('q', value)[0]
elif prop["type"] == PROP_TYPE_INT32:
return struct.unpack('i', value)[0]
elif prop["type"] == PROP_TYPE_BOOLEAN:
return struct.unpack('?', value)[0]
elif prop["type"] == PROP_TYPE_STRING:
return value.decode('latin-1')
return value
except struct.error as e:
print(e)
return None
def str_to_prop_value(prop, strval):
try:
if prop["type"] == PROP_TYPE_TIMESTAMP:
return int(strval)
elif prop["type"] == PROP_TYPE_INT32:
return int(strval)
elif prop["type"] == PROP_TYPE_BOOLEAN:
return bool(strval)
elif prop["type"] == PROP_TYPE_STRING:
return strval
return strval
except ValueError as e:
print(e)
return None
def prop_is_readonly(prop):
return (prop["flags"] & PROP_FLAG_READONLY) is not 0
def on_except(err):
if config_throw_except:
raise RuntimeError(err)
else:
print(err)
def get_transport(sel_transport, service_name):
try:
tp = None
if (sel_transport == 'http'):
example_path = os.environ['IDF_PATH'] + "/examples/protocols/esp_local_ctrl"
cert_path = example_path + "/main/certs/rootCA.pem"
tp = esp_prov.transport.Transport_HTTP(service_name, cert_path)
elif (sel_transport == 'ble'):
tp = esp_prov.transport.Transport_BLE(
devname=service_name, service_uuid='0000ffff-0000-1000-8000-00805f9b34fb',
nu_lookup={'esp_local_ctrl/version': '0001',
'esp_local_ctrl/session': '0002',
'esp_local_ctrl/control': '0003'}
)
return tp
except RuntimeError as e:
on_except(e)
return None
def version_match(tp, expected, verbose=False):
try:
response = tp.send_data('esp_local_ctrl/version', expected)
return (response.lower() == expected.lower())
except Exception as e:
on_except(e)
return None
def get_all_property_values(tp):
try:
props = []
message = proto.get_prop_count_request()
response = tp.send_data('esp_local_ctrl/control', message)
count = proto.get_prop_count_response(response)
if count == 0:
raise RuntimeError("No properties found!")
indices = [i for i in range(count)]
message = proto.get_prop_vals_request(indices)
response = tp.send_data('esp_local_ctrl/control', message)
props = proto.get_prop_vals_response(response)
if len(props) != count:
raise RuntimeError("Incorrect count of properties!")
for p in props:
p["value"] = decode_prop_value(p, p["value"])
return props
except RuntimeError as e:
on_except(e)
return []
def set_property_values(tp, props, indices, values, check_readonly=False):
try:
if check_readonly:
for index in indices:
if prop_is_readonly(props[index]):
raise RuntimeError("Cannot set value of Read-Only property")
message = proto.set_prop_vals_request(indices, values)
response = tp.send_data('esp_local_ctrl/control', message)
return proto.set_prop_vals_response(response)
except RuntimeError as e:
on_except(e)
return False
if __name__ == '__main__':
parser = argparse.ArgumentParser(add_help=False)
parser = argparse.ArgumentParser(description="Control an ESP32 running esp_local_ctrl service")
parser.add_argument("--version", dest='version', type=str,
help="Protocol version", default='')
parser.add_argument("--transport", dest='transport', type=str,
help="transport i.e http or ble", default='http')
parser.add_argument("--name", dest='service_name', type=str,
help="BLE Device Name / HTTP Server hostname or IP", default='')
parser.add_argument("-v", "--verbose", dest='verbose', help="increase output verbosity", action="store_true")
args = parser.parse_args()
if args.version != '':
print("==== Esp_Ctrl Version: " + args.version + " ====")
if args.service_name == '':
args.service_name = 'my_esp_ctrl_device'
if args.transport == 'http':
args.service_name += '.local'
obj_transport = get_transport(args.transport, args.service_name)
if obj_transport is None:
print("---- Invalid transport ----")
exit(1)
if args.version != '':
print("\n==== Verifying protocol version ====")
if not version_match(obj_transport, args.version, args.verbose):
print("---- Error in protocol version matching ----")
exit(2)
print("==== Verified protocol version successfully ====")
while True:
properties = get_all_property_values(obj_transport)
if len(properties) == 0:
print("---- Error in reading property values ----")
exit(4)
print("\n==== Available Properties ====")
print("{0: >4} {1: <16} {2: <10} {3: <16} {4: <16}".format(
"S.N.", "Name", "Type", "Flags", "Value"))
for i in range(len(properties)):
print("[{0: >2}] {1: <16} {2: <10} {3: <16} {4: <16}".format(
i + 1, properties[i]["name"], prop_typestr(properties[i]),
["","Read-Only"][prop_is_readonly(properties[i])],
str(properties[i]["value"])))
select = 0
while True:
try:
inval = input("\nSelect properties to set (0 to re-read, 'q' to quit) : ")
if inval.lower() == 'q':
print("Quitting...")
exit(5)
invals = inval.split(',')
selections = [int(val) for val in invals]
if min(selections) < 0 or max(selections) > len(properties):
raise ValueError("Invalid input")
break
except ValueError as e:
print(str(e) + "! Retry...")
if len(selections) == 1 and selections[0] == 0:
continue
set_values = []
set_indices = []
for select in selections:
while True:
inval = input("Enter value to set for property (" + properties[select - 1]["name"] + ") : ")
value = encode_prop_value(properties[select - 1],
str_to_prop_value(properties[select - 1], inval))
if value is None:
print("Invalid input! Retry...")
continue
break
set_values += [value]
set_indices += [select - 1]
if not set_property_values(obj_transport, properties, set_indices, set_values):
print("Failed to set values!")

View file

@ -0,0 +1,93 @@
# 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.
#
from __future__ import print_function
from future.utils import tobytes
import os
def _load_source(name, path):
try:
from importlib.machinery import SourceFileLoader
return SourceFileLoader(name, path).load_module()
except ImportError:
# importlib.machinery doesn't exists in Python 2 so we will use imp (deprecated in Python 3)
import imp
return imp.load_source(name, path)
idf_path = os.environ['IDF_PATH']
constants_pb2 = _load_source("constants_pb2", idf_path + "/components/protocomm/python/constants_pb2.py")
local_ctrl_pb2 = _load_source("esp_local_ctrl_pb2", idf_path + "/components/esp_local_ctrl/python/esp_local_ctrl_pb2.py")
def get_prop_count_request():
req = local_ctrl_pb2.LocalCtrlMessage()
req.msg = local_ctrl_pb2.TypeCmdGetPropertyCount
payload = local_ctrl_pb2.CmdGetPropertyCount()
req.cmd_get_prop_count.MergeFrom(payload)
return req.SerializeToString()
def get_prop_count_response(response_data):
resp = local_ctrl_pb2.LocalCtrlMessage()
resp.ParseFromString(tobytes(response_data))
if (resp.resp_get_prop_count.status == 0):
return resp.resp_get_prop_count.count
else:
return 0
def get_prop_vals_request(indices):
req = local_ctrl_pb2.LocalCtrlMessage()
req.msg = local_ctrl_pb2.TypeCmdGetPropertyValues
payload = local_ctrl_pb2.CmdGetPropertyValues()
payload.indices.extend(indices)
req.cmd_get_prop_vals.MergeFrom(payload)
return req.SerializeToString()
def get_prop_vals_response(response_data):
resp = local_ctrl_pb2.LocalCtrlMessage()
resp.ParseFromString(tobytes(response_data))
results = []
if (resp.resp_get_prop_vals.status == 0):
for prop in resp.resp_get_prop_vals.props:
results += [{
"name": prop.name,
"type": prop.type,
"flags": prop.flags,
"value": tobytes(prop.value)
}]
return results
def set_prop_vals_request(indices, values):
req = local_ctrl_pb2.LocalCtrlMessage()
req.msg = local_ctrl_pb2.TypeCmdSetPropertyValues
payload = local_ctrl_pb2.CmdSetPropertyValues()
for i, v in zip(indices, values):
prop = payload.props.add()
prop.index = i
prop.value = v
req.cmd_set_prop_vals.MergeFrom(payload)
return req.SerializeToString()
def set_prop_vals_response(response_data):
resp = local_ctrl_pb2.LocalCtrlMessage()
resp.ParseFromString(tobytes(response_data))
return (resp.resp_set_prop_vals.status == 0)

View file

@ -0,0 +1 @@
CONFIG_ESP_HTTPS_SERVER_ENABLE=y

View file

@ -61,7 +61,7 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None):
try:
tp = None
if (sel_transport == 'softap'):
tp = transport.Transport_Softap(softap_endpoint)
tp = transport.Transport_HTTP(softap_endpoint)
elif (sel_transport == 'ble'):
# BLE client is now capable of automatically figuring out
# the primary service from the advertisement data and the

View file

@ -14,5 +14,5 @@
#
from .transport_console import * # noqa: F403, F401
from .transport_softap import * # noqa: F403, F401
from .transport_http import * # noqa: F403, F401
from .transport_ble import * # noqa: F403, F401

View file

@ -16,14 +16,25 @@
from __future__ import print_function
from future.utils import tobytes
import socket
import http.client
import ssl
from .transport import Transport
class Transport_Softap(Transport):
def __init__(self, url):
self.conn = http.client.HTTPConnection(url, timeout=30)
class Transport_HTTP(Transport):
def __init__(self, hostname, certfile=None):
try:
socket.gethostbyname(hostname.split(':')[0])
except socket.gaierror:
raise RuntimeError("Unable to resolve hostname :" + hostname)
if certfile is None:
self.conn = http.client.HTTPConnection(hostname, timeout=30)
else:
ssl_ctx = ssl.create_default_context(cafile=certfile)
self.conn = http.client.HTTPSConnection(hostname, context=ssl_ctx, timeout=30)
self.headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
def _send_post_request(self, path, data):