diff --git a/.flake8 b/.flake8 index 3d6f324761..2dfcfd2574 100644 --- a/.flake8 +++ b/.flake8 @@ -156,6 +156,7 @@ exclude = components/protocomm/python/sec0_pb2.py, components/protocomm/python/sec1_pb2.py, components/protocomm/python/session_pb2.py, + components/wifi_provisioning/python/wifi_scan_pb2.py, components/wifi_provisioning/python/wifi_config_pb2.py, components/wifi_provisioning/python/wifi_constants_pb2.py, examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py, diff --git a/components/wifi_provisioning/CMakeLists.txt b/components/wifi_provisioning/CMakeLists.txt index 9266acce00..fdb2333641 100644 --- a/components/wifi_provisioning/CMakeLists.txt +++ b/components/wifi_provisioning/CMakeLists.txt @@ -1,11 +1,13 @@ set(COMPONENT_ADD_INCLUDEDIRS include) set(COMPONENT_PRIV_INCLUDEDIRS src proto-c ../protocomm/proto-c) set(COMPONENT_SRCS "src/wifi_config.c" + "src/wifi_scan.c" "src/manager.c" "src/handlers.c" "src/scheme_softap.c" "src/scheme_console.c" "proto-c/wifi_config.pb-c.c" + "proto-c/wifi_scan.pb-c.c" "proto-c/wifi_constants.pb-c.c") set(COMPONENT_REQUIRES lwip protocomm) diff --git a/components/wifi_provisioning/Kconfig b/components/wifi_provisioning/Kconfig new file mode 100644 index 0000000000..d850f4052a --- /dev/null +++ b/components/wifi_provisioning/Kconfig @@ -0,0 +1,10 @@ +menu "Wi-Fi Provisioning Manager" + + config WIFI_PROV_SCAN_MAX_ENTRIES + int "Max Wi-Fi Scan Result Entries" + default 16 + range 1 255 + help + This sets the maximum number of entries of Wi-Fi scan results that will be kept by the provisioning manager + +endmenu diff --git a/components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h b/components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h new file mode 100644 index 0000000000..a4ebb7e570 --- /dev/null +++ b/components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h @@ -0,0 +1,166 @@ +// 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. + +#ifndef _PROV_WIFI_SCAN_H_ +#define _PROV_WIFI_SCAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define WIFI_SSID_LEN sizeof(((wifi_ap_record_t *)0)->ssid) +#define WIFI_BSSID_LEN sizeof(((wifi_ap_record_t *)0)->bssid) + +/** + * @brief Type of context data passed to each get/set/apply handler + * function set in `wifi_prov_scan_handlers` structure. + * + * This is passed as an opaque pointer, thereby allowing it be defined + * later in application code as per requirements. + */ +typedef struct wifi_prov_scan_ctx wifi_prov_scan_ctx_t; + +/** + * @brief Structure of entries in the scan results list + */ +typedef struct { + /** + * SSID of Wi-Fi AP + */ + char ssid[WIFI_SSID_LEN]; + + /** + * BSSID of Wi-Fi AP + */ + char bssid[WIFI_BSSID_LEN]; + + /** + * Wi-Fi channel number + */ + uint8_t channel; + + /** + * Signal strength + */ + int rssi; + + /** + * Wi-Fi security mode + */ + uint8_t auth; +} wifi_prov_scan_result_t; + +/** + * @brief Internal handlers for receiving and responding to protocomm + * requests from client + * + * This is to be passed as priv_data for protocomm request handler + * (refer to `wifi_prov_scan_handler()`) when calling `protocomm_add_endpoint()`. + */ +typedef struct wifi_prov_scan_handlers { + /** + * Handler function called when scan start command is received + * with various scan parameters : + * + * blocking (input) - If true, the function should return only + * when the scanning is finished + * + * passive (input) - If true, scan is to be started in passive + * mode (this may be slower) instead of active mode + * + * group_channels (input) - This specifies whether to scan + * all channels in one go (when zero) or perform scanning of + * channels in groups, with 120ms delay between scanning of + * consecutive groups, and the value of this parameter sets the + * number of channels in each group. This is useful when transport + * mode is SoftAP, where scanning all channels in one go may not + * give the Wi-Fi driver enough time to send out beacons, and + * hence may cause disconnection with any connected stations. + * When scanning in groups, the manager will wait for atleast + * 120ms after completing scan on a group of channels, and thus + * allow the driver to send out the beacons. For example, given + * that the total number of Wi-Fi channels is 14, then setting + * group_channels to 4, will create 5 groups, with each group + * having 3 channels, except the last one which will have + * 14 % 3 = 2 channels. So, when scan is started, the first 3 + * channels will be scanned, followed by a 120ms delay, and then + * the next 3 channels, and so on, until all the 14 channels have + * been scanned. One may need to adjust this parameter as having + * only few channels in a group may slow down the overall scan + * time, while having too many may again cause disconnection. + * Usually a value of 4 should work for most cases. Note that + * for any other mode of transport, e.g. BLE, this can be safely + * set to 0, and hence achieve the fastest overall scanning time. + * + * period_ms (input) - Scan parameter specifying how long to + * wait on each channel (in milli-seconds) + */ + esp_err_t (*scan_start)(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms, + wifi_prov_scan_ctx_t **ctx); + + /** + * Handler function called when scan status is requested. Status + * is given the parameters : + * + * scan_finished (output) - When scan has finished this returns true + * + * result_count (output) - This gives the total number of results + * obtained till now. If scan is yet happening this number will + * keep on updating + */ + esp_err_t (*scan_status)(bool *scan_finished, + uint16_t *result_count, + wifi_prov_scan_ctx_t **ctx); + + /** + * Handler function called when scan result is requested. Parameters : + * + * scan_result - For fetching scan results. This can be called even + * if scan is still on going + * + * start_index (input) - Starting index from where to fetch the + * entries from the results list + * + * count (input) - Number of entries to fetch from the starting index + * + * entries (output) - List of entries returned. Each entry consists + * of ssid, channel and rssi information + */ + esp_err_t (*scan_result)(uint16_t result_index, + wifi_prov_scan_result_t *result, + wifi_prov_scan_ctx_t **ctx); + + /** + * Context pointer to be passed to above handler functions upon invocation + */ + wifi_prov_scan_ctx_t *ctx; +} wifi_prov_scan_handlers_t; + +/** + * @brief Handler for sending on demand Wi-Fi scan results + * + * This is to be registered as the `prov-scan` endpoint handler + * (protocomm `protocomm_req_handler_t`) using `protocomm_add_endpoint()` + */ +esp_err_t wifi_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c new file mode 100644 index 0000000000..4cf5b5dc3b --- /dev/null +++ b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.c @@ -0,0 +1,878 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: wifi_scan.proto */ + +/* Do not generate deprecated warnings for self */ +#ifndef PROTOBUF_C__NO_DEPRECATED +#define PROTOBUF_C__NO_DEPRECATED +#endif + +#include "wifi_scan.pb-c.h" +void cmd_scan_start__init + (CmdScanStart *message) +{ + static const CmdScanStart init_value = CMD_SCAN_START__INIT; + *message = init_value; +} +size_t cmd_scan_start__get_packed_size + (const CmdScanStart *message) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_start__pack + (const CmdScanStart *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_start__pack_to_buffer + (const CmdScanStart *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_start__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanStart * + cmd_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanStart *) + protobuf_c_message_unpack (&cmd_scan_start__descriptor, + allocator, len, data); +} +void cmd_scan_start__free_unpacked + (CmdScanStart *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_start__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_start__init + (RespScanStart *message) +{ + static const RespScanStart init_value = RESP_SCAN_START__INIT; + *message = init_value; +} +size_t resp_scan_start__get_packed_size + (const RespScanStart *message) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_start__pack + (const RespScanStart *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_start__pack_to_buffer + (const RespScanStart *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_start__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanStart * + resp_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanStart *) + protobuf_c_message_unpack (&resp_scan_start__descriptor, + allocator, len, data); +} +void resp_scan_start__free_unpacked + (RespScanStart *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_start__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_scan_status__init + (CmdScanStatus *message) +{ + static const CmdScanStatus init_value = CMD_SCAN_STATUS__INIT; + *message = init_value; +} +size_t cmd_scan_status__get_packed_size + (const CmdScanStatus *message) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_status__pack + (const CmdScanStatus *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_status__pack_to_buffer + (const CmdScanStatus *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_status__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanStatus * + cmd_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanStatus *) + protobuf_c_message_unpack (&cmd_scan_status__descriptor, + allocator, len, data); +} +void cmd_scan_status__free_unpacked + (CmdScanStatus *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_status__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_status__init + (RespScanStatus *message) +{ + static const RespScanStatus init_value = RESP_SCAN_STATUS__INIT; + *message = init_value; +} +size_t resp_scan_status__get_packed_size + (const RespScanStatus *message) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_status__pack + (const RespScanStatus *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_status__pack_to_buffer + (const RespScanStatus *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_status__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanStatus * + resp_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanStatus *) + protobuf_c_message_unpack (&resp_scan_status__descriptor, + allocator, len, data); +} +void resp_scan_status__free_unpacked + (RespScanStatus *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_status__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void cmd_scan_result__init + (CmdScanResult *message) +{ + static const CmdScanResult init_value = CMD_SCAN_RESULT__INIT; + *message = init_value; +} +size_t cmd_scan_result__get_packed_size + (const CmdScanResult *message) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t cmd_scan_result__pack + (const CmdScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t cmd_scan_result__pack_to_buffer + (const CmdScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &cmd_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +CmdScanResult * + cmd_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (CmdScanResult *) + protobuf_c_message_unpack (&cmd_scan_result__descriptor, + allocator, len, data); +} +void cmd_scan_result__free_unpacked + (CmdScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &cmd_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void wi_fi_scan_result__init + (WiFiScanResult *message) +{ + static const WiFiScanResult init_value = WI_FI_SCAN_RESULT__INIT; + *message = init_value; +} +size_t wi_fi_scan_result__get_packed_size + (const WiFiScanResult *message) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t wi_fi_scan_result__pack + (const WiFiScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t wi_fi_scan_result__pack_to_buffer + (const WiFiScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +WiFiScanResult * + wi_fi_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (WiFiScanResult *) + protobuf_c_message_unpack (&wi_fi_scan_result__descriptor, + allocator, len, data); +} +void wi_fi_scan_result__free_unpacked + (WiFiScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &wi_fi_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void resp_scan_result__init + (RespScanResult *message) +{ + static const RespScanResult init_value = RESP_SCAN_RESULT__INIT; + *message = init_value; +} +size_t resp_scan_result__get_packed_size + (const RespScanResult *message) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t resp_scan_result__pack + (const RespScanResult *message, + uint8_t *out) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t resp_scan_result__pack_to_buffer + (const RespScanResult *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &resp_scan_result__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +RespScanResult * + resp_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (RespScanResult *) + protobuf_c_message_unpack (&resp_scan_result__descriptor, + allocator, len, data); +} +void resp_scan_result__free_unpacked + (RespScanResult *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &resp_scan_result__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +void wi_fi_scan_payload__init + (WiFiScanPayload *message) +{ + static const WiFiScanPayload init_value = WI_FI_SCAN_PAYLOAD__INIT; + *message = init_value; +} +size_t wi_fi_scan_payload__get_packed_size + (const WiFiScanPayload *message) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); +} +size_t wi_fi_scan_payload__pack + (const WiFiScanPayload *message, + uint8_t *out) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); +} +size_t wi_fi_scan_payload__pack_to_buffer + (const WiFiScanPayload *message, + ProtobufCBuffer *buffer) +{ + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); +} +WiFiScanPayload * + wi_fi_scan_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data) +{ + return (WiFiScanPayload *) + protobuf_c_message_unpack (&wi_fi_scan_payload__descriptor, + allocator, len, data); +} +void wi_fi_scan_payload__free_unpacked + (WiFiScanPayload *message, + ProtobufCAllocator *allocator) +{ + if(!message) + return; + assert(message->base.descriptor == &wi_fi_scan_payload__descriptor); + protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); +} +static const ProtobufCFieldDescriptor cmd_scan_start__field_descriptors[4] = +{ + { + "blocking", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, blocking), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "passive", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, passive), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "group_channels", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, group_channels), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "period_ms", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanStart, period_ms), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_scan_start__field_indices_by_name[] = { + 0, /* field[0] = blocking */ + 2, /* field[2] = group_channels */ + 1, /* field[1] = passive */ + 3, /* field[3] = period_ms */ +}; +static const ProtobufCIntRange cmd_scan_start__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 4 } +}; +const ProtobufCMessageDescriptor cmd_scan_start__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanStart", + "CmdScanStart", + "CmdScanStart", + "", + sizeof(CmdScanStart), + 4, + cmd_scan_start__field_descriptors, + cmd_scan_start__field_indices_by_name, + 1, cmd_scan_start__number_ranges, + (ProtobufCMessageInit) cmd_scan_start__init, + NULL,NULL,NULL /* reserved[123] */ +}; +#define resp_scan_start__field_descriptors NULL +#define resp_scan_start__field_indices_by_name NULL +#define resp_scan_start__number_ranges NULL +const ProtobufCMessageDescriptor resp_scan_start__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanStart", + "RespScanStart", + "RespScanStart", + "", + sizeof(RespScanStart), + 0, + resp_scan_start__field_descriptors, + resp_scan_start__field_indices_by_name, + 0, resp_scan_start__number_ranges, + (ProtobufCMessageInit) resp_scan_start__init, + NULL,NULL,NULL /* reserved[123] */ +}; +#define cmd_scan_status__field_descriptors NULL +#define cmd_scan_status__field_indices_by_name NULL +#define cmd_scan_status__number_ranges NULL +const ProtobufCMessageDescriptor cmd_scan_status__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanStatus", + "CmdScanStatus", + "CmdScanStatus", + "", + sizeof(CmdScanStatus), + 0, + cmd_scan_status__field_descriptors, + cmd_scan_status__field_indices_by_name, + 0, cmd_scan_status__number_ranges, + (ProtobufCMessageInit) cmd_scan_status__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_scan_status__field_descriptors[2] = +{ + { + "scan_finished", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BOOL, + 0, /* quantifier_offset */ + offsetof(RespScanStatus, scan_finished), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "result_count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(RespScanStatus, result_count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_scan_status__field_indices_by_name[] = { + 1, /* field[1] = result_count */ + 0, /* field[0] = scan_finished */ +}; +static const ProtobufCIntRange resp_scan_status__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor resp_scan_status__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanStatus", + "RespScanStatus", + "RespScanStatus", + "", + sizeof(RespScanStatus), + 2, + resp_scan_status__field_descriptors, + resp_scan_status__field_indices_by_name, + 1, resp_scan_status__number_ranges, + (ProtobufCMessageInit) resp_scan_status__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor cmd_scan_result__field_descriptors[2] = +{ + { + "start_index", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanResult, start_index), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "count", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(CmdScanResult, count), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned cmd_scan_result__field_indices_by_name[] = { + 1, /* field[1] = count */ + 0, /* field[0] = start_index */ +}; +static const ProtobufCIntRange cmd_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 2 } +}; +const ProtobufCMessageDescriptor cmd_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "CmdScanResult", + "CmdScanResult", + "CmdScanResult", + "", + sizeof(CmdScanResult), + 2, + cmd_scan_result__field_descriptors, + cmd_scan_result__field_indices_by_name, + 1, cmd_scan_result__number_ranges, + (ProtobufCMessageInit) cmd_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor wi_fi_scan_result__field_descriptors[5] = +{ + { + "ssid", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, ssid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "channel", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_UINT32, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, channel), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "rssi", + 3, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_INT32, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, rssi), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "bssid", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, bssid), + NULL, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "auth", + 5, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanResult, auth), + &wifi_auth_mode__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned wi_fi_scan_result__field_indices_by_name[] = { + 4, /* field[4] = auth */ + 3, /* field[3] = bssid */ + 1, /* field[1] = channel */ + 2, /* field[2] = rssi */ + 0, /* field[0] = ssid */ +}; +static const ProtobufCIntRange wi_fi_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 5 } +}; +const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "WiFiScanResult", + "WiFiScanResult", + "WiFiScanResult", + "", + sizeof(WiFiScanResult), + 5, + wi_fi_scan_result__field_descriptors, + wi_fi_scan_result__field_indices_by_name, + 1, wi_fi_scan_result__number_ranges, + (ProtobufCMessageInit) wi_fi_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor resp_scan_result__field_descriptors[1] = +{ + { + "entries", + 1, + PROTOBUF_C_LABEL_REPEATED, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(RespScanResult, n_entries), + offsetof(RespScanResult, entries), + &wi_fi_scan_result__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned resp_scan_result__field_indices_by_name[] = { + 0, /* field[0] = entries */ +}; +static const ProtobufCIntRange resp_scan_result__number_ranges[1 + 1] = +{ + { 1, 0 }, + { 0, 1 } +}; +const ProtobufCMessageDescriptor resp_scan_result__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "RespScanResult", + "RespScanResult", + "RespScanResult", + "", + sizeof(RespScanResult), + 1, + resp_scan_result__field_descriptors, + resp_scan_result__field_indices_by_name, + 1, resp_scan_result__number_ranges, + (ProtobufCMessageInit) resp_scan_result__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCFieldDescriptor wi_fi_scan_payload__field_descriptors[8] = +{ + { + "msg", + 1, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanPayload, msg), + &wi_fi_scan_msg_type__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "status", + 2, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_ENUM, + 0, /* quantifier_offset */ + offsetof(WiFiScanPayload, status), + &status__descriptor, + NULL, + 0, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_start", + 10, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_start), + &cmd_scan_start__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_start", + 11, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_start), + &resp_scan_start__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_status", + 12, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_status), + &cmd_scan_status__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_status", + 13, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_status), + &resp_scan_status__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "cmd_scan_result", + 14, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, cmd_scan_result), + &cmd_scan_result__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, + { + "resp_scan_result", + 15, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_MESSAGE, + offsetof(WiFiScanPayload, payload_case), + offsetof(WiFiScanPayload, resp_scan_result), + &resp_scan_result__descriptor, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, +}; +static const unsigned wi_fi_scan_payload__field_indices_by_name[] = { + 6, /* field[6] = cmd_scan_result */ + 2, /* field[2] = cmd_scan_start */ + 4, /* field[4] = cmd_scan_status */ + 0, /* field[0] = msg */ + 7, /* field[7] = resp_scan_result */ + 3, /* field[3] = resp_scan_start */ + 5, /* field[5] = resp_scan_status */ + 1, /* field[1] = status */ +}; +static const ProtobufCIntRange wi_fi_scan_payload__number_ranges[2 + 1] = +{ + { 1, 0 }, + { 10, 2 }, + { 0, 8 } +}; +const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor = +{ + PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, + "WiFiScanPayload", + "WiFiScanPayload", + "WiFiScanPayload", + "", + sizeof(WiFiScanPayload), + 8, + wi_fi_scan_payload__field_descriptors, + wi_fi_scan_payload__field_indices_by_name, + 2, wi_fi_scan_payload__number_ranges, + (ProtobufCMessageInit) wi_fi_scan_payload__init, + NULL,NULL,NULL /* reserved[123] */ +}; +static const ProtobufCEnumValue wi_fi_scan_msg_type__enum_values_by_number[6] = +{ + { "TypeCmdScanStart", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart", 0 }, + { "TypeRespScanStart", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStart", 1 }, + { "TypeCmdScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus", 2 }, + { "TypeRespScanStatus", "WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus", 3 }, + { "TypeCmdScanResult", "WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult", 4 }, + { "TypeRespScanResult", "WI_FI_SCAN_MSG_TYPE__TypeRespScanResult", 5 }, +}; +static const ProtobufCIntRange wi_fi_scan_msg_type__value_ranges[] = { +{0, 0},{0, 6} +}; +static const ProtobufCEnumValueIndex wi_fi_scan_msg_type__enum_values_by_name[6] = +{ + { "TypeCmdScanResult", 4 }, + { "TypeCmdScanStart", 0 }, + { "TypeCmdScanStatus", 2 }, + { "TypeRespScanResult", 5 }, + { "TypeRespScanStart", 1 }, + { "TypeRespScanStatus", 3 }, +}; +const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor = +{ + PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, + "WiFiScanMsgType", + "WiFiScanMsgType", + "WiFiScanMsgType", + "", + 6, + wi_fi_scan_msg_type__enum_values_by_number, + 6, + wi_fi_scan_msg_type__enum_values_by_name, + 1, + wi_fi_scan_msg_type__value_ranges, + NULL,NULL,NULL,NULL /* reserved[1234] */ +}; diff --git a/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h new file mode 100644 index 0000000000..9caea2c7cd --- /dev/null +++ b/components/wifi_provisioning/proto-c/wifi_scan.pb-c.h @@ -0,0 +1,350 @@ +/* Generated by the protocol buffer compiler. DO NOT EDIT! */ +/* Generated from: wifi_scan.proto */ + +#ifndef PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED +#define PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED + +#include + +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" +#include "wifi_constants.pb-c.h" + +typedef struct _CmdScanStart CmdScanStart; +typedef struct _RespScanStart RespScanStart; +typedef struct _CmdScanStatus CmdScanStatus; +typedef struct _RespScanStatus RespScanStatus; +typedef struct _CmdScanResult CmdScanResult; +typedef struct _WiFiScanResult WiFiScanResult; +typedef struct _RespScanResult RespScanResult; +typedef struct _WiFiScanPayload WiFiScanPayload; + + +/* --- enums --- */ + +typedef enum _WiFiScanMsgType { + WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart = 0, + WI_FI_SCAN_MSG_TYPE__TypeRespScanStart = 1, + WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus = 2, + WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus = 3, + WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult = 4, + WI_FI_SCAN_MSG_TYPE__TypeRespScanResult = 5 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_MSG_TYPE) +} WiFiScanMsgType; + +/* --- messages --- */ + +struct _CmdScanStart +{ + ProtobufCMessage base; + protobuf_c_boolean blocking; + protobuf_c_boolean passive; + uint32_t group_channels; + uint32_t period_ms; +}; +#define CMD_SCAN_START__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_start__descriptor) \ + , 0, 0, 0, 0 } + + +struct _RespScanStart +{ + ProtobufCMessage base; +}; +#define RESP_SCAN_START__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_start__descriptor) \ + } + + +struct _CmdScanStatus +{ + ProtobufCMessage base; +}; +#define CMD_SCAN_STATUS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_status__descriptor) \ + } + + +struct _RespScanStatus +{ + ProtobufCMessage base; + protobuf_c_boolean scan_finished; + uint32_t result_count; +}; +#define RESP_SCAN_STATUS__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_status__descriptor) \ + , 0, 0 } + + +struct _CmdScanResult +{ + ProtobufCMessage base; + uint32_t start_index; + uint32_t count; +}; +#define CMD_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&cmd_scan_result__descriptor) \ + , 0, 0 } + + +struct _WiFiScanResult +{ + ProtobufCMessage base; + ProtobufCBinaryData ssid; + uint32_t channel; + int32_t rssi; + ProtobufCBinaryData bssid; + WifiAuthMode auth; +}; +#define WI_FI_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_result__descriptor) \ + , {0,NULL}, 0, 0, {0,NULL}, WIFI_AUTH_MODE__Open } + + +struct _RespScanResult +{ + ProtobufCMessage base; + size_t n_entries; + WiFiScanResult **entries; +}; +#define RESP_SCAN_RESULT__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&resp_scan_result__descriptor) \ + , 0,NULL } + + +typedef enum { + WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET = 0, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_START = 10, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START = 11, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_STATUS = 12, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS = 13, + WI_FI_SCAN_PAYLOAD__PAYLOAD_CMD_SCAN_RESULT = 14, + WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT = 15 + PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(WI_FI_SCAN_PAYLOAD__PAYLOAD) +} WiFiScanPayload__PayloadCase; + +struct _WiFiScanPayload +{ + ProtobufCMessage base; + WiFiScanMsgType msg; + Status status; + WiFiScanPayload__PayloadCase payload_case; + union { + CmdScanStart *cmd_scan_start; + RespScanStart *resp_scan_start; + CmdScanStatus *cmd_scan_status; + RespScanStatus *resp_scan_status; + CmdScanResult *cmd_scan_result; + RespScanResult *resp_scan_result; + }; +}; +#define WI_FI_SCAN_PAYLOAD__INIT \ + { PROTOBUF_C_MESSAGE_INIT (&wi_fi_scan_payload__descriptor) \ + , WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart, STATUS__Success, WI_FI_SCAN_PAYLOAD__PAYLOAD__NOT_SET, {0} } + + +/* CmdScanStart methods */ +void cmd_scan_start__init + (CmdScanStart *message); +size_t cmd_scan_start__get_packed_size + (const CmdScanStart *message); +size_t cmd_scan_start__pack + (const CmdScanStart *message, + uint8_t *out); +size_t cmd_scan_start__pack_to_buffer + (const CmdScanStart *message, + ProtobufCBuffer *buffer); +CmdScanStart * + cmd_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_start__free_unpacked + (CmdScanStart *message, + ProtobufCAllocator *allocator); +/* RespScanStart methods */ +void resp_scan_start__init + (RespScanStart *message); +size_t resp_scan_start__get_packed_size + (const RespScanStart *message); +size_t resp_scan_start__pack + (const RespScanStart *message, + uint8_t *out); +size_t resp_scan_start__pack_to_buffer + (const RespScanStart *message, + ProtobufCBuffer *buffer); +RespScanStart * + resp_scan_start__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_start__free_unpacked + (RespScanStart *message, + ProtobufCAllocator *allocator); +/* CmdScanStatus methods */ +void cmd_scan_status__init + (CmdScanStatus *message); +size_t cmd_scan_status__get_packed_size + (const CmdScanStatus *message); +size_t cmd_scan_status__pack + (const CmdScanStatus *message, + uint8_t *out); +size_t cmd_scan_status__pack_to_buffer + (const CmdScanStatus *message, + ProtobufCBuffer *buffer); +CmdScanStatus * + cmd_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_status__free_unpacked + (CmdScanStatus *message, + ProtobufCAllocator *allocator); +/* RespScanStatus methods */ +void resp_scan_status__init + (RespScanStatus *message); +size_t resp_scan_status__get_packed_size + (const RespScanStatus *message); +size_t resp_scan_status__pack + (const RespScanStatus *message, + uint8_t *out); +size_t resp_scan_status__pack_to_buffer + (const RespScanStatus *message, + ProtobufCBuffer *buffer); +RespScanStatus * + resp_scan_status__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_status__free_unpacked + (RespScanStatus *message, + ProtobufCAllocator *allocator); +/* CmdScanResult methods */ +void cmd_scan_result__init + (CmdScanResult *message); +size_t cmd_scan_result__get_packed_size + (const CmdScanResult *message); +size_t cmd_scan_result__pack + (const CmdScanResult *message, + uint8_t *out); +size_t cmd_scan_result__pack_to_buffer + (const CmdScanResult *message, + ProtobufCBuffer *buffer); +CmdScanResult * + cmd_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void cmd_scan_result__free_unpacked + (CmdScanResult *message, + ProtobufCAllocator *allocator); +/* WiFiScanResult methods */ +void wi_fi_scan_result__init + (WiFiScanResult *message); +size_t wi_fi_scan_result__get_packed_size + (const WiFiScanResult *message); +size_t wi_fi_scan_result__pack + (const WiFiScanResult *message, + uint8_t *out); +size_t wi_fi_scan_result__pack_to_buffer + (const WiFiScanResult *message, + ProtobufCBuffer *buffer); +WiFiScanResult * + wi_fi_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void wi_fi_scan_result__free_unpacked + (WiFiScanResult *message, + ProtobufCAllocator *allocator); +/* RespScanResult methods */ +void resp_scan_result__init + (RespScanResult *message); +size_t resp_scan_result__get_packed_size + (const RespScanResult *message); +size_t resp_scan_result__pack + (const RespScanResult *message, + uint8_t *out); +size_t resp_scan_result__pack_to_buffer + (const RespScanResult *message, + ProtobufCBuffer *buffer); +RespScanResult * + resp_scan_result__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void resp_scan_result__free_unpacked + (RespScanResult *message, + ProtobufCAllocator *allocator); +/* WiFiScanPayload methods */ +void wi_fi_scan_payload__init + (WiFiScanPayload *message); +size_t wi_fi_scan_payload__get_packed_size + (const WiFiScanPayload *message); +size_t wi_fi_scan_payload__pack + (const WiFiScanPayload *message, + uint8_t *out); +size_t wi_fi_scan_payload__pack_to_buffer + (const WiFiScanPayload *message, + ProtobufCBuffer *buffer); +WiFiScanPayload * + wi_fi_scan_payload__unpack + (ProtobufCAllocator *allocator, + size_t len, + const uint8_t *data); +void wi_fi_scan_payload__free_unpacked + (WiFiScanPayload *message, + ProtobufCAllocator *allocator); +/* --- per-message closures --- */ + +typedef void (*CmdScanStart_Closure) + (const CmdScanStart *message, + void *closure_data); +typedef void (*RespScanStart_Closure) + (const RespScanStart *message, + void *closure_data); +typedef void (*CmdScanStatus_Closure) + (const CmdScanStatus *message, + void *closure_data); +typedef void (*RespScanStatus_Closure) + (const RespScanStatus *message, + void *closure_data); +typedef void (*CmdScanResult_Closure) + (const CmdScanResult *message, + void *closure_data); +typedef void (*WiFiScanResult_Closure) + (const WiFiScanResult *message, + void *closure_data); +typedef void (*RespScanResult_Closure) + (const RespScanResult *message, + void *closure_data); +typedef void (*WiFiScanPayload_Closure) + (const WiFiScanPayload *message, + void *closure_data); + +/* --- services --- */ + + +/* --- descriptors --- */ + +extern const ProtobufCEnumDescriptor wi_fi_scan_msg_type__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_start__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_start__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_status__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_status__descriptor; +extern const ProtobufCMessageDescriptor cmd_scan_result__descriptor; +extern const ProtobufCMessageDescriptor wi_fi_scan_result__descriptor; +extern const ProtobufCMessageDescriptor resp_scan_result__descriptor; +extern const ProtobufCMessageDescriptor wi_fi_scan_payload__descriptor; + +PROTOBUF_C__END_DECLS + + +#endif /* PROTOBUF_C_wifi_5fscan_2eproto__INCLUDED */ diff --git a/components/wifi_provisioning/proto/wifi_scan.proto b/components/wifi_provisioning/proto/wifi_scan.proto new file mode 100644 index 0000000000..ea240f20f7 --- /dev/null +++ b/components/wifi_provisioning/proto/wifi_scan.proto @@ -0,0 +1,63 @@ +syntax = "proto3"; + +import "constants.proto"; +import "wifi_constants.proto"; + +message CmdScanStart { + bool blocking = 1; + bool passive = 2; + uint32 group_channels = 3; + uint32 period_ms = 4; +} + +message RespScanStart { + +} + +message CmdScanStatus { + +} + +message RespScanStatus { + bool scan_finished = 1; + uint32 result_count = 2; +} + +message CmdScanResult { + uint32 start_index = 1; + uint32 count = 2; +} + +message WiFiScanResult { + bytes ssid = 1; + uint32 channel = 2; + int32 rssi = 3; + bytes bssid = 4; + WifiAuthMode auth = 5; +} + +message RespScanResult { + repeated WiFiScanResult entries = 1; +} + +enum WiFiScanMsgType { + TypeCmdScanStart = 0; + TypeRespScanStart = 1; + TypeCmdScanStatus = 2; + TypeRespScanStatus = 3; + TypeCmdScanResult = 4; + TypeRespScanResult = 5; +} + +message WiFiScanPayload { + WiFiScanMsgType msg = 1; + Status status = 2; + oneof payload { + CmdScanStart cmd_scan_start = 10; + RespScanStart resp_scan_start = 11; + CmdScanStatus cmd_scan_status = 12; + RespScanStatus resp_scan_status = 13; + CmdScanResult cmd_scan_result = 14; + RespScanResult resp_scan_result = 15; + } +} diff --git a/components/wifi_provisioning/python/wifi_scan_pb2.py b/components/wifi_provisioning/python/wifi_scan_pb2.py new file mode 100644 index 0000000000..2e95d8f505 --- /dev/null +++ b/components/wifi_provisioning/python/wifi_scan_pb2.py @@ -0,0 +1,522 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: wifi_scan.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 +import wifi_constants_pb2 as wifi__constants__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='wifi_scan.proto', + package='', + syntax='proto3', + serialized_options=None, + serialized_pb=_b('\n\x0fwifi_scan.proto\x1a\x0f\x63onstants.proto\x1a\x14wifi_constants.proto\"\\\n\x0c\x43mdScanStart\x12\x10\n\x08\x62locking\x18\x01 \x01(\x08\x12\x0f\n\x07passive\x18\x02 \x01(\x08\x12\x16\n\x0egroup_channels\x18\x03 \x01(\r\x12\x11\n\tperiod_ms\x18\x04 \x01(\r\"\x0f\n\rRespScanStart\"\x0f\n\rCmdScanStatus\"=\n\x0eRespScanStatus\x12\x15\n\rscan_finished\x18\x01 \x01(\x08\x12\x14\n\x0cresult_count\x18\x02 \x01(\r\"3\n\rCmdScanResult\x12\x13\n\x0bstart_index\x18\x01 \x01(\r\x12\r\n\x05\x63ount\x18\x02 \x01(\r\"i\n\x0eWiFiScanResult\x12\x0c\n\x04ssid\x18\x01 \x01(\x0c\x12\x0f\n\x07\x63hannel\x18\x02 \x01(\r\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\x12\r\n\x05\x62ssid\x18\x04 \x01(\x0c\x12\x1b\n\x04\x61uth\x18\x05 \x01(\x0e\x32\r.WifiAuthMode\"2\n\x0eRespScanResult\x12 \n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x0f.WiFiScanResult\"\xd8\x02\n\x0fWiFiScanPayload\x12\x1d\n\x03msg\x18\x01 \x01(\x0e\x32\x10.WiFiScanMsgType\x12\x17\n\x06status\x18\x02 \x01(\x0e\x32\x07.Status\x12\'\n\x0e\x63md_scan_start\x18\n \x01(\x0b\x32\r.CmdScanStartH\x00\x12)\n\x0fresp_scan_start\x18\x0b \x01(\x0b\x32\x0e.RespScanStartH\x00\x12)\n\x0f\x63md_scan_status\x18\x0c \x01(\x0b\x32\x0e.CmdScanStatusH\x00\x12+\n\x10resp_scan_status\x18\r \x01(\x0b\x32\x0f.RespScanStatusH\x00\x12)\n\x0f\x63md_scan_result\x18\x0e \x01(\x0b\x32\x0e.CmdScanResultH\x00\x12+\n\x10resp_scan_result\x18\x0f \x01(\x0b\x32\x0f.RespScanResultH\x00\x42\t\n\x07payload*\x9c\x01\n\x0fWiFiScanMsgType\x12\x14\n\x10TypeCmdScanStart\x10\x00\x12\x15\n\x11TypeRespScanStart\x10\x01\x12\x15\n\x11TypeCmdScanStatus\x10\x02\x12\x16\n\x12TypeRespScanStatus\x10\x03\x12\x15\n\x11TypeCmdScanResult\x10\x04\x12\x16\n\x12TypeRespScanResult\x10\x05\x62\x06proto3') + , + dependencies=[constants__pb2.DESCRIPTOR,wifi__constants__pb2.DESCRIPTOR,]) + +_WIFISCANMSGTYPE = _descriptor.EnumDescriptor( + name='WiFiScanMsgType', + full_name='WiFiScanMsgType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='TypeCmdScanStart', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanStart', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdScanStatus', index=2, number=2, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanStatus', index=3, number=3, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeCmdScanResult', index=4, number=4, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='TypeRespScanResult', index=5, number=5, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=809, + serialized_end=965, +) +_sym_db.RegisterEnumDescriptor(_WIFISCANMSGTYPE) + +WiFiScanMsgType = enum_type_wrapper.EnumTypeWrapper(_WIFISCANMSGTYPE) +TypeCmdScanStart = 0 +TypeRespScanStart = 1 +TypeCmdScanStatus = 2 +TypeRespScanStatus = 3 +TypeCmdScanResult = 4 +TypeRespScanResult = 5 + + + +_CMDSCANSTART = _descriptor.Descriptor( + name='CmdScanStart', + full_name='CmdScanStart', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='blocking', full_name='CmdScanStart.blocking', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='passive', full_name='CmdScanStart.passive', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='group_channels', full_name='CmdScanStart.group_channels', 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='period_ms', full_name='CmdScanStart.period_ms', 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), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58, + serialized_end=150, +) + + +_RESPSCANSTART = _descriptor.Descriptor( + name='RespScanStart', + full_name='RespScanStart', + 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=152, + serialized_end=167, +) + + +_CMDSCANSTATUS = _descriptor.Descriptor( + name='CmdScanStatus', + full_name='CmdScanStatus', + 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=169, + serialized_end=184, +) + + +_RESPSCANSTATUS = _descriptor.Descriptor( + name='RespScanStatus', + full_name='RespScanStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='scan_finished', full_name='RespScanStatus.scan_finished', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='result_count', full_name='RespScanStatus.result_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=186, + serialized_end=247, +) + + +_CMDSCANRESULT = _descriptor.Descriptor( + name='CmdScanResult', + full_name='CmdScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='start_index', full_name='CmdScanResult.start_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='count', full_name='CmdScanResult.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=249, + serialized_end=300, +) + + +_WIFISCANRESULT = _descriptor.Descriptor( + name='WiFiScanResult', + full_name='WiFiScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='ssid', full_name='WiFiScanResult.ssid', index=0, + number=1, 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), + _descriptor.FieldDescriptor( + name='channel', full_name='WiFiScanResult.channel', 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), + _descriptor.FieldDescriptor( + name='rssi', full_name='WiFiScanResult.rssi', index=2, + number=3, type=5, cpp_type=1, 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='bssid', full_name='WiFiScanResult.bssid', index=3, + number=4, 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), + _descriptor.FieldDescriptor( + name='auth', full_name='WiFiScanResult.auth', index=4, + number=5, 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=302, + serialized_end=407, +) + + +_RESPSCANRESULT = _descriptor.Descriptor( + name='RespScanResult', + full_name='RespScanResult', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='entries', full_name='RespScanResult.entries', 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=409, + serialized_end=459, +) + + +_WIFISCANPAYLOAD = _descriptor.Descriptor( + name='WiFiScanPayload', + full_name='WiFiScanPayload', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='msg', full_name='WiFiScanPayload.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='status', full_name='WiFiScanPayload.status', index=1, + number=2, 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_scan_start', full_name='WiFiScanPayload.cmd_scan_start', index=2, + 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_scan_start', full_name='WiFiScanPayload.resp_scan_start', index=3, + 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_scan_status', full_name='WiFiScanPayload.cmd_scan_status', index=4, + 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_scan_status', full_name='WiFiScanPayload.resp_scan_status', index=5, + 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_scan_result', full_name='WiFiScanPayload.cmd_scan_result', index=6, + 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_scan_result', full_name='WiFiScanPayload.resp_scan_result', index=7, + 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='WiFiScanPayload.payload', + index=0, containing_type=None, fields=[]), + ], + serialized_start=462, + serialized_end=806, +) + +_WIFISCANRESULT.fields_by_name['auth'].enum_type = wifi__constants__pb2._WIFIAUTHMODE +_RESPSCANRESULT.fields_by_name['entries'].message_type = _WIFISCANRESULT +_WIFISCANPAYLOAD.fields_by_name['msg'].enum_type = _WIFISCANMSGTYPE +_WIFISCANPAYLOAD.fields_by_name['status'].enum_type = constants__pb2._STATUS +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].message_type = _CMDSCANSTART +_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].message_type = _RESPSCANSTART +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].message_type = _CMDSCANSTATUS +_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].message_type = _RESPSCANSTATUS +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].message_type = _CMDSCANRESULT +_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].message_type = _RESPSCANRESULT +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_start']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_start']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_start'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_status']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_status']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_status'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['cmd_scan_result']) +_WIFISCANPAYLOAD.fields_by_name['cmd_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +_WIFISCANPAYLOAD.oneofs_by_name['payload'].fields.append( + _WIFISCANPAYLOAD.fields_by_name['resp_scan_result']) +_WIFISCANPAYLOAD.fields_by_name['resp_scan_result'].containing_oneof = _WIFISCANPAYLOAD.oneofs_by_name['payload'] +DESCRIPTOR.message_types_by_name['CmdScanStart'] = _CMDSCANSTART +DESCRIPTOR.message_types_by_name['RespScanStart'] = _RESPSCANSTART +DESCRIPTOR.message_types_by_name['CmdScanStatus'] = _CMDSCANSTATUS +DESCRIPTOR.message_types_by_name['RespScanStatus'] = _RESPSCANSTATUS +DESCRIPTOR.message_types_by_name['CmdScanResult'] = _CMDSCANRESULT +DESCRIPTOR.message_types_by_name['WiFiScanResult'] = _WIFISCANRESULT +DESCRIPTOR.message_types_by_name['RespScanResult'] = _RESPSCANRESULT +DESCRIPTOR.message_types_by_name['WiFiScanPayload'] = _WIFISCANPAYLOAD +DESCRIPTOR.enum_types_by_name['WiFiScanMsgType'] = _WIFISCANMSGTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +CmdScanStart = _reflection.GeneratedProtocolMessageType('CmdScanStart', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANSTART, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanStart) + )) +_sym_db.RegisterMessage(CmdScanStart) + +RespScanStart = _reflection.GeneratedProtocolMessageType('RespScanStart', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANSTART, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanStart) + )) +_sym_db.RegisterMessage(RespScanStart) + +CmdScanStatus = _reflection.GeneratedProtocolMessageType('CmdScanStatus', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANSTATUS, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanStatus) + )) +_sym_db.RegisterMessage(CmdScanStatus) + +RespScanStatus = _reflection.GeneratedProtocolMessageType('RespScanStatus', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANSTATUS, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanStatus) + )) +_sym_db.RegisterMessage(RespScanStatus) + +CmdScanResult = _reflection.GeneratedProtocolMessageType('CmdScanResult', (_message.Message,), dict( + DESCRIPTOR = _CMDSCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:CmdScanResult) + )) +_sym_db.RegisterMessage(CmdScanResult) + +WiFiScanResult = _reflection.GeneratedProtocolMessageType('WiFiScanResult', (_message.Message,), dict( + DESCRIPTOR = _WIFISCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:WiFiScanResult) + )) +_sym_db.RegisterMessage(WiFiScanResult) + +RespScanResult = _reflection.GeneratedProtocolMessageType('RespScanResult', (_message.Message,), dict( + DESCRIPTOR = _RESPSCANRESULT, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:RespScanResult) + )) +_sym_db.RegisterMessage(RespScanResult) + +WiFiScanPayload = _reflection.GeneratedProtocolMessageType('WiFiScanPayload', (_message.Message,), dict( + DESCRIPTOR = _WIFISCANPAYLOAD, + __module__ = 'wifi_scan_pb2' + # @@protoc_insertion_point(class_scope:WiFiScanPayload) + )) +_sym_db.RegisterMessage(WiFiScanPayload) + + +# @@protoc_insertion_point(module_scope) diff --git a/components/wifi_provisioning/src/handlers.c b/components/wifi_provisioning/src/handlers.c index 0a57ef56cc..a53c9d6e43 100644 --- a/components/wifi_provisioning/src/handlers.c +++ b/components/wifi_provisioning/src/handlers.c @@ -21,6 +21,7 @@ #include #include "wifi_provisioning/wifi_config.h" +#include "wifi_provisioning/wifi_scan.h" #include "wifi_provisioning/manager.h" #include "wifi_provisioning_priv.h" @@ -134,13 +135,65 @@ static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx) return ret; } -wifi_prov_config_handlers_t get_wifi_prov_handlers(void) +esp_err_t get_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr) { - wifi_prov_config_handlers_t wifi_prov_handlers = { - .get_status_handler = get_status_handler, - .set_config_handler = set_config_handler, - .apply_config_handler = apply_config_handler, - .ctx = NULL - }; - return wifi_prov_handlers; + if (!ptr) { + return ESP_ERR_INVALID_ARG; + } + ptr->get_status_handler = get_status_handler; + ptr->set_config_handler = set_config_handler; + ptr->apply_config_handler = apply_config_handler; + ptr->ctx = NULL; + return ESP_OK; +} + +/*************************************************************************/ + +static esp_err_t scan_start(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms, + wifi_prov_scan_ctx_t **ctx) +{ + return wifi_prov_mgr_wifi_scan_start(blocking, passive, group_channels, period_ms); +} + +static esp_err_t scan_status(bool *scan_finished, + uint16_t *result_count, + wifi_prov_scan_ctx_t **ctx) +{ + *scan_finished = wifi_prov_mgr_wifi_scan_finished(); + *result_count = wifi_prov_mgr_wifi_scan_result_count(); + return ESP_OK; +} + +static esp_err_t scan_result(uint16_t result_index, + wifi_prov_scan_result_t *result, + wifi_prov_scan_ctx_t **ctx) +{ + const wifi_ap_record_t *record = wifi_prov_mgr_wifi_scan_result(result_index); + if (!record) { + return ESP_FAIL; + } + + /* Compile time check ensures memory safety in case SSID length in + * record / result structure definition changes in future */ + _Static_assert(sizeof(result->ssid) == sizeof(record->ssid), + "source and destination should be of same size"); + memcpy(result->ssid, record->ssid, sizeof(record->ssid)); + memcpy(result->bssid, record->bssid, sizeof(record->bssid)); + result->channel = record->primary; + result->rssi = record->rssi; + result->auth = record->authmode; + return ESP_OK; +} + +esp_err_t get_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr) +{ + if (!ptr) { + return ESP_ERR_INVALID_ARG; + } + ptr->scan_start = scan_start; + ptr->scan_status = scan_status; + ptr->scan_result = scan_result; + ptr->ctx = NULL; + return ESP_OK; } diff --git a/components/wifi_provisioning/src/manager.c b/components/wifi_provisioning/src/manager.c index 5f772a7dff..af7991fa76 100644 --- a/components/wifi_provisioning/src/manager.c +++ b/components/wifi_provisioning/src/manager.c @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include @@ -31,7 +32,11 @@ #include "wifi_provisioning_priv.h" -#define WIFI_PROV_MGR_VERSION "v1.0" +#define WIFI_PROV_MGR_VERSION "v1.1" +#define MAX_SCAN_RESULTS CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES + +#define ACQUIRE_LOCK(mux) assert(xSemaphoreTake(mux, portMAX_DELAY) == pdTRUE) +#define RELEASE_LOCK(mux) assert(xSemaphoreGive(mux) == pdTRUE) static const char *TAG = "wifi_prov_mgr"; @@ -50,6 +55,9 @@ typedef enum { * the provisioning service */ struct wifi_prov_capabilities { + /* Security 0 is used */ + bool no_sec; + /* Proof of Possession is not required for establishing session */ bool no_pop; @@ -101,6 +109,9 @@ struct wifi_prov_mgr_ctx { /* Protocomm handlers for Wi-Fi configuration endpoint */ wifi_prov_config_handlers_t *wifi_prov_handlers; + /* Protocomm handlers for Wi-Fi scan endpoint */ + wifi_prov_scan_handlers_t *wifi_scan_handlers; + /* Count of used endpoint UUIDs */ unsigned int endpoint_uuid_used; @@ -113,6 +124,15 @@ struct wifi_prov_mgr_ctx { /* Delay after which resources will be cleaned up asynchronously * upon execution of wifi_prov_mgr_stop_provisioning() */ uint32_t cleanup_delay; + + /* Wi-Fi scan parameters and state variables */ + bool scanning; + uint8_t channels_per_group; + uint16_t curr_channel; + uint16_t ap_list_len[14]; // 14 entries corresponding to each channel + wifi_ap_record_t *ap_list[14]; + wifi_ap_record_t *ap_list_sorted[MAX_SCAN_RESULTS]; + wifi_scan_config_t scan_cfg; }; /* Mutex to lock/unlock access to provisioning singleton @@ -148,7 +168,7 @@ static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) /* Release the mutex before executing the callbacks. This is done so that * wifi_prov_mgr_event_handler() doesn't stay blocked for the duration */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); if (scheme_cb) { /* Call scheme specific event handler */ @@ -160,7 +180,7 @@ static void execute_event_cb(wifi_prov_cb_event_t event_id, void *event_data) app_cb(app_data, event_id, event_data); } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); } } @@ -177,7 +197,7 @@ esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, } esp_err_t ret = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { if (!prov_ctx->app_info_json) { @@ -198,12 +218,12 @@ esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, cJSON_AddItemToArray(capabilities_json, cJSON_CreateString(capabilities[i])); } } - + ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -223,10 +243,15 @@ static cJSON* wifi_prov_get_info_json(void) /* Capabilities field */ cJSON_AddItemToObject(prov_info_json, "cap", prov_capabilities); - /* If Proof of Possession is not used, indicate in capabilities */ - if (prov_ctx->mgr_info.capabilities.no_pop) { + /* If Security / Proof of Possession is not used, indicate in capabilities */ + if (prov_ctx->mgr_info.capabilities.no_sec) { + cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_sec")); + } else if (prov_ctx->mgr_info.capabilities.no_pop) { cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("no_pop")); } + + /* Indicate capability for performing Wi-Fi scan */ + cJSON_AddItemToArray(prov_capabilities, cJSON_CreateString("wifi_scan")); return full_info_json; } @@ -287,12 +312,13 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha } prov_ctx->wifi_prov_handlers = malloc(sizeof(wifi_prov_config_handlers_t)); - if (!prov_ctx->wifi_prov_handlers) { + ret = get_wifi_prov_handlers(prov_ctx->wifi_prov_handlers); + if (ret != ESP_OK) { ESP_LOGD(TAG, "Failed to allocate memory for provisioning handlers"); scheme->prov_stop(prov_ctx->pc); protocomm_delete(prov_ctx->pc); + return ESP_ERR_NO_MEM; } - *prov_ctx->wifi_prov_handlers = get_wifi_prov_handlers(); /* Add protocomm endpoint for Wi-Fi station configuration */ ret = protocomm_add_endpoint(prov_ctx->pc, "prov-config", @@ -306,6 +332,29 @@ static esp_err_t wifi_prov_mgr_start_service(const char *service_name, const cha return ret; } + prov_ctx->wifi_scan_handlers = malloc(sizeof(wifi_prov_scan_handlers_t)); + ret = get_wifi_scan_handlers(prov_ctx->wifi_scan_handlers); + if (ret != ESP_OK) { + ESP_LOGD(TAG, "Failed to allocate memory for Wi-Fi scan handlers"); + free(prov_ctx->wifi_prov_handlers); + scheme->prov_stop(prov_ctx->pc); + protocomm_delete(prov_ctx->pc); + return ESP_ERR_NO_MEM; + } + + /* Add endpoint for scanning Wi-Fi APs and sending scan list */ + ret = protocomm_add_endpoint(prov_ctx->pc, "prov-scan", + wifi_prov_scan_handler, + prov_ctx->wifi_scan_handlers); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi scan endpoint"); + free(prov_ctx->wifi_scan_handlers); + free(prov_ctx->wifi_prov_handlers); + scheme->prov_stop(prov_ctx->pc); + protocomm_delete(prov_ctx->pc); + return ret; + } + ESP_LOGI(TAG, "Provisioning started with service name : %s ", service_name ? service_name : ""); return ESP_OK; @@ -320,7 +369,7 @@ esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name) esp_err_t err = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { err = prov_ctx->mgr_config.scheme.set_config_endpoint( @@ -332,7 +381,7 @@ esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name) } else { prov_ctx->endpoint_uuid_used++; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return err; } @@ -345,13 +394,13 @@ esp_err_t wifi_prov_mgr_endpoint_register(const char *ep_name, protocomm_req_han esp_err_t err = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state > WIFI_PROV_STATE_STARTING && prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) { err = protocomm_add_endpoint(prov_ctx->pc, ep_name, handler, user_ctx); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to register handler for endpoint"); @@ -366,13 +415,13 @@ void wifi_prov_mgr_endpoint_unregister(const char *ep_name) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state > WIFI_PROV_STATE_STARTING && prov_ctx->prov_state < WIFI_PROV_STATE_STOPPING) { protocomm_remove_endpoint(prov_ctx->pc, ep_name); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } static void prov_stop_task(void *arg) @@ -403,15 +452,19 @@ static void prov_stop_task(void *arg) free(prov_ctx->wifi_prov_handlers); prov_ctx->wifi_prov_handlers = NULL; + free(prov_ctx->wifi_scan_handlers->ctx); + free(prov_ctx->wifi_scan_handlers); + prov_ctx->wifi_scan_handlers = NULL; + /* Switch device to Wi-Fi STA mode irrespective of * whether provisioning was completed or not */ esp_wifi_set_mode(WIFI_MODE_STA); ESP_LOGI(TAG, "Provisioning stopped"); if (is_this_a_task) { - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); prov_ctx->prov_state = WIFI_PROV_STATE_IDLE; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); ESP_LOGD(TAG, "execute_event_cb : %d", WIFI_PROV_END); if (scheme_cb) { @@ -445,18 +498,18 @@ static bool wifi_prov_mgr_stop_service(bool blocking) while (prov_ctx && ( prov_ctx->prov_state == WIFI_PROV_STATE_STARTING || prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING)) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(100 / portTICK_PERIOD_MS); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); } } else { /* Wait for any ongoing call to wifi_prov_mgr_start_service() * from another thread to finish */ while (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_STARTING) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(100 / portTICK_PERIOD_MS); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); } if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_STOPPING) { @@ -486,12 +539,22 @@ static bool wifi_prov_mgr_stop_service(bool blocking) prov_ctx->pop.data = NULL; } + /* Delete all scan results */ + for (uint16_t channel = 0; channel < 14; channel++) { + free(prov_ctx->ap_list[channel]); + prov_ctx->ap_list[channel] = NULL; + } + prov_ctx->scanning = false; + for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) { + prov_ctx->ap_list_sorted[i] = NULL; + } + if (blocking) { /* Run the cleanup without launching a separate task. Also the * WIFI_PROV_END event is not emitted in this case */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); prov_stop_task((void *)0); - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); prov_ctx->prov_state = WIFI_PROV_STATE_IDLE; } else { /* Launch cleanup task to perform the cleanup asynchronously. @@ -521,16 +584,17 @@ esp_err_t wifi_prov_mgr_disable_auto_stop(uint32_t cleanup_delay) } esp_err_t ret = ESP_FAIL; - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state == WIFI_PROV_STATE_IDLE) { prov_ctx->mgr_info.capabilities.no_auto_stop = true; prov_ctx->cleanup_delay = cleanup_delay; + ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -542,15 +606,134 @@ esp_err_t wifi_prov_mgr_done(void) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); - /* Stop provisioning if auto stop is not disabled */ + bool auto_stop_enabled = false; + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && !prov_ctx->mgr_info.capabilities.no_auto_stop) { + auto_stop_enabled = true; + } + RELEASE_LOCK(prov_ctx_lock); + + /* Stop provisioning if auto stop is enabled */ + if (auto_stop_enabled) { wifi_prov_mgr_stop_provisioning(); } - xSemaphoreGiveRecursive(prov_ctx_lock); return ESP_OK; } +static esp_err_t update_wifi_scan_results(void) +{ + if (!prov_ctx->scanning) { + return ESP_ERR_INVALID_STATE; + } + ESP_LOGD(TAG, "Scan finished"); + + esp_err_t ret = ESP_FAIL; + uint16_t count = 0; + uint16_t curr_channel = prov_ctx->curr_channel; + + if (prov_ctx->ap_list[curr_channel]) { + free(prov_ctx->ap_list[curr_channel]); + prov_ctx->ap_list[curr_channel] = NULL; + prov_ctx->ap_list_len[curr_channel] = 0; + } + + if (esp_wifi_scan_get_ap_num(&count) != ESP_OK) { + ESP_LOGE(TAG, "Failed to get count of scanned APs"); + goto exit; + } + + if (!count) { + ESP_LOGD(TAG, "Scan result empty"); + ret = ESP_OK; + goto exit; + } + + prov_ctx->ap_list[curr_channel] = (wifi_ap_record_t *) calloc(count, sizeof(wifi_ap_record_t)); + if (!prov_ctx->ap_list[curr_channel]) { + ESP_LOGE(TAG, "Failed to allocate memory for AP list"); + goto exit; + } + if (esp_wifi_scan_get_ap_records(&count, prov_ctx->ap_list[curr_channel]) != ESP_OK) { + ESP_LOGE(TAG, "Failed to get scanned AP records"); + goto exit; + } + prov_ctx->ap_list_len[curr_channel] = count; + + if (prov_ctx->channels_per_group) { + ESP_LOGD(TAG, "Scan results for channel %d :", curr_channel); + } else { + ESP_LOGD(TAG, "Scan results :"); + } + ESP_LOGD(TAG, "\tS.N. %-32s %-12s %s %s", "SSID", "BSSID", "RSSI", "AUTH"); + for (uint8_t i = 0; i < prov_ctx->ap_list_len[curr_channel]; i++) { + ESP_LOGD(TAG, "\t[%2d] %-32s %02x%02x%02x%02x%02x%02x %4d %4d", i, + prov_ctx->ap_list[curr_channel][i].ssid, + prov_ctx->ap_list[curr_channel][i].bssid[0], + prov_ctx->ap_list[curr_channel][i].bssid[1], + prov_ctx->ap_list[curr_channel][i].bssid[2], + prov_ctx->ap_list[curr_channel][i].bssid[3], + prov_ctx->ap_list[curr_channel][i].bssid[4], + prov_ctx->ap_list[curr_channel][i].bssid[5], + prov_ctx->ap_list[curr_channel][i].rssi, + prov_ctx->ap_list[curr_channel][i].authmode); + } + + /* Store results in sorted list */ + { + int rc = MIN(count, MAX_SCAN_RESULTS); + int is = MAX_SCAN_RESULTS - rc - 1; + while (rc > 0 && is >= 0) { + if (prov_ctx->ap_list_sorted[is]) { + if (prov_ctx->ap_list_sorted[is]->rssi > prov_ctx->ap_list[curr_channel][rc - 1].rssi) { + prov_ctx->ap_list_sorted[is + rc] = &prov_ctx->ap_list[curr_channel][rc - 1]; + rc--; + continue; + } + prov_ctx->ap_list_sorted[is + rc] = prov_ctx->ap_list_sorted[is]; + } + is--; + } + while (rc > 0) { + prov_ctx->ap_list_sorted[rc - 1] = &prov_ctx->ap_list[curr_channel][rc - 1]; + rc--; + } + } + + ret = ESP_OK; + exit: + + if (!prov_ctx->channels_per_group) { + /* All channel scan was performed + * so nothing more to do */ + prov_ctx->scanning = false; + goto final; + } + + curr_channel = prov_ctx->curr_channel = (prov_ctx->curr_channel + 1) % 14; + if (ret != ESP_OK || curr_channel == 0) { + prov_ctx->scanning = false; + goto final; + } + + if ((curr_channel % prov_ctx->channels_per_group) == 0) { + vTaskDelay(120 / portTICK_PERIOD_MS); + } + + ESP_LOGD(TAG, "Scan starting on channel %u...", curr_channel); + prov_ctx->scan_cfg.channel = curr_channel; + ret = esp_wifi_scan_start(&prov_ctx->scan_cfg, false); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to start scan"); + prov_ctx->scanning = false; + goto final; + } + ESP_LOGD(TAG, "Scan started"); + + final: + + return ret; +} + /* Event handler for starting/stopping provisioning. * To be called from within the context of the main * event handler */ @@ -563,20 +746,26 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) ESP_LOGE(TAG, "Provisioning manager not initialized"); return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* If pointer to provisioning application data is NULL * then provisioning manager is not running, therefore * return with error to allow the global handler to act */ if (!prov_ctx) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } + /* If scan completed then update scan result */ + if (prov_ctx->prov_state == WIFI_PROV_STATE_STARTED && + event->event_id == SYSTEM_EVENT_SCAN_DONE) { + update_wifi_scan_results(); + } + /* Only handle events when credential is received and * Wi-Fi STA is yet to complete trying the connection */ if (prov_ctx->prov_state != WIFI_PROV_STATE_CRED_RECV) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -654,10 +843,149 @@ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) break; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } +esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive, + uint8_t group_channels, uint32_t period_ms) +{ + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return ESP_ERR_INVALID_STATE; + } + ACQUIRE_LOCK(prov_ctx_lock); + + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return ESP_ERR_INVALID_STATE; + } + + if (prov_ctx->scanning) { + ESP_LOGD(TAG, "Scan already running"); + RELEASE_LOCK(prov_ctx_lock); + return ESP_OK; + } + + /* Clear sorted list for new entries */ + for (uint8_t i = 0; i < MAX_SCAN_RESULTS; i++) { + prov_ctx->ap_list_sorted[i] = NULL; + } + + if (passive) { + prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_PASSIVE; + prov_ctx->scan_cfg.scan_time.passive = period_ms; + } else { + prov_ctx->scan_cfg.scan_type = WIFI_SCAN_TYPE_ACTIVE; + prov_ctx->scan_cfg.scan_time.active.min = period_ms; + prov_ctx->scan_cfg.scan_time.active.max = period_ms; + } + prov_ctx->channels_per_group = group_channels; + + if (prov_ctx->channels_per_group) { + ESP_LOGD(TAG, "Scan starting on channel 1..."); + prov_ctx->scan_cfg.channel = 1; + } else { + ESP_LOGD(TAG, "Scan starting..."); + prov_ctx->scan_cfg.channel = 0; + } + + if (esp_wifi_scan_start(&prov_ctx->scan_cfg, false) != ESP_OK) { + ESP_LOGE(TAG, "Failed to start scan"); + return ESP_FAIL; + } + + ESP_LOGD(TAG, "Scan started"); + prov_ctx->scanning = true; + prov_ctx->curr_channel = prov_ctx->scan_cfg.channel; + RELEASE_LOCK(prov_ctx_lock); + + /* If scan is to be non-blocking, return immediately */ + if (!blocking) { + return ESP_OK; + } + + /* Loop till scan is complete */ + bool scanning = true; + while (scanning) { + ACQUIRE_LOCK(prov_ctx_lock); + scanning = (prov_ctx && prov_ctx->scanning); + RELEASE_LOCK(prov_ctx_lock); + + /* 120ms delay is sufficient for Wi-Fi beacons to be sent */ + vTaskDelay(120 / portTICK_PERIOD_MS); + } + return ESP_OK; +} + +bool wifi_prov_mgr_wifi_scan_finished(void) +{ + bool scan_finished = true; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return scan_finished; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return scan_finished; + } + + scan_finished = !prov_ctx->scanning; + RELEASE_LOCK(prov_ctx_lock); + return scan_finished; +} + +uint16_t wifi_prov_mgr_wifi_scan_result_count(void) +{ + uint16_t rval = 0; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return rval; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return rval; + } + + while (rval < MAX_SCAN_RESULTS) { + if (!prov_ctx->ap_list_sorted[rval]) { + break; + } + rval++; + } + RELEASE_LOCK(prov_ctx_lock); + return rval; +} + +const wifi_ap_record_t *wifi_prov_mgr_wifi_scan_result(uint16_t index) +{ + const wifi_ap_record_t *rval = NULL; + if (!prov_ctx_lock) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + return rval; + } + + ACQUIRE_LOCK(prov_ctx_lock); + if (!prov_ctx) { + ESP_LOGE(TAG, "Provisioning manager not initialized"); + RELEASE_LOCK(prov_ctx_lock); + return rval; + } + + if (index < MAX_SCAN_RESULTS) { + rval = prov_ctx->ap_list_sorted[index]; + } + RELEASE_LOCK(prov_ctx_lock); + return rval; +} + esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state) { if (!prov_ctx_lock) { @@ -665,14 +993,14 @@ esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx == NULL || state == NULL) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } *state = prov_ctx->wifi_state; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -683,19 +1011,19 @@ esp_err_t wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t * return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx == NULL || reason == NULL) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } if (prov_ctx->wifi_state != WIFI_PROV_STA_DISCONNECTED) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } *reason = prov_ctx->wifi_disconnect_reason; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -745,15 +1073,15 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (!prov_ctx) { ESP_LOGE(TAG, "Invalid state of Provisioning app"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } if (prov_ctx->prov_state >= WIFI_PROV_STATE_CRED_RECV) { ESP_LOGE(TAG, "Wi-Fi credentials already received by provisioning app"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } debug_print_wifi_credentials(wifi_cfg->sta, "Received"); @@ -761,7 +1089,7 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) /* Configure Wi-Fi as both AP and/or Station */ if (esp_wifi_set_mode(prov_ctx->mgr_config.scheme.wifi_mode) != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi mode"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } @@ -774,26 +1102,20 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) * provided credentials on NVS */ if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK) { ESP_LOGE(TAG, "Failed to set storage Wi-Fi"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* Configure Wi-Fi station with host credentials * provided during provisioning */ if (esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_cfg) != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi configuration"); - xSemaphoreGiveRecursive(prov_ctx_lock); - return ESP_FAIL; - } - /* (Re)Start Wi-Fi */ - if (esp_wifi_start() != ESP_OK) { - ESP_LOGE(TAG, "Failed to set Wi-Fi configuration"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* Connect to AP */ if (esp_wifi_connect() != ESP_OK) { ESP_LOGE(TAG, "Failed to connect Wi-Fi"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_FAIL; } /* This delay allows channel change to complete */ @@ -804,7 +1126,7 @@ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg) prov_ctx->prov_state = WIFI_PROV_STATE_CRED_RECV; /* Execute user registered callback handler */ execute_event_cb(WIFI_PROV_CRED_RECV, (void *)&wifi_cfg->sta); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_OK; } @@ -817,7 +1139,7 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) * other thread is trying to take this mutex while it is being * deleted from another thread then the reference may become * invalid and cause exception */ - prov_ctx_lock = xSemaphoreCreateRecursiveMutex(); + prov_ctx_lock = xSemaphoreCreateMutex(); if (!prov_ctx_lock) { ESP_LOGE(TAG, "Failed to create mutex"); return ESP_ERR_NO_MEM; @@ -840,10 +1162,10 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) } } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx) { ESP_LOGE(TAG, "Provisioning manager already initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } @@ -851,7 +1173,7 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) prov_ctx = (struct wifi_prov_mgr_ctx *) calloc(1, sizeof(struct wifi_prov_mgr_ctx)); if (!prov_ctx) { ESP_LOGE(TAG, "Error allocating memory for singleton instance"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_NO_MEM; } @@ -869,6 +1191,12 @@ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config) goto exit; } + ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-scan", 0xFF50); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "failed to configure Wi-Fi scanning endpoint"); + goto exit; + } + ret = scheme->set_config_endpoint(prov_ctx->prov_scheme_config, "prov-session", 0xFF51); if (ret != ESP_OK) { ESP_LOGE(TAG, "failed to configure security endpoint"); @@ -904,7 +1232,7 @@ exit: } else { execute_event_cb(WIFI_PROV_INIT, NULL); } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -916,16 +1244,16 @@ void wifi_prov_mgr_wait(void) } while (1) { - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (prov_ctx && prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) { - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); vTaskDelay(1000 / portTICK_PERIOD_MS); continue; } break; } - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } void wifi_prov_mgr_deinit(void) @@ -935,7 +1263,7 @@ void wifi_prov_mgr_deinit(void) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* This will do one of these: * 1) if found running, stop the provisioning service (returns true) @@ -949,7 +1277,7 @@ void wifi_prov_mgr_deinit(void) * was not even initialized */ if (!service_was_running && !prov_ctx) { ESP_LOGD(TAG, "Manager already de-initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return; } @@ -971,7 +1299,7 @@ void wifi_prov_mgr_deinit(void) /* Free manager context */ free(prov_ctx); prov_ctx = NULL; - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); /* If a running service was also stopped during de-initialization * then WIFI_PROV_END event also needs to be emitted before deinit */ @@ -1004,16 +1332,16 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const return ESP_ERR_INVALID_STATE; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (!prov_ctx) { ESP_LOGE(TAG, "Provisioning manager not initialized"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } if (prov_ctx->prov_state != WIFI_PROV_STATE_IDLE) { ESP_LOGE(TAG, "Provisioning service already started"); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ESP_ERR_INVALID_STATE; } @@ -1023,6 +1351,21 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const * thread doesn't interfere with this process */ prov_ctx->prov_state = WIFI_PROV_STATE_STARTING; + /* Start Wi-Fi in Station Mode. + * This is necessary for scanning to work */ + esp_err_t err = esp_wifi_set_mode(WIFI_MODE_STA); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi mode to STA"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + err = esp_wifi_start(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to start Wi-Fi"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + /* Change Wi-Fi storage to RAM temporarily and erase any old * credentials (i.e. without erasing the copy on NVS). Also * call disconnect to make sure device doesn't remain connected @@ -1030,12 +1373,29 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const wifi_config_t wifi_cfg_empty, wifi_cfg_old; memset(&wifi_cfg_empty, 0, sizeof(wifi_config_t)); esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg_old); - esp_wifi_set_storage(WIFI_STORAGE_RAM); + err = esp_wifi_set_storage(WIFI_STORAGE_RAM); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set Wi-Fi storage to RAM"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg_empty); - esp_wifi_disconnect(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to set empty Wi-Fi credentials"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } + err = esp_wifi_disconnect(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to disconnect"); + RELEASE_LOCK(prov_ctx_lock); + return err; + } /* Initialize app data */ - if (pop) { + if (security == WIFI_PROV_SECURITY_0) { + prov_ctx->mgr_info.capabilities.no_sec = true; + } else if (pop) { prov_ctx->pop.len = strlen(pop); prov_ctx->pop.data = malloc(prov_ctx->pop.len); if (!prov_ctx->pop.data) { @@ -1070,7 +1430,7 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const * which may trigger system level events. Hence, releasing the context lock will * ensure that wifi_prov_mgr_event_handler() doesn't block the global event_loop * handler when system events need to be handled */ - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); /* Start provisioning service */ ret = wifi_prov_mgr_start_service(service_name, service_key); @@ -1078,7 +1438,7 @@ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const esp_timer_delete(prov_ctx->timer); free((void *)prov_ctx->pop.data); } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); if (ret == ESP_OK) { prov_ctx->prov_state = WIFI_PROV_STATE_STARTED; /* Execute user registered callback handler */ @@ -1092,7 +1452,7 @@ err: esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_cfg_old); exit: - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); return ret; } @@ -1103,7 +1463,7 @@ void wifi_prov_mgr_stop_provisioning(void) return; } - xSemaphoreTakeRecursive(prov_ctx_lock, portMAX_DELAY); + ACQUIRE_LOCK(prov_ctx_lock); /* Launches task for stopping the provisioning service. This will do one of these: * 1) start a task for stopping the provisioning service (returns true) @@ -1113,5 +1473,5 @@ void wifi_prov_mgr_stop_provisioning(void) */ wifi_prov_mgr_stop_service(0); - xSemaphoreGiveRecursive(prov_ctx_lock); + RELEASE_LOCK(prov_ctx_lock); } diff --git a/components/wifi_provisioning/src/scheme_softap.c b/components/wifi_provisioning/src/scheme_softap.c index 270ef1f587..84262e9375 100644 --- a/components/wifi_provisioning/src/scheme_softap.c +++ b/components/wifi_provisioning/src/scheme_softap.c @@ -54,8 +54,8 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK; } - /* Start Wi-Fi in AP mode with configuration built above */ - esp_err_t err = esp_wifi_set_mode(WIFI_MODE_AP); + /* Run Wi-Fi in AP + STA mode with configuration built above */ + esp_err_t err = esp_wifi_set_mode(WIFI_MODE_APSTA); if (err != ESP_OK) { ESP_LOGE(TAG, "Failed to set Wi-Fi mode : %d", err); return err; @@ -65,12 +65,7 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass) ESP_LOGE(TAG, "Failed to set Wi-Fi config : %d", err); return err; } - err = esp_wifi_start(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to start Wi-Fi : %d", err); - return err; - } - ESP_LOGD(TAG, "Wi-Fi SoftAP started"); + return ESP_OK; } diff --git a/components/wifi_provisioning/src/wifi_provisioning_priv.h b/components/wifi_provisioning/src/wifi_provisioning_priv.h index e93c0859d9..756e82f452 100644 --- a/components/wifi_provisioning/src/wifi_provisioning_priv.h +++ b/components/wifi_provisioning/src/wifi_provisioning_priv.h @@ -21,6 +21,7 @@ #include "wifi_provisioning/manager.h" #include "wifi_provisioning/wifi_config.h" +#include "wifi_provisioning/wifi_scan.h" /** * @brief Notify manager that provisioning is done @@ -36,9 +37,68 @@ */ esp_err_t wifi_prov_mgr_done(void); +/** + * @brief Start Wi-Fi AP Scan + * + * @param[in] blocking Set true to return only after scanning is complete + * @param[in] passive Set true to perform passive scan instead of default active scan + * @param[in] group_channels Number of channels to scan in one go + * (set to 0 for scanning all channels in one go) + * @param[in] period_ms Scan time (in milli-seconds) on each channel + * + * @return + * - ESP_OK : Successfully started Wi-Fi scanning + * - ESP_FAIL : Provisioning app not running + */ +esp_err_t wifi_prov_mgr_wifi_scan_start(bool blocking, bool passive, + uint8_t group_channels, + uint32_t period_ms); + +/** + * @brief Use to query the state of Wi-Fi scan + * + * @return + * - true : Scan finished + * - false : Scan running + */ +bool wifi_prov_mgr_wifi_scan_finished(void); + +/** + * @brief Get the count of results in the scan list + * + * @return + * - count : Number of Wi-Fi Access Points detected while scanning + */ +uint16_t wifi_prov_mgr_wifi_scan_result_count(void); + +/** + * @brief Get AP record for a particular index in the scan list result + * + * @param[out] index Index of the result to fetch + * + * @return + * - result : Pointer to Access Point record + */ +const wifi_ap_record_t *wifi_prov_mgr_wifi_scan_result(uint16_t index); + /** * @brief Get protocomm handlers for wifi_config provisioning endpoint * - * @return wifi_prov_config_handlers_t structure + * @param[out] ptr pointer to structure to be set + * + * @return + * - ESP_OK : success + * - ESP_ERR_INVALID_ARG : null argument */ -wifi_prov_config_handlers_t get_wifi_prov_handlers(void); +esp_err_t get_wifi_prov_handlers(wifi_prov_config_handlers_t *ptr); + +/** + * @brief Get protocomm handlers for wifi_scan provisioning endpoint + * + * @param[out] ptr pointer to structure to be set + * + * @return + * - ESP_OK : success + * - ESP_ERR_INVALID_ARG : null argument + */ +esp_err_t get_wifi_scan_handlers(wifi_prov_scan_handlers_t *ptr); diff --git a/components/wifi_provisioning/src/wifi_scan.c b/components/wifi_provisioning/src/wifi_scan.c new file mode 100644 index 0000000000..8ab3980dc1 --- /dev/null +++ b/components/wifi_provisioning/src/wifi_scan.c @@ -0,0 +1,297 @@ +// 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 +#include +#include +#include +#include + +#include "wifi_scan.pb-c.h" + +#include + +static const char *TAG = "proto_wifi_scan"; + +typedef struct wifi_prov_scan_cmd { + int cmd_num; + esp_err_t (*command_handler)(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data); +} wifi_prov_scan_cmd_t; + +static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, + void *priv_data); + +static wifi_prov_scan_cmd_t cmd_table[] = { + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStart, + .command_handler = cmd_scan_start_handler + }, + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanStatus, + .command_handler = cmd_scan_status_handler + }, + { + .cmd_num = WI_FI_SCAN_MSG_TYPE__TypeCmdScanResult, + .command_handler = cmd_scan_result_handler + } +}; + +static esp_err_t cmd_scan_start_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanStart *resp_payload = (RespScanStart *) malloc(sizeof(RespScanStart)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + + resp_scan_start__init(resp_payload); + resp->status = (h->scan_start(req->cmd_scan_start->blocking, + req->cmd_scan_start->passive, + req->cmd_scan_start->group_channels, + req->cmd_scan_start->period_ms, + &h->ctx) == ESP_OK ? + STATUS__Success : STATUS__InternalError); + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_START; + resp->resp_scan_start = resp_payload; + return ESP_OK; +} + +static esp_err_t cmd_scan_status_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + bool scan_finished = false; + uint16_t result_count = 0; + + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanStatus *resp_payload = (RespScanStatus *) malloc(sizeof(RespScanStatus)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + + resp_scan_status__init(resp_payload); + resp->status = (h->scan_status(&scan_finished, &result_count, &h->ctx) == ESP_OK ? + STATUS__Success : STATUS__InternalError); + resp_payload->scan_finished = scan_finished; + resp_payload->result_count = result_count; + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_STATUS; + resp->resp_scan_status = resp_payload; + return ESP_OK; +} + +static esp_err_t cmd_scan_result_handler(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + esp_err_t err; + wifi_prov_scan_result_t scan_result = {{0}, {0}, 0, 0, 0}; + WiFiScanResult **results = NULL; + wifi_prov_scan_handlers_t *h = (wifi_prov_scan_handlers_t *) priv_data; + if (!h) { + ESP_LOGE(TAG, "Command invoked without handlers"); + return ESP_ERR_INVALID_STATE; + } + + RespScanResult *resp_payload = (RespScanResult *) malloc(sizeof(RespScanResult)); + if (!resp_payload) { + ESP_LOGE(TAG, "Error allocating memory"); + return ESP_ERR_NO_MEM; + } + resp_scan_result__init(resp_payload); + + resp->status = STATUS__Success; + resp->payload_case = WI_FI_SCAN_PAYLOAD__PAYLOAD_RESP_SCAN_RESULT; + resp->resp_scan_result = resp_payload; + + results = (WiFiScanResult **) calloc(req->cmd_scan_result->count, + sizeof(WiFiScanResult *)); + if (!results) { + ESP_LOGE(TAG, "Failed to allocate memory for results array"); + return ESP_ERR_NO_MEM; + } + resp_payload->entries = results; + resp_payload->n_entries = req->cmd_scan_result->count; + + for (uint16_t i = 0; i < req->cmd_scan_result->count; i++) { + err = h->scan_result(i + req->cmd_scan_result->start_index, + &scan_result, &h->ctx); + if (err != ESP_OK) { + resp->status = STATUS__InternalError; + break; + } + + results[i] = (WiFiScanResult *) malloc(sizeof(WiFiScanResult)); + if (!results[i]) { + ESP_LOGE(TAG, "Failed to allocate memory for result entry"); + return ESP_ERR_NO_MEM; + } + wi_fi_scan_result__init(results[i]); + + results[i]->ssid.len = strnlen(scan_result.ssid, 32); + results[i]->ssid.data = (uint8_t *) strndup(scan_result.ssid, 32); + if (!results[i]->ssid.data) { + ESP_LOGE(TAG, "Failed to allocate memory for scan result entry SSID"); + return ESP_ERR_NO_MEM; + } + + results[i]->channel = scan_result.channel; + results[i]->rssi = scan_result.rssi; + results[i]->auth = scan_result.auth; + + results[i]->bssid.len = sizeof(scan_result.bssid); + results[i]->bssid.data = malloc(results[i]->bssid.len); + if (!results[i]->bssid.data) { + ESP_LOGE(TAG, "Failed to allocate memory for scan result entry BSSID"); + return ESP_ERR_NO_MEM; + } + memcpy(results[i]->bssid.data, scan_result.bssid, results[i]->bssid.len); + } + return ESP_OK; +} + + +static int lookup_cmd_handler(int cmd_id) +{ + int i; + + for (i = 0; i < sizeof(cmd_table)/sizeof(wifi_prov_scan_cmd_t); i++) { + if (cmd_table[i].cmd_num == cmd_id) { + return i; + } + } + + return -1; +} + +static void wifi_prov_scan_cmd_cleanup(WiFiScanPayload *resp, void *priv_data) +{ + switch (resp->msg) { + case WI_FI_SCAN_MSG_TYPE__TypeRespScanStart: + { + free(resp->resp_scan_start); + } + break; + case WI_FI_SCAN_MSG_TYPE__TypeRespScanStatus: + { + free(resp->resp_scan_status); + } + break; + case WI_FI_SCAN_MSG_TYPE__TypeRespScanResult: + { + if (!resp->resp_scan_result) return; + if (resp->resp_scan_result->entries) { + for (uint16_t i = 0; i < resp->resp_scan_result->n_entries; i++) { + if (!resp->resp_scan_result->entries[i]) continue; + free(resp->resp_scan_result->entries[i]->ssid.data); + free(resp->resp_scan_result->entries[i]->bssid.data); + free(resp->resp_scan_result->entries[i]); + } + free(resp->resp_scan_result->entries); + } + free(resp->resp_scan_result); + } + break; + default: + ESP_LOGE(TAG, "Unsupported response type in cleanup_handler"); + break; + } + return; +} + +static esp_err_t wifi_prov_scan_cmd_dispatcher(WiFiScanPayload *req, + WiFiScanPayload *resp, void *priv_data) +{ + esp_err_t ret; + + ESP_LOGD(TAG, "In wifi_prov_scan_cmd_dispatcher Cmd=%d", req->msg); + + int cmd_index = lookup_cmd_handler(req->msg); + if (cmd_index < 0) { + ESP_LOGE(TAG, "Invalid command handler lookup"); + return ESP_FAIL; + } + + ret = cmd_table[cmd_index].command_handler(req, resp, priv_data); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Error executing command handler"); + return ESP_FAIL; + } + + return ESP_OK; +} + +esp_err_t wifi_prov_scan_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, + uint8_t **outbuf, ssize_t *outlen, void *priv_data) +{ + WiFiScanPayload *req; + WiFiScanPayload resp; + esp_err_t ret = ESP_OK; + + req = wi_fi_scan_payload__unpack(NULL, inlen, inbuf); + if (!req) { + ESP_LOGE(TAG, "Unable to unpack scan message"); + return ESP_ERR_INVALID_ARG; + } + + wi_fi_scan_payload__init(&resp); + ret = wifi_prov_scan_cmd_dispatcher(req, &resp, priv_data); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Command dispatcher error %d", ret); + ret = ESP_FAIL; + goto exit; + } + + resp.msg = req->msg + 1; /* Response is request + 1 */ + *outlen = wi_fi_scan_payload__get_packed_size(&resp); + if (*outlen <= 0) { + ESP_LOGE(TAG, "Invalid encoding for response"); + ret = ESP_FAIL; + goto exit; + } + + *outbuf = (uint8_t *) malloc(*outlen); + if (!*outbuf) { + ESP_LOGE(TAG, "System out of memory"); + ret = ESP_ERR_NO_MEM; + goto exit; + } + wi_fi_scan_payload__pack(&resp, *outbuf); + ESP_LOGD(TAG, "Response packet size : %d", *outlen); + exit: + + wi_fi_scan_payload__free_unpacked(req, NULL); + wifi_prov_scan_cmd_cleanup(&resp, priv_data); + return ret; +} diff --git a/docs/Doxyfile b/docs/Doxyfile index 771a2f08db..027b283bc4 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -119,6 +119,7 @@ INPUT = \ ../../components/wifi_provisioning/include/wifi_provisioning/scheme_softap.h \ ../../components/wifi_provisioning/include/wifi_provisioning/scheme_console.h \ ../../components/wifi_provisioning/include/wifi_provisioning/wifi_config.h \ + ../../components/wifi_provisioning/include/wifi_provisioning/wifi_scan.h \ ## ## Storage - API Reference ## diff --git a/docs/en/api-reference/provisioning/wifi_provisioning.rst b/docs/en/api-reference/provisioning/wifi_provisioning.rst index 54797d5cfb..5cec30165a 100644 --- a/docs/en/api-reference/provisioning/wifi_provisioning.rst +++ b/docs/en/api-reference/provisioning/wifi_provisioning.rst @@ -234,6 +234,9 @@ Once connected to the device, the provisioning related protocomm endpoints can b * - prov-session - http://.local/prov-session - Security endpoint used for session establishment + * - prov-scan + - http://wifi-prov.local/prov-scan + - Endpoint used for starting Wi-Fi scan and receiving scan results * - prov-config - http://.local/prov-config - Endpoint used for configuring Wi-Fi credentials on device @@ -247,12 +250,29 @@ User side applications need to implement the signature handshaking required for See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under `components/protocomm/proto `_, which define the Protobuf message structures supported by `prov-session` endpoint. -Once a session is established, Wi-Fi credentials are configured using the following set of commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto `_) : +Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under `components/wifi_provisioning/proto `_) : * `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response. * `set_config` - For setting the Wi-Fi connection credentials * `apply_config` - For applying the credentials saved during `set_config` and start the Wi-Fi station +After session establishment, client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the `wifi_config` commands described above. The `wifi_scan` endpoint supports the following protobuf commands : + + * `scan_start` - For starting Wi-Fi scan with various options : + + * `blocking` (input) - If true, the command returns only when the scanning is finished + * `passive` (input) - If true scan is started in passive mode (this may be slower) instead of active mode + * `group_channels` (input) - This specifies whether to scan all channels in one go (when zero) or perform scanning of channels in groups, with 120ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager will wait for atleast 120ms after completing scan on a group of channels, and thus allow the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting group_channels to 4, will create 5 groups, with each group having 3 channels, except the last one which will have 14 % 3 = 2 channels. So, when scan is started, the first 3 channels will be scanned, followed by a 120ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned. One may need to adjust this parameter as having only few channels in a group may slow down the overall scan time, while having too many may again cause disconnection. Usually a value of 4 should work for most cases. Note that for any other mode of transport, e.g. BLE, this can be safely set to 0, and hence achieve the fastest overall scanning time. + * `period_ms` (input) - Scan parameter specifying how long to wait on each channel + * `scan_status` - Gives the status of scanning process : + + * `scan_finished` (output) - When scan has finished this returns true + * `result_count` (output) - This gives the total number of results obtained till now. If scan is yet happening this number will keep on updating + * `scan_result` - For fetching scan results. This can be called even if scan is still on going + + * `start_index` (input) - Starting index from where to fetch the entries from the results list + * `count` (input) - Number of entries to fetch from the starting index + * `entries` (output) - List of entries returned. Each entry consists of `ssid`, `channel` and `rssi` information Additional Endpoints ^^^^^^^^^^^^^^^^^^^^ diff --git a/examples/provisioning/manager/wifi_prov_mgr_test.py b/examples/provisioning/manager/wifi_prov_mgr_test.py index ef0294250b..25bb463d2e 100644 --- a/examples/provisioning/manager/wifi_prov_mgr_test.py +++ b/examples/provisioning/manager/wifi_prov_mgr_test.py @@ -63,7 +63,7 @@ def test_examples_wifi_prov_mgr(env, extra_data): print("Starting Provisioning") verbose = False - protover = "v1.0" + protover = "v1.1" secver = 1 pop = "abcd1234" provmode = "ble" @@ -84,6 +84,10 @@ def test_examples_wifi_prov_mgr(env, extra_data): if not esp_prov.version_match(transport, protover): raise RuntimeError("Mismatch in protocol version") + print("Verifying scan list capability") + if not esp_prov.has_capability(transport, 'wifi_scan'): + raise RuntimeError("Capability not present") + print("Starting Session") if not esp_prov.establish_session(transport, security): raise RuntimeError("Failed to start session") diff --git a/tools/esp_prov/README.md b/tools/esp_prov/README.md index 8466e02ad6..c4fef6938c 100644 --- a/tools/esp_prov/README.md +++ b/tools/esp_prov/README.md @@ -6,7 +6,7 @@ # SYNOPSIS ``` -python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > --ssid < AP SSID > --passphrase < AP Password > --sec_ver < Security version 0 / 1 > [ Optional parameters... ] +python esp_prov.py --transport < mode of provisioning : softap \ ble \ console > --sec_ver < Security version 0 / 1 > [ Optional parameters... ] ``` # DESCRIPTION @@ -18,8 +18,10 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end | prov-session | http://ip:port/prov-session | Security endpoint used for session establishment | | prov-config | http://ip:port/prov-config | Endpoint used for configuring Wi-Fi credentials on device | | proto-ver | http://ip:port/proto-ver | Version endpoint for checking protocol compatibility | +| prov-scan | http://ip:port/prov-scan | Endpoint used for scanning Wi-Fi APs | | custom-config | http://ip:port/custom-config | Optional endpoint for configuring custom credentials | + # PARAMETERS * `--help` @@ -37,11 +39,11 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end * `console` For debugging via console based provisioning. The client->device commands are printed to STDOUT and device->client messages are accepted via STDIN. This is to be used when device is accepting provisioning commands on UART console. -* `--ssid ` - For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning +* `--ssid ` (Optional) + For specifying the SSID of the Wi-Fi AP to which the device is to connect after provisioning. If not provided, scanning is initiated and scan results, as seen by the device, are displayed, of which an SSID can be picked and the corresponding password specified. -* `--passphrase ` - For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning +* `--passphrase ` (Optional) + For specifying the password of the Wi-Fi AP to which the device is to connect after provisioning. Only used when corresponding SSID is provided using `--ssid` * `--sec_ver ` For specifying version of protocomm endpoint security to use. For now two versions are supported: @@ -51,9 +53,6 @@ Usage of `esp-prov` assumes that the provisioning app has specific protocomm end * `--pop ` (Optional) For specifying optional Proof of Possession string to use for protocomm endpoint security version 1. This option is ignored when security version 0 is in use -* `--proto_ver ` (Optional) (Default `V0.1`) - For specifying version string for checking compatibility with provisioning app prior to starting provisioning process - * `--softap_endpoint ` (Optional) (Default `192.168.4.1:80`) For specifying the IP and port of the HTTP server on which provisioning app is running. The client must connect to the device SoftAP prior to running `esp_prov` diff --git a/tools/esp_prov/esp_prov.py b/tools/esp_prov/esp_prov.py index 0839f9d1df..ad199143ae 100644 --- a/tools/esp_prov/esp_prov.py +++ b/tools/esp_prov/esp_prov.py @@ -16,11 +16,13 @@ # from __future__ import print_function +from builtins import input import argparse import time import os import sys import json +from getpass import getpass try: import security @@ -68,12 +70,10 @@ def get_transport(sel_transport, softap_endpoint=None, ble_devname=None): # table are provided only to support devices running older firmware, # in which case, the automated discovery will fail and the client # will fallback to using the provided UUIDs instead + nu_lookup = {'prov-session': 'ff51', 'prov-config': 'ff52', 'proto-ver': 'ff53'} tp = transport.Transport_BLE(devname=ble_devname, service_uuid='0000ffff-0000-1000-8000-00805f9b34fb', - nu_lookup={'prov-session': 'ff51', - 'prov-config': 'ff52', - 'proto-ver': 'ff53' - }) + nu_lookup=nu_lookup) elif (sel_transport == 'console'): tp = transport.Transport_Console() return tp @@ -106,6 +106,33 @@ def version_match(tp, protover, verbose=False): return None +def has_capability(tp, capability, verbose=False): + try: + response = tp.send_data('proto-ver', capability) + + if verbose: + print("proto-ver response : ", response) + + info = json.loads(response) + if capability in info['prov']['cap']: + return True + + except Exception as e: + on_except(e) + + return False + + +def get_version(tp): + response = None + try: + response = tp.send_data('proto-ver', '---') + except RuntimeError as e: + on_except(e) + response = '' + return response + + def establish_session(tp, sec): try: response = None @@ -132,6 +159,56 @@ def custom_config(tp, sec, custom_info, custom_ver): return None +def scan_wifi_APs(sel_transport, tp, sec): + APs = [] + group_channels = 0 + readlen = 100 + if sel_transport == 'softap': + # In case of softAP we must perform the scan on individual channels, one by one, + # so that the Wi-Fi controller gets ample time to send out beacons (necessary to + # maintain connectivity with authenticated stations. As scanning one channel at a + # time will be slow, we can group more than one channels to be scanned in quick + # succession, hence speeding up the scan process. Though if too many channels are + # present in a group, the controller may again miss out on sending beacons. Hence, + # the application must should use an optimum value. The following value usually + # works out in most cases + group_channels = 5 + elif sel_transport == 'ble': + # Read at most 4 entries at a time. This is because if we are using BLE transport + # then the response packet size should not exceed the present limit of 256 bytes of + # characteristic value imposed by protocomm_ble. This limit may be removed in the + # future + readlen = 4 + try: + message = prov.scan_start_request(sec, blocking=True, group_channels=group_channels) + start_time = time.time() + response = tp.send_data('prov-scan', message) + stop_time = time.time() + print("++++ Scan process executed in " + str(stop_time - start_time) + " sec") + prov.scan_start_response(sec, response) + + message = prov.scan_status_request(sec) + response = tp.send_data('prov-scan', message) + result = prov.scan_status_response(sec, response) + print("++++ Scan results : " + str(result["count"])) + if result["count"] != 0: + index = 0 + remaining = result["count"] + while remaining: + count = [remaining, readlen][remaining > readlen] + message = prov.scan_result_request(sec, index, count) + response = tp.send_data('prov-scan', message) + APs += prov.scan_result_response(sec, response) + remaining -= count + index += count + + except RuntimeError as e: + on_except(e) + return None + + return APs + + def send_wifi_config(tp, sec, ssid, passphrase): try: message = prov.config_set_config_request(sec, ssid, passphrase) @@ -166,12 +243,12 @@ if __name__ == '__main__': parser = argparse.ArgumentParser(description="Generate ESP prov payload") parser.add_argument("--ssid", dest='ssid', type=str, - help="SSID of Wi-Fi Network", required=True) + help="SSID of Wi-Fi Network", default='') parser.add_argument("--passphrase", dest='passphrase', type=str, help="Passphrase of Wi-Fi network", default='') parser.add_argument("--sec_ver", dest='secver', type=int, - help="Security scheme version", default=1) + help="Security scheme version", default=None) parser.add_argument("--proto_ver", dest='protover', type=str, help="Protocol version", default='') parser.add_argument("--pop", dest='pop', type=str, @@ -199,14 +276,27 @@ if __name__ == '__main__': if args.protover != '': print("==== Esp_Prov Version: " + args.protover + " ====") - obj_security = get_security(args.secver, args.pop, args.verbose) - if obj_security is None: - print("---- Invalid Security Version ----") - exit(1) - obj_transport = get_transport(args.provmode, args.softap_endpoint, args.ble_devname) if obj_transport is None: print("---- Invalid provisioning mode ----") + exit(1) + + # If security version not specified check in capabilities + if args.secver is None: + # When no_sec is present, use security 0, else security 1 + args.secver = int(not has_capability(obj_transport, 'no_sec')) + + if (args.secver != 0) and not has_capability(obj_transport, 'no_pop'): + if len(args.pop) == 0: + print("---- Proof of Possession argument not provided ----") + exit(2) + elif len(args.pop) != 0: + print("---- Proof of Possession will be ignored ----") + args.pop = '' + + obj_security = get_security(args.secver, args.pop, args.verbose) + if obj_security is None: + print("---- Invalid Security Version ----") exit(2) if args.protover != '': @@ -229,6 +319,49 @@ if __name__ == '__main__': exit(5) print("==== Custom config sent successfully ====") + if args.ssid == '': + if not has_capability(obj_transport, 'wifi_scan'): + print("---- Wi-Fi Scan List is not supported by provisioning service ----") + print("---- Rerun esp_prov with SSID and Passphrase as argument ----") + exit(3) + + while True: + print("\n==== Scanning Wi-Fi APs ====") + start_time = time.time() + APs = scan_wifi_APs(args.provmode, obj_transport, obj_security) + end_time = time.time() + print("\n++++ Scan finished in " + str(end_time - start_time) + " sec") + if APs is None: + print("---- Error in scanning Wi-Fi APs ----") + exit(8) + + if len(APs) == 0: + print("No APs found!") + exit(9) + + print("==== Wi-Fi Scan results ====") + print("{0: >4} {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}".format( + "S.N.", "SSID", "BSSID", "CHN", "RSSI", "AUTH")) + for i in range(len(APs)): + print("[{0: >2}] {1: <33} {2: <12} {3: >4} {4: <4} {5: <16}".format( + i + 1, APs[i]["ssid"], APs[i]["bssid"], APs[i]["channel"], APs[i]["rssi"], APs[i]["auth"])) + + while True: + try: + select = int(input("Select AP by number (0 to rescan) : ")) + if select < 0 or select > len(APs): + raise ValueError + break + except ValueError: + print("Invalid input! Retry") + + if select != 0: + break + + args.ssid = APs[select - 1]["ssid"] + prompt_str = "Enter passphrase for {0} : ".format(args.ssid) + args.passphrase = getpass(prompt_str) + print("\n==== Sending Wi-Fi credential to esp32 ====") if not send_wifi_config(obj_transport, obj_security, args.ssid, args.passphrase): print("---- Error in send Wi-Fi config ----") diff --git a/tools/esp_prov/proto/__init__.py b/tools/esp_prov/proto/__init__.py index c0292bb771..82726cd955 100644 --- a/tools/esp_prov/proto/__init__.py +++ b/tools/esp_prov/proto/__init__.py @@ -37,6 +37,7 @@ session_pb2 = _load_source("session_pb2", idf_path + "/components/protocomm/ # wifi_provisioning component related python files generated from .proto files wifi_constants_pb2 = _load_source("wifi_constants_pb2", idf_path + "/components/wifi_provisioning/python/wifi_constants_pb2.py") wifi_config_pb2 = _load_source("wifi_config_pb2", idf_path + "/components/wifi_provisioning/python/wifi_config_pb2.py") +wifi_scan_pb2 = _load_source("wifi_scan_pb2", idf_path + "/components/wifi_provisioning/python/wifi_scan_pb2.py") # custom_provisioning component related python files generated from .proto files custom_config_pb2 = _load_source("custom_config_pb2", idf_path + diff --git a/tools/esp_prov/prov/__init__.py b/tools/esp_prov/prov/__init__.py index 12529d9d06..9c55a1fefd 100644 --- a/tools/esp_prov/prov/__init__.py +++ b/tools/esp_prov/prov/__init__.py @@ -15,3 +15,4 @@ from .wifi_prov import * # noqa F403 from .custom_prov import * # noqa F403 +from .wifi_scan import * # noqa F403 diff --git a/tools/esp_prov/prov/wifi_scan.py b/tools/esp_prov/prov/wifi_scan.py new file mode 100644 index 0000000000..1b3f913565 --- /dev/null +++ b/tools/esp_prov/prov/wifi_scan.py @@ -0,0 +1,105 @@ +# 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. +# + +# APIs for interpreting and creating protobuf packets for Wi-Fi Scanning + +from __future__ import print_function +from future.utils import tobytes + +import utils +import proto + + +def print_verbose(security_ctx, data): + if (security_ctx.verbose): + print("++++ " + data + " ++++") + + +def scan_start_request(security_ctx, blocking=True, passive=False, group_channels=5, period_ms=120): + # Form protobuf request packet for ScanStart command + cmd = proto.wifi_scan_pb2.WiFiScanPayload() + cmd.msg = proto.wifi_scan_pb2.TypeCmdScanStart + cmd.cmd_scan_start.blocking = blocking + cmd.cmd_scan_start.passive = passive + cmd.cmd_scan_start.group_channels = group_channels + cmd.cmd_scan_start.period_ms = period_ms + enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1') + print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanStart) " + utils.str_to_hexstr(enc_cmd)) + return enc_cmd + + +def scan_start_response(security_ctx, response_data): + # Interpret protobuf response packet from ScanStart command + dec_resp = security_ctx.decrypt_data(tobytes(response_data)) + resp = proto.wifi_scan_pb2.WiFiScanPayload() + resp.ParseFromString(dec_resp) + print_verbose(security_ctx, "ScanStart status " + str(resp.status)) + if resp.status != 0: + raise RuntimeError + + +def scan_status_request(security_ctx): + # Form protobuf request packet for ScanStatus command + cmd = proto.wifi_scan_pb2.WiFiScanPayload() + cmd.msg = proto.wifi_scan_pb2.TypeCmdScanStatus + enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1') + print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanStatus) " + utils.str_to_hexstr(enc_cmd)) + return enc_cmd + + +def scan_status_response(security_ctx, response_data): + # Interpret protobuf response packet from ScanStatus command + dec_resp = security_ctx.decrypt_data(tobytes(response_data)) + resp = proto.wifi_scan_pb2.WiFiScanPayload() + resp.ParseFromString(dec_resp) + print_verbose(security_ctx, "ScanStatus status " + str(resp.status)) + if resp.status != 0: + raise RuntimeError + return {"finished": resp.resp_scan_status.scan_finished, "count": resp.resp_scan_status.result_count} + + +def scan_result_request(security_ctx, index, count): + # Form protobuf request packet for ScanResult command + cmd = proto.wifi_scan_pb2.WiFiScanPayload() + cmd.msg = proto.wifi_scan_pb2.TypeCmdScanResult + cmd.cmd_scan_result.start_index = index + cmd.cmd_scan_result.count = count + enc_cmd = security_ctx.encrypt_data(cmd.SerializeToString()).decode('latin-1') + print_verbose(security_ctx, "Client -> Device (Encrypted CmdScanResult) " + utils.str_to_hexstr(enc_cmd)) + return enc_cmd + + +def scan_result_response(security_ctx, response_data): + # Interpret protobuf response packet from ScanResult command + dec_resp = security_ctx.decrypt_data(tobytes(response_data)) + resp = proto.wifi_scan_pb2.WiFiScanPayload() + resp.ParseFromString(dec_resp) + print_verbose(security_ctx, "ScanResult status " + str(resp.status)) + if resp.status != 0: + raise RuntimeError + authmode_str = ["Open", "WEP", "WPA_PSK", "WPA2_PSK", "WPA_WPA2_PSK", "WPA2_ENTERPRISE"] + results = [] + for entry in resp.resp_scan_result.entries: + results += [{"ssid": entry.ssid.decode('latin-1').rstrip('\x00'), + "bssid": utils.str_to_hexstr(entry.bssid.decode('latin-1')), + "channel": entry.channel, + "rssi": entry.rssi, + "auth": authmode_str[entry.auth]}] + print_verbose(security_ctx, "ScanResult SSID : " + str(results[-1]["ssid"])) + print_verbose(security_ctx, "ScanResult BSSID : " + str(results[-1]["bssid"])) + print_verbose(security_ctx, "ScanResult Channel : " + str(results[-1]["channel"])) + print_verbose(security_ctx, "ScanResult RSSI : " + str(results[-1]["rssi"])) + print_verbose(security_ctx, "ScanResult AUTH : " + str(results[-1]["auth"])) + return results