diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 6461c91..3725589 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,9 +1,23 @@ -idf_component_register(SRCS "main.c" - "cmd_sniffer.c" - "cmd_pcap.c" - "ethernet.c" - "sdcard.c" - "spi.c" - PRIV_REQUIRES console esp_wifi fatfs esp_eth app_trace nvs_flash - INCLUDE_DIRS ".") +idf_component_register( + SRCS + "main.c" + "cmd_sniffer.c" + "cmd_pcap.c" + "config.c" + "ethernet.c" + "events.c" + "mqtt.c" + "sdcard.c" + "spi.c" + PRIV_REQUIRES + app_trace + console + esp_eth + esp_netif + esp_wifi + fatfs + nvs_flash + INCLUDE_DIRS + "." +) diff --git a/main/cmd_sniffer.c b/main/cmd_sniffer.c index 9908dd0..27a6650 100644 --- a/main/cmd_sniffer.c +++ b/main/cmd_sniffer.c @@ -1,20 +1,16 @@ -/* cmd_sniffer example. - This example code is in the Public Domain (or CC0 licensed, at your option.) +#include "sdkconfig.h" - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ #include #include #include +#include +#include + #include "argtable3/argtable3.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/semphr.h" -#include -#include #include "esp_log.h" #include "esp_wifi.h" #include "esp_console.h" @@ -22,7 +18,8 @@ #include "cmd_sniffer.h" #include "cmd_pcap.h" #include "esp_check.h" -#include "sdkconfig.h" + +#include "events.h" #define SNIFFER_DEFAULT_CHANNEL (1) #define SNIFFER_PAYLOAD_FCS_LEN (4) @@ -32,7 +29,7 @@ #define SNIFFER_DECIMAL_NUM (10) -static const char *SNIFFER_TAG = "cmd_sniffer"; +static const char TAG[] = "SNIFFER"; typedef struct { char *filter_name; @@ -52,13 +49,6 @@ typedef struct { esp_eth_handle_t eth_handles[SNIFFER_MAX_ETH_INTFS]; } sniffer_runtime_t; -typedef struct { - void *payload; - uint32_t length; - uint32_t seconds; - uint32_t microseconds; -} sniffer_packet_info_t; - static sniffer_runtime_t snf_rt = {0}; static wlan_filter_table_t wifi_filter_hash_table[SNIFFER_WLAN_FILTER_MAX] = {0}; static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer); @@ -123,28 +113,51 @@ static void queue_packet(void *recv_packet, sniffer_packet_info_t *packet_info) if (snf_rt.work_queue) { /* send packet_info */ if (xQueueSend(snf_rt.work_queue, packet_info, pdMS_TO_TICKS(SNIFFER_PROCESS_PACKET_TIMEOUT_MS)) != pdTRUE) { - ESP_LOGE(SNIFFER_TAG, "sniffer work queue full"); + ESP_LOGE(TAG, "sniffer work queue full"); free(packet_info->payload); } } } else { - ESP_LOGE(SNIFFER_TAG, "No enough memory for promiscuous packet"); + ESP_LOGE(TAG, "No enough memory for promiscuous packet"); + } +} + +static void send_packet_event(void *recv_packet, sniffer_packet_info_t *packet_info) +{ + /* Copy a packet from Link Layer driver and queue the copy to be processed by sniffer task */ + size_t combined_length = sizeof(sniffer_combined_info_t) + packet_info->length; + sniffer_combined_info_t *info_to_queue = malloc(combined_length); + if (info_to_queue) { + info_to_queue->info = *packet_info; + // TODO: This is one more copy than would be nice. Can we send shared_ptr over some sort of queue? + memcpy(info_to_queue->payload, recv_packet, packet_info->length); + info_to_queue->info.payload = NULL; + + int result = esp_event_post(SNIFFER_EVENT_BASE, SNIFFER_GOT_FRAME, info_to_queue, combined_length, 0); + if (result != ESP_OK) + { + ESP_LOGW(TAG, "Could not post event SNIFFER_GOT_FRAME: %s", esp_err_to_name(result)); + } + free(info_to_queue); + } else { + ESP_LOGE(TAG, "No enough memory for promiscuous packet"); } } static void wifi_sniffer_cb(void *recv_buf, wifi_promiscuous_pkt_type_t type) { sniffer_packet_info_t packet_info; - wifi_promiscuous_pkt_t *sniffer = (wifi_promiscuous_pkt_t *)recv_buf; + wifi_promiscuous_pkt_t *packet = (wifi_promiscuous_pkt_t *)recv_buf; /* prepare packet_info */ - packet_info.seconds = sniffer->rx_ctrl.timestamp / 1000000U; - packet_info.microseconds = sniffer->rx_ctrl.timestamp % 1000000U; - packet_info.length = sniffer->rx_ctrl.sig_len; + packet_info.seconds = packet->rx_ctrl.timestamp / 1000000U; + packet_info.microseconds = packet->rx_ctrl.timestamp % 1000000U; + packet_info.length = packet->rx_ctrl.sig_len; /* For now, the sniffer only dumps the length of the MISC type frame */ - if (type != WIFI_PKT_MISC && !sniffer->rx_ctrl.rx_state) { + if (type != WIFI_PKT_MISC && !packet->rx_ctrl.rx_state) { packet_info.length -= SNIFFER_PAYLOAD_FCS_LEN; - queue_packet(sniffer->payload, &packet_info); + //queue_packet(sniffer->payload, &packet_info); + send_packet_event(packet->payload, &packet_info); } } @@ -184,7 +197,7 @@ static void sniffer_task(void *parameters) } if (packet_capture(packet_info.payload, packet_info.length, packet_info.seconds, packet_info.microseconds) != ESP_OK) { - ESP_LOGW(SNIFFER_TAG, "save captured packet failed"); + ESP_LOGW(TAG, "save captured packet failed"); } free(packet_info.payload); if (sniffer->packets_to_sniff > 0) { @@ -204,25 +217,25 @@ static esp_err_t sniffer_stop(sniffer_runtime_t *sniffer) bool eth_set_promiscuous; esp_err_t ret = ESP_OK; - ESP_GOTO_ON_FALSE(sniffer->is_running, ESP_ERR_INVALID_STATE, err, SNIFFER_TAG, "sniffer is already stopped"); + ESP_GOTO_ON_FALSE(sniffer->is_running, ESP_ERR_INVALID_STATE, err, TAG, "sniffer is already stopped"); switch (sniffer->interf) { case SNIFFER_INTF_WLAN: /* Disable wifi promiscuous mode */ - ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(false), err, SNIFFER_TAG, "stop wifi promiscuous failed"); + ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(false), err, TAG, "stop wifi promiscuous failed"); break; case SNIFFER_INTF_ETH: /* Disable Ethernet Promiscuous Mode */ eth_set_promiscuous = false; ESP_GOTO_ON_ERROR(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, ð_set_promiscuous), - err, SNIFFER_TAG, "stop Ethernet promiscuous failed"); + err, TAG, "stop Ethernet promiscuous failed"); esp_eth_update_input_path(sniffer->eth_handles[sniffer->interf_num], NULL, NULL); break; default: - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, SNIFFER_TAG, "unsupported interface"); + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unsupported interface"); break; } - ESP_LOGI(SNIFFER_TAG, "stop promiscuous ok"); + ESP_LOGI(TAG, "stop promiscuous ok"); /* stop sniffer local task */ sniffer->is_running = false; @@ -260,7 +273,7 @@ static esp_err_t sniffer_start(sniffer_runtime_t *sniffer) wifi_promiscuous_filter_t wifi_filter; bool eth_set_promiscuous; - ESP_GOTO_ON_FALSE(!(sniffer->is_running), ESP_ERR_INVALID_STATE, err, SNIFFER_TAG, "sniffer is already running"); + ESP_GOTO_ON_FALSE(!(sniffer->is_running), ESP_ERR_INVALID_STATE, err, TAG, "sniffer is already running"); switch (sniffer->interf) { case SNIFFER_INTF_WLAN: @@ -270,21 +283,21 @@ static esp_err_t sniffer_start(sniffer_runtime_t *sniffer) link_type = PCAP_LINK_TYPE_ETHERNET; break; default: - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, SNIFFER_TAG, "unsupported interface"); + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unsupported interface"); break; } /* init a pcap session */ - ESP_GOTO_ON_ERROR(sniff_packet_start(link_type), err, SNIFFER_TAG, "init pcap session failed"); + ESP_GOTO_ON_ERROR(sniff_packet_start(link_type), err, TAG, "init pcap session failed"); sniffer->is_running = true; sniffer->work_queue = xQueueCreate(CONFIG_SNIFFER_WORK_QUEUE_LEN, sizeof(sniffer_packet_info_t)); - ESP_GOTO_ON_FALSE(sniffer->work_queue, ESP_FAIL, err_queue, SNIFFER_TAG, "create work queue failed"); + ESP_GOTO_ON_FALSE(sniffer->work_queue, ESP_FAIL, err_queue, TAG, "create work queue failed"); sniffer->sem_task_over = xSemaphoreCreateBinary(); - ESP_GOTO_ON_FALSE(sniffer->sem_task_over, ESP_FAIL, err_sem, SNIFFER_TAG, "create work queue failed"); + ESP_GOTO_ON_FALSE(sniffer->sem_task_over, ESP_FAIL, err_sem, TAG, "create work queue failed"); ESP_GOTO_ON_FALSE(xTaskCreate(sniffer_task, "snifferT", CONFIG_SNIFFER_TASK_STACK_SIZE, sniffer, CONFIG_SNIFFER_TASK_PRIORITY, &sniffer->task), ESP_FAIL, - err_task, SNIFFER_TAG, "create task failed"); + err_task, TAG, "create task failed"); switch (sniffer->interf) { case SNIFFER_INTF_WLAN: @@ -292,20 +305,23 @@ static esp_err_t sniffer_start(sniffer_runtime_t *sniffer) wifi_filter.filter_mask = sniffer->filter; esp_wifi_set_promiscuous_filter(&wifi_filter); esp_wifi_set_promiscuous_rx_cb(wifi_sniffer_cb); - ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(true), err_start, SNIFFER_TAG, "set promis failed"); - //ESP_GOTO_ON_ERROR(esp_wifi_set_channel(sniffer->channel, WIFI_SECOND_CHAN_NONE), err_start, SNIFFER_TAG, "set channel failed"); - phy_11p_set(1,0); - ESP_GOTO_ON_ERROR(esp_wifi_set_channel(140, WIFI_SECOND_CHAN_NONE), err_start, SNIFFER_TAG, "set channel failed"); + ESP_GOTO_ON_ERROR(esp_wifi_set_promiscuous(true), err_start, TAG, "set promis failed"); + //ESP_GOTO_ON_ERROR(esp_wifi_set_channel(sniffer->channel, WIFI_SECOND_CHAN_NONE), err_start, TAG, "set channel failed"); + // enable 802.11p mode (enable, unknown (must be 0)) + phy_11p_set(1, 0); + // set a channel with a frequency close to our desired frequency (not sure if strictly needed) + ESP_GOTO_ON_ERROR(esp_wifi_set_channel(140, WIFI_SECOND_CHAN_NONE), err_start, TAG, "set channel failed"); + // switch channel (channel, ignored, ignored, ht_mode?) phy_change_channel(sniffer->channel, 1, 0, 0); - ESP_LOGI(SNIFFER_TAG, "start WiFi promiscuous ok"); + ESP_LOGI(TAG, "start WiFi promiscuous ok"); break; case SNIFFER_INTF_ETH: /* Start Ethernet Promiscuous Mode */ eth_set_promiscuous = true; ESP_GOTO_ON_ERROR(esp_eth_ioctl(sniffer->eth_handles[sniffer->interf_num], ETH_CMD_S_PROMISCUOUS, ð_set_promiscuous), - err_start, SNIFFER_TAG, "start Ethernet promiscuous failed"); + err_start, TAG, "start Ethernet promiscuous failed"); esp_eth_update_input_path(sniffer->eth_handles[sniffer->interf_num], eth_sniffer_cb, NULL); - ESP_LOGI(SNIFFER_TAG, "start Ethernet promiscuous ok"); + ESP_LOGI(TAG, "start Ethernet promiscuous ok"); break; default: break; @@ -342,7 +358,7 @@ esp_err_t sniffer_reg_eth_intf(esp_eth_handle_t eth_handle) while ((snf_rt.eth_handles[i] != NULL) && (i < SNIFFER_MAX_ETH_INTFS)) { i++; } - ESP_GOTO_ON_FALSE(i < SNIFFER_MAX_ETH_INTFS, ESP_FAIL, err, SNIFFER_TAG, "maximum num. of eth interfaces registered"); + ESP_GOTO_ON_FALSE(i < SNIFFER_MAX_ETH_INTFS, ESP_FAIL, err, TAG, "maximum num. of eth interfaces registered"); snf_rt.eth_handles[i] = eth_handle; err: @@ -380,16 +396,16 @@ static int do_sniffer_cmd(int argc, char **argv) snf_rt.interf = SNIFFER_INTF_ETH; snf_rt.interf_num = eth_intf_num; } else { - ESP_LOGE(SNIFFER_TAG, "interface %s not found", sniffer_args.interface->sval[0]); + ESP_LOGE(TAG, "interface %s not found", sniffer_args.interface->sval[0]); return 1; } } else { - ESP_LOGE(SNIFFER_TAG, "interface %s not found", sniffer_args.interface->sval[0]); + ESP_LOGE(TAG, "interface %s not found", sniffer_args.interface->sval[0]); return 1; } } else { snf_rt.interf = SNIFFER_INTF_WLAN; - ESP_LOGW(SNIFFER_TAG, "sniffing interface set to wlan by default"); + ESP_LOGW(TAG, "sniffing interface set to wlan by default"); } /* Check channel: "-c" option */ @@ -402,7 +418,7 @@ static int do_sniffer_cmd(int argc, char **argv) break; case SNIFFER_INTF_ETH: if (sniffer_args.channel->count) { - ESP_LOGW(SNIFFER_TAG, "'channel' option is not available for Ethernet"); + ESP_LOGW(TAG, "'channel' option is not available for Ethernet"); } break; default: @@ -427,7 +443,7 @@ static int do_sniffer_cmd(int argc, char **argv) break; case SNIFFER_INTF_ETH: if (sniffer_args.filter->count) { - ESP_LOGW(SNIFFER_TAG, "'filter' option is not available for Ethernet"); + ESP_LOGW(TAG, "'filter' option is not available for Ethernet"); } default: break; @@ -437,7 +453,7 @@ static int do_sniffer_cmd(int argc, char **argv) snf_rt.packets_to_sniff = -1; if (sniffer_args.number->count) { snf_rt.packets_to_sniff = sniffer_args.number->ival[0]; - ESP_LOGI(SNIFFER_TAG, "%" PRIi32 " packages will be captured", snf_rt.packets_to_sniff); + ESP_LOGI(TAG, "%" PRIi32 " packages will be captured", snf_rt.packets_to_sniff); } /* start sniffer */ diff --git a/main/cmd_sniffer.h b/main/cmd_sniffer.h index 8972d0d..3e3458e 100644 --- a/main/cmd_sniffer.h +++ b/main/cmd_sniffer.h @@ -14,6 +14,18 @@ extern "C" { #endif +typedef struct { + void *payload; + uint32_t length; + uint32_t seconds; + uint32_t microseconds; +} sniffer_packet_info_t; + +typedef struct { + sniffer_packet_info_t info; + uint8_t payload[]; +} sniffer_combined_info_t; + /** * @brief Supported Sniffer Interface * @@ -42,6 +54,7 @@ typedef enum { void register_sniffer_cmd(void); esp_err_t sniffer_reg_eth_intf(esp_eth_handle_t eth_handle); + #ifdef __cplusplus } #endif diff --git a/main/config.c b/main/config.c new file mode 100644 index 0000000..0f37949 --- /dev/null +++ b/main/config.c @@ -0,0 +1,596 @@ +#include "sdkconfig.h" + +#include +#include +#include + +#include "esp_console.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "mbedtls/base64.h" +#include "nvs.h" +#include "nvs_flash.h" +#include "argtable3/argtable3.h" + +#include "config.h" + +static const char TAG[] = "CONFIG"; + +static nvs_handle_t handle; + +typedef esp_err_t (*config_u8_getter) (uint8_t *out); +typedef esp_err_t (*config_u16_getter) (uint16_t *out); +typedef esp_err_t (*config_u32_getter) (uint32_t *out); +typedef esp_err_t (*config_u64_getter) (uint64_t *out); +typedef esp_err_t (*config_i8_getter) (int8_t *out); +typedef esp_err_t (*config_i16_getter) (int16_t *out); +typedef esp_err_t (*config_i32_getter) (int32_t *out); +typedef esp_err_t (*config_i64_getter) (int64_t *out); +typedef esp_err_t (*config_str_getter) (char *out, size_t *size); +typedef esp_err_t (*config_blob_getter)(uint8_t *out, size_t *size); + +typedef esp_err_t (*config_u8_setter) (uint8_t val); +typedef esp_err_t (*config_u16_setter) (uint16_t val); +typedef esp_err_t (*config_u32_setter) (uint32_t val); +typedef esp_err_t (*config_u64_setter) (uint64_t val); +typedef esp_err_t (*config_i8_setter) (int8_t val); +typedef esp_err_t (*config_i16_setter) (int16_t val); +typedef esp_err_t (*config_i32_setter) (int32_t val); +typedef esp_err_t (*config_i64_setter) (int64_t val); +typedef esp_err_t (*config_str_setter) (const char *val); +typedef esp_err_t (*config_blob_setter)(const uint8_t *val, size_t size); + +typedef struct config_key { + char name[NVS_KEY_NAME_MAX_SIZE]; + nvs_type_t type; + size_t buffer_size; + void *getter; + void *setter; +} config_key_t; + +static esp_err_t config_get_node_id(char *out, size_t *size); + +static const config_key_t config_keys[] = { + [CONFIG_INDEX_NODEID] = { "nodeid", NVS_TYPE_STR, CONFIG_NODEID_BUFFER_SIZE, config_get_node_id, NULL }, + [CONFIG_INDEX_MQTT_URI] = { "mqtturi", NVS_TYPE_STR, CONFIG_MQTT_URI_BUFFER_SIZE, NULL, NULL }, +}; +#define CONFIG_KEYS_END (&config_keys[sizeof(config_keys)/sizeof(*config_keys)]) + + +void config_init(void) +{ + esp_err_t err = nvs_flash_init(); + if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + err = nvs_flash_init(); + } + ESP_ERROR_CHECK(err); + + ESP_ERROR_CHECK(nvs_open("its", NVS_READWRITE, &handle)); +} + +esp_err_t config_get_node_id(char *out, size_t *size) +{ + size_t size_copy = *size; + + esp_err_t res = nvs_get_str(handle, "nodeid", out, &size_copy); + if (res != ESP_OK) + { + if (res != ESP_ERR_NVS_NOT_FOUND) + ESP_LOGW(TAG, "nvs_get_str failed: %s", esp_err_to_name(res)); + + uint8_t base_mac[6]; + ESP_ERROR_CHECK(esp_base_mac_addr_get(base_mac)); + + int print_res = snprintf(out, *size, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + base_mac[0], base_mac[1], base_mac[2], base_mac[3], base_mac[4], base_mac[5]); + + if (print_res > *size - 1) + { + ESP_LOGE(TAG, "buffer too small to print"); + return ESP_ERR_INVALID_SIZE; + } + + if (print_res < 0) + { + ESP_LOGE(TAG, "snprintf failed"); + return ESP_ERR_INVALID_STATE; + } + + size_copy = print_res + 1; + } + + *size = size_copy; + + return ESP_OK; +} + +esp_err_t config_get_str(config_index_t index, char *out, size_t *size) +{ + const config_key_t *key = &config_keys[index]; + + if (key->type != NVS_TYPE_STR) + { + ESP_LOGE(TAG, "Attempt to get key %s with wrong type str", key->name); + return ESP_ERR_INVALID_ARG; + } + + if (key->getter) + return ((config_str_getter)key->getter)(out, size); + else + return nvs_get_str(handle, key->name, out, size); +} + +esp_err_t config_set_str(config_index_t index, const char *value) +{ + const config_key_t *key = &config_keys[index]; + + if (key->type != NVS_TYPE_STR) + { + ESP_LOGE(TAG, "Attempt to set key %s with wrong type str", key->name); + return ESP_ERR_INVALID_ARG; + } + + if (strlen(value) >= key->buffer_size) + return ESP_ERR_INVALID_SIZE; + + if (key->setter) + return ((config_str_setter)key->setter)(value); + else + return nvs_set_str(handle, key->name, value); +} + +static const config_key_t *config_key_find(const char *name) +{ + for (const config_key_t *it = config_keys; it != CONFIG_KEYS_END; it++) + { + if (strcmp(name, it->name)) + continue; + + return it; + } + + return NULL; +} + +static struct { + arg_lit_t *raw; + arg_str_t *key; + arg_str_t *value; + arg_end_t *end; +} config_set_args; + +static int cmd_config_set(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&config_set_args); + if (nerrors != 0) { + arg_print_errors(stderr, config_set_args.end, argv[0]); + return 1; + } + + const char *key_str = config_set_args.key->sval[0]; + const char *value_str = config_set_args.value->sval[0]; + + const config_key_t *key = config_key_find(key_str); + if (key == NULL) + { + ESP_LOGE(TAG, "No such config key: %s", key_str); + return 1; + } + + esp_err_t res; + switch (key->type) + { + case NVS_TYPE_U8: + case NVS_TYPE_U16: + case NVS_TYPE_U32: + case NVS_TYPE_U64: + { + char *end; + uint64_t parsed = strtoull(value_str, &end, 0); + if (*end != '\0') + { + ESP_LOGE(TAG, "Invalid unsigned integer"); + return 1; + } + + if ((key->type == NVS_TYPE_U8 && parsed > UINT8_MAX) || + (key->type == NVS_TYPE_U16 && parsed > UINT16_MAX) || + (key->type == NVS_TYPE_U32 && parsed > UINT32_MAX)) + { + ESP_LOGE(TAG, "Value out of range for type"); + return 1; + } + + if (key->setter == NULL || config_set_args.raw->count) + { + switch (key->type) { + case NVS_TYPE_U8: + res = nvs_set_u8(handle, key_str, (uint8_t)parsed); + break; + case NVS_TYPE_U16: + res = nvs_set_u16(handle, key_str, (uint16_t)parsed); + break; + case NVS_TYPE_U32: + res = nvs_set_u32(handle, key_str, (uint32_t)parsed); + break; + case NVS_TYPE_U64: + res = nvs_set_u64(handle, key_str, parsed); + break; + default: + __builtin_unreachable(); + } + } + else + { + switch (key->type) { + case NVS_TYPE_U8: + res = ((config_u8_setter)key->setter)((uint8_t)parsed); + break; + case NVS_TYPE_U16: + res = ((config_u16_setter)key->setter)((uint16_t)parsed); + break; + case NVS_TYPE_U32: + res = ((config_u32_setter)key->setter)((uint32_t)parsed); + break; + case NVS_TYPE_U64: + res = ((config_u64_setter)key->setter)(parsed); + break; + default: + __builtin_unreachable(); + } + } + } + + break; + case NVS_TYPE_I8: + case NVS_TYPE_I16: + case NVS_TYPE_I32: + case NVS_TYPE_I64: + { + char *end; + int64_t parsed = strtoll(value_str, &end, 0); + if (*end != '\0') + { + ESP_LOGE(TAG, "Invalid signed integer"); + return 1; + } + + if ((key->type == NVS_TYPE_I8 && (parsed < INT8_MIN || parsed > INT8_MAX)) || + (key->type == NVS_TYPE_I16 && (parsed < INT16_MIN || parsed > INT16_MAX)) || + (key->type == NVS_TYPE_I32 && (parsed < INT32_MIN || parsed > INT32_MAX))) + { + ESP_LOGE(TAG, "Value out of range for type"); + return 1; + } + + if (key->setter == NULL || config_set_args.raw->count) + { + switch (key->type) { + case NVS_TYPE_U8: + res = nvs_set_i8(handle, key_str, (int8_t)parsed); + break; + case NVS_TYPE_U16: + res = nvs_set_i16(handle, key_str, (int16_t)parsed); + break; + case NVS_TYPE_U32: + res = nvs_set_i32(handle, key_str, (int32_t)parsed); + break; + case NVS_TYPE_U64: + res = nvs_set_i64(handle, key_str, parsed); + break; + default: + __builtin_unreachable(); + } + } + else + { + switch (key->type) { + case NVS_TYPE_U8: + res = ((config_i8_setter)key->setter)((int8_t)parsed); + break; + case NVS_TYPE_U16: + res = ((config_i16_setter)key->setter)((int16_t)parsed); + break; + case NVS_TYPE_U32: + res = ((config_i32_setter)key->setter)((int32_t)parsed); + break; + case NVS_TYPE_U64: + res = ((config_i64_setter)key->setter)(parsed); + break; + default: + __builtin_unreachable(); + } + } + } + + break; + case NVS_TYPE_STR: + if (strlen(value_str) >= key->buffer_size) + { + ESP_LOGE(TAG, "Value too long"); + return 1; + } + + if (key->setter == NULL || config_set_args.raw->count) + res = nvs_set_str(handle, key_str, value_str); + else + res = ((config_str_setter)key->setter)(value_str); + break; + case NVS_TYPE_BLOB: + { + unsigned char *buf = malloc(key->buffer_size); + size_t olen; + int result = mbedtls_base64_decode(buf, key->buffer_size, &olen, (const uint8_t *)value_str, strlen(value_str)); + if (result != 0) + { + ESP_LOGE(TAG, "mbedtls_base64_decode failed: %#x", result); + free(buf); + return 1; + } + + if (olen > key->buffer_size) + { + ESP_LOGE(TAG, "Value too long"); + free(buf); + return 1; + } + + if (key->setter == NULL || config_set_args.raw->count) + res = nvs_set_blob(handle, key_str, buf, olen); + else + res = ((config_blob_setter)key->setter)(buf, olen); + free(buf); + } + break; + default: + __builtin_unreachable(); + // avoid compiler warning + res = ESP_ERR_INVALID_STATE; + } + + if (res != ESP_OK) + { + ESP_LOGE(TAG, "set failed: %s", esp_err_to_name(res)); + return 1; + } + + return 0; +} + +void register_config_set(void) +{ + config_set_args.raw = arg_lit0("R", NULL, "skip setter functions, directly write NVS"); + config_set_args.key = arg_str1(NULL, NULL, "key", "the key"); + config_set_args.value = arg_str1(NULL, NULL, "value", "the value to set"); + config_set_args.end = arg_end(1); + + const esp_console_cmd_t cmd = { + .command = "config_set", + .help = "set a config key", + .hint = NULL, + .func = &cmd_config_set, + .argtable = &config_set_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + +static struct { + arg_lit_t *raw; + arg_str_t *key; + arg_end_t *end; +} config_get_args; + +static int cmd_config_get(int argc, char **argv) +{ + int nerrors = arg_parse(argc, argv, (void **)&config_get_args); + if (nerrors != 0) { + arg_print_errors(stderr, config_get_args.end, argv[0]); + return 1; + } + + const char *key_str = config_get_args.key->sval[0]; + + const config_key_t *key = config_key_find(key_str); + if (key == NULL) + { + ESP_LOGE(TAG, "No such config key: %s", key_str); + return 1; + } + + esp_err_t res; + + switch (key->type) + { + case NVS_TYPE_U8: + case NVS_TYPE_U16: + case NVS_TYPE_U32: + case NVS_TYPE_U64: + { + uint64_t value = 0; + + if (key->getter == NULL || config_get_args.raw->count) + { + switch (key->type) { + case NVS_TYPE_U8: + res = nvs_get_u8(handle, key_str, (uint8_t *)&value); + break; + case NVS_TYPE_U16: + res = nvs_get_u16(handle, key_str, (uint16_t *)&value); + break; + case NVS_TYPE_U32: + res = nvs_get_u32(handle, key_str, (uint32_t *)&value); + break; + case NVS_TYPE_U64: + res = nvs_get_u64(handle, key_str, &value); + break; + default: + __builtin_unreachable(); + } + } + else + { + switch (key->type) { + case NVS_TYPE_U8: + res = ((config_u8_getter)key->getter)((uint8_t *)&value); + break; + case NVS_TYPE_U16: + res = ((config_u16_getter)key->getter)((uint16_t *)&value); + break; + case NVS_TYPE_U32: + res = ((config_u32_getter)key->getter)((uint32_t *)&value); + break; + case NVS_TYPE_U64: + res = ((config_u64_getter)key->getter)(&value); + break; + default: + __builtin_unreachable(); + } + } + + if (res == ESP_OK) + printf("%"PRIu64 "\n", value); + } + + break; + case NVS_TYPE_I8: + case NVS_TYPE_I16: + case NVS_TYPE_I32: + case NVS_TYPE_I64: + { + int64_t value = 0; + + if (key->getter == NULL || config_get_args.raw->count) + { + switch (key->type) { + case NVS_TYPE_I8: + res = nvs_get_i8(handle, key_str, (int8_t *)&value); + value = (int64_t)(int8_t)value; + break; + case NVS_TYPE_I16: + res = nvs_get_i16(handle, key_str, (int16_t *)&value); + value = (int64_t)(int16_t)value; + break; + case NVS_TYPE_I32: + res = nvs_get_i32(handle, key_str, (int32_t *)&value); + value = (int64_t)(int32_t)value; + break; + case NVS_TYPE_I64: + res = nvs_get_i64(handle, key_str, &value); + break; + default: + __builtin_unreachable(); + } + } + else + { + switch (key->type) { + case NVS_TYPE_I8: + res = ((config_i8_getter)key->getter)((int8_t *)&value); + value = (int64_t)(int8_t)value; + break; + case NVS_TYPE_I16: + res = ((config_i16_getter)key->getter)((int16_t *)&value); + value = (int64_t)(int16_t)value; + break; + case NVS_TYPE_I32: + res = ((config_i32_getter)key->getter)((int32_t *)&value); + value = (int64_t)(int32_t)value; + break; + case NVS_TYPE_I64: + res = ((config_i64_getter)key->getter)(&value); + break; + default: + __builtin_unreachable(); + } + } + + if (res == ESP_OK) + printf("%"PRIi64 "\n", value); + } + + break; + case NVS_TYPE_STR: + char *value = malloc(key->buffer_size); + size_t size = key->buffer_size; + + if (key->getter == NULL || config_get_args.raw->count) + res = nvs_get_str(handle, key_str, value, &size); + else + res = ((config_str_getter)key->getter)(value, &size); + + if (res == ESP_OK) + printf("%s\n", value); + + free(value); + break; + case NVS_TYPE_BLOB: + { + unsigned char *buf = malloc(key->buffer_size); + size_t actual_size; + + if (key->getter == NULL || config_get_args.raw->count) + res = nvs_get_blob(handle, key_str, buf, &actual_size); + else + res = ((config_blob_getter)key->getter)(buf, &actual_size); + + if (res != ESP_OK) + { + free(buf); + break; + } + + const size_t base64_buffer_size = (((4 * key->buffer_size / 3) + 3) & ~3) + 1; + unsigned char *base64_buf = malloc(base64_buffer_size); + size_t olen; + int result = mbedtls_base64_encode(base64_buf, base64_buffer_size, &olen, (const uint8_t *)buf, actual_size); + if (result != 0) + { + ESP_LOGE(TAG, "mbedtls_base64_encode failed: %#x", result); + free(buf); + free(base64_buf); + return 1; + } + + printf("%s\n", base64_buf); + free(buf); + free(base64_buf); + } + break; + default: + __builtin_unreachable(); + // avoid compiler warning + res = ESP_ERR_INVALID_STATE; + } + + if (res != ESP_OK) + { + ESP_LOGE(TAG, "get failed: %s", esp_err_to_name(res)); + return 1; + } + + return 0; +} + +void register_config_get(void) +{ + config_get_args.raw = arg_lit0("R", NULL, "skip getter functions, directly read NVS"); + config_get_args.key = arg_str1(NULL, NULL, "key", "the key"); + config_get_args.end = arg_end(1); + + const esp_console_cmd_t cmd = { + .command = "config_get", + .help = "get a config key", + .hint = NULL, + .func = &cmd_config_get, + .argtable = &config_get_args + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + +void config_register_commands(void) +{ + register_config_set(); + register_config_get(); +} diff --git a/main/config.h b/main/config.h new file mode 100644 index 0000000..89e853c --- /dev/null +++ b/main/config.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esp_err.h" + +#define CONFIG_NODEID_BUFFER_SIZE 64 +#define CONFIG_MQTT_URI_BUFFER_SIZE 256 + +void config_init(void); + +typedef enum { + CONFIG_INDEX_NODEID, + CONFIG_INDEX_MQTT_URI, +} config_index_t; + +esp_err_t config_get_str(config_index_t index, char *out, size_t *size); +esp_err_t config_set_str(config_index_t index, const char *value); + + +void config_register_commands(void); diff --git a/main/ethernet.c b/main/ethernet.c index 9e6c7fd..47a305e 100644 --- a/main/ethernet.c +++ b/main/ethernet.c @@ -10,6 +10,7 @@ #include "lwip/netif.h" #include "cmd_sniffer.h" +#include "events.h" #include "ethernet.h" @@ -18,6 +19,9 @@ static const char TAG[] = "ETHERNET"; +static esp_netif_t *mgmt_netif; +static esp_eth_handle_t mgmt_eth; + /** Event handler for Ethernet events */ static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) @@ -33,15 +37,20 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); break; case ETHERNET_EVENT_DISCONNECTED: - printf("\n"); ESP_LOGI(TAG, "Ethernet link down"); + if (eth_handle == mgmt_eth) + { + esp_err_t post_res = esp_event_post(APP_EVENT_BASE, APP_ETHERNET_MGMT_INTERFACE_DISCONNECTED, NULL, 0, 0); + if (post_res != ESP_OK) + { + ESP_LOGE(TAG, "esp_event_post failed: %s", esp_err_to_name(post_res)); + } + } break; case ETHERNET_EVENT_START: - printf("\n"); ESP_LOGI(TAG, "Ethernet started"); break; case ETHERNET_EVENT_STOP: - printf("\n"); ESP_LOGI(TAG, "Ethernet stopped"); break; default: @@ -53,23 +62,48 @@ static void eth_event_handler(void *arg, esp_event_base_t event_base, static void ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + + char ifname[NETIF_NAMESIZE] = {0}; + esp_err_t res = esp_netif_get_netif_impl_name(event->esp_netif, ifname); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Failed to get netif name: %s", esp_err_to_name(res)); + strcpy(ifname, "unk"); + } + switch (event_id) { case IP_EVENT_ETH_GOT_IP: { - ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; - - char ifname[NETIF_NAMESIZE] = {0}; - esp_err_t res = esp_netif_get_netif_impl_name(event->esp_netif, ifname); - if (res != ESP_OK) - { - ESP_LOGE(TAG, "Failed to get netif name: %s", esp_err_to_name(res)); - strcpy(ifname, "unk"); - } - const esp_netif_ip_info_t *ip_info = &event->ip_info; ESP_LOGI(TAG, "Ethernet %s got IP: " IPSTR " netmask: " IPSTR " gw: " IPSTR, ifname, IP2STR(&ip_info->ip), IP2STR(&ip_info->netmask), IP2STR(&ip_info->gw)); + + // If this is the management netif, post an event to start MQTT etc. + if (event->esp_netif == mgmt_netif) + { + esp_err_t post_res = esp_event_post(APP_EVENT_BASE, APP_ETHERNET_MGMT_INTERFACE_CONNECTED, NULL, 0, 0); + if (post_res != ESP_OK) + { + ESP_LOGE(TAG, "esp_event_post failed: %s", esp_err_to_name(post_res)); + } + } break; } + case IP_EVENT_ETH_LOST_IP: + { + ESP_LOGI(TAG, "Ethernet %s lost IP", ifname); + + // If this is the management netif, post an event to start MQTT etc. + if (event->esp_netif == mgmt_netif) + { + esp_err_t post_res = esp_event_post(APP_EVENT_BASE, APP_ETHERNET_MGMT_INTERFACE_DISCONNECTED, NULL, 0, 0); + if (post_res != ESP_OK) + { + ESP_LOGE(TAG, "esp_event_post failed: %s", esp_err_to_name(post_res)); + } + } + } + default: break; } @@ -109,6 +143,9 @@ void initialize_ethernet(void) cfg.base = &esp_netif_config; esp_netif_t *eth_netif = esp_netif_new(&cfg); + mgmt_netif = eth_netif; + mgmt_eth = eth_handles[i]; + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i]))); ESP_ERROR_CHECK(esp_eth_start(eth_handles[i])); } diff --git a/main/events.c b/main/events.c new file mode 100644 index 0000000..4859c93 --- /dev/null +++ b/main/events.c @@ -0,0 +1,9 @@ +#include "sdkconfig.h" + +#include "esp_event.h" + +#include "events.h" + +ESP_EVENT_DEFINE_BASE(APP_EVENT_BASE); + +ESP_EVENT_DEFINE_BASE(SNIFFER_EVENT_BASE); diff --git a/main/events.h b/main/events.h new file mode 100644 index 0000000..c4e5c48 --- /dev/null +++ b/main/events.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esp_event.h" + +ESP_EVENT_DECLARE_BASE(APP_EVENT_BASE); + +enum AppEvent +{ + APP_ETHERNET_MGMT_INTERFACE_CONNECTED, + APP_ETHERNET_MGMT_INTERFACE_DISCONNECTED +}; + + +ESP_EVENT_DECLARE_BASE(SNIFFER_EVENT_BASE); + +enum SnifferEvent +{ + SNIFFER_GOT_FRAME +}; diff --git a/main/idf_component.yml b/main/idf_component.yml index 2da9f04..a6125d2 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -2,3 +2,5 @@ dependencies: pcap: "^1.0.0" espressif/ethernet_init: version: "~1.3.0" + espressif/mqtt: + version: "~1.0.0" diff --git a/main/main.c b/main/main.c index f8932b2..0cc823e 100644 --- a/main/main.c +++ b/main/main.c @@ -14,7 +14,9 @@ #include "cmd_sniffer.h" #include "cmd_pcap.h" +#include "config.h" #include "ethernet.h" +#include "mqtt.h" #include "sdcard.h" #include "spi.h" @@ -40,16 +42,6 @@ static void initialize_filesystem(void) } } -static void initialize_nvs(void) -{ - esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - err = nvs_flash_init(); - } - ESP_ERROR_CHECK(err); -} - /* Initialize wifi with tcp/ip adapter */ static void initialize_wifi(void) { @@ -59,27 +51,26 @@ static void initialize_wifi(void) ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_NULL)); } -void app_main(void) +static esp_console_repl_t *repl; +static void console_init(void) { - initialize_nvs(); - initialize_filesystem(); + // 31 buffer size - length of colors and 1 space after prompt - 1 closing angle bracket - 1 null byte + const size_t max_nodeid_length = 31 - (sizeof(LOG_COLOR_I " " LOG_RESET_COLOR) - 1) - 1 - 1; - initialize_spi(); + char prompt[CONFIG_NODEID_BUFFER_SIZE]; + size_t size = sizeof(prompt); + ESP_ERROR_CHECK(config_get_str(CONFIG_INDEX_NODEID, prompt, &size)); - /*--- Initialize Network ---*/ - ESP_ERROR_CHECK(esp_event_loop_create_default()); - /* Initialize WiFi */ - initialize_wifi(); - /* Initialize Ethernet */ - initialize_ethernet(); + if (size - 1 > max_nodeid_length) + strcpy(&prompt[max_nodeid_length - 3], "..."); + + strcat(prompt, ">"); - /*--- Initialize Console ---*/ - esp_console_repl_t *repl = NULL; esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); #if CONFIG_SNIFFER_STORE_HISTORY repl_config.history_save_path = HISTORY_FILE_PATH; #endif - repl_config.prompt = "cli>"; + repl_config.prompt = prompt; // install console REPL environment #if CONFIG_ESP_CONSOLE_UART @@ -92,15 +83,62 @@ void app_main(void) esp_console_dev_usb_serial_jtag_config_t usbjtag_config = ESP_CONSOLE_DEV_USB_SERIAL_JTAG_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl)); #endif +} + +int cmd_reboot(int argc, char **argv) +{ + (void)argc; + (void)argv; + + esp_restart(); + + return 1; +} + +void register_reboot(void) +{ + const esp_console_cmd_t cmd = { + .command = "reboot", + .help = "reboot the device", + .hint = NULL, + .func = &cmd_reboot, + }; + ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); +} + +void app_main(void) +{ + config_init(); + + initialize_filesystem(); + + initialize_spi(); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // Make sure MQTT has registered its event handlers before Ethernet goes up + mqtt_init(); + + /*--- Initialize Network ---*/ + /* Initialize WiFi */ + initialize_wifi(); + /* Initialize Ethernet */ + initialize_ethernet(); + + /*--- Initialize Console ---*/ + console_init(); /* Register commands */ #if CONFIG_ENABLE_SD - register_mount(); - register_unmount(); + sdcard_register_commands(); #endif register_sniffer_cmd(); register_pcap_cmd(); + config_register_commands(); + + register_reboot(); + // start console REPL ESP_ERROR_CHECK(esp_console_start_repl(repl)); } diff --git a/main/mqtt.c b/main/mqtt.c new file mode 100644 index 0000000..e84fc54 --- /dev/null +++ b/main/mqtt.c @@ -0,0 +1,172 @@ +#include "sdkconfig.h" + +#include "esp_log.h" +#include "mqtt_client.h" + +#include "cmd_sniffer.h" +#include "config.h" +#include "events.h" + +#include "mqtt.h" + +static const char TAG[] = "MQTT"; + +static esp_mqtt_client_handle_t client; + +static char topic_prefix[96]; +static char command_topic[128]; +static char packet_topic[128]; + +static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { + ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); + + esp_mqtt_event_handle_t event = event_data; + esp_mqtt_client_handle_t client = event->client; + int msg_id; + // your_context_t *context = event->context; + switch (event->event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_subscribe(client, command_topic, 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err); + ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err); + ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno, + strerror(event->error_handle->esp_transport_sock_errno)); + } else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) { + ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code); + } else { + ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type); + } + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } +} + +static int make_topic_prefix() +{ + size_t size = sizeof(topic_prefix); + strcpy(topic_prefix, "its/"); + size -= 4; + + esp_err_t res = config_get_str(CONFIG_INDEX_NODEID, topic_prefix + 4, &size); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Could not get node ID from config: %s", esp_err_to_name(res)); + return res; + } + + topic_prefix[4 + size - 1] = '/'; + topic_prefix[4 + size] = '\0'; + + return ESP_OK; +} + +void mqtt_start(void) +{ + if (client) + { + ESP_LOGW(TAG, "MQTT already started"); + return; + } + + make_topic_prefix(); + + strcpy(command_topic, topic_prefix); + strcat(command_topic, "command"); + + strcpy(packet_topic, topic_prefix); + strcat(packet_topic, "packet"); + + esp_mqtt_client_config_t mqtt_cfg = {0}; + + char mqtt_uri[CONFIG_MQTT_URI_BUFFER_SIZE]; + size_t size = sizeof(mqtt_uri); + esp_err_t res = config_get_str(CONFIG_INDEX_MQTT_URI, mqtt_uri, &size); + if (res != ESP_OK) + { + ESP_LOGE(TAG, "Could not get MQTT URI from config: %s", esp_err_to_name(res)); + return; + } + + mqtt_cfg.broker.address.uri = mqtt_uri; + + esp_mqtt_client_handle_t client_ = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_register_event(client_, ESP_EVENT_ANY_ID, mqtt_event_handler, client_); + esp_mqtt_client_start(client_); + + client = client_; + ESP_LOGI(TAG, "MQTT started"); +} + +void mqtt_stop(void) +{ + if (!client) + { + ESP_LOGW(TAG, "Attempted to stop MQTT while not running"); + return; + } + + esp_mqtt_client_stop(client); + + esp_mqtt_client_handle_t client_ = client; + client = NULL; + esp_mqtt_client_destroy(client_); + ESP_LOGI(TAG, "MQTT stopped"); +} + +static void app_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + switch (event_id) + { + case APP_ETHERNET_MGMT_INTERFACE_CONNECTED: + mqtt_start(); + break; + case APP_ETHERNET_MGMT_INTERFACE_DISCONNECTED: + mqtt_stop(); + break; + } +} + +static void sniffer_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) +{ + if (!client) + return; + + switch (event_id) + { + case SNIFFER_GOT_FRAME: + sniffer_combined_info_t *info = event_data; + esp_mqtt_client_publish(client, packet_topic, (const char *)info->payload, info->info.length, 0, 0); + } +} + +void mqtt_init(void) +{ + esp_event_handler_register(APP_EVENT_BASE, ESP_EVENT_ANY_ID, app_event_handler, NULL); + esp_event_handler_register(SNIFFER_EVENT_BASE, ESP_EVENT_ANY_ID, sniffer_event_handler, NULL); +} diff --git a/main/mqtt.h b/main/mqtt.h new file mode 100644 index 0000000..d7c0296 --- /dev/null +++ b/main/mqtt.h @@ -0,0 +1,3 @@ +#pragma once + +void mqtt_init(void); diff --git a/main/sdcard.c b/main/sdcard.c index 538d583..88c3d1c 100644 --- a/main/sdcard.c +++ b/main/sdcard.c @@ -139,4 +139,11 @@ void register_unmount(void) }; ESP_ERROR_CHECK(esp_console_cmd_register(&cmd)); } + +void sdcard_register_commands(void) +{ + register_mount(); + register_unmount(); +} + #endif // CONFIG_ENABLE_SD diff --git a/main/sdcard.h b/main/sdcard.h index 4ce596a..ee0542a 100644 --- a/main/sdcard.h +++ b/main/sdcard.h @@ -1,4 +1,3 @@ #pragma once -void register_mount(void); -void register_unmount(void); +void sdcard_register_commands(void); diff --git a/sdkconfig b/sdkconfig index 35b3f67..beb8381 100644 --- a/sdkconfig +++ b/sdkconfig @@ -2404,7 +2404,9 @@ CONFIG_ESP_TIMER_IMPL_SYSTIMER=y # # ESP Trace Configuration # +# default: # CONFIG_ESP_TRACE_LIB_EXTERNAL is not set +# default: CONFIG_ESP_TRACE_LIB_NONE=y # default: CONFIG_ESP_TRACE_LIB_NAME="none" @@ -3986,6 +3988,33 @@ CONFIG_WL_SECTOR_SIZE_4096=y # default: CONFIG_WL_SECTOR_SIZE=4096 # end of Wear Levelling + +# +# ESP-MQTT Configurations +# +# default: +CONFIG_MQTT_PROTOCOL_311=y +# default: +# CONFIG_MQTT_PROTOCOL_5 is not set +# default: +CONFIG_MQTT_TRANSPORT_SSL=y +# default: +CONFIG_MQTT_TRANSPORT_WEBSOCKET=y +# default: +CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y +# default: +# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set +# default: +# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set +# default: +# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set +# default: +# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set +# default: +# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set +# default: +# CONFIG_MQTT_CUSTOM_OUTBOX is not set +# end of ESP-MQTT Configurations # end of Component config # default: