diff --git a/.gitignore b/.gitignore index 01d2b74c..b72c8b24 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,7 @@ hardware/minino-backups/ /**/.DS_Store # Firmware binaries -/**/build/ +/**/build/* /**/managed_components/ /**/build_files/ /**/build_files.tgz diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt index dd8ea68b..2339b367 100644 --- a/firmware/CMakeLists.txt +++ b/firmware/CMakeLists.txt @@ -6,6 +6,7 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS components/oled_driver) set(EXTRA_COMPONENT_DIRS components/wifi_sniffer) +set(EXTRA_COMPONENT_DIRS components/ble_hid) set(EXTRA_COMPONENT_DIRS components/buzzer) set(EXTRA_COMPONENT_DIRS components/files_ops) set(EXTRA_COMPONENT_DIRS components/flash_fs) diff --git a/firmware/README.md b/firmware/README.md index 7a003e62..ace5a8fd 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -136,208 +136,28 @@ chmod +x get_build.sh The build files will be in the `build_files.zip` file. Now you can create a release on GitHub and attach the `build_files.zip` file. -## Development process -### Add a new menu +# Flashing release +## OTA +### Table for [ESP Tool](https://espressif.github.io/esptool-js/) +| Flash Address | File | +|---------------|----------------------| +| 0x0 | bootloader.bin | +| 0x8000 | partition-table.bin | +| 0x15000 | ota_data_initial.bin | +| 0xa0000 | minino.bin | -#### Menus structure +### Command -Menus are defined in `screen_module_menu_t` in the `screens_module.h` file. Most of them have a tree structure, you can go from one menu to another, and go back. For example in the `MENU_MAIN` menu, you can go to `MENU_APPLICATIONS`, `MENU_SETTINGS`, or `MENU_ABOUT` and go back to `MENU_MAIN`. - -```mermaid -graph TD - A[MENU_MAIN] --> B[MENU_APPLICATIONS] - A --> C[MENU_SETTINGS] - A --> D[MENU_ABOUT] - B --> A - C --> A - D --> A -``` - -**Menus can only have two possible actions: go to another menu or go back.** - -Let's say you want to add a new menu called `MENU_GPS_WARDRIVING` that will be a child of `MENU_GPS` wich is a child of `MENU_APPLICATIONS`. - -```mermaid -graph TD - A[MENU_MAIN] --> B[MENU_APPLICATIONS] - B --> C[MENU_GPS] - C --> D[MENU_GPS_WARDRIVING] - D --> C - B --> A - C --> B -``` - -#### Steps to add a new menu - -1. The first step is to add an enum value in `screen_module_menu_t`, it can be anywhere, but it's recommended to place it near to it's parent to make it easier to find. In this case, we will add it after `MENU_GPS`. - -```c -/** - * @brief Enum of menus - * - * Used to navigate through the different menus - * - * Modify this menu also requires to modify the `menu_list`, `next_menu_table`, - * `prev_menu_table` and `menu_items` arrays - */ -typedef enum { - MENU_MAIN = 0, - MENU_APPLICATIONS, - MENU_SETTINGS, - MENU_ABOUT, - /* Applications */ - ... - MENU_GPS, - /* GPS applications */ - MENU_GPS_WARDRIVING, - MENU_GPS_DATE_TIME, - MENU_GPS_LOCATION, - MENU_GPS_SPEED, - MENU_GPS_HELP, - ... - /* Menu count */ - MENU_COUNT, -} screen_module_menu_t; -``` - -> **Note:** The `MENU_COUNT` is used to get the number of menus, it's important to keep it at the end of the enum because it's used to do some runtime checks. - -2. Add `MENU_GPS_WARDRIVING` as a string in `menu_list`, this is to debug purposes. - -```c -/** - * @brief List of menus - * - * Used to get the menu name from the enum value - * following the order of the `screen_module_menu_t` enum - * - * Usage: menu_list[screen_module_menu_t] - */ -const char* menu_list[] = { - "MENU_MAIN", - "MENU_APPLICATIONS", - "MENU_SETTINGS", - "MENU_ABOUT", - ... - "MENU_GPS", - ... - "MENU_GPS_WARDRIVING", // Add this line - "MENU_GPS_DATE_TIME", - "MENU_GPS_LOCATION", - "MENU_GPS_SPEED", - "MENU_GPS_HELP", - ... -}; -``` - -3. Add the option to the gps items array. - -```c -char* gps_items[] = { - "Wardrive", // Add this line - "Date & Time", - "Location", - "Speed", - "Help", - NULL, -}; -``` - -> **Note:** The `NULL` at the end is to indicate the end of the array. It's important to add it, otherwise, the program will have undefined behavior. - -4. Define the next menus of `MENU_GPS`, to go to `MENU_GPS_WARDRIVING` in the `screen_module_menu_t` array. We decided to place it as the first child of `MENU_GPS`, this **must** be consistent with the order of `gps_items`. - -```c -/** - * @brief List of menus - * - * Used to get the next menu to display when the user selects an option - * following the order of the `screen_module_menu_t` enum - * - * Usage: next_menu_table[screen_module_menu_t][selected_item] - */ -const int next_menu_table[][MAX_NUM_ITEMS] = { - // MENU_MAIN - {MENU_APPLICATIONS, MENU_SETTINGS, MENU_ABOUT}, - ... - // MENU_GPS - {MENU_GPS_WARDRIVING, MENU_GPS_DATE_TIME, MENU_GPS_LOCATION, MENU_GPS_SPEED, - MENU_GPS_HELP}, - ... -}; -``` - -In this case, the comments `// MENU_MAIN` and `// MENU_GPS` represent the parent menu, they *must* be in the same order as the `screen_module_menu_t` enum. The `next_menu_table` is a 2D array where the first index is the parent menu and the second index is the child menu. The order of the child menus must be the same as the order of the items in the `menu_items` array. - -5. Define the next menu of `MENU_GPS_WARDRIVING`. In this case, it's an application that doesn't have any child menus, so pressing the select button should do nothing. - -```c -const int next_menu_table[][MAX_NUM_ITEMS] = { - ... - // MENU_GPS_WARDRIVING - {MENU_GPS_WARDRIVING}, // Add it as itself does nothing - ... -}; -``` - -6. Define the previous menu of `MENU_GPS_WARDRIVING` in the `prev_menu_table` array. - -```c -/** - * @brief List of menus - * - * Used to get the previous menu to display when the user returns to the - * previous menu in `menu_screens_exit_submenu`. Add the previous menu - * following the order of the `screen_module_menu_t` enum - * - * Usage: prev_menu_table[screen_module_menu_t] - */ -const int prev_menu_table[] = { - // PREVIOUS_MENU, // CURRENT_MENU - /*****************************************************************/ - MENU_MAIN, // MENU_MAIN - MENU_MAIN, // MENU_APPLICATIONS - MENU_MAIN, // MENU_SETTINGS - MENU_MAIN, // MENU_ABOUT - ... - MENU_GPS, // MENU_GPS_WARDRIVING --> Add this line - MENU_GPS, // MENU_GPS_DATE_TIME - MENU_GPS, // MENU_GPS_LOCATION - MENU_GPS, // MENU_GPS_SPEED - MENU_GPS, // MENU_GPS_HELP - ... -}; -``` - -Again, the comments represent the parent menu, and they *must* be in the same order as the `screen_module_menu_t` enum. The `prev_menu_table` is a 1D array where the index is the child menu and the value is the parent menu. - -7. Add the menu items to the `menu_items` array. For now, we will add an empty array, but you can add the items you want to display in the menu. - -```c -/** - * @brief List of menu items - * - * Used to get the menu items from the menu enum value - * following the order of the `screen_module_menu_t` enum - * - * Usage: menu_items[screen_module_menu_t] - */ -char** menu_items[] = { - main_items, // MENU_MAIN - applications_items, // MENU_APPLICATIONS - settings_items, // MENU_SETTINGS - about_items, // MENU_ABOUT - ... - gps_items, // MENU_GPS - ... - empty_items, // MENU_GPS_WARDRIVING - gps_date_time_items, // MENU_GPS_DATE_TIME - gps_location_items, // MENU_GPS_LOCATION - gps_speed_items, // MENU_GPS_SPEED - gps_help, // MENU_GPS_HELP - ... -}; -``` - -And that's it! You should be able to navigate to the new menu. Test it and review this guide again in case you missed something. \ No newline at end of file +```bash + python -m esptool --chip esp32c6 -b 460800 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 8MB --flash_freq 80m 0x0 bootloader.bin 0x8000 partition-table.bin 0x15000 ota_data_initial.bin 0xa0000 minino.bin +``` +## NO OTA +| Flash Address | File | +|---------------|----------------------| +| 0x0 | bootloader.bin | +| 0x8000 | partition-table.bin | +| 0x20000 | minino.bin | +```bash + python -m esptool --chip esp32c6 -b 460800 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 8MB --flash_freq 80m 0x0 bootloader.bin 0x8000 partition-table.bin 0x20000 minino.bin +``` \ No newline at end of file diff --git a/firmware/components/ble_hid/CMakeLists.txt b/firmware/components/ble_hid/CMakeLists.txt new file mode 100644 index 00000000..c23075ef --- /dev/null +++ b/firmware/components/ble_hid/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register(SRCS "ble_hidd_main.c" + "esp_hidd_prf_api.c" + "hid_dev.c" + "hid_device_le_prf.c" + INCLUDE_DIRS "." + PRIV_REQUIRES bt nvs_flash esp_driver_gpio) + target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable) \ No newline at end of file diff --git a/firmware/components/ble_hid/ble_hidd_main.c b/firmware/components/ble_hid/ble_hidd_main.c new file mode 100644 index 00000000..accf4900 --- /dev/null +++ b/firmware/components/ble_hid/ble_hidd_main.c @@ -0,0 +1,300 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include "ble_hidd_main.h" +#include +#include +#include +#include "esp_bt.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "freertos/task.h" +#include "nvs_flash.h" + +#include "driver/gpio.h" +#include "esp_bt_defs.h" +#include "esp_bt_device.h" +#include "esp_bt_main.h" +#include "esp_gap_ble_api.h" +#include "esp_gatt_defs.h" +#include "esp_gatts_api.h" +#include "esp_hidd_prf_api.h" +#include "hid_dev.h" + +/** + * Brief: + * This example Implemented BLE HID device profile related functions, in which + * the HID device has 4 Reports (1 is mouse, 2 is keyboard and LED, 3 is + * Consumer Devices, 4 is Vendor devices). Users can choose different reports + * according to their own application scenarios. BLE HID profile inheritance and + * USB HID class. + */ + +/** + * Note: + * 1. Win10 does not support vendor report , So SUPPORT_REPORT_VENDOR is always + * set to FALSE, it defines in hidd_le_prf_int.h + * 2. Update connection parameters are not allowed during iPhone HID encryption, + * slave turns off the ability to automatically update connection parameters + * during encryption. + * 3. After our HID device is connected, the iPhones write 1 to the Report + * Characteristic Configuration Descriptor, even if the HID encryption is not + * completed. This should actually be written 1 after the HID encryption is + * completed. we modify the permissions of the Report Characteristic + * Configuration Descriptor to `ESP_GATT_PERM_READ | + * ESP_GATT_PERM_WRITE_ENCRYPTED`. if you got `GATT_INSUF_ENCRYPTION` error, + * please ignore. + */ + +#define HID_DEMO_TAG "HID_DEMO" +#define CHAR_DECLARATION_SIZE (sizeof(uint8_t)) + +static uint16_t hid_conn_id = 0; +static bool sec_conn = false; +static hid_event_callback_f hid_event_callback = NULL; + +static void hidd_event_callback(esp_hidd_cb_event_t event, + esp_hidd_cb_param_t* param); + +static char* HIDD_DEVICE_NAME = "MININO_HID"; +static uint8_t hidd_service_uuid128[] = { + /* LSB + <--------------------------------------------------------------------------------> + MSB */ + // first uuid, 16bit, [12],[13] is the value + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x12, 0x18, 0x00, 0x00, +}; + +static esp_ble_adv_data_t hidd_adv_data = { + .set_scan_rsp = false, + .include_name = true, + .include_txpower = true, + .min_interval = 0x0006, // slave connection min interval, Time = + // min_interval * 1.25 msec + .max_interval = 0x0010, // slave connection max interval, Time = + // max_interval * 1.25 msec + .appearance = 0x03c0, // HID Generic, + .manufacturer_len = 0, + .p_manufacturer_data = NULL, + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = sizeof(hidd_service_uuid128), + .p_service_uuid = hidd_service_uuid128, + .flag = 0x6, +}; + +static esp_ble_adv_params_t hidd_adv_params = { + .adv_int_min = 0x20, + .adv_int_max = 0x30, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + //.peer_addr = + //.peer_addr_type = + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +static void hidd_event_callback(esp_hidd_cb_event_t event, + esp_hidd_cb_param_t* param) { + switch (event) { + case ESP_HIDD_EVENT_REG_FINISH: { + if (param->init_finish.state == ESP_HIDD_INIT_OK) { + // esp_bd_addr_t rand_addr = {0x04,0x11,0x11,0x11,0x11,0x05}; + esp_ble_gap_set_device_name(HIDD_DEVICE_NAME); + esp_ble_gap_config_adv_data(&hidd_adv_data); + } + break; + } + case ESP_BAT_EVENT_REG: { + break; + } + case ESP_HIDD_EVENT_DEINIT_FINISH: + break; + case ESP_HIDD_EVENT_BLE_CONNECT: { + ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_CONNECT"); + hid_conn_id = param->connect.conn_id; + if (hid_event_callback != NULL) { + hid_event_callback(true); + } + break; + } + case ESP_HIDD_EVENT_BLE_DISCONNECT: { + sec_conn = false; + ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_DISCONNECT"); + esp_ble_gap_start_advertising(&hidd_adv_params); + if (hid_event_callback != NULL) { + hid_event_callback(false); + } + break; + } + case ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT: { + ESP_LOGI(HID_DEMO_TAG, "%s, ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT", + __func__); + ESP_LOG_BUFFER_HEX(HID_DEMO_TAG, param->vendor_write.data, + param->vendor_write.length); + break; + } + case ESP_HIDD_EVENT_BLE_LED_REPORT_WRITE_EVT: { + ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_LED_REPORT_WRITE_EVT"); + ESP_LOG_BUFFER_HEX(HID_DEMO_TAG, param->led_write.data, + param->led_write.length); + break; + } + default: + break; + } + return; +} + +static void gap_event_handler(esp_gap_ble_cb_event_t event, + esp_ble_gap_cb_param_t* param) { + switch (event) { + case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: + esp_ble_gap_start_advertising(&hidd_adv_params); + break; + case ESP_GAP_BLE_SEC_REQ_EVT: + for (int i = 0; i < ESP_BD_ADDR_LEN; i++) { + ESP_LOGD(HID_DEMO_TAG, "%x:", param->ble_security.ble_req.bd_addr[i]); + } + esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); + break; + case ESP_GAP_BLE_AUTH_CMPL_EVT: + sec_conn = true; + esp_bd_addr_t bd_addr; + memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, + sizeof(esp_bd_addr_t)); + ESP_LOGI(HID_DEMO_TAG, "remote BD_ADDR: %08x%04x", + (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + + bd_addr[3], + (bd_addr[4] << 8) + bd_addr[5]); + ESP_LOGI(HID_DEMO_TAG, "address type = %d", + param->ble_security.auth_cmpl.addr_type); + ESP_LOGI(HID_DEMO_TAG, "pair status = %s", + param->ble_security.auth_cmpl.success ? "success" : "fail"); + if (!param->ble_security.auth_cmpl.success) { + ESP_LOGE(HID_DEMO_TAG, "fail reason = 0x%x", + param->ble_security.auth_cmpl.fail_reason); + } + break; + default: + break; + } +} + +void ble_hid_volume_up(bool press) { + if (sec_conn) { + esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_UP, press); + } +} + +void ble_hid_volume_down(bool press) { + if (sec_conn) { + esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_VOLUME_DOWN, press); + } +} + +void ble_hid_play(bool press) { + if (sec_conn) { + esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_PLAY, press); + } +} + +void ble_hid_pause(bool press) { + if (sec_conn) { + esp_hidd_send_consumer_value(hid_conn_id, HID_CONSUMER_PAUSE, press); + } +} + +void ble_hid_register_callback(hid_event_callback_f callback) { + hid_event_callback = callback; +} + +void ble_hid_get_device_name(char* device_name) { + strcpy(device_name, HIDD_DEVICE_NAME); +} + +void ble_hid_get_device_mac(uint8_t* mac) { + esp_read_mac(mac, ESP_MAC_BT); +} + +void ble_hid_begin() { + esp_err_t ret; + + // Initialize NVS. + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || + ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); + + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(HID_DEMO_TAG, "%s initialize controller failed", __func__); + return; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(HID_DEMO_TAG, "%s enable controller failed", __func__); + return; + } + + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(HID_DEMO_TAG, "%s init bluedroid failed", __func__); + return; + } + + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(HID_DEMO_TAG, "%s init bluedroid failed", __func__); + return; + } + + if ((ret = esp_hidd_profile_init()) != ESP_OK) { + ESP_LOGE(HID_DEMO_TAG, "%s init bluedroid failed", __func__); + } + + /// register the callback function to the gap module + esp_ble_gap_register_callback(gap_event_handler); + esp_hidd_register_callbacks(hidd_event_callback); + + /* set the security iocap & auth_req & key size & init key response key + * parameters to the stack*/ + esp_ble_auth_req_t auth_req = + ESP_LE_AUTH_BOND; // bonding with peer device after authentication + esp_ble_io_cap_t iocap = + ESP_IO_CAP_NONE; // set the IO capability to No output No input + uint8_t key_size = 16; // the key size should be 7~16 bytes + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, + sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, + sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, + sizeof(uint8_t)); + /* If your BLE device act as a Slave, the init_key means you hope which types + of key of the master should distribute to you, and the response key means + which key you can distribute to the Master; If your BLE device act as a + master, the response key means you hope which types of key of the slave should + distribute to you, and the init key means which key you can distribute to the + slave. */ + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, + sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, + sizeof(uint8_t)); +} diff --git a/firmware/components/ble_hid/ble_hidd_main.h b/firmware/components/ble_hid/ble_hidd_main.h new file mode 100644 index 00000000..683c538f --- /dev/null +++ b/firmware/components/ble_hid/ble_hidd_main.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +typedef void (*hid_event_callback_f)(bool connection); + +void ble_hid_begin(); +void ble_hid_volume_down(bool press); +void ble_hid_volume_up(bool press); +void ble_hid_play(bool press); +void ble_hid_pause(bool press); +void ble_hid_get_device_name(char* device_name); +void ble_hid_get_device_mac(uint8_t* mac); +void ble_hid_register_callback(hid_event_callback_f callback); \ No newline at end of file diff --git a/firmware/components/ble_hid/esp_hidd_prf_api.c b/firmware/components/ble_hid/esp_hidd_prf_api.c new file mode 100644 index 00000000..73f6a63c --- /dev/null +++ b/firmware/components/ble_hid/esp_hidd_prf_api.c @@ -0,0 +1,139 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "esp_hidd_prf_api.h" +#include +#include +#include "esp_log.h" +#include "hid_dev.h" +#include "hidd_le_prf_int.h" + +// HID keyboard input report length +#define HID_KEYBOARD_IN_RPT_LEN 8 + +// HID LED output report length +#define HID_LED_OUT_RPT_LEN 1 + +// HID mouse input report length +#define HID_MOUSE_IN_RPT_LEN 5 + +// HID consumer control input report length +#define HID_CC_IN_RPT_LEN 2 + +esp_err_t esp_hidd_register_callbacks(esp_hidd_event_cb_t callbacks) { + esp_err_t hidd_status; + + if (callbacks != NULL) { + hidd_le_env.hidd_cb = callbacks; + } else { + return ESP_FAIL; + } + + if ((hidd_status = hidd_register_cb()) != ESP_OK) { + return hidd_status; + } + + esp_ble_gatts_app_register(BATTRAY_APP_ID); + + if ((hidd_status = esp_ble_gatts_app_register(HIDD_APP_ID)) != ESP_OK) { + return hidd_status; + } + + return hidd_status; +} + +esp_err_t esp_hidd_profile_init(void) { + if (hidd_le_env.enabled) { + ESP_LOGE(HID_LE_PRF_TAG, "HID device profile already initialized"); + return ESP_FAIL; + } + // Reset the hid device target environment + memset(&hidd_le_env, 0, sizeof(hidd_le_env_t)); + hidd_le_env.enabled = true; + return ESP_OK; +} + +esp_err_t esp_hidd_profile_deinit(void) { + uint16_t hidd_svc_hdl = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]; + if (!hidd_le_env.enabled) { + ESP_LOGE(HID_LE_PRF_TAG, "HID device profile already initialized"); + return ESP_OK; + } + + if (hidd_svc_hdl != 0) { + esp_ble_gatts_stop_service(hidd_svc_hdl); + esp_ble_gatts_delete_service(hidd_svc_hdl); + } else { + return ESP_FAIL; + } + + /* register the HID device profile to the BTA_GATTS module*/ + esp_ble_gatts_app_unregister(hidd_le_env.gatt_if); + + return ESP_OK; +} + +uint16_t esp_hidd_get_version(void) { + return HIDD_VERSION; +} + +void esp_hidd_send_consumer_value(uint16_t conn_id, + uint8_t key_cmd, + bool key_pressed) { + uint8_t buffer[HID_CC_IN_RPT_LEN] = {0, 0}; + if (key_pressed) { + ESP_LOGD(HID_LE_PRF_TAG, "hid_consumer_build_report"); + hid_consumer_build_report(buffer, key_cmd); + } + ESP_LOGD(HID_LE_PRF_TAG, "buffer[0] = %x, buffer[1] = %x", buffer[0], + buffer[1]); + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, HID_RPT_ID_CC_IN, + HID_REPORT_TYPE_INPUT, HID_CC_IN_RPT_LEN, buffer); + return; +} + +void esp_hidd_send_keyboard_value(uint16_t conn_id, + key_mask_t special_key_mask, + uint8_t* keyboard_cmd, + uint8_t num_key) { + if (num_key > HID_KEYBOARD_IN_RPT_LEN - 2) { + ESP_LOGE(HID_LE_PRF_TAG, "%s(), the number key should not be more than %d", + __func__, HID_KEYBOARD_IN_RPT_LEN); + return; + } + + uint8_t buffer[HID_KEYBOARD_IN_RPT_LEN] = {0}; + + buffer[0] = special_key_mask; + + for (int i = 0; i < num_key; i++) { + buffer[i + 2] = keyboard_cmd[i]; + } + + ESP_LOGD(HID_LE_PRF_TAG, "the key vaule = %d,%d,%d, %d, %d, %d,%d, %d", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], + buffer[6], buffer[7]); + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, HID_RPT_ID_KEY_IN, + HID_REPORT_TYPE_INPUT, HID_KEYBOARD_IN_RPT_LEN, buffer); + return; +} + +void esp_hidd_send_mouse_value(uint16_t conn_id, + uint8_t mouse_button, + int8_t mickeys_x, + int8_t mickeys_y) { + uint8_t buffer[HID_MOUSE_IN_RPT_LEN]; + + buffer[0] = mouse_button; // Buttons + buffer[1] = mickeys_x; // X + buffer[2] = mickeys_y; // Y + buffer[3] = 0; // Wheel + buffer[4] = 0; // AC Pan + + hid_dev_send_report(hidd_le_env.gatt_if, conn_id, HID_RPT_ID_MOUSE_IN, + HID_REPORT_TYPE_INPUT, HID_MOUSE_IN_RPT_LEN, buffer); + return; +} diff --git a/firmware/components/ble_hid/esp_hidd_prf_api.h b/firmware/components/ble_hid/esp_hidd_prf_api.h new file mode 100644 index 00000000..24af0b4e --- /dev/null +++ b/firmware/components/ble_hid/esp_hidd_prf_api.h @@ -0,0 +1,177 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef __ESP_HIDD_API_H__ +#define __ESP_HIDD_API_H__ + +#include "esp_bt_defs.h" +#include "esp_err.h" +#include "esp_gatt_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ESP_HIDD_EVENT_REG_FINISH = 0, + ESP_BAT_EVENT_REG, + ESP_HIDD_EVENT_DEINIT_FINISH, + ESP_HIDD_EVENT_BLE_CONNECT, + ESP_HIDD_EVENT_BLE_DISCONNECT, + ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, + ESP_HIDD_EVENT_BLE_LED_REPORT_WRITE_EVT, +} esp_hidd_cb_event_t; + +/// HID config status +typedef enum { + ESP_HIDD_STA_CONN_SUCCESS = 0x00, + ESP_HIDD_STA_CONN_FAIL = 0x01, +} esp_hidd_sta_conn_state_t; + +/// HID init status +typedef enum { + ESP_HIDD_INIT_OK = 0, + ESP_HIDD_INIT_FAILED = 1, +} esp_hidd_init_state_t; + +/// HID deinit status +typedef enum { + ESP_HIDD_DEINIT_OK = 0, + ESP_HIDD_DEINIT_FAILED = 0, +} esp_hidd_deinit_state_t; + +#define LEFT_CONTROL_KEY_MASK (1 << 0) +#define LEFT_SHIFT_KEY_MASK (1 << 1) +#define LEFT_ALT_KEY_MASK (1 << 2) +#define LEFT_GUI_KEY_MASK (1 << 3) +#define RIGHT_CONTROL_KEY_MASK (1 << 4) +#define RIGHT_SHIFT_KEY_MASK (1 << 5) +#define RIGHT_ALT_KEY_MASK (1 << 6) +#define RIGHT_GUI_KEY_MASK (1 << 7) + +typedef uint8_t key_mask_t; +/** + * @brief HIDD callback parameters union + */ +typedef union { + /** + * @brief ESP_HIDD_EVENT_INIT_FINISH + */ + struct hidd_init_finish_evt_param { + esp_hidd_init_state_t state; /*!< Initial status */ + esp_gatt_if_t gatts_if; + } init_finish; /*!< HID callback param of ESP_HIDD_EVENT_INIT_FINISH */ + + /** + * @brief ESP_HIDD_EVENT_DEINIT_FINISH + */ + struct hidd_deinit_finish_evt_param { + esp_hidd_deinit_state_t state; /*!< De-initial status */ + } deinit_finish; /*!< HID callback param of ESP_HIDD_EVENT_DEINIT_FINISH */ + + /** + * @brief ESP_HIDD_EVENT_CONNECT + */ + struct hidd_connect_evt_param { + uint16_t conn_id; + esp_bd_addr_t remote_bda; /*!< HID Remote bluetooth connection index */ + } connect; /*!< HID callback param of ESP_HIDD_EVENT_CONNECT */ + + /** + * @brief ESP_HIDD_EVENT_DISCONNECT + */ + struct hidd_disconnect_evt_param { + esp_bd_addr_t remote_bda; /*!< HID Remote bluetooth device address */ + } disconnect; /*!< HID callback param of ESP_HIDD_EVENT_DISCONNECT */ + + /** + * @brief ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT + */ + struct hidd_vendor_write_evt_param { + uint16_t conn_id; /*!< HID connection index */ + uint16_t report_id; /*!< HID report index */ + uint16_t length; /*!< data length */ + uint8_t* data; /*!< The pointer to the data */ + } vendor_write; /*!< HID callback param of + ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT */ + + /** + * @brief ESP_HIDD_EVENT_BLE_LED_REPORT_WRITE_EVT + */ + struct hidd_led_write_evt_param { + uint16_t conn_id; + uint8_t report_id; + uint8_t length; + uint8_t* data; + } led_write; +} esp_hidd_cb_param_t; + +/** + * @brief HID device event callback function type + * @param event : Event type + * @param param : Point to callback parameter, currently is union type + */ +typedef void (*esp_hidd_event_cb_t)(esp_hidd_cb_event_t event, + esp_hidd_cb_param_t* param); + +/** + * + * @brief This function is called to receive hid device callback event + * + * @param[in] callbacks: callback functions + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_register_callbacks(esp_hidd_event_cb_t callbacks); + +/** + * + * @brief This function is called to initialize hid device profile + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_profile_init(void); + +/** + * + * @brief This function is called to de-initialize hid device profile + * + * @return ESP_OK - success, other - failed + * + */ +esp_err_t esp_hidd_profile_deinit(void); + +/** + * + * @brief Get hidd profile version + * + * @return Most 8bit significant is Great version, Least 8bit is Sub + * version + * + */ +uint16_t esp_hidd_get_version(void); + +void esp_hidd_send_consumer_value(uint16_t conn_id, + uint8_t key_cmd, + bool key_pressed); + +void esp_hidd_send_keyboard_value(uint16_t conn_id, + key_mask_t special_key_mask, + uint8_t* keyboard_cmd, + uint8_t num_key); + +void esp_hidd_send_mouse_value(uint16_t conn_id, + uint8_t mouse_button, + int8_t mickeys_x, + int8_t mickeys_y); + +#ifdef __cplusplus +} +#endif + +#endif /* __ESP_HIDD_API_H__ */ diff --git a/firmware/components/ble_hid/hid_dev.c b/firmware/components/ble_hid/hid_dev.c new file mode 100644 index 00000000..8ba0b218 --- /dev/null +++ b/firmware/components/ble_hid/hid_dev.c @@ -0,0 +1,132 @@ +/* + * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "hid_dev.h" +#include +#include +#include +#include +#include "esp_log.h" + +static hid_report_map_t* hid_dev_rpt_tbl; +static uint8_t hid_dev_rpt_tbl_Len; + +static hid_report_map_t* hid_dev_rpt_by_id(uint8_t id, uint8_t type) { + hid_report_map_t* rpt = hid_dev_rpt_tbl; + + for (uint8_t i = hid_dev_rpt_tbl_Len; i > 0; i--, rpt++) { + if (rpt->id == id && rpt->type == type && rpt->mode == hidProtocolMode) { + return rpt; + } + } + + return NULL; +} + +void hid_dev_register_reports(uint8_t num_reports, hid_report_map_t* p_report) { + hid_dev_rpt_tbl = p_report; + hid_dev_rpt_tbl_Len = num_reports; + return; +} + +void hid_dev_send_report(esp_gatt_if_t gatts_if, + uint16_t conn_id, + uint8_t id, + uint8_t type, + uint8_t length, + uint8_t* data) { + hid_report_map_t* p_rpt; + + // get att handle for report + if ((p_rpt = hid_dev_rpt_by_id(id, type)) != NULL) { + // if notifications are enabled + ESP_LOGD(HID_LE_PRF_TAG, "%s(), send the report, handle = %d", __func__, + p_rpt->handle); + esp_ble_gatts_send_indicate(gatts_if, conn_id, p_rpt->handle, length, data, + false); + } + + return; +} + +void hid_consumer_build_report(uint8_t* buffer, consumer_cmd_t cmd) { + if (!buffer) { + ESP_LOGE(HID_LE_PRF_TAG, + "%s(), the buffer is NULL, hid build report failed.", __func__); + return; + } + + switch (cmd) { + case HID_CONSUMER_CHANNEL_UP: + HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_UP); + break; + + case HID_CONSUMER_CHANNEL_DOWN: + HID_CC_RPT_SET_CHANNEL(buffer, HID_CC_RPT_CHANNEL_DOWN); + break; + + case HID_CONSUMER_VOLUME_UP: + HID_CC_RPT_SET_VOLUME_UP(buffer); + break; + + case HID_CONSUMER_VOLUME_DOWN: + HID_CC_RPT_SET_VOLUME_DOWN(buffer); + break; + + case HID_CONSUMER_MUTE: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_MUTE); + break; + + case HID_CONSUMER_POWER: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_POWER); + break; + + case HID_CONSUMER_RECALL_LAST: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_LAST); + break; + + case HID_CONSUMER_ASSIGN_SEL: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_ASSIGN_SEL); + break; + + case HID_CONSUMER_PLAY: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PLAY); + break; + + case HID_CONSUMER_PAUSE: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_PAUSE); + break; + + case HID_CONSUMER_RECORD: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_RECORD); + break; + + case HID_CONSUMER_FAST_FORWARD: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_FAST_FWD); + break; + + case HID_CONSUMER_REWIND: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_REWIND); + break; + + case HID_CONSUMER_SCAN_NEXT_TRK: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_NEXT_TRK); + break; + + case HID_CONSUMER_SCAN_PREV_TRK: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_SCAN_PREV_TRK); + break; + + case HID_CONSUMER_STOP: + HID_CC_RPT_SET_BUTTON(buffer, HID_CC_RPT_STOP); + break; + + default: + break; + } + + return; +} diff --git a/firmware/components/ble_hid/hid_dev.h b/firmware/components/ble_hid/hid_dev.h new file mode 100644 index 00000000..34e0e997 --- /dev/null +++ b/firmware/components/ble_hid/hid_dev.h @@ -0,0 +1,258 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef HID_DEV_H__ +#define HID_DEV_H__ + +#include "hidd_le_prf_int.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* HID Report type */ +#define HID_TYPE_INPUT 1 +#define HID_TYPE_OUTPUT 2 +#define HID_TYPE_FEATURE 3 + +// HID Keyboard/Keypad Usage IDs (subset of the codes available in the USB HID +// Usage Tables spec) +#define HID_KEY_RESERVED 0 // No event inidicated +#define HID_KEY_A 4 // Keyboard a and A +#define HID_KEY_B 5 // Keyboard b and B +#define HID_KEY_C 6 // Keyboard c and C +#define HID_KEY_D 7 // Keyboard d and D +#define HID_KEY_E 8 // Keyboard e and E +#define HID_KEY_F 9 // Keyboard f and F +#define HID_KEY_G 10 // Keyboard g and G +#define HID_KEY_H 11 // Keyboard h and H +#define HID_KEY_I 12 // Keyboard i and I +#define HID_KEY_J 13 // Keyboard j and J +#define HID_KEY_K 14 // Keyboard k and K +#define HID_KEY_L 15 // Keyboard l and L +#define HID_KEY_M 16 // Keyboard m and M +#define HID_KEY_N 17 // Keyboard n and N +#define HID_KEY_O 18 // Keyboard o and O +#define HID_KEY_P 19 // Keyboard p and p +#define HID_KEY_Q 20 // Keyboard q and Q +#define HID_KEY_R 21 // Keyboard r and R +#define HID_KEY_S 22 // Keyboard s and S +#define HID_KEY_T 23 // Keyboard t and T +#define HID_KEY_U 24 // Keyboard u and U +#define HID_KEY_V 25 // Keyboard v and V +#define HID_KEY_W 26 // Keyboard w and W +#define HID_KEY_X 27 // Keyboard x and X +#define HID_KEY_Y 28 // Keyboard y and Y +#define HID_KEY_Z 29 // Keyboard z and Z +#define HID_KEY_1 30 // Keyboard 1 and ! +#define HID_KEY_2 31 // Keyboard 2 and @ +#define HID_KEY_3 32 // Keyboard 3 and # +#define HID_KEY_4 33 // Keyboard 4 and % +#define HID_KEY_5 34 // Keyboard 5 and % +#define HID_KEY_6 35 // Keyboard 6 and ^ +#define HID_KEY_7 36 // Keyboard 7 and & +#define HID_KEY_8 37 // Keyboard 8 and * +#define HID_KEY_9 38 // Keyboard 9 and ( +#define HID_KEY_0 39 // Keyboard 0 and ) +#define HID_KEY_RETURN 40 // Keyboard Return (ENTER) +#define HID_KEY_ESCAPE 41 // Keyboard ESCAPE +#define HID_KEY_DELETE 42 // Keyboard DELETE (Backspace) +#define HID_KEY_TAB 43 // Keyboard Tab +#define HID_KEY_SPACEBAR 44 // Keyboard Spacebar +#define HID_KEY_MINUS 45 // Keyboard - and (underscore) +#define HID_KEY_EQUAL 46 // Keyboard = and + +#define HID_KEY_LEFT_BRKT 47 // Keyboard [ and { +#define HID_KEY_RIGHT_BRKT 48 // Keyboard ] and } +#define HID_KEY_BACK_SLASH 49 // Keyboard \ and | +#define HID_KEY_SEMI_COLON 51 // Keyboard ; and : +#define HID_KEY_SGL_QUOTE 52 // Keyboard ' and " +#define HID_KEY_GRV_ACCENT 53 // Keyboard Grave Accent and Tilde +#define HID_KEY_COMMA 54 // Keyboard , and < +#define HID_KEY_DOT 55 // Keyboard . and > +#define HID_KEY_FWD_SLASH 56 // Keyboard / and ? +#define HID_KEY_CAPS_LOCK 57 // Keyboard Caps Lock +#define HID_KEY_F1 58 // Keyboard F1 +#define HID_KEY_F2 59 // Keyboard F2 +#define HID_KEY_F3 60 // Keyboard F3 +#define HID_KEY_F4 61 // Keyboard F4 +#define HID_KEY_F5 62 // Keyboard F5 +#define HID_KEY_F6 63 // Keyboard F6 +#define HID_KEY_F7 64 // Keyboard F7 +#define HID_KEY_F8 65 // Keyboard F8 +#define HID_KEY_F9 66 // Keyboard F9 +#define HID_KEY_F10 67 // Keyboard F10 +#define HID_KEY_F11 68 // Keyboard F11 +#define HID_KEY_F12 69 // Keyboard F12 +#define HID_KEY_PRNT_SCREEN 70 // Keyboard Print Screen +#define HID_KEY_SCROLL_LOCK 71 // Keyboard Scroll Lock +#define HID_KEY_PAUSE 72 // Keyboard Pause +#define HID_KEY_INSERT 73 // Keyboard Insert +#define HID_KEY_HOME 74 // Keyboard Home +#define HID_KEY_PAGE_UP 75 // Keyboard PageUp +#define HID_KEY_DELETE_FWD 76 // Keyboard Delete Forward +#define HID_KEY_END 77 // Keyboard End +#define HID_KEY_PAGE_DOWN 78 // Keyboard PageDown +#define HID_KEY_RIGHT_ARROW 79 // Keyboard RightArrow +#define HID_KEY_LEFT_ARROW 80 // Keyboard LeftArrow +#define HID_KEY_DOWN_ARROW 81 // Keyboard DownArrow +#define HID_KEY_UP_ARROW 82 // Keyboard UpArrow +#define HID_KEY_NUM_LOCK 83 // Keypad Num Lock and Clear +#define HID_KEY_DIVIDE 84 // Keypad / +#define HID_KEY_MULTIPLY 85 // Keypad * +#define HID_KEY_SUBTRACT 86 // Keypad - +#define HID_KEY_ADD 87 // Keypad + +#define HID_KEY_ENTER 88 // Keypad ENTER +#define HID_KEYPAD_1 89 // Keypad 1 and End +#define HID_KEYPAD_2 90 // Keypad 2 and Down Arrow +#define HID_KEYPAD_3 91 // Keypad 3 and PageDn +#define HID_KEYPAD_4 92 // Keypad 4 and Lfet Arrow +#define HID_KEYPAD_5 93 // Keypad 5 +#define HID_KEYPAD_6 94 // Keypad 6 and Right Arrow +#define HID_KEYPAD_7 95 // Keypad 7 and Home +#define HID_KEYPAD_8 96 // Keypad 8 and Up Arrow +#define HID_KEYPAD_9 97 // Keypad 9 and PageUp +#define HID_KEYPAD_0 98 // Keypad 0 and Insert +#define HID_KEYPAD_DOT 99 // Keypad . and Delete +#define HID_KEY_MUTE 127 // Keyboard Mute +#define HID_KEY_VOLUME_UP 128 // Keyboard Volume up +#define HID_KEY_VOLUME_DOWN 129 // Keyboard Volume down +#define HID_KEY_LEFT_CTRL 224 // Keyboard LeftContorl +#define HID_KEY_LEFT_SHIFT 225 // Keyboard LeftShift +#define HID_KEY_LEFT_ALT 226 // Keyboard LeftAlt +#define HID_KEY_LEFT_GUI 227 // Keyboard LeftGUI +#define HID_KEY_RIGHT_CTRL 228 // Keyboard RightContorl +#define HID_KEY_RIGHT_SHIFT 229 // Keyboard RightShift +#define HID_KEY_RIGHT_ALT 230 // Keyboard RightAlt +#define HID_KEY_RIGHT_GUI 231 // Keyboard RightGUI +typedef uint8_t keyboard_cmd_t; + +#define HID_MOUSE_LEFT 253 +#define HID_MOUSE_MIDDLE 254 +#define HID_MOUSE_RIGHT 255 +typedef uint8_t mouse_cmd_t; + +// HID Consumer Usage IDs (subset of the codes available in the USB HID Usage +// Tables spec) +#define HID_CONSUMER_POWER 48 // Power +#define HID_CONSUMER_RESET 49 // Reset +#define HID_CONSUMER_SLEEP 50 // Sleep + +#define HID_CONSUMER_MENU 64 // Menu +#define HID_CONSUMER_SELECTION 128 // Selection +#define HID_CONSUMER_ASSIGN_SEL 129 // Assign Selection +#define HID_CONSUMER_MODE_STEP 130 // Mode Step +#define HID_CONSUMER_RECALL_LAST 131 // Recall Last +#define HID_CONSUMER_QUIT 148 // Quit +#define HID_CONSUMER_HELP 149 // Help +#define HID_CONSUMER_CHANNEL_UP 156 // Channel Increment +#define HID_CONSUMER_CHANNEL_DOWN 157 // Channel Decrement + +#define HID_CONSUMER_PLAY 176 // Play +#define HID_CONSUMER_PAUSE 177 // Pause +#define HID_CONSUMER_RECORD 178 // Record +#define HID_CONSUMER_FAST_FORWARD 179 // Fast Forward +#define HID_CONSUMER_REWIND 180 // Rewind +#define HID_CONSUMER_SCAN_NEXT_TRK 181 // Scan Next Track +#define HID_CONSUMER_SCAN_PREV_TRK 182 // Scan Previous Track +#define HID_CONSUMER_STOP 183 // Stop +#define HID_CONSUMER_EJECT 184 // Eject +#define HID_CONSUMER_RANDOM_PLAY 185 // Random Play +#define HID_CONSUMER_SELECT_DISC 186 // Select Disk +#define HID_CONSUMER_ENTER_DISC 187 // Enter Disc +#define HID_CONSUMER_REPEAT 188 // Repeat +#define HID_CONSUMER_STOP_EJECT 204 // Stop/Eject +#define HID_CONSUMER_PLAY_PAUSE 205 // Play/Pause +#define HID_CONSUMER_PLAY_SKIP 206 // Play/Skip + +#define HID_CONSUMER_VOLUME 224 // Volume +#define HID_CONSUMER_BALANCE 225 // Balance +#define HID_CONSUMER_MUTE 226 // Mute +#define HID_CONSUMER_BASS 227 // Bass +#define HID_CONSUMER_VOLUME_UP 233 // Volume Increment +#define HID_CONSUMER_VOLUME_DOWN 234 // Volume Decrement +typedef uint8_t consumer_cmd_t; + +#define HID_CC_RPT_MUTE 1 +#define HID_CC_RPT_POWER 2 +#define HID_CC_RPT_LAST 3 +#define HID_CC_RPT_ASSIGN_SEL 4 +#define HID_CC_RPT_PLAY 5 +#define HID_CC_RPT_PAUSE 6 +#define HID_CC_RPT_RECORD 7 +#define HID_CC_RPT_FAST_FWD 8 +#define HID_CC_RPT_REWIND 9 +#define HID_CC_RPT_SCAN_NEXT_TRK 10 +#define HID_CC_RPT_SCAN_PREV_TRK 11 +#define HID_CC_RPT_STOP 12 + +#define HID_CC_RPT_CHANNEL_UP 0x01 +#define HID_CC_RPT_CHANNEL_DOWN 0x03 +#define HID_CC_RPT_VOLUME_UP 0x40 +#define HID_CC_RPT_VOLUME_DOWN 0x80 + +// HID Consumer Control report bitmasks +#define HID_CC_RPT_NUMERIC_BITS 0xF0 +#define HID_CC_RPT_CHANNEL_BITS 0xCF +#define HID_CC_RPT_VOLUME_BITS 0x3F +#define HID_CC_RPT_BUTTON_BITS 0xF0 +#define HID_CC_RPT_SELECTION_BITS 0xCF + +// Macros for the HID Consumer Control 2-byte report +#define HID_CC_RPT_SET_NUMERIC(s, x) \ + (s)[0] &= HID_CC_RPT_NUMERIC_BITS; \ + (s)[0] = (x) +#define HID_CC_RPT_SET_CHANNEL(s, x) \ + (s)[0] &= HID_CC_RPT_CHANNEL_BITS; \ + (s)[0] |= ((x) & 0x03) << 4 +#define HID_CC_RPT_SET_VOLUME_UP(s) \ + (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ + (s)[0] |= 0x40 +#define HID_CC_RPT_SET_VOLUME_DOWN(s) \ + (s)[0] &= HID_CC_RPT_VOLUME_BITS; \ + (s)[0] |= 0x80 +#define HID_CC_RPT_SET_BUTTON(s, x) \ + (s)[1] &= HID_CC_RPT_BUTTON_BITS; \ + (s)[1] |= (x) +#define HID_CC_RPT_SET_SELECTION(s, x) \ + (s)[1] &= HID_CC_RPT_SELECTION_BITS; \ + (s)[1] |= ((x) & 0x03) << 4 + +// HID report mapping table +typedef struct { + uint16_t handle; // Handle of report characteristic + uint16_t cccdHandle; // Handle of CCCD for report characteristic + uint8_t id; // Report ID + uint8_t type; // Report type + uint8_t mode; // Protocol mode (report or boot) +} hid_report_map_t; + +// HID dev configuration structure +typedef struct { + uint32_t idleTimeout; // Idle timeout in milliseconds + uint8_t hidFlags; // HID feature flags + +} hid_dev_cfg_t; + +void hid_dev_register_reports(uint8_t num_reports, hid_report_map_t* p_report); + +void hid_dev_send_report(esp_gatt_if_t gatts_if, + uint16_t conn_id, + uint8_t id, + uint8_t type, + uint8_t length, + uint8_t* data); + +void hid_consumer_build_report(uint8_t* buffer, consumer_cmd_t cmd); + +void hid_keyboard_build_report(uint8_t* buffer, keyboard_cmd_t cmd); + +void hid_mouse_build_report(uint8_t* buffer, mouse_cmd_t cmd); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* HID_DEV_H__ */ diff --git a/firmware/components/ble_hid/hid_device_le_prf.c b/firmware/components/ble_hid/hid_device_le_prf.c new file mode 100644 index 00000000..c9afe378 --- /dev/null +++ b/firmware/components/ble_hid/hid_device_le_prf.c @@ -0,0 +1,900 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "esp_log.h" +#include "hidd_le_prf_int.h" + +/// characteristic presentation information +struct prf_char_pres_fmt { + /// Unit (The Unit is a UUID) + uint16_t unit; + /// Description + uint16_t description; + /// Format + uint8_t format; + /// Exponent + uint8_t exponent; + /// Name space + uint8_t name_space; +}; + +// HID report mapping table +static hid_report_map_t hid_rpt_map[HID_NUM_REPORTS]; + +// HID Report Map characteristic value +// Keyboard report descriptor (using format for Boot interface descriptor) +static const uint8_t hidReportMap[] = { + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report Id (1) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x05, 0x09, // Usage Page (Buttons) + 0x19, 0x01, // Usage Minimum (01) - Button 1 + 0x29, 0x03, // Usage Maximum (03) - Button 3 + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x03, // Report Count (3) + 0x81, 0x02, // Input (Data, Variable, Absolute) - Button states + 0x75, 0x05, // Report Size (5) + 0x95, 0x01, // Report Count (1) + 0x81, 0x01, // Input (Constant) - Padding or Reserved bits + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x03, // Report Count (3) + 0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate + 0xC0, // End Collection + 0xC0, // End Collection + + 0x05, 0x01, // Usage Pg (Generic Desktop) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection: (Application) + 0x85, 0x02, // Report Id (2) + // + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0xE0, // Usage Min (224) + 0x29, 0xE7, // Usage Max (231) + 0x15, 0x00, // Log Min (0) + 0x25, 0x01, // Log Max (1) + // + // Modifier byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input: (Data, Variable, Absolute) + // + // Reserved byte + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input: (Constant) + // + // LED report + 0x05, 0x08, // Usage Pg (LEDs) + 0x19, 0x01, // Usage Min (1) + 0x29, 0x05, // Usage Max (5) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x91, 0x02, // Output: (Data, Variable, Absolute) + // + // LED report padding + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output: (Constant) + // + // Key arrays (6 bytes) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Log Min (0) + 0x25, 0x65, // Log Max (101) + 0x05, 0x07, // Usage Pg (Key Codes) + 0x19, 0x00, // Usage Min (0) + 0x29, 0x65, // Usage Max (101) + 0x81, 0x00, // Input: (Data, Array) + // + 0xC0, // End Collection + // + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x03, // Report Id (3) + 0x09, 0x02, // Usage (Numeric Key Pad) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x0A, // Usage Max (Button 10) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0A, // Logical Max (10) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + 0x05, 0x0C, // Usage Pg (Consumer Devices) + 0x09, 0x86, // Usage (Channel) + 0x15, 0xFF, // Logical Min (-1) + 0x25, 0x01, // Logical Max (1) + 0x75, 0x02, // Report Size (2) + 0x95, 0x01, // Report Count (1) + 0x81, 0x46, // Input (Data, Var, Rel, Null) + 0x09, 0xE9, // Usage (Volume Up) + 0x09, 0xEA, // Usage (Volume Down) + 0x15, 0x00, // Logical Min (0) + 0x75, 0x01, // Report Size (1) + 0x95, 0x02, // Report Count (2) + 0x81, 0x02, // Input (Data, Var, Abs) + 0x09, 0xE2, // Usage (Mute) + 0x09, 0x30, // Usage (Power) + 0x09, 0x83, // Usage (Recall Last) + 0x09, 0x81, // Usage (Assign Selection) + 0x09, 0xB0, // Usage (Play) + 0x09, 0xB1, // Usage (Pause) + 0x09, 0xB2, // Usage (Record) + 0x09, 0xB3, // Usage (Fast Forward) + 0x09, 0xB4, // Usage (Rewind) + 0x09, 0xB5, // Usage (Scan Next) + 0x09, 0xB6, // Usage (Scan Prev) + 0x09, 0xB7, // Usage (Stop) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x0C, // Logical Max (12) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0x09, 0x80, // Usage (Selection) + 0xA1, 0x02, // Collection (Logical) + 0x05, 0x09, // Usage Pg (Button) + 0x19, 0x01, // Usage Min (Button 1) + 0x29, 0x03, // Usage Max (Button 3) + 0x15, 0x01, // Logical Min (1) + 0x25, 0x03, // Logical Max (3) + 0x75, 0x02, // Report Size (2) + 0x81, 0x00, // Input (Data, Ary, Abs) + 0xC0, // End Collection + 0x81, 0x03, // Input (Const, Var, Abs) + 0xC0, // End Collectionq + +#if (SUPPORT_REPORT_VENDOR == true) + 0x06, 0xFF, 0xFF, // Usage Page(Vendor defined) + 0x09, 0xA5, // Usage(Vendor Defined) + 0xA1, 0x01, // Collection(Application) + 0x85, 0x04, // Report Id (4) + 0x09, 0xA6, // Usage(Vendor defined) + 0x09, 0xA9, // Usage(Vendor defined) + 0x75, 0x08, // Report Size + 0x95, 0x7F, // Report Count = 127 Btyes + 0x91, 0x02, // Output(Data, Variable, Absolute) + 0xC0, // End Collection +#endif + +}; + +/// Battery Service Attributes Indexes +enum { + BAS_IDX_SVC, + + BAS_IDX_BATT_LVL_CHAR, + BAS_IDX_BATT_LVL_VAL, + BAS_IDX_BATT_LVL_NTF_CFG, + BAS_IDX_BATT_LVL_PRES_FMT, + + BAS_IDX_NB, +}; + +#define HI_UINT16(a) (((a) >> 8) & 0xFF) +#define LO_UINT16(a) ((a) & 0xFF) +#define PROFILE_NUM 1 +#define PROFILE_APP_IDX 0 + +struct gatts_profile_inst { + esp_gatts_cb_t gatts_cb; + uint16_t gatts_if; + uint16_t app_id; + uint16_t conn_id; +}; + +hidd_le_env_t hidd_le_env; + +// HID report map length +uint8_t hidReportMapLen = sizeof(hidReportMap); +uint8_t hidProtocolMode = HID_PROTOCOL_MODE_REPORT; + +// HID report mapping table +// static hidRptMap_t hidRptMap[HID_NUM_REPORTS]; + +// HID Information characteristic value +static const uint8_t hidInfo[HID_INFORMATION_LEN] = { + LO_UINT16(0x0111), HI_UINT16(0x0111), // bcdHID (USB HID version) + 0x00, // bCountryCode + HID_KBD_FLAGS // Flags +}; + +// HID External Report Reference Descriptor +static uint16_t hidExtReportRefDesc = ESP_GATT_UUID_BATTERY_LEVEL; + +// HID Report Reference characteristic descriptor, mouse input +static uint8_t hidReportRefMouseIn[HID_REPORT_REF_LEN] = { + HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT}; + +// HID Report Reference characteristic descriptor, key input +static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] = {HID_RPT_ID_KEY_IN, + HID_REPORT_TYPE_INPUT}; + +// HID Report Reference characteristic descriptor, LED output +static uint8_t hidReportRefLedOut[HID_REPORT_REF_LEN] = { + HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT}; + +#if (SUPPORT_REPORT_VENDOR == true) + +static uint8_t hidReportRefVendorOut[HID_REPORT_REF_LEN] = { + HID_RPT_ID_VENDOR_OUT, HID_REPORT_TYPE_OUTPUT}; +#endif + +// HID Report Reference characteristic descriptor, Feature +static uint8_t hidReportRefFeature[HID_REPORT_REF_LEN] = { + HID_RPT_ID_FEATURE, HID_REPORT_TYPE_FEATURE}; + +// HID Report Reference characteristic descriptor, consumer control input +static uint8_t hidReportRefCCIn[HID_REPORT_REF_LEN] = {HID_RPT_ID_CC_IN, + HID_REPORT_TYPE_INPUT}; + +/* + * Heart Rate PROFILE ATTRIBUTES + **************************************************************************************** + */ + +/// hid Service uuid +static uint16_t hid_le_svc = ATT_SVC_HID; +uint16_t hid_count = 0; +esp_gatts_incl_svc_desc_t incl_svc = {0}; + +#define CHAR_DECLARATION_SIZE (sizeof(uint8_t)) +/// the uuid definition +static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE; +static const uint16_t include_service_uuid = ESP_GATT_UUID_INCLUDE_SERVICE; +static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE; +static const uint16_t character_client_config_uuid = + ESP_GATT_UUID_CHAR_CLIENT_CONFIG; +static const uint16_t hid_info_char_uuid = ESP_GATT_UUID_HID_INFORMATION; +static const uint16_t hid_report_map_uuid = ESP_GATT_UUID_HID_REPORT_MAP; +static const uint16_t hid_control_point_uuid = ESP_GATT_UUID_HID_CONTROL_POINT; +static const uint16_t hid_report_uuid = ESP_GATT_UUID_HID_REPORT; +static const uint16_t hid_proto_mode_uuid = ESP_GATT_UUID_HID_PROTO_MODE; +static const uint16_t hid_kb_input_uuid = ESP_GATT_UUID_HID_BT_KB_INPUT; +static const uint16_t hid_kb_output_uuid = ESP_GATT_UUID_HID_BT_KB_OUTPUT; +static const uint16_t hid_mouse_input_uuid = ESP_GATT_UUID_HID_BT_MOUSE_INPUT; +static const uint16_t hid_repot_map_ext_desc_uuid = + ESP_GATT_UUID_EXT_RPT_REF_DESCR; +static const uint16_t hid_report_ref_descr_uuid = ESP_GATT_UUID_RPT_REF_DESCR; +/// the propoty definition +static const uint8_t char_prop_notify = ESP_GATT_CHAR_PROP_BIT_NOTIFY; +static const uint8_t char_prop_read = ESP_GATT_CHAR_PROP_BIT_READ; +static const uint8_t char_prop_write_nr = ESP_GATT_CHAR_PROP_BIT_WRITE_NR; +static const uint8_t char_prop_read_write = + ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ; +static const uint8_t char_prop_read_notify = + ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY; +static const uint8_t char_prop_read_write_notify = + ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | + ESP_GATT_CHAR_PROP_BIT_NOTIFY; +static const uint8_t char_prop_read_write_write_nr = + ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | + ESP_GATT_CHAR_PROP_BIT_WRITE_NR; + +/// battary Service +static const uint16_t battary_svc = ESP_GATT_UUID_BATTERY_SERVICE_SVC; + +static const uint16_t bat_lev_uuid = ESP_GATT_UUID_BATTERY_LEVEL; +static const uint8_t bat_lev_ccc[2] = {0x00, 0x00}; +static const uint16_t char_format_uuid = ESP_GATT_UUID_CHAR_PRESENT_FORMAT; + +static uint8_t battary_lev = 50; +/// Full HRS Database Description - Used to add attributes into the database +static const esp_gatts_attr_db_t bas_att_db[BAS_IDX_NB] = { + // Battary Service Declaration + [BAS_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &primary_service_uuid, + ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(battary_svc), + (uint8_t*) &battary_svc}}, + + // Battary level Characteristic Declaration + [BAS_IDX_BATT_LVL_CHAR] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, + CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + + // Battary level Characteristic Value + [BAS_IDX_BATT_LVL_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &bat_lev_uuid, + ESP_GATT_PERM_READ, sizeof(uint8_t), + sizeof(uint8_t), &battary_lev}}, + + // Battary level Characteristic - Client Characteristic Configuration + // Descriptor + [BAS_IDX_BATT_LVL_NTF_CFG] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_client_config_uuid, + ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, + sizeof(uint16_t), sizeof(bat_lev_ccc), + (uint8_t*) bat_lev_ccc}}, + + // Battary level report Characteristic Declaration + [BAS_IDX_BATT_LVL_PRES_FMT] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &char_format_uuid, + ESP_GATT_PERM_READ, + sizeof(struct prf_char_pres_fmt), 0, NULL}}, +}; + +/// Full Hid device Database Description - Used to add attributes into the +/// database +static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] = { + // HID Service Declaration + [HIDD_LE_IDX_SVC] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &primary_service_uuid, + ESP_GATT_PERM_READ_ENCRYPTED, sizeof(uint16_t), + sizeof(hid_le_svc), (uint8_t*) &hid_le_svc}}, + + // HID Service Declaration + [HIDD_LE_IDX_INCL_SVC] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &include_service_uuid, ESP_GATT_PERM_READ, + sizeof(esp_gatts_incl_svc_desc_t), sizeof(esp_gatts_incl_svc_desc_t), + (uint8_t*) &incl_svc}}, + + // HID Information Characteristic Declaration + [HIDD_LE_IDX_HID_INFO_CHAR] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, + CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read}}, + // HID Information Characteristic Value + [HIDD_LE_IDX_HID_INFO_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_info_char_uuid, + ESP_GATT_PERM_READ, sizeof(hids_hid_info_t), + sizeof(hidInfo), (uint8_t*) &hidInfo}}, + + // HID Control Point Characteristic Declaration + [HIDD_LE_IDX_HID_CTNL_PT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_write_nr}}, + // HID Control Point Characteristic Value + [HIDD_LE_IDX_HID_CTNL_PT_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_control_point_uuid, + ESP_GATT_PERM_WRITE, sizeof(uint8_t), 0, + NULL}}, + + // Report Map Characteristic Declaration + [HIDD_LE_IDX_REPORT_MAP_CHAR] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, + CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read}}, + // Report Map Characteristic Value + [HIDD_LE_IDX_REPORT_MAP_VAL] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_map_uuid, ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAP_MAX_LEN, sizeof(hidReportMap), + (uint8_t*) &hidReportMap}}, + + // Report Map Characteristic - External Report Reference Descriptor + [HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_repot_map_ext_desc_uuid, + ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(uint16_t), + (uint8_t*) &hidExtReportRefDesc}}, + + // Protocol Mode Characteristic Declaration + [HIDD_LE_IDX_PROTO_MODE_CHAR] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, + CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_write}}, + // Protocol Mode Characteristic Value + [HIDD_LE_IDX_PROTO_MODE_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_proto_mode_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + sizeof(uint8_t), sizeof(hidProtocolMode), + (uint8_t*) &hidProtocolMode}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, NULL}}, + + [HIDD_LE_IDX_REPORT_MOUSE_IN_CCC] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), sizeof(uint16_t), 0, + NULL}}, + + [HIDD_LE_IDX_REPORT_MOUSE_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefMouseIn), + sizeof(hidReportRefMouseIn), hidReportRefMouseIn}}, + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_KEY_IN_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_KEY_IN_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, NULL}}, + // Report KEY INPUT Characteristic - Client Characteristic Configuration + // Descriptor + [HIDD_LE_IDX_REPORT_KEY_IN_CCC] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), sizeof(uint16_t), 0, + NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_KEY_IN_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefKeyIn), + sizeof(hidReportRefKeyIn), hidReportRefKeyIn}}, + + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_LED_OUT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_write_write_nr}}, + + [HIDD_LE_IDX_REPORT_LED_OUT_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ | + ESP_GATT_PERM_WRITE, + HIDD_LE_REPORT_MAX_LEN, 0, NULL}}, + [HIDD_LE_IDX_REPORT_LED_OUT_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefLedOut), + sizeof(hidReportRefLedOut), hidReportRefLedOut}}, +#if (SUPPORT_REPORT_VENDOR == true) + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_write_notify}}, + [HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ | + ESP_GATT_PERM_WRITE, + HIDD_LE_REPORT_MAX_LEN, 0, NULL}}, + [HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefVendorOut), + sizeof(hidReportRefVendorOut), hidReportRefVendorOut}}, +#endif + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_CC_IN_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_CC_IN_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ, + HIDD_LE_REPORT_MAX_LEN, 0, NULL}}, + // Report KEY INPUT Characteristic - Client Characteristic Configuration + // Descriptor + [HIDD_LE_IDX_REPORT_CC_IN_CCC] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_client_config_uuid, + (ESP_GATT_PERM_READ | + ESP_GATT_PERM_WRITE_ENCRYPTED), + sizeof(uint16_t), 0, NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_CC_IN_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefCCIn), + sizeof(hidReportRefCCIn), hidReportRefCCIn}}, + + // Boot Keyboard Input Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + // Boot Keyboard Input Report Characteristic Value + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_kb_input_uuid, ESP_GATT_PERM_READ, + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL}}, + // Boot Keyboard Input Report Characteristic - Client Characteristic + // Configuration Descriptor + [HIDD_LE_IDX_BOOT_KB_IN_REPORT_NTF_CFG] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), sizeof(uint16_t), 0, + NULL}}, + + // Boot Keyboard Output Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_KB_OUT_REPORT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_write}}, + // Boot Keyboard Output Report Characteristic Value + [HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_kb_output_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL}}, + + // Boot Mouse Input Report Characteristic Declaration + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_CHAR] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_notify}}, + // Boot Mouse Input Report Characteristic Value + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_mouse_input_uuid, ESP_GATT_PERM_READ, + HIDD_LE_BOOT_REPORT_MAX_LEN, 0, NULL}}, + // Boot Mouse Input Report Characteristic - Client Characteristic + // Configuration Descriptor + [HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &character_client_config_uuid, + (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE), sizeof(uint16_t), 0, + NULL}}, + + // Report Characteristic Declaration + [HIDD_LE_IDX_REPORT_CHAR] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, + (uint8_t*) &character_declaration_uuid, + ESP_GATT_PERM_READ, CHAR_DECLARATION_SIZE, + CHAR_DECLARATION_SIZE, + (uint8_t*) &char_prop_read_write}}, + // Report Characteristic Value + [HIDD_LE_IDX_REPORT_VAL] = {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_uuid, + ESP_GATT_PERM_READ, HIDD_LE_REPORT_MAX_LEN, 0, + NULL}}, + // Report Characteristic - Report Reference Descriptor + [HIDD_LE_IDX_REPORT_REP_REF] = + {{ESP_GATT_AUTO_RSP}, + {ESP_UUID_LEN_16, (uint8_t*) &hid_report_ref_descr_uuid, + ESP_GATT_PERM_READ, sizeof(hidReportRefFeature), + sizeof(hidReportRefFeature), hidReportRefFeature}}, +}; + +static void hid_add_id_tbl(void); + +void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param) { + switch (event) { + case ESP_GATTS_REG_EVT: { + esp_ble_gap_config_local_icon(ESP_BLE_APPEARANCE_GENERIC_HID); + esp_hidd_cb_param_t hidd_param; + hidd_param.init_finish.state = param->reg.status; + if (param->reg.app_id == HIDD_APP_ID) { + hidd_le_env.gatt_if = gatts_if; + if (hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_REG_FINISH, &hidd_param); + hidd_le_create_service(hidd_le_env.gatt_if); + } + } + if (param->reg.app_id == BATTRAY_APP_ID) { + hidd_param.init_finish.gatts_if = gatts_if; + if (hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_BAT_EVENT_REG, &hidd_param); + } + } + + break; + } + case ESP_GATTS_CONF_EVT: { + break; + } + case ESP_GATTS_CREATE_EVT: + break; + case ESP_GATTS_CONNECT_EVT: { + esp_hidd_cb_param_t cb_param = {0}; + ESP_LOGI(HID_LE_PRF_TAG, "HID connection establish, conn_id = %x", + param->connect.conn_id); + memcpy(cb_param.connect.remote_bda, param->connect.remote_bda, + sizeof(esp_bd_addr_t)); + cb_param.connect.conn_id = param->connect.conn_id; + hidd_clcb_alloc(param->connect.conn_id, param->connect.remote_bda); + esp_ble_set_encryption(param->connect.remote_bda, + ESP_BLE_SEC_ENCRYPT_NO_MITM); + if (hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_CONNECT, &cb_param); + } + break; + } + case ESP_GATTS_DISCONNECT_EVT: { + if (hidd_le_env.hidd_cb != NULL) { + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_DISCONNECT, NULL); + } + hidd_clcb_dealloc(param->disconnect.conn_id); + break; + } + case ESP_GATTS_CLOSE_EVT: + break; + case ESP_GATTS_WRITE_EVT: { + esp_hidd_cb_param_t cb_param = {0}; + if (param->write.handle == + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_LED_OUT_VAL]) { + cb_param.led_write.conn_id = param->write.conn_id; + cb_param.led_write.report_id = HID_RPT_ID_LED_OUT; + cb_param.led_write.length = param->write.len; + cb_param.led_write.data = param->write.value; + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_LED_REPORT_WRITE_EVT, + &cb_param); + } +#if (SUPPORT_REPORT_VENDOR == true) + if (param->write.handle == + hidd_le_env.hidd_inst + .att_tbl[HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] && + hidd_le_env.hidd_cb != NULL) { + cb_param.vendor_write.conn_id = param->write.conn_id; + cb_param.vendor_write.report_id = HID_RPT_ID_VENDOR_OUT; + cb_param.vendor_write.length = param->write.len; + cb_param.vendor_write.data = param->write.value; + (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, + &cb_param); + } +#endif + break; + } + case ESP_GATTS_CREAT_ATTR_TAB_EVT: { + if (param->add_attr_tab.num_handle == BAS_IDX_NB && + param->add_attr_tab.svc_uuid.uuid.uuid16 == + ESP_GATT_UUID_BATTERY_SERVICE_SVC && + param->add_attr_tab.status == ESP_GATT_OK) { + incl_svc.start_hdl = param->add_attr_tab.handles[BAS_IDX_SVC]; + incl_svc.end_hdl = incl_svc.start_hdl + BAS_IDX_NB - 1; + ESP_LOGI(HID_LE_PRF_TAG, + "%s(), start added the hid service to the stack database. " + "incl_handle = %d", + __func__, incl_svc.start_hdl); + esp_ble_gatts_create_attr_tab(hidd_le_gatt_db, gatts_if, HIDD_LE_IDX_NB, + 0); + } + if (param->add_attr_tab.num_handle == HIDD_LE_IDX_NB && + param->add_attr_tab.status == ESP_GATT_OK) { + memcpy(hidd_le_env.hidd_inst.att_tbl, param->add_attr_tab.handles, + HIDD_LE_IDX_NB * sizeof(uint16_t)); + ESP_LOGI(HID_LE_PRF_TAG, "hid svc handle = %x", + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]); + hid_add_id_tbl(); + esp_ble_gatts_start_service( + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_SVC]); + } else { + esp_ble_gatts_start_service(param->add_attr_tab.handles[0]); + } + break; + } + + default: + break; + } +} + +void hidd_le_create_service(esp_gatt_if_t gatts_if) { + /* Here should added the battery service first, because the hid service should + include the battery service. After finish to added the battery service then + can added the hid service. */ + esp_ble_gatts_create_attr_tab(bas_att_db, gatts_if, BAS_IDX_NB, 0); +} + +void hidd_le_init(void) { + // Reset the hid device target environment + memset(&hidd_le_env, 0, sizeof(hidd_le_env_t)); +} + +void hidd_clcb_alloc(uint16_t conn_id, esp_bd_addr_t bda) { + uint8_t i_clcb = 0; + hidd_clcb_t* p_clcb = NULL; + + for (i_clcb = 0, p_clcb = hidd_le_env.hidd_clcb; i_clcb < HID_MAX_APPS; + i_clcb++, p_clcb++) { + if (!p_clcb->in_use) { + p_clcb->in_use = true; + p_clcb->conn_id = conn_id; + p_clcb->connected = true; + memcpy(p_clcb->remote_bda, bda, ESP_BD_ADDR_LEN); + break; + } + } + return; +} + +bool hidd_clcb_dealloc(uint16_t conn_id) { + uint8_t i_clcb = 0; + hidd_clcb_t* p_clcb = NULL; + + for (i_clcb = 0, p_clcb = hidd_le_env.hidd_clcb; i_clcb < HID_MAX_APPS; + i_clcb++, p_clcb++) { + memset(p_clcb, 0, sizeof(hidd_clcb_t)); + return true; + } + + return false; +} + +static struct gatts_profile_inst heart_rate_profile_tab[PROFILE_NUM] = { + [PROFILE_APP_IDX] = + { + .gatts_cb = esp_hidd_prf_cb_hdl, + .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is + ESP_GATT_IF_NONE */ + }, + +}; + +static void gatts_event_handler(esp_gatts_cb_event_t event, + esp_gatt_if_t gatts_if, + esp_ble_gatts_cb_param_t* param) { + /* If event is register event, store the gatts_if for each profile */ + if (event == ESP_GATTS_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + heart_rate_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if; + } else { + ESP_LOGI(HID_LE_PRF_TAG, "Reg app failed, app_id %04x, status %d", + param->reg.app_id, param->reg.status); + return; + } + } + + do { + int idx; + for (idx = 0; idx < PROFILE_NUM; idx++) { + if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a + certain gatt_if, need to call every + profile cb function */ + gatts_if == heart_rate_profile_tab[idx].gatts_if) { + if (heart_rate_profile_tab[idx].gatts_cb) { + heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param); + } + } + } + } while (0); +} + +esp_err_t hidd_register_cb(void) { + esp_err_t status; + status = esp_ble_gatts_register_callback(gatts_event_handler); + return status; +} + +void hidd_set_attr_value(uint16_t handle, + uint16_t val_len, + const uint8_t* value) { + hidd_inst_t* hidd_inst = &hidd_le_env.hidd_inst; + if (hidd_inst->att_tbl[HIDD_LE_IDX_HID_INFO_VAL] <= handle && + hidd_inst->att_tbl[HIDD_LE_IDX_REPORT_REP_REF] >= handle) { + esp_ble_gatts_set_attr_value(handle, val_len, value); + } else { + ESP_LOGE(HID_LE_PRF_TAG, "%s error:Invalid handle value.", __func__); + } + return; +} + +void hidd_get_attr_value(uint16_t handle, uint16_t* length, uint8_t** value) { + hidd_inst_t* hidd_inst = &hidd_le_env.hidd_inst; + if (hidd_inst->att_tbl[HIDD_LE_IDX_HID_INFO_VAL] <= handle && + hidd_inst->att_tbl[HIDD_LE_IDX_REPORT_REP_REF] >= handle) { + esp_ble_gatts_get_attr_value(handle, length, (const uint8_t**) value); + } else { + ESP_LOGE(HID_LE_PRF_TAG, "%s error:Invalid handle value.", __func__); + } + + return; +} + +static void hid_add_id_tbl(void) { + // Mouse input report + hid_rpt_map[0].id = hidReportRefMouseIn[0]; + hid_rpt_map[0].type = hidReportRefMouseIn[1]; + hid_rpt_map[0].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_MOUSE_IN_VAL]; + hid_rpt_map[0].cccdHandle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_MOUSE_IN_VAL]; + hid_rpt_map[0].mode = HID_PROTOCOL_MODE_REPORT; + + // Key input report + hid_rpt_map[1].id = hidReportRefKeyIn[0]; + hid_rpt_map[1].type = hidReportRefKeyIn[1]; + hid_rpt_map[1].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_KEY_IN_VAL]; + hid_rpt_map[1].cccdHandle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_KEY_IN_CCC]; + hid_rpt_map[1].mode = HID_PROTOCOL_MODE_REPORT; + + // Consumer Control input report + hid_rpt_map[2].id = hidReportRefCCIn[0]; + hid_rpt_map[2].type = hidReportRefCCIn[1]; + hid_rpt_map[2].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_CC_IN_VAL]; + hid_rpt_map[2].cccdHandle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_CC_IN_CCC]; + hid_rpt_map[2].mode = HID_PROTOCOL_MODE_REPORT; + + // LED output report + hid_rpt_map[3].id = hidReportRefLedOut[0]; + hid_rpt_map[3].type = hidReportRefLedOut[1]; + hid_rpt_map[3].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_LED_OUT_VAL]; + hid_rpt_map[3].cccdHandle = 0; + hid_rpt_map[3].mode = HID_PROTOCOL_MODE_REPORT; + + // Boot keyboard input report + // Use same ID and type as key input report + hid_rpt_map[4].id = hidReportRefKeyIn[0]; + hid_rpt_map[4].type = hidReportRefKeyIn[1]; + hid_rpt_map[4].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL]; + hid_rpt_map[4].cccdHandle = 0; + hid_rpt_map[4].mode = HID_PROTOCOL_MODE_BOOT; + + // Boot keyboard output report + // Use same ID and type as LED output report + hid_rpt_map[5].id = hidReportRefLedOut[0]; + hid_rpt_map[5].type = hidReportRefLedOut[1]; + hid_rpt_map[5].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL]; + hid_rpt_map[5].cccdHandle = 0; + hid_rpt_map[5].mode = HID_PROTOCOL_MODE_BOOT; + + // Boot mouse input report + // Use same ID and type as mouse input report + hid_rpt_map[6].id = hidReportRefMouseIn[0]; + hid_rpt_map[6].type = hidReportRefMouseIn[1]; + hid_rpt_map[6].handle = + hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL]; + hid_rpt_map[6].cccdHandle = 0; + hid_rpt_map[6].mode = HID_PROTOCOL_MODE_BOOT; + + // Feature report + hid_rpt_map[7].id = hidReportRefFeature[0]; + hid_rpt_map[7].type = hidReportRefFeature[1]; + hid_rpt_map[7].handle = hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_VAL]; + hid_rpt_map[7].cccdHandle = 0; + hid_rpt_map[7].mode = HID_PROTOCOL_MODE_REPORT; + + // Setup report ID map + hid_dev_register_reports(HID_NUM_REPORTS, hid_rpt_map); +} diff --git a/firmware/components/ble_hid/hidd_le_prf_int.h b/firmware/components/ble_hid/hidd_le_prf_int.h new file mode 100644 index 00000000..eeb07e64 --- /dev/null +++ b/firmware/components/ble_hid/hidd_le_prf_int.h @@ -0,0 +1,328 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#ifndef __HID_DEVICE_LE_PRF__ +#define __HID_DEVICE_LE_PRF__ +#include +#include "esp_gap_ble_api.h" +#include "esp_gatt_defs.h" +#include "esp_gatts_api.h" +#include "esp_hidd_prf_api.h" +#include "hid_dev.h" + +#define SUPPORT_REPORT_VENDOR false +// HID BLE profile log tag +#define HID_LE_PRF_TAG "HID_LE_PRF" + +/// Maximal number of HIDS that can be added in the DB +#ifndef USE_ONE_HIDS_INSTANCE + #define HIDD_LE_NB_HIDS_INST_MAX (2) +#else + #define HIDD_LE_NB_HIDS_INST_MAX (1) +#endif + +#define HIDD_GREAT_VER 0x01 // Version + Subversion +#define HIDD_SUB_VER 0x00 // Version + Subversion +#define HIDD_VERSION \ + ((HIDD_GREAT_VER << 8) | HIDD_SUB_VER) // Version + Subversion + +#define HID_MAX_APPS 1 + +// Number of HID reports defined in the service +#define HID_NUM_REPORTS 9 + +// HID Report IDs for the service +#define HID_RPT_ID_MOUSE_IN 1 // Mouse input report ID +#define HID_RPT_ID_KEY_IN 2 // Keyboard input report ID +#define HID_RPT_ID_CC_IN 3 // Consumer Control input report ID +#define HID_RPT_ID_VENDOR_OUT 4 // Vendor output report ID +#define HID_RPT_ID_LED_OUT 2 // LED output report ID +#define HID_RPT_ID_FEATURE 0 // Feature report ID + +#define HIDD_APP_ID 0x1812 // ATT_SVC_HID + +#define BATTRAY_APP_ID 0x180f + +#define ATT_SVC_HID 0x1812 + +/// Maximal number of Report Char. that can be added in the DB for one HIDS - Up +/// to 11 +#define HIDD_LE_NB_REPORT_INST_MAX (5) + +/// Maximal length of Report Char. Value +#define HIDD_LE_REPORT_MAX_LEN (255) +/// Maximal length of Report Map Char. Value +#define HIDD_LE_REPORT_MAP_MAX_LEN (512) + +/// Length of Boot Report Char. Value Maximal Length +#define HIDD_LE_BOOT_REPORT_MAX_LEN (8) + +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_KB_IN_NTF_CFG_MASK (0x40) +/// Boot KB Input Report Notification Configuration Bit Mask +#define HIDD_LE_BOOT_MOUSE_IN_NTF_CFG_MASK (0x80) +/// Boot Report Notification Configuration Bit Mask +#define HIDD_LE_REPORT_NTF_CFG_MASK (0x20) + +/* HID information flags */ +#define HID_FLAGS_REMOTE_WAKE 0x01 // RemoteWake +#define HID_FLAGS_NORMALLY_CONNECTABLE 0x02 // NormallyConnectable + +/* Control point commands */ +#define HID_CMD_SUSPEND 0x00 // Suspend +#define HID_CMD_EXIT_SUSPEND 0x01 // Exit Suspend + +/* HID protocol mode values */ +#define HID_PROTOCOL_MODE_BOOT 0x00 // Boot Protocol Mode +#define HID_PROTOCOL_MODE_REPORT 0x01 // Report Protocol Mode + +/* Attribute value lengths */ +#define HID_PROTOCOL_MODE_LEN 1 // HID Protocol Mode +#define HID_INFORMATION_LEN 4 // HID Information +#define HID_REPORT_REF_LEN 2 // HID Report Reference Descriptor +#define HID_EXT_REPORT_REF_LEN 2 // External Report Reference Descriptor + +// HID feature flags +#define HID_KBD_FLAGS HID_FLAGS_REMOTE_WAKE + +/* HID Report type */ +#define HID_REPORT_TYPE_INPUT 1 +#define HID_REPORT_TYPE_OUTPUT 2 +#define HID_REPORT_TYPE_FEATURE 3 + +/// HID Service Attributes Indexes +enum { + HIDD_LE_IDX_SVC, + + // Included Service + HIDD_LE_IDX_INCL_SVC, + + // HID Information + HIDD_LE_IDX_HID_INFO_CHAR, + HIDD_LE_IDX_HID_INFO_VAL, + + // HID Control Point + HIDD_LE_IDX_HID_CTNL_PT_CHAR, + HIDD_LE_IDX_HID_CTNL_PT_VAL, + + // Report Map + HIDD_LE_IDX_REPORT_MAP_CHAR, + HIDD_LE_IDX_REPORT_MAP_VAL, + HIDD_LE_IDX_REPORT_MAP_EXT_REP_REF, + + // Protocol Mode + HIDD_LE_IDX_PROTO_MODE_CHAR, + HIDD_LE_IDX_PROTO_MODE_VAL, + + // Report mouse input + HIDD_LE_IDX_REPORT_MOUSE_IN_CHAR, + HIDD_LE_IDX_REPORT_MOUSE_IN_VAL, + HIDD_LE_IDX_REPORT_MOUSE_IN_CCC, + HIDD_LE_IDX_REPORT_MOUSE_REP_REF, + // Report Key input + HIDD_LE_IDX_REPORT_KEY_IN_CHAR, + HIDD_LE_IDX_REPORT_KEY_IN_VAL, + HIDD_LE_IDX_REPORT_KEY_IN_CCC, + HIDD_LE_IDX_REPORT_KEY_IN_REP_REF, + /// Report Led output + HIDD_LE_IDX_REPORT_LED_OUT_CHAR, + HIDD_LE_IDX_REPORT_LED_OUT_VAL, + HIDD_LE_IDX_REPORT_LED_OUT_REP_REF, + +#if (SUPPORT_REPORT_VENDOR == true) + /// Report Vendor + HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR, + HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL, + HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF, +#endif + HIDD_LE_IDX_REPORT_CC_IN_CHAR, + HIDD_LE_IDX_REPORT_CC_IN_VAL, + HIDD_LE_IDX_REPORT_CC_IN_CCC, + HIDD_LE_IDX_REPORT_CC_IN_REP_REF, + + // Boot Keyboard Input Report + HIDD_LE_IDX_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_KB_IN_REPORT_NTF_CFG, + + // Boot Keyboard Output Report + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_IDX_BOOT_KB_OUT_REPORT_VAL, + + // Boot Mouse Input Report + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_VAL, + HIDD_LE_IDX_BOOT_MOUSE_IN_REPORT_NTF_CFG, + + // Report + HIDD_LE_IDX_REPORT_CHAR, + HIDD_LE_IDX_REPORT_VAL, + HIDD_LE_IDX_REPORT_REP_REF, + // HIDD_LE_IDX_REPORT_NTF_CFG, + + HIDD_LE_IDX_NB, +}; + +/// Attribute Table Indexes +enum { + HIDD_LE_INFO_CHAR, + HIDD_LE_CTNL_PT_CHAR, + HIDD_LE_REPORT_MAP_CHAR, + HIDD_LE_REPORT_CHAR, + HIDD_LE_PROTO_MODE_CHAR, + HIDD_LE_BOOT_KB_IN_REPORT_CHAR, + HIDD_LE_BOOT_KB_OUT_REPORT_CHAR, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR, + HIDD_LE_CHAR_MAX //= HIDD_LE_REPORT_CHAR + HIDD_LE_NB_REPORT_INST_MAX, +}; + +/// att read event table Indexs +enum { + HIDD_LE_READ_INFO_EVT, + HIDD_LE_READ_CTNL_PT_EVT, + HIDD_LE_READ_REPORT_MAP_EVT, + HIDD_LE_READ_REPORT_EVT, + HIDD_LE_READ_PROTO_MODE_EVT, + HIDD_LE_BOOT_KB_IN_REPORT_EVT, + HIDD_LE_BOOT_KB_OUT_REPORT_EVT, + HIDD_LE_BOOT_MOUSE_IN_REPORT_EVT, + + HID_LE_EVT_MAX +}; + +/// Client Characteristic Configuration Codes +enum { + HIDD_LE_DESC_MASK = 0x10, + + HIDD_LE_BOOT_KB_IN_REPORT_CFG = + HIDD_LE_BOOT_KB_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_BOOT_MOUSE_IN_REPORT_CFG = + HIDD_LE_BOOT_MOUSE_IN_REPORT_CHAR | HIDD_LE_DESC_MASK, + HIDD_LE_REPORT_CFG = HIDD_LE_REPORT_CHAR | HIDD_LE_DESC_MASK, +}; + +/// Features Flag Values +enum { + HIDD_LE_CFG_KEYBOARD = 0x01, + HIDD_LE_CFG_MOUSE = 0x02, + HIDD_LE_CFG_PROTO_MODE = 0x04, + HIDD_LE_CFG_MAP_EXT_REF = 0x08, + HIDD_LE_CFG_BOOT_KB_WR = 0x10, + HIDD_LE_CFG_BOOT_MOUSE_WR = 0x20, +}; + +/// Report Char. Configuration Flag Values +enum { + HIDD_LE_CFG_REPORT_IN = 0x01, + HIDD_LE_CFG_REPORT_OUT = 0x02, + // HOGPD_CFG_REPORT_FEAT can be used as a mask to check Report type + HIDD_LE_CFG_REPORT_FEAT = 0x03, + HIDD_LE_CFG_REPORT_WR = 0x10, +}; + +/// Pointer to the connection clean-up function +#define HIDD_LE_CLEANUP_FNCT (NULL) + +/* + * TYPE DEFINITIONS + **************************************************************************************** + */ + +/// HIDD Features structure +typedef struct { + /// Service Features + uint8_t svc_features; + /// Number of Report Char. instances to add in the database + uint8_t report_nb; + /// Report Char. Configuration + uint8_t report_char_cfg[HIDD_LE_NB_REPORT_INST_MAX]; +} hidd_feature_t; + +typedef struct { + bool in_use; + bool congest; + uint16_t conn_id; + bool connected; + esp_bd_addr_t remote_bda; + uint32_t trans_id; + uint8_t cur_srvc_id; + +} hidd_clcb_t; + +// HID report mapping table +typedef struct { + uint16_t handle; // Handle of report characteristic + uint16_t cccdHandle; // Handle of CCCD for report characteristic + uint8_t id; // Report ID + uint8_t type; // Report type + uint8_t mode; // Protocol mode (report or boot) +} hidRptMap_t; + +typedef struct { + /// hidd profile id + uint8_t app_id; + /// Notified handle + uint16_t ntf_handle; + /// Attribute handle Table + uint16_t att_tbl[HIDD_LE_IDX_NB]; + /// Supported Features + hidd_feature_t hidd_feature[HIDD_LE_NB_HIDS_INST_MAX]; + /// Current Protocol Mode + uint8_t proto_mode[HIDD_LE_NB_HIDS_INST_MAX]; + /// Number of HIDS added in the database + uint8_t hids_nb; + uint8_t pending_evt; + uint16_t pending_hal; +} hidd_inst_t; + +/// Report Reference structure +typedef struct { + /// Report ID + uint8_t report_id; + /// Report Type + uint8_t report_type; +} hids_report_ref_t; + +/// HID Information structure +typedef struct { + /// bcdHID + uint16_t bcdHID; + /// bCountryCode + uint8_t bCountryCode; + /// Flags + uint8_t flags; +} hids_hid_info_t; + +/* service engine control block */ +typedef struct { + hidd_clcb_t hidd_clcb[HID_MAX_APPS]; /* connection link*/ + esp_gatt_if_t gatt_if; + bool enabled; + bool is_take; + bool is_primery; + hidd_inst_t hidd_inst; + esp_hidd_event_cb_t hidd_cb; + uint8_t inst_id; +} hidd_le_env_t; + +extern hidd_le_env_t hidd_le_env; +extern uint8_t hidProtocolMode; + +void hidd_clcb_alloc(uint16_t conn_id, esp_bd_addr_t bda); + +bool hidd_clcb_dealloc(uint16_t conn_id); + +void hidd_le_create_service(esp_gatt_if_t gatts_if); + +void hidd_set_attr_value(uint16_t handle, + uint16_t val_len, + const uint8_t* value); + +void hidd_get_attr_value(uint16_t handle, uint16_t* length, uint8_t** value); + +esp_err_t hidd_register_cb(void); + +#endif ///__HID_DEVICE_LE_PRF__ diff --git a/firmware/components/buzzer/buzzer.c b/firmware/components/buzzer/buzzer.c index b52447e3..522e68fc 100644 --- a/firmware/components/buzzer/buzzer.c +++ b/firmware/components/buzzer/buzzer.c @@ -18,9 +18,17 @@ typedef struct { uint8_t pin; uint32_t freq; uint32_t duty; + bool enabled; } buzzer_t; -buzzer_t buzzer; +static buzzer_t buzzer; + +void buzzer_enable() { + buzzer.enabled = true; +} +void buzzer_disable() { + buzzer.enabled = false; +} void buzzer_begin(uint8_t pin) { buzzer.pin = pin; @@ -57,8 +65,10 @@ void buzzer_set_duty(uint32_t duty) { } void buzzer_play() { + if (!buzzer.enabled) { + return; + } buzzer_configure(); - // Set the duty cycle ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, buzzer.duty)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); @@ -73,6 +83,9 @@ void buzzer_play_for_task(void* duration) { } void buzzer_play_for(uint32_t duration) { + if (!buzzer.enabled) { + return; + } uint32_t* duration_ptr = malloc(sizeof(uint32_t)); *duration_ptr = duration; xTaskCreate(buzzer_play_for_task, "buzzer_play_for_task", 2048, duration_ptr, diff --git a/firmware/components/buzzer/include/buzzer.h b/firmware/components/buzzer/include/buzzer.h index aeac0075..32702c19 100644 --- a/firmware/components/buzzer/include/buzzer.h +++ b/firmware/components/buzzer/include/buzzer.h @@ -50,3 +50,6 @@ void buzzer_play_for(uint32_t duration); * @return void */ void buzzer_stop(); + +void buzzer_enable(); +void buzzer_disable(); \ No newline at end of file diff --git a/firmware/components/flash_fs/flash_fs.c b/firmware/components/flash_fs/flash_fs.c index d1265587..64b1c2b7 100644 --- a/firmware/components/flash_fs/flash_fs.c +++ b/firmware/components/flash_fs/flash_fs.c @@ -6,7 +6,20 @@ #define TAG "Flash_fs" -size_t flash_fs_size, flash_fs_used; +static size_t flash_fs_size, flash_fs_used; + +static void (*flash_fs_show_event_cb)(flash_fs_events_t, void*) = NULL; +static bool already_mounted = false; + +void flash_fs_begin(void* screens_cb) { + flash_fs_show_event_cb = screens_cb; +} + +static void flash_fs_show_event(flash_fs_events_t event, void* ctx) { + if (flash_fs_show_event_cb) { + flash_fs_show_event_cb(event, ctx); + } +} esp_err_t flash_fs_mount() { esp_vfs_spiffs_conf_t conf = {.base_path = FLASH_FS_MOUNT_PATH, @@ -14,10 +27,16 @@ esp_err_t flash_fs_mount() { .max_files = 5, .format_if_mount_failed = true}; - esp_err_t ret = esp_vfs_spiffs_register(&conf); - if (ret == ESP_OK || ret == ESP_ERR_INVALID_STATE) { - esp_spiffs_info(conf.partition_label, &flash_fs_size, &flash_fs_used); - return ESP_OK; + if (!esp_spiffs_mounted(conf.partition_label)) { + flash_fs_show_event(FLASH_FS_MOUNTING_EV, NULL); + esp_err_t ret = esp_vfs_spiffs_register(&conf); + if (ret == ESP_OK || ret == ESP_ERR_INVALID_STATE) { + esp_spiffs_info(conf.partition_label, &flash_fs_size, &flash_fs_used); + flash_fs_show_event(FLASH_FS_RESULT_EV, ESP_OK); + return ESP_OK; + } + flash_fs_show_event(FLASH_FS_RESULT_EV, ret); + return ret; } - return ret; + return ESP_OK; } diff --git a/firmware/components/flash_fs/include/flash_fs.h b/firmware/components/flash_fs/include/flash_fs.h index 1ed6d66f..5228756c 100644 --- a/firmware/components/flash_fs/include/flash_fs.h +++ b/firmware/components/flash_fs/include/flash_fs.h @@ -4,4 +4,7 @@ #define FLASH_FS_MOUNT_PATH "/internal" +typedef enum { FLASH_FS_MOUNTING_EV, FLASH_FS_RESULT_EV } flash_fs_events_t; + +void flash_fs_begin(void* screens_cb); esp_err_t flash_fs_mount(); diff --git a/firmware/components/ledc_controller/ledc_controller.c b/firmware/components/ledc_controller/ledc_controller.c index 5115b8ff..d9220169 100644 --- a/firmware/components/ledc_controller/ledc_controller.c +++ b/firmware/components/ledc_controller/ledc_controller.c @@ -506,7 +506,7 @@ esp_err_t led_controller_start_blink_effect(led_t* led, esp_err_t led_controller_stop_any_effect(led_t* led) { if (!led) { - ESP_LOGE(TAG, "Invalid LED pointer"); + // ESP_LOGE(TAG, "Invalid LED pointer"); return ESP_ERR_INVALID_ARG; } diff --git a/firmware/components/leds/include/leds.h b/firmware/components/leds/include/leds.h index e1cee7f8..da797b00 100644 --- a/firmware/components/leds/include/leds.h +++ b/firmware/components/leds/include/leds.h @@ -8,7 +8,8 @@ typedef enum { LED_LEFT, LED_RIGHT } leds_enum; -void leds_init(); +void leds_begin(); +void leds_deinit(); void leds_on(); void leds_off(); void leds_set_brightness(uint8_t led, uint8_t brightness); diff --git a/firmware/components/leds/leds.c b/firmware/components/leds/leds.c index 9afa70d7..3123b280 100644 --- a/firmware/components/leds/leds.c +++ b/firmware/components/leds/leds.c @@ -1,4 +1,7 @@ #include "leds.h" + +#include + #include "driver/ledc.h" #include "ledc_controller.h" @@ -8,43 +11,57 @@ #define RIGHT_LED_CHANNEL LEDC_CHANNEL_1 #define LEDC_TIMER LEDC_TIMER_0 -led_t left_led, right_led; +static led_t *left_led, *right_led; + +void leds_begin() { + left_led = (led_t*) malloc(sizeof(led_t)); + right_led = (led_t*) malloc(sizeof(led_t)); + *left_led = led_controller_led_new(LEFT_LED_IO, LEFT_LED_CHANNEL); + *right_led = led_controller_led_new(RIGHT_LED_IO, RIGHT_LED_CHANNEL); + led_controller_led_init(left_led); + led_controller_led_init(right_led); +} -void leds_init() { - left_led = led_controller_led_new(LEFT_LED_IO, LEFT_LED_CHANNEL); - right_led = led_controller_led_new(RIGHT_LED_IO, RIGHT_LED_CHANNEL); - led_controller_led_init(&left_led); - led_controller_led_init(&right_led); +void leds_deinit() { + if (!left_led || !right_led) { + return; + } + led_controller_led_deinit(left_led); + led_controller_led_deinit(right_led); + free(left_led); + free(right_led); + left_led = NULL; + right_led = NULL; } void leds_on() { - led_controller_led_on(&left_led); - led_controller_led_on(&right_led); + led_controller_led_on(left_led); + led_controller_led_on(right_led); } void leds_off() { - led_controller_led_off(&left_led); - led_controller_led_off(&right_led); + led_controller_led_off(left_led); + led_controller_led_off(right_led); } void leds_set_brightness(uint8_t led, uint8_t brightness) { - led_controller_set_duty(led == LED_LEFT ? &left_led : &right_led, brightness); + led_controller_set_duty(led == LED_LEFT ? left_led : right_led, brightness); } void led_left_on() { - led_controller_led_on(&left_led); + led_controller_led_on(left_led); } void led_left_off() { - led_controller_led_off(&left_led); + led_controller_led_off(left_led); } void led_right_on() { - led_controller_led_on(&right_led); + led_controller_led_on(right_led); } void led_right_off() { - led_controller_led_off(&right_led); + led_controller_led_off(right_led); } void led_start_blink(uint8_t led, @@ -53,14 +70,14 @@ void led_start_blink(uint8_t led, uint32_t time_on, uint32_t time_off, uint32_t time_out) { - led_controller_start_blink_effect(led == LED_LEFT ? &left_led : &right_led, + led_controller_start_blink_effect(led == LED_LEFT ? left_led : right_led, duty, pulse_count, time_on, time_off, time_out); } void led_start_breath(uint8_t led, uint16_t period_ms) { - led_controller_start_breath_effect(led == LED_LEFT ? &left_led : &right_led, + led_controller_start_breath_effect(led == LED_LEFT ? left_led : right_led, period_ms); } void led_stop(uint8_t led) { - led_controller_stop_any_effect(led == LED_LEFT ? &left_led : &right_led); + led_controller_stop_any_effect(led == LED_LEFT ? left_led : right_led); } diff --git a/firmware/components/open_thread/open_thread.c b/firmware/components/open_thread/open_thread.c index 8ae6813c..c5f9748c 100644 --- a/firmware/components/open_thread/open_thread.c +++ b/firmware/components/open_thread/open_thread.c @@ -268,8 +268,6 @@ otError openthread_udp_send(otUdpSocket* mSocket, messageInfo.mPeerPort = port; message = otUdpNewMessage(instance, &messageSettings); - if (message == NULL) - printf("ERR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); uint8_t* payload = (uint8_t*) malloc(data_size); if (!payload) { diff --git a/firmware/components/thread_broadcast/thread_broadcast.c b/firmware/components/thread_broadcast/thread_broadcast.c index ce0d8434..a258e7e7 100644 --- a/firmware/components/thread_broadcast/thread_broadcast.c +++ b/firmware/components/thread_broadcast/thread_broadcast.c @@ -1,5 +1,6 @@ #include "thread_broadcast.h" #include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -12,19 +13,20 @@ void (*on_msg_recieve_cb)(char*) = NULL; void on_udp_recieve(void* aContext, otMessage* aMessage, const otMessageInfo* aMessageInfo) { - printf("MSG\n"); otError error = OT_ERROR_NONE; int payload_size = (otMessageGetLength(aMessage) - otMessageGetOffset(aMessage)); void* data = malloc(payload_size); otMessageRead(aMessage, otMessageGetOffset(aMessage), data, payload_size); - char* str = (char*) data; - str[payload_size] = "\0"; + char* str = (char*) malloc(payload_size + 1); + sprintf(str, "%s", (char*) data); + printf("MSG\n"); printf("%s\n", str); if (on_msg_recieve_cb != NULL) { on_msg_recieve_cb(str); } + free(str); free(data); } @@ -32,10 +34,10 @@ void sender() { uint16_t counter = 0; while (1) { counter++; - char* str = (char*) malloc(15); - sprintf(str, "counter: %d", counter); + char* str = (char*) malloc(20); + sprintf(str, "Counter: %d", counter); vTaskDelay(pdMS_TO_TICKS(500)); - openthread_udp_send(&mSocket, "ff02::1", PORT, &str, sizeof(str)); + openthread_udp_send(&mSocket, "ff02::1", PORT, str, strlen(str)); free(str); } } diff --git a/firmware/components/trackers_scanner/trackers_scanner.c b/firmware/components/trackers_scanner/trackers_scanner.c index 4d2f67c8..347c948c 100644 --- a/firmware/components/trackers_scanner/trackers_scanner.c +++ b/firmware/components/trackers_scanner/trackers_scanner.c @@ -23,9 +23,9 @@ static void handle_bt_gapc_events(esp_gap_ble_cb_event_t event_type, esp_ble_gap_cb_param_t* param); void trackers_scanner_start() { -#if !defined(CONFIG_TRACKERS_SCANNER_DEBUG) - esp_log_level_set(TAG_BLE_CLIENT_MODULE, ESP_LOG_NONE); -#endif + // #if !defined(CONFIG_TRACKERS_SCANNER_DEBUG) + // esp_log_level_set(TAG_BLE_CLIENT_MODULE, ESP_LOG_NONE); + // #endif gattc_scan_params_t scan_params = { .remote_filter_service_uuid = @@ -90,7 +90,7 @@ void trackers_scanner_register_cb(bluetooth_traker_scanner_cb_t callback) { static void task_tracker_timer() { ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task started"); trackers_scan_duration = 0; - while (1) { + while (trackers_scanner_active) { if (trackers_scan_duration >= TRACKER_SCAN_DURATION) { ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task stopped"); trackers_scanner_stop(); @@ -100,14 +100,18 @@ static void task_tracker_timer() { } void trackers_scanner_stop() { + trackers_scanner_active = false; ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task stopped"); if (trackers_scan_timer_task != NULL) { - vTaskDelete(trackers_scan_timer_task); - trackers_scan_timer_task = NULL; + ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task stopped"); + vTaskSuspend(trackers_scan_timer_task); } + ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task stopped"); trackers_scan_duration = 0; + vTaskDelete(NULL); // TODO: When this is called, the BLE stopping bricks the device // bt_gattc_task_stop(); + ESP_LOGI(TAG_BLE_CLIENT_MODULE, "Trackers task stopped"); } static void tracker_dissector(esp_ble_gap_cb_param_t* scan_rst, @@ -133,7 +137,7 @@ static void tracker_dissector(esp_ble_gap_cb_param_t* scan_rst, scan_rst->scan_rst.bda[1], scan_rst->scan_rst.bda[0]); ESP_LOGI(TAG_BLE_CLIENT_MODULE, "ADV data %d:", scan_rst->scan_rst.adv_data_len); - esp_log_buffer_hex(TAG_BLE_CLIENT_MODULE, &scan_rst->scan_rst.ble_adv, + ESP_LOG_BUFFER_HEX(TAG_BLE_CLIENT_MODULE, &scan_rst->scan_rst.ble_adv, scan_rst->scan_rst.adv_data_len); ESP_LOGI(TAG_BLE_CLIENT_MODULE, " "); break; @@ -142,22 +146,16 @@ static void tracker_dissector(esp_ble_gap_cb_param_t* scan_rst, } void trackers_scanner_add_tracker_profile(tracker_profile_t** profiles, - int* num_profiles, - uint8_t mac_address[6], - int rssi, - char* name) { + uint16_t* num_profiles, + tracker_profile_t new_profile) { *profiles = realloc(*profiles, (*num_profiles + 1) * sizeof(tracker_profile_t)); - - (*profiles)[*num_profiles].rssi = rssi; - (*profiles)[*num_profiles].name = name; - memcpy((*profiles)[*num_profiles].mac_address, mac_address, 6); - + (*profiles)[*num_profiles] = new_profile; (*num_profiles)++; } int trackers_scanner_find_profile_by_mac(tracker_profile_t* profiles, - int num_profiles, + uint16_t num_profiles, uint8_t mac_address[6]) { for (int i = 0; i < num_profiles; i++) { if (memcmp(profiles[i].mac_address, mac_address, 6) == 0) { diff --git a/firmware/components/trackers_scanner/trackers_scanner.h b/firmware/components/trackers_scanner/trackers_scanner.h index 3ba3e698..649acdbf 100644 --- a/firmware/components/trackers_scanner/trackers_scanner.h +++ b/firmware/components/trackers_scanner/trackers_scanner.h @@ -78,15 +78,11 @@ bool trackers_scanner_is_active(); * * @param profiles The list of tracker profiles * @param num_profiles The number of tracker profiles - * @param mac_address The mac address of the tracker - * @param rssi The rssi of the tracker - * @param name The name of the tracker + * @param new_profile The new tracker profile to add */ void trackers_scanner_add_tracker_profile(tracker_profile_t** profiles, - int* num_profiles, - uint8_t mac_address[6], - int rssi, - char* name); + uint16_t* num_profiles, + tracker_profile_t new_profile); /** * @brief Find a profile by the mac address @@ -97,6 +93,6 @@ void trackers_scanner_add_tracker_profile(tracker_profile_t** profiles, * @return int Index of the profile or -1 if not found */ int trackers_scanner_find_profile_by_mac(tracker_profile_t* profiles, - int num_profiles, + uint16_t num_profiles, uint8_t mac_address[6]); #endif // TRACKERS_SCANNER_H diff --git a/firmware/components/wifi_attacks/wifi_attacks.h b/firmware/components/wifi_attacks/wifi_attacks.h index b150ecaa..3f6e9757 100644 --- a/firmware/components/wifi_attacks/wifi_attacks.h +++ b/firmware/components/wifi_attacks/wifi_attacks.h @@ -31,6 +31,7 @@ typedef enum { WIFI_ATTACK_COMBINE, WIFI_ATTACK_MULTI_AP, WIFI_ATTACK_PASSWORD, + WIFI_ATTACKS_NUM } wifi_attacks_types_t; /** diff --git a/firmware/components/wifi_controller/Kconfig.projbuild b/firmware/components/wifi_controller/Kconfig.projbuild index 67b74a20..85c3d4bb 100644 --- a/firmware/components/wifi_controller/Kconfig.projbuild +++ b/firmware/components/wifi_controller/Kconfig.projbuild @@ -7,13 +7,13 @@ menu "Wi-Fi Controller" menu "Manager AP" config MANAGER_AP_SSID string "Manager AP SSID" - default "APPSECManager" + default "MININO_MANAGER" help SSID of management AP config MANAGER_AP_PASSWORD string "Manager AP Password" - default "appsec1234" + default "minino1234" help Password for management AP WPA2 (minimum 8 characters) diff --git a/firmware/components/wifi_sniffer/include/wifi_sniffer.h b/firmware/components/wifi_sniffer/include/wifi_sniffer.h index bbad9f52..7d59befa 100644 --- a/firmware/components/wifi_sniffer/include/wifi_sniffer.h +++ b/firmware/components/wifi_sniffer/include/wifi_sniffer.h @@ -40,13 +40,6 @@ void wifi_sniffer_stop(); */ void wifi_sniffer_close_file(); -/** - * @brief Exit the wifi sniffer - * - * @return void - */ -void wifi_sniffer_exit(); - /** * @brief Load the summary * diff --git a/firmware/components/wifi_sniffer/wifi_sniffer.c b/firmware/components/wifi_sniffer/wifi_sniffer.c index bf384dda..c259ca1c 100644 --- a/firmware/components/wifi_sniffer/wifi_sniffer.c +++ b/firmware/components/wifi_sniffer/wifi_sniffer.c @@ -21,7 +21,6 @@ #include "flash_fs.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "menu_screens_modules.h" #include "preferences.h" #include "sd_card.h" #include "sdkconfig.h" @@ -84,11 +83,6 @@ void wifi_sniffer_close_file() { } } -void wifi_sniffer_exit() { - screen_module_set_screen(MENU_WIFI_ANALIZER); - esp_restart(); -} - void wifi_sniffer_load_summary() { const char** summary_argv[] = {"pcap", "--summary", "-f", "sniffer"}; uint8_t summary_argc = 4; diff --git a/firmware/components/zigbee_switch/zigbee_switch.c b/firmware/components/zigbee_switch/zigbee_switch.c index 09218f45..51c44633 100644 --- a/firmware/components/zigbee_switch/zigbee_switch.c +++ b/firmware/components/zigbee_switch/zigbee_switch.c @@ -62,7 +62,7 @@ const char* switch_state_names[] = { "SWITCH_LIGHT_FOUND", "SWITCH_NO_DEVICES", "SWITCH_EXIT", }; -switch_state_t switch_state = SWITCH_CREATE_NETWORK; +volatile switch_state_t switch_state = SWITCH_CREATE_NETWORK; switch_state_t switch_state_prev = SWITCH_EXIT; uint16_t open_network_duration = 0; @@ -283,7 +283,7 @@ void wait_for_devices_task(void* pvParameters) { continue; } zigbee_switch_display_status_cb(WAITING_FOR_DEVICES); - vTaskDelay(100 / portTICK_PERIOD_MS); + vTaskDelay(300 / portTICK_PERIOD_MS); } } @@ -335,10 +335,6 @@ static void esp_zb_task(void* pvParameters) { } void zigbee_switch_init() { -#if !defined(CONFIG_ZIGBEE_SWITCH_DEBUG) - esp_log_level_set(TAG, ESP_LOG_NONE); -#endif - esp_zb_platform_config_t config = { .radio_config = ESP_ZB_DEFAULT_RADIO_CONFIG(), .host_config = ESP_ZB_DEFAULT_HOST_CONFIG(), diff --git a/firmware/main/CMakeLists.txt b/firmware/main/CMakeLists.txt index 275add81..326e32da 100644 --- a/firmware/main/CMakeLists.txt +++ b/firmware/main/CMakeLists.txt @@ -1,73 +1,31 @@ -set(modules "modules/led_events/led_events.c" - "modules/keyboard/keyboard_module.c" - "modules/menu_screens/menu_screens_modules.c" - "modules/oled_screen/oled_screen.c" - "modules/settings/settings_module.c" - "modules/settings/sd_card/sd_card_settings_module.c" - "modules/settings/sd_card/sd_card_settings_screens_module.c" - "modules/wifi/wifi_module.c" - "modules/wifi/wifi_screens_module.c" - "modules/zigbee/zigbee_module.c" - "modules/zigbee/zigbee_screens_module.c" - "modules/ble/ble_module.c" - "modules/ble/ble_screens_module.c" - "modules/open_thread/open_thread_module.c" - "modules/open_thread/open_thread_screens_module.c" - "modules/ota/ota_module.c" - "modules/ota/ota_module_screens.c" - "modules/cat_dos/catdos_module.c" - "modules/cat_dos/cat_console.c" - "modules/cat_dos/cmd_catdos.c" - "modules/gps/gps_module.c" - "modules/gps/wardriving/wardriving_module.c" - "modules/gps/wardriving/wardriving_screens_module.c" - "modules/web_file_browser/http_server/web_file_browser.c" - "modules/web_file_browser/web_file_browser_module.c" - "modules/web_file_browser/web_file_browser_screens.c" - "modules/animations_task/animations_task.c" - "apps/thread_sniffer/thread_sniffer.c" - "apps/thread_sniffer/thread_sniffer_screens.c" - "apps/wifi/deauth/deauth_module.c" - "apps/wifi/deauth/deauth_screens.c" - "modules/settings/wifi/wifi_settings.c" - "modules/settings/display/display_settings.c") +file(GLOB_RECURSE ALL_SOURCE_FILES "./*") +set(modules_src "") -set(drivers "drivers/oled_driver/oled_driver.c" - "drivers/oled_driver/oled_driver_i2c.c" - "drivers/oled_driver/oled_driver_spi.c") + foreach(file ${ALL_SOURCE_FILES}) + get_filename_component(extension ${file} EXT) + if(NOT extension STREQUAL "") + list(APPEND modules_src ${file}) + endif() + endforeach() + + file(GLOB_RECURSE ALL_INCLUDE_PATHS "./*") + set(headers_dirs "") + + foreach(path ${ALL_INCLUDE_PATHS}) + get_filename_component(parentDir ${path} DIRECTORY) + + if(IS_DIRECTORY ${parentDir}) + list(APPEND headers_dirs ${parentDir}) + endif() + endforeach() idf_component_register( SRCS - "main.c" - "${modules}" - "${drivers}" + "${modules_src}" EMBED_FILES modules/web_file_browser/http_server/header.html modules/web_file_browser/http_server/favicon_b.ico modules/web_file_browser/http_server/style.css INCLUDE_DIRS - "." - "modules/animations_task" - "modules/keyboard/" - "modules/menu_screens/" - "drivers/oled_driver/" - "modules/oled_screen/" - "modules/settings/" - "modules/settings/sd_card" - "modules/settings/wifi/" - "modules/settings/display/" - "modules/wifi/" - "modules/ble/" - "modules/zigbee/" - "modules/led_events" - "modules/open_thread" - "modules/web_file_browser/http_server" - "modules/web_file_browser" - "modules/ota" - "modules/cat_dos/" - "modules/gps" - "modules/gps/wardriving" - "apps/thread_sniffer" - "apps/wifi/deauth" - "general/") + "${headers_dirs}") # # Append all directories to INCLUDE_DIRS diff --git a/firmware/main/Kconfig.projbuild b/firmware/main/Kconfig.projbuild index 6839ecd5..438195ca 100644 --- a/firmware/main/Kconfig.projbuild +++ b/firmware/main/Kconfig.projbuild @@ -562,3 +562,158 @@ menu "Frequency Configuration" default 13 if EXAMPLE_MIN_CPU_FREQ_13M default 32 if EXAMPLE_MIN_CPU_FREQ_32M endmenu + +menu "Apps & Features" +################################# WIFI ################################### +config WIFI_APPS_ENABLE + bool "Enable WiFi Apps" + default true + help + Enable or disable all WiFi applications. + +if WIFI_APPS_ENABLE + +config WIFI_APP_ANALYZER + bool "Enable Analyzer App" + default true + help + Enable or disable the WiFi Analyzer application. + +config WIFI_APP_DEAUTH + bool "Enable Deauth App" + default true + help + Enable or disable the WiFi Deauth application. + +config WIFI_APP_DOS + bool "Enable DoS App" + default true + help + Enable or disable the WiFi DoS application. + +endif # WIFI_APPS_ENABLE + +############################### BLUETOOTH ################################# + +config BLUETOOTH_APPS_ENABLE + bool "Enable Bluetooth Apps" + default true + help + Enable or disable all Bluetooth applications. + +if BLUETOOTH_APPS_ENABLE + +config BLUETOOTH_APP_TRAKERS + bool "Enable Trakers App" + default true + help + Enable or disable the Bluetooth Trakers application. + +config BLUETOOTH_APP_SPAM + bool "Enable Spam App" + default true + help + Enable or disable the Bluetooth Spam application. + +config BLUETOOTH_APP_HID + bool "Enable HID App" + default true + help + Enable or disable the Bluetooth HID application. +endif # BLUETOOTH_APPS_ENABLE + +################################# ZIGBEE ################################### + +config ZIGBEE_APPS_ENABLE + bool "Enable Zigbee Apps" + default true + help + Enable or disable all Zigbee applications. + +if ZIGBEE_APPS_ENABLE + +config ZIGBEE_APP_SPOOFING + bool "Enable Spoofing App" + default true + help + Enable or disable the Zigbee Spoofing application. + +config ZIGBEE_APP_SNIFFER + bool "Enable Sniffer App" + default true + help + Enable or disable the Zigbee Sniffer application. +endif # ZIGBEE_APPS_ENABLE + +################################# THREAD ################################### + +config THREAD_APPS_ENABLE + bool "Enable Thread Apps" + default true + help + Enable or disable all Thread applications. + +if THREAD_APPS_ENABLE + +config THREAD_APP_BROADCAST + bool "Enable Boradcast App" + default true + help + Enable or disable the Thread Broadcast application. + +config THREAD_APP_SNIFFER + bool "Enable Sniffer App" + default true + help + Enable or disable the Thread Sniffer application. +endif # THREAD_APPS_ENABLE + +################################# GPS ################################### + +config GPS_APPS_ENABLE + bool "Enable GPS Apps" + default true + help + Enable or disable all GPS applications. + +if GPS_APPS_ENABLE + +config GPS_APP_WARDRIVING + bool "Enable Wardriving App" + default true + help + Enable or disable the GPS Wardriving application. +endif # GPS_APPS_ENABLE + +################################# OTA ################################### + +config OTA_ENABLE + bool "Enable OTA feature" + default true + help + Enable or disable OTA feature. + +########################### FILE MANAGER ############################# + +config FILE_MANAGER_ENABLE + bool "Enable File Manager Features" + default true + help + Enable or disable all File Manager Features. + +if FILE_MANAGER_ENABLE + +config FILE_MANAGER_LOCAL + bool "Enable Local File Manager" + default true + help + Enable or disable the Local File Manager feature. + +config FILE_MANAGER_WEB + bool "Enable Web File Manager" + default true + help + Enable or disable the Web File Manager Feature. +endif # FILE_MANAGER_ENABLE + +endmenu \ No newline at end of file diff --git a/firmware/main/apps/ble/hid_device/hid_module.c b/firmware/main/apps/ble/hid_device/hid_module.c new file mode 100644 index 00000000..3b053244 --- /dev/null +++ b/firmware/main/apps/ble/hid_device/hid_module.c @@ -0,0 +1,121 @@ +#include "apps/ble/hid_device/hid_module.h" +#include "apps/ble/hid_device/hid_screens.h" +#include "ble_hidd_main.h" +#include "esp_log.h" +#include "esp_mac.h" +#include "menus_module.h" + +static uint16_t current_item = 0; + +static void hid_module_cb_event(uint8_t button_name, uint8_t button_event); +static void hid_module_cb_event_volumen(uint8_t button_name, + uint8_t button_event); +static void hid_module_cb_connection_handler(bool connection); + +static void hid_module_reset_menu() { + current_item = 0; + hid_module_register_menu(GENERAL_TREE_APP_MENU); + hid_module_display_menu(current_item); + menus_module_set_app_state(true, hid_module_cb_event); +} + +static void hid_module_cb_connection_handler(bool connection) { + hid_module_display_device_connection(connection); + if (!connection) { + // esp_restart(); + } +} + +static void hid_module_cb_event_volumen(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + current_item = current_item-- == 0 ? HID_DEVICE_COUNT - 1 : current_item; + hid_module_display_menu(current_item); + break; + case BUTTON_DOWN: + current_item = ++current_item > HID_DEVICE_COUNT - 1 ? 0 : current_item; + hid_module_display_menu(current_item); + break; + case BUTTON_LEFT: + current_item = 0; + hid_module_register_menu(GENERAL_TREE_APP_MENU); + hid_module_display_menu(current_item); + menus_module_set_app_state(true, hid_module_cb_event); + break; + case BUTTON_RIGHT: + if (current_item == HID_DEVICE_VOL_UP) { + ble_hid_volume_up(true); + ble_hid_volume_up(false); + hid_module_display_notify_volumen_up(); + } else if (current_item == HID_DEVICE_VOL_DOWN) { + ble_hid_volume_down(true); + ble_hid_volume_down(false); + hid_module_display_notify_volumen_down(); + } else if (current_item == HID_DEVICE_PLAY) { + ble_hid_play(true); + ble_hid_play(false); + hid_module_display_notify_play_pause(); + } + break; + default: + break; + } +} + +static void hid_module_cb_event(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + current_item = current_item-- == 0 ? HID_MENU_COUNT - 1 : current_item; + hid_module_display_menu(current_item); + break; + case BUTTON_DOWN: + current_item = ++current_item > HID_MENU_COUNT - 1 ? 0 : current_item; + hid_module_display_menu(current_item); + break; + case BUTTON_RIGHT: + if (current_item == HID_CONFIG_NAME) { + current_item = 0; + char* hid_name[20]; + ble_hid_get_device_name(&hid_name); + general_screen_display_card_information_handler( + "Device Name", &hid_name, hid_module_reset_menu, + hid_module_cb_event); + } else if (current_item == HID_CONFIG_MAC) { + current_item = 0; + uint8_t hid_mac[8] = {0}; + esp_read_mac(hid_mac, ESP_MAC_BT); + char mac_address[20]; + sprintf(mac_address, "%02X:%02X:%02X:%02X", hid_mac[2], hid_mac[3], + hid_mac[4], hid_mac[5]); + general_screen_display_card_information_handler( + "Device MAC", &mac_address, hid_module_reset_menu, + hid_module_cb_event); + } else if (current_item == HID_CONFIG_START) { + current_item = 0; + hid_module_register_menu(GENERAL_TREE_APP_SUBMENU); + hid_module_display_device_pairing(); + ble_hid_register_callback(hid_module_cb_connection_handler); + ble_hid_begin(); + menus_module_set_app_state(true, hid_module_cb_event_volumen); + } + break; + case BUTTON_LEFT: + menus_module_restart(); + break; + default: + break; + } +} + +void hid_module_begin() { + hid_module_register_menu(GENERAL_TREE_APP_MENU); + hid_module_display_menu(current_item); + menus_module_set_app_state(true, hid_module_cb_event); +} diff --git a/firmware/main/apps/ble/hid_device/hid_module.h b/firmware/main/apps/ble/hid_device/hid_module.h new file mode 100644 index 00000000..dd6c2afb --- /dev/null +++ b/firmware/main/apps/ble/hid_device/hid_module.h @@ -0,0 +1,5 @@ +#include +#ifndef HID_MODULE_H + #define HID_MODULE_H +void hid_module_begin(); +#endif // HID_MODULE_H diff --git a/firmware/main/apps/ble/hid_device/hid_screens.c b/firmware/main/apps/ble/hid_device/hid_screens.c new file mode 100644 index 00000000..413f3aa8 --- /dev/null +++ b/firmware/main/apps/ble/hid_device/hid_screens.c @@ -0,0 +1,95 @@ +#include "hid_screens.h" +#include +#include +#include "animations_task.h" +#include "freertos/FreeRTOS.h" +#include "general/bitmaps_general.h" +#include "led_events.h" +#include "oled_screen.h" + +static uint16_t hid_current_item = 0; + +static const general_menu_t hid_menu = { + .menu_items = hid_menu_items, + .menu_count = HID_MENU_COUNT, + .menu_level = GENERAL_TREE_APP_MENU, +}; + +static const general_menu_t hid_device_menu = { + .menu_items = hid_device_items, + .menu_count = HID_DEVICE_COUNT, + .menu_level = GENERAL_TREE_APP_SUBMENU, +}; + +void hid_module_register_menu(menu_tree_t menu) { + switch (menu) { + case GENERAL_TREE_APP_MENU: + general_register_menu(&hid_menu); + break; + case GENERAL_TREE_APP_SUBMENU: + general_register_menu(&hid_device_menu); + break; + default: + general_register_menu(&hid_menu); + break; + } +} + +void hid_module_display_device_information(char* title, char* body) { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_card_information(title, body); +} + +void hid_module_display_notify_volumen_up() { + led_control_run_effect(led_control_pulse_led_right); + genera_screen_display_notify_information("Notify", "Volumen Up"); + vTaskDelay(500 / portTICK_PERIOD_MS); + general_screen_display_menu(hid_current_item); +} + +void hid_module_display_notify_volumen_down() { + led_control_run_effect(led_control_pulse_led_left); + genera_screen_display_notify_information("Notify", "Volumen Down"); + vTaskDelay(500 / portTICK_PERIOD_MS); + general_screen_display_menu(hid_current_item); +} + +void hid_module_display_notify_play_pause() { + led_control_run_effect(led_control_ble_tracking); + genera_screen_display_notify_information("Notify", "Play/Pause"); + vTaskDelay(500 / portTICK_PERIOD_MS); + general_screen_display_menu(hid_current_item); +} + +void hid_module_display_device_pairing() { + led_control_run_effect(led_control_ble_spam_breathing); + genera_screen_display_notify_information("Pairing", "Waiting for connection"); +} + +void hid_module_display_device_connection(bool status) { + led_control_stop(); + if (status) { + genera_screen_display_notify_information("Notify", "Connected"); + } else { + general_register_menu(&hid_menu); + genera_screen_display_notify_information("Notify", "Disconnected"); + } + vTaskDelay(1000 / portTICK_PERIOD_MS); + hid_current_item = 0; + general_screen_display_menu(hid_current_item); +} + +void hid_module_display_device_name() { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_card_information("HID Device", "HIDNAME"); +} +void hid_module_display_device_mac() { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_card_information("HID Device", "MACADDD"); +} + +void hid_module_display_menu(uint16_t current_item) { + led_control_run_effect(led_control_pulse_leds); + hid_current_item = current_item; + general_screen_display_menu(current_item); +} \ No newline at end of file diff --git a/firmware/main/apps/ble/hid_device/hid_screens.h b/firmware/main/apps/ble/hid_device/hid_screens.h new file mode 100644 index 00000000..77d1c839 --- /dev/null +++ b/firmware/main/apps/ble/hid_device/hid_screens.h @@ -0,0 +1,38 @@ +#include +#include +#include "general/general_screens.h" +#ifndef HID_SCREENS_H + #define HID_SCREENS_H + +enum { + HID_CONFIG_NAME, + HID_CONFIG_MAC, + HID_CONFIG_START, + HID_MENU_COUNT +} hid_menu_item = HID_CONFIG_NAME; +char* hid_menu_items[HID_MENU_COUNT] = {"Device name", "Device MAC", "Start"}; + +enum { + HID_DEVICE_VOL_UP, + HID_DEVICE_VOL_DOWN, + HID_DEVICE_PLAY, + HID_DEVICE_COUNT +} hid_device_item = HID_DEVICE_VOL_UP; +char* hid_device_items[HID_DEVICE_COUNT] = { + "Volumen Up", + "Volumen Down", + "Play/Pause", +}; + +void hid_module_register_menu(menu_tree_t menu); +void hid_clear_screen(); +void hid_module_display_menu(uint16_t current_item); +void hid_module_display_device_name(); +void hid_module_display_device_mac(); +void hid_module_display_notify_volumen_up(); +void hid_module_display_notify_volumen_down(); +void hid_module_display_notify_play_pause(); +void hid_module_display_device_connection(bool status); +void hid_module_display_device_pairing(); +void hid_module_display_device_information(char* title, char* body); +#endif // HID_SCREENS_H diff --git a/firmware/main/apps/ble/spam/spam_module.c b/firmware/main/apps/ble/spam/spam_module.c new file mode 100644 index 00000000..7b4994c8 --- /dev/null +++ b/firmware/main/apps/ble/spam/spam_module.c @@ -0,0 +1,43 @@ +#include "apps/ble/spam/spam_module.h" +#include "animations_task.h" +#include "apps/ble/spam/spam_screens.h" +#include "bt_spam.h" +#include "esp_log.h" +#include "led_events.h" +#include "menus_module.h" +#include "oled_screen.h" + +static void ble_module_state_machine(uint8_t button_name, uint8_t button_event); + +static void ble_module_state_machine(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN && + button_event != BUTTON_LONG_PRESS_HOLD) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + bt_spam_app_stop(); + menus_module_set_app_state(false, NULL); + animations_task_stop(); + menus_module_restart(); + break; + case BUTTON_RIGHT: + case BUTTON_UP: + case BUTTON_DOWN: + case BUTTON_BOOT: + default: + break; + } +} + +void ble_module_begin() { +#if !defined(CONFIG_BLE_MODULE_DEBUG) + esp_log_level_set(TAG_BLE_MODULE, ESP_LOG_NONE); +#endif + menus_module_set_app_state(true, ble_module_state_machine); + oled_screen_clear(); + ble_screens_start_scanning_animation(); + bt_spam_register_cb(ble_screens_display_scanning_text); + bt_spam_app_main(); +}; \ No newline at end of file diff --git a/firmware/main/apps/ble/spam/spam_module.h b/firmware/main/apps/ble/spam/spam_module.h new file mode 100644 index 00000000..a32fd0e5 --- /dev/null +++ b/firmware/main/apps/ble/spam/spam_module.h @@ -0,0 +1,11 @@ + +#ifndef SPAM_MODULE_H +#define SPAM_MODULE_H +#define TAG_BLE_MODULE "ble_module:main" + +/** + * @brief Begin the bluetooth module + * + */ +void ble_module_begin(); +#endif // SPAM_MODULE_H diff --git a/firmware/main/apps/ble/spam/spam_screens.c b/firmware/main/apps/ble/spam/spam_screens.c new file mode 100644 index 00000000..f7c1877d --- /dev/null +++ b/firmware/main/apps/ble/spam/spam_screens.c @@ -0,0 +1,22 @@ +#include "spam_screens.h" +#include +#include "animations_task.h" +#include "oled_screen.h" + +static void ble_screens_display_scanning_animation() { + static uint8_t frame = 0; + oled_screen_display_bitmap(ble_bitmap_scan_attack_allArray[frame], 0, 16, 128, + 32, OLED_DISPLAY_NORMAL); + frame = ++frame > 3 ? 0 : frame; +} + +void ble_screens_start_scanning_animation() { + oled_screen_clear(); + oled_screen_display_text_center("BLE SPAM", 0, OLED_DISPLAY_NORMAL); + animations_task_run(ble_screens_display_scanning_animation, 100, NULL); +} + +void ble_screens_display_scanning_text(char* name) { + oled_screen_clear_line(0, 7, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center(name, 7, OLED_DISPLAY_INVERT); +} diff --git a/firmware/main/modules/ble/ble_bitmaps.h b/firmware/main/apps/ble/spam/spam_screens.h similarity index 98% rename from firmware/main/modules/ble/ble_bitmaps.h rename to firmware/main/apps/ble/spam/spam_screens.h index 07240bde..a161586e 100644 --- a/firmware/main/modules/ble/ble_bitmaps.h +++ b/firmware/main/apps/ble/spam/spam_screens.h @@ -1,5 +1,6 @@ -#ifndef BLE_BITMAPS_H -#define BLE_BITMAPS_H +#ifndef SPAM_SCREENS_H +#define SPAM_SCREENS_H + // 'ble_loading-2', 128x32px unsigned char ble_bitmap_ble_loading_2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -188,4 +189,7 @@ unsigned char* ble_bitmap_scan_attack_allArray[4] = { ble_bitmap_ble_loading_1, ble_bitmap_ble_loading_2, ble_bitmap_ble_loading_3, ble_bitmap_ble_loading_4}; -#endif // BLE_BITMAPS_H +void ble_screens_start_scanning_animation(); +void ble_screens_display_scanning_text(char* name); +void ble_screens_display_ble_spam(); +#endif // SPAM_SCREENS_H diff --git a/firmware/main/apps/ble/trackers/trackers_module.c b/firmware/main/apps/ble/trackers/trackers_module.c new file mode 100644 index 00000000..1f841565 --- /dev/null +++ b/firmware/main/apps/ble/trackers/trackers_module.c @@ -0,0 +1,152 @@ +#include "apps/ble/trackers/trackers_module.h" +#include "apps/ble/trackers/trackers_screens.h" +#include "esp_log.h" +#include "menus_module.h" +#include "trackers_scanner.h" + +static uint16_t current_item = 0; +static uint16_t trackers_count = 0; +static bool trackers_scanned = false; +static tracker_profile_t* scanned_airtags = NULL; +char* tracker_information[4] = { + NULL, + NULL, + "MAC ADDRS", + NULL, +}; + +static const general_menu_t trackers_information = { + .menu_items = tracker_information, + .menu_count = 4, + .menu_level = GENERAL_TREE_APP_INFORMATION, +}; + +static void module_main_cb_event(uint8_t button_name, uint8_t button_event); +static void module_list_cb_event(uint8_t button_name, uint8_t button_event); + +static void module_reset_menu() { + current_item = 0; + module_register_menu(GENERAL_TREE_APP_SUBMENU); + module_display_menu(current_item); + menus_module_set_app_state(true, module_list_cb_event); +} + +static void module_handle_trackers(tracker_profile_t record) { + int device_exists = trackers_scanner_find_profile_by_mac( + scanned_airtags, trackers_count, record.mac_address); + if (device_exists == -1) { + if (scanned_airtags == NULL) { + module_register_menu(GENERAL_TREE_APP_MENU); + } + module_add_tracker_to_list(record.name); + module_display_device_detected(record.name); + trackers_scanner_add_tracker_profile(&scanned_airtags, &trackers_count, + record); + } else { + scanned_airtags[device_exists].rssi = record.rssi; + module_update_tracker_name(scanned_airtags[device_exists].name, + device_exists); + } +} + +static void module_main_cb_event(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + current_item = current_item-- == 0 ? TRACKERS_COUNT - 1 : current_item; + module_display_menu(current_item); + break; + case BUTTON_DOWN: + current_item = ++current_item > TRACKERS_COUNT - 1 ? 0 : current_item; + module_display_menu(current_item); + break; + case BUTTON_RIGHT: + if (current_item == TRACKERS_SCAN && !trackers_scanned) { + trackers_scanned = true; + module_update_scan_state(trackers_scanned); + module_display_scanning(); + trackers_scanner_register_cb(module_handle_trackers); + trackers_scanner_start(); + } else if (current_item == TRACKERS_LIST) { + current_item = 0; + module_register_menu(GENERAL_TREE_APP_SUBMENU); + module_display_menu(current_item); + menus_module_set_app_state(true, module_list_cb_event); + } + break; + case BUTTON_LEFT: + if (current_item == TRACKERS_LIST) { + module_register_menu(GENERAL_TREE_APP_MENU); + module_display_menu(current_item); + menus_module_set_app_state(true, module_main_cb_event); + } else { + menus_module_restart(); + } + break; + default: + break; + } +} + +static void module_list_cb_event(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + + switch (button_name) { + case BUTTON_UP: + current_item = current_item-- == 0 ? TRACKERS_COUNT - 1 : current_item; + module_display_menu(current_item); + break; + case BUTTON_DOWN: + current_item = ++current_item > TRACKERS_COUNT - 1 ? 0 : current_item; + module_display_menu(current_item); + break; + case BUTTON_RIGHT: + char tracker_mac[18]; + snprintf(tracker_mac, sizeof(tracker_mac), "%02X:%02X:%02X:%02X:%02X", + scanned_airtags[current_item].mac_address[1], + scanned_airtags[current_item].mac_address[2], + scanned_airtags[current_item].mac_address[3], + scanned_airtags[current_item].mac_address[4], + scanned_airtags[current_item].mac_address[5]); + char tracker_rssi[18]; + snprintf(tracker_rssi, sizeof(tracker_rssi), "RSSI: %d", + scanned_airtags[current_item].rssi); + char tracker_name[18]; + snprintf(tracker_name, sizeof(tracker_name), "Name: %s", + scanned_airtags[current_item].name); + tracker_information[0] = malloc(strlen(tracker_name) + 1); + strcpy(tracker_information[0], tracker_name); + tracker_information[1] = malloc(strlen(tracker_rssi) + 1); + strcpy(tracker_information[1], tracker_rssi); + tracker_information[3] = malloc(strlen(tracker_mac) + 1); + strcpy(tracker_information[3], tracker_mac); + general_register_scrolling_menu(&trackers_information); + general_screen_display_scrolling_text_handler(module_reset_menu); + break; + case BUTTON_LEFT: + if (tracker_information[0] != NULL) { + free(tracker_information[0]); + free(tracker_information[1]); + free(tracker_information[3]); + tracker_information[0] = NULL; + tracker_information[1] = NULL; + tracker_information[3] = NULL; + } + menus_module_set_app_state(true, module_main_cb_event); + module_register_menu(GENERAL_TREE_APP_MENU); + module_display_menu(current_item); + break; + default: + break; + } +} + +void trackers_module_begin() { + module_register_menu(GENERAL_TREE_APP_MENU); + module_display_menu(current_item); + menus_module_set_app_state(true, module_main_cb_event); +} diff --git a/firmware/main/apps/ble/trackers/trackers_module.h b/firmware/main/apps/ble/trackers/trackers_module.h new file mode 100644 index 00000000..1f3a025b --- /dev/null +++ b/firmware/main/apps/ble/trackers/trackers_module.h @@ -0,0 +1,5 @@ +#include +#ifndef TRACKERS_MODULE_H + #define TRACKERS_MODULE_H +void trackers_module_begin(); +#endif // TRACKERS_MODULE_H diff --git a/firmware/main/apps/ble/trackers/trackers_screens.c b/firmware/main/apps/ble/trackers/trackers_screens.c new file mode 100644 index 00000000..3da54fb3 --- /dev/null +++ b/firmware/main/apps/ble/trackers/trackers_screens.c @@ -0,0 +1,76 @@ +#include "trackers_screens.h" +#include +#include +#include "animations_task.h" +#include "freertos/FreeRTOS.h" +#include "general/bitmaps_general.h" +#include "general/general_screens.h" +#include "led_events.h" +#include "oled_screen.h" + +static uint16_t hid_current_item = 0; +static uint16_t trackers_current_item = 0; +static char* list_trackers[20]; + +static const general_menu_t main_menu = { + .menu_items = trackers_menu_items, + .menu_count = TRACKERS_COUNT, + .menu_level = GENERAL_TREE_APP_MENU, +}; + +static general_menu_t trackers_list = { + .menu_items = list_trackers, + .menu_count = 20, + .menu_level = GENERAL_TREE_APP_SUBMENU, +}; + +void module_register_menu(menu_tree_t menu) { + switch (menu) { + case GENERAL_TREE_APP_MENU: + general_register_menu(&main_menu); + break; + case GENERAL_TREE_APP_SUBMENU: + general_register_menu(&trackers_list); + break; + default: + general_register_menu(&main_menu); + break; + } +} + +void module_add_tracker_to_list(char* tracker_name) { + list_trackers[trackers_current_item] = tracker_name; + trackers_current_item++; + trackers_list.menu_count = trackers_current_item; +} + +void module_update_scan_state(bool scanning) { + trackers_menu_items[TRACKERS_SCAN] = scanning ? "SCANNING" : "SCAN"; +} + +void module_update_tracker_name(char* tracker_name, uint16_t index) { + list_trackers[index] = tracker_name; +} + +void module_display_scanning() { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_notify_information("Searching", "Looking for devices"); +} + +void module_display_tracker_information(char* title, char* body) { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_card_information(title, body); +} + +void module_display_device_detected(char* device_name) { + led_control_run_effect(led_control_pulse_leds); + genera_screen_display_notify_information("Device found", device_name); + vTaskDelay(500 / portTICK_PERIOD_MS); + general_screen_display_menu(hid_current_item); +} + +void module_display_menu(uint16_t current_item) { + led_control_run_effect(led_control_pulse_leds); + hid_current_item = current_item; + general_screen_display_menu(current_item); +} \ No newline at end of file diff --git a/firmware/main/apps/ble/trackers/trackers_screens.h b/firmware/main/apps/ble/trackers/trackers_screens.h new file mode 100644 index 00000000..35ca2110 --- /dev/null +++ b/firmware/main/apps/ble/trackers/trackers_screens.h @@ -0,0 +1,24 @@ +#include +#include +#include "general/general_screens.h" +#ifndef TRACKERS_SCREENS_H + #define TRACKERS_SCREENS_H + +enum { + TRACKERS_SCAN, + TRACKERS_LIST, + TRACKERS_COUNT +} trackers_menu_item = TRACKERS_SCAN; +char* trackers_menu_items[TRACKERS_COUNT] = {"SCAN", "LIST"}; + +void clear_screen(); +void module_register_menu(menu_tree_t menu); +void module_display_menu(uint16_t current_item); + +void module_display_scanning(); +void module_display_device_detected(char* device_name); +void module_display_tracker_information(char* title, char* body); +void module_update_scan_state(bool scanning); +void module_add_tracker_to_list(char* tracker_name); +void module_update_tracker_name(char* tracker_name, uint16_t index); +#endif // TRACKERS_SCREENS_H diff --git a/firmware/main/apps/wifi/deauth/deauth_module.c b/firmware/main/apps/wifi/deauth/deauth_module.c index 680ba487..e62058a0 100644 --- a/firmware/main/apps/wifi/deauth/deauth_module.c +++ b/firmware/main/apps/wifi/deauth/deauth_module.c @@ -6,13 +6,13 @@ #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "led_events.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "wifi_attacks.h" #include "wifi_controller.h" #include "wifi_scanner.h" #define DEFAULT_SCAN_LIST_SIZE CONFIG_SCAN_MAX_AP -#define SCAN_RETRIES 10 +#define SCAN_RETRIES 5 typedef enum { DEAUTH_STATE_IDLE = 0, @@ -64,12 +64,12 @@ static void scanning_task(void* pvParameters) { ap_records = wifi_scanner_get_ap_records(); menu_stadistics.count = ap_records->count; animations_task_stop(); - led_control_stop(); + + ESP_LOGI("deauth", "Scanning done: %d", ap_records->count); deauth_display_menu(current_item, menu_stadistics); current_wifi_state.state = DEAUTH_STATE_MENU; - vTaskDelete(NULL); - led_control_stop(); + vTaskDelete(NULL); } static void deauth_run_scan_task() { @@ -89,17 +89,18 @@ static void deauth_handle_attacks() { case ROGUE_AP: case COMBINED: ESP_LOGI("deauth", "Attack: %d", menu_stadistics.attack); + deauth_display_attaking_text(); animations_task_run(&deauth_display_attacking_animation, 200, NULL); ESP_LOGI("deauth", "Attack: %d", menu_stadistics.attack); wifi_attack_handle_attacks(menu_stadistics.attack, &menu_stadistics.selected_ap); ESP_LOGI("deauth", "Attack: %d", menu_stadistics.attack); - menu_screens_set_app_state(true, deauth_module_cb_event_run); + menus_module_set_app_state(true, deauth_module_cb_event_run); current_item = 0; break; case CAPTIVEPORTAL: current_item = 0; - menu_screens_set_app_state(true, deauth_module_cb_event_captive_portal); + menus_module_set_app_state(true, deauth_module_cb_event_captive_portal); deauth_display_captive_portals(current_item, menu_stadistics); break; default: @@ -117,6 +118,7 @@ static void deauth_decrement_item() { void deauth_module_begin() { deauth_clear_screen(); + deauth_display_scanning_text(); animations_task_run(&deauth_display_scanning, 200, NULL); current_wifi_state.state = DEAUTH_STATE_IDLE; @@ -127,7 +129,7 @@ void deauth_module_begin() { xTaskCreate(scanning_task, "wifi_scan", 4096, NULL, 5, NULL); deauth_run_scan_task(); - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); menu_stadistics.attack = 99; @@ -144,39 +146,35 @@ static void deauth_module_cb_event(uint8_t button_name, uint8_t button_event) { switch (button_name) { case BUTTON_UP: - deauth_decrement_item(); - if (current_item < 0) { - current_item = MENUCOUNT - 1; - } + current_item = current_item-- == 0 ? MENUCOUNT - 1 : current_item; deauth_display_menu(current_item, menu_stadistics); break; case BUTTON_DOWN: - deauth_increment_item(); - if (current_item > MENUCOUNT - 1) { - current_item = 0; - } + current_item = ++current_item > MENUCOUNT - 1 ? 0 : current_item; deauth_display_menu(current_item, menu_stadistics); break; case BUTTON_RIGHT: switch (current_item) { case SCAN: + current_wifi_state.state = DEAUTH_STATE_IDLE; wifi_scanner_clear_ap_records(); deauth_clear_screen(); + deauth_display_scanning_text(); animations_task_run(&deauth_display_scanning, 200, NULL); xTaskCreate(scanning_task, "wifi_scan", 4096, NULL, 5, NULL); deauth_run_scan_task(); - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); current_item = 0; break; case SELECT: current_item = 0; - menu_screens_set_app_state(true, deauth_module_cb_event_select_ap); + menus_module_set_app_state(true, deauth_module_cb_event_select_ap); deauth_display_scanned_ap(ap_records->records, ap_records->count, current_item); break; case DEAUTH: current_item = 0; - menu_screens_set_app_state(true, deauth_module_cb_event_attacks); + menus_module_set_app_state(true, deauth_module_cb_event_attacks); deauth_display_attacks(current_item, menu_stadistics); break; case RUN: @@ -203,8 +201,7 @@ static void deauth_module_cb_event(uint8_t button_name, uint8_t button_event) { case BUTTON_LEFT: wifi_scanner_clear_ap_records(); printf("Exit deauth: %d\n", current_item); - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_restart(); // led_control_stop(); break; default: @@ -219,30 +216,24 @@ static void deauth_module_cb_event_select_ap(uint8_t button_name, } switch (button_name) { case BUTTON_UP: - deauth_decrement_item(); - if (current_item < 0) { - current_item = ap_records->count; - } + current_item = current_item-- == 0 ? ap_records->count - 1 : current_item; deauth_display_scanned_ap(ap_records->records, ap_records->count, current_item); break; case BUTTON_DOWN: - deauth_increment_item(); - if (current_item > ap_records->count) { - current_item = 0; - } + current_item = ++current_item > ap_records->count - 1 ? 0 : current_item; deauth_display_scanned_ap(ap_records->records, ap_records->count, current_item); break; case BUTTON_RIGHT: menu_stadistics.selected_ap = ap_records->records[current_item]; - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); deauth_display_menu(current_item, menu_stadistics); current_item = 0; break; case BUTTON_LEFT: current_item = 0; - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); deauth_display_menu(current_item, menu_stadistics); break; default: @@ -257,23 +248,23 @@ static void deauth_module_cb_event_attacks(uint8_t button_name, } switch (button_name) { case BUTTON_UP: - deauth_decrement_item(); + current_item = current_item-- == 0 ? ATTACKSCOUNT - 1 : current_item; deauth_display_attacks(current_item, menu_stadistics); break; case BUTTON_DOWN: - deauth_increment_item(); + current_item = ++current_item > ATTACKSCOUNT - 1 ? 0 : current_item; deauth_display_attacks(current_item, menu_stadistics); break; case BUTTON_RIGHT: menu_stadistics.attack = current_item; - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); current_item = 0; deauth_display_menu(current_item, menu_stadistics); break; case BUTTON_LEFT: current_item = 0; - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); deauth_display_menu(current_item, menu_stadistics); break; default: @@ -293,7 +284,7 @@ static void deauth_module_cb_event_run(uint8_t button_name, led_control_stop(); animations_task_stop(); wifi_attacks_module_stop(); - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); deauth_display_menu(current_item, menu_stadistics); break; case BUTTON_UP: @@ -311,23 +302,19 @@ static void deauth_module_cb_event_captive_portal(uint8_t button_name, } switch (button_name) { case BUTTON_UP: - deauth_decrement_item(); - if (current_item < 0) { - current_item = CAPTIVEPORTALCOUNT - 1; - } + current_item = + current_item-- == 0 ? CAPTIVEPORTALCOUNT - 1 : current_item; deauth_display_captive_portals(current_item, menu_stadistics); break; case BUTTON_DOWN: - deauth_increment_item(); - if (current_item > CAPTIVEPORTALCOUNT - 1) { - current_item = 0; - } + current_item = ++current_item > CAPTIVEPORTALCOUNT - 1 ? 0 : current_item; deauth_display_captive_portals(current_item, menu_stadistics); break; case BUTTON_LEFT: current_item = 0; + led_control_stop(); captive_portal_stop(); - menu_screens_set_app_state(true, deauth_module_cb_event); + menus_module_set_app_state(true, deauth_module_cb_event); deauth_display_menu(current_item, menu_stadistics); break; case BUTTON_RIGHT: @@ -338,7 +325,7 @@ static void deauth_module_cb_event_captive_portal(uint8_t button_name, deauth_display_captive_waiting(); xTaskCreate(captive_portal_begin, "captive_portal_start", 4096, NULL, 5, NULL); - menu_screens_set_app_state(true, deauth_module_cb_event_run); + menus_module_set_app_state(true, deauth_module_cb_event_run); current_item = 0; break; default: diff --git a/firmware/main/apps/wifi/deauth/deauth_screens.c b/firmware/main/apps/wifi/deauth/deauth_screens.c index d0ffbd71..7d0b746c 100644 --- a/firmware/main/apps/wifi/deauth/deauth_screens.c +++ b/firmware/main/apps/wifi/deauth/deauth_screens.c @@ -32,6 +32,11 @@ void deauth_display_warning_not_attack_selected() { oled_screen_display_text_center("SELECT AN ATTACK", 2, OLED_DISPLAY_NORMAL); } +void deauth_display_scanning_text() { + oled_screen_clear(); + oled_screen_display_text_center("SCANNING AP", 0, OLED_DISPLAY_NORMAL); +} + void deauth_display_scanning() { oled_screen_display_text_center("SCANNING AP", 0, OLED_DISPLAY_NORMAL); static uint8_t idx = 0; @@ -40,8 +45,12 @@ void deauth_display_scanning() { idx = ++idx > (BITMAPS_WIFI_LOADING_FRAME - 1) ? 0 : idx; } -void deauth_display_attacking_animation() { +void deauth_display_attaking_text() { + oled_screen_clear(); oled_screen_display_text_center("ATTACKING AP", 0, OLED_DISPLAY_NORMAL); +} + +void deauth_display_attacking_animation() { static uint8_t idx = 0; oled_screen_display_bitmap(punch_animation[idx], 48, 16, 32, 32, OLED_DISPLAY_NORMAL); @@ -50,7 +59,7 @@ void deauth_display_attacking_animation() { void deauth_display_menu(uint16_t current_item, menu_stadistics_t menu_stadistics) { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Exit", 0, 0, OLED_DISPLAY_NORMAL); int position = 1; @@ -86,12 +95,13 @@ void deauth_display_menu(uint16_t current_item, } position = position + 2; } + oled_screen_display_show(); } void deauth_display_scanned_ap(wifi_ap_record_t* ap_records, uint16_t scanned_records, uint16_t current_option) { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); ap_count = scanned_records; @@ -113,11 +123,12 @@ void deauth_display_scanned_ap(wifi_ap_record_t* ap_records, (i + 1) - current_option, OLED_DISPLAY_NORMAL); } } + oled_screen_display_show(); } void deauth_display_attacks(uint16_t current_item, menu_stadistics_t menu_stadistics) { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); for (uint16_t i = 0; i < ATTACKSCOUNT; i++) { @@ -136,11 +147,12 @@ void deauth_display_attacks(uint16_t current_item, oled_screen_display_text(item, 0, i + ITEMOFFSET, OLED_DISPLAY_NORMAL); } } + oled_screen_display_show(); } void deauth_display_captive_portals(uint16_t current_item, menu_stadistics_t menu_stadistics) { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); for (uint16_t i = 0; i < CAPTIVEPORTALCOUNT; i++) { @@ -159,6 +171,7 @@ void deauth_display_captive_portals(uint16_t current_item, oled_screen_display_text(item, 0, i + ITEMOFFSET, OLED_DISPLAY_NORMAL); } } + oled_screen_display_show(); } void deauth_display_captive_waiting() { diff --git a/firmware/main/apps/wifi/deauth/deauth_screens.h b/firmware/main/apps/wifi/deauth/deauth_screens.h index 856995b7..36ae51a9 100644 --- a/firmware/main/apps/wifi/deauth/deauth_screens.h +++ b/firmware/main/apps/wifi/deauth/deauth_screens.h @@ -129,7 +129,9 @@ const unsigned char* punch_animation[] = { michi_punch_2, }; +void deauth_display_scanning_text(); void deauth_display_scanning(); +void deauth_display_attaking_text(); void deauth_display_attacking_animation(); void deauth_display_menu(uint16_t current_item, menu_stadistics_t menu_stadistics); diff --git a/firmware/main/apps/zigbee/z_switch/z_switch_module.c b/firmware/main/apps/zigbee/z_switch/z_switch_module.c new file mode 100644 index 00000000..337cf6ea --- /dev/null +++ b/firmware/main/apps/zigbee/z_switch/z_switch_module.c @@ -0,0 +1,51 @@ +#include "apps/zigbee/z_switch/z_switch_module.h" +#include "apps/zigbee/z_switch/z_switch_screens.h" +#include "esp_log.h" +#include "menus_module.h" + +static uint16_t current_item = 0; + +static void z_switch_module_cb_event(uint8_t button_name, uint8_t button_event); +static void z_switch_module_cb_connection_handler(bool connection); + +static void module_reset_menu() { + current_item = 0; + menus_module_set_app_state(true, z_switch_module_cb_event); +} + +static void module_increment_item() { + current_item++; +} + +static void module_decrement_item() { + current_item--; +} + +static void z_switch_module_cb_connection_handler(bool connection) {} + +static void z_switch_module_cb_event(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + break; + case BUTTON_DOWN: + break; + case BUTTON_RIGHT: + break; + case BUTTON_LEFT: + menus_module_restart(); + break; + default: + break; + } +} + +void z_switch_module_begin() { + radio_selector_set_zigbee_switch(); + zigbee_switch_set_display_status_cb(z_switch_handle_connection_status); + zigbee_switch_init(); + menus_module_set_app_state(true, z_switch_module_cb_event); +} diff --git a/firmware/main/apps/zigbee/z_switch/z_switch_module.h b/firmware/main/apps/zigbee/z_switch/z_switch_module.h new file mode 100644 index 00000000..1acc97f0 --- /dev/null +++ b/firmware/main/apps/zigbee/z_switch/z_switch_module.h @@ -0,0 +1,5 @@ +#include +#ifndef Z_SWITCH_MODULE_H + #define Z_SWITCH_MODULE_H +void z_switch_module_begin(); +#endif // Z_SWITCH_MODULE_H diff --git a/firmware/main/apps/zigbee/z_switch/z_switch_screens.c b/firmware/main/apps/zigbee/z_switch/z_switch_screens.c new file mode 100644 index 00000000..37546ca9 --- /dev/null +++ b/firmware/main/apps/zigbee/z_switch/z_switch_screens.c @@ -0,0 +1,43 @@ +#include "z_switch_screens.h" +#include +#include +#include "animations_task.h" +#include "freertos/FreeRTOS.h" +#include "general/bitmaps_general.h" +#include "led_events.h" +#include "oled_screen.h" + +static uint16_t hid_current_item = 0; + +static void z_switch_display_creating_network() { + oled_screen_clear(); + oled_screen_display_text_center("Creating network", 2, OLED_DISPLAY_NORMAL); +} + +static void z_switch_display_waiting_device() { + oled_screen_clear(); + oled_screen_display_text_center("Waiting for devices", 2, + OLED_DISPLAY_NORMAL); +} + +void z_switch_handle_connection_status(uint8_t status) { + switch (status) { + case CREATING_NETWORK: + z_switch_display_creating_network(); + break; + case CREATING_NETWORK_FAILED: + break; + case WAITING_FOR_DEVICES: + z_switch_display_waiting_device(); + break; + case NO_DEVICES_FOUND: + break; + case CLOSING_NETWORK: + break; + case LIGHT_PRESSED: + break; + case LIGHT_RELASED: + default: + break; + } +} \ No newline at end of file diff --git a/firmware/main/apps/zigbee/z_switch/z_switch_screens.h b/firmware/main/apps/zigbee/z_switch/z_switch_screens.h new file mode 100644 index 00000000..2c616315 --- /dev/null +++ b/firmware/main/apps/zigbee/z_switch/z_switch_screens.h @@ -0,0 +1,10 @@ +#include +#include +#include "general/general_screens.h" +#include "radio_selector.h" +#include "zigbee_switch.h" +#ifndef Z_SWITCH_SCREENS_H + #define Z_SWITCH_SCREENS_H + +void z_switch_handle_connection_status(uint8_t status); +#endif // Z_SWITCH_SCREENS_H diff --git a/firmware/main/drivers/oled_driver/oled_driver.c b/firmware/main/drivers/oled_driver/oled_driver.c index 4d62b63b..2828ed4b 100644 --- a/firmware/main/drivers/oled_driver/oled_driver.c +++ b/firmware/main/drivers/oled_driver/oled_driver.c @@ -175,20 +175,17 @@ void oled_driver_display_text_x3(oled_driver_t* dev, } } -void oled_driver_clear_screen(oled_driver_t* dev, bool invert) { - // char space[16]; - // memset(space, 0x00, sizeof(space)); - // for (int page = 0; page < dev->_pages; page++) { - // oled_driver_display_text(dev, page, space, sizeof(space), invert); - // } - - char* space = " "; - int pages = 7; - for (int page = 0; page <= pages; page++) { - oled_driver_display_text(dev, page, space, 0, invert); +void oled_driver_clear_buffer(oled_driver_t* dev) { + for (int i = 0; i < dev->_pages; i++) { + memset(dev->_page[i]._segs, 0, dev->_width); } } +void oled_driver_clear_screen(oled_driver_t* dev, bool invert) { + oled_driver_clear_buffer(dev); + oled_driver_show_buffer(dev); +} + void oled_driver_clear_line(oled_driver_t* dev, int x, int page, bool invert) { // char space[16]; // memset(space, 0x00, sizeof(space)); @@ -496,7 +493,6 @@ void oled_driver_bitmaps(oled_driver_t* dev, _seg++; } } - vTaskDelay(1); offset = offset + _width; dstBits++; _seg = xpos; @@ -756,3 +752,51 @@ void oled_driver_draw_custom_box(oled_driver_t* dev) { // oled_driver_show_buffer(dev); } + +void oled_driver_draw_modal_box(oled_driver_t* dev, + int pos_x, + int modal_height) { +#ifdef CONFIG_RESOLUTION_128X64 + int initial_page = 2; + int height_offset = 35; + int y_offset = 3; +#else + int initial_page = 1; + int height_offset = 18; + int y_offset = 1; +#endif + int page = initial_page; + int x = pos_x; + int y = page * 8 - y_offset; // 13 + int width = x + dev->_width - 4; + int height = y + height_offset; //- 6; // 15 + + oled_driver_draw_rect(dev, x, y, width, height, 0); + oled_driver_draw_rect(dev, x, y, width - 1, height - 1, 0); + + // Top left border + oled_driver_draw_pixel(dev, x, y, 1); + oled_driver_draw_pixel(dev, x + 1, y, 1); + oled_driver_draw_pixel(dev, x, y + 1, 1); + oled_driver_draw_pixel(dev, x + 1, y + 1, 0); + + // Top right border + oled_driver_draw_pixel(dev, width - 1, y, 1); + oled_driver_draw_pixel(dev, width - 2, y, 1); + oled_driver_draw_pixel(dev, width - 1, y + 1, 1); + oled_driver_draw_pixel(dev, width - 2, y + 1, 0); + + // Bottom left border + oled_driver_draw_pixel(dev, x, y + height - 1, 1); + oled_driver_draw_pixel(dev, x + 1, y + height - 1, 1); + oled_driver_draw_pixel(dev, x, y + height - 2, 1); + oled_driver_draw_pixel(dev, x + 1, y + height - 2, 0); + + // Bottom right border + oled_driver_draw_pixel(dev, width - 1, y + height - 1, 1); + oled_driver_draw_pixel(dev, width - 2, y + height - 1, 1); + oled_driver_draw_pixel(dev, width - 1, y + height - 2, 1); + oled_driver_draw_pixel(dev, width - 2, y + height - 2, 0); + + // oled_driver_show_buffer(dev); +} diff --git a/firmware/main/drivers/oled_driver/oled_driver.h b/firmware/main/drivers/oled_driver/oled_driver.h index 248e531b..a7954afa 100644 --- a/firmware/main/drivers/oled_driver/oled_driver.h +++ b/firmware/main/drivers/oled_driver/oled_driver.h @@ -127,6 +127,7 @@ void oled_driver_display_text_x3(oled_driver_t* dev, char* text, int text_len, bool invert); +void oled_driver_clear_buffer(oled_driver_t* dev); void oled_driver_clear_screen(oled_driver_t* dev, bool invert); void oled_driver_clear_line(oled_driver_t* dev, int x, int page, bool invert); void oled_driver_contrast(oled_driver_t* dev, int contrast); @@ -242,7 +243,9 @@ void spi_display_image(oled_driver_t* dev, int width); void spi_contrast(oled_driver_t* dev, int contrast); void spi_hardware_scroll(oled_driver_t* dev, oled_driver_scroll_type_t scroll); - +void oled_driver_draw_modal_box(oled_driver_t* dev, + int pos_x, + int modal_height); #ifdef __cplusplus } #endif diff --git a/firmware/main/general/bitmaps_general.h b/firmware/main/general/bitmaps_general.h index dca0747a..f30fe5d7 100644 --- a/firmware/main/general/bitmaps_general.h +++ b/firmware/main/general/bitmaps_general.h @@ -1,3 +1,8 @@ +#include +#include +#include +#ifndef BITMAPS_GENERAL_H + #define BITMAPS_GENERAL_H // 'FACE', 8x8px const unsigned char minino_face[] = {0x42, 0xe7, 0xff, 0xff, 0x99, 0x99, 0x7e, 0x3c}; @@ -88,42 +93,49 @@ static const unsigned char epd_bitmap_electroniccats[] = { unsigned char* epd_startup_logo[] = {epd_bitmap_minino_text_logo, epd_bitmap_face_logo}; -epd_bitmap_t minino_face_bitmap = { +const epd_bitmap_t minino_face_bitmap = { .bitmap = minino_face, .width = 8, .height = 8, }; -epd_bitmap_t minino_letters_bitmap = { +const epd_bitmap_t minino_letters_bitmap = { .bitmap = epd_bitmap_minino_text_logo, .width = 64, .height = 32, }; -epd_bitmap_t minino_face_logo = { +const epd_bitmap_t minino_face_logo = { .bitmap = epd_bitmap_face_logo, .width = 32, .height = 32, }; -epd_bitmap_t minino_pwnlabs_logo = { +const epd_bitmap_t minino_pwnlabs_logo = { .bitmap = epd_bitmap_pwn_02, .width = 64, .height = 32, }; -epd_bitmap_t minino_electroniccats_logo = { +const epd_bitmap_t minino_electroniccats_logo = { .bitmap = epd_bitmap_electroniccats, .width = 32, .height = 32, }; typedef enum { - MININO_FACE, MININO_LETTERS, + MININO_FACE, MININO_PWNLABS, MININO_ELECTRONICCATS, + MININO_FACE_MINI, MININO_COUNT } epd_bitmap_type_t; -char* epd_bitmaps_list[] = {"Letters", "Face", "PwnLabs", "EC", NULL}; +epd_bitmap_t screen_savers[] = {minino_letters_bitmap, minino_face_logo, + minino_pwnlabs_logo, minino_electroniccats_logo, + minino_face_bitmap}; + +char* epd_bitmaps_list[] = {"Letters", "Face", "PwnLabs", + "EC", "Mini face", NULL}; +#endif // BITMAPS_GENERAL_H \ No newline at end of file diff --git a/firmware/main/general/general_radio_selection/general_radio_selection.c b/firmware/main/general/general_radio_selection/general_radio_selection.c new file mode 100644 index 00000000..a0eb165d --- /dev/null +++ b/firmware/main/general/general_radio_selection/general_radio_selection.c @@ -0,0 +1,120 @@ +#include "general_radio_selection.h" + +#include "bitmaps_general.h" +#include "buzzer.h" +#include "menus_module.h" +#include "oled_screen.h" + +#define MAX_OPTIONS_NUM 6 + +static const uint32_t SOUND_DURATION = 100; +static general_radio_selection_t* general_radio_selection_ctx; + +static void list_radio_options_old_style(); +static void list_radio_options_new_style(); + +static void* list_radio_options_styles[] = {list_radio_options_old_style, + list_radio_options_new_style}; +static void (*list_radio_options)() = NULL; + +static void list_radio_options_old_style() { + general_radio_selection_t* ctx = general_radio_selection_ctx; + static uint8_t items_offset = 0; + items_offset = MAX(ctx->selected_option - 4, items_offset); + items_offset = MIN(MAX(ctx->options_count - 4, 0), items_offset); + items_offset = MIN(ctx->selected_option, items_offset); + oled_screen_clear_buffer(); + char* str = malloc(20); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + for (uint8_t i = 0; i < (MIN(ctx->options_count, MAX_OPTIONS_NUM - 1)); i++) { + bool is_selected = i + items_offset == ctx->selected_option; + bool is_current = i + items_offset == ctx->current_option; + char state = is_current ? 'x' : ' '; + sprintf(str, "[%c] %s", state, ctx->options[i + items_offset]); + oled_screen_display_text(str, 0, i + 2, is_selected); + } + oled_screen_display_show(); + free(str); +} + +static void list_radio_options_new_style() { + general_radio_selection_t* ctx = general_radio_selection_ctx; + static uint8_t items_offset = 0; + items_offset = MAX(ctx->selected_option - 4, items_offset); + items_offset = MIN(MAX(ctx->options_count - 4, 0), items_offset); + items_offset = MIN(ctx->selected_option, items_offset); + oled_screen_clear_buffer(); + char* str = malloc(20); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + for (uint8_t i = 0; i < (MIN(ctx->options_count, MAX_OPTIONS_NUM - 1)); i++) { + bool is_selected = i + items_offset == ctx->selected_option; + bool is_current = i + items_offset == ctx->current_option; + oled_screen_display_bitmap(minino_face, 0, (ctx->selected_option + 2) * 8, + 8, 8, OLED_DISPLAY_NORMAL); + sprintf(str, "%s%s", ctx->options[i + items_offset], + is_current ? "[curr]" : ""); + oled_screen_display_text(str, is_selected ? 16 : 0, i + 2, is_selected); + } + oled_screen_display_show(); + free(str); +} + +static void input_cb(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + void (*exit_cb)() = general_radio_selection_ctx->exit_cb; + if (exit_cb) { + exit_cb(); + } + free(general_radio_selection_ctx); + break; + case BUTTON_RIGHT: + general_radio_selection_ctx->current_option = + general_radio_selection_ctx->selected_option; + void (*select_cb)() = general_radio_selection_ctx->select_cb; + if (select_cb) { + select_cb(general_radio_selection_ctx->current_option); + } + buzzer_play_for(SOUND_DURATION); + list_radio_options(); + break; + case BUTTON_UP: + general_radio_selection_ctx->selected_option = + general_radio_selection_ctx->selected_option == 0 + ? general_radio_selection_ctx->options_count - 1 + : general_radio_selection_ctx->selected_option - 1; + list_radio_options(); + break; + case BUTTON_DOWN: + general_radio_selection_ctx->selected_option = + ++general_radio_selection_ctx->selected_option < + general_radio_selection_ctx->options_count + ? general_radio_selection_ctx->selected_option + : 0; + list_radio_options(); + break; + default: + break; + } +} + +void general_radio_selection( + general_radio_selection_menu_t radio_selection_menu) { + general_radio_selection_ctx = calloc(1, sizeof(general_radio_selection_t)); + general_radio_selection_ctx->options = radio_selection_menu.options; + general_radio_selection_ctx->options_count = + radio_selection_menu.options_count; + general_radio_selection_ctx->banner = radio_selection_menu.banner; + general_radio_selection_ctx->current_option = + radio_selection_menu.current_option; + general_radio_selection_ctx->selected_option = + radio_selection_menu.current_option; + general_radio_selection_ctx->select_cb = radio_selection_menu.select_cb; + general_radio_selection_ctx->exit_cb = radio_selection_menu.exit_cb; + menus_module_set_app_state(true, input_cb); + list_radio_options = list_radio_options_styles[radio_selection_menu.style]; + list_radio_options(); +} \ No newline at end of file diff --git a/firmware/main/general/general_radio_selection/general_radio_selection.h b/firmware/main/general/general_radio_selection/general_radio_selection.h new file mode 100644 index 00000000..5ae566fd --- /dev/null +++ b/firmware/main/general/general_radio_selection/general_radio_selection.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include "general_screens.h" + +typedef void (*radio_selection_handler_t)(uint8_t); + +typedef enum { + RADIO_SELECTION_OLD_STYLE, + RADIO_SELECTION_NEW_STYLE +} radio_selection_style_t; + +typedef struct { + uint8_t selected_option; + uint8_t options_count; + char** options; + char* banner; + uint8_t current_option; + radio_selection_handler_t* select_cb; + void* exit_cb; +} general_radio_selection_t; + +typedef struct { + char** options; + char* banner; + uint8_t current_option; + uint8_t options_count; + radio_selection_handler_t* select_cb; + void* exit_cb; + radio_selection_style_t style; +} general_radio_selection_menu_t; + +void general_radio_selection( + general_radio_selection_menu_t radio_selection_menu); \ No newline at end of file diff --git a/firmware/main/general/general_screens.c b/firmware/main/general/general_screens.c new file mode 100644 index 00000000..46908ad0 --- /dev/null +++ b/firmware/main/general/general_screens.c @@ -0,0 +1,259 @@ +#include "general/general_screens.h" +#include "general/bitmaps_general.h" +#include "menus_module.h" +#include "oled_screen.h" + +#define MAX_LINE_CHAR 16 + +#ifdef CONFIG_RESOLUTION_128X64 + #define ITEMOFFSET 2 + #define ITEM_PAGE_OFFSET 2 +#else // CONFIG_RESOLUTION_128X32 + #define ITEMOFFSET 1 + #define ITEM_PAGE_OFFSET 1 +#endif +static uint8_t scrolling_option = 0; +static const general_menu_t* current_menu_ctx = NULL; +static const general_menu_t* scrolling_menu_ctx = NULL; +static void* (*menu_exit_function)(void); +static void* (*menu_restore_function)(void); +static void general_screen_display_scrolling(); +static void general_screen_cb_modal(uint8_t button_name, uint8_t button_event); +static void general_screen_cb_scroll(uint8_t button_name, uint8_t button_event); +static const general_menu_t card_info_menu_ctx = { + .menu_items = NULL, + .menu_count = 0, + .menu_level = GENERAL_TREE_APP_SUBMENU, +}; + +char** general_screen_truncate_text(char* p_text, int* num_lines) { + char** lines = NULL; + *num_lines = 0; + + if (strlen(p_text) > MAX_LINE_CHAR) { + char temp[50]; + strncpy(temp, p_text, 50); + + char* token = strtok(temp, " "); + char current_line[MAX_LINE_CHAR] = ""; + + while (token != NULL) { + if (strlen(current_line) + strlen(token) + 1 <= MAX_LINE_CHAR) { + if (strlen(current_line) > 0) { + strcat(current_line, " "); + } + strcat(current_line, token); + } else { + lines = realloc(lines, sizeof(char*) * (*num_lines + 1)); + lines[*num_lines] = strdup(current_line); + (*num_lines)++; + + strcpy(current_line, token); + } + token = strtok(NULL, " "); + } + + if (strlen(current_line) > 0) { + lines = realloc(lines, sizeof(char*) * (*num_lines + 1)); + lines[*num_lines] = strdup(current_line); + (*num_lines)++; + } + } else { + lines = realloc(lines, sizeof(char*) * (*num_lines + 1)); + lines[*num_lines] = strdup(p_text); + (*num_lines)++; + } + + return lines; // Regresar el array de líneas spliteadas +} + +static void general_screen_display_selected_item(char* item_text, + uint8_t item_number) { + oled_screen_display_bitmap(minino_face, 0, (item_number * 8), 8, 8, + OLED_DISPLAY_NORMAL); + oled_screen_display_text(item_text, 16, item_number, OLED_DISPLAY_INVERT); +} + +static void general_screen_increment_option() { + scrolling_option++; + if (scrolling_option >= scrolling_menu_ctx->menu_count) { + scrolling_option = 0; + } +} + +static void general_screen_decrement_option() { + scrolling_option = scrolling_option-- == 0 + ? scrolling_menu_ctx->menu_count - 1 + : scrolling_option; +} + +static void general_screen_display_breadcrumb() { + if (current_menu_ctx->menu_level == GENERAL_TREE_APP_MENU) { + oled_screen_display_text("< Exit", 0, 0, OLED_DISPLAY_NORMAL); + } else { + oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); + } +} + +static void general_screen_cb_modal(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + break; + case BUTTON_DOWN: + break; + case BUTTON_RIGHT: + break; + case BUTTON_LEFT: + menus_module_set_app_state_last(); + menu_exit_function(); + break; + default: + break; + } +} + +static void general_screen_cb_scroll(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_UP: + general_screen_decrement_option(); + general_screen_display_scrolling(); + break; + case BUTTON_DOWN: + general_screen_increment_option(); + general_screen_display_scrolling(); + break; + case BUTTON_RIGHT: + break; + case BUTTON_LEFT: + general_register_menu(current_menu_ctx); + general_register_scrolling_menu(NULL); + menus_module_set_app_state_last(); + menu_exit_function(); + break; + default: + break; + } +} + +static void general_screen_display_scrolling() { + general_clear_screen(); + oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); + + if (scrolling_menu_ctx == NULL) { + return; + } + + oled_screen_display_card_border(); +#ifdef CONFIG_RESOLUTION_128X64 + uint16_t items_per_screen = 3; + uint16_t screen_title = 2; + + oled_screen_display_text_center("Information", ITEM_PAGE_OFFSET, + OLED_DISPLAY_NORMAL); +#else + uint16_t items_per_screen = 2; + uint16_t screen_title = 0; +#endif + + uint16_t end_index = scrolling_option + items_per_screen; + if (end_index > scrolling_menu_ctx->menu_count) { + end_index = scrolling_menu_ctx->menu_count; + } + + for (uint16_t i = scrolling_option; i < end_index; i++) { + oled_screen_display_text( + scrolling_menu_ctx->menu_items[i], 3, + (i - scrolling_option) + (ITEMOFFSET + screen_title), + OLED_DISPLAY_NORMAL); + } +} + +void general_register_menu(const general_menu_t* ctx) { + current_menu_ctx = ctx; +} + +void general_register_scrolling_menu(const general_menu_t* ctx) { + scrolling_menu_ctx = ctx; +} + +void general_clear_screen() { + oled_screen_clear_buffer(); +} + +void general_screen_display_scrolling_text_handler(void* callback_exit) { + scrolling_option = 0; + menu_exit_function = callback_exit; + menus_module_set_app_state(true, general_screen_cb_scroll); + general_screen_display_scrolling(); +} + +void general_screen_display_card_information_handler(char* title, + char* body, + void* callback_exit, + void* callback_restore) { + menu_exit_function = callback_exit; + menu_restore_function = callback_restore; + menus_module_set_app_state(true, general_screen_cb_modal); + genera_screen_display_card_information(title, body); +} + +void genera_screen_display_card_information(char* title, char* body) { + general_register_menu(&card_info_menu_ctx); + general_clear_screen(); + general_screen_display_breadcrumb(); + oled_screen_display_card_border(); + int page = ITEM_PAGE_OFFSET; + oled_screen_display_text_center(title, page, OLED_DISPLAY_NORMAL); + page++; + if (strlen(body) > MAX_LINE_CHAR) { + oled_screen_display_text_splited(body, &page, OLED_DISPLAY_NORMAL); + return; + } + oled_screen_display_text_center(body, page, OLED_DISPLAY_NORMAL); +} + +void genera_screen_display_notify_information(char* title, char* body) { + general_clear_screen(); + general_screen_display_breadcrumb(); + int page = ITEM_PAGE_OFFSET; + oled_screen_display_text_center(title, page, OLED_DISPLAY_NORMAL); + page++; + if (strlen(body) > MAX_LINE_CHAR) { + oled_screen_display_text_splited(body, &page, OLED_DISPLAY_NORMAL); + return; + } + oled_screen_display_text_center(body, page, OLED_DISPLAY_NORMAL); +} + +void general_screen_display_menu(uint16_t current_option) { + general_clear_screen(); + general_screen_display_breadcrumb(); + + if (current_menu_ctx == NULL) { + return; + } + + if (current_option == NULL) { + current_option = 0; + } + + for (uint16_t i = 0; i < current_menu_ctx->menu_count; i++) { + if (i >= current_menu_ctx->menu_count) { + break; + } + if (i == current_option) { + general_screen_display_selected_item(current_menu_ctx->menu_items[i], + i + ITEMOFFSET); + } else { + oled_screen_display_text(current_menu_ctx->menu_items[i], 0, + i + ITEMOFFSET, OLED_DISPLAY_NORMAL); + } + } +} \ No newline at end of file diff --git a/firmware/main/general/general_screens.h b/firmware/main/general/general_screens.h new file mode 100644 index 00000000..15774bf7 --- /dev/null +++ b/firmware/main/general/general_screens.h @@ -0,0 +1,44 @@ +#include +#include +#ifndef GENERAL_SCREENS_H + #define GENERAL_SCREENS_H + + #if CONFIG_RESOLUTION_128X64 + #define ITEMS_PER_SCREEN 5 + #elif CONFIG_RESOLUTION_128X32 + #define ITEMS_PER_SCREEN 3 + #endif + +typedef enum { + GENERAL_MENU_MAIN = 0, + GENERAL_MENU_SUBMENU +} general_menu_tree_index_t; + +typedef enum { + GENERAL_TREE_APP_MENU, + GENERAL_TREE_APP_SUBMENU, + GENERAL_TREE_APP_INFORMATION +} menu_tree_t; + +typedef struct { + char** menu_items; + uint16_t menu_count; + menu_tree_t menu_level; +} general_menu_t; + +void general_register_menu(const general_menu_t* ctx); +void general_register_scrolling_menu(const general_menu_t* ctx); +void general_clear_screen(); +void general_screen_display_menu(uint16_t current_option); +void genera_screen_display_card_information(char* title, char* body); +void genera_screen_display_notify_information(char* title, char* body); +void general_screen_display_card_information_handler(char* title, + char* body, + void* callback_exit, + void* callback_restore); +void general_screen_display_scrolling_text_handler(void* callback_exit); +char** general_screen_truncate_text(char* p_text, int* num_lines); +void general_screen_display_auto_card(char* lines, + int num_lines, + void* callback_exit); +#endif // GENERAL_SCREENS_H diff --git a/firmware/main/idf_component.yml b/firmware/main/idf_component.yml index ddc9597b..b6371a37 100644 --- a/firmware/main/idf_component.yml +++ b/firmware/main/idf_component.yml @@ -12,6 +12,8 @@ dependencies: path: ../components/openthread OTA: path: ../components/OTA + ble_hid: + path: ../components/ble_hid espressif/iperf: version: "~0.1.1" diff --git a/firmware/main/main.c b/firmware/main/main.c index 6dd8f955..effd4b71 100644 --- a/firmware/main/main.c +++ b/firmware/main/main.c @@ -1,12 +1,15 @@ #include -#include "apps/wifi/deauth/include/deauth_module.h" +#include "apps/ble/hid_device/hid_module.h" +#include "apps/ble/trackers/trackers_module.h" +#include "buzzer.h" #include "cat_console.h" #include "esp_log.h" #include "esp_timer.h" #include "flash_fs.h" +#include "flash_fs_screens.h" #include "keyboard_module.h" #include "leds.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "open_thread.h" #include "preferences.h" #include "sd_card.h" @@ -18,35 +21,23 @@ static const char* TAG = "main"; -void reboot_counter() { - int32_t counter = preferences_get_int("reboot_counter", 0); - ESP_LOGI(TAG, "Reboot counter: %ld", counter); - counter++; - preferences_put_int("reboot_counter", counter); -} - -void app_main(void) { +void app_main() { #if !defined(CONFIG_MAIN_DEBUG) esp_log_level_set(TAG, ESP_LOG_NONE); #endif - uint64_t start_time, end_time; - start_time = esp_timer_get_time(); + preferences_begin(); + bool stealth_mode = preferences_get_bool("stealth_mode", false); + if (!stealth_mode) { + buzzer_enable(); + leds_begin(); + } buzzer_begin(BUZZER_PIN); - leds_init(); - preferences_begin(); sd_card_begin(); + flash_fs_begin(flash_fs_screens_handler); keyboard_module_begin(); - menu_screens_begin(); - reboot_counter(); + menus_module_begin(); leds_off(); - - end_time = esp_timer_get_time(); - float time = (float) (end_time - start_time) / 1000000; - char* time_str = malloc(sizeof(time) + 1); - sprintf(time_str, "%2.2f", time); - ESP_LOGI(TAG, "Total time taken: %s seconds", time_str); - preferences_put_bool("wifi_connected", false); - cat_console_begin(); + // cat_console_begin(); } diff --git a/firmware/main/modules/about/about_module.c b/firmware/main/modules/about/about_module.c new file mode 100644 index 00000000..7061764c --- /dev/null +++ b/firmware/main/modules/about/about_module.c @@ -0,0 +1,64 @@ +#include "about_module.h" +#include +#include +#include "animations_task.h" +#include "freertos/FreeRTOS.h" +#include "led_events.h" +#include "menus_module.h" +#include "oled_screen.h" + +static char* about_credits_text[] = { + "Developed by", + "Electronic Cats", + "and PWnLabs", + "", + "With love from", + "Mexico...", + "", + "Thanks", + "- Kevin", + " @kevlem97", + "- Roberto", + "- Francisco", + " @deimoshall", + "and Electronic", + "Cats team", +}; + +static char* about_legal_text[] = { + "The user", "assumes all", "responsibility", "for the use of", + "MININO and", "agrees to use", "it legally and", "ethically,", + "avoiding any", "activities that", "may cause harm,", "interference,", + "or unauthorized", "access to", "systems or data.", +}; + +static const general_menu_t about_credits_menu = { + .menu_items = about_credits_text, + .menu_count = 14, + .menu_level = GENERAL_TREE_APP_INFORMATION, +}; + +static const general_menu_t about_legal_menu = { + .menu_items = about_legal_text, + .menu_count = 15, + .menu_level = GENERAL_TREE_APP_INFORMATION, +}; + +void about_module_display_credits_menu() { + general_register_scrolling_menu(&about_credits_menu); + general_screen_display_scrolling_text_handler(menus_module_exit_app); +} + +void about_module_display_legal_menu() { + general_register_scrolling_menu(&about_legal_menu); + general_screen_display_scrolling_text_handler(menus_module_exit_app); +} + +void about_module_display_version() { + general_screen_display_card_information_handler( + "Minino", "v" CONFIG_PROJECT_VERSION, menus_module_exit_app, NULL); +} +void about_module_display_license() { + general_screen_display_card_information_handler("License", "GNU GPL 3.0", + menus_module_exit_app, NULL); +} diff --git a/firmware/main/modules/about/about_module.h b/firmware/main/modules/about/about_module.h new file mode 100644 index 00000000..6158b108 --- /dev/null +++ b/firmware/main/modules/about/about_module.h @@ -0,0 +1,10 @@ +#include +#include +#include "general/general_screens.h" +#ifndef ABOUT_MODULE_H + #define ABOUT_MODULE_H +void about_module_display_credits_menu(); +void about_module_display_legal_menu(); +void about_module_display_version(); +void about_module_display_license(); +#endif // ABOUT_MODULE_H diff --git a/firmware/main/modules/animations_task/animations_task.c b/firmware/main/modules/animations_task/animations_task.c index 1e2245c1..fb3fd964 100644 --- a/firmware/main/modules/animations_task/animations_task.c +++ b/firmware/main/modules/animations_task/animations_task.c @@ -2,6 +2,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "preferences.h" void (*animations_task_cb)(void*) = NULL; @@ -20,6 +21,9 @@ static void animations_task(void* ctx) { } void animations_task_run(void* animation_cb, uint32_t period_ms, void* ctx) { + if (preferences_get_bool("stealth_mode", false)) { + return; + } animations_task_cb = animation_cb; delay_ms = period_ms; xTaskCreate(animations_task, "animations_task", 2048, ctx, 5, NULL); diff --git a/firmware/main/modules/ble/ble_module.c b/firmware/main/modules/ble/ble_module.c deleted file mode 100644 index 2fb3f978..00000000 --- a/firmware/main/modules/ble/ble_module.c +++ /dev/null @@ -1,170 +0,0 @@ -#include "ble_module.h" -#include "animations_task.h" -#include "bt_spam.h" -#include "esp_log.h" -#include "led_events.h" -#include "menu_screens_modules.h" -#include "modules/ble/ble_screens_module.h" -#include "oled_screen.h" -#include "trackers_scanner.h" - -static app_screen_state_information_t app_screen_state_information = { - .in_app = false, - .app_selected = 0, -}; -static int trackers_count = 0; -static int device_selection = 0; -static bool is_displaying = false; -static bool is_modal_displaying = false; -static tracker_profile_t* scanned_airtags = NULL; -static TaskHandle_t ble_task_display_records = NULL; -static TaskHandle_t ble_task_display_animation = NULL; - -static void ble_module_app_selector(); -static void ble_module_state_machine(uint8_t button_name, uint8_t button_event); -static void ble_module_display_trackers_cb(tracker_profile_t record); -static void ble_module_task_start_trackers_display_devices(); -static void ble_module_task_stop_trackers_display_devices(); - -void ble_module_begin(int app_selected) { -#if !defined(CONFIG_BLE_MODULE_DEBUG) - esp_log_level_set(TAG_BLE_MODULE, ESP_LOG_NONE); -#endif - - ESP_LOGI(TAG_BLE_MODULE, "Initializing ble module screen state machine"); - app_screen_state_information.app_selected = app_selected; - - menu_screens_set_app_state(true, ble_module_state_machine); - oled_screen_clear(); - ble_module_app_selector(); -}; - -static void ble_module_app_selector() { - led_control_run_effect(led_control_ble_tracking); - switch (app_screen_state_information.app_selected) { - case MENU_BLUETOOTH_TRAKERS_SCAN: - trackers_scanner_register_cb(ble_module_display_trackers_cb); - ble_module_task_start_trackers_display_devices(); - trackers_scanner_start(); - break; - case MENU_BLUETOOTH_SPAM: - // xTaskCreate(ble_screens_display_scanning_animation, - // "ble_module_scanning", - // 4096, NULL, 5, &ble_task_display_animation); - ble_screens_start_scanning_animation(); - bt_spam_register_cb(ble_screens_display_scanning_text); - bt_spam_app_main(); - break; - default: - break; - } -} -static void ble_module_state_machine(uint8_t button_name, - uint8_t button_event) { - if (button_event != BUTTON_PRESS_DOWN && - button_event != BUTTON_LONG_PRESS_HOLD) { - return; - } - switch (app_screen_state_information.app_selected) { - case MENU_BLUETOOTH_TRAKERS_SCAN: - switch (button_name) { - case BUTTON_LEFT: - if (is_modal_displaying) { - is_modal_displaying = false; - ble_screens_display_trackers_profiles_modal(); - break; - } - ble_module_task_stop_trackers_display_devices(); - trackers_scanner_stop(); - led_control_stop(); - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); - break; - case BUTTON_RIGHT: - ESP_LOGI(TAG_BLE_MODULE, "Button right pressed - Option selected: %d", - device_selection); - if (is_modal_displaying) { - break; - } - is_modal_displaying = true; - ESP_LOGW(TAG_BLE_MODULE, "Device selected: %d", device_selection); - if (scanned_airtags) { - ble_screens_display_modal_trackers_profile( - scanned_airtags[device_selection]); - } - break; - case BUTTON_UP: - ESP_LOGI(TAG_BLE_MODULE, "Button up pressed"); - device_selection = (device_selection == 0) ? 0 : device_selection - 1; - break; - case BUTTON_DOWN: - ESP_LOGI(TAG_BLE_MODULE, "Button down pressed"); - device_selection = (device_selection == (trackers_count - 1)) - ? device_selection - : device_selection + 1; - break; - case BUTTON_BOOT: - default: - break; - } - break; - case MENU_BLUETOOTH_SPAM: - switch (button_name) { - case BUTTON_LEFT: - bt_spam_app_stop(); - led_control_stop(); - menu_screens_set_app_state(false, NULL); - animations_task_stop(); - menu_screens_exit_submenu(); - // esp_restart(); - break; - case BUTTON_RIGHT: - case BUTTON_UP: - case BUTTON_DOWN: - case BUTTON_BOOT: - default: - break; - } - break; - default: - break; - } -} - -static void ble_module_display_trackers_cb(tracker_profile_t record) { - int has_device = trackers_scanner_find_profile_by_mac( - scanned_airtags, trackers_count, record.mac_address); - if (has_device == -1) { - trackers_scanner_add_tracker_profile(&scanned_airtags, &trackers_count, - record.mac_address, record.rssi, - record.name); - } else { - scanned_airtags[has_device].rssi = record.rssi; - if (is_modal_displaying) { - ble_screens_display_modal_trackers_profile( - scanned_airtags[device_selection]); - } - } -} - -static void ble_module_create_task_trackers_display_devices() { - while (is_displaying) { - if (!is_modal_displaying) { - ble_screens_display_trackers_profiles(scanned_airtags, trackers_count, - device_selection); - } - vTaskDelay(1000 / portTICK_PERIOD_MS); - } - vTaskDelete(NULL); -} - -static void ble_module_task_start_trackers_display_devices() { - is_displaying = true; - xTaskCreate(ble_module_create_task_trackers_display_devices, - "display_records", 2048, NULL, 10, &ble_task_display_records); -} - -static void ble_module_task_stop_trackers_display_devices() { - is_displaying = false; - vTaskSuspend(ble_task_display_records); -} diff --git a/firmware/main/modules/ble/ble_module.h b/firmware/main/modules/ble/ble_module.h deleted file mode 100644 index e0134d27..00000000 --- a/firmware/main/modules/ble/ble_module.h +++ /dev/null @@ -1,12 +0,0 @@ -#include "trackers_scanner.h" -#ifndef BLE_MODULE_H - #define BLE_MODULE_H - #define TAG_BLE_MODULE "ble_module:main" - -/** - * @brief Begin the bluetooth module - * - * @param app_selected The selected app - */ -void ble_module_begin(int app_selected); -#endif // BLE_MODULE_H diff --git a/firmware/main/modules/ble/ble_screens_module.c b/firmware/main/modules/ble/ble_screens_module.c deleted file mode 100644 index a5afabd5..00000000 --- a/firmware/main/modules/ble/ble_screens_module.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include "animations_task.h" -#include "modules/ble/ble_bitmaps.h" -#include "oled_screen.h" -#include "trackers_scanner.h" - -static void ble_screens_display_scanning_animation() { - static uint8_t frame = 0; - oled_screen_display_bitmap(ble_bitmap_scan_attack_allArray[frame], 0, 16, 128, - 32, OLED_DISPLAY_NORMAL); - frame = ++frame > 3 ? 0 : frame; -} - -void ble_screens_start_scanning_animation() { - oled_screen_clear(); - oled_screen_display_text_center("BLE SPAM", 0, OLED_DISPLAY_NORMAL); - animations_task_run(ble_screens_display_scanning_animation, 100, NULL); -} - -void ble_screens_display_scanning_text(char* name) { - oled_screen_clear_line(0, 7, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(name, 7, OLED_DISPLAY_INVERT); -} - -void ble_screens_display_trackers_profiles_modal() { - oled_screen_clear(); - oled_screen_display_text_center("Trackers Scanner", 0, OLED_DISPLAY_INVERT); -} - -void ble_screens_display_trackers_profiles(tracker_profile_t* trackers_scanned, - int trackers_count, - int device_selection) { - char* name_str = (char*) malloc(50); - oled_screen_display_text_center("Trackers Scanner", 0, OLED_DISPLAY_INVERT); - int started_page = 2; - for (int i_device = 0; i_device < trackers_count; i_device++) { - oled_screen_clear_line(0, started_page, OLED_DISPLAY_NORMAL); - sprintf(name_str, "%s RSSI: %d dBM", trackers_scanned[i_device].name, - trackers_scanned[i_device].rssi); - oled_screen_display_text_splited(name_str, &started_page, - (device_selection == i_device) - ? OLED_DISPLAY_INVERT - : OLED_DISPLAY_NORMAL); - } - free(name_str); -} - -void ble_screens_display_modal_trackers_profile(tracker_profile_t profile) { - oled_screen_clear(); - int started_page = 1; - char* name = (char*) malloc(MAX_LINE_CHAR); - char* rssi = (char*) malloc(MAX_LINE_CHAR); - char* mac_addrs = (char*) malloc(20); - char* str_adv_data = (char*) malloc(64); - - memset(str_adv_data, 0, 64); - sprintf(name, "%s", profile.name); - sprintf(rssi, "RSSI: %d dBm", profile.rssi); - sprintf(mac_addrs, "%02X:%02X:%02X:%02X:%02X%02X", profile.mac_address[0], - profile.mac_address[1], profile.mac_address[2], - profile.mac_address[3], profile.mac_address[4], - profile.mac_address[5]); - - sprintf(str_adv_data, "ADV: "); - for (int i = 96; i < 112; i++) { - sprintf(str_adv_data + strlen(str_adv_data), "%02X ", profile.adv_data[i]); - } - oled_screen_display_text_center(name, 0, OLED_DISPLAY_NORMAL); - oled_screen_display_text_splited(rssi, &started_page, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("MAC Address", started_page, - OLED_DISPLAY_NORMAL); - started_page++; - oled_screen_display_text_center(mac_addrs, started_page, OLED_DISPLAY_NORMAL); - started_page++; - oled_screen_display_text_splited(str_adv_data, &started_page, - OLED_DISPLAY_NORMAL); - free(name); - free(rssi); - free(mac_addrs); - free(str_adv_data); -} diff --git a/firmware/main/modules/ble/ble_screens_module.h b/firmware/main/modules/ble/ble_screens_module.h deleted file mode 100644 index e261c92b..00000000 --- a/firmware/main/modules/ble/ble_screens_module.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "trackers_scanner.h" -#ifndef BLE_SCREENS_MODULE_H - #define BLE_SCREENS_MODULE_H - -void ble_screens_start_scanning_animation(); -void ble_screens_display_scanning_text(char* name); -void ble_screens_display_ble_spam(); -void ble_screens_display_trackers_profiles_modal(); -void ble_screens_display_trackers_profiles(tracker_profile_t* trackers_scanned, - int trackers_count, - int device_selection); -void ble_screens_display_modal_trackers_profile(tracker_profile_t profile); -#endif // BLE_SCREENS_MODULE_H diff --git a/firmware/main/modules/cat_dos/catdos_module.c b/firmware/main/modules/cat_dos/catdos_module.c index 7e3ceef7..68180bb0 100644 --- a/firmware/main/modules/cat_dos/catdos_module.c +++ b/firmware/main/modules/cat_dos/catdos_module.c @@ -21,7 +21,7 @@ #include "lwip/netdb.h" #include "lwip/sockets.h" #include "lwip/sys.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" #include "sdkconfig.h" @@ -46,10 +46,6 @@ static enum { static int catdos_state = CATDOS_STATE_CONFIG_WIFI; -app_screen_state_information_t app_screen_state_information = { - .in_app = false, - .app_selected = 0, -}; static bool running_attack = false; static TaskHandle_t task_display_attacking = NULL; static bool catdos_module_is_config_wifi(); @@ -439,7 +435,7 @@ void catdos_module_begin() { esp_log_level_set(CATDOS_TAG, ESP_LOG_NONE); #endif // ESP_ERROR_CHECK(esp_event_loop_create_default()); - menu_screens_set_app_state(true, catdos_module_state_machine); + menus_module_set_app_state(true, catdos_module_state_machine); oled_screen_clear(OLED_DISPLAY_NORMAL); oled_screen_display_text_center("THIS APP STILL", 0, OLED_DISPLAY_INVERT); @@ -591,8 +587,7 @@ static void catdos_module_state_machine(uint8_t button_name, case CATDOS_STATE_CONFIG_WIFI: { switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_restart(); break; case BUTTON_RIGHT: ESP_LOGI(CATDOS_TAG, "Selected item: %d", selected_item); @@ -631,8 +626,7 @@ static void catdos_module_state_machine(uint8_t button_name, case CATDOS_STATE_ATTACK: { switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_exit_app(); break; case BUTTON_RIGHT: catdos_module_send_attack(); diff --git a/firmware/main/modules/coroutine/coroutine.c b/firmware/main/modules/coroutine/coroutine.c new file mode 100644 index 00000000..b5cfb1d9 --- /dev/null +++ b/firmware/main/modules/coroutine/coroutine.c @@ -0,0 +1,7 @@ +#include "coroutine.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +void start_coroutine(void* routine, void* ctx) { + xTaskCreate(routine, "coroutine_task", 4096, ctx, 10, NULL); +} \ No newline at end of file diff --git a/firmware/main/modules/coroutine/coroutine.h b/firmware/main/modules/coroutine/coroutine.h new file mode 100644 index 00000000..cfb97753 --- /dev/null +++ b/firmware/main/modules/coroutine/coroutine.h @@ -0,0 +1,3 @@ +#pragma once + +void start_coroutine(void* routine, void* ctx); \ No newline at end of file diff --git a/firmware/main/modules/file_manager/file_manager_module.c b/firmware/main/modules/file_manager/file_manager_module.c new file mode 100644 index 00000000..7344a09f --- /dev/null +++ b/firmware/main/modules/file_manager/file_manager_module.c @@ -0,0 +1,312 @@ +#include "file_manager_module.h" + +#include +#include +#include "dirent.h" +#include "esp_log.h" + +#include "coroutine.h" +#include "file_manager_screens.h" +#include "flash_fs.h" +#include "keyboard_modal.h" +#include "menus_module.h" +#include "modals_module.h" +#include "sd_card.h" + +#define INTERNAL_ROOT "/internal" +#define SD_CARD_ROOT "/sdcard" +#define TAG "File Manager" + +typedef enum { + FM_CANCELED_OPTION = -1, + FM_RENAME_OPTION, + FM_ERASE_OPTION +} file_options_t; + +typedef enum { + FILE_MANAGER_EXIT = -1, + FILE_MANAGER_ROOT_INTERNAL, + FILE_MANAGER_ROOT_SDCARD, +} root_selection_t; + +static file_manager_context_t* fm_ctx; +static file_manager_show_event_cb_t file_manager_show_event_cb = NULL; +static char* file_options[] = {"Rename", "Delete", NULL}; +static void file_manager_input_cb(uint8_t button_name, uint8_t button_event); + +static void open_root_options(); + +void file_manager_set_show_event_callback(file_manager_show_event_cb_t cb) { + file_manager_show_event_cb = cb; +} + +static void show_event(file_manager_events_t event, void* context) { + if (file_manager_show_event_cb) { + file_manager_show_event_cb(event, context); + } +} + +static void clear_items() { + fm_ctx->items_count = 0; + for (uint8_t i = 0; i < fm_ctx->items_count; i++) { + free(fm_ctx->file_items_arr[i]); + } + free(fm_ctx->file_items_arr); +} + +static void get_parent_path(const char* path, char* parent_path) { + char temp_path[256]; + strncpy(temp_path, path, sizeof(temp_path)); + temp_path[sizeof(temp_path) - 1] = '\0'; + + char* last_slash = strrchr(temp_path, '/'); + if (last_slash != NULL) { + if (last_slash == temp_path) { + strcpy(parent_path, "/"); + } else { + size_t len = last_slash - temp_path; + strncpy(parent_path, temp_path, len); + parent_path[len] = '\0'; + } + } else { + strcpy(parent_path, "."); + } +} + +static void update_files() { + clear_items(); + + DIR* dir; + struct dirent* entry; + dir = opendir(fm_ctx->current_path); // check false + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_REG || entry->d_type == DT_DIR) { + fm_ctx->items_count++; + } + } + closedir(dir); + + fm_ctx->is_root = strcmp(SD_CARD_ROOT, fm_ctx->current_path) == 0 || + strcmp(INTERNAL_ROOT, fm_ctx->current_path) == 0; + fm_ctx->file_items_arr = + malloc(fm_ctx->items_count * sizeof(file_item_t*)); // check false + + dir = opendir(fm_ctx->current_path); // check false + + uint16_t idx = 0; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_type == DT_REG || entry->d_type == DT_DIR) { + file_item_t* item = malloc(sizeof(file_item_t)); // check false + item->is_dir = (entry->d_type == DT_DIR); + item->name = strdup(entry->d_name); // check false + size_t path_len = + strlen(fm_ctx->current_path) + strlen(entry->d_name) + 2; + item->path = malloc(path_len); // chek false + snprintf(item->path, path_len, "%s/%s", fm_ctx->current_path, + entry->d_name); + fm_ctx->file_items_arr[idx++] = item; + } + } + closedir(dir); +} + +static void print_files() { + show_event(FILE_MANAGER_UPDATE_LIST_EV, fm_ctx); +} + +static void refresh_files() { + update_files(); + print_files(); +} + +static file_manager_context_t* file_manager_context_alloc() { + file_manager_context_t* ctx = + malloc(sizeof(file_manager_context_t)); // check false + memset(ctx, 0, sizeof(file_manager_context_t)); + ctx->file_items_arr = NULL; + return ctx; +} + +static void file_manager_module_exit() { + clear_items(); + free(fm_ctx); + menus_module_restart(); +} + +static void navigation_up() { + fm_ctx->selected_item = fm_ctx->selected_item == 0 + ? fm_ctx->items_count - 1 + : fm_ctx->selected_item - 1; + print_files(); +} +static void navigation_down() { + fm_ctx->selected_item = + ++fm_ctx->selected_item < fm_ctx->items_count ? fm_ctx->selected_item : 0; + print_files(); +} + +static void navigation_back() { + if (fm_ctx->is_root) { + start_coroutine(open_root_options, NULL); + } else { + get_parent_path(fm_ctx->current_path, fm_ctx->current_path); + fm_ctx->selected_item = 0; + refresh_files(); + } +} + +void split_filename(const char* filepath, char* filename, char* extension) { + const char* dot = strrchr(filepath, '.'); + if (dot != NULL) { + strcpy(extension, dot + 1); + size_t length = dot - filepath; + strncpy(filename, filepath, length); + filename[length] = '\0'; + } else { + strcpy(filename, filepath); + extension[0] = '\0'; + } +} + +static void file_options_handler(int8_t selection) { + switch (selection) { + case FM_RENAME_OPTION: + char filename[50]; + char extension[10]; + split_filename(fm_ctx->file_items_arr[fm_ctx->selected_item]->name, + filename, extension); + char* new_name = keyboard_modal_write(filename, " RENAME "); + if (new_name != NULL) { + char* new_path = + (char*) malloc(strlen(new_name) + strlen(fm_ctx->current_path) + + strlen(extension) + 3); + sprintf(new_path, "%s/%s.%s", fm_ctx->current_path, new_name, + extension); + if (rename(fm_ctx->file_items_arr[fm_ctx->selected_item]->path, + new_path) == 0) { + modals_module_show_info("Success", "File was renamed successfully ", + 1000, true); + } else { + modals_module_show_info("Error", strerror(errno), 2000, true); + } + free(new_path); + } + menus_module_set_app_state(true, file_manager_input_cb); + break; + case FM_ERASE_OPTION: + if (modals_module_get_user_y_n_selection(" Are You Sure ") == + YES_OPTION) { + if (remove(fm_ctx->file_items_arr[fm_ctx->selected_item]->path) == 0) { + modals_module_show_info("Deleted", "File was deleted successfully", + 1000, true); + } else { + modals_module_show_info("Error", "Something was wrong, try again", + 2000, true); + } + } + menus_module_set_app_state(true, file_manager_input_cb); + break; + default: + break; + } +} + +static void open_file_options() { + int8_t selection = modals_module_get_user_selection(file_options, "< Cancel"); + menus_module_set_app_state(true, file_manager_input_cb); + file_options_handler(selection); + update_files(); + fm_ctx->selected_item = MIN(fm_ctx->selected_item, fm_ctx->items_count - 1); + print_files(); + vTaskDelete(NULL); +} + +static void navigation_enter() { + if (!fm_ctx->items_count) { + return; + } + if (fm_ctx->file_items_arr[fm_ctx->selected_item]->is_dir) { + fm_ctx->current_path = fm_ctx->file_items_arr[fm_ctx->selected_item]->path; + fm_ctx->selected_item = 0; + refresh_files(); + } else { + start_coroutine(open_file_options, NULL); + } +} + +static void file_manager_input_cb(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + navigation_back(); + break; + case BUTTON_RIGHT: + navigation_enter(); + break; + case BUTTON_UP: + navigation_up(); + break; + case BUTTON_DOWN: + navigation_down(); + break; + default: + break; + } +} + +static void open_root_directory(char* root) { + fm_ctx->current_path = root; + menus_module_set_app_state(true, file_manager_input_cb); + file_manager_set_show_event_callback(file_manager_screens_event_handler); + refresh_files(); +} + +static void open_root_options() { + char** root_paths = NULL; + uint8_t root_idx = 0; + if (flash_fs_mount() == ESP_OK) { + root_paths = (char**) malloc(sizeof(char*) * (root_idx + 1)); + root_paths[root_idx] = (char*) malloc(sizeof(INTERNAL_ROOT) + 1); + strcpy(root_paths[root_idx++], "Internal"); + } + if (sd_card_mount() == ESP_OK) { + root_paths = (char**) realloc(root_paths, sizeof(char*) * (root_idx + 1)); + root_paths[root_idx] = (char*) malloc(sizeof(SD_CARD_ROOT) + 1); + strcpy(root_paths[root_idx++], "SD CARD"); + } + if (!root_idx) { + modals_module_show_info("ERROR", "No file systems detected", 2000, true); + file_manager_module_exit(); + } + root_paths = (char**) realloc(root_paths, sizeof(root_paths) + 1); + root_paths[root_idx] = NULL; + int8_t root_selection = + modals_module_get_user_selection(root_paths, "< Exit"); + root_idx = 0; + while (root_paths[root_idx] != NULL) { + free(root_paths[root_idx]); + root_idx++; + } + free(root_paths); + switch (root_selection) { + case FILE_MANAGER_EXIT: + file_manager_module_exit(); + break; + case FILE_MANAGER_ROOT_INTERNAL: + open_root_directory(INTERNAL_ROOT); + break; + case FILE_MANAGER_ROOT_SDCARD: + open_root_directory(SD_CARD_ROOT); + break; + default: + break; + } + vTaskDelete(NULL); +} + +void file_manager_module_init() { + fm_ctx = file_manager_context_alloc(); + start_coroutine(open_root_options, NULL); +} \ No newline at end of file diff --git a/firmware/main/modules/file_manager/file_manager_module.h b/firmware/main/modules/file_manager/file_manager_module.h new file mode 100644 index 00000000..87c7c748 --- /dev/null +++ b/firmware/main/modules/file_manager/file_manager_module.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +typedef enum { + FILE_MANAGER_UPDATE_LIST_EV, + FILE_MANAGER_SHOW_FATAL_ERR_EV +} file_manager_events_t; + +typedef struct { + bool is_dir; + char* name; + char* path; +} file_item_t; + +typedef struct { + uint8_t items_count; + uint8_t selected_item; + bool is_root; + char* current_path; + file_item_t** file_items_arr; +} file_manager_context_t; + +typedef void (*file_manager_show_event_cb_t)(file_manager_events_t, void*); + +void file_manager_module_init(); +void file_manager_set_show_event_callback(file_manager_show_event_cb_t cb); \ No newline at end of file diff --git a/firmware/main/modules/file_manager/file_manager_screens.c b/firmware/main/modules/file_manager/file_manager_screens.c new file mode 100644 index 00000000..458313a8 --- /dev/null +++ b/firmware/main/modules/file_manager/file_manager_screens.c @@ -0,0 +1,42 @@ +#include "file_manager_screens.h" +#include "oled_screen.h" + +#define MAX_ITEMS_NUM 7 + +static void update_list(file_manager_context_t* ctx) { + static uint8_t items_offset = 0; + items_offset = MAX(ctx->selected_item - 6, items_offset); + items_offset = MIN(MAX(ctx->items_count - 7, 0), items_offset); + items_offset = MIN(ctx->selected_item, items_offset); + oled_screen_clear_buffer(); + oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); + if (ctx->items_count == 0) { + oled_screen_display_text(" Empty folder ", 0, 3, OLED_DISPLAY_NORMAL); + oled_screen_display_text("No files to show", 0, 4, OLED_DISPLAY_NORMAL); + } else { + for (uint8_t i = 0; i < (MIN(ctx->items_count, MAX_ITEMS_NUM)); i++) { + char* str = (char*) malloc(30); + sprintf(str, "%s%s", ctx->file_items_arr[i + items_offset]->name, + ctx->file_items_arr[i + items_offset]->is_dir ? ">" : ""); + oled_screen_display_text(str, 0, i + 1, + ctx->selected_item == i + items_offset); + free(str); + } + } + oled_screen_display_show(); +} + +static void show_fatal_error(char* error_tag) {} +void file_manager_screens_event_handler(file_manager_events_t event, + void* context) { + switch (event) { + case FILE_MANAGER_UPDATE_LIST_EV: + update_list(context); + break; + case FILE_MANAGER_SHOW_FATAL_ERR_EV: + show_fatal_error(context); + break; + default: + break; + } +} \ No newline at end of file diff --git a/firmware/main/modules/file_manager/file_manager_screens.h b/firmware/main/modules/file_manager/file_manager_screens.h new file mode 100644 index 00000000..b32c86ef --- /dev/null +++ b/firmware/main/modules/file_manager/file_manager_screens.h @@ -0,0 +1,6 @@ +#pragma once + +#include "file_manager_module.h" + +void file_manager_screens_event_handler(file_manager_events_t event, + void* context); diff --git a/firmware/main/modules/gps/gps_module.c b/firmware/main/modules/gps/gps_module.c index 71678a1f..249b3c03 100644 --- a/firmware/main/modules/gps/gps_module.c +++ b/firmware/main/modules/gps/gps_module.c @@ -2,7 +2,8 @@ #include "stdint.h" #include "gps_module.h" -#include "menu_screens_modules.h" +#include "gps_screens.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" #include "wardriving_module.h" @@ -32,54 +33,8 @@ const float TIME_ZONES[] = {-12.0, -11.0, -10.0, -9.5, -9.0, -8.0, -7.0, -6.0, 2.0, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 5.75, 6.0, 6.5, 7.0, 8.0, 8.75, 9.0, 9.5, 10.0, 10.5, 11.0, 12.0, 12.75, 13.0, 14.0}; - -// TODO: Refactor this update functions to screen module -void update_date_and_time(gps_t* gps) { - char* signal_str = (char*) malloc(20); - char* date_str = (char*) malloc(20); - char* time_str = (char*) malloc(20); - - sprintf(signal_str, "Signal: %s", gps_module_get_signal_strength(gps)); - sprintf(date_str, "Date: %d/%d/%d", gps->date.year, gps->date.month, - gps->date.day); - sprintf(time_str, "Time: %d:%d:%d", gps->tim.hour, gps->tim.minute, - gps->tim.second); - - gps_date_time_items[1] = signal_str; - gps_date_time_items[3] = date_str; - gps_date_time_items[4] = time_str; -} - -void update_location(gps_t* gps) { - char* signal_str = (char*) malloc(20); - char* latitude_str = (char*) malloc(22); - char* longitude_str = (char*) malloc(22); - char* altitude_str = (char*) malloc(22); - char* speed_str = (char*) malloc(22); - - // TODO: add ° symbol - sprintf(signal_str, "Signal: %s", gps_module_get_signal_strength(gps)); - sprintf(latitude_str, " %.05f N", gps->latitude); - sprintf(longitude_str, " %.05f E", gps->longitude); - sprintf(altitude_str, " %.04fm", gps->altitude); - - gps_location_items[1] = signal_str; - gps_location_items[4] = latitude_str; - gps_location_items[6] = longitude_str; - gps_location_items[8] = altitude_str; -} - -void update_speed(gps_t* gps) { - char* signal_str = (char*) malloc(20); - char* speed_str = (char*) malloc(22); - - sprintf(signal_str, "Signal: %s", gps_module_get_signal_strength(gps)); - sprintf(speed_str, "Speed: %.02fm/s", gps->speed); - - gps_speed_items[1] = signal_str; - gps_speed_items[3] = speed_str; -} - +static void gps_module_general_data_input_cb(uint8_t button_name, + uint8_t button_event); /** * @brief GPS Event Handler * @@ -92,26 +47,15 @@ static void gps_event_handler(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { - screen_module_menu_t current_menu = menu_screens_get_current_menu(); - - if (current_menu == MENU_GPS) { - return; - } - switch (event_id) { case GPS_UPDATE: /* update GPS information */ gps_t* gps = gps_module_get_instance(event_data); - if (gps_event_callback != NULL) { gps_event_callback(gps); return; } - - update_date_and_time(gps); - update_location(gps); - update_speed(gps); - menu_screens_display_menu(); + gps_screens_update_handler(gps); break; case GPS_UNKNOWN: /* print unknown statements */ @@ -138,6 +82,7 @@ void gps_module_start_scan() { nmea_hdl = nmea_parser_init(&config); /* register event handler for NMEA parser library */ nmea_parser_add_handler(nmea_hdl, gps_event_handler, NULL); + gps_screens_show_waiting_signal(); } void gps_module_stop_read() { @@ -161,56 +106,6 @@ char* gps_module_get_signal_strength(gps_t* gps) { } } -void gps_module_exit_submenu_cb() { - screen_module_menu_t current_menu = menu_screens_get_current_menu(); - - switch (current_menu) { - case MENU_GPS_WARDRIVING: - wardriving_module_end(); - break; - case MENU_GPS_WARDRIVING_START: - wardriving_module_stop_scan(); - break; - case MENU_GPS: - menu_screens_unregister_submenu_cbs(); - break; - case MENU_GPS_DATE_TIME: - case MENU_GPS_LOCATION: - case MENU_GPS_SPEED: - gps_module_stop_read(); - break; - default: - break; - } -} - -void gps_module_enter_submenu_cb(screen_module_menu_t user_selection) { - switch (user_selection) { - case MENU_GPS_WARDRIVING: - wardriving_module_begin(); - break; - case MENU_GPS_WARDRIVING_START: - wardriving_module_start_scan(); - menu_screens_set_app_state(true, wardriving_module_keyboard_cb); - break; - case MENU_GPS_DATE_TIME: - case MENU_GPS_LOCATION: - case MENU_GPS_SPEED: - gps_module_start_scan(); - break; - default: - break; - } -} - -void gps_module_begin() { -#if !defined(CONFIG_GPS_MODULE_DEBUG) - esp_log_level_set(TAG, ESP_LOG_NONE); -#endif - menu_screens_register_exit_submenu_cb(gps_module_exit_submenu_cb); - menu_screens_register_enter_submenu_cb(gps_module_enter_submenu_cb); -} - gps_t* gps_module_get_instance(void* event_data) { gps_t* gps = (gps_t*) event_data; @@ -283,3 +178,17 @@ void gps_module_register_cb(gps_event_callback_t callback) { void gps_module_unregister_cb() { gps_event_callback = NULL; } + +void gps_module_general_data_run() { + menus_module_set_app_state(true, gps_module_general_data_input_cb); + gps_module_start_scan(); +} + +static void gps_module_general_data_input_cb(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN || button_name != BUTTON_LEFT) { + return; + } + gps_module_stop_read(); + menus_module_exit_app(); +} \ No newline at end of file diff --git a/firmware/main/modules/gps/gps_module.h b/firmware/main/modules/gps/gps_module.h index 503027ab..47fd5d64 100644 --- a/firmware/main/modules/gps/gps_module.h +++ b/firmware/main/modules/gps/gps_module.h @@ -82,3 +82,5 @@ void gps_module_register_cb(gps_event_callback_t callback); * @return void */ void gps_module_unregister_cb(); + +void gps_module_general_data_run(); diff --git a/firmware/main/modules/gps/gps_screens.c b/firmware/main/modules/gps/gps_screens.c new file mode 100644 index 00000000..ddd40be5 --- /dev/null +++ b/firmware/main/modules/gps/gps_screens.c @@ -0,0 +1,87 @@ +#include "gps_screens.h" + +#include "general_screens.h" +#include "menus_module.h" +#include "oled_screen.h" + +char* gps_help_2[] = { + "Verify your", "time zone if", "the time is not", + "correct, go to", "`Settings/", "System/Time", + "zone` and", "select the", "correct one.", +}; +const general_menu_t gps_help_menu = {.menu_count = 9, + .menu_items = gps_help_2, + .menu_level = GENERAL_TREE_APP_MENU}; + +void gps_screens_show_help() { + general_register_scrolling_menu(&gps_help_menu); + general_screen_display_scrolling_text_handler(menus_module_exit_app); +} + +static void gps_screens_update_date_and_time(gps_t* gps) { + char* str = (char*) malloc(20); + oled_screen_clear_buffer(); + sprintf(str, "Signal: %s ", gps_module_get_signal_strength(gps)); + oled_screen_display_text(str, 0, 0, OLED_DISPLAY_NORMAL); + sprintf(str, "Date: %d/%d/%d", gps->date.year, gps->date.month, + gps->date.day); + oled_screen_display_text(str, 0, 2, OLED_DISPLAY_NORMAL); + sprintf(str, "Time: %d:%d:%d", gps->tim.hour, gps->tim.minute, + gps->tim.second); + oled_screen_display_text(str, 0, 3, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); + free(str); +} + +static void gps_screens_update_location(gps_t* gps) { + char* str = (char*) malloc(20); + oled_screen_clear_buffer(); + sprintf(str, "Signal: %s ", gps_module_get_signal_strength(gps)); + oled_screen_display_text(str, 0, 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text("Latitude:", 0, 2, OLED_DISPLAY_NORMAL); + sprintf(str, " %.05f N", gps->latitude); + oled_screen_display_text(str, 0, 3, OLED_DISPLAY_NORMAL); + oled_screen_display_text("Longitude:", 0, 4, OLED_DISPLAY_NORMAL); + sprintf(str, " %.05f E", gps->longitude); + oled_screen_display_text(str, 0, 5, OLED_DISPLAY_NORMAL); + oled_screen_display_text("Altitude:", 0, 6, OLED_DISPLAY_NORMAL); + sprintf(str, " %.04fm", gps->altitude); + oled_screen_display_text(str, 0, 7, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); + free(str); +} + +static void gps_screens_update_speed(gps_t* gps) { + char* str = (char*) malloc(20); + oled_screen_clear_buffer(); + sprintf(str, "Signal: %s ", gps_module_get_signal_strength(gps)); + oled_screen_display_text(str, 0, 0, OLED_DISPLAY_NORMAL); + sprintf(str, "Speed: %.02fm/s", gps->speed); + oled_screen_display_text(str, 0, 2, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); + free(str); +} + +void gps_screens_show_waiting_signal() { + oled_screen_clear_buffer(); + oled_screen_display_text_center("Waiting Signal", 0, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); +} + +void gps_screens_update_handler(gps_t* gps) { + menu_idx_t current = menus_module_get_current_menu(); + switch (current) { + case MENU_GPS_DATE_TIME_2: + gps_screens_update_date_and_time(gps); + break; + case MENU_GPS_LOCATION_2: + gps_screens_update_location(gps); + break; + case MENU_GPS_SPEED_2: + gps_screens_update_speed(gps); + break; + default: + return; + break; + } +} \ No newline at end of file diff --git a/firmware/main/modules/gps/gps_screens.h b/firmware/main/modules/gps/gps_screens.h new file mode 100644 index 00000000..4fbd434a --- /dev/null +++ b/firmware/main/modules/gps/gps_screens.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +#include "gps_module.h" + +void gps_screens_update_handler(gps_t* gps); +void gps_screens_show_waiting_signal(); +void gps_screens_show_help(); \ No newline at end of file diff --git a/firmware/main/modules/gps/wardriving/wardriving_module.c b/firmware/main/modules/gps/wardriving/wardriving_module.c index afd00b4e..c8d6c430 100644 --- a/firmware/main/modules/gps/wardriving/wardriving_module.c +++ b/firmware/main/modules/gps/wardriving/wardriving_module.c @@ -5,7 +5,7 @@ #include "freertos/task.h" #include "gps_module.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "sd_card.h" #include "wardriving_module.h" #include "wardriving_screens_module.h" @@ -292,7 +292,7 @@ void wardriving_module_start_scan() { if (wardriving_module_verify_sd_card() != ESP_OK) { return; } - + menus_module_set_app_state(true, wardriving_module_keyboard_cb); ESP_LOGI(TAG, "Start scan"); wardriving_module_state = WARDRIVING_MODULE_STATE_SCANNING; xTaskCreate(wardriving_module_scan_task, "wardriving_module_scan_task", 4096, @@ -328,8 +328,7 @@ void wardriving_module_keyboard_cb(uint8_t button_name, uint8_t button_event) { switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_exit_app(); break; case BUTTON_RIGHT: if (wardriving_module_state == WARDRIVING_MODULE_STATE_NO_SD_CARD) { diff --git a/firmware/main/modules/gps/wardriving/wardriving_screens_module.c b/firmware/main/modules/gps/wardriving/wardriving_screens_module.c index 29b293f9..66290b69 100644 --- a/firmware/main/modules/gps/wardriving/wardriving_screens_module.c +++ b/firmware/main/modules/gps/wardriving/wardriving_screens_module.c @@ -1,18 +1,38 @@ #include +#include "general_screens.h" #include "gps_bitmaps.h" +#include "menus_module.h" #include "oled_screen.h" #include "wardriving_screens_module.h" +char* wardriving_help_2[] = { + "This tool", "allows you to", "scan for WiFi", + "networks and", "save the", "results in a", + "CSV file on", "the SD card.", "", + "Before starting", "the scan, make", "sure your date", + "and time are", "correct.", +}; +const general_menu_t wardriving_help_menu = { + .menu_count = 14, + .menu_items = wardriving_help_2, + .menu_level = GENERAL_TREE_APP_MENU}; + +void wardriving_screens_show_help() { + general_register_scrolling_menu(&wardriving_help_menu); + general_screen_display_scrolling_text_handler(menus_module_exit_app); +} + void wardriving_screens_module_scanning(uint32_t packets, char* signal) { char* packets_str = (char*) malloc(20); sprintf(packets_str, "%ld", packets); - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("Packets", 64, 0, OLED_DISPLAY_INVERT); oled_screen_display_text(packets_str, 64, 1, OLED_DISPLAY_INVERT); oled_screen_display_text("Signal", 64, 3, OLED_DISPLAY_INVERT); oled_screen_display_text(signal, 64, 4, OLED_DISPLAY_INVERT); + oled_screen_display_show(); } void wardriving_screens_module_loading_text() { diff --git a/firmware/main/modules/gps/wardriving/wardriving_screens_module.h b/firmware/main/modules/gps/wardriving/wardriving_screens_module.h index e09852ee..44b82bdc 100644 --- a/firmware/main/modules/gps/wardriving/wardriving_screens_module.h +++ b/firmware/main/modules/gps/wardriving/wardriving_screens_module.h @@ -51,3 +51,5 @@ void wardriving_screens_module_formating_sd_card(); * @return void */ void wardriving_screens_module_failed_format_sd_card(); + +void wardriving_screens_show_help(); diff --git a/firmware/main/modules/keyboard/keyboard_module.c b/firmware/main/modules/keyboard/keyboard_module.c index 56f1d44e..c78661dc 100644 --- a/firmware/main/modules/keyboard/keyboard_module.c +++ b/firmware/main/modules/keyboard/keyboard_module.c @@ -1,33 +1,28 @@ #include "keyboard_module.h" #include "esp_log.h" #include "esp_timer.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "preferences.h" static int IDLE_TIMEOUT_S = 30; static const char* TAG = "keyboard"; -app_state_t app_state; +static input_callback_t input_callback = NULL; esp_timer_handle_t idle_timer; -bool is_idle; +static bool is_idle = false; +static bool lock_input = false; -void timer_callback() { - screen_module_menu_t menu = menu_screens_get_current_menu(); - if (menu == MENU_WIFI_ANALYZER_RUN || menu == MENU_WIFI_ANALYZER_SUMMARY || - menu == MENU_GPS_DATE_TIME || menu == MENU_GPS_LOCATION || - menu == MENU_GPS_SPEED) { - return; - } +static void button_event_cb(void* arg, void* data); - is_idle = true; - run_screen_saver(); -} void keyboard_module_reset_idle_timer() { esp_timer_stop(idle_timer); esp_timer_start_once(idle_timer, IDLE_TIMEOUT_S * 1000 * 1000); } -static void button_event_cb(void* arg, void* data); +void keyboard_module_set_lock(bool lock) { + lock_input = lock; +} + void button_init(uint32_t button_num, uint8_t mask) { button_config_t btn_cfg = { .type = BUTTON_TYPE_GPIO, @@ -75,59 +70,33 @@ static void button_event_cb(void* arg, void* data) { uint8_t button_event = ((button_event_t) data) & 0x0F; // & 0x0F to get the event number without the mask - const char* button_name_str = button_names[button_name]; - const char* button_event_str = button_events_name[button_event]; - - ESP_LOGI(TAG, "Button: %s, Event: %s", button_name_str, button_event_str); - - stop_screen_saver(); - esp_timer_stop(idle_timer); + // esp_timer_stop(idle_timer); // If we have an app with a custom handler, we call it - app_state = menu_screens_get_app_state(); - if (app_state.in_app) { - app_state.app_handler(button_name, button_event); - return; - } - IDLE_TIMEOUT_S = preferences_get_int("dp_time", 30); - esp_timer_start_once(idle_timer, IDLE_TIMEOUT_S * 1000 * 1000); - if (button_event != BUTTON_PRESS_DOWN) { + if (lock_input) { return; } - - if (is_idle) { - is_idle = false; - menu_screens_display_menu(); + if (input_callback) { + input_callback(button_name, button_event); return; } - switch (button_name) { - case BUTTON_BOOT: - break; - case BUTTON_LEFT: - menu_screens_exit_submenu(); - break; - case BUTTON_RIGHT: - int is_main = preferences_get_int("MENUNUMBER", MENU_MAIN); - if (preferences_get_int("logo_show", 1) == 1 && is_main == MENU_MAIN) { - preferences_put_int("logo_show", 0); - menu_screens_decrement_selected_item(); - break; - } - menu_screens_enter_submenu(); - break; - case BUTTON_UP: - menu_screens_decrement_selected_item(); - break; - case BUTTON_DOWN: - menu_screens_ingrement_selected_item(); - break; - default: - break; - } + // IDLE_TIMEOUT_S = preferences_get_int("dp_time", 30); + // esp_timer_start_once(idle_timer, IDLE_TIMEOUT_S * 1000 * 1000); + // if (button_event != BUTTON_PRESS_DOWN) { + // return; + // } + + // if (is_idle) { + // is_idle = false; + // return; + // } } +void keyboard_module_set_input_callback(input_callback_t input_cb) { + input_callback = input_cb; +} void keyboard_module_begin() { #if !defined(CONFIG_KEYBOARD_DEBUG) esp_log_level_set(TAG, ESP_LOG_NONE); @@ -137,9 +106,4 @@ void keyboard_module_begin() { button_init(RIGHT_BUTTON_PIN, RIGHT_BUTTON_MASK); button_init(UP_BUTTON_PIN, UP_BUTTON_MASK); button_init(DOWN_BUTTON_PIN, DOWN_BUTTON_MASK); - esp_timer_create_args_t timer_args = {.callback = timer_callback, - .arg = NULL, - - .name = "one_shot_timer"}; - esp_err_t err = esp_timer_create(&timer_args, &idle_timer); } diff --git a/firmware/main/modules/keyboard/keyboard_module.h b/firmware/main/modules/keyboard/keyboard_module.h index f036e43e..90677b63 100644 --- a/firmware/main/modules/keyboard/keyboard_module.h +++ b/firmware/main/modules/keyboard/keyboard_module.h @@ -16,26 +16,6 @@ #define BUTTON_ACTIVE_LEVEL 0 -/** - * @brief Events for the available keyboard buttons events - * - */ -static const char* button_events_name[] = { - "BUTTON_PRESS_DOWN", "BUTTON_PRESS_UP", - "BUTTON_PRESS_REPEAT", "BUTTON_PRESS_REPEAT_DONE", - "BUTTON_SINGLE_CLICK", "BUTTON_DOUBLE_CLICK", - "BUTTON_MULTIPLE_CLICK", "BUTTON_LONG_PRESS_START", - "BUTTON_LONG_PRESS_HOLD", "BUTTON_LONG_PRESS_UP", -}; - -/** - * @brief Events for the available keyboard buttons events - * - */ -static const char* button_names[] = { - "BOOT", "LEFT", "RIGHT", "UP", "DOWN", -}; - /** * @brief Enum of the available keyboard buttons * @@ -57,6 +37,8 @@ typedef struct { uint8_t button_event; } button_event_state_t; +typedef void (*input_callback_t)(uint8_t, uint8_t); + /** * @brief Initialize the keyboard button * @@ -69,3 +51,7 @@ typedef struct { void keyboard_module_begin(); void keyboard_module_reset_idle_timer(); + +void keyboard_module_set_lock(bool lock); + +void keyboard_module_set_input_callback(input_callback_t input_cb); \ No newline at end of file diff --git a/firmware/main/modules/led_events/led_events.c b/firmware/main/modules/led_events/led_events.c index ef2f31f3..99848ecc 100644 --- a/firmware/main/modules/led_events/led_events.c +++ b/firmware/main/modules/led_events/led_events.c @@ -4,10 +4,11 @@ #include "leds.h" static TaskHandle_t led_evenet_task = NULL; //////////// +static volatile bool led_event_running = false; void led_control_ble_tracking(void) { - led_start_blink(LED_LEFT, 255, 3, 100, 100, 400); - led_start_blink(LED_RIGHT, 255, 3, 100, 100, 400); + led_start_blink(LED_LEFT, 150, 3, 100, 100, 400); + led_start_blink(LED_RIGHT, 150, 3, 100, 100, 400); vTaskSuspend(NULL); /////////////////////// } @@ -35,7 +36,31 @@ void led_control_zigbee_scanning(void) { vTaskSuspend(NULL); /////////////////////// } +void led_control_pulse_leds(void) { + leds_on(); + vTaskDelay(150 / portTICK_PERIOD_MS); + leds_off(); + vTaskSuspend(NULL); /////////////////////// +} + +void led_control_pulse_led_right(void) { + led_right_on(); + vTaskDelay(150 / portTICK_PERIOD_MS); + led_right_off(); + vTaskSuspend(NULL); /////////////////////// +} + +void led_control_pulse_led_left(void) { + led_left_on(); + vTaskDelay(150 / portTICK_PERIOD_MS); + led_left_off(); + vTaskSuspend(NULL); /////////////////////// +} + void led_control_stop(void) { + if (led_event_running == false) + return; + led_event_running = false; leds_off(); vTaskDelete(led_evenet_task); ///////////// led_evenet_task = NULL; /////////////////// @@ -43,7 +68,7 @@ void led_control_stop(void) { void led_control_run_effect(effect_control effect_function) { // effect_function(); - + led_event_running = true; xTaskCreate(effect_function, "effect_function", 4096, NULL, 0, &led_evenet_task); //////////// } diff --git a/firmware/main/modules/led_events/led_events.h b/firmware/main/modules/led_events/led_events.h index 726ea627..2ce84b69 100644 --- a/firmware/main/modules/led_events/led_events.h +++ b/firmware/main/modules/led_events/led_events.h @@ -6,6 +6,9 @@ typedef void (*effect_control)(void); void led_control_run_effect(effect_control effect_function); void led_control_stop(void); +void led_control_pulse_leds(void); +void led_control_pulse_led_right(void); +void led_control_pulse_led_left(void); // BLE void led_control_ble_tracking(void); void led_control_ble_spam_breathing(void); diff --git a/firmware/main/modules/menu_screens/bitmaps.h b/firmware/main/modules/menu_screens/bitmaps.h deleted file mode 100644 index 1e8326ad..00000000 --- a/firmware/main/modules/menu_screens/bitmaps.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -// 'clear_line', 128x8px -static const unsigned char epd_bitmap_clear_line[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/firmware/main/modules/menu_screens/menu_screens_modules.c b/firmware/main/modules/menu_screens/menu_screens_modules.c deleted file mode 100644 index e4b1b85b..00000000 --- a/firmware/main/modules/menu_screens/menu_screens_modules.c +++ /dev/null @@ -1,676 +0,0 @@ -#include "menu_screens_modules.h" -#include "OTA.h" -#include "bitmaps.h" -#include "bitmaps_general.h" -#include "ble_module.h" -#include "esp_log.h" -#include "gps_module.h" -#include "leds.h" -#include "modules/settings/wifi/wifi_settings.h" -#include "oled_screen.h" -#include "open_thread.h" -#include "open_thread_module.h" -#include "ota_module.h" -#include "preferences.h" -#include "radio_selector.h" -#include "settings_module.h" -#include "string.h" -#include "web_file_browser_module.h" -#include "wifi_module.h" -#include "wifi_sniffer.h" -#include "zigbee_module.h" -#include "zigbee_screens_module.h" -#include "zigbee_switch.h" - -#define MAX_MENU_ITEMS_PER_SCREEN 3 - -static const char* TAG = "menu_screens_modules"; -uint8_t selected_item; -uint32_t num_items; -screen_module_menu_t previous_menu; -screen_module_menu_t current_menu; -uint8_t bluetooth_devices_count; - -static TaskHandle_t screen_saver_task = NULL; -static bool screen_saver_running = false; - -#ifdef CONFIG_RESOLUTION_128X64 - #define SCREEN_WIDTH 128 - #define SCREEN_HEIGHT 64 -#else // CONFIG_RESOLUTION_128X32 - #define SCREEN_WIDTH 128 - #define SCREEN_HEIGHT 32 -#endif - -static app_state_t app_state = { - .in_app = false, - .app_handler = NULL, -}; - -static enter_submenu_cb_t enter_submenu_cb = NULL; -static exit_submenu_cb_t exit_submenu_cb = NULL; - -void handle_user_selection(screen_module_menu_t user_selection); - -esp_err_t test_menu_list() { - ESP_LOGI(TAG, "Testing menus list size"); - size_t menu_list_size = sizeof(menu_list) / sizeof(menu_list[0]); - if (menu_list_size != MENU_COUNT) { - ESP_LOGE(TAG, "menu_list size is not as screen_module_menu_t enum"); - return ESP_FAIL; - } - ESP_LOGI(TAG, "Test passed"); - return ESP_OK; -} - -esp_err_t test_menu_next_menu_table() { - ESP_LOGI(TAG, "Testing next menu table size"); - size_t next_menu_table_size = - sizeof(next_menu_table) / sizeof(next_menu_table[0]); - if (next_menu_table_size != MENU_COUNT) { - ESP_LOGE(TAG, "next_menu_table size is not as screen_module_menu_t enum"); - return ESP_FAIL; - } - ESP_LOGI(TAG, "Test passed"); - return ESP_OK; -} - -esp_err_t test_prev_menu_table() { - ESP_LOGI(TAG, "Testing previous menu table size"); - size_t prev_menu_table_size = - sizeof(prev_menu_table) / sizeof(prev_menu_table[0]); - if (prev_menu_table_size != MENU_COUNT) { - ESP_LOGE(TAG, "prev_menu_table size is not as screen_module_menu_t enum"); - return ESP_FAIL; - } - ESP_LOGI(TAG, "Test passed"); - return ESP_OK; -} - -esp_err_t test_menu_items() { - ESP_LOGI(TAG, "Testing menu items size"); - size_t menu_items_size = sizeof(menu_items) / sizeof(menu_items[0]); - if (menu_items_size != MENU_COUNT) { - ESP_LOGE(TAG, "menu_items size is not as screen_module_menu_t enum"); - return ESP_FAIL; - } - ESP_LOGI(TAG, "Test passed"); - return ESP_OK; -} - -void run_tests() { - ESP_ERROR_CHECK(test_menu_list()); - ESP_ERROR_CHECK(test_menu_next_menu_table()); - ESP_ERROR_CHECK(test_prev_menu_table()); - ESP_ERROR_CHECK(test_menu_items()); -} - -static void show_splash_screen() { - int get_logo = preferences_get_int("dp_select", 0); - epd_bitmap_t logo; - // TODO: Add a function to get the based on array index - if (get_logo == 1) { - logo = minino_face_logo; - } else if (get_logo == 2) { - logo = minino_pwnlabs_logo; - } else if (get_logo == 3) { - logo = minino_electroniccats_logo; - } else { - logo = minino_letters_bitmap; - } - - screen_saver_running = true; - int w_screen_space = SCREEN_WIDTH - logo.width; - int h_screen_space = SCREEN_HEIGHT - logo.height; - int start_x_position = w_screen_space / 2; - static int start_y_position = 16; - static int x_direction = 1; - static int y_direction = 1; - - while (screen_saver_running) { - oled_screen_display_bitmap(logo.bitmap, start_x_position, start_y_position, - logo.width, logo.height, OLED_DISPLAY_NORMAL); - - start_x_position += x_direction; - start_y_position += y_direction; - - if (start_x_position <= 0 || start_x_position >= w_screen_space - 2) { - x_direction = -x_direction; - } - if (start_y_position <= 0 || start_y_position >= h_screen_space) { - y_direction = -y_direction; - } - vTaskDelay(10 / portTICK_PERIOD_MS); - } - - vTaskDelete(NULL); -} - -void run_screen_saver() { - oled_screen_clear(); - xTaskCreate(show_splash_screen, "show_splash_screen", 4096, NULL, 5, - &screen_saver_task); -} - -void start_screen_saver() { - if (screen_saver_task == NULL) { - run_screen_saver(); - } else { - screen_saver_running = true; - vTaskResume(screen_saver_task); - } -} - -void stop_screen_saver() { - if (screen_saver_task != NULL) { - screen_saver_running = false; - // vTaskSuspend(screen_saver_task); - } -} - -void show_logo() { - // buzzer_set_freq(50); - oled_screen_clear(); - leds_on(); - buzzer_play(); - // oled_screen_display_bitmap(epd_bitmap_face_logo, 46, 16, 32, 32, - // OLED_DISPLAY_NORMAL); - run_screen_saver(); - vTaskDelay(500 / portTICK_PERIOD_MS); - buzzer_stop(); -} - -void screen_module_set_screen(int current_menu) { - preferences_put_int("MENUNUMBER", prev_menu_table[current_menu]); - oled_screen_clear(); - menu_screens_display_text_banner("Exiting..."); -} - -void screen_module_get_screen() { - current_menu = preferences_get_int("MENUNUMBER", MENU_MAIN); - handle_user_selection(current_menu); - - // Update number of items - if (current_menu == MENU_MAIN) { - char** submenu = menu_items[current_menu]; - if (submenu != NULL) { - while (submenu[num_items] != NULL) { - num_items++; - } - } - preferences_put_int("logo_show", 1); - show_logo(); - } else { - preferences_put_int("logo_show", 0); - preferences_put_int("MENUNUMBER", MENU_MAIN); - menu_screens_display_menu(); - } -} - -void menu_screens_begin() { -#if !defined(CONFIG_MENU_SCREENS_DEBUG) - esp_log_level_set(TAG, ESP_LOG_NONE); -#endif - - selected_item = 0; - previous_menu = MENU_MAIN; - current_menu = MENU_MAIN; - num_items = 0; - bluetooth_devices_count = 0; - - run_tests(); - oled_screen_begin(); - oled_screen_clear(); - screen_module_get_screen(); -} - -/** - * @brief Add empty strings at the beginning and end of the array - * - * @param array - * @param length - * - * @return char** - */ -char** add_empty_strings(char** array, int length) { - char** newArray = malloc((length + 2) * sizeof(char*)); - - // Add the empty string at the beginning - newArray[0] = strdup(""); - - // Copy the original array - for (int i = 0; i < length; i++) { - newArray[i + 1] = strdup(array[i]); - } - - // Add the empty string at the end - newArray[length + 1] = strdup(""); - - num_items = length + 2; - - return newArray; -} - -/** - * @brief Remove the items flag - * - * @param items - * @param length - * - * @return char** - */ -char** remove_items_flag(char** items, int length) { - char** newArray = malloc((length - 1) * sizeof(char*)); - - for (int i = 0; i < length - 1; i++) { - newArray[i] = strdup(items[i + 1]); - // ESP_LOGI(TAG, "Item: %s", newArray[i]); - } - // ESP_LOGI(TAG, "Number of items: %d", length - 1); - - num_items = length + 1; - - return newArray; -} - -/** - * @brief Check if the current menu is empty - * - * @return bool - */ -bool is_menu_empty(screen_module_menu_t menu) { - return menu_items[menu][0] == NULL; -} - -/** - * @brief Check if the current menu is vertical scroll - * - * @return bool - */ -bool is_menu_vertical_scroll(screen_module_menu_t menu) { - if (is_menu_empty(menu)) { - return false; - } - return strcmp(menu_items[menu][0], VERTICAL_SCROLL_TEXT) == 0; -} - -/** - * @brief Check if the current menu is configuration - * - * @return bool - */ -bool is_menu_configuration(screen_module_menu_t menu) { - if (is_menu_empty(menu)) { - return false; - } - return strcmp(menu_items[menu][0], CONFIGURATION_MENU_ITEMS) == 0; -} - -bool is_menu_question(screen_module_menu_t menu) { - if (is_menu_empty(menu)) { - return false; - } - return strcmp(menu_items[menu][0], QUESTION_MENU_ITEMS) == 0; -} - -/** - * @brief Get the menu items for the current menu - * - * @return char** - */ -char** get_menu_items() { - num_items = 0; - char** submenu = menu_items[current_menu]; - if (submenu != NULL) { - while (submenu[num_items] != NULL) { - ESP_LOGI(TAG, "Item: %s", submenu[num_items]); - num_items++; - } - } - ESP_LOGI(TAG, "Number of items: %" PRIu32, num_items); - - if (num_items == 0) { - return NULL; - } - - if (is_menu_vertical_scroll(current_menu) || - is_menu_configuration(current_menu) || is_menu_question(current_menu)) { - return submenu; - } - - return add_empty_strings(menu_items[current_menu], num_items); -} - -/** - * @brief Display the menu items - * - * Show only 3 options at a time in the following order: - * Page 1: Option 1 - * Page 3: Option 2 -> selected option - * Page 5: Option 3 - * - * @param items - * - * @return void - */ -void display_menu_items(char** items) { -#ifdef CONFIG_RESOLUTION_128X64 - char* prefix = " "; - uint8_t page = 1; - uint8_t page_increment = 2; -#else // CONFIG_RESOLUTION_128X32 - char* prefix = "> "; - uint8_t page = 1; - uint8_t page_increment = 1; -#endif - - oled_screen_clear(); - for (int i = 0; i < 3; i++) { - char* text = (char*) malloc(strlen(items[i + selected_item]) + 2); - if (i == 0) { - sprintf(text, " %s", items[i + selected_item]); - } else if (i == 1) { - // sprintf(text, " %s", items[i + selected_item]); - sprintf(text, "%s%s", prefix, items[i + selected_item]); - } else { - sprintf(text, " %s", items[i + selected_item]); - } - - oled_screen_display_text(text, 0, page, OLED_DISPLAY_NORMAL); - page += page_increment; - } - -#ifdef CONFIG_RESOLUTION_128X64 - oled_screen_display_selected_item_box(); - oled_screen_display_show(); -#endif -} - -/** - * @brief Display the scrolling text - * - * @param text - * - * @return void - */ -void display_scrolling_text(char** text) { - uint8_t startIdx = - (selected_item >= MAX_PAGE) ? selected_item - (MAX_PAGE - 1) : 0; - selected_item = (num_items - 2 > MAX_PAGE && selected_item < (MAX_PAGE - 1)) - ? (MAX_PAGE - 1) - : selected_item; - oled_screen_clear(); - ESP_LOGI(TAG, "num: %" PRIu32, num_items - 2); - - for (uint8_t i = startIdx; i < num_items - 2; i++) { - // ESP_LOGI(TAG, "Text[%d]: %s", i, text[i]); - if (i == selected_item) { - oled_screen_display_text( - text[i], 0, i - startIdx, - OLED_DISPLAY_NORMAL); // Change it to INVERT to debug - } else { - oled_screen_display_text(text[i], 0, i - startIdx, OLED_DISPLAY_NORMAL); - } - } -} - -void display_configuration_items(char** items) { - uint8_t startIdx = - (selected_item >= MAX_PAGE) ? selected_item - (MAX_PAGE - 1) : 0; - oled_screen_clear(); - - for (uint8_t i = startIdx; i < num_items - 2; i++) { - if (i == selected_item) { - oled_screen_display_text(items[i], 0, i - startIdx, OLED_DISPLAY_INVERT); - } else { - oled_screen_display_text(items[i], 0, i - startIdx, OLED_DISPLAY_NORMAL); - } - } -} - -void display_question_items(char** items) { -#ifdef CONFIG_RESOLUTION_128X64 - uint8_t page_offset = 4; - uint8_t question_page = 1; -#else // CONFIG_RESOLUTION_128X32 - uint8_t page_offset = 2; - uint8_t question_page = 0; -#endif - - oled_screen_clear(); - - char* question = items[2]; - oled_screen_display_text_center(question, question_page, OLED_DISPLAY_NORMAL); - - // There are only two possible answers - if (selected_item > 1) { - selected_item = 1; - } - - for (uint8_t i = 0; i <= 1; i++) { - if (i == selected_item) { - oled_screen_display_text_center(items[i], i + page_offset, - OLED_DISPLAY_INVERT); - } else { - oled_screen_display_text_center(items[i], i + page_offset, - OLED_DISPLAY_NORMAL); - } - } -} - -/** - * @brief Display the menu items - * - * @return void - */ -void menu_screens_display_menu() { - char** items = get_menu_items(); - - if (items == NULL) { - ESP_LOGW(TAG, "Options is NULL"); - return; - } - - if (is_menu_vertical_scroll(current_menu)) { - char** text = remove_items_flag(items, num_items); - display_scrolling_text(text); - } else if (is_menu_configuration(current_menu)) { - char** new_items = remove_items_flag(items, num_items); - display_configuration_items(new_items); - } else if (is_menu_question(current_menu)) { - char** new_items = remove_items_flag(items, num_items); - display_question_items(new_items); - } else { - display_menu_items(items); - } -} - -app_state_t menu_screens_get_app_state() { - return app_state; -} - -void menu_screens_set_app_state(bool in_app, app_handler_t app_handler) { - app_state.in_app = in_app; - app_state.app_handler = app_handler; -} - -void menu_screens_register_enter_submenu_cb(enter_submenu_cb_t cb) { - enter_submenu_cb = cb; - ESP_LOGI(TAG, "Enter submenu callback registered"); -} - -void menu_screens_register_exit_submenu_cb(exit_submenu_cb_t cb) { - exit_submenu_cb = cb; - ESP_LOGI(TAG, "Exit submenu callback registered"); -} - -void menu_screens_unregister_submenu_cbs() { - enter_submenu_cb = NULL; - exit_submenu_cb = NULL; - ESP_LOGI(TAG, "Submenu callbacks unregistered"); -} - -screen_module_menu_t menu_screens_get_current_menu() { - return current_menu; -} - -uint32_t menu_screens_get_menu_length(char* menu[]) { - uint32_t num_items = 0; - if (menu != NULL) { - while (menu[num_items] != NULL) { - // ESP_LOGI(TAG, "Item: %s", menu[num_items]); - num_items++; - } - } - return num_items; -} - -bool menu_screens_is_configuration(screen_module_menu_t menu) { - if (is_menu_configuration(menu) && current_menu == menu) { - return true; - } else { - return false; - } -} - -void menu_screens_exit_submenu() { - ESP_LOGI(TAG, "Exiting submenu"); - previous_menu = prev_menu_table[current_menu]; - ESP_LOGI(TAG, "Previous: %s Current: %s", menu_list[previous_menu], - menu_list[current_menu]); - - if (exit_submenu_cb != NULL) { - exit_submenu_cb(); - } - - // TODO: Store selected item history into flash - selected_item = selected_item_history[current_menu]; - current_menu = previous_menu; - menu_screens_display_menu(); -} - -void handle_user_selection(screen_module_menu_t user_selection) { - if (enter_submenu_cb != NULL) { - enter_submenu_cb(user_selection); - return; - } - - switch (user_selection) { - case MENU_WEB_SD_BROWSER: - web_file_browser_module_init(); - break; - case MENU_SETTINGS: - settings_module_begin(); - break; - case MENU_WIFI_APPS: - wifi_module_begin(); - break; - case MENU_BLUETOOTH_TRAKERS_SCAN: - ble_module_begin(MENU_BLUETOOTH_TRAKERS_SCAN); - break; - case MENU_BLUETOOTH_SPAM: - ble_module_begin(MENU_BLUETOOTH_SPAM); - break; - case MENU_ZIGBEE_SWITCH: - zigbee_module_begin(MENU_ZIGBEE_SWITCH); - break; - case MENU_ZIGBEE_SNIFFER: - zigbee_module_begin(MENU_ZIGBEE_SNIFFER); - break; - case MENU_THREAD_APPS: - open_thread_module_begin(); - break; - case MENU_ZIGBEE_LIGHT: - oled_screen_clear(); - menu_screens_display_text_banner("In development"); - break; - case MENU_GPS: - gps_module_begin(); - break; - case MENU_ABOUT_UPDATE: - ota_module_init(); - break; - default: - ESP_LOGI(TAG, "Unhandled menu: %s", menu_list[user_selection]); - break; - } -} - -void menu_screens_enter_submenu() { - ESP_LOGI(TAG, "Selected item: %d", selected_item); - screen_module_menu_t next_menu = MENU_MAIN; - - if (is_menu_empty(current_menu)) { - ESP_LOGW(TAG, "Empty menu"); - return; - } else if (is_menu_vertical_scroll(current_menu)) { - selected_item = 0; // Avoid selecting invalid item - next_menu = current_menu; - } else if (is_menu_configuration(current_menu)) { - next_menu = current_menu; - } else { - next_menu = next_menu_table[current_menu][selected_item]; - } - - ESP_LOGI(TAG, "Previous: %s Current: %s", menu_list[current_menu], - menu_list[next_menu]); - - handle_user_selection(next_menu); - - if (current_menu != next_menu) { - selected_item_history[next_menu] = selected_item; - selected_item = 0; - } - current_menu = next_menu; - - if (!app_state.in_app) { - menu_screens_display_menu(); - } -} - -uint8_t menu_screens_get_selected_item() { - return selected_item; -} - -void menu_screens_ingrement_selected_item() { - selected_item = (selected_item == num_items - MAX_MENU_ITEMS_PER_SCREEN) - ? selected_item - : selected_item + 1; - menu_screens_display_menu(); -} - -void menu_screens_decrement_selected_item() { - selected_item = (selected_item == 0) ? 0 : selected_item - 1; - menu_screens_display_menu(); -} - -void menu_screens_display_text_banner(char* text) { -#ifdef CONFIG_RESOLUTION_128X64 - uint8_t page = 3; -#else // CONFIG_RESOLUTION_128X32 - uint8_t page = 2; -#endif - oled_screen_display_text_center(text, page, OLED_DISPLAY_NORMAL); -} - -void menu_screens_update_options(char* options[], uint8_t selected_option) { - uint32_t menu_length = menu_screens_get_menu_length(options); - uint8_t option = selected_option + 1; - uint8_t i = 0; - - for (i = 1; i < menu_length; i++) { - char* prev_item = options[i]; - ESP_LOGI(TAG, "Prev item: %s", prev_item); - char* new_item = malloc(strlen(prev_item) + 5); - char* start_of_number = strchr(prev_item, ']') + 2; - if (i == option) { - snprintf(new_item, strlen(prev_item) + 5, "[x] %s", start_of_number); - options[i] = new_item; - } else { - snprintf(new_item, strlen(prev_item) + 5, "[ ] %s", start_of_number); - options[i] = new_item; - } - ESP_LOGI(TAG, "New item: %s", options[i]); - } - options[i] = NULL; -} diff --git a/firmware/main/modules/menu_screens/menu_screens_modules.h b/firmware/main/modules/menu_screens/menu_screens_modules.h deleted file mode 100644 index 975e5ce4..00000000 --- a/firmware/main/modules/menu_screens/menu_screens_modules.h +++ /dev/null @@ -1,197 +0,0 @@ -#pragma once - -#include -#include - -#include "buzzer.h" -#include "cmd_sniffer.h" -#include "keyboard_module.h" -#include "screens_modules.h" - -typedef void (*app_handler_t)(uint8_t button_name, uint8_t button_event); -typedef void (*enter_submenu_cb_t)(screen_module_menu_t user_selection); -typedef void (*exit_submenu_cb_t)(); - -/** - * @brief Structure to store the app screen state information - * - */ -typedef struct { - bool in_app; - int app_selected; -} app_screen_state_information_t; - -/** - * @brief Struct to hold the keyboard state in app - */ -typedef struct { - bool in_app; - app_handler_t app_handler; -} app_state_t; - -/** - * @brief Enum with the screen module controls - */ -typedef enum { - SCREEN_IN_NAVIGATION = 0, - SCREEN_IN_APP, -} screen_module_controls_type_t; - -/** - * @brief Initialize the menu screens - * - * @return void - */ -void menu_screens_begin(); - -/** - * @brief Display the main menu - * - * @return void - */ -void menu_screens_display_menu(); - -/** - * @brief Get the app state - * - * @return app_state_t - */ -app_state_t menu_screens_get_app_state(); - -/** - * @brief Update the app state - * - * @param bool in_app - * @param app_handler_t app_handler - * - * @return void - */ -void menu_screens_set_app_state(bool in_app, app_handler_t app_handler); - -/** - * @brief Register enter submenu callback - * - * @param enter_submenu_cb_t enter_submenu_cb The user selection callback - * - * @return void - */ -void menu_screens_register_enter_submenu_cb(enter_submenu_cb_t cb); - -/** - * @brief Register exit submenu callback - * - * @param exit_submenu_cb_t enter_submenu_cb The user selection callback - * - * @return void - */ - -/** - * @brief Register exit submenu callback - * - * @param exit_submenu_cb_t cb The user selection callback - * - * @return void - */ -void menu_screens_register_exit_submenu_cb(exit_submenu_cb_t cb); - -/** - * @brief Unregister submenu callbacks - * - * @return void - */ -void menu_screens_unregister_submenu_cbs(); - -/** - * @brief Get the current menu - * - * @return screen_module_menu_t - */ -screen_module_menu_t menu_screens_get_current_menu(); - -/** - * @brief Get the current menu length - * - * @param char* menu[] The menu - * - * @return uint32_t - */ -uint32_t menu_screens_get_menu_length(char* menu[]); - -/** - * @brief Check if the given menu is configuration - * - * @param screen_module_menu_t user_selection The user selection - * - * @return bool - */ -bool menu_screens_is_configuration(screen_module_menu_t user_selection); - -/** - * @brief Exit the submenu - * - * @return void - */ -void menu_screens_exit_submenu(); - -/** - * @brief Enter the submenu - * - * @return void - */ -void menu_screens_enter_submenu(); - -/** - * @brief Get the selected item - * - * @return uint8_t - */ -uint8_t menu_screens_get_selected_item(); - -/** - * @brief Increment the selected item - * - * @return void - */ -void menu_screens_ingrement_selected_item(); - -/** - * @brief Decrement the selected item - * - * @return void - */ -void menu_screens_decrement_selected_item(); - -/** - * @brief Display `text` banner - * - * @param char* text The text to display - * - * @return void - */ -void menu_screens_display_text_banner(char* text); - -/** - * @brief Update the items array - * - * Set [x] to the selected option - * Set [ ] to the other options - * - * @param char* options[] The options - * @param uint8_t selected_option The selected option - * - * @return void - */ -void menu_screens_update_options(char* options[], uint8_t selected_option); - -/** - * @brief Saves the previous menu of the current menu in flash before software - * reset - * - * @param current_menu current menu - * - * @return void - */ -void screen_module_set_screen(int current_menu); - -void run_screen_saver(); -void stop_screen_saver(); \ No newline at end of file diff --git a/firmware/main/modules/menu_screens/screens_modules.h b/firmware/main/modules/menu_screens/screens_modules.h deleted file mode 100644 index 0461686c..00000000 --- a/firmware/main/modules/menu_screens/screens_modules.h +++ /dev/null @@ -1,784 +0,0 @@ -#pragma once - -#include - -#define MAX_NUM_ITEMS 8 // Can be increased if needed - -/** - * @brief Scrolling text flag - * - * Used to identify if the text is scrollable - * - * Add this flag to the text to make it scrollable - */ -#define VERTICAL_SCROLL_TEXT "vertical_scroll_text" - -/** - * @brief Configuration menu items - * - * Used to identify the configuration menu items - * - * Add this flag to the menu item to make it a configuration item - */ -#define CONFIGURATION_MENU_ITEMS "configuration" - -/** - * @brief Question menu items - * - * Used to identify the question menu items - * - * Add this flag to the menu item to make it a question item - */ -#define QUESTION_MENU_ITEMS "question" - -/** - * @brief Enum of menus - * - * Used to navigate through the different menus - * - * Modify this menu also requires to modify the `menu_list`, `next_menu_table`, - * `prev_menu_table` and `menu_items` arrays - */ -typedef enum { - MENU_MAIN = 0, - MENU_APPLICATIONS, - MENU_SETTINGS, - MENU_ABOUT, - /* Applications */ - MENU_WIFI_APPS, - MENU_BLUETOOTH_APPS, - MENU_ZIGBEE_APPS, - MENU_THREAD_APPS, - MENU_GPS, - /* WiFi applications */ - MENU_WIFI_ANALIZER, - MENU_WIFI_DEAUTH, - MENU_WIFI_DOS, - /* WiFi analizer items */ - MENU_WIFI_ANALYZER_RUN, - MENU_WIFI_ANALYZER_SETTINGS, - MENU_WIFI_ANALYZER_HELP, - /* WiFi analizer start items */ - MENU_WIFI_ANALYZER_ASK_SUMMARY, - MENU_WIFI_ANALYZER_SUMMARY, - /* WiFi analizer settings */ - MENU_WIFI_ANALYZER_CHANNEL, - MENU_WIFI_ANALYZER_DESTINATION, - MENU_WIFI_ANALYZER_SD_EREASE_WARNING, - /* Bluetooth applications */ - MENU_BLUETOOTH_TRAKERS_SCAN, - MENU_BLUETOOTH_SPAM, - /* Zigbee applications */ - MENU_ZIGBEE_SPOOFING, - MENU_ZIGBEE_SWITCH, - MENU_ZIGBEE_LIGHT, - MENU_ZIGBEE_SNIFFER, - /* Thread applications */ - MENU_THREAD_BROADCAST, - MENU_THREAD_SNIFFER, - /* Thread Sniffer App*/ - MENU_THREAD_SNIFFER_RUN, - /* GPS applications */ - MENU_GPS_WARDRIVING, - MENU_GPS_DATE_TIME, - MENU_GPS_LOCATION, - MENU_GPS_SPEED, - MENU_GPS_HELP, - /* Wardriving submenus */ - MENU_GPS_WARDRIVING_START, - MENU_GPS_WARDRIVING_HELP, - /* About submenus */ - MENU_ABOUT_VERSION, - MENU_ABOUT_LICENSE, - MENU_ABOUT_CREDITS, - MENU_ABOUT_LEGAL, - MENU_ABOUT_UPDATE, - /* Settings items */ - MENU_SETTINGS_DISPLAY, - MENU_WEB_SD_BROWSER, - MENU_SETTINGS_SYSTEM, - MENU_SETTINGS_TIME_ZONE, - MENU_SETTINGS_WIFI, - MENU_SETTINGS_SD_CARD, - MENU_SETTINGS_SD_CARD_INFO, - MENU_SETTINGS_SD_CARD_FORMAT, - /* Menu count */ - MENU_COUNT, // Keep this at the end -} screen_module_menu_t; - -/** - * @brief List of menus - * - * Used to get the menu name from the enum value - * following the order of the `screen_module_menu_t` enum - * - * Usage: menu_list[screen_module_menu_t] - */ -const char* menu_list[] = { - "MENU_MAIN", - "MENU_APPLICATIONS", - "MENU_SETTINGS", - "MENU_ABOUT", - "MENU_WIFI_APPS", - "MENU_BLUETOOTH_APPS", - "MENU_ZIGBEE_APPS", - "MENU_THREAD_APPS", - "MENU_GPS", - "MENU_WIFI_ANALIZER", - "MENU_WIFI_DEAUTH", - "MENU_WIFI_DOS", - "MENU_WIFI_ANALYZER_RUN", - "MENU_WIFI_ANALYZER_SETTINGS", - "MENU_WIFI_ANALYZER_HELP", - "MENU_WIFI_ANALYZER_ASK_SUMMARY", - "MENU_WIFI_ANALYZER_SUMMARY", - "MENU_WIFI_ANALYZER_CHANNEL", - "MENU_WIFI_ANALYZER_DESTINATION", - "MENU_WIFI_ANALYZER_SD_EREASE_WARNING", - "MENU_BLUETOOTH_TRAKERS_SCAN", - "MENU_BLUETOOTH_SPAM", - "MENU_ZIGBEE_SPOOFING", - "MENU_ZIGBEE_SWITCH", - "MENU_ZIGBEE_LIGHT", - "MENU_ZIGBEE_SNIFFER", - "MENU_THREAD_BROADCAST", - "MENU_THREAD_SNIFFER", - "MENU_THREAD_SNIFFER_RUN", - "MENU_GPS_WARDRIVING", - "MENU_GPS_DATE_TIME", - "MENU_GPS_LOCATION", - "MENU_GPS_SPEED", - "MENU_GPS_HELP", - "MENU_GPS_WARDRIVING_START", - "MENU_GPS_WARDRIVING_HELP", - "MENU_ABOUT_VERSION", - "MENU_ABOUT_LICENSE", - "MENU_ABOUT_CREDITS", - "MENU_ABOUT_LEGAL", - "MENU_ABOUT_UPDATE", - "MENU_SETTINGS_DISPLAY", - "MENU_WEB_SD_BROWSER", - "MENU_SETTINGS_SYSTEM", - "MENU_SETTINGS_TIME_ZONE", - "MENU_SETTINGS_WIFI", - "MENU_SETTINGS_SD_CARD", - "MENU_SETTINGS_SD_CARD_INFO", - "MENU_SETTINGS_SD_CARD_FORMAT", -}; - -/** - * @brief List of menus - * - * Used to get the next menu to display when the user selects an option - * following the order of the `screen_module_menu_t` enum - * - * Usage: next_menu_table[screen_module_menu_t][selected_item] - */ -const int next_menu_table[][MAX_NUM_ITEMS] = { - // MENU_MAIN - {MENU_APPLICATIONS, MENU_SETTINGS, MENU_ABOUT}, - // MENU_APPLICATIONS - { - MENU_WIFI_APPS, MENU_BLUETOOTH_APPS, MENU_ZIGBEE_APPS, MENU_THREAD_APPS, - MENU_GPS //, MENU_WEB_SD_BROWSER - }, - // MENU_SETTINGS - {MENU_SETTINGS_DISPLAY, MENU_SETTINGS_SYSTEM, MENU_WEB_SD_BROWSER}, - // MENU_ABOUT - {MENU_ABOUT_VERSION, MENU_ABOUT_LICENSE, MENU_ABOUT_CREDITS, - MENU_ABOUT_LEGAL, MENU_ABOUT_UPDATE}, - // MENU_WIFI_APPS - {MENU_WIFI_ANALIZER, MENU_WIFI_DEAUTH, MENU_WIFI_DOS}, - // MENU_BLUETOOTH_APPS - {MENU_BLUETOOTH_TRAKERS_SCAN, MENU_BLUETOOTH_SPAM}, - // MENU_ZIGBEE_APPS - {MENU_ZIGBEE_SPOOFING, MENU_ZIGBEE_SNIFFER}, - // MENU_THREAD_APPS - {MENU_THREAD_BROADCAST, MENU_THREAD_SNIFFER}, - // MENU_GPS - {MENU_GPS_WARDRIVING, MENU_GPS_DATE_TIME, MENU_GPS_LOCATION, MENU_GPS_SPEED, - MENU_GPS_HELP}, - // MENU_WIFI_ANALIZER - {MENU_WIFI_ANALYZER_RUN, MENU_WIFI_ANALYZER_SETTINGS, - MENU_WIFI_ANALYZER_HELP}, - // MENU_WIFI_DEAUTH - {MENU_WIFI_DEAUTH}, - // MENU_WIFI_DOS - {MENU_WIFI_DOS}, - // MENU_WIFI_ANALYZER_RUN - {MENU_WIFI_ANALYZER_RUN}, - // MENU_WIFI_ANALYZER_SETTINGS - {MENU_WIFI_ANALYZER_CHANNEL, MENU_WIFI_ANALYZER_DESTINATION}, - // MENU_WIFI_ANALYZER_HELP - {MENU_WIFI_ANALYZER_HELP}, - // MENU_WIFI_ANALYZER_ASK_SUMMARY [0] -> Yes, [1] -> No - {MENU_WIFI_ANALYZER_SUMMARY, MENU_WIFI_ANALIZER}, - // MENU_WIFI_ANALYZER_SUMMARY - {MENU_WIFI_ANALYZER_SUMMARY}, - // MENU_WIFI_ANALYZER_CHANNEL - {MENU_WIFI_ANALYZER_CHANNEL}, - // MENU_WIFI_ANALYZER_DESTINATION - {MENU_WIFI_ANALYZER_DESTINATION}, - // MENU_WIFI_ANALYZER_SD_EREASE_WARNING - {MENU_WIFI_ANALYZER_SD_EREASE_WARNING}, - // MENU_BLUETOOTH_TRAKERS_SCAN - {MENU_BLUETOOTH_TRAKERS_SCAN}, - // MENU_BLUETOOTH_SPAM - {MENU_BLUETOOTH_SPAM}, - // MENU_ZIGBEE_SPOOFING - {MENU_ZIGBEE_SWITCH, MENU_ZIGBEE_LIGHT}, - // MENU_ZIGBEE_SWITCH - {MENU_ZIGBEE_SWITCH}, - // MENU_ZIGBEE_LIGHT - {MENU_ZIGBEE_LIGHT}, - // MENU_ZIGBEE_SNIFFER - {MENU_ZIGBEE_SNIFFER}, - // MENU_THREAD_BROADCAST - {MENU_THREAD_BROADCAST}, - // MENU_THREAD_SNIFFER - {MENU_THREAD_SNIFFER_RUN}, - // MENU_THREAD_SNIFFER_RUN - {MENU_THREAD_SNIFFER_RUN}, - // MENU_GPS_WARDRIVING - {MENU_GPS_WARDRIVING_START, MENU_GPS_WARDRIVING_HELP}, - // MENU_GPS_DATE_TIME - {MENU_GPS_DATE_TIME}, - // MENU_GPS_LOCATION - {MENU_GPS_LOCATION}, - // MENU_GPS_SPEED - {MENU_GPS_SPEED}, - // MENU_GPS_HELP - {MENU_GPS_HELP}, - // MENU_GPS_WARDRIVING_START - {MENU_GPS_WARDRIVING_START}, - // MENU_GPS_WARDRIVING_HELP - {MENU_GPS_WARDRIVING_HELP}, - // MENU_ABOUT_VERSION - {MENU_ABOUT_VERSION}, - // MENU_ABOUT_LICENSE - {MENU_ABOUT_LICENSE}, - // MENU_ABOUT_CREDITS - {MENU_ABOUT_CREDITS}, - // MENU_ABOUT_LEGAL - {MENU_ABOUT_LEGAL}, - // MENU_ABOUT_UPDATE - {MENU_ABOUT_UPDATE}, - // MENU_SETTINGS_DISPLAY - {MENU_SETTINGS_DISPLAY}, - // MENU_WEB_SD_BROWSER - {MENU_WEB_SD_BROWSER}, - // MENU_SETTINGS_SYSTEM - {MENU_SETTINGS_TIME_ZONE, MENU_SETTINGS_WIFI, MENU_SETTINGS_SD_CARD}, - // MENU_SETTINGS_TIME_ZONE - {MENU_SETTINGS_TIME_ZONE}, - // MENU_SETTINGS_WIFI - {MENU_SETTINGS_WIFI}, - // MENU_SETTINGS_SD_CARD - {MENU_SETTINGS_SD_CARD_INFO, MENU_SETTINGS_SD_CARD_FORMAT}, - // MENU_SETTINGS_SD_CARD_INFO - {MENU_SETTINGS_SD_CARD_INFO}, - // MENU_SETTINGS_SD_CARD_FORMAT - {MENU_SETTINGS_SD_CARD_INFO}, -}; - -/** - * @brief List of menus - * - * Used to get the previous menu to display when the user returns to the - * previous menu in `menu_screens_exit_submenu`. Add the previous menu - * following the order of the `screen_module_menu_t` enum - * - * Usage: prev_menu_table[screen_module_menu_t] - */ -const int prev_menu_table[] = { - // PREVIOUS_MENU, // CURRENT_MENU - /*****************************************************************/ - MENU_MAIN, // MENU_MAIN - MENU_MAIN, // MENU_APPLICATIONS - MENU_MAIN, // MENU_SETTINGS - MENU_MAIN, // MENU_ABOUT - MENU_APPLICATIONS, // MENU_WIFI_APPS - MENU_APPLICATIONS, // MENU_BLUETOOTH_APPS - MENU_APPLICATIONS, // MENU_ZIGBEE_APPS - MENU_APPLICATIONS, // MENU_THREAD_APPS - MENU_APPLICATIONS, // MENU_GPS - MENU_WIFI_APPS, // MENU_WIFI_ANALIZER - MENU_WIFI_APPS, // MENU_WIFI_DEAUTH - MENU_WIFI_APPS, // MENU_WIFI_DOS - MENU_WIFI_ANALYZER_SUMMARY, // MENU_WIFI_ANALYZER_RUN - MENU_WIFI_ANALIZER, // MENU_WIFI_ANALYZER_SETTINGS - MENU_WIFI_ANALIZER, // MENU_WIFI_ANALYZER_HELP - MENU_WIFI_ANALYZER_RUN, // MENU_WIFI_ANALYZER_ASK_SUMMARY - MENU_WIFI_ANALIZER, // MENU_WIFI_ANALYZER_SUMMARY - MENU_WIFI_ANALYZER_SETTINGS, // MENU_WIFI_ANALYZER_CHANNEL - MENU_WIFI_ANALYZER_SETTINGS, // MENU_WIFI_ANALYZER_DESTINATION - MENU_WIFI_ANALYZER_SETTINGS, // MENU_WIFI_ANALYZER_SD_EREASE_WARNING - MENU_BLUETOOTH_APPS, // MENU_BLUETOOTH_TRAKERS_SCAN - MENU_BLUETOOTH_APPS, // MENU_BLUETOOTH_SPAM - MENU_ZIGBEE_APPS, // MENU_ZIGBEE_SPOOFING - MENU_ZIGBEE_SPOOFING, // MENU_ZIGBEE_SWITCH - MENU_ZIGBEE_SPOOFING, // MENU_ZIGBEE_LIGHT - MENU_ZIGBEE_APPS, // MENU_ZIGBEE_SNIFFER - MENU_THREAD_APPS, // MENU_THREAD_BROADCAST - MENU_THREAD_APPS, // MENU_THREAD_SNIFFER - MENU_THREAD_SNIFFER, // MENU_THREAD_SNIFFER_RUN - MENU_GPS, // MENU_GPS_WARDRIVING - MENU_GPS, // MENU_GPS_DATE_TIME - MENU_GPS, // MENU_GPS_LOCATION - MENU_GPS, // MENU_GPS_SPEED - MENU_GPS, // MENU_GPS_HELP - MENU_GPS_WARDRIVING, // MENU_GPS_WARDRIVING_START - MENU_GPS_WARDRIVING, // MENU_GPS_WARDRIVING_HELP - MENU_ABOUT, // MENU_ABOUT_VERSION - MENU_ABOUT, // MENU_ABOUT_LICENSE - MENU_ABOUT, // MENU_ABOUT_CREDITS - MENU_ABOUT, // MENU_ABOUT_LEGAL - MENU_ABOUT, // MENU_ABOUT_UPDATE - MENU_SETTINGS, // MENU_SETTINGS_DISPLAY - MENU_SETTINGS, // MENU_WEB_SD_BROWSER - MENU_SETTINGS, // MENU_SETTINGS_SYSTEM - MENU_SETTINGS_SYSTEM, // MENU_SETTINGS_TIME_ZONE - MENU_SETTINGS_SYSTEM, // MENU_SETTINGS_WIFI - MENU_SETTINGS_SYSTEM, // MENU_SETTINGS_SD_CARD - MENU_SETTINGS_SD_CARD, // MENU_SETTINGS_SD_CARD_INFO - MENU_SETTINGS_SD_CARD, // MENU_SETTINGS_SD_CARD_FORMAT -}; - -/** - * @brief History of selected items in each menu - * - * Used to keep track of the selected item in each menu - * - * Usage: selected_item_history[screen_module_menu_t] - */ -int selected_item_history[MENU_COUNT] = {0}; - -char* main_items[] = { - "Applications", - "Settings", - "About", - NULL, -}; - -char* applications_items[] = { - "WiFi", "Bluetooth", "Zigbee", "Thread", "GPS", NULL, -}; - -char* settings_items[] = { - "Display", - "System", - "File Manager", - NULL, -}; - -char* about_items[] = { - "Version", "License", "Credits", "Legal", "Update", NULL, -}; - -char* version_text[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "", - "", - "", - " Minino v" CONFIG_PROJECT_VERSION, - NULL, -}; - -char* license_text[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "", - "", - "", - " GNU GPL 3.0", - NULL, -}; - -char* credits_text[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Developed by", - "Electronic Cats", - "and PWnLabs", - "", - "With love from", - "Mexico...", - "", - "Thanks", - "- Kevin", - " @kevlem97", - "- Roberto", - "- Francisco", - " @deimoshall", - "and Electronic", - "Cats team", - NULL, -}; - -char* legal_text[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "The user", - "assumes all", - "responsibility", - "for the use of", - "MININO and", - "agrees to use", - "it legally and", - "ethically,", - "avoiding any", - "activities that", - "may cause harm,", - "interference,", - "or unauthorized", - "access to", - "systems or data.", - NULL, -}; - -char* wifi_items[] = { - "Analyzer", - "Deauth", - "DoS", - NULL, -}; - -const char* wifi_analyzer_items[] = { - "Start", - "Settings", - "Help", - NULL, -}; - -char* wifi_analizer_summary[120] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Summary", - NULL, -}; - -char* wifi_analizer_settings_items[] = { - "Channel", - "Destination", - NULL, -}; - -char* wifi_analizer_help[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "This tool", - "allows you to", - "analyze the", - "WiFi networks", - "around you.", - "", - "You can select", - "the channel and", - "the destination", - "to save the", - "results.", - NULL, -}; - -char* wifi_analizer_sd_warning[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Warning", - "", - "The SD card", - "is not", - "available.", - "", - "Please insert", - "an SD card", - "to save the", - "results.", - NULL, -}; - -char* wifi_analizer_sd_erease_warning[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "WARNING", - "Your SD card", - "data may be", - "erased if you", - "start the", - "WiFi analizer", - NULL, -}; - -char* wifi_analizer_summary_question[] = { - QUESTION_MENU_ITEMS, "Yes", "No", "Show summary?", NULL, -}; - -char* wifi_analizer_channel_items[] = { - CONFIGURATION_MENU_ITEMS, - "[ ] 1", - "[ ] 2", - "[ ] 3", - "[ ] 4", - "[ ] 5", - "[ ] 6", - "[ ] 7", - "[ ] 8", - "[ ] 9", - "[ ] 10", - "[ ] 11", - "[ ] 12", - "[ ] 13", - "[ ] 14", - NULL, -}; - -char* wifi_analizer_destination_items[] = { - CONFIGURATION_MENU_ITEMS, - "[ ] SD Card", - "[ ] Internal", - NULL, -}; - -char* bluetooth_items[] = { - "Trakers scan", - "Spam", - NULL, -}; - -char* zigbee_items[] = { - "Spoofing", - "Sniffer", - NULL, -}; - -char* zigbee_spoofing_items[] = { - "Switch", - "Light", - NULL, -}; - -char* thread_items[] = { - "Broadcast", - "Sniffer", - NULL, -}; - -char* thread_sniffer_items[] = { - "Run", - NULL, -}; - -char* gps_items[] = { - "Wardrive", "Date & Time", "Location", "Speed", "Help", NULL, -}; - -char* gps_date_time_items[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Signal:", - "", - "Date:", - "Time:", - NULL, -}; - -char* gps_location_items[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Signal:", - "", - "Latitude:", - "", - "Longitude:", - "", - "Altitude:", - "", - NULL, -}; - -char* gps_speed_items[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Signal:", - "", - "Speed:", - NULL, -}; - -char* gps_help[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "Verify your", - "time zone if", - "the time is not", - "correct, go to", - "`Settings/", - "System/Time", - "zone` and", - "select the", - "correct one.", - NULL, -}; - -char* wardriving_items[] = { - "Start", - "Help", - NULL, -}; - -char* wardriving_help[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "This tool", - "allows you to", - "scan for WiFi", - "networks and", - "save the", - "results in a", - "CSV file on", - "the SD card.", - "", - "Before starting", - "the scan, make", - "sure your date", - "and time are", - "correct.", - NULL, -}; - -char* gps_time_zone_options[] = { - CONFIGURATION_MENU_ITEMS, - "[ ] UTC-12", - "[ ] UTC-11", - "[ ] UTC-10", - "[ ] UTC-9:30", - "[ ] UTC-9", - "[ ] UTC-8", - "[ ] UTC-7", - "[ ] UTC-6", - "[ ] UTC-5", - "[ ] UTC-4", - "[ ] UTC-3:30", - "[ ] UTC-3", - "[ ] UTC-2", - "[ ] UTC-1", - "[ ] UTC+0", - "[ ] UTC+1", - "[ ] UTC+2", - "[ ] UTC+3", - "[ ] UTC+3:30", - "[ ] UTC+4", - "[ ] UTC+4:30", - "[ ] UTC+5", - "[ ] UTC+5:30", - "[ ] UTC+5:45", - "[ ] UTC+6", - "[ ] UTC+6:30", - "[ ] UTC+7", - "[ ] UTC+8", - "[ ] UTC+8:45", - "[ ] UTC+9", - "[ ] UTC+9:30", - "[ ] UTC+10", - "[ ] UTC+10:30", - "[ ] UTC+11", - "[ ] UTC+12", - "[ ] UTC+12:45", - "[ ] UTC+13", - "[ ] UTC+14", - NULL, -}; - -char* system_settings_items[] = { - "Time zone", - "WiFi", - "SD card", - NULL, -}; - -char* sd_card_settings_items[] = { - "Info", - "Check Format", - NULL, -}; - -char* sd_card_info[] = { - VERTICAL_SCROLL_TEXT, - /***************/ - "SD Card Info", - "", - "Name:", - "Space:", - "Speed:", - "Type:", - NULL, -}; - -char* sd_card_format_array[] = { - "This array is not used", - NULL, -}; - -char* empty_items[] = { - NULL, -}; - -/** - * @brief List of menu items - * - * Used to get the menu items from the menu enum value - * following the order of the `screen_module_menu_t` enum - * - * Usage: menu_items[screen_module_menu_t] - */ -char** menu_items[] = { - main_items, // MENU_MAIN - applications_items, // MENU_APPLICATIONS - settings_items, // MENU_SETTINGS - about_items, // MENU_ABOUT - wifi_items, // MENU_WIFI_APPS - bluetooth_items, // MENU_BLUETOOTH_APPS - zigbee_items, // MENU_ZIGBEE_APPS - thread_items, // MENU_THREAD_APPS - gps_items, // MENU_GPS - wifi_analyzer_items, // MENU_WIFI_ANALIZER - empty_items, // MENU_WIFI_DEAUTH - empty_items, // MENU_WIFI_DOS - empty_items, // MENU_WIFI_ANALYZER_RUN - wifi_analizer_settings_items, // MENU_WIFI_ANALYZER_SETTINGS - wifi_analizer_help, // MENU_WIFI_ANALYZER_HELP - wifi_analizer_summary_question, // MENU_WIFI_ANALYZER_ASK_SUMMARY - wifi_analizer_summary, // MENU_WIFI_ANALYZER_SUMMARY - wifi_analizer_channel_items, // MENU_WIFI_ANALYZER_CHANNEL - wifi_analizer_destination_items, // MENU_WIFI_ANALYZER_DESTINATION - wifi_analizer_sd_erease_warning, // MENU_WIFI_ANALYZER_SD_EREASE_WARNING - empty_items, // MENU_BLUETOOTH_TRAKERS_SCAN - empty_items, // MENU_BLUETOOTH_SPAM - zigbee_spoofing_items, // MENU_ZIGBEE_SPOOFING - empty_items, // MENU_ZIGBEE_SWITCH - empty_items, // MENU_ZIGBEE_LIGHT - empty_items, // MENU_ZIGBEE_SNIFFER - empty_items, // MENU_THREAD_BROADCAST - thread_sniffer_items, // MENU_THREAD_SNIFFER - empty_items, // MENU_THREAD_SNIFFER_RUN - wardriving_items, // MENU_GPS_WARDRIVING - gps_date_time_items, // MENU_GPS_DATE_TIME - gps_location_items, // MENU_GPS_LOCATION - gps_speed_items, // MENU_GPS_SPEED - gps_help, // MENU_GPS_HELP - empty_items, // MENU_GPS_WARDRIVING_START - wardriving_help, // MENU_GPS_WARDRIVING_HELP - version_text, // MENU_ABOUT_VERSION - license_text, // MENU_ABOUT_LICENSE - credits_text, // MENU_ABOUT_CREDITS - legal_text, // MENU_ABOUT_LEGAL - empty_items, // MENU_ABOUT_UPDATE - empty_items, // MENU_SETTINGS_DISPLAY - empty_items, // MENU_WEB_SD_BROWSER - system_settings_items, // MENU_SETTINGS_SYSTEM - gps_time_zone_options, // MENU_SETTINGS_TIME_ZONE - empty_items, // MENU_SETTINGS_WIFI - sd_card_settings_items, // MENU_SETTINGS_SD_CARD - sd_card_info, // MENU_SETTINGS_SD_CARD_INFO - sd_card_format_array, // MENU_SETTINGS_SD_CARD_FORMAT -}; diff --git a/firmware/main/modules/menus_module/menus.h b/firmware/main/modules/menus_module/menus.h new file mode 100644 index 00000000..414d1000 --- /dev/null +++ b/firmware/main/modules/menus_module/menus.h @@ -0,0 +1,509 @@ +#pragma once +#include +#include +#include "about_module.h" +#include "hid_module.h" +#include "spam_module.h" +#include "trackers_module.h" +#include "z_switch_module.h" + +#include "catdos_module.h" +#include "deauth_module.h" +#include "display_settings.h" +#include "file_manager_module.h" +#include "gps_module.h" +#include "gps_screens.h" +#include "open_thread_module.h" +#include "ota_module.h" +#include "sd_card_settings_module.h" +#include "settings_module.h" +#include "stealth_mode.h" +#include "wardriving_module.h" +#include "wardriving_screens_module.h" +#include "web_file_browser_module.h" +#include "wifi_module.h" +#include "wifi_settings.h" +#include "zigbee_module.h" + +typedef enum { + MENU_MAIN_2 = 0, + MENU_APPLICATIONS_2, + MENU_SETTINGS_2, + MENU_ABOUT_2, + /* Applications */ + MENU_WIFI_APPS_2, + MENU_BLUETOOTH_APPS_2, + MENU_ZIGBEE_APPS_2, + MENU_THREAD_APPS_2, + MENU_GPS_2, + /* WiFi applications */ + MENU_WIFI_ANALIZER_2, + MENU_WIFI_DEAUTH_2, + MENU_WIFI_DOS_2, + /* WiFi analizer items */ + MENU_WIFI_ANALYZER_RUN_2, + MENU_WIFI_ANALYZER_SETTINGS_2, + MENU_WIFI_ANALYZER_HELP_2, + /* WiFi analizer start items */ + MENU_WIFI_ANALYZER_ASK_SUMMARY_2, + MENU_WIFI_ANALYZER_SUMMARY_2, + /* WiFi analizer settings */ + MENU_WIFI_ANALYZER_CHANNEL_2, + MENU_WIFI_ANALYZER_DESTINATION_2, + MENU_WIFI_ANALYZER_SD_EREASE_WARNING_2, + /* Bluetooth applications */ + MENU_BLUETOOTH_TRAKERS_SCAN_2, + MENU_BLUETOOTH_SPAM_2, + MENU_BLUETOOTH_HID, + /* Zigbee applications */ + MENU_ZIGBEE_SPOOFING_2, + MENU_ZIGBEE_SWITCH_2, + MENU_ZIGBEE_LIGHT_2, + MENU_ZIGBEE_SNIFFER_2, + /* Thread applications */ + MENU_THREAD_BROADCAST_2, + MENU_THREAD_SNIFFER_2, + /* Thread Sniffer App */ + MENU_THREAD_SNIFFER_RUN_2, + /* GPS applications */ + MENU_GPS_WARDRIVING_2, + MENU_GPS_DATE_TIME_2, + MENU_GPS_LOCATION_2, + MENU_GPS_SPEED_2, + MENU_GPS_HELP_2, + /* Wardriving submenus */ + MENU_GPS_WARDRIVING_START_2, + MENU_GPS_WARDRIVING_HELP_2, + /* About submenus */ + MENU_ABOUT_VERSION_2, + MENU_ABOUT_LICENSE_2, + MENU_ABOUT_CREDITS_2, + MENU_ABOUT_LEGAL_2, + MENU_ABOUT_UPDATE_2, + /* Settings items */ + MENU_SETTINGS_DISPLAY_2, + MENU_FILE_MANAGER_2, + MENU_FILE_MANAGER_LOCAL_2, + MENU_FILE_MANAGER_WEB_2, + MENU_SETTINGS_SYSTEM_2, + MENU_SETTINGS_TIME_ZONE_2, + MENU_SETTINGS_WIFI_2, + MENU_SETTINGS_SD_CARD_2, + MENU_SETTINGS_SD_CARD_INFO_2, + MENU_SETTINGS_SD_CARD_FORMAT_2, + MENU_STEALTH_MODE_2, + /* Menu count */ + MENU_COUNT_2, // Keep this at the end +} menu_idx_t; + +typedef struct { + menu_idx_t menu_idx; + menu_idx_t parent_idx; + const char* display_name; + uint8_t last_selected_submenu; + void* on_enter_cb; + void* on_exit_cb; + bool is_visible; +} menu_t; + +typedef struct { + menu_idx_t current_menu; + menu_idx_t parent_menu_idx; + uint8_t selected_submenu; + uint8_t submenus_count; + uint8_t menus_count; + uint8_t** submenus_idx; + bool input_lock; +} menus_manager_t; + +menu_t menus[] = { ////////////////////////////////// + {.display_name = "Must Not See This", + .menu_idx = MENU_MAIN_2, + .parent_idx = -1, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = false}, + {.display_name = "Applications", + .menu_idx = MENU_APPLICATIONS_2, + .parent_idx = MENU_MAIN_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Settings", + .menu_idx = MENU_SETTINGS_2, + .parent_idx = MENU_MAIN_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "About", + .menu_idx = MENU_ABOUT_2, + .parent_idx = MENU_MAIN_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Version", + .menu_idx = MENU_ABOUT_VERSION_2, + .parent_idx = MENU_ABOUT_2, + .last_selected_submenu = 0, + .on_enter_cb = about_module_display_version, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "License", + .menu_idx = MENU_ABOUT_LICENSE_2, + .parent_idx = MENU_ABOUT_2, + .last_selected_submenu = 0, + .on_enter_cb = about_module_display_license, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Credits", + .menu_idx = MENU_ABOUT_CREDITS_2, + .parent_idx = MENU_ABOUT_2, + .last_selected_submenu = 0, + .on_enter_cb = about_module_display_credits_menu, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Legal", + .menu_idx = MENU_ABOUT_LEGAL_2, + .parent_idx = MENU_ABOUT_2, + .last_selected_submenu = 0, + .on_enter_cb = about_module_display_legal_menu, + .on_exit_cb = NULL, + .is_visible = true}, +#ifdef CONFIG_WIFI_APPS_ENABLE + {.display_name = "WiFi", + .menu_idx = MENU_WIFI_APPS_2, + .parent_idx = MENU_APPLICATIONS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_WIFI_APP_ANALYZER + {.display_name = "Analyzer", + .menu_idx = MENU_WIFI_ANALIZER_2, + .parent_idx = MENU_WIFI_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_module_analizer_begin, + .on_exit_cb = wifi_module_analyzer_exit, + .is_visible = true}, + {.display_name = "Start", + .menu_idx = MENU_WIFI_ANALYZER_RUN_2, + .parent_idx = MENU_WIFI_ANALIZER_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_module_analyzer_run, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Settings", + .menu_idx = MENU_WIFI_ANALYZER_SETTINGS_2, + .parent_idx = MENU_WIFI_ANALIZER_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Channel", + .menu_idx = MENU_WIFI_ANALYZER_CHANNEL_2, + .parent_idx = MENU_WIFI_ANALYZER_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_module_analyzer_channel, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Destination", + .menu_idx = MENU_WIFI_ANALYZER_DESTINATION_2, + .parent_idx = MENU_WIFI_ANALYZER_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_module_analyzer_destination, + .on_exit_cb = wifi_module_analyzer_destination_exit, + .is_visible = true}, + {.display_name = "Help", + .menu_idx = MENU_WIFI_ANALYZER_HELP_2, + .parent_idx = MENU_WIFI_ANALIZER_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_module_show_analyzer_help, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_WIFI_APP_DEAUTH + {.display_name = "Deauth", + .menu_idx = MENU_WIFI_DEAUTH_2, + .parent_idx = MENU_WIFI_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = deauth_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_WIFI_APP_DOS + {.display_name = "DoS", + .menu_idx = MENU_WIFI_DOS_2, + .parent_idx = MENU_WIFI_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = catdos_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif +#endif +#ifdef CONFIG_BLUETOOTH_APPS_ENABLE + {.display_name = "Bluetooth", + .menu_idx = MENU_BLUETOOTH_APPS_2, + .parent_idx = MENU_APPLICATIONS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_BLUETOOTH_APP_TRAKERS + {.display_name = "Trakers scan", + .menu_idx = MENU_BLUETOOTH_TRAKERS_SCAN_2, + .parent_idx = MENU_BLUETOOTH_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = trackers_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_BLUETOOTH_APP_SPAM + {.display_name = "Spam", + .menu_idx = MENU_BLUETOOTH_SPAM_2, + .parent_idx = MENU_BLUETOOTH_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = ble_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_BLUETOOTH_APP_HID + {.display_name = "HID", + .menu_idx = MENU_BLUETOOTH_HID, + .parent_idx = MENU_BLUETOOTH_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = hid_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif +#endif +#ifdef CONFIG_ZIGBEE_APPS_ENABLE + {.display_name = "Zigbee", + .menu_idx = MENU_ZIGBEE_APPS_2, + .parent_idx = MENU_APPLICATIONS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_ZIGBEE_APP_SPOOFING + {.display_name = "Spoofing", + .menu_idx = MENU_ZIGBEE_SPOOFING_2, + .parent_idx = MENU_ZIGBEE_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Switch", + .menu_idx = MENU_ZIGBEE_SWITCH_2, + .parent_idx = MENU_ZIGBEE_SPOOFING_2, + .last_selected_submenu = 0, + .on_enter_cb = zigbee_module_switch_enter, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Light", + .menu_idx = MENU_ZIGBEE_LIGHT_2, + .parent_idx = MENU_ZIGBEE_SPOOFING_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_ZIGBEE_APP_SNIFFER + {.display_name = "Sniffer", + .menu_idx = MENU_ZIGBEE_SNIFFER_2, + .parent_idx = MENU_ZIGBEE_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = zigbee_module_sniffer_enter, + .on_exit_cb = NULL, + .is_visible = true}, + #endif +#endif +#ifdef CONFIG_THREAD_APPS_ENABLE + {.display_name = "Thread", + .menu_idx = MENU_THREAD_APPS_2, + .parent_idx = MENU_APPLICATIONS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_THREAD_APP_BROADCAST + {.display_name = "Broadcast", + .menu_idx = MENU_THREAD_BROADCAST_2, + .parent_idx = MENU_THREAD_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = open_thread_module_broadcast_enter, + .on_exit_cb = open_thread_module_exit, + .is_visible = true}, + #endif + #ifdef CONFIG_THREAD_APP_SNIFFER + {.display_name = "Sniffer", + .menu_idx = MENU_THREAD_SNIFFER_2, + .parent_idx = MENU_THREAD_APPS_2, + .last_selected_submenu = 0, + .on_enter_cb = open_thread_module_sniffer_enter, + .on_exit_cb = open_thread_module_exit, + .is_visible = true}, + {.display_name = "Run", + .menu_idx = MENU_THREAD_SNIFFER_RUN_2, + .parent_idx = MENU_THREAD_SNIFFER_2, + .last_selected_submenu = 0, + .on_enter_cb = open_thread_module_sniffer_run, + .on_exit_cb = NULL, + .is_visible = true}, + #endif +#endif +#ifdef CONFIG_GPS_APPS_ENABLE + {.display_name = "GPS", + .menu_idx = MENU_GPS_2, + .parent_idx = MENU_APPLICATIONS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_GPS_APP_WARDRIVING + {.display_name = "Wardriving", + .menu_idx = MENU_GPS_WARDRIVING_2, + .parent_idx = MENU_GPS_2, + .last_selected_submenu = 0, + .on_enter_cb = wardriving_module_begin, + .on_exit_cb = wardriving_module_end, + .is_visible = true}, + {.display_name = "Start", + .menu_idx = MENU_GPS_WARDRIVING_START_2, + .parent_idx = MENU_GPS_WARDRIVING_2, + .last_selected_submenu = 0, + .on_enter_cb = wardriving_module_start_scan, + .on_exit_cb = wardriving_module_stop_scan, + .is_visible = true}, + {.display_name = "Help", + .menu_idx = MENU_GPS_WARDRIVING_HELP_2, + .parent_idx = MENU_GPS_WARDRIVING_2, + .last_selected_submenu = 0, + .on_enter_cb = wardriving_screens_show_help, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + {.display_name = "Date & Time", + .menu_idx = MENU_GPS_DATE_TIME_2, + .parent_idx = MENU_GPS_2, + .last_selected_submenu = 0, + .on_enter_cb = gps_module_general_data_run, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Location", + .menu_idx = MENU_GPS_LOCATION_2, + .parent_idx = MENU_GPS_2, + .last_selected_submenu = 0, + .on_enter_cb = gps_module_general_data_run, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Speed", + .menu_idx = MENU_GPS_SPEED_2, + .parent_idx = MENU_GPS_2, + .last_selected_submenu = 0, + .on_enter_cb = gps_module_general_data_run, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Help", + .menu_idx = MENU_GPS_HELP_2, + .parent_idx = MENU_GPS_2, + .last_selected_submenu = 0, + .on_enter_cb = gps_screens_show_help, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Time zone", + .menu_idx = MENU_SETTINGS_TIME_ZONE_2, + .parent_idx = MENU_SETTINGS_SYSTEM_2, + .last_selected_submenu = 0, + .on_enter_cb = settings_module_time_zone, + .on_exit_cb = NULL, + .is_visible = true}, +#endif +#ifdef CONFIG_OTA_ENABLE + {.display_name = "Update", + .menu_idx = MENU_ABOUT_UPDATE_2, + .parent_idx = MENU_ABOUT_2, + .last_selected_submenu = 0, + .on_enter_cb = ota_module_init, + .on_exit_cb = NULL, + .is_visible = true}, +#endif + {.display_name = "Display", + .menu_idx = MENU_SETTINGS_DISPLAY_2, + .parent_idx = MENU_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = display_config_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "System", + .menu_idx = MENU_SETTINGS_SYSTEM_2, + .parent_idx = MENU_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "WiFi", + .menu_idx = MENU_SETTINGS_WIFI_2, + .parent_idx = MENU_SETTINGS_SYSTEM_2, + .last_selected_submenu = 0, + .on_enter_cb = wifi_settings_begin, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "SD card", + .menu_idx = MENU_SETTINGS_SD_CARD_2, + .parent_idx = MENU_SETTINGS_SYSTEM_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Info", + .menu_idx = MENU_SETTINGS_SD_CARD_INFO_2, + .parent_idx = MENU_SETTINGS_SD_CARD_2, + .last_selected_submenu = 0, + .on_enter_cb = update_sd_card_info, + .on_exit_cb = NULL, + .is_visible = true}, + {.display_name = "Check Format", + .menu_idx = MENU_SETTINGS_SD_CARD_FORMAT_2, + .parent_idx = MENU_SETTINGS_SD_CARD_2, + .last_selected_submenu = 0, + .on_enter_cb = sd_card_settings_verify_sd_card, + .on_exit_cb = NULL, + .is_visible = true}, +#ifdef CONFIG_FILE_MANAGER_ENABLE + {.display_name = "File Manager", + .menu_idx = MENU_FILE_MANAGER_2, + .parent_idx = MENU_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = NULL, + .on_exit_cb = NULL, + .is_visible = true}, + #ifdef CONFIG_FILE_MANAGER_LOCAL + {.display_name = "Local", + .menu_idx = MENU_FILE_MANAGER_LOCAL_2, + .parent_idx = MENU_FILE_MANAGER_2, + .last_selected_submenu = 0, + .on_enter_cb = file_manager_module_init, + .on_exit_cb = NULL, + .is_visible = true}, + #endif + #ifdef CONFIG_FILE_MANAGER_WEB + {.display_name = "Web", + .menu_idx = MENU_FILE_MANAGER_WEB_2, + .parent_idx = MENU_FILE_MANAGER_2, + .last_selected_submenu = 0, + .on_enter_cb = web_file_browser_module_begin, + .on_exit_cb = NULL, + .is_visible = true}, + #endif +#endif + {.display_name = "Stealth Mode", + .menu_idx = MENU_STEALTH_MODE_2, + .parent_idx = MENU_SETTINGS_2, + .last_selected_submenu = 0, + .on_enter_cb = stealth_mode_open_menu, + .on_exit_cb = NULL, + .is_visible = true}}; \ No newline at end of file diff --git a/firmware/main/modules/menus_module/menus_module.c b/firmware/main/modules/menus_module/menus_module.c new file mode 100644 index 00000000..698dc384 --- /dev/null +++ b/firmware/main/modules/menus_module/menus_module.c @@ -0,0 +1,235 @@ +#include "menus_module.h" + +#include +#include "bitmaps_general.h" +#include "buzzer.h" +#include "led_events.h" +#include "menus_screens.h" +#include "modals_module.h" +#include "oled_screen.h" +#include "preferences.h" +#include "screen_saver.h" + +#ifdef CONFIG_RESOLUTION_128X64 + #define SCREEN_WIDTH 128 + #define SCREEN_HEIGHT 64 +#else // CONFIG_RESOLUTION_128X32 + #define SCREEN_WIDTH 128 + #define SCREEN_HEIGHT 32 +#endif + +static menus_manager_t* menus_ctx; +static void menus_input_cb(uint8_t button_name, uint8_t button_event); +static app_state2_t app_state2 = {.in_app = false, + .input_callback = NULL, + .input_last_callback = NULL}; +static TaskHandle_t screen_saver_task = NULL; +static bool screen_saver_running = false; + +static uint8_t get_menu_idx(menu_idx_t menu_idx) { + for (uint8_t i = 0; i < menus_ctx->menus_count; i++) { + if (menus[i].menu_idx == menu_idx) { + return i; + } + } + return 0; +} + +static void update_menus() { + if (menus_ctx->submenus_idx != NULL) { + for (uint8_t i = 0; i < menus_ctx->submenus_count; i++) { + free(menus_ctx->submenus_idx[i]); + } + free(menus_ctx->submenus_idx); + } + menus_ctx->submenus_idx = NULL; + menus_ctx->submenus_count = 0; + for (uint8_t i = 0; i < menus_ctx->menus_count; i++) { + if (menus[i].is_visible && menus[i].parent_idx == menus_ctx->current_menu) { + menus_ctx->submenus_count++; + } + } + if (!menus_ctx->submenus_count) { + return; + } + menus_ctx->submenus_idx = + malloc(menus_ctx->submenus_count * sizeof(uint8_t*)); + uint8_t submenu_idx = 0; + for (uint8_t i = 0; i < menus_ctx->menus_count; i++) { + if (menus[i].is_visible && menus[i].parent_idx == menus_ctx->current_menu) { + menus_ctx->submenus_idx[submenu_idx] = malloc(sizeof(uint8_t)); + *menus_ctx->submenus_idx[submenu_idx] = i; + submenu_idx++; + } + } +} + +static void display_menus() { + menus_screens_display_menus_f(menus_ctx); +} + +static void refresh_menus() { + update_menus(); + menus_ctx->selected_submenu = + menus[get_menu_idx(menus_ctx->current_menu)].last_selected_submenu; + display_menus(); +} +static void navigation_up() { + menus_ctx->selected_submenu = menus_ctx->selected_submenu == 0 + ? menus_ctx->submenus_count - 1 + : menus_ctx->selected_submenu - 1; + display_menus(); +} +static void navigation_down() { + menus_ctx->selected_submenu = + ++menus_ctx->selected_submenu < menus_ctx->submenus_count + ? menus_ctx->selected_submenu + : 0; + display_menus(); +} + +static void navigation_enter() { + if (!menus_ctx->submenus_count) { + return; + } + menus[get_menu_idx(menus_ctx->current_menu)].last_selected_submenu = + menus_ctx->selected_submenu; + menus_ctx->current_menu = + menus[*menus_ctx->submenus_idx[menus_ctx->selected_submenu]].menu_idx; + menus_ctx->parent_menu_idx = + menus[get_menu_idx(menus_ctx->current_menu)].parent_idx; + refresh_menus(); + void (*cb)() = menus[get_menu_idx(menus_ctx->current_menu)].on_enter_cb; + if (cb) { + cb(); + } +} + +static void navigation_exit() { + if (menus_ctx->current_menu == MENU_MAIN_2) { + screen_saver_run(); + return; + } + menus[get_menu_idx(menus_ctx->current_menu)].last_selected_submenu = + menus_ctx->selected_submenu; + void (*cb)() = menus[get_menu_idx(menus_ctx->current_menu)].on_exit_cb; + if (cb) { + cb(); + } + menus_ctx->current_menu = + menus[get_menu_idx(menus_ctx->current_menu)].parent_idx; + menus_ctx->parent_menu_idx = + menus[get_menu_idx(menus_ctx->current_menu)].parent_idx; + refresh_menus(); +} + +static void menus_input_cb(uint8_t button_name, uint8_t button_event) { + if (menus_ctx->input_lock) { + return; + } + + if (app_state2.in_app) { + if (app_state2.input_callback) { + app_state2.input_callback(button_name, button_event); + return; + } + app_state2.in_app = false; + return; + } + + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + + if (screen_saver_get_idle_state()) { + display_menus(); + return; + } + + switch (button_name) { + case BUTTON_LEFT: + navigation_exit(); + break; + case BUTTON_RIGHT: + navigation_enter(); + break; + case BUTTON_UP: + navigation_up(); + break; + case BUTTON_DOWN: + navigation_down(); + break; + default: + break; + } +} + +static void show_logo() { + oled_screen_clear(); + led_control_run_effect(led_control_pulse_leds); + buzzer_play_for(100); + screen_saver_run(); +} + +void menus_module_set_reset_screen(menu_idx_t menu) { + preferences_put_int("MENUNUMBER", menu); + modals_module_show_banner("Exiting..."); +} + +static void get_reset_menu() { + menus_ctx->current_menu = preferences_get_int("MENUNUMBER", MENU_MAIN_2); + if ((int) menus_ctx->current_menu == MENU_MAIN_2) { + show_logo(); + } else { + preferences_put_int("MENUNUMBER", MENU_MAIN_2); + screen_saver_get_idle_state(); + refresh_menus(); + } +} + +void menus_module_enable_input() { + menus_ctx->input_lock = false; +} +void menus_module_disable_input() { + menus_ctx->input_lock = true; +} + +void menus_module_set_app_state(bool in_app, input_callback_t input_cb) { + app_state2.in_app = in_app; + app_state2.input_last_callback = app_state2.input_callback; + app_state2.input_callback = input_cb; + screen_saver_get_idle_state(); +} + +void menus_module_set_app_state_last() { + app_state2.input_callback = app_state2.input_last_callback; +} + +void menus_module_restart() { + menus_module_set_reset_screen(menus_ctx->parent_menu_idx); + esp_restart(); +} + +void menus_module_exit_app() { + menus_module_set_app_state(false, menus_input_cb); + screen_saver_get_idle_state(); + navigation_exit(); +} + +menu_idx_t menus_module_get_current_menu() { + return menus_ctx->current_menu; +} + +bool menus_module_get_app_state() { + return app_state2.in_app; +} + +void menus_module_begin() { + menus_ctx = calloc(1, sizeof(menus_manager_t)); + menus_ctx->menus_count = sizeof(menus) / sizeof(menu_t); + screen_saver_begin(); + keyboard_module_set_input_callback(menus_input_cb); + oled_screen_begin(); + get_reset_menu(); + update_menus(); +} \ No newline at end of file diff --git a/firmware/main/modules/menus_module/menus_module.h b/firmware/main/modules/menus_module/menus_module.h new file mode 100644 index 00000000..6d68b3d2 --- /dev/null +++ b/firmware/main/modules/menus_module/menus_module.h @@ -0,0 +1,31 @@ +#pragma once + +#include "menus.h" + +#include "keyboard_module.h" + +#ifdef CONFIG_RESOLUTION_128X64 + #define SCREEN_WIDTH2 128 + #define SCREEN_HEIGHT2 64 +#else // CONFIG_RESOLUTION_128X32 + #define SCREEN_WIDTH2 128 + #define SCREEN_HEIGHT2 32 +#endif + +typedef struct { + bool in_app; + input_callback_t input_callback; + input_callback_t input_last_callback; +} app_state2_t; + +void menus_module_begin(); +void menus_module_enable_input(); +void menus_module_disable_input(); +void menus_module_set_app_state(bool in_app, input_callback_t input_cb); +menu_idx_t menus_module_get_current_menu(); +void menus_module_set_app_state_last(); +bool menus_module_get_app_state(); +void menus_module_restart(); +void menus_module_exit_app(); +void menus_module_screen_saver_run(); +void menus_module_set_reset_screen(menu_idx_t menu); diff --git a/firmware/main/modules/menus_module/menus_screens.c b/firmware/main/modules/menus_module/menus_screens.c new file mode 100644 index 00000000..f19c9fc8 --- /dev/null +++ b/firmware/main/modules/menus_module/menus_screens.c @@ -0,0 +1,60 @@ +#include "menus_screens.h" + +#include +#include "oled_screen.h" + +#define MAX_MENUS_ON_SCREEN 8 + +void menus_screens_display_menus(menus_manager_t* ctx) { + static uint8_t items_offset = 0; + items_offset = + MAX(ctx->selected_submenu - (MAX_MENUS_ON_SCREEN - 1), items_offset); + items_offset = + MIN(MAX(ctx->submenus_count - MAX_MENUS_ON_SCREEN, 0), items_offset); + items_offset = MIN(ctx->selected_submenu, items_offset); + oled_screen_clear(); + for (uint8_t i = 0; i < (MIN(ctx->submenus_count, MAX_MENUS_ON_SCREEN)); + i++) { + const char* display_name = + menus[*ctx->submenus_idx[i + items_offset]].display_name; + oled_screen_display_text(display_name, 0, i, + ctx->selected_submenu == i + items_offset); + } +} +void menus_screens_display_menus_f(menus_manager_t* ctx) { + oled_screen_clear_buffer(); + if (!ctx->submenus_count) { + return; + } +#ifdef CONFIG_RESOLUTION_128X64 + char* prefix = " "; + uint8_t page = 1; + uint8_t page_increment = 2; +#else // CONFIG_RESOLUTION_128X32 + char* prefix = "> "; + uint8_t page = 0; + uint8_t page_increment = 1; +#endif + + bool skip_first = !ctx->selected_submenu; + bool skip_last = ctx->selected_submenu == ctx->submenus_count - 1; + + uint8_t idx = 0; + for (uint8_t i = 0; i < 3; i++) { + if ((!i && skip_first) || (i == 2 && skip_last)) { + continue; + } + char* display_name = + menus[*ctx->submenus_idx[(idx++) + ctx->selected_submenu - !skip_first]] + .display_name; + char* str = (char*) malloc(strlen(display_name) + 3); + sprintf(str, "%s%s", i == 1 ? prefix : " ", display_name); + oled_screen_display_text(str, 0, i * page_increment + page, + OLED_DISPLAY_NORMAL); + } + +#ifdef CONFIG_RESOLUTION_128X64 + oled_screen_display_selected_item_box(); + oled_screen_display_show(); +#endif +} diff --git a/firmware/main/modules/menus_module/menus_screens.h b/firmware/main/modules/menus_module/menus_screens.h new file mode 100644 index 00000000..d1b511c9 --- /dev/null +++ b/firmware/main/modules/menus_module/menus_screens.h @@ -0,0 +1,6 @@ +#pragma once + +#include "menus_module.h" + +void menus_screens_display_menus(menus_manager_t* ctx); +void menus_screens_display_menus_f(menus_manager_t* ctx); \ No newline at end of file diff --git a/firmware/main/modules/modals/keyboard/keyboard_modal.c b/firmware/main/modules/modals/keyboard/keyboard_modal.c new file mode 100644 index 00000000..d0e25d1a --- /dev/null +++ b/firmware/main/modules/modals/keyboard/keyboard_modal.c @@ -0,0 +1,98 @@ +#include "keyboard_modal.h" + +#include + +#include "keyboard_module.h" +#include "keyboard_screens.h" +#include "menus_module.h" + +#define TAG "Keyboard Modal" + +static keyboard_modal_ctx_t* kb_ctx; + +static void keyboard_event_press_down(uint8_t button_name) { + switch (button_name) { + case BUTTON_LEFT: + kb_ctx->current_char = kb_ctx->current_char == 0 + ? kb_ctx->text_length - 1 + : kb_ctx->current_char - 1; + keyboard_screens_update_text(kb_ctx); + break; + case BUTTON_RIGHT: + kb_ctx->current_char = ++kb_ctx->current_char < kb_ctx->text_length + ? kb_ctx->current_char + : 0; + keyboard_screens_update_text(kb_ctx); + break; + case BUTTON_UP: + kb_ctx->new_text[kb_ctx->current_char] = + ++kb_ctx->new_text[kb_ctx->current_char] > 'z' || + kb_ctx->new_text[kb_ctx->current_char] < '0' + ? '0' + : kb_ctx->new_text[kb_ctx->current_char] < 'a' && + kb_ctx->new_text[kb_ctx->current_char] > '9' + ? 'a' + : kb_ctx->new_text[kb_ctx->current_char]; + keyboard_screens_update_text(kb_ctx); + break; + case BUTTON_DOWN: + kb_ctx->new_text[kb_ctx->current_char] = + --kb_ctx->new_text[kb_ctx->current_char] < '0' || + kb_ctx->new_text[kb_ctx->current_char] > 'z' + ? 'z' + : kb_ctx->new_text[kb_ctx->current_char] > '9' && + kb_ctx->new_text[kb_ctx->current_char] < 'a' + ? '9' + : kb_ctx->new_text[kb_ctx->current_char]; + keyboard_screens_update_text(kb_ctx); + break; + case BUTTON_BOOT: + break; + default: + break; + } +} + +static void keyboard_modal_input_cb(uint8_t button_name, uint8_t button_event) { + switch (button_event) { + case BUTTON_PRESS_DOWN: + keyboard_event_press_down(button_name); + break; + case BUTTON_LONG_PRESS_START: + if (button_name == BUTTON_RIGHT) { + kb_ctx->consumed = 1; + } else if (button_name == BUTTON_LEFT) { + kb_ctx->consumed = -1; + } + break; + default: + break; + } +} + +static void keyboard_modal_alloc(char* text, char* banner) { + kb_ctx = malloc(sizeof(keyboard_modal_ctx_t)); + memset(kb_ctx, 0, sizeof(keyboard_modal_ctx_t)); + kb_ctx->old_text = text; + kb_ctx->banner = banner; + kb_ctx->text_length = strlen(text); + kb_ctx->new_text = (char*) malloc(kb_ctx->text_length + 1); + strcpy(kb_ctx->new_text, text); +} + +char* keyboard_modal_write(char* text, char* banner) { + keyboard_modal_alloc(text, banner); + menus_module_set_app_state(true, keyboard_modal_input_cb); + keyboard_screens_show(kb_ctx); + keyboard_screens_update_text(kb_ctx); + while (!kb_ctx->consumed) + ; + if (kb_ctx->consumed > 0) { + char* new_text = (char*) malloc(kb_ctx->text_length + 1); + strcpy(new_text, kb_ctx->new_text); + free(kb_ctx); + return new_text; + } + free(kb_ctx); + return NULL; +} \ No newline at end of file diff --git a/firmware/main/modules/modals/keyboard/keyboard_modal.h b/firmware/main/modules/modals/keyboard/keyboard_modal.h new file mode 100644 index 00000000..3311d64f --- /dev/null +++ b/firmware/main/modules/modals/keyboard/keyboard_modal.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +typedef struct { + char* old_text; + char* new_text; + char* banner; + size_t text_length; + uint8_t current_char; + volatile int8_t consumed; + bool caps; + bool shift; +} keyboard_modal_ctx_t; + +char* keyboard_modal_write(char* text, char* banner); \ No newline at end of file diff --git a/firmware/main/modules/modals/keyboard/keyboard_screens.c b/firmware/main/modules/modals/keyboard/keyboard_screens.c new file mode 100644 index 00000000..1ab66957 --- /dev/null +++ b/firmware/main/modules/modals/keyboard/keyboard_screens.c @@ -0,0 +1,28 @@ +#include "keyboard_screens.h" + +#include "oled_screen.h" +#define TAG "Keyboard Screens" + +#define MAX_CHARS 16 + +void keyboard_screens_update_text(keyboard_modal_ctx_t* ctx) { + static uint8_t chars_offset = 0; + chars_offset = MAX(ctx->current_char - 14, chars_offset); + chars_offset = MIN(ctx->current_char, chars_offset); + oled_screen_clear_line(0, 2, OLED_DISPLAY_NORMAL); + for (uint8_t i = 0; i < (MIN(ctx->text_length, MAX_CHARS - 1)); i++) { + char a_char[2]; + snprintf(a_char, sizeof(a_char), "%c", ctx->new_text[i + chars_offset]); + oled_screen_display_text(&a_char, i * 8, 2, + ctx->current_char == i + chars_offset); + } +} + +void keyboard_screens_show(keyboard_modal_ctx_t* ctx) { + oled_screen_clear(); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text("----------------", 0, 1, OLED_DISPLAY_NORMAL); + oled_screen_display_text("----------------", 0, 3, OLED_DISPLAY_NORMAL); + oled_screen_display_text("Hold > to Save", 0, 5, OLED_DISPLAY_NORMAL); + oled_screen_display_text("Hold < to Cancel", 0, 6, OLED_DISPLAY_NORMAL); +} \ No newline at end of file diff --git a/firmware/main/modules/modals/keyboard/keyboard_screens.h b/firmware/main/modules/modals/keyboard/keyboard_screens.h new file mode 100644 index 00000000..5a2f42da --- /dev/null +++ b/firmware/main/modules/modals/keyboard/keyboard_screens.h @@ -0,0 +1,6 @@ +#pragma once + +#include "keyboard_modal.h" + +void keyboard_screens_update_text(keyboard_modal_ctx_t* ctx); +void keyboard_screens_show(keyboard_modal_ctx_t* ctx); diff --git a/firmware/main/modules/modals/modals_module.c b/firmware/main/modules/modals/modals_module.c new file mode 100644 index 00000000..c81f9688 --- /dev/null +++ b/firmware/main/modules/modals/modals_module.c @@ -0,0 +1,172 @@ +#include "modals_module.h" + +#include +#include "menus_module.h" +#include "modals_screens.h" + +static modal_get_user_selection_t* modal_get_user_selection_ctx; +static modal_get_radio_selection_t* modal_get_radio_selection_ctx; + +static char* yes_no_options[] = {"NO", "YES", NULL}; + +static void (*custom_list_options_cb)(modal_get_user_selection_t*) = NULL; +static void (*custom_list_radio_options_cb)(modal_get_radio_selection_t*) = + NULL; + +static void list_options() { + if (custom_list_options_cb) { + custom_list_options_cb(modal_get_user_selection_ctx); + return; + } + modals_screens_default_list_options_cb(modal_get_user_selection_ctx); +} + +static void list_radio_options() { + if (custom_list_radio_options_cb) { + custom_list_radio_options_cb(modal_get_radio_selection_ctx); + return; + } + modals_screens_default_list_radio_options_cb(modal_get_radio_selection_ctx); +} + +static void get_user_selection_input_cb(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + modal_get_user_selection_ctx->selected_option = -1; + modal_get_user_selection_ctx->consumed = true; + break; + case BUTTON_RIGHT: + modal_get_user_selection_ctx->consumed = true; + break; + case BUTTON_UP: + modal_get_user_selection_ctx->selected_option = + modal_get_user_selection_ctx->selected_option == 0 + ? modal_get_user_selection_ctx->options_count - 1 + : modal_get_user_selection_ctx->selected_option - 1; + list_options(); + break; + case BUTTON_DOWN: + modal_get_user_selection_ctx->selected_option = + ++modal_get_user_selection_ctx->selected_option < + modal_get_user_selection_ctx->options_count + ? modal_get_user_selection_ctx->selected_option + : 0; + list_options(); + break; + default: + break; + } +} + +static void get_radio_selection_input_cb(uint8_t button_name, + uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + modal_get_radio_selection_ctx->consumed = true; + break; + case BUTTON_RIGHT: + modal_get_radio_selection_ctx->current_option = + modal_get_radio_selection_ctx->selected_option; + list_radio_options(); + break; + case BUTTON_UP: + modal_get_radio_selection_ctx->selected_option = + modal_get_radio_selection_ctx->selected_option == 0 + ? modal_get_radio_selection_ctx->options_count - 1 + : modal_get_radio_selection_ctx->selected_option - 1; + list_radio_options(); + break; + case BUTTON_DOWN: + modal_get_radio_selection_ctx->selected_option = + ++modal_get_radio_selection_ctx->selected_option < + modal_get_radio_selection_ctx->options_count + ? modal_get_radio_selection_ctx->selected_option + : 0; + list_radio_options(); + break; + default: + break; + } +} + +int count_items(char** items) { + int count = 0; + while (items[count] != NULL) { + count++; + } + return count; +} + +int8_t modals_module_get_user_selection(char** options, char* banner) { + modal_get_user_selection_ctx = malloc(sizeof(modal_get_user_selection_t)); + memset(modal_get_user_selection_ctx, 0, sizeof(modal_get_user_selection_t)); + modal_get_user_selection_ctx->options = options; + modal_get_user_selection_ctx->options_count = count_items(options); + modal_get_user_selection_ctx->banner = banner; + menus_module_set_app_state(true, get_user_selection_input_cb); + list_options(); + while (!modal_get_user_selection_ctx->consumed) + ; + int8_t selection = modal_get_user_selection_ctx->selected_option; + free(modal_get_user_selection_ctx); + return selection; +} +int8_t modals_module_get_user_y_n_selection(char* banner) { + modal_get_user_selection_ctx = malloc(sizeof(modal_get_user_selection_t)); + memset(modal_get_user_selection_ctx, 0, sizeof(modal_get_user_selection_t)); + modal_get_user_selection_ctx->options = yes_no_options; + modal_get_user_selection_ctx->options_count = 2; + modal_get_user_selection_ctx->banner = banner; + custom_list_options_cb = modals_screens_list_y_n_options_cb; + menus_module_set_app_state(true, get_user_selection_input_cb); + list_options(); + while (!modal_get_user_selection_ctx->consumed) + ; + custom_list_options_cb = NULL; + int8_t selection = modal_get_user_selection_ctx->selected_option; + free(modal_get_user_selection_ctx); + return selection; +} + +uint8_t modals_module_get_radio_selection(char** options, + char* banner, + uint8_t current_option) { + modal_get_radio_selection_ctx = malloc(sizeof(modal_get_radio_selection_t)); + memset(modal_get_radio_selection_ctx, 0, sizeof(modal_get_radio_selection_t)); + modal_get_radio_selection_ctx->options = options; + modal_get_radio_selection_ctx->options_count = count_items(options); + modal_get_radio_selection_ctx->banner = banner; + modal_get_radio_selection_ctx->current_option = current_option; + modal_get_radio_selection_ctx->selected_option = current_option; + menus_module_set_app_state(true, get_radio_selection_input_cb); + list_radio_options(); + while (!modal_get_radio_selection_ctx->consumed) + ; + uint8_t selection = modal_get_radio_selection_ctx->current_option; + free(modal_get_radio_selection_ctx); + return selection; +} + +void modals_module_show_info(char* head, + char* body, + size_t time_ms, + bool lock_input) { + if (lock_input) { + menus_module_disable_input(); + } + modals_screens_show_info(head, body, time_ms); + if (lock_input) { + menus_module_enable_input(); + } +} + +void modals_module_show_banner(char* text) { + modals_screens_show_banner(text); +} \ No newline at end of file diff --git a/firmware/main/modules/modals/modals_module.h b/firmware/main/modules/modals/modals_module.h new file mode 100644 index 00000000..3b4205a7 --- /dev/null +++ b/firmware/main/modules/modals/modals_module.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +typedef enum { CANCELED_OPTION = -1, NO_OPTION, YES_OPTION } yes_no_options_t; + +typedef struct { + int8_t selected_option; + uint8_t options_count; + char** options; + char* banner; + volatile bool consumed; +} modal_get_user_selection_t; + +typedef struct { + uint8_t selected_option; + uint8_t options_count; + char** options; + char* banner; + uint8_t current_option; + volatile bool consumed; +} modal_get_radio_selection_t; + +int8_t modals_module_get_user_selection(char** options, char* banner); +void set_get_user_selection_handler(void* cb); +int8_t modals_module_get_user_y_n_selection(char* banner); +uint8_t modals_module_get_radio_selection(char** options, + char* banner, + uint8_t current_option); +void modals_module_show_info(char* head, + char* body, + size_t time_ms, + bool lock_input); +void modals_module_show_banner(char* text); \ No newline at end of file diff --git a/firmware/main/modules/modals/modals_screens.c b/firmware/main/modules/modals/modals_screens.c new file mode 100644 index 00000000..c7dd8833 --- /dev/null +++ b/firmware/main/modules/modals/modals_screens.c @@ -0,0 +1,70 @@ +#include "modals_screens.h" +#include "bitmaps_general.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "oled_screen.h" + +#define MAX_OPTIONS_NUM 7 + +void modals_screens_list_y_n_options_cb(modal_get_user_selection_t* ctx) { + oled_screen_clear_buffer(); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center(ctx->options[0], 3, + ctx->selected_option == 0); + oled_screen_display_text_center(ctx->options[1], 4, + ctx->selected_option == 1); + oled_screen_display_show(); +} + +void modals_screens_default_list_options_cb(modal_get_user_selection_t* ctx) { + static uint8_t items_offset = 0; + items_offset = MAX(ctx->selected_option - 6, items_offset); + items_offset = MIN(ctx->selected_option, items_offset); + oled_screen_clear_buffer(); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + for (uint8_t i = 0; i < (MIN(ctx->options_count, MAX_OPTIONS_NUM - 1)); i++) { + oled_screen_display_text_center(ctx->options[i + items_offset], i + 2, + ctx->selected_option == i + items_offset); + } + oled_screen_display_show(); +} + +void modals_screens_default_list_radio_options_cb( + modal_get_radio_selection_t* ctx) { + static uint8_t items_offset = 0; + items_offset = MAX(ctx->selected_option - 6, items_offset); + items_offset = MIN(ctx->selected_option, items_offset); + oled_screen_clear(); + oled_screen_display_text(ctx->banner, 0, 0, OLED_DISPLAY_NORMAL); + for (uint8_t i = 0; i < (MIN(ctx->options_count, MAX_OPTIONS_NUM - 1)); i++) { + char* str = malloc(20); + bool is_selected = i + items_offset == ctx->selected_option; + bool is_current = i + items_offset == ctx->current_option; + oled_screen_display_bitmap(minino_face, 0, (ctx->selected_option + 2) * 8, + 8, 8, OLED_DISPLAY_NORMAL); + sprintf(str, "%s%s", ctx->options[i + items_offset], + is_current ? "[curr]" : ""); + oled_screen_display_text(str, is_selected ? 16 : 0, i + 2, is_selected); + free(str); + } +} + +void modals_screens_show_info(char* head, char* body, size_t time_ms) { + oled_screen_clear_buffer(); + int page = 2; + oled_screen_display_text_center(head, 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text_splited(body, &page, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); + vTaskDelay(pdMS_TO_TICKS(time_ms)); + oled_screen_clear(); +} + +void modals_screens_show_banner(char* text) { +#ifdef CONFIG_RESOLUTION_128X64 + uint8_t page = 3; +#else // CONFIG_RESOLUTION_128X32 + uint8_t page = 2; +#endif + oled_screen_clear(); + oled_screen_display_text_center(text, page, OLED_DISPLAY_NORMAL); +} \ No newline at end of file diff --git a/firmware/main/modules/modals/modals_screens.h b/firmware/main/modules/modals/modals_screens.h new file mode 100644 index 00000000..37aae1d3 --- /dev/null +++ b/firmware/main/modules/modals/modals_screens.h @@ -0,0 +1,11 @@ +#pragma once +#include + +#include "modals_module.h" + +void modals_screens_default_list_options_cb(modal_get_user_selection_t* ctx); +void modals_screens_show_info(char* head, char* body, size_t time_ms); +void modals_screens_list_y_n_options_cb(modal_get_user_selection_t* ctx); +void modals_screens_default_list_radio_options_cb( + modal_get_radio_selection_t* ctx); +void modals_screens_show_banner(char* text); \ No newline at end of file diff --git a/firmware/main/modules/oled_screen/oled_screen.c b/firmware/main/modules/oled_screen/oled_screen.c index a29958b6..01d094c2 100644 --- a/firmware/main/modules/oled_screen/oled_screen.c +++ b/firmware/main/modules/oled_screen/oled_screen.c @@ -4,7 +4,6 @@ #include "freertos/semphr.h" #include "freertos/task.h" -#include "bitmaps.h" #include "esp_log.h" #include "oled_screen.h" @@ -62,6 +61,11 @@ void oled_screen_display_show() { oled_driver_show_buffer(&dev); xSemaphoreGive(oled_mutex); } +void oled_screen_clear_buffer() { + xSemaphoreTake(oled_mutex, portMAX_DELAY); + oled_driver_clear_buffer(&dev); + xSemaphoreGive(oled_mutex); +} void oled_screen_display_text(char* text, int x, int page, bool invert) { if (text == NULL) { @@ -69,11 +73,6 @@ void oled_screen_display_text(char* text, int x, int page, bool invert) { return; } - if (strlen(text) > MAX_LINE_CHAR) { - ESP_LOGE(TAG, "%s is too long for the screen", text); - return; - } - uint8_t _x = x + (strlen(text) * 8) > 128 ? 0 : x; if (_x != x) { ESP_LOGW(TAG, "Text %s is too long for the screen, x offset: %d", text, _x); @@ -104,10 +103,8 @@ void oled_screen_display_text_center(char* text, int page, bool invert) { } void oled_screen_clear_line(int x, int page, bool invert) { - // oled_driver_clear_line(&dev, x, page, invert); xSemaphoreTake(oled_mutex, portMAX_DELAY); - oled_driver_bitmaps(&dev, x, page * 8, epd_bitmap_clear_line, 128 - x, 8, - invert); + oled_driver_clear_line(&dev, x, page, invert); xSemaphoreGive(oled_mutex); } @@ -141,6 +138,13 @@ void oled_screen_display_selected_item_box() { xSemaphoreGive(oled_mutex); } +void oled_screen_display_card_border() { + xSemaphoreTake(oled_mutex, portMAX_DELAY); + oled_driver_draw_modal_box(&dev, 0, 3); + oled_driver_show_buffer(&dev); + xSemaphoreGive(oled_mutex); +} + void oled_screen_display_text_splited(char* p_text, int* p_started_page, int invert) { @@ -157,18 +161,18 @@ void oled_screen_display_text_splited(char* p_text, } strcat(current_line, token); } else { - oled_screen_display_text(current_line, 0, *p_started_page, invert); + oled_screen_display_text(current_line, 3, *p_started_page, invert); (*p_started_page)++; strcpy(current_line, token); } token = strtok(NULL, " "); } if (strlen(current_line) > 0) { - oled_screen_display_text(current_line, 0, *p_started_page, invert); + oled_screen_display_text(current_line, 3, *p_started_page, invert); (*p_started_page)++; } } else { - oled_screen_display_text(p_text, 0, *p_started_page, invert); + oled_screen_display_text(p_text, 3, *p_started_page, invert); (*p_started_page)++; } } diff --git a/firmware/main/modules/oled_screen/oled_screen.h b/firmware/main/modules/oled_screen/oled_screen.h index eeafbc5d..48bc947f 100644 --- a/firmware/main/modules/oled_screen/oled_screen.h +++ b/firmware/main/modules/oled_screen/oled_screen.h @@ -121,7 +121,8 @@ void oled_screen_display_selected_item_box(); /** * @brief Display and split the text on the OLED display * - * @param p_text Pointer of the text to display on the OLED display + * @param p_text Pointer of the text to display on the OLED display limited to + * 50 char * @param p_started_page Pointer to the index of the page to display the text on * the OLED display * @param invert Invert the background and foreground color of the OLED display @@ -130,4 +131,7 @@ void oled_screen_display_text_splited(char* p_text, int* p_started_page, int invert); -void oled_screen_display_loading_bar(uint8_t value, uint8_t page); \ No newline at end of file +void oled_screen_display_loading_bar(uint8_t value, uint8_t page); +void oled_screen_display_card_border(); +void oled_screen_clear_buffer(); +void oled_screen_display_show(); \ No newline at end of file diff --git a/firmware/main/modules/open_thread/open_thread_module.c b/firmware/main/modules/open_thread/open_thread_module.c index a0437503..db969cec 100644 --- a/firmware/main/modules/open_thread/open_thread_module.c +++ b/firmware/main/modules/open_thread/open_thread_module.c @@ -1,7 +1,7 @@ #include "open_thread_module.h" #include "esp_log.h" #include "led_events.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "open_thread.h" #include "open_thread_screens_module.h" @@ -14,75 +14,50 @@ uint8_t channel = 15; static void thread_broadcast_input(uint8_t button_name, uint8_t button_event); static void thread_sniffer_input(uint8_t button_name, uint8_t button_event); -static void open_thread_module_exit_submenu_cb(); -static void open_thread_module_enter_submenu_cb( - screen_module_menu_t user_selection); void open_thread_module_begin() { #if !defined(CONFIG_OPEN_THREAD_MODULE_DEBUG) esp_log_level_set(TAG_OT_MODULE, ESP_LOG_NONE); #endif radio_selector_set_thread(); - menu_screens_register_enter_submenu_cb(open_thread_module_enter_submenu_cb); - menu_screens_register_exit_submenu_cb(open_thread_module_exit_submenu_cb); } void open_thread_module_exit() { - screen_module_set_screen(MENU_THREAD_SNIFFER); + menus_module_set_reset_screen(MENU_THREAD_APPS_2); esp_restart(); } -static void open_thread_module_enter_submenu_cb( - screen_module_menu_t user_selection) { - oled_screen_clear(); - switch (user_selection) { - case MENU_THREAD_BROADCAST: - menu_screens_set_app_state(true, thread_broadcast_input); - led_control_run_effect(led_control_zigbee_scanning); - open_thread_screens_display_broadcast_mode(channel); - thread_broadcast_set_on_msg_recieve_cb( - open_thread_screens_show_new_message); - thread_broadcast_init(); - break; - case MENU_THREAD_SNIFFER: - thread_sniffer_set_show_event_cb(thread_sniffer_show_event_handler); - thread_sniffer_init(); - break; - case MENU_THREAD_SNIFFER_RUN: - menu_screens_set_app_state(true, thread_sniffer_input); - led_control_run_effect(led_control_zigbee_scanning); - thread_sniffer_run(); - break; - default: - break; - } +void open_thread_module_broadcast_enter() { + radio_selector_set_thread(); + menus_module_set_app_state(true, thread_broadcast_input); + led_control_run_effect(led_control_zigbee_scanning); + open_thread_screens_display_broadcast_mode(channel); + thread_broadcast_set_on_msg_recieve_cb(open_thread_screens_show_new_message); + thread_broadcast_init(); } -static void open_thread_module_exit_submenu_cb() { - screen_module_menu_t current_menu = menu_screens_get_current_menu(); - switch (current_menu) { - case MENU_THREAD_APPS: - menu_screens_unregister_submenu_cbs(); - break; - case MENU_THREAD_SNIFFER: - open_thread_module_exit(); - break; - default: - break; - } +void open_thread_module_sniffer_enter() { + radio_selector_set_thread(); + thread_sniffer_set_show_event_cb(thread_sniffer_show_event_handler); + thread_sniffer_init(); +} +void open_thread_module_sniffer_run() { + menus_module_set_app_state(true, thread_sniffer_input); + led_control_run_effect(led_control_zigbee_scanning); + thread_sniffer_run(); } static void thread_broadcast_input(uint8_t button_name, uint8_t button_event) { - if (button_event != BUTTON_SINGLE_CLICK) { + if (button_event != BUTTON_PRESS_DOWN) { return; } switch (button_name) { case BUTTON_LEFT: led_control_stop(); - screen_module_set_screen(MENU_THREAD_BROADCAST); - esp_restart(); + open_thread_module_exit(); break; case BUTTON_RIGHT: + break; case BUTTON_UP: printf("channel++\n"); channel = ++channel > 26 ? 11 : channel; @@ -101,15 +76,14 @@ static void thread_broadcast_input(uint8_t button_name, uint8_t button_event) { } static void thread_sniffer_input(uint8_t button_name, uint8_t button_event) { - if (button_event != BUTTON_SINGLE_CLICK) { + if (button_event != BUTTON_PRESS_DOWN) { return; } switch (button_name) { case BUTTON_LEFT: thread_sniffer_stop(); led_control_stop(); - menu_screens_exit_submenu(); - menu_screens_set_app_state(false, NULL); + menus_module_exit_app(); break; case BUTTON_RIGHT: break; diff --git a/firmware/main/modules/open_thread/open_thread_module.h b/firmware/main/modules/open_thread/open_thread_module.h index 5c471d22..d2612cc3 100644 --- a/firmware/main/modules/open_thread/open_thread_module.h +++ b/firmware/main/modules/open_thread/open_thread_module.h @@ -1,10 +1,12 @@ #pragma once #define TAG_OT_MODULE "open_thread:main" -/** - * @brief Begin the bluetooth module - * - * @param app_selected The selected app - */ + void open_thread_module_begin(); void open_thread_module_exit(); + +void open_thread_module_broadcast_enter(); + +void open_thread_module_sniffer_enter(); + +void open_thread_module_sniffer_run(); \ No newline at end of file diff --git a/firmware/main/modules/open_thread/open_thread_screens_module.c b/firmware/main/modules/open_thread/open_thread_screens_module.c index 6556c3bc..dd752011 100644 --- a/firmware/main/modules/open_thread/open_thread_screens_module.c +++ b/firmware/main/modules/open_thread/open_thread_screens_module.c @@ -2,6 +2,7 @@ #include "oled_screen.h" void open_thread_screens_display_broadcast_mode(uint8_t ch) { + oled_screen_clear(); oled_screen_display_text(" BroadCast Mode ", 0, 0, OLED_DISPLAY_NORMAL); char* str = (char*) malloc(18); sprintf(str, " Channel %d ", ch); @@ -13,9 +14,9 @@ void open_thread_screens_show_new_message(char* msg) { oled_screen_clear_line(0, 2, OLED_DISPLAY_NORMAL); oled_screen_display_text(" New Message ", 0, 2, OLED_DISPLAY_INVERT); char* str = (char*) malloc(18); - sprintf(str, " Counter: %s ", msg); + sprintf(str, "%s", msg); oled_screen_clear_line(0, 4, OLED_DISPLAY_NORMAL); - oled_screen_display_text(str, 0, 4, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center(str, 4, OLED_DISPLAY_NORMAL); free(str); } diff --git a/firmware/main/modules/ota/ota_module.c b/firmware/main/modules/ota/ota_module.c index 1aed7409..485538e4 100644 --- a/firmware/main/modules/ota/ota_module.c +++ b/firmware/main/modules/ota/ota_module.c @@ -1,30 +1,25 @@ #include "ota_module.h" #include "OTA.h" #include "keyboard_module.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "ota_module_screens.h" -static void ota_module_input(uint8_t button_name, uint8_t button_event); +void ota_module_input(uint8_t button_name, uint8_t button_event); void ota_module_init() { OTA_set_show_event_cb(ota_module_screens_show_event); ota_module_screens_show_help(); OTA_init(); - menu_screens_set_app_state(true, ota_module_input); + menus_module_set_app_state(true, ota_module_input); } -void ota_module_deinit() { - screen_module_set_screen(MENU_ABOUT_UPDATE); - esp_restart(); -} - -static void ota_module_input(uint8_t button_name, uint8_t button_event) { +void ota_module_input(uint8_t button_name, uint8_t button_event) { if (button_event != BUTTON_SINGLE_CLICK || is_ota_running) { return; } switch (button_name) { case BUTTON_LEFT: - ota_module_deinit(); + menus_module_restart(); break; case BUTTON_RIGHT: case BUTTON_UP: diff --git a/firmware/main/modules/ota/ota_module.h b/firmware/main/modules/ota/ota_module.h index cc838da3..909bd11a 100644 --- a/firmware/main/modules/ota/ota_module.h +++ b/firmware/main/modules/ota/ota_module.h @@ -1,2 +1,6 @@ #pragma once -void ota_module_init(); \ No newline at end of file + +#include + +void ota_module_init(); +void ota_module_input(uint8_t button_name, uint8_t button_event); \ No newline at end of file diff --git a/firmware/main/modules/screen_saver/screen_saver.c b/firmware/main/modules/screen_saver/screen_saver.c new file mode 100644 index 00000000..e66311e5 --- /dev/null +++ b/firmware/main/modules/screen_saver/screen_saver.c @@ -0,0 +1,91 @@ +#include "screen_saver.h" + +#include "bitmaps_general.h" +#include "esp_timer.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "menus_module.h" +#include "oled_screen.h" +#include "preferences.h" + +static int IDLE_TIMEOUT_S = 30; + +static volatile bool screen_saver_running; +esp_timer_handle_t screen_savar_idle_timer2; + +void screen_saver_run(); + +static void timer_callback() { + if (menus_module_get_app_state() || screen_saver_running) { + return; + } + + menu_idx_t menu = menus_module_get_current_menu(); + if (menu == MENU_WIFI_ANALYZER_RUN_2 || + menu == MENU_WIFI_ANALYZER_SUMMARY_2 || menu == MENU_GPS_DATE_TIME_2 || + menu == MENU_GPS_LOCATION_2 || menu == MENU_GPS_SPEED_2) { + return; + } + + screen_saver_run(); +} + +static void show_splash_screen() { + int get_logo = preferences_get_int("dp_select", 0); + epd_bitmap_t logo; + logo = screen_savers[get_logo]; + + screen_saver_running = true; + int w_screen_space = SCREEN_WIDTH2 - logo.width; + int h_screen_space = SCREEN_HEIGHT2 - logo.height; + int start_x_position = w_screen_space / 2; + static int start_y_position = 16; + static int x_direction = 1; + static int y_direction = 1; + + while (screen_saver_running) { + // oled_screen_clear_buffer(); + oled_screen_display_bitmap(logo.bitmap, start_x_position, start_y_position, + logo.width, logo.height, OLED_DISPLAY_NORMAL); + + start_x_position += x_direction; + start_y_position += y_direction; + + if (start_x_position <= 0 || start_x_position >= w_screen_space - 2) { + x_direction = -x_direction; + } + if (start_y_position <= 0 || start_y_position >= h_screen_space) { + y_direction = -y_direction; + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } + + vTaskDelete(NULL); +} + +void screen_saver_run() { + oled_screen_clear(); + xTaskCreate(show_splash_screen, "show_splash_screen", 4096, NULL, 5, NULL); +} + +void screen_saver_stop() { + screen_saver_running = false; +} + +void screen_saver_set_idle_timeout(uint8_t timeout_seconds) { + IDLE_TIMEOUT_S = timeout_seconds; +} + +bool screen_saver_get_idle_state() { + bool idle = screen_saver_running; + screen_saver_stop(); + esp_timer_stop(screen_savar_idle_timer2); + esp_timer_start_once(screen_savar_idle_timer2, IDLE_TIMEOUT_S * 1000 * 1000); + return idle; +} + +void screen_saver_begin() { + esp_timer_create_args_t timer_args = { + .callback = timer_callback, .arg = NULL, .name = "idle_timer"}; + esp_err_t err = esp_timer_create(&timer_args, &screen_savar_idle_timer2); +} \ No newline at end of file diff --git a/firmware/main/modules/screen_saver/screen_saver.h b/firmware/main/modules/screen_saver/screen_saver.h new file mode 100644 index 00000000..46f5a6bc --- /dev/null +++ b/firmware/main/modules/screen_saver/screen_saver.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +void screen_saver_run(); +void screen_saver_stop(); +void screen_saver_begin(); +bool screen_saver_get_idle_state(); +void screen_saver_set_idle_timeout(uint8_t timeout_seconds); \ No newline at end of file diff --git a/firmware/main/modules/settings/display/display_settings.c b/firmware/main/modules/settings/display/display_settings.c index 4ad6b05a..83f755d0 100644 --- a/firmware/main/modules/settings/display/display_settings.c +++ b/firmware/main/modules/settings/display/display_settings.c @@ -3,7 +3,7 @@ #include "bitmaps_general.h" #include "esp_log.h" #include "led_events.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" @@ -45,7 +45,7 @@ static void config_module_wifi_display_selected_item_center( } static void display_config_display_menu_item() { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Exit", 0, 0, OLED_DISPLAY_NORMAL); for (int i = 0; display_settings_menu_items[i] != NULL; i++) { int page = (i + 1); @@ -57,10 +57,11 @@ static void display_config_display_menu_item() { OLED_DISPLAY_NORMAL); } } + oled_screen_display_show(); } static void display_config_display_list_logo() { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); int current_scren = preferences_get_int("dp_select", 0); for (int i = 0; epd_bitmaps_list[i] != NULL; i++) { @@ -77,26 +78,28 @@ static void display_config_display_list_logo() { oled_screen_display_text(display_text, 0, page, OLED_DISPLAY_NORMAL); } } + oled_screen_display_show(); } static void display_config_display_time_selection() { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text("< Back", 0, 0, OLED_DISPLAY_NORMAL); oled_screen_display_text_center("Time in seconds", 1, OLED_DISPLAY_NORMAL); oled_screen_display_text_center("Min:30 - Max:360", 2, OLED_DISPLAY_NORMAL); char time_text[18]; sprintf(time_text, "Time: %d", time_default_time); oled_screen_display_text_center(time_text, 4, OLED_DISPLAY_NORMAL); + oled_screen_display_show(); } void display_config_module_begin() { ESP_LOGI(TAG_DISPLAY_CONFIG, "Initializing ble module screen state machine"); - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); display_config_display_menu_item(); }; static void display_settings_show_modal() { - oled_screen_clear(); + oled_screen_clear_buffer(); oled_screen_display_text_center("Apply this config?", 1, OLED_DISPLAY_NORMAL); if (selected_item == 0) { config_module_wifi_display_selected_item_center("YES", 3); @@ -105,6 +108,7 @@ static void display_settings_show_modal() { oled_screen_display_text_center("YES", 3, OLED_DISPLAY_NORMAL); config_module_wifi_display_selected_item_center("NO", 4); } + oled_screen_display_show(); } static void display_config_module_state_machine(uint8_t button_name, @@ -114,30 +118,31 @@ static void display_config_module_state_machine(uint8_t button_name, } switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_restart(); break; case BUTTON_RIGHT: ESP_LOGI(TAG_DISPLAY_CONFIG, "Selected item: %d", selected_item); if (selected_item == 0) { selected_item = 0; - menu_screens_set_app_state( + menus_module_set_app_state( true, display_config_module_state_machine_menu_logo); display_config_display_list_logo(); } else { selected_item = 0; - menu_screens_set_app_state( + menus_module_set_app_state( true, display_config_module_state_machine_menu_time); display_config_display_time_selection(); } break; case BUTTON_UP: - selected_item = (selected_item == 0) ? DISPLAY_COUNT : selected_item - 1; + selected_item = + (selected_item == 0) ? DISPLAY_COUNT - 1 : selected_item - 1; display_config_display_menu_item(); break; case BUTTON_DOWN: - selected_item = (selected_item == DISPLAY_COUNT) ? 0 : selected_item + 1; + selected_item = + (selected_item == DISPLAY_COUNT - 1) ? 0 : selected_item + 1; display_config_display_menu_item(); break; case BUTTON_BOOT: @@ -154,7 +159,7 @@ static void display_config_module_state_machine_menu_time( } switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); display_config_display_menu_item(); break; case BUTTON_RIGHT: @@ -164,7 +169,7 @@ static void display_config_module_state_machine_menu_time( oled_screen_display_text_center("Saved", 3, OLED_DISPLAY_NORMAL); keyboard_module_reset_idle_timer(); vTaskDelay(2000 / portTICK_PERIOD_MS); - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); selected_item = 0; display_config_display_menu_item(); break; @@ -194,23 +199,25 @@ static void display_config_module_state_machine_menu_logo( } switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); display_config_display_menu_item(); break; case BUTTON_RIGHT: ESP_LOGI(TAG_DISPLAY_CONFIG, "Selected item: %d", selected_item); screen_selected = selected_item; selected_item = 0; - menu_screens_set_app_state(true, + menus_module_set_app_state(true, display_config_module_state_machine_modal); display_settings_show_modal(); break; case BUTTON_UP: - selected_item = (selected_item == 0) ? MININO_COUNT : selected_item - 1; + selected_item = + (selected_item == 0) ? MININO_COUNT - 1 : selected_item - 1; display_config_display_list_logo(); break; case BUTTON_DOWN: - selected_item = (selected_item == MININO_COUNT) ? 0 : selected_item + 1; + selected_item = + (selected_item == MININO_COUNT - 1) ? 0 : selected_item + 1; display_config_display_list_logo(); break; case BUTTON_BOOT: @@ -226,7 +233,7 @@ static void display_config_module_state_machine_modal(uint8_t button_name, } switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); display_config_display_menu_item(); break; case BUTTON_RIGHT: @@ -237,16 +244,16 @@ static void display_config_module_state_machine_modal(uint8_t button_name, oled_screen_display_text_center("Saved", 3, OLED_DISPLAY_NORMAL); vTaskDelay(2000 / portTICK_PERIOD_MS); } - menu_screens_set_app_state(true, display_config_module_state_machine); + menus_module_set_app_state(true, display_config_module_state_machine); selected_item = 0; display_config_display_menu_item(); break; case BUTTON_UP: - selected_item = (selected_item == 0) ? 2 : selected_item - 1; + selected_item = (selected_item == 0) ? 1 : selected_item - 1; display_settings_show_modal(); break; case BUTTON_DOWN: - selected_item = (selected_item == 2) ? 0 : selected_item + 1; + selected_item = (selected_item == 1) ? 0 : selected_item + 1; display_settings_show_modal(); break; case BUTTON_BOOT: diff --git a/firmware/main/modules/settings/flash_fs/flash_fs_screens.c b/firmware/main/modules/settings/flash_fs/flash_fs_screens.c new file mode 100644 index 00000000..4ceaa28c --- /dev/null +++ b/firmware/main/modules/settings/flash_fs/flash_fs_screens.c @@ -0,0 +1,28 @@ +#include "flash_fs_screens.h" + +#include "keyboard_module.h" +#include "modals_module.h" + +static void show_mounting_banner() { + modals_module_show_info( + "Mounting Flash", "Mounting Flash File System, please wait", 2000, false); +} + +static void show_result_banner(esp_err_t err) { + if (err != ESP_OK) { + modals_module_show_info("ERROR", esp_err_to_name(err), 2000, false); + } +} + +void flash_fs_screens_handler(flash_fs_events_t event, void* ctx) { + switch (event) { + case FLASH_FS_MOUNTING_EV: + show_mounting_banner(); + break; + case FLASH_FS_RESULT_EV: + show_result_banner(ctx); + break; + default: + break; + } +} \ No newline at end of file diff --git a/firmware/main/modules/settings/flash_fs/flash_fs_screens.h b/firmware/main/modules/settings/flash_fs/flash_fs_screens.h new file mode 100644 index 00000000..7f1b564a --- /dev/null +++ b/firmware/main/modules/settings/flash_fs/flash_fs_screens.h @@ -0,0 +1,5 @@ +#pragma once + +#include "flash_fs.h" + +void flash_fs_screens_handler(flash_fs_events_t event, void* ctx); \ No newline at end of file diff --git a/firmware/main/modules/settings/sd_card/sd_card_settings_module.c b/firmware/main/modules/settings/sd_card/sd_card_settings_module.c index 7081adef..56f82166 100644 --- a/firmware/main/modules/settings/sd_card/sd_card_settings_module.c +++ b/firmware/main/modules/settings/sd_card/sd_card_settings_module.c @@ -1,7 +1,7 @@ #include "esp_log.h" #include "keyboard_module.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "sd_card.h" #include "sd_card_settings_module.h" #include "sd_card_settings_screens_module.h" @@ -27,6 +27,7 @@ const char* sd_card_state_to_name[] = { sd_card_settings_state_t state = SD_CARD_SETTINGS_VERIFYING; void sd_card_settings_verify_sd_card() { + menus_module_set_app_state(true, sd_card_settings_keyboard_cb); ESP_LOGI(TAG, "Verifying SD card..."); state = SD_CARD_SETTINGS_VERIFYING; @@ -51,8 +52,7 @@ void sd_card_settings_keyboard_cb(uint8_t button_name, uint8_t button_event) { switch (button_name) { case BUTTON_LEFT: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_exit_app(); break; case BUTTON_RIGHT: ESP_LOGI(TAG, "State: %s", sd_card_state_to_name[state]); @@ -70,12 +70,10 @@ void sd_card_settings_keyboard_cb(uint8_t button_name, uint8_t button_event) { } break; case SD_CARD_SETTINGS_OK: - menu_screens_set_app_state(false, NULL); - menu_screens_enter_submenu(); + menus_module_exit_app(); break; default: - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_exit_app(); break; } break; diff --git a/firmware/main/modules/settings/settings_module.c b/firmware/main/modules/settings/settings_module.c index cbd67bd0..d230fe89 100644 --- a/firmware/main/modules/settings/settings_module.c +++ b/firmware/main/modules/settings/settings_module.c @@ -1,27 +1,42 @@ #include "settings_module.h" #include +#include "coroutine.h" #include "display_settings.h" #include "esp_log.h" +#include "file_manager_module.h" +#include "general_radio_selection.h" #include "gps_module.h" -#include "menu_screens_modules.h" +#include "menus_module.h" +#include "modals_module.h" #include "modules/settings/wifi/wifi_settings.h" #include "oled_screen.h" +#include "preferences.h" #include "sd_card.h" #include "sd_card_settings_module.h" #include "settings_module.h" +#include "stealth_mode.h" #include "web_file_browser_module.h" static const char* TAG = "settings_module"; -void update_time_zone_options() { - uint8_t selected_option = gps_module_get_time_zone(); - menu_screens_update_options(gps_time_zone_options, selected_option); -} +char* gps_time_zone_options_2[] = { + "UTC-12", "UTC-11", "UTC-10", "UTC-9:30", "UTC-9", "UTC-8", + "UTC-7", "UTC-6", "UTC-5", "UTC-4", "UTC-3:30", "UTC-3", + "UTC-2", "UTC-1", "UTC+0", "UTC+1", "UTC+2", "UTC+3", + "UTC+3:30", "UTC+4", "UTC+4:30", "UTC+5", "UTC+5:30", "UTC+5:45", + "UTC+6", "UTC+6:30", "UTC+7", "UTC+8", "UTC+8:45", "UTC+9", + "UTC+9:30", "UTC+10", "UTC+10:30", "UTC+11", "UTC+12", "UTC+12:45", + "UTC+13", "UTC+14"}; + +char* sd_card_info_2[6]; +general_menu_t SD_inf = {.menu_count = 6, + .menu_items = sd_card_info_2, + .menu_level = GENERAL_MENU_MAIN}; void update_sd_card_info() { sd_card_mount(); oled_screen_clear(); - menu_screens_display_text_banner("Loading..."); + modals_module_show_banner("Loading..."); vTaskDelay(1000 / portTICK_PERIOD_MS); // Wait for the SD card to be mounted sd_card_info_t sd_info = sd_card_get_info(); @@ -34,62 +49,25 @@ void update_sd_card_info() { char* type_str = malloc(strlen(sd_info.type) + 1 + 6); sprintf(type_str, "Type: %s", sd_info.type); - sd_card_info[3] = name_str; - sd_card_info[4] = capacity_str; - sd_card_info[5] = speed_str; - sd_card_info[6] = type_str; + sd_card_info_2[0] = ""; + sd_card_info_2[1] = "SD Card Info"; + sd_card_info_2[2] = name_str; + sd_card_info_2[3] = capacity_str; + sd_card_info_2[4] = speed_str; + sd_card_info_2[5] = type_str; sd_card_unmount(); + general_register_scrolling_menu(&SD_inf); + general_screen_display_scrolling_text_handler(menus_module_exit_app); } -void settings_module_exit_submenu_cb() { - screen_module_menu_t current_menu = menu_screens_get_current_menu(); - switch (current_menu) { - case MENU_WEB_SD_BROWSER: - case MENU_SETTINGS: - settings_module_exit(); - break; - default: - break; - } -} - -void settings_module_enter_submenu_cb(screen_module_menu_t user_selection) { - uint8_t selected_item = menu_screens_get_selected_item(); - ESP_LOGI(TAG, "Selected item: %d", selected_item); - switch (user_selection) { - case MENU_WEB_SD_BROWSER: - web_file_browser_module_init(); - break; - case MENU_SETTINGS_DISPLAY: - display_config_module_begin(); - break; - case MENU_SETTINGS_TIME_ZONE: - if (menu_screens_is_configuration(user_selection)) { - gps_module_set_time_zone(selected_item); - } - update_time_zone_options(); - break; - case MENU_SETTINGS_WIFI: - config_module_begin(MENU_SETTINGS_WIFI); - break; - case MENU_SETTINGS_SD_CARD_INFO: - update_sd_card_info(); - break; - case MENU_SETTINGS_SD_CARD_FORMAT: - sd_card_settings_verify_sd_card(); - menu_screens_set_app_state(true, sd_card_settings_keyboard_cb); - break; - default: - break; - } -} - -void settings_module_begin() { - ESP_LOGI(TAG, "Settings module begin"); - menu_screens_register_exit_submenu_cb(settings_module_exit_submenu_cb); - menu_screens_register_enter_submenu_cb(settings_module_enter_submenu_cb); -} - -void settings_module_exit() { - menu_screens_unregister_submenu_cbs(); -} +void settings_module_time_zone() { + general_radio_selection_menu_t time_zone; + time_zone.banner = "Select Time Zone"; + time_zone.exit_cb = menus_module_exit_app; + time_zone.options = gps_time_zone_options_2; + time_zone.options_count = 38; + time_zone.style = RADIO_SELECTION_OLD_STYLE; + time_zone.current_option = gps_module_get_time_zone(); + time_zone.select_cb = gps_module_set_time_zone; + general_radio_selection(time_zone); +} \ No newline at end of file diff --git a/firmware/main/modules/settings/settings_module.h b/firmware/main/modules/settings/settings_module.h index 0a6e95a0..2c732922 100644 --- a/firmware/main/modules/settings/settings_module.h +++ b/firmware/main/modules/settings/settings_module.h @@ -1,15 +1,5 @@ #pragma once -/** - * @brief Initialize the settings module - * - * @return void - */ -void settings_module_begin(); +void settings_module_time_zone(); -/** - * @brief Deinitialize the settings module - * - * @return void - */ -void settings_module_exit(); +void update_sd_card_info(); \ No newline at end of file diff --git a/firmware/main/modules/settings/stealth_mode/stealth_mode.c b/firmware/main/modules/settings/stealth_mode/stealth_mode.c new file mode 100644 index 00000000..5b1922d7 --- /dev/null +++ b/firmware/main/modules/settings/stealth_mode/stealth_mode.c @@ -0,0 +1,38 @@ +#include "stealth_mode.h" + +#include +#include + +#include "buzzer.h" +#include "coroutine.h" +#include "general_radio_selection.h" +#include "leds.h" +#include "menus_module.h" +#include "modals_module.h" +#include "preferences.h" + +char* stealth_mode_options[] = {"Disabled", "Enabled"}; + +static void stealth_selection_handler(uint8_t stealth_mode) { + preferences_put_bool("stealth_mode", stealth_mode); + if (stealth_mode) { + buzzer_disable(); + leds_deinit(); + } else { + buzzer_enable(); + leds_begin(); + } +} + +void stealth_mode_open_menu() { + general_radio_selection_menu_t stealth_mode_radio_menu; + stealth_mode_radio_menu.banner = "Stealth Mode"; + stealth_mode_radio_menu.exit_cb = menus_module_exit_app; + stealth_mode_radio_menu.options = stealth_mode_options; + stealth_mode_radio_menu.options_count = 2; + stealth_mode_radio_menu.style = RADIO_SELECTION_OLD_STYLE; + stealth_mode_radio_menu.current_option = + preferences_get_bool("stealth_mode", false); + stealth_mode_radio_menu.select_cb = stealth_selection_handler; + general_radio_selection(stealth_mode_radio_menu); +} \ No newline at end of file diff --git a/firmware/main/modules/settings/stealth_mode/stealth_mode.h b/firmware/main/modules/settings/stealth_mode/stealth_mode.h new file mode 100644 index 00000000..239823aa --- /dev/null +++ b/firmware/main/modules/settings/stealth_mode/stealth_mode.h @@ -0,0 +1,3 @@ +#pragma once + +void stealth_mode_open_menu(); \ No newline at end of file diff --git a/firmware/main/modules/settings/wifi/wifi_settings.c b/firmware/main/modules/settings/wifi/wifi_settings.c index f445463b..9645d2c5 100644 --- a/firmware/main/modules/settings/wifi/wifi_settings.c +++ b/firmware/main/modules/settings/wifi/wifi_settings.c @@ -3,7 +3,7 @@ #include "cmd_wifi.h" #include "esp_log.h" #include "led_events.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" @@ -13,10 +13,6 @@ static int selected_item = 0; static int total_items = 0; static int max_items = 6; -static app_screen_state_information_t app_screen_state_information = { - .in_app = false, - .app_selected = 0, -}; char* options_wifi_menu[] = {"Connect", "Forget", NULL}; typedef enum { @@ -35,7 +31,7 @@ typedef struct { static wifi_setting_state_t wifi_setting_state = WIFI_SETTING_IDLE; static wifi_setting_t wifi_config_state; -static void config_module_app_selector(); +static void only_exit_input_cb(uint8_t button_name, uint8_t button_event); static void config_module_state_machine(uint8_t button_name, uint8_t button_event); static void config_module_state_machine_config(uint8_t button_name, @@ -92,7 +88,7 @@ static void config_module_wifi_display_disconnected() { wifi_config_state.state = WIFI_SETTING_IDLE; selected_item = 0; vTaskDelay(2000 / portTICK_PERIOD_MS); - menu_screens_set_app_state(true, config_module_state_machine); + menus_module_set_app_state(true, config_module_state_machine); config_module_wifi_display_list(); } @@ -101,8 +97,7 @@ static void config_module_wifi_display_connected() { oled_screen_display_text_center("Connected", 4, OLED_DISPLAY_NORMAL); vTaskDelay(2000 / portTICK_PERIOD_MS); cmd_wifi_unregister_callback(); - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); + menus_module_exit_app(); } static void config_module_wifi_handle_connection(bool state) { @@ -200,37 +195,29 @@ static void config_module_wifi_display_connect_modal() { } } -void config_module_begin(int app_selected) { -#if !defined(CONFIG_CONFIGURATION_DEBUG) - esp_log_level_set(TAG_CONFIG_MODULE, ESP_LOG_NONE); -#endif - - ESP_LOGI(TAG_CONFIG_MODULE, "Initializing ble module screen state machine"); - app_screen_state_information.app_selected = app_selected; - - menu_screens_set_app_state(true, config_module_state_machine); - oled_screen_clear(); - config_module_app_selector(); -}; - -static void config_module_app_selector() { - switch (app_screen_state_information.app_selected) { - case MENU_SETTINGS_WIFI: - int count = validate_wifi_count(); - if (count == 0) { - break; - } - wifi_config_state.state = WIFI_SETTING_IDLE; - wifi_config_state.total_items = count; - total_items = count; - ESP_LOGI(__func__, "Saved APs: %d", count); - config_module_wifi_display_list(); - break; - default: - break; +void wifi_settings_begin() { + int count = validate_wifi_count(); + if (count == 0) { + menus_module_set_app_state(true, only_exit_input_cb); + return; } + menus_module_set_app_state(true, config_module_state_machine); + wifi_config_state.state = WIFI_SETTING_IDLE; + wifi_config_state.total_items = count; + total_items = count; + ESP_LOGI(__func__, "Saved APs: %d", count); + config_module_wifi_display_list(); } +static void only_exit_input_cb(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + if (button_name == BUTTON_LEFT) { + cmd_wifi_unregister_callback(); + menus_module_exit_app(); + } +} static void config_module_state_machine(uint8_t button_name, uint8_t button_event) { if (button_event != BUTTON_PRESS_DOWN) { @@ -239,40 +226,33 @@ static void config_module_state_machine(uint8_t button_name, ESP_LOGI(TAG_CONFIG_MODULE, "BLE engine state machine from team: %d %d", button_name, button_event); - switch (app_screen_state_information.app_selected) { - case MENU_SETTINGS_WIFI: - ESP_LOGI(TAG_CONFIG_MODULE, "Bluetooth scanner entered"); - switch (button_name) { - case BUTTON_LEFT: - cmd_wifi_unregister_callback(); - menu_screens_set_app_state(false, NULL); - menu_screens_exit_submenu(); - break; - case BUTTON_RIGHT: - ESP_LOGI(TAG_CONFIG_MODULE, "Selected item: %d", selected_item); - wifi_config_state.selected_item = selected_item; - wifi_config_state.state = WIFI_SETTING_CONFIG; - selected_item = 0; - config_module_wifi_display_sel_options(); - menu_screens_set_app_state(true, config_module_state_machine_config); - break; - case BUTTON_UP: - selected_item = - (selected_item == 0) ? total_items - 1 : selected_item - 1; + switch (button_name) { + case BUTTON_LEFT: + cmd_wifi_unregister_callback(); + menus_module_exit_app(); + break; + case BUTTON_RIGHT: + ESP_LOGI(TAG_CONFIG_MODULE, "Selected item: %d", selected_item); + wifi_config_state.selected_item = selected_item; + wifi_config_state.state = WIFI_SETTING_CONFIG; + selected_item = 0; - config_module_wifi_display_list(); - break; - case BUTTON_DOWN: - selected_item = - (selected_item == total_items - 1) ? 0 : selected_item + 1; - config_module_wifi_display_list(); - break; - case BUTTON_BOOT: - default: - break; - } + config_module_wifi_display_sel_options(); + menus_module_set_app_state(true, config_module_state_machine_config); + break; + case BUTTON_UP: + selected_item = + (selected_item == 0) ? total_items - 1 : selected_item - 1; + + config_module_wifi_display_list(); break; + case BUTTON_DOWN: + selected_item = + (selected_item == total_items - 1) ? 0 : selected_item + 1; + config_module_wifi_display_list(); + break; + case BUTTON_BOOT: default: break; } @@ -287,7 +267,7 @@ static void config_module_state_machine_config(uint8_t button_name, case BUTTON_LEFT: wifi_config_state.state = WIFI_SETTING_IDLE; selected_item = 0; - menu_screens_set_app_state(true, config_module_state_machine); + menus_module_set_app_state(true, config_module_state_machine); config_module_wifi_display_list(); break; case BUTTON_RIGHT: @@ -295,12 +275,12 @@ static void config_module_state_machine_config(uint8_t button_name, if (selected_item == 0) { selected_item = 0; config_module_wifi_display_connect_modal(); - menu_screens_set_app_state( + menus_module_set_app_state( true, config_module_state_machine_config_modal_connect); } else { selected_item = 0; config_module_wifi_display_forget_modal(); - menu_screens_set_app_state( + menus_module_set_app_state( true, config_module_state_machine_config_modal_forget); } break; @@ -345,11 +325,11 @@ static void config_module_state_machine_config_modal_connect( preferences_get_string(wifi_ssid, wifi_pass, 100); connect_wifi(wifi_ssid, wifi_pass, config_module_wifi_handle_connection); - menu_screens_set_app_state(true, config_module_state_machine_config); + menus_module_set_app_state(true, config_module_state_machine_config); } else { selected_item = 0; wifi_config_state.state = WIFI_SETTING_IDLE; - menu_screens_set_app_state(true, config_module_state_machine_config); + menus_module_set_app_state(true, config_module_state_machine_config); config_module_wifi_display_sel_options(); } break; @@ -402,7 +382,7 @@ static void config_module_state_machine_config_modal_forget( } selected_item = 0; wifi_config_state.state = WIFI_SETTING_IDLE; - menu_screens_set_app_state(true, config_module_state_machine_config); + menus_module_set_app_state(true, config_module_state_machine_config); config_module_wifi_display_sel_options(); break; case BUTTON_UP: diff --git a/firmware/main/modules/settings/wifi/wifi_settings.h b/firmware/main/modules/settings/wifi/wifi_settings.h index 96578750..71e0318e 100644 --- a/firmware/main/modules/settings/wifi/wifi_settings.h +++ b/firmware/main/modules/settings/wifi/wifi_settings.h @@ -1,10 +1,5 @@ #ifndef CONFIGURATION_MODULE_H #define CONFIGURATION_MODULE_H -/** - * @brief Begin the bluetooth module - * - * @param app_selected The selected app - */ -void config_module_begin(int app_selected); +void wifi_settings_begin(); #endif // CONFIGURATION_MODULE_H diff --git a/firmware/main/modules/web_file_browser/http_server/web_file_browser.c b/firmware/main/modules/web_file_browser/http_server/web_file_browser.c index 32dcb3d0..d72775a8 100644 --- a/firmware/main/modules/web_file_browser/http_server/web_file_browser.c +++ b/firmware/main/modules/web_file_browser/http_server/web_file_browser.c @@ -39,7 +39,7 @@ static void web_file_browser_show_event(uint8_t event, void* context) { } } -void web_file_browser_init() { +void web_file_browser_begin() { #if !defined(CONFIG_WEB_FILE_BROWSER_DEBUG) esp_log_level_set(TAG, ESP_LOG_NONE); #endif diff --git a/firmware/main/modules/web_file_browser/http_server/web_file_browser.h b/firmware/main/modules/web_file_browser/http_server/web_file_browser.h index 5a22447e..1ae7646e 100644 --- a/firmware/main/modules/web_file_browser/http_server/web_file_browser.h +++ b/firmware/main/modules/web_file_browser/http_server/web_file_browser.h @@ -14,6 +14,6 @@ typedef enum { typedef void (*web_file_browser_show_event_cb_t)(uint8_t, void*); web_file_browser_show_event_cb_t wfb_show_event_cb = NULL; -void web_file_browser_init(); +void web_file_browser_begin(); void web_file_browser_stop(); void web_file_browser_set_show_event_cb(web_file_browser_show_event_cb_t cb); \ No newline at end of file diff --git a/firmware/main/modules/web_file_browser/web_file_browser_module.c b/firmware/main/modules/web_file_browser/web_file_browser_module.c index 1e56c044..466d2372 100644 --- a/firmware/main/modules/web_file_browser/web_file_browser_module.c +++ b/firmware/main/modules/web_file_browser/web_file_browser_module.c @@ -2,7 +2,7 @@ #include "flash_fs.h" #include "keyboard_module.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" #include "sd_card.h" @@ -14,9 +14,9 @@ static void web_file_browser_input_cb(uint8_t button_name, uint8_t button_event); static void web_file_browser_module_exit(); -void web_file_browser_module_init() { +void web_file_browser_module_begin() { oled_screen_clear(); - menu_screens_set_app_state(true, web_file_browser_input_cb); + menus_module_set_app_state(true, web_file_browser_input_cb); if (sd_card_mount() == ESP_OK || flash_fs_mount() == ESP_OK) { bool wifi_connected = preferences_get_bool("wifi_connected", false); if (!wifi_connected) { @@ -24,7 +24,7 @@ void web_file_browser_module_init() { } // wifi_ap_init(); web_file_browser_set_show_event_cb(web_file_browse_show_event_handler); - web_file_browser_init(); + web_file_browser_begin(); } else { oled_screen_display_text(" SD Card ", 0, 3, OLED_DISPLAY_NORMAL); oled_screen_display_text(" Mount Failed ", 0, 4, OLED_DISPLAY_NORMAL); @@ -33,12 +33,12 @@ void web_file_browser_module_init() { } } void web_file_browser_module_exit() { - screen_module_set_screen(MENU_WEB_SD_BROWSER); + menus_module_set_reset_screen(MENU_FILE_MANAGER_2); esp_restart(); } static void web_file_browser_input_cb(uint8_t button_name, uint8_t button_event) { - if (button_event != BUTTON_SINGLE_CLICK) { + if (button_event != BUTTON_PRESS_DOWN) { return; } switch (button_name) { diff --git a/firmware/main/modules/web_file_browser/web_file_browser_module.h b/firmware/main/modules/web_file_browser/web_file_browser_module.h index c8eb2f3c..8f33c52b 100644 --- a/firmware/main/modules/web_file_browser/web_file_browser_module.h +++ b/firmware/main/modules/web_file_browser/web_file_browser_module.h @@ -1,3 +1,3 @@ #pragma once -void web_file_browser_module_init(); \ No newline at end of file +void web_file_browser_module_begin(); \ No newline at end of file diff --git a/firmware/main/modules/wifi/wifi_module.c b/firmware/main/modules/wifi/wifi_module.c index bbd8c9a0..1398a5b3 100644 --- a/firmware/main/modules/wifi/wifi_module.c +++ b/firmware/main/modules/wifi/wifi_module.c @@ -1,5 +1,5 @@ +#include "wifi_module.h" -#include "modules/wifi/wifi_module.h" #include "captive_portal.h" #include "catdos_module.h" #include "esp_check.h" @@ -9,67 +9,62 @@ #include "keyboard_module.h" #include "string.h" -#include "apps/wifi/deauth/include/deauth_module.h" -#include "captive_portal.h" +#include "deauth_module.h" +#include "general_radio_selection.h" +#include "general_screens.h" #include "led_events.h" -#include "menu_screens_modules.h" -#include "modules/wifi/wifi_module.h" -#include "modules/wifi/wifi_screens_module.h" +#include "menus_module.h" #include "oled_screen.h" #include "sd_card.h" #include "wifi_attacks.h" #include "wifi_controller.h" +#include "wifi_module.h" #include "wifi_scanner.h" +#include "wifi_screens_module.h" static const char* TAG = "wifi_module"; bool analizer_initialized = false; -const uint32_t SOUND_DURATION = 100; - -/** - * @brief Enum with the wifi module states - * - */ -typedef enum { - WIFI_STATE_SCANNING = 0, - WIFI_STATE_SCANNED, - WIFI_STATE_DETAILS, - WIFI_STATE_ATTACK_SELECTOR, - WIFI_STATE_ATTACK, - WIFI_STATE_ATTACK_CAPTIVE_PORTAL, -} wifi_state_t; - -/** - * @brief Structure to store the wifi module data - * - */ -typedef struct { - wifi_state_t state; - wifi_config_t wifi_config; -} wifi_module_t; - -char* wifi_state_names[] = { - "WIFI_STATE_SCANNING", "WIFI_STATE_SCANNED", - "WIFI_STATE_DETAILS", "WIFI_STATE_ATTACK_SELECTOR", - "WIFI_STATE_ATTACK", "WIFI_STATE_ATTACK_CAPTIVE_PORTAL"}; -static TaskHandle_t task_display_scanning = NULL; -static TaskHandle_t task_display_attacking = NULL; -static wifi_scanner_ap_records_t* ap_records; -static wifi_module_t current_wifi_state; -static int current_option = 0; -static bool show_details = false; -static bool valid_records = false; -static int index_targeted = 0; +static general_menu_t analyzer_summary_menu; +static char* wifi_analizer_summary_2[120] = { + "Summary", +}; +static const char* wifi_analizer_help_2[] = { + "This tool", "allows you to", "analyze the", + "WiFi networks", "around you.", "", + "You can select", "the channel and", "the destination", + "to save the", "results.", +}; + +static const general_menu_t analyzer_help_menu = { + .menu_items = wifi_analizer_help_2, + .menu_count = 11, + .menu_level = GENERAL_TREE_APP_MENU}; + +static const char* destination_options[] = {"SD", "Internal"}; +static const char* channel_options[] = { + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", +}; + +void wifi_module_show_analyzer_help() { + general_register_scrolling_menu(&analyzer_help_menu); + general_screen_display_scrolling_text_handler(menus_module_exit_app); +} +static void wifi_module_input_cb(uint8_t button_name, uint8_t button_event); + +uint16_t get_summary_rows_count() { + uint8_t num_items = 0; + char** submenu = wifi_analizer_summary_2; + if (submenu != NULL) { + while (submenu[num_items] != NULL) { + num_items++; + } + } -static void scanning_task(void* pvParameters) { - while (!valid_records) { - wifi_scanner_module_scan(); - vTaskDelay(5000 / portTICK_PERIOD_MS); + if (num_items == 0) { + return -1; } - vTaskSuspend(task_display_scanning); - wifi_screens_module_display_scanned_networks( - ap_records->records, ap_records->count, current_option); - vTaskDelete(NULL); + return num_items; } void wifi_module_init_sniffer() { @@ -80,18 +75,9 @@ void wifi_module_init_sniffer() { case ESP_OK: ESP_LOGI(TAG, "SD card mounted"); break; - case ESP_ERR_ALREADY_MOUNTED: - ESP_LOGI(TAG, "SD card already mounted"); - break; case ESP_ERR_NOT_SUPPORTED: ESP_LOGI(TAG, "SD card not supported"); - oled_screen_display_text_center("SD card not", 0, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("supported", 1, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("Switching to", 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("internal storage", 4, - OLED_DISPLAY_NORMAL); - vTaskDelay(2000 / portTICK_PERIOD_MS); - oled_screen_clear(); + wifi_screeens_show_sd_not_supported(); wifi_sniffer_set_destination_internal(); // TODO: add an option to format the SD card break; @@ -99,129 +85,91 @@ void wifi_module_init_sniffer() { ESP_LOGE(TAG, "SD card mount failed: reason: %s", esp_err_to_name(err)); case ESP_ERR_NOT_FOUND: ESP_LOGW(TAG, "SD card not found"); - oled_screen_display_text_center("SD card ", 0, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("not found", 1, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("Switching to", 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("internal storage", 4, - OLED_DISPLAY_NORMAL); - vTaskDelay(2000 / portTICK_PERIOD_MS); - oled_screen_clear(); + wifi_screeens_show_sd_not_found(); wifi_sniffer_set_destination_internal(); break; } } - wifi_sniffer_start(); led_control_run_effect(led_control_zigbee_scanning); } +static void wifi_module_summary_exit_cb() { + wifi_sniffer_close_file(); + menus_module_exit_app(); +} -void wifi_module_exit_submenu_cb() { - screen_module_menu_t current_menu = menu_screens_get_current_menu(); +void wifi_module_analyzer_run_exit() { + analyzer_summary_menu.menu_items = wifi_analizer_summary_2; + analyzer_summary_menu.menu_level = GENERAL_TREE_APP_MENU; + wifi_sniffer_stop(); + led_control_stop(); + wifi_sniffer_load_summary(); + analyzer_summary_menu.menu_count = get_summary_rows_count(); + general_register_scrolling_menu(&analyzer_summary_menu); + general_screen_display_scrolling_text_handler(wifi_module_summary_exit_cb); +} - switch (current_menu) { - case MENU_WIFI_APPS: - menu_screens_unregister_submenu_cbs(); - break; - case MENU_WIFI_ANALYZER_RUN: - wifi_sniffer_stop(); - led_control_stop(); - wifi_sniffer_load_summary(); - break; - case MENU_WIFI_ANALYZER_ASK_SUMMARY: - oled_screen_clear(); - wifi_sniffer_start(); - led_control_run_effect(led_control_zigbee_scanning); - break; - case MENU_WIFI_ANALYZER_SUMMARY: - wifi_sniffer_close_file(); - break; - case MENU_WIFI_ANALIZER: - screen_module_set_screen(MENU_WIFI_ANALIZER); - esp_restart(); - break; - case MENU_WIFI_ANALYZER_DESTINATION: - if (wifi_sniffer_is_destination_sd()) { - // Verify if the SD card is inserted - sd_card_unmount(); - if (sd_card_mount() == ESP_OK) { - vTaskDelay(100 / portTICK_PERIOD_MS); - sd_card_unmount(); - } else { - wifi_sniffer_set_destination_internal(); - } - } - break; - // case MENU_WIFI_DOS: - // screen_module_set_screen(MENU_WIFI_DOS); - // esp_restart(); - break; - default: - break; - } +void wifi_module_analyzer_summary_exit() { + wifi_sniffer_close_file(); } -void wifi_module_enter_submenu_cb(screen_module_menu_t user_selection) { - uint8_t selected_item = menu_screens_get_selected_item(); +void wifi_module_analyzer_exit() { + menus_module_restart(); +} - switch (user_selection) { - case MENU_WIFI_ANALIZER: - wifi_module_analizer_begin(); - break; - case MENU_WIFI_DEAUTH: - deauth_module_begin(); - break; - case MENU_WIFI_DOS: - oled_screen_clear(); - catdos_module_begin(); - break; - case MENU_WIFI_ANALYZER_RUN: - wifi_module_init_sniffer(); - break; - case MENU_WIFI_ANALYZER_SUMMARY: - // wifi_sniffer_load_summary(); - break; - case MENU_WIFI_ANALYZER_CHANNEL: - if (menu_screens_is_configuration(user_selection)) { - buzzer_play_for(SOUND_DURATION); - wifi_sniffer_set_channel(selected_item + 1); - } - wifi_module_update_channel_options(); - break; - case MENU_WIFI_ANALYZER_DESTINATION: - if (menu_screens_is_configuration(user_selection)) { - buzzer_play_for(SOUND_DURATION); - if (selected_item == WIFI_SNIFFER_DESTINATION_SD) { - wifi_sniffer_set_destination_sd(); - } else { - wifi_sniffer_set_destination_internal(); - } - } - wifi_module_update_destination_options(); - break; - default: - break; +void wifi_module_analyzer_destination_exit() { + if (wifi_sniffer_is_destination_sd()) { + // Verify if the SD card is inserted + sd_card_unmount(); + if (sd_card_mount() == ESP_OK) { + vTaskDelay(100 / portTICK_PERIOD_MS); + sd_card_unmount(); + } else { + wifi_sniffer_set_destination_internal(); + } } } -void wifi_module_begin() { -#if !defined(CONFIG_WIFI_MODULE_DEBUG) - esp_log_level_set(TAG, ESP_LOG_NONE); -#endif - menu_screens_register_enter_submenu_cb(wifi_module_enter_submenu_cb); - menu_screens_register_exit_submenu_cb(wifi_module_exit_submenu_cb); +void wifi_module_analyzer_run() { + wifi_module_init_sniffer(); + menus_module_set_app_state(true, wifi_module_input_cb); } -void wifi_module_exit() { - screen_module_set_screen(MENU_WIFI_DEAUTH); - esp_restart(); +static void wifi_module_set_destination(uint8_t selected_item) { + if (selected_item == WIFI_SNIFFER_DESTINATION_SD) { + wifi_sniffer_set_destination_sd(); + } else { + wifi_sniffer_set_destination_internal(); + } +} +static void wifi_module_set_channel(uint8_t selected_item) { + wifi_sniffer_set_channel(selected_item + 1); } -void wifi_module_analizer_begin() { - if (analizer_initialized) { - ESP_LOGW(TAG, "WiFi analizer already initialized"); - return; - } +void wifi_module_analyzer_channel() { + general_radio_selection_menu_t channel = {0}; + channel.banner = "Choose Channel", + channel.current_option = wifi_sniffer_get_channel() - 1; + channel.options = channel_options; + channel.options_count = 14; + channel.select_cb = wifi_module_set_channel; + channel.exit_cb = menus_module_exit_app; + channel.style = RADIO_SELECTION_OLD_STYLE; + general_radio_selection(channel); +} +void wifi_module_analyzer_destination() { + general_radio_selection_menu_t destination = {0}; + destination.banner = "Choose Destination", + destination.current_option = wifi_sniffer_is_destination_internal(); + destination.options = destination_options; + destination.options_count = 2; + destination.select_cb = wifi_module_set_destination; + destination.exit_cb = menus_module_exit_app; + destination.style = RADIO_SELECTION_OLD_STYLE; + general_radio_selection(destination); +} +void wifi_module_analizer_begin() { ESP_LOGI(TAG, "Initializing WiFi analizer module"); wifi_sniffer_register_cb(wifi_screens_module_display_sniffer_cb); wifi_sniffer_register_animation_cbs(wifi_screens_sniffer_animation_start, @@ -257,14 +205,14 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { snprintf(link_type_str, 16, "LinkType: %" PRIu32, file_header.link_type); // Load header information - uint32_t summary_index = 2; // Skip scroll text flag and Summary title - wifi_analizer_summary[summary_index++] = "----------------"; - wifi_analizer_summary[summary_index++] = "Magic Number:"; - wifi_analizer_summary[summary_index++] = magic_number_str; - wifi_analizer_summary[summary_index++] = major_version_str; - wifi_analizer_summary[summary_index++] = snaplen_str; - wifi_analizer_summary[summary_index++] = link_type_str; - wifi_analizer_summary[summary_index++] = "----------------"; + uint32_t summary_index = 1; // Skip scroll text flag and Summary title + wifi_analizer_summary_2[summary_index++] = "----------------"; + wifi_analizer_summary_2[summary_index++] = "Magic Number:"; + wifi_analizer_summary_2[summary_index++] = magic_number_str; + wifi_analizer_summary_2[summary_index++] = major_version_str; + wifi_analizer_summary_2[summary_index++] = snaplen_str; + wifi_analizer_summary_2[summary_index++] = link_type_str; + wifi_analizer_summary_2[summary_index++] = "----------------"; uint32_t packet_num = 0; pcap_packet_header_t packet_header; @@ -291,10 +239,10 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { packet_header.packet_length); // Load packet header information - wifi_analizer_summary[summary_index++] = packet_num_str; - wifi_analizer_summary[summary_index++] = timestamp_seconds_str; - wifi_analizer_summary[summary_index++] = capture_length_str; - wifi_analizer_summary[summary_index++] = packet_length_str; + wifi_analizer_summary_2[summary_index++] = packet_num_str; + wifi_analizer_summary_2[summary_index++] = timestamp_seconds_str; + wifi_analizer_summary_2[summary_index++] = capture_length_str; + wifi_analizer_summary_2[summary_index++] = packet_length_str; size_t payload_length = packet_header.capture_length; packet_payload = malloc(payload_length); @@ -325,11 +273,11 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { snprintf(bssid_str2, 32, " %2X:%2X:%2X", packet_payload[19], packet_payload[20], packet_payload[21]); - wifi_analizer_summary[summary_index++] = "SSID:"; - wifi_analizer_summary[summary_index++] = ssid_str; - wifi_analizer_summary[summary_index++] = channel_str; - wifi_analizer_summary[summary_index++] = bssid_str; - wifi_analizer_summary[summary_index++] = bssid_str2; + wifi_analizer_summary_2[summary_index++] = "SSID:"; + wifi_analizer_summary_2[summary_index++] = ssid_str; + wifi_analizer_summary_2[summary_index++] = channel_str; + wifi_analizer_summary_2[summary_index++] = bssid_str; + wifi_analizer_summary_2[summary_index++] = bssid_str2; } // Frame Control Field is coded as LSB first char* frame_type_str = malloc(32); @@ -351,20 +299,20 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { snprintf(source_str2, 32, " %2X:%2X:%2X", packet_payload[13], packet_payload[14], packet_payload[15]); - wifi_analizer_summary[summary_index++] = frame_type_str; - wifi_analizer_summary[summary_index++] = frame_subtype_str; - wifi_analizer_summary[summary_index++] = "Destination:"; - wifi_analizer_summary[summary_index++] = destination_str; - wifi_analizer_summary[summary_index++] = destination_str2; - wifi_analizer_summary[summary_index++] = source_str; - wifi_analizer_summary[summary_index++] = source_str2; + wifi_analizer_summary_2[summary_index++] = frame_type_str; + wifi_analizer_summary_2[summary_index++] = frame_subtype_str; + wifi_analizer_summary_2[summary_index++] = "Destination:"; + wifi_analizer_summary_2[summary_index++] = destination_str; + wifi_analizer_summary_2[summary_index++] = destination_str2; + wifi_analizer_summary_2[summary_index++] = source_str; + wifi_analizer_summary_2[summary_index++] = source_str2; - wifi_analizer_summary[summary_index++] = "----------------"; + wifi_analizer_summary_2[summary_index++] = "----------------"; } else { char* link_type_str = malloc(32); snprintf(link_type_str, 32, "Link Type: %" PRIu32, file_header.link_type); - wifi_analizer_summary[summary_index++] = "Unknown link type"; - wifi_analizer_summary[summary_index++] = link_type_str; + wifi_analizer_summary_2[summary_index++] = "Unknown link type"; + wifi_analizer_summary_2[summary_index++] = link_type_str; } free(packet_payload); packet_payload = NULL; @@ -373,15 +321,15 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { } if (packet_num > 0) { - wifi_analizer_summary[summary_index++] = "Open the pcap"; - wifi_analizer_summary[summary_index++] = "file in"; - wifi_analizer_summary[summary_index++] = "Wireshark to see"; - wifi_analizer_summary[summary_index++] = "more."; + wifi_analizer_summary_2[summary_index++] = "Open the pcap"; + wifi_analizer_summary_2[summary_index++] = "file in"; + wifi_analizer_summary_2[summary_index++] = "Wireshark to see"; + wifi_analizer_summary_2[summary_index++] = "more."; } else { - wifi_analizer_summary[summary_index++] = "No packets found"; + wifi_analizer_summary_2[summary_index++] = "No packets found"; } - wifi_analizer_summary[summary_index++] = NULL; + wifi_analizer_summary_2[summary_index++] = NULL; if (packet_payload) { free(packet_payload); } @@ -390,19 +338,24 @@ void wifi_module_analizer_summary_cb(FILE* pcap_file) { if (packet_payload) { free(packet_payload); } - wifi_analizer_summary[summary_index++] = NULL; + wifi_analizer_summary_2[summary_index++] = NULL; } -void wifi_module_update_channel_options() { - uint8_t selected_option = wifi_sniffer_get_channel(); - selected_option--; - menu_screens_update_options(wifi_analizer_channel_items, selected_option); -} - -void wifi_module_update_destination_options() { - uint8_t selected_option = 0; - if (wifi_sniffer_is_destination_internal()) { - selected_option = 1; +static void wifi_module_input_cb(uint8_t button_name, uint8_t button_event) { + if (button_event != BUTTON_PRESS_DOWN) { + return; + } + switch (button_name) { + case BUTTON_LEFT: + wifi_module_analyzer_run_exit(); + break; + case BUTTON_RIGHT: + break; + case BUTTON_UP: + break; + case BUTTON_DOWN: + break; + default: + break; } - menu_screens_update_options(wifi_analizer_destination_items, selected_option); } diff --git a/firmware/main/modules/wifi/wifi_module.h b/firmware/main/modules/wifi/wifi_module.h index b74aca81..b42020b6 100644 --- a/firmware/main/modules/wifi/wifi_module.h +++ b/firmware/main/modules/wifi/wifi_module.h @@ -2,7 +2,6 @@ #include "esp_wifi.h" #include "keyboard_module.h" -#include "menu_screens_modules.h" /** * @brief Initialize the wifi module @@ -11,13 +10,6 @@ */ void wifi_module_begin(); -/** - * @brief Initialize the wifi module - * - * @return void - */ -void wifi_module_deauth_begin(); - /** * @brief Initialize the wifi module * @@ -25,11 +17,19 @@ void wifi_module_deauth_begin(); */ void wifi_module_analizer_begin(); +void wifi_module_init_sniffer(); + +void wifi_module_analyzer_run(); + /** * @brief Stop the wifi module * */ void wifi_module_exit(void); +void wifi_module_analyzer_run_exit(); +void wifi_module_analyzer_exit(); +void wifi_module_analyzer_summary_exit(); +void wifi_module_analyzer_destination_exit(); /** * @brief Callback to show the summary of the wifi analizer @@ -40,23 +40,7 @@ void wifi_module_exit(void); */ void wifi_module_analizer_summary_cb(FILE* pcap_file); -/** - * @brief Update the channel items array - * - * @return void - */ -void wifi_module_update_channel_options(); - -/** - * @brief Update the destination items array - * - * @return void - */ -void wifi_module_update_destination_options(); +void wifi_module_show_analyzer_help(); -/** - * @brief State machine for the wifi module - * - * @param button_pressed The button pressed - */ -void wifi_module_keyboard_cb(uint8_t button_name, uint8_t button_event); +void wifi_module_analyzer_destination(); +void wifi_module_analyzer_channel(); \ No newline at end of file diff --git a/firmware/main/modules/wifi/wifi_screens_module.c b/firmware/main/modules/wifi/wifi_screens_module.c index 41e86307..59f94e90 100644 --- a/firmware/main/modules/wifi/wifi_screens_module.c +++ b/firmware/main/modules/wifi/wifi_screens_module.c @@ -6,203 +6,8 @@ #include "modules/wifi/wifi_bitmaps.h" #include "oled_screen.h" -int max_records_to_display = 7; TaskHandle_t wifi_sniffer_animation_task_handle = NULL; -static const char* wifi_auth_modes[] = {"OPEN", - "WEP", - "WPA_PSK", - "WPA2_PSK", - "WPA_WPA2_PSK", - "ENTERPRISE", - "WPA3_PSK", - "WPA2/3_PSK", - "WAPI_PSK", - "OWE", - "WPA3_ENT_192", - "WPA3_EXT_PSK", - "WPA3EXTPSK_MIXED", - "MAX"}; - -static const char* wifi_cipher_types[] = { - "NONE", "WEP40", "WEP104", "TKIP", "CCMP", - "TKIP_CCMP", "AES_CMAC128", "SMS4", "GCMP", "GCMP256", - "AES_GMAC128", "AES_GMAC256", "UNKNOWN"}; - -void wifi_screens_module_scanning(void) { - oled_screen_clear(); - oled_screen_display_text_center("SCANNING", 0, OLED_DISPLAY_NORMAL); - while (true) { - for (int i = 0; i < wifi_bitmap_allArray_LEN; i++) { - oled_screen_display_bitmap(wifi_bitmap_allArray[i], 48, 16, 32, 32, - OLED_DISPLAY_NORMAL); - vTaskDelay(500 / portTICK_PERIOD_MS); - } - vTaskDelay(500 / portTICK_PERIOD_MS); - } -} - -void wifi_screens_module_animate_attacking(wifi_ap_record_t* ap_record) { - oled_screen_clear(); - char* ssid = (char*) malloc(33); - memset(ssid, 0, 33); - sprintf(ssid, "%s", (char*) ap_record->ssid); - - oled_screen_display_text_center("TARGETING", 0, OLED_DISPLAY_INVERT); - oled_screen_display_text_center(ssid, 1, OLED_DISPLAY_INVERT); - - while (true) { - for (int i = 0; i < wifi_bitmap_allArray_LEN; i++) { - oled_screen_display_bitmap(wifi_bitmap_allArray[i], 48, 16, 32, 32, - OLED_DISPLAY_NORMAL); - vTaskDelay(500 / portTICK_PERIOD_MS); - } - vTaskDelay(500 / portTICK_PERIOD_MS); - } - free(ssid); -} - -void wifi_screens_module_display_scanned_networks(wifi_ap_record_t* ap_records, - int scanned_records, - int current_option) { - oled_screen_clear(); - oled_screen_display_text_center("Select a network", 0, OLED_DISPLAY_NORMAL); - - for (int i = current_option; i < (max_records_to_display + current_option); - i++) { - if (i >= scanned_records) { - break; - } - if (i == current_option) { - char* prefix = "> "; - char item_text[strlen(prefix) + strlen((char*) ap_records[i].ssid) + 1]; - strcpy(item_text, prefix); - strcat(item_text, (char*) ap_records[i].ssid); - oled_screen_display_text(item_text, 0, (i + 1) - current_option, - OLED_DISPLAY_INVERT); - } else { - oled_screen_display_text((char*) ap_records[i].ssid, 0, - (i + 1) - current_option, OLED_DISPLAY_NORMAL); - } - } -} - -void wifi_screens_module_display_details_network(wifi_ap_record_t* ap_record, - int page) { - oled_screen_clear(); - char* ssid = (char*) malloc(33); - memset(ssid, 0, 33); - sprintf(ssid, "%s", (char*) ap_record->ssid); - oled_screen_display_text_center(ssid, 0, OLED_DISPLAY_INVERT); - - if (page == 0) { - char* bssid = (char*) malloc(20); - char* rssi_channel = (char*) malloc(MAX_LINE_CHAR); - char* auth_mode = (char*) malloc(20); - - sprintf(auth_mode, "%s", wifi_auth_modes[ap_record->authmode]); - sprintf(rssi_channel, "%d dBm %d", ap_record->rssi, ap_record->primary); - sprintf(bssid, "%02X:%02X:%02X:%02X:%02X%02X", ap_record->bssid[0], - ap_record->bssid[1], ap_record->bssid[2], ap_record->bssid[3], - ap_record->bssid[4], ap_record->bssid[5]); - oled_screen_display_text_center("RSSI PRIM CH", 2, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(rssi_channel, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("BSSID", 4, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(bssid, 5, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("AUTH MODE", 6, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(auth_mode, 7, OLED_DISPLAY_NORMAL); - free(bssid); - free(rssi_channel); - free(auth_mode); - } else { - char* pairwise_cipher = (char*) malloc(20); - char* group_cipher = (char*) malloc(20); - - sprintf(pairwise_cipher, "%s", - wifi_cipher_types[ap_record->pairwise_cipher]); - sprintf(group_cipher, "%s", wifi_cipher_types[ap_record->group_cipher]); - - oled_screen_display_text_center("PAIRWISE CIPHER", 2, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(pairwise_cipher, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("GROUP CIPHER", 5, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(group_cipher, 6, OLED_DISPLAY_NORMAL); - - free(pairwise_cipher); - free(group_cipher); - } - free(ssid); -} - -void wifi_screens_module_display_attack_selector(char* attack_options[], - int list_count, - int current_option) { - oled_screen_clear(); - oled_screen_display_text_center("Select Attack", 0, OLED_DISPLAY_NORMAL); - for (int i = 0; i < list_count; i++) { - if (attack_options[i] == NULL) { - break; - } - - if (i == current_option) { - char* prefix = "> "; - char item_text[strlen(prefix) + strlen(attack_options[i]) + 1]; - strcpy(item_text, prefix); - strcat(item_text, attack_options[i]); - oled_screen_display_text(item_text, 0, i + 1, OLED_DISPLAY_INVERT); - } else { - oled_screen_display_text(attack_options[i], 0, i + 1, - OLED_DISPLAY_NORMAL); - } - } -} - -void wifi_screens_module_display_captive_pass(char* ssid, - char* user, - char* pass) { - oled_screen_clear(); - oled_screen_display_text_center("Captive Portal", 0, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("SSID", 1, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(ssid, 2, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("PASS", 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(pass, 4, OLED_DISPLAY_INVERT); -} - -void wifi_screens_module_display_captive_user_pass(char* ssid, - char* user, - char* pass) { - oled_screen_clear(); - oled_screen_display_text_center("Captive Portal", 0, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("SSID", 1, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(ssid, 2, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center("USER", 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(user, 4, OLED_DISPLAY_INVERT); - oled_screen_display_text_center("PASS", 5, OLED_DISPLAY_NORMAL); - oled_screen_display_text_center(pass, 6, OLED_DISPLAY_INVERT); -} - -void wifi_screens_module_display_captive_selector(char* attack_options[], - int list_count, - int current_option) { - oled_screen_clear(); - oled_screen_display_text_center("Select Portal", 0, OLED_DISPLAY_NORMAL); - for (int i = 0; i < list_count; i++) { - if (attack_options[i] == NULL) { - break; - } - - if (i == current_option) { - char* prefix = "> "; - char item_text[strlen(prefix) + strlen(attack_options[i]) + 1]; - strcpy(item_text, prefix); - strcat(item_text, attack_options[i]); - oled_screen_display_text(item_text, 0, i + 1, OLED_DISPLAY_INVERT); - } else { - oled_screen_display_text(attack_options[i], 0, i + 1, - OLED_DISPLAY_NORMAL); - } - } -} - void wifi_screens_module_display_sniffer_cb(sniffer_runtime_t* sniffer) { if (sniffer->is_running) { const char* packets_str = malloc(16); @@ -235,3 +40,21 @@ void wifi_screens_sniffer_animation_start() { void wifi_screens_sniffer_animation_stop() { animations_task_stop(); } + +void wifi_screeens_show_sd_not_supported() { + oled_screen_display_text_center("SD card not", 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("supported", 1, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("Switching to", 3, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("internal storage", 4, OLED_DISPLAY_NORMAL); + vTaskDelay(2000 / portTICK_PERIOD_MS); + oled_screen_clear(); +} + +void wifi_screeens_show_sd_not_found() { + oled_screen_display_text_center("SD card ", 0, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("not found", 1, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("Switching to", 3, OLED_DISPLAY_NORMAL); + oled_screen_display_text_center("internal storage", 4, OLED_DISPLAY_NORMAL); + vTaskDelay(2000 / portTICK_PERIOD_MS); + oled_screen_clear(); +} diff --git a/firmware/main/modules/wifi/wifi_screens_module.h b/firmware/main/modules/wifi/wifi_screens_module.h index a0c0ed3a..1b7d8a0e 100644 --- a/firmware/main/modules/wifi/wifi_screens_module.h +++ b/firmware/main/modules/wifi/wifi_screens_module.h @@ -6,19 +6,6 @@ #define WIFI_SCREENS_MODULE_H #define TAG_WIFI_SCREENS_MODULE "module:wifi_screens" -/** - * @brief Display the wifi module scanning screen - * - */ -void wifi_screens_module_scanning(void); - -/** - * @brief Display the wifi module scanned screen - * - * @param ap_records The pointer to the scanned AP records - */ -void wifi_screens_module_animate_attacking(wifi_ap_record_t* ap_record); - /** * @brief Display the wifi module scanned screen * @@ -30,45 +17,6 @@ void wifi_screens_module_display_scanned_networks(wifi_ap_record_t* ap_records, int scanned_records, int current_option); -/** - * @brief Display the wifi module details screen - * - * @param ap_record The pointer to the AP record - * @param page The page to display - */ -void wifi_screens_module_display_details_network(wifi_ap_record_t* ap_record, - int page); - -/** - * @brief Display the wifi module attack selector screen - * - * @param attack_options The list of attack options - * @param list_count The number of options - * @param current_option The current option selected - */ -void wifi_screens_module_display_attack_selector(char* attack_options[], - int list_count, - int current_option); - -void wifi_screens_module_display_captive_pass(char* ssid, - char* user, - char* pass); - -void wifi_screens_module_display_captive_user_pass(char* ssid, - char* user, - char* pass); - -/** - * @brief Display the wifi module portals selector screen - * - * @param attack_options The list of portals options - * @param list_count The number of options - * @param current_option The current option selected - */ -void wifi_screens_module_display_captive_selector(char* attack_options[], - int list_count, - int current_option); - /** * @brief Display the wifi sniffer progress screen * @@ -107,3 +55,7 @@ void wifi_screens_sniffer_animation_start(); * @return void */ void wifi_screens_sniffer_animation_stop(); + +void wifi_screeens_show_sd_not_supported(); + +void wifi_screeens_show_sd_not_found(); \ No newline at end of file diff --git a/firmware/main/modules/zigbee/zigbee_module.c b/firmware/main/modules/zigbee/zigbee_module.c index acbc71c5..3a6ec3d0 100644 --- a/firmware/main/modules/zigbee/zigbee_module.c +++ b/firmware/main/modules/zigbee/zigbee_module.c @@ -1,8 +1,9 @@ #include "zigbee_module.h" +#include "animations_task.h" #include "esp_log.h" #include "ieee_sniffer.h" #include "led_events.h" -#include "menu_screens_modules.h" +#include "menus_module.h" #include "oled_screen.h" #include "preferences.h" #include "radio_selector.h" @@ -10,10 +11,6 @@ #include "zigbee_screens_module.h" #include "zigbee_switch.h" -app_screen_state_information_t app_screen_state_information = { - .in_app = false, - .app_selected = 0, -}; static int packet_count = 0; int current_channel = IEEE_SNIFFER_CHANNEL_DEFAULT; static TaskHandle_t zigbee_task_display_records = NULL; @@ -21,8 +18,8 @@ static TaskHandle_t zigbee_task_display_animation = NULL; static TaskHandle_t zigbee_task_sniffer = NULL; static void zigbee_module_app_selector(); -static void zigbee_module_state_machine(uint8_t button_name, - uint8_t button_event); +static void switch_input_cb(uint8_t button_name, uint8_t button_event); +static void sniffer_input_cb(uint8_t button_name, uint8_t button_event); static void zigbee_module_display_records_cb(uint8_t* packet, uint8_t packet_length) { @@ -39,110 +36,93 @@ void zigbee_module_begin(int app_selected) { #if !defined(CONFIG_ZIGBEE_MODULE_DEBUG) esp_log_level_set(TAG_ZIGBEE_MODULE, ESP_LOG_NONE); #endif +}; - ESP_LOGI(TAG_ZIGBEE_MODULE, - "Initializing zigbee module screen state machine"); - app_screen_state_information.app_selected = app_selected; +void zigbee_module_switch_enter() { + radio_selector_set_zigbee_switch(); + menus_module_set_app_state(true, switch_input_cb); + zigbee_switch_set_display_status_cb(zigbee_screens_module_display_status); + zigbee_switch_init(); +} - menu_screens_set_app_state(true, zigbee_module_state_machine); - oled_screen_clear(OLED_DISPLAY_NORMAL); - zigbee_module_app_selector(); -}; +void zigbee_module_sniffer_enter() { + radio_selector_set_zigbee_sniffer(); + menus_module_set_app_state(true, sniffer_input_cb); + zigbee_screens_display_device_ad(); + vTaskDelay(8000 / portTICK_PERIOD_MS); + ieee_sniffer_register_cb(zigbee_module_display_records_cb); + zigbee_screens_display_zigbee_sniffer_text(); + animations_task_run(zigbee_screens_display_scanning_animation, 200, NULL); + xTaskCreate(ieee_sniffer_begin, "ieee_sniffer_task", 4096, NULL, 5, + &zigbee_task_sniffer); + led_control_run_effect(led_control_zigbee_scanning); +} -void zigbee_module_app_selector() { - switch (app_screen_state_information.app_selected) { - case MENU_ZIGBEE_SWITCH: - radio_selector_set_zigbee_switch(); - zigbee_switch_set_display_status_cb(zigbee_screens_module_display_status); - zigbee_switch_init(); +static void switch_input_cb(uint8_t button_name, uint8_t button_event) { + ESP_LOGI(TAG_ZIGBEE_MODULE, "Zigbee Switch Entered"); + switch (button_name) { + case BUTTON_RIGHT: + switch (button_event) { + case BUTTON_PRESS_DOWN: + if (zigbee_switch_is_light_connected()) { + zigbee_screens_module_toogle_pressed(); + } + break; + case BUTTON_PRESS_UP: + if (zigbee_switch_is_light_connected()) { + zigbee_screens_module_toggle_released(); + zigbee_switch_toggle(); + } + break; + } break; - case MENU_ZIGBEE_SNIFFER: - radio_selector_set_zigbee_sniffer(); - zigbee_screens_display_device_ad(); - vTaskDelay(8000 / portTICK_PERIOD_MS); - ieee_sniffer_register_cb(zigbee_module_display_records_cb); - xTaskCreate(zigbee_screens_display_scanning_animation, - "zigbee_module_scanning", 4096, NULL, 5, - &zigbee_task_display_animation); - xTaskCreate(ieee_sniffer_begin, "ieee_sniffer_task", 4096, NULL, 5, - &zigbee_task_sniffer); - led_control_run_effect(led_control_zigbee_scanning); + case BUTTON_LEFT: + switch (button_event) { + case BUTTON_PRESS_DOWN: + menus_module_set_reset_screen(MENU_ZIGBEE_SPOOFING_2); + zigbee_switch_deinit(); + break; + } break; default: break; } } -void zigbee_module_state_machine(uint8_t button_name, uint8_t button_event) { - switch (app_screen_state_information.app_selected) { - case MENU_ZIGBEE_SWITCH: - ESP_LOGI(TAG_ZIGBEE_MODULE, "Zigbee Switch Entered"); - switch (button_name) { - case BUTTON_RIGHT: - switch (button_event) { - case BUTTON_PRESS_DOWN: - if (zigbee_switch_is_light_connected()) { - zigbee_screens_module_toogle_pressed(); - } - break; - case BUTTON_PRESS_UP: - if (zigbee_switch_is_light_connected()) { - zigbee_screens_module_toggle_released(); - zigbee_switch_toggle(); - } - break; - } - break; - case BUTTON_LEFT: - switch (button_event) { - case BUTTON_PRESS_DOWN: - screen_module_set_screen(MENU_ZIGBEE_SWITCH); - zigbee_switch_deinit(); - break; - } - break; - default: - break; +static void sniffer_input_cb(uint8_t button_name, uint8_t button_event) { + ESP_LOGI(TAG_ZIGBEE_MODULE, "Zigbee Sniffer Entered"); + switch (button_name) { + case BUTTON_LEFT: + if (button_event == BUTTON_SINGLE_CLICK) { + led_control_stop(); + menus_module_set_reset_screen(MENU_ZIGBEE_APPS_2); + esp_restart(); } break; - case MENU_ZIGBEE_SNIFFER: - ESP_LOGI(TAG_ZIGBEE_MODULE, "Zigbee Sniffer Entered"); - switch (button_name) { - case BUTTON_LEFT: - if (button_event == BUTTON_SINGLE_CLICK) { - led_control_stop(); - screen_module_set_screen(MENU_ZIGBEE_SNIFFER); - esp_restart(); - } - break; - case BUTTON_RIGHT: - ESP_LOGI(TAG_ZIGBEE_MODULE, "Button right pressed - Option selected"); - break; - case BUTTON_UP: - ESP_LOGI(TAG_ZIGBEE_MODULE, "Button up pressed"); - if (button_event == BUTTON_SINGLE_CLICK) { - current_channel = (current_channel == IEEE_SNIFFER_CHANNEL_MAX) - ? IEEE_SNIFFER_CHANNEL_MIN - : (current_channel + 1); - ieee_sniffer_set_channel(current_channel); - // zigbee_screens_display_scanning_text(0, current_channel); - } - break; - case BUTTON_DOWN: - ESP_LOGI(TAG_ZIGBEE_MODULE, "Button down pressed"); - if (button_event == BUTTON_SINGLE_CLICK) { - current_channel = (current_channel == IEEE_SNIFFER_CHANNEL_MIN) - ? IEEE_SNIFFER_CHANNEL_MAX - : (current_channel - 1); - ieee_sniffer_set_channel(current_channel); - // zigbee_screens_display_scanning_text(0, current_channel); - } - break; - case BUTTON_BOOT: - default: - break; + case BUTTON_RIGHT: + ESP_LOGI(TAG_ZIGBEE_MODULE, "Button right pressed - Option selected"); + break; + case BUTTON_UP: + ESP_LOGI(TAG_ZIGBEE_MODULE, "Button up pressed"); + if (button_event == BUTTON_SINGLE_CLICK) { + current_channel = (current_channel == IEEE_SNIFFER_CHANNEL_MAX) + ? IEEE_SNIFFER_CHANNEL_MIN + : (current_channel + 1); + ieee_sniffer_set_channel(current_channel); + // zigbee_screens_display_scanning_text(0, current_channel); + } + break; + case BUTTON_DOWN: + ESP_LOGI(TAG_ZIGBEE_MODULE, "Button down pressed"); + if (button_event == BUTTON_SINGLE_CLICK) { + current_channel = (current_channel == IEEE_SNIFFER_CHANNEL_MIN) + ? IEEE_SNIFFER_CHANNEL_MAX + : (current_channel - 1); + ieee_sniffer_set_channel(current_channel); + // zigbee_screens_display_scanning_text(0, current_channel); } break; + case BUTTON_BOOT: default: break; } diff --git a/firmware/main/modules/zigbee/zigbee_module.h b/firmware/main/modules/zigbee/zigbee_module.h index 6a1c2fd0..db8c07e5 100644 --- a/firmware/main/modules/zigbee/zigbee_module.h +++ b/firmware/main/modules/zigbee/zigbee_module.h @@ -7,4 +7,9 @@ * @param app_selected The selected app */ void zigbee_module_begin(int app_selected); + +void zigbee_module_switch_enter(); + +void zigbee_module_sniffer_enter(); + #endif // ZIGBEE_MODULE_H diff --git a/firmware/main/modules/zigbee/zigbee_screens_module.c b/firmware/main/modules/zigbee/zigbee_screens_module.c index 4470ee00..5f73b5d1 100644 --- a/firmware/main/modules/zigbee/zigbee_screens_module.c +++ b/firmware/main/modules/zigbee/zigbee_screens_module.c @@ -1,4 +1,5 @@ #include "zigbee_screens_module.h" +#include "general/general_screens.h" #include "oled_screen.h" #include "zigbee_bitmaps.h" #include "zigbee_switch.h" @@ -15,40 +16,34 @@ void zigbee_screens_module_toggle_released() { void zigbee_screens_module_creating_network() { oled_screen_clear(); - oled_screen_display_text("Creating", 25, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text("network...", 20, 4, OLED_DISPLAY_NORMAL); + genera_screen_display_card_information("Creating network", "Please wait..."); } void zigbee_screens_module_creating_network_failed() { oled_screen_clear(); - oled_screen_display_text("Creating", 25, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text("network", 29, 4, OLED_DISPLAY_NORMAL); - oled_screen_display_text("failed", 33, 5, OLED_DISPLAY_NORMAL); + genera_screen_display_card_information("Creating network", "Failed"); } void zigbee_screens_module_waiting_for_devices() { static uint8_t dots = 0; dots = ++dots > 3 ? 0 : dots; - oled_screen_clear_line(80, 4, OLED_DISPLAY_NORMAL); - oled_screen_display_text("Waiting for", 19, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text("devices", 24, 4, OLED_DISPLAY_NORMAL); + genera_screen_display_card_information("Waiting for", "devices"); // Print dots from lef to right - for (int i = 0; i < dots; i++) { - oled_screen_display_text(".", 80 + (i * 8), 4, OLED_DISPLAY_NORMAL); + for (int i = 0; i < 3; i++) { + oled_screen_display_text(i < dots ? "." : "", 56 + (i * 8), 4, + OLED_DISPLAY_NORMAL); } } void zigbee_screens_module_no_devices_found() { oled_screen_clear(); vTaskDelay(100 / portTICK_PERIOD_MS); - oled_screen_display_text("No devices", 24, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text("found", 44, 4, OLED_DISPLAY_NORMAL); + genera_screen_display_card_information("No devices", "found"); } void zigbee_screens_module_closing_network() { oled_screen_clear(); - oled_screen_display_text("Closing", 25, 3, OLED_DISPLAY_NORMAL); - oled_screen_display_text("network...", 20, 4, OLED_DISPLAY_NORMAL); + genera_screen_display_card_information("Closing network", "Please wait..."); } void zigbee_screens_module_display_status(uint8_t status) { @@ -81,7 +76,7 @@ void zigbee_screens_module_display_status(uint8_t status) { /////////////////////////////////////////////////////////////////////////// void zigbee_screens_display_device_ad() { oled_screen_clear(OLED_DISPLAY_NORMAL); - int index_page = 1; + int index_page = 0; oled_screen_display_text_splited("Use our", &index_page, OLED_DISPLAY_NORMAL); oled_screen_display_text_splited("PyCatSniffer", &index_page, OLED_DISPLAY_NORMAL); @@ -91,16 +86,16 @@ void zigbee_screens_display_device_ad() { OLED_DISPLAY_NORMAL); } -void zigbee_screens_display_scanning_animation() { +void zigbee_screens_display_zigbee_sniffer_text() { oled_screen_clear(OLED_DISPLAY_NORMAL); oled_screen_display_text_center("ZIGBEE SNIFFER", 0, OLED_DISPLAY_NORMAL); - while (true) { - for (int i = 0; i < zigbee_bitmap_allArray_LEN; i++) { - oled_screen_display_bitmap(zigbee_bitmap_allArray[i], 0, 16, 128, 32, - OLED_DISPLAY_NORMAL); - vTaskDelay(500 / portTICK_PERIOD_MS); - } - } +} + +void zigbee_screens_display_scanning_animation() { + static uint8_t frame = 0; + oled_screen_display_bitmap(zigbee_bitmap_allArray[frame], 0, 16, 128, 32, + OLED_DISPLAY_NORMAL); + frame = ++frame > zigbee_bitmap_allArray_LEN - 1 ? 0 : frame; } void zigbee_screens_display_scanning_text(int count) { diff --git a/firmware/main/modules/zigbee/zigbee_screens_module.h b/firmware/main/modules/zigbee/zigbee_screens_module.h index 092ed3cb..d79ec0e0 100644 --- a/firmware/main/modules/zigbee/zigbee_screens_module.h +++ b/firmware/main/modules/zigbee/zigbee_screens_module.h @@ -1,6 +1,6 @@ #pragma once -#include "menu_screens_modules.h" +#include /** * @brief Display toogle button pressed @@ -60,3 +60,4 @@ void zigbee_screens_module_display_status(uint8_t status); void zigbee_screens_display_device_ad(void); void zigbee_screens_display_scanning_animation(void); void zigbee_screens_display_scanning_text(int count); +void zigbee_screens_display_zigbee_sniffer_text(); diff --git a/firmware/partitions.csv b/firmware/partitions.csv index 7e44e15c..e01522d2 100644 --- a/firmware/partitions.csv +++ b/firmware/partitions.csv @@ -6,5 +6,5 @@ zb_storage, data, fat, , 16K, zb_fct, data, fat, , 1K, otadata, data, ota, , 8K, internal, data, spiffs, , 512K, -ota_0, app, ota_0, , 3M, -ota_1, app, ota_1, , 3M, \ No newline at end of file +ota_0, app, ota_0, , 3200k, +ota_1, app, ota_1, , 3200k, \ No newline at end of file diff --git a/firmware/partitions_no_ota.csv b/firmware/partitions_no_ota.csv index 466f3c30..ecbb9697 100644 --- a/firmware/partitions_no_ota.csv +++ b/firmware/partitions_no_ota.csv @@ -4,4 +4,4 @@ nvs, data, nvs, , 0x6000, phy_init, data, phy, , 0x1000, zb_storage, data, fat, , 16K, zb_fct, data, fat, , 1K, -factory, app, factory, , 3M, +factory, app, factory, , 7M, diff --git a/firmware/profiles/noota b/firmware/profiles/noota new file mode 100644 index 00000000..df42f14a --- /dev/null +++ b/firmware/profiles/noota @@ -0,0 +1 @@ +-B build-noota -DSDKCONFIG=build-noota/sdkconfig -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.noota" diff --git a/firmware/profiles/ota b/firmware/profiles/ota new file mode 100644 index 00000000..c9349bb4 --- /dev/null +++ b/firmware/profiles/ota @@ -0,0 +1 @@ +-B build-ota -DSDKCONFIG=build-ota/sdkconfig -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.ota" diff --git a/firmware/sdkconfig.defaults b/firmware/sdkconfig.defaults index 6d00ecaa..83e8e768 100644 --- a/firmware/sdkconfig.defaults +++ b/firmware/sdkconfig.defaults @@ -18,16 +18,7 @@ CONFIG_BT_BLUEDROID_ENABLED=y CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y # Open Thread Configuration -# -# Partition Table -# -CONFIG_OPENTHREAD_ENABLED=y -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" -CONFIG_PARTITION_TABLE_OFFSET=0x8000 -CONFIG_PARTITION_TABLE_MD5=y -# end of Partition Table + # # mbedTLS @@ -91,3 +82,46 @@ CONFIG_LOG_MASTER_LEVEL=y # CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y + + +# +# Enabled Features +# +## WIFI ## +CONFIG_WIFI_APPS_ENABLE=y +CONFIG_WIFI_APP_ANALYZER=y +CONFIG_WIFI_APP_DEAUTH=y +CONFIG_WIFI_APP_DOS=y +## BLUETOOTH ## +CONFIG_BLUETOOTH_APPS_ENABLE=y +CONFIG_BLUETOOTH_APP_TRAKERS=y +CONFIG_BLUETOOTH_APP_SPAM=y +CONFIG_BLUETOOTH_APP_HID=y +## ZIGBEE ## +CONFIG_ZIGBEE_APPS_ENABLE=y +CONFIG_ZIGBEE_APP_SPOOFING=y +CONFIG_ZIGBEE_APP_SNIFFER=y +## THREAD ## +CONFIG_THREAD_APPS_ENABLE=y +CONFIG_THREAD_APP_BROADCAST=y +CONFIG_THREAD_APP_SNIFFER=y +## GPS ## +CONFIG_GPS_APPS_ENABLE=y +CONFIG_GPS_APP_WARDRIVING=y +## OTA ## +CONFIG_OTA_ENABLE=y +## FILE MANAGER ## +CONFIG_FILE_MANAGER_ENABLE=y +CONFIG_FILE_MANAGER_LOCAL=y +CONFIG_FILE_MANAGER_WEB=y + +# +# Partition Table +# +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table \ No newline at end of file diff --git a/firmware/sdkconfig.noota b/firmware/sdkconfig.noota new file mode 100644 index 00000000..a12c451c --- /dev/null +++ b/firmware/sdkconfig.noota @@ -0,0 +1,34 @@ + +# +# Enabled Features +# +## OTA ## +# CONFIG_OTA_ENABLE is not set +# +# Partition Table +# +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_no_ota.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_no_ota.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Log Level +# +CONFIG_LOG_DEFAULT_LEVEL_NONE=y +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=0 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_ERROR is not set +# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set +# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=0 \ No newline at end of file diff --git a/firmware/sdkconfig.ota b/firmware/sdkconfig.ota new file mode 100644 index 00000000..747ef66a --- /dev/null +++ b/firmware/sdkconfig.ota @@ -0,0 +1,34 @@ + +# +# Enabled Features +# +## OTA ## +CONFIG_OTA_ENABLE=y +# +# Partition Table +# +CONFIG_OPENTHREAD_ENABLED=y +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table + +# +# Log Level +# +CONFIG_LOG_DEFAULT_LEVEL_NONE=y +# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set +# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +# CONFIG_LOG_DEFAULT_LEVEL_INFO is not set +# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set +# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL=0 +CONFIG_LOG_MAXIMUM_EQUALS_DEFAULT=y +# CONFIG_LOG_MAXIMUM_LEVEL_ERROR is not set +# CONFIG_LOG_MAXIMUM_LEVEL_WARN is not set +# CONFIG_LOG_MAXIMUM_LEVEL_INFO is not set +# CONFIG_LOG_MAXIMUM_LEVEL_DEBUG is not set +# CONFIG_LOG_MAXIMUM_LEVEL_VERBOSE is not set +CONFIG_LOG_MAXIMUM_LEVEL=0 \ No newline at end of file