diff --git a/Bluetooth.h b/Bluetooth.h index 61505a5..5812b8e 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -22,8 +22,8 @@ #elif HAS_BLE == true #include "esp_bt_main.h" #include "esp_bt_device.h" - // TODO: Remove - #define SerialBT Serial + #include "src/ble/BLESerial.h" + BLESerial SerialBT; #endif #elif MCU_VARIANT == MCU_NRF52 @@ -36,6 +36,7 @@ #endif #define BT_PAIRING_TIMEOUT 35000 +#define BLE_FLUSH_TIMEOUT 20 uint32_t bt_pairing_started = 0; #define BT_DEV_ADDR_LEN 6 @@ -59,6 +60,7 @@ char bt_devname[11]; } void bt_stop() { + //display_unblank(); if (bt_state != BT_STATE_OFF) { SerialBT.end(); bt_allow_pairing = false; @@ -67,6 +69,7 @@ char bt_devname[11]; } void bt_start() { + //display_unblank(); if (bt_state == BT_STATE_OFF) { SerialBT.begin(bt_devname); bt_state = BT_STATE_ON; @@ -74,6 +77,7 @@ char bt_devname[11]; } void bt_enable_pairing() { + //display_unblank(); if (bt_state == BT_STATE_OFF) bt_start(); bt_allow_pairing = true; bt_pairing_started = millis(); @@ -81,12 +85,14 @@ char bt_devname[11]; } void bt_disable_pairing() { + //display_unblank(); bt_allow_pairing = false; bt_ssp_pin = 0; bt_state = BT_STATE_ON; } void bt_pairing_complete(boolean success) { + //display_unblank(); if (success) { bt_disable_pairing(); } else { @@ -94,7 +100,8 @@ char bt_devname[11]; } } - void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){ + void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { + //display_unblank(); if(event == ESP_SPP_SRV_OPEN_EVT) { bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; @@ -157,25 +164,122 @@ char bt_devname[11]; } #elif HAS_BLE == true - void bt_stop() { - if (bt_state != BT_STATE_OFF) { - bt_allow_pairing = false; - bt_state = BT_STATE_OFF; - } - } + BLESecurity *ble_security = new BLESecurity(); + bool ble_authenticated = false; + uint32_t pairing_pin = 0; + + void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flush(); } } void bt_disable_pairing() { + //display_unblank(); bt_allow_pairing = false; bt_ssp_pin = 0; bt_state = BT_STATE_ON; } - void bt_connect_callback(uint16_t conn_handle) { + void bt_passkey_notify_callback(uint32_t passkey) { + // Serial.printf("Got passkey notification: %d\n", passkey); + bt_ssp_pin = passkey; + bt_state = BT_STATE_PAIRING; + bt_allow_pairing = true; + bt_pairing_started = millis(); + kiss_indicate_btpin(); + } + + bool bt_confirm_pin_callback(uint32_t pin) { + // Serial.printf("Confirm PIN callback: %d\n", pin); + return true; + } + + void bt_debond_all() { + // Serial.println("Debonding all"); + int dev_num = esp_ble_get_bond_device_num(); + esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); + esp_ble_get_bond_device_list(&dev_num, dev_list); + for (int i = 0; i < dev_num; i++) { esp_ble_remove_bond_device(dev_list[i].bd_addr); } + free(dev_list); + } + + void bt_update_passkey() { + // Serial.println("Updating passkey"); + pairing_pin = random(899999)+100000; + bt_ssp_pin = pairing_pin; + } + + uint32_t bt_passkey_callback() { + // Serial.println("API passkey request"); + if (pairing_pin == 0) { bt_update_passkey(); } + return pairing_pin; + } + + bool bt_client_authenticated() { + return ble_authenticated; + } + + void bt_security_setup() { + uint32_t passkey = bt_passkey_callback(); + + // Serial.printf("Executing BT security setup, passkey is %d\n", passkey); + + uint8_t key_size = 16; + 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_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; + + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + 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)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + 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)); + } + + bool bt_security_request_callback() { + if (bt_allow_pairing) { + // Serial.println("Accepting security request"); + return true; + } else { + // Serial.println("Rejecting security request"); + return false; + } + } + + void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result) { + if (auth_result.success == true) { + // Serial.println("Authentication success"); + ble_authenticated = true; + bt_state = BT_STATE_CONNECTED; + } else { + // Serial.println("Authentication fail"); + ble_authenticated = false; + bt_state = BT_STATE_ON; + bt_security_setup(); + } + bt_allow_pairing = false; + bt_ssp_pin = 0; + } + + void bt_connect_callback(BLEServer *server) { + // uint16_t conn_id = server->getConnId(); + // Serial.printf("Connected: %d\n", conn_id); + //display_unblank(); + ble_authenticated = false; bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; } - void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { + void bt_disconnect_callback(BLEServer *server) { + // uint16_t conn_id = server->getConnId(); + // Serial.printf("Disconnected: %d\n", conn_id); + //display_unblank(); + ble_authenticated = false; bt_state = BT_STATE_ON; } @@ -200,8 +304,8 @@ char bt_devname[11]; sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); free(data); - // TODO: Implement GAP & GATT for RNode comms over BLE - + bt_security_setup(); + bt_ready = true; return true; @@ -212,9 +316,20 @@ char bt_devname[11]; } void bt_start() { + //display_unblank(); if (bt_state == BT_STATE_OFF) { bt_state = BT_STATE_ON; - // TODO: Implement + SerialBT.begin(bt_devname); + SerialBT.setTimeout(10); + } + } + + void bt_stop() { + //display_unblank(); + if (bt_state != BT_STATE_OFF) { + bt_allow_pairing = false; + bt_state = BT_STATE_OFF; + SerialBT.end(); } } @@ -229,7 +344,13 @@ char bt_devname[11]; } void bt_enable_pairing() { + //display_unblank(); if (bt_state == BT_STATE_OFF) bt_start(); + + bt_security_setup(); + //bt_debond_all(); + //bt_update_passkey(); + bt_allow_pairing = true; bt_pairing_started = millis(); bt_state = BT_STATE_PAIRING; @@ -239,26 +360,31 @@ char bt_devname[11]; if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { bt_disable_pairing(); } + if (bt_state == BT_STATE_CONNECTED && millis()-SerialBT.lastFlushTime >= BLE_FLUSH_TIMEOUT) { + if (SerialBT.transmitBufferLength > 0) { + bt_flush(); + } + } } #endif #elif MCU_VARIANT == MCU_NRF52 -uint8_t eeprom_read(uint32_t mapped_addr); + uint8_t eeprom_read(uint32_t mapped_addr); -void bt_stop() { - if (bt_state != BT_STATE_OFF) { - bt_allow_pairing = false; - bt_state = BT_STATE_OFF; + void bt_stop() { + if (bt_state != BT_STATE_OFF) { + bt_allow_pairing = false; + bt_state = BT_STATE_OFF; + } } -} -void bt_disable_pairing() { - bt_allow_pairing = false; - bt_ssp_pin = 0; - bt_state = BT_STATE_ON; -} + void bt_disable_pairing() { + bt_allow_pairing = false; + bt_ssp_pin = 0; + bt_state = BT_STATE_ON; + } -void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { + void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { BLEConnection* connection = Bluefruit.Connection(conn_handle); @@ -291,24 +417,23 @@ void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { } else { bt_ssp_pin = 0; } -} + } -bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { + bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { for (int i = 0; i < 6; i++) { - // multiply by tens however many times needed to make numbers appear in order - bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); + // multiply by tens however many times needed to make numbers appear in order + bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); } kiss_indicate_btpin(); if (bt_allow_pairing) { - return true; + return true; } return false; -} + } -void bt_connect_callback(uint16_t conn_handle) { + void bt_connect_callback(uint16_t conn_handle) { bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; - BLEConnection* conn = Bluefruit.Connection(conn_handle); conn->requestPHY(BLE_GAP_PHY_2MBPS); conn->requestMtuExchange(512+3); @@ -321,93 +446,91 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { } } -bool bt_setup_hw() { - if (!bt_ready) { - #if HAS_EEPROM - if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { - #else - if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { - #endif - bt_enabled = true; - } else { - bt_enabled = false; - } - Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); - Bluefruit.autoConnLed(false); - if (Bluefruit.begin()) { - Bluefruit.setTxPower(8); // Check bluefruit.h for supported values - Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no - // This device is indeed capable of yes / no through the pairing mode - // being set, but I have chosen to set it thus to force the input of the - // pin on the device initiating the pairing. This prevents it from being - // paired with automatically by a hypothetical malicious device nearby - // without physical access to the RNode. - - Bluefruit.Security.setMITM(true); - Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); - Bluefruit.Security.setSecuredCallback(bt_connect_callback); - Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); - Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); - Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms - - const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); - char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); - for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { - data[i] = gap_addr.addr[i]; - } + bool bt_setup_hw() { + if (!bt_ready) { #if HAS_EEPROM - data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); + if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { #else - data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); + if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { #endif - unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); - memcpy(bt_dh, hash, BT_DEV_HASH_LEN); - sprintf(bt_devname, "openCom XL %02X%02X", bt_dh[14], bt_dh[15]); - free(data); + bt_enabled = true; + } else { + bt_enabled = false; + } + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.autoConnLed(false); + if (Bluefruit.begin()) { + Bluefruit.setTxPower(8); // Check bluefruit.h for supported values + Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no + // This device is indeed capable of yes / no through the pairing mode + // being set, but I have chosen to set it thus to force the input of the + // pin on the device initiating the pairing. - bt_ready = true; - return true; + Bluefruit.Security.setMITM(true); + Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); + Bluefruit.Security.setSecuredCallback(bt_connect_callback); + Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); + Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); + Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms + const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); + char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); + for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { + data[i] = gap_addr.addr[i]; + } + #if HAS_EEPROM + data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); + #else + data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); + #endif + unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); + memcpy(bt_dh, hash, BT_DEV_HASH_LEN); + sprintf(bt_devname, "openCom XL %02X%02X", bt_dh[14], bt_dh[15]); + free(data); + + bt_ready = true; + return true; + + } else { return false; } } else { return false; } - } else { return false; } -} + } -void bt_start() { - if (bt_state == BT_STATE_OFF) { - Bluefruit.setName(bt_devname); - bledis.setManufacturer(BLE_MANUFACTURER); - bledis.setModel(BLE_MODEL); - // start device information service - bledis.begin(); + void bt_start() { + if (bt_state == BT_STATE_OFF) { + Bluefruit.setName(bt_devname); + bledis.setManufacturer(BLE_MANUFACTURER); + bledis.setModel(BLE_MODEL); + // start device information service + bledis.begin(); - if (!SerialBT_init) { + if (!SerialBT_init) { - SerialBT.bufferTXD(true); // enable buffering + SerialBT.bufferTXD(true); // enable buffering - SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial - SerialBT.begin(); - SerialBT_init = true; - } + SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial + SerialBT.begin(); + SerialBT_init = true; + } - blebas.begin(); + blebas.begin(); - Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); - // Include bleuart 128-bit uuid - Bluefruit.Advertising.addService(SerialBT); + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(SerialBT); - // There is no room for Name in Advertising packet - // Use Scan response for Name - Bluefruit.ScanResponse.addName(); + // There is no room for Name in Advertising packet + // Use Scan response for Name + Bluefruit.ScanResponse.addName(); - Bluefruit.Advertising.start(0); + Bluefruit.Advertising.start(0); - bt_state = BT_STATE_ON; - } -} + bt_state = BT_STATE_ON; + } + } -bool bt_init() { + bool bt_init() { bt_state = BT_STATE_OFF; if (bt_setup_hw()) { if (bt_enabled && !console_active) bt_start(); @@ -415,18 +538,18 @@ bool bt_init() { } else { return false; } -} - -void bt_enable_pairing() { - if (bt_state == BT_STATE_OFF) bt_start(); - bt_allow_pairing = true; - bt_pairing_started = millis(); - bt_state = BT_STATE_PAIRING; -} - -void update_bt() { - if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { - bt_disable_pairing(); } -} + + void bt_enable_pairing() { + if (bt_state == BT_STATE_OFF) bt_start(); + bt_allow_pairing = true; + bt_pairing_started = millis(); + bt_state = BT_STATE_PAIRING; + } + + void update_bt() { + if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { + bt_disable_pairing(); + } + } #endif diff --git a/Boards.h b/Boards.h index c9193fe..1aa6804 100644 --- a/Boards.h +++ b/Boards.h @@ -25,23 +25,102 @@ #define MCU_ESP32 0x81 #define MCU_NRF52 0x71 - // Boards - #define BOARD_RNODE 0x31 - #define BOARD_HMBRW 0x32 + // Products, boards and models. Grouped by manufacturer. + // Below are the original RNodes, sold by Mark Qvist. + #define PRODUCT_RNODE 0x03 // RNode devices + #define BOARD_RNODE 0x31 // Original v1.0 RNode + #define MODEL_A4 0xA4 // RNode v1.0, 433 MHz + #define MODEL_A9 0xA9 // RNode v1.0, 868 MHz + + #define BOARD_RNODE_NG_20 0x40 // RNode hardware revision v2.0 + #define MODEL_A3 0xA3 // RNode v2.0, 433 MHz + #define MODEL_A8 0xA8 // RNode v2.0, 868 MHz + + #define BOARD_RNODE_NG_21 0x41 // RNode hardware revision v2.1 + #define MODEL_A2 0xA2 // RNode v2.1, 433 MHz + #define MODEL_A7 0xA7 // RNode v2.1, 868 MHz + + #define BOARD_RNODE_NG_22 0x42 // RNode hardware revision v2.2 (T3S3) + #define MODEL_A1 0xA1 // RNode v2.2, 433 MHz with SX1268 + #define MODEL_A5 0xA5 // RNode v2.2, 433 MHz with SX1278 + #define MODEL_A6 0xA6 // RNode v2.2, 868 MHz with SX1262 + #define MODEL_AA 0xAA // RNode v2.2, 868 MHz with SX1276 + + #define PRODUCT_TBEAM 0xE0 // T-Beam - sold by LilyGO #define BOARD_TBEAM 0x33 + #define MODEL_E4 0xE4 // T-Beam SX1278, 433 Mhz + #define MODEL_E9 0xE9 // T-Beam SX1276, 868 Mhz + #define MODEL_E3 0xE3 // T-Beam SX1268, 433 Mhz + #define MODEL_E8 0xE8 // T-Beam SX1262, 868 Mhz + + #define PRODUCT_TDECK_V1 0xD0 // T-Deck - sold by LilyGO + #define BOARD_TDECK 0x3B + #define MODEL_D4 0xD4 // LilyGO T-Deck, 433 MHz + #define MODEL_D9 0xD9 // LilyGO T-Deck, 868 MHz + + #define PRODUCT_TBEAM_S_V1 0xEA // T-Beam Supreme - sold by LilyGO + #define BOARD_TBEAM_S_V1 0x3D + #define MODEL_DB 0xDB // LilyGO T-Beam Supreme, 433 MHz + #define MODEL_DC 0xDC // LilyGO T-Beam Supreme, 868 MHz + + #define PRODUCT_T32_10 0xB2 // T3 v1.0 - sold by LilyGO + #define BOARD_LORA32_V1_0 0x39 + #define MODEL_BA 0xBA // LilyGO T3 v1.0, 433 MHz + #define MODEL_BB 0xBB // LilyGO T3 v1.0, 868 MHz + + #define PRODUCT_T32_20 0xB0 // T3 v2.0 - sold by LilyGO + #define BOARD_LORA32_V2_0 0x36 + #define MODEL_B3 0xB3 // LilyGO T3 v2.0, 433 MHz + #define MODEL_B8 0xB8 // LilyGO T3 v2.0, 868 MHz + + #define PRODUCT_T32_21 0xB1 // T3 v2.1 - sold by LilyGO + #define BOARD_LORA32_V2_1 0x37 + #define MODEL_B4 0xB4 // LilyGO T3 v2.1, 433 MHz + #define MODEL_B9 0xB9 // LilyGO T3 v2.1, 868 MHz + + #define BOARD_T3S3 0x42 // T3S3 - sold by LilyGO + #define MODEL_A1 0xA1 // T3S3 SX1262 868/915 MHz + #define MODEL_AB 0xAB // T3S3 SX1276 868/915 MHz + #define MODEL_A5 0xA5 // T3S3 SX1278 433 MHz + #define MODEL_AB 0xAB // T3S3 SX1280 2.4 GHz w/ PA + + #define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices + #define BOARD_TECHO 0x43 + #define MODEL_16 0x16 // T-Echo 433 MHz + #define MODEL_17 0x17 // T-Echo 868/915 MHz + + + #define PRODUCT_H32_V2 0xC0 // LoRa32 v2 - sold by Heltec + #define BOARD_HELTEC32_V2 0x38 + #define MODEL_C4 0xC4 // Heltec Lora32 v2, 433 MHz + #define MODEL_C9 0xC9 // Heltec Lora32 v2, 868 MHz + + #define PRODUCT_H32_V3 0xC1 // LoRa32 v3 - sold by Heltec + #define BOARD_HELTEC32_V3 0x3A + #define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz + #define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz + + #define PRODUCT_RAK4631 0x10 // RAK4631 - sold by RAKWireless + #define BOARD_RAK4631 0x51 + #define MODEL_11 0x11 // RAK4631, 433 MHz + #define MODEL_12 0x12 // RAK4631, 868 MHz + #define MODEL_13 0x13 // RAK4631, 433MHz with WisBlock SX1280 module (LIBSYS002) + #define MODEL_14 0x14 // RAK4631, 868/915 MHz with WisBlock SX1280 module (LIBSYS002) + + #define PRODUCT_OPENCOM_XL 0x20 // openCom XL - sold by Liberated Embedded Systems + #define BOARD_OPENCOM_XL 0x52 + #define MODEL_21 0x21 // openCom XL, 868/915 MHz + + #define BOARD_E22_ESP32 0x44 // Custom Ebyte E22 board design for meshtastic, source: + // https://github.com/NanoVHF/Meshtastic-DIY/blob/main/Schematics/E-Byte_E22/Mesh_Ebyte_E22-XXXM30S.pdf + + #define PRODUCT_HMBRW 0xF0 + #define BOARD_HMBRW 0x32 #define BOARD_HUZZAH32 0x34 #define BOARD_GENERIC_ESP32 0x35 - #define BOARD_LORA32_V2_0 0x36 - #define BOARD_LORA32_V2_1 0x37 - #define BOARD_LORA32_V1_0 0x39 - #define BOARD_HELTEC32_V2 0x38 - #define BOARD_HELTEC32_V3 0x3A - #define BOARD_RNODE_NG_20 0x40 - #define BOARD_RNODE_NG_21 0x41 - #define BOARD_T3S3 0x42 - #define BOARD_TECHO 0x43 #define BOARD_GENERIC_NRF52 0x50 - #define BOARD_FREENODE 0x52 + #define MODEL_FE 0xFE // Homebrew board, max 17dBm output power + #define MODEL_FF 0xFF // Homebrew board, max 14dBm output power // Displays #define OLED 0x01 @@ -131,7 +210,6 @@ #define DISPLAY OLED #define HAS_PMU true #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_SD false #define HAS_EEPROM true @@ -139,10 +217,39 @@ #define I2C_SCL 22 #define PMU_IRQ 35 #define INTERFACE_COUNT 1 + #define HAS_INPUT true + const int pin_btn_usr1 = 38; const int pin_led_rx = 2; const int pin_led_tx = 4; - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; + #if BOARD_VARIANT == MODEL_E4 || BOARD_VARIANT == MODEL_E9 + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; + const bool interface_cfg[INTERFACE_COUNT][3] = { + // SX127X + { + true, // DEFAULT_SPI + false, // HAS_TCXO + false // DIO2_AS_RF_SWITCH + }, + }; + const int8_t interface_pins[INTERFACE_COUNT][10] = { + // SX127X + { + 18, // pin_ss + -1, // pin_sclk + -1, // pin_mosi + -1, // pin_miso + -1, // pin_busy + 26, // pin_dio + 23, // pin_reset + -1, // pin_txen + -1, // pin_rxen + -1 // pin_tcxo_enable + } + }; + + #elif BOARD_VARIANT == MODEL_E3 || BOARD_VARIANT == MODEL_E8 + const uint8_t interfaces[INTERFACE_COUNT] = {SX126X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX1262 { @@ -166,6 +273,7 @@ -1 // pin_tcxo_enable } }; + #endif #elif BOARD_MODEL == BOARD_HUZZAH32 #define HAS_BLUETOOTH true @@ -204,7 +312,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 @@ -248,7 +355,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 @@ -293,7 +399,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_PMU true #define HAS_CONSOLE true #define HAS_EEPROM true @@ -367,6 +472,13 @@ #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 + #define HAS_INPUT true + #define HAS_SLEEP true + #define PIN_WAKEUP GPIO_NUM_0 + #define WAKEUP_LEVEL 0 + + const int pin_btn_usr1 = 0; + #if defined(EXTERNAL_LEDS) const int pin_led_rx = 36; const int pin_led_tx = 37; @@ -405,7 +517,8 @@ #define HAS_DISPLAY true #define HAS_BLUETOOTH false #define HAS_BLE true - #define HAS_CONSOLE false + #define HAS_PMU true + #define HAS_CONSOLE true #define HAS_EEPROM true #define HAS_INPUT true #define HAS_SLEEP true @@ -551,7 +664,6 @@ #elif BOARD_MODEL == BOARD_T3S3 #define IS_ESP32S3 true - #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_CONSOLE false @@ -579,6 +691,7 @@ const int SD_MOSI = 11; const int SD_CLK = 14; const int SD_CS = 13; + #if HAS_NP == false #if defined(EXTERNAL_LEDS) const int pin_led_rx = 37; @@ -599,17 +712,6 @@ true // DIO2_AS_RF_SWITCH }, }; - #elif BOARD_VARIANT == MODEL_A5 // SX1280 with PA - const uint8_t interfaces[INTERFACE_COUNT] = {SX1280}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1280 - { - false, // DEFAULT_SPI - false, // HAS_TCXO - false // DIO2_AS_RF_SWITCH - }, - }; - #endif const uint8_t interface_pins[INTERFACE_COUNT][10] = { // SX1262 { @@ -625,13 +727,184 @@ -1 // pin_tcxo_enable } }; - #else - #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. - #endif + #elif BOARD_VARIANT == MODEL_AB // SX1280 with PA + const uint8_t interfaces[INTERFACE_COUNT] = {SX1280}; + const bool interface_cfg[INTERFACE_COUNT][3] = { + // SX1280 + { + false, // DEFAULT_SPI + false, // HAS_TCXO + false // DIO2_AS_RF_SWITCH + }, + }; + const uint8_t interface_pins[INTERFACE_COUNT][10] = { + // SX1280 + { + 7, // pin_ss + 5, // pin_sclk + 6, // pin_mosi + 3, // pin_miso + 36, // pin_busy + 9, // pin_dio + 8, // pin_reset + 10, // pin_txen + 21, // pin_rxen + -1 // pin_tcxo_enable + } + }; + #endif + + #elif BOARD_MODEL == BOARD_E22_ESP32 + #define HAS_DISPLAY true + #define DISPLAY OLED + #define HAS_BLUETOOTH true + #define HAS_BLE true + #define HAS_CONSOLE true + #define HAS_SD false + #define HAS_EEPROM true + #define I2C_SDA 21 + #define I2C_SCL 22 + #define INTERFACE_COUNT 1 + const int pin_led_rx = 2; + const int pin_led_tx = 4; + + const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; + const bool interface_cfg[INTERFACE_COUNT][3] = { + // SX1262 + { + true, // DEFAULT_SPI + true, // HAS_TCXO + true // DIO2_AS_RF_SWITCH + }, + }; + const int8_t interface_pins[INTERFACE_COUNT][10] = { + // SX1262 + { + 18, // pin_ss + 5, // pin_sclk + 27, // pin_mosi + 19, // pin_miso + 32, // pin_busy + 33, // pin_dio + 23, // pin_reset + -1, // pin_txen + 14, // pin_rxen + -1 // pin_tcxo_enable + } + }; + + #elif BOARD_MODEL == BOARD_TDECK + #define IS_ESP32S3 true + #define MODEM SX1262 + #define DIO2_AS_RF_SWITCH true + #define HAS_BUSY true + #define HAS_TCXO true + + #define HAS_DISPLAY false + #define HAS_CONSOLE false + #define HAS_BLUETOOTH false + #define HAS_BLE true + #define HAS_PMU true + #define HAS_NP false + #define HAS_SD false + #define HAS_EEPROM true + + #define HAS_INPUT true + #define HAS_SLEEP true + #define PIN_WAKEUP GPIO_NUM_0 + #define WAKEUP_LEVEL 0 + + const int pin_poweron = 10; + const int pin_btn_usr1 = 0; + + const int pin_cs = 9; + const int pin_reset = 17; + const int pin_sclk = 40; + const int pin_mosi = 41; + const int pin_miso = 38; + const int pin_tcxo_enable = -1; + const int pin_dio = 45; + const int pin_busy = 13; + + const int SD_MISO = 38; + const int SD_MOSI = 41; + const int SD_CLK = 40; + const int SD_CS = 39; + + const int DISPLAY_DC = 11; + const int DISPLAY_CS = 12; + const int DISPLAY_MISO = 38; + const int DISPLAY_MOSI = 41; + const int DISPLAY_CLK = 40; + const int DISPLAY_BL_PIN = 42; + + #if HAS_NP == false + #if defined(EXTERNAL_LEDS) + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #else + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #endif + #endif + + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #define IS_ESP32S3 true + #define MODEM SX1262 + #define DIO2_AS_RF_SWITCH true + #define HAS_BUSY true + #define HAS_TCXO true + + #define HAS_DISPLAY true + #define HAS_CONSOLE true + #define HAS_BLUETOOTH false + #define HAS_BLE true + #define HAS_PMU true + #define HAS_NP false + #define HAS_SD false + #define HAS_EEPROM true + + #define HAS_INPUT true + #define HAS_SLEEP false + + #define PMU_IRQ 40 + #define I2C_SCL 41 + #define I2C_SDA 42 + + const int pin_btn_usr1 = 0; + + const int pin_cs = 10; + const int pin_reset = 5; + const int pin_sclk = 12; + const int pin_mosi = 11; + const int pin_miso = 13; + const int pin_tcxo_enable = -1; + const int pin_dio = 1; + const int pin_busy = 4; + + const int SD_MISO = 37; + const int SD_MOSI = 35; + const int SD_CLK = 36; + const int SD_CS = 47; + + const int IMU_CS = 34; + + #if HAS_NP == false + #if defined(EXTERNAL_LEDS) + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #else + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #endif + #endif + #endif + #elif MCU_VARIANT == MCU_NRF52 #if BOARD_MODEL == BOARD_TECHO #define VALIDATE_FIRMWARE false + #define HAS_INPUT true //#define GPS_BAUD_RATE 115200 //#define PIN_GPS_TX 41 //#define PIN_GPS_RX 40 @@ -639,17 +912,18 @@ #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED //#define HAS_EEPROM true //#define HAS_SD true - //#define HAS_DISPLAY true + #define HAS_DISPLAY true + #define DISPLAY EINK_BW + #define DISPLAY_MODEL GxEPD2_154_D67 //#define HAS_CONSOLE true //#define HAS_TXCO true - //#define DISPLAY EINK_BW //#define HAS_BLE true //#define HAS_PMU true #define CONFIG_UART_BUFFER_SIZE 40000 #define CONFIG_QUEUE_0_SIZE 6144 #define CONFIG_QUEUE_MAX_LENGTH 200 - #define BLE_MANUFACTURER "LilyGO" - #define BLE_MODEL "T-Echo" + //#define BLE_MANUFACTURER "LilyGO" + //#define BLE_MODEL "T-Echo" #define INTERFACE_COUNT 1 //#define I2C_SDA 26 //#define I2C_SCL 27 @@ -686,10 +960,17 @@ const int pin_disp_reset = 2; const int pin_disp_busy = 3; const int pin_disp_en = 43; + const int pin_disp_sck = 31; + const int pin_disp_mosi = 29; + const int pin_disp_miso = -1; + + #define HAS_BACKLIGHT true + const int pin_btn_usr1 = 42; + const int pin_backlight = 43; const int pin_led_rx = LED_BLUE; const int pin_led_tx = LED_RED; - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_OPENCOM_XL #define HAS_EEPROM false #define HAS_DISPLAY true #define DISPLAY EINK_BW @@ -699,16 +980,14 @@ #define HAS_PMU true #define HAS_NP false #define HAS_SD false - #define CONFIG_UART_BUFFER_SIZE 40000 #define CONFIG_QUEUE_0_SIZE 6144 - #define CONFIG_QUEUE_1_SIZE 20000 #define CONFIG_QUEUE_MAX_LENGTH 200 #define EEPROM_SIZE 296 #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #define BLE_MANUFACTURER "RAK Wireless" #define BLE_MODEL "RAK4640" - #define HAS_BUZZER true + #define HAS_BUZZER false #define PIN_BUZZER WB_IO2 // todo, I would much rather these be in Buzzer.h @@ -718,14 +997,15 @@ #define TX_HI_TONE 550 #define MAX_BUZZER_DELAY 100 - #define HAS_BUZZER_CTRL true + #define HAS_BUZZER_CTRL false - #define HAS_INPUT true + #define HAS_INPUT false #define PIN_BUTTON WB_SW1 #define INTERFACE_COUNT 2 #define CONFIG_QUEUE_1_SIZE 40000 + #define CONFIG_UART_BUFFER_SIZE 40000 // \todo, does it have to be this big? // first interface in list is the primary const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X}; @@ -778,6 +1058,7 @@ const int pin_disp_busy = WB_IO4; const int pin_disp_en = WB_IO2; + const int pin_btn_usr1 = 9; const int pin_led_rx = LED_BLUE; const int pin_led_tx = LED_GREEN; #else diff --git a/Config.h b/Config.h index bba27d4..45b1e7b 100644 --- a/Config.h +++ b/Config.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #define CONFIG_H #define MAJ_VERS 0x01 - #define MIN_VERS 0x4a + #define MIN_VERS 0x4b #define MODE_HOST 0x11 #define MODE_TNC 0x12 @@ -65,7 +65,6 @@ // packet RSSI register const int rssi_offset = 157; - // Default LoRa settings const int lora_rx_turnaround_ms = 66; const int lora_post_tx_yield_slots = 6; @@ -78,10 +77,10 @@ bool pmu_ready = false; bool promisc = false; bool implicit = false; + bool memory_low = false; uint8_t implicit_l = 0; - volatile bool packet_ready = false; - volatile uint8_t packet_interface = 0xFF; + uint8_t packet_interface = 0xFF; uint8_t op_mode = MODE_HOST; uint8_t model = 0x00; @@ -90,7 +89,7 @@ int last_rssi = -292; uint8_t last_rssi_raw = 0x00; uint8_t last_snr_raw = 0x80; - uint8_t seq = 0xFF; + uint8_t seq[INTERFACE_COUNT]; uint16_t read_len = 0; bool serial_in_frame = false; @@ -115,9 +114,10 @@ unsigned long last_rx = 0; // Power management + #define BATTERY_STATE_UNKNOWN 0x00 #define BATTERY_STATE_DISCHARGING 0x01 - #define BATTERY_STATE_CHARGING 0x02 - #define BATTERY_STATE_CHARGED 0x03 + #define BATTERY_STATE_CHARGING 0x02 + #define BATTERY_STATE_CHARGED 0x03 bool battery_installed = false; bool battery_indeterminate = false; bool external_power = false; @@ -127,6 +127,7 @@ uint8_t battery_state = 0x00; uint8_t display_intensity = 0xFF; uint8_t display_addr = 0xFF; + bool display_blanking_enabled = false; bool display_diagnostics = true; bool device_init_done = false; bool eeprom_ok = false; @@ -134,9 +135,9 @@ // Boot flags #define START_FROM_BOOTLOADER 0x01 - #define START_FROM_POWERON 0x02 - #define START_FROM_BROWNOUT 0x03 - #define START_FROM_JTAG 0x04 + #define START_FROM_POWERON 0x02 + #define START_FROM_BROWNOUT 0x03 + #define START_FROM_JTAG 0x04 // Subinterfaces // select interface 0 by default diff --git a/Console.h b/Console.h index 4321d9f..c59d348 100644 --- a/Console.h +++ b/Console.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/Console/Makefile b/Console/Makefile index 6fdfc65..15d06d2 100644 --- a/Console/Makefile +++ b/Console/Makefile @@ -21,7 +21,7 @@ pages-debug: sourcepack: @echo Packing firmware sources... - zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h ../Input.h ../LICENSE ../Makefile ../MD5.cpp ../MD5.h ../Modem.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../sx126x.cpp ../sx126x.h ../sx127x.cpp ../sx127x.h ../sx128x.cpp ../sx128x.h ../Utilities.h + zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../src/ble/BLESerial.cpp ../src/ble/BLESerial.h ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h .../Input.h ../Interfaces.h ../LICENSE ../Makefile ../src/misc/FIFOBuffer.c ../src/misc/FIFOBuffer.h ../src/misc/MD5.cpp ../src/misc/MD5.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../Radio.cpp ../Radio.hpp ../Utilities.h ../esp32_btbufs.py data: @echo Including assets... diff --git a/Console/build.py b/Console/build.py index 5d8a119..f61fc04 100644 --- a/Console/build.py +++ b/Console/build.py @@ -4,9 +4,9 @@ import sys import shutil packages = { - "rns": "rns-0.7.5-py3-none-any.whl", - "nomadnet": "nomadnet-0.4.9-py3-none-any.whl", - "lxmf": "lxmf-0.4.3-py3-none-any.whl", + "rns": "rns-0.8.2-py3-none-any.whl", + "nomadnet": "nomadnet-0.5.4-py3-none-any.whl", + "lxmf": "lxmf-0.5.5-py3-none-any.whl", "rnsh": "rnsh-0.1.4-py3-none-any.whl", } @@ -174,26 +174,34 @@ mf.write(help_redirect) mf.close() def optimise_manual(path): - pm = 110 + pm = 60 scale_imgs = [ ("_images/board_rnodev2.png", pm), ("_images/board_rnode.png", pm), - ("_images/board_heltec32.png", pm), + ("_images/board_heltec32v20.png", pm), + ("_images/board_heltec32v30.png", pm), ("_images/board_t3v21.png", pm), ("_images/board_t3v20.png", pm), - ("_images/sideband_devices.webp", pm), + ("_images/board_t3v10.png", pm), + ("_images/board_t3s3.png", pm), ("_images/board_tbeam.png", pm), + ("_images/board_tdeck.png", pm), + ("_images/board_rak4631.png", pm), + ("_images/board_tbeam_supreme.png", pm), + ("_images/sideband_devices.webp", pm), ("_images/nomadnet_3.png", pm), + ("_images/meshchat_1.webp", pm), ("_images/radio_is5ac.png", pm), ("_images/radio_rblhg5.png", pm), ("_static/rns_logo_512.png", 256), + ("../images/bg_h_1.webp", pm), ] import subprocess import shlex for i,s in scale_imgs: fp = path+"/"+i - resize = "convert "+fp+" -resize "+str(s)+" "+fp + resize = "convert "+fp+" -quality 25 -resize "+str(s)+" "+fp print(resize) subprocess.call(shlex.split(resize), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -205,6 +213,7 @@ def optimise_manual(path): "_static/scripts/furo.js.map", "_static/jquery-3.6.0.js", "_static/jquery.js", + "static/underscore-1.13.1.js", "_static/_sphinx_javascript_frameworks_compat.js", "_static/scripts/furo.js.LICENSE.txt", "_static/styles/furo-extensions.css.map", diff --git a/Device.h b/Device.h index 760ff40..54a7e6c 100644 --- a/Device.h +++ b/Device.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -296,7 +296,8 @@ bool device_init() { } #else // Skip hash comparison and checking BT - return true; + device_init_done = true; + return device_init_done; #endif } #endif diff --git a/Display.h b/Display.h index 3b20efe..c9f9b3f 100644 --- a/Display.h +++ b/Display.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -13,12 +13,29 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - #include #if DISPLAY == OLED #include #include +#define DISPLAY_BLACK SSD1306_BLACK +#define DISPLAY_WHITE SSD1306_WHITE + +#if BOARD_MODEL == BOARD_TDECK + #include + #define DISPLAY_BLACK ST77XX_BLACK + #define DISPLAY_WHITE ST77XX_WHITE +#elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #include + #define DISPLAY_BLACK ST77XX_BLACK + #define DISPLAY_WHITE ST77XX_WHITE +#else + #include + #include +#endif + +#include "Fonts/Org_01.h" + #define DISP_W 128 #define DISP_H 64 #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C @@ -29,6 +46,8 @@ void display_add_callback(void (*callback)()) { void busyCallback(const void* p) { display_callback(); } +#define DISPLAY_BLACK GxEPD_BLACK +#define DISPLAY_WHITE GxEPD_WHITE #endif #if DISPLAY == EINK_BW // use GxEPD2 because adafruit EPD support for partial refresh is bad @@ -75,10 +94,16 @@ void busyCallback(const void* p) { #define SCL_OLED 17 #define SDA_OLED 18 #endif -#elif BOARD_MODEL == BOARD_FREENODE +#elif BOARD_MODEL == BOARD_OPENCOM_XL #if DISPLAY == OLED + // RAK1921/SSD1306 + #define DISP_RST -1 + #define DISP_ADDR 0x3C + #define SCL_OLED 14 + #define SDA_OLED 13 // todo: add support for OLED board #elif DISPLAY == EINK_BW + // todo: change this to be defined in Boards.h in the future #define DISP_W 250 #define DISP_H 122 #define DISP_ADDR -1 @@ -89,53 +114,71 @@ void busyCallback(const void* p) { #define DISP_ADDR -1 #define DISPLAY_MODEL GxEPD2_213_Z98c #endif +#elif BOARD_MODEL == BOARD_TECHO + SPIClass displaySPI = SPIClass(NRF_SPIM0, pin_disp_miso, pin_disp_sck, pin_disp_mosi); + #define DISP_W 128 + #define DISP_H 64 + #define DISP_ADDR -1 +#elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #define DISP_RST -1 + #define DISP_ADDR 0x3C + #define SCL_OLED 18 + #define SDA_OLED 17 + #define DISP_CUSTOM_ADDR false #else #define DISP_RST -1 #define DISP_ADDR 0x3C #define DISP_CUSTOM_ADDR true #endif -#define UNSCALED_MAX 64 - #define SMALL_FONT &Org_01 #include "Graphics.h" -#if BOARD_MODEL != BOARD_FREENODE -// support for BOARD_FREENODE OLED not implemented yet -#if DISPLAY == OLED -Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); -float disp_target_fps = 7; -#define SCREENSAVER_TIME 500 // ms -uint32_t last_screensaver = 0; -#define SCREENSAVER_INTERVAL 600000 // 10 minutes in ms -bool screensaver_enabled = false; -#endif -#endif -#if BOARD_MODEL == BOARD_FREENODE -#if DISPLAY == EINK_BW +#if BOARD_MODEL == BOARD_OPENCOM_XL + #if DISPLAY == EINK_BW + GxEPD2_BW display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); + float disp_target_fps = 0.2; + uint32_t last_epd_refresh = 0; + #define REFRESH_PERIOD 300000 // 5 minutes in ms + #elif DISPLAY == EINK_3C + GxEPD2_3C display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); + float disp_target_fps = 0.05; // refresh usually takes longer on 3C, hence this is 4x the BW refresh period + uint32_t last_epd_refresh = 0; + #define REFRESH_PERIOD 600000 // 10 minutes in ms + #endif +#elif BOARD_MODEL == BOARD_TECHO GxEPD2_BW display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); float disp_target_fps = 0.2; uint32_t last_epd_refresh = 0; #define REFRESH_PERIOD 300000 // 5 minutes in ms -#elif DISPLAY == EINK_3C -GxEPD2_3C display(DISPLAY_MODEL(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy)); -float disp_target_fps = 0.05; // refresh usually takes longer on 3C, hence this is 4x the BW refresh period -uint32_t last_epd_refresh = 0; -#define REFRESH_PERIOD 600000 // 10 minutes in ms -#endif #else -// add more eink compatible boards here + #if DISPLAY == OLED + #if BOARD_MODEL == BOARD_TDECK + Adafruit_ST7789 display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1); + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Adafruit_SH1106G display = Adafruit_SH1106G(DISP_W, DISP_H, &Wire, -1); + #else + Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); + #endif + float disp_target_fps = 7; + #define SCREENSAVER_TIME 500 // ms + uint32_t last_screensaver = 0; + #define SCREENSAVER_INTERVAL 600000 // 10 minutes in ms + bool screensaver_enabled = false; + #endif #endif #define DISP_MODE_UNKNOWN 0x00 #define DISP_MODE_LANDSCAPE 0x01 #define DISP_MODE_PORTRAIT 0x02 #define DISP_PIN_SIZE 6 +#define DISPLAY_BLANKING_TIMEOUT 15*1000 uint8_t disp_mode = DISP_MODE_UNKNOWN; uint8_t disp_ext_fb = false; unsigned char fb[512]; uint32_t last_disp_update = 0; +bool display_tx = false; int disp_update_interval = 1000/disp_target_fps; uint32_t last_page_flip = 0; @@ -156,12 +199,12 @@ uint8_t online_interface_list[INTERFACE_COUNT] = {0}; uint8_t online_interfaces = 0; -#if DISPLAY == OLED +#if DISP_H == 64 #define WATERFALL_SIZE 46 -#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) +#elif DISP_H == 122 #define WATERFALL_SIZE 92 #else -// add more eink compatible boards here +#define WATERFALL_SIZE int(DISP_H * 0.75) // default to 75% of the display height #endif int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0}; @@ -172,12 +215,12 @@ int p_ad_y = 0; int p_as_x = 0; int p_as_y = 0; -#if DISPLAY == OLED -GFXcanvas1 stat_area(64, 64); -GFXcanvas1 disp_area(64, 64); -#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) +#if DISP_H == 122 GFXcanvas1 stat_area(DISP_H, DISP_W/2); GFXcanvas1 disp_area(DISP_H, DISP_W/2); +#else +GFXcanvas1 stat_area(64, 64); +GFXcanvas1 disp_area(64, 64); #endif void update_area_positions() { @@ -196,10 +239,40 @@ void update_area_positions() { uint8_t display_contrast = 0x00; #if DISPLAY == OLED -void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { +#if BOARD_MODEL == BOARD_TBEAM_S_V1 +void set_contrast(Adafruit_SH1106G *display, uint8_t value) { +} +#elif BOARD_MODEL == BOARD_TDECK +void set_contrast(Adafruit_ST7789 *display, uint8_t value) { +static uint8_t level = 0; +static uint8_t steps = 16; +if (value > 15) value = 15; +if (value == 0) { + digitalWrite(DISPLAY_BL_PIN, 0); + delay(3); + level = 0; + return; +} +if (level == 0) { + digitalWrite(DISPLAY_BL_PIN, 1); + level = steps; + delayMicroseconds(30); +} +int from = steps - level; +int to = steps - value; +int num = (steps + to - from) % steps; +for (int i = 0; i < num; i++) { + digitalWrite(DISPLAY_BL_PIN, 0); + digitalWrite(DISPLAY_BL_PIN, 1); +} +level = value; +} +#else + void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { display->ssd1306_command(SSD1306_SETCONTRAST); display->ssd1306_command(contrast); -} + } +#endif #endif bool display_init() { @@ -231,7 +304,19 @@ bool display_init() { delay(50); digitalWrite(pin_display_en, HIGH); Wire.begin(SDA_OLED, SCL_OLED); - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_TECHO + pinMode(pin_disp_en, INPUT_PULLUP); + digitalWrite(pin_disp_en, HIGH); + + display.init(0, true, 10, false, displaySPI, SPISettings(4000000, MSBFIRST, SPI_MODE0)); + display.setPartialWindow(0, 0, DISP_W, DISP_H); + + // Because refreshing this display can take some time, sometimes serial + // commands will be missed. Therefore, during periods where the device is + // waiting for the display to update, it will poll the serial buffer to + // check for any commands from the host. + display.epd2.setBusyCallback(busyCallback); + #elif BOARD_MODEL == BOARD_OPENCOM_XL #if DISPLAY == OLED #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C pinMode(pin_disp_en, INPUT_PULLUP); @@ -245,6 +330,8 @@ bool display_init() { // check for any commands from the host. display.epd2.setBusyCallback(busyCallback); #endif + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Wire.begin(SDA_OLED, SCL_OLED); #endif #if DISP_CUSTOM_ADDR == true @@ -258,12 +345,17 @@ bool display_init() { uint8_t display_address = DISP_ADDR; #endif - - #if DISPLAY == OLED - if(!display.begin(SSD1306_SWITCHCAPVCC, display_address)) { - #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C + #if DISPLAY == EINK_BW || DISPLAY == EINK_3C // don't check if display is actually connected if(false) { + #elif BOARD_MODEL == BOARD_TDECK + display.init(240, 320); + display.setSPISpeed(80e6); + if (false) { + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + if (!display.begin(display_address, true)) { + #else + if (!display.begin(SSD1306_SWITCHCAPVCC, display_address)) { #endif return false; } else { @@ -288,20 +380,29 @@ bool display_init() { #elif BOARD_MODEL == BOARD_TBEAM disp_mode = DISP_MODE_LANDSCAPE; display.setRotation(0); + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(1); #elif BOARD_MODEL == BOARD_HELTEC32_V2 disp_mode = DISP_MODE_PORTRAIT; display.setRotation(1); - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_OPENCOM_XL #if DISPLAY == OLED #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C disp_mode = DISP_MODE_PORTRAIT; #endif + #elif BOARD_MODEL == BOARD_TECHO + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(3); #elif BOARD_MODEL == BOARD_HELTEC32_V3 disp_mode = DISP_MODE_PORTRAIT; - // Antenna conx up display.setRotation(1); - // USB-C up - // display.setRotation(3); + #elif BOARD_MODEL == BOARD_RAK4631 + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(0); + #elif BOARD_MODEL == BOARD_TDECK + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); #else disp_mode = DISP_MODE_PORTRAIT; display.setRotation(3); @@ -315,10 +416,14 @@ bool display_init() { disp_area.cp437(true); display.cp437(true); - #if HAS_EEPROM - display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); - #elif MCU_VARIANT == MCU_NRF52 - display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); + #if MCU_VARIANT != MCU_NRF52 + display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); + #else + display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); + #endif + + #if BOARD_MODEL == BOARD_TDECK + display.fillScreen(DISPLAY_BLACK); #endif return true; @@ -330,50 +435,50 @@ bool display_init() { void draw_cable_icon(int px, int py) { if (cable_state == CABLE_STATE_DISCONNECTED) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_cable+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_cable+0*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else if (cable_state == CABLE_STATE_CONNECTED) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_cable+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_cable+1*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } void draw_bt_icon(int px, int py) { if (bt_state == BT_STATE_OFF) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_bt+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_bt+0*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else if (bt_state == BT_STATE_ON) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_bt+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_bt+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_bt+1*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_bt+1*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else if (bt_state == BT_STATE_PAIRING) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_bt+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_bt+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_bt+2*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_bt+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else if (bt_state == BT_STATE_CONNECTED) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_bt+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_bt+3*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_bt+3*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_bt+3*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_bt+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_bt+0*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } @@ -381,60 +486,60 @@ void draw_bt_icon(int px, int py) { void draw_lora_icon(RadioInterface* radio, int px, int py) { // todo: make display show other interfaces if (radio_online) { - #if DISPLAY == OLED - if (online_interface_list[interface_page] != radio->getIndex()) { - stat_area.drawBitmap(px - 1, py-1, bm_dot_sqr, 18, 19, SSD1306_WHITE, SSD1306_BLACK); + #if DISP_H == 122 + if (online_interface_list[interface_page] != radio->getIndex()) { + stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 34, 36, DISPLAY_WHITE, DISPLAY_BLACK); - // redraw stat area on next refresh - stat_area_initialised = false; - } - if (radio->getRadioOnline()) { - stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - } else { - stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - } - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - if (online_interface_list[interface_page] != radio->getIndex()) { - stat_area.drawBitmap(px - 2, py - 2, bm_dot_sqr, 34, 36, GxEPD_WHITE, GxEPD_BLACK); + // redraw stat area on next refresh + stat_area_initialised = false; + } + if (radio->getRadioOnline()) { + stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + } else { + stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + } + #else + if (online_interface_list[interface_page] != radio->getIndex()) { + stat_area.drawBitmap(px - 1, py - 1, bm_dot_sqr, 18, 19, DISPLAY_WHITE, DISPLAY_BLACK); - // redraw stat area on next refresh - stat_area_initialised = false; - } - if (radio->getRadioOnline()) { - stat_area.drawBitmap(px, py, bm_rf+1*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); - } else { - stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); - } - #endif - } else { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); - #endif - } + // redraw stat area on next refresh + stat_area_initialised = false; + } + if (radio->getRadioOnline()) { + stat_area.drawBitmap(px, py, bm_rf+1*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + } else { + stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + } + #endif + } else { + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_rf+0*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #endif + } } void draw_mw_icon(int px, int py) { if (INTERFACE_COUNT >= 2) { if (interface_obj[1]->getRadioOnline()) { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_rf+3*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_rf+3*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } else { - #if DISPLAY == OLED - stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(px, py, bm_rf+2*128, 30, 32, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } @@ -444,79 +549,87 @@ void draw_battery_bars(int px, int py) { if (pmu_ready) { if (battery_ready) { if (battery_installed) { - float battery_value = battery_percent; + float battery_value = battery_percent; + + // Disable charging state display for now, since + // boards without dedicated PMU are completely + // unreliable for determining actual charging state. + bool disable_charge_status = false; + if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING) { + disable_charge_status = true; + } - if (battery_state == BATTERY_STATE_CHARGING) { + if (battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { battery_value = charge_tick; charge_tick += 3; if (charge_tick > 100) charge_tick = 0; } - if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING) { - #if DISPLAY == OLED - stat_area.fillRect(px-2, py-2, 18, 7, SSD1306_BLACK); - stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px-2, py-2, 24, 9, GxEPD_BLACK); - stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, GxEPD_WHITE, GxEPD_BLACK); + if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { + #if DISP_H == 122 + stat_area.fillRect(px-2, py-2, 24, 9, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.fillRect(px-2, py-2, 18, 7, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { if (battery_state == BATTERY_STATE_CHARGED) { - #if DISPLAY == OLED - stat_area.fillRect(px-2, py-2, 18, 7, SSD1306_BLACK); - stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px-2, py-2, 24, 9, GxEPD_BLACK); - stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.fillRect(px-2, py-2, 24, 9, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.fillRect(px-2, py-2, 18, 7, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - stat_area.fillRect(px, py, 14, 3, SSD1306_BLACK); - stat_area.fillRect(px-2, py-2, 18, 7, SSD1306_BLACK); - stat_area.drawRect(px-2, py-2, 17, 7, SSD1306_WHITE); - stat_area.drawLine(px+15, py, px+15, py+3, SSD1306_WHITE); - if (battery_value > 7) stat_area.drawLine(px, py, px, py+2, SSD1306_WHITE); - if (battery_value > 20) stat_area.drawLine(px+1*2, py, px+1*2, py+2, SSD1306_WHITE); - if (battery_value > 33) stat_area.drawLine(px+2*2, py, px+2*2, py+2, SSD1306_WHITE); - if (battery_value > 46) stat_area.drawLine(px+3*2, py, px+3*2, py+2, SSD1306_WHITE); - if (battery_value > 59) stat_area.drawLine(px+4*2, py, px+4*2, py+2, SSD1306_WHITE); - if (battery_value > 72) stat_area.drawLine(px+5*2, py, px+5*2, py+2, SSD1306_WHITE); - if (battery_value > 85) stat_area.drawLine(px+6*2, py, px+6*2, py+2, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px, py, 20, 5, GxEPD_BLACK); - stat_area.fillRect(px-2, py-4, 34, 19, GxEPD_BLACK); - stat_area.drawRect(px-2, py-2, 23, 9, GxEPD_WHITE); - stat_area.drawLine(px+21, py, px+21, py+5, GxEPD_WHITE); - if (battery_value > 0) stat_area.drawLine(px, py, px, py+4, GxEPD_WHITE); - if (battery_value >= 10) stat_area.drawLine(px+1*2, py, px+1*2, py+4, GxEPD_WHITE); - if (battery_value >= 20) stat_area.drawLine(px+2*2, py, px+2*2, py+4, GxEPD_WHITE); - if (battery_value >= 30) stat_area.drawLine(px+3*2, py, px+3*2, py+4, GxEPD_WHITE); - if (battery_value >= 40) stat_area.drawLine(px+4*2, py, px+4*2, py+4, GxEPD_WHITE); - if (battery_value >= 50) stat_area.drawLine(px+5*2, py, px+5*2, py+4, GxEPD_WHITE); - if (battery_value >= 60) stat_area.drawLine(px+6*2, py, px+6*2, py+4, GxEPD_WHITE); - if (battery_value >= 70) stat_area.drawLine(px+7*2, py, px+7*2, py+4, GxEPD_WHITE); - if (battery_value >= 80) stat_area.drawLine(px+8*2, py, px+8*2, py+4, GxEPD_WHITE); - if (battery_value >= 90) stat_area.drawLine(px+9*2, py, px+9*2, py+4, GxEPD_WHITE); + #if DISP_H == 122 + stat_area.fillRect(px, py, 20, 5, DISPLAY_BLACK); + stat_area.fillRect(px-2, py-4, 34, 19, DISPLAY_BLACK); + stat_area.drawRect(px-2, py-2, 23, 9, DISPLAY_WHITE); + stat_area.drawLine(px+21, py, px+21, py+5, DISPLAY_WHITE); + if (battery_value > 0) stat_area.drawLine(px, py, px, py+4, DISPLAY_WHITE); + if (battery_value >= 10) stat_area.drawLine(px+1*2, py, px+1*2, py+4, DISPLAY_WHITE); + if (battery_value >= 20) stat_area.drawLine(px+2*2, py, px+2*2, py+4, DISPLAY_WHITE); + if (battery_value >= 30) stat_area.drawLine(px+3*2, py, px+3*2, py+4, DISPLAY_WHITE); + if (battery_value >= 40) stat_area.drawLine(px+4*2, py, px+4*2, py+4, DISPLAY_WHITE); + if (battery_value >= 50) stat_area.drawLine(px+5*2, py, px+5*2, py+4, DISPLAY_WHITE); + if (battery_value >= 60) stat_area.drawLine(px+6*2, py, px+6*2, py+4, DISPLAY_WHITE); + if (battery_value >= 70) stat_area.drawLine(px+7*2, py, px+7*2, py+4, DISPLAY_WHITE); + if (battery_value >= 80) stat_area.drawLine(px+8*2, py, px+8*2, py+4, DISPLAY_WHITE); + if (battery_value >= 90) stat_area.drawLine(px+9*2, py, px+9*2, py+4, DISPLAY_WHITE); + #else + stat_area.fillRect(px, py, 14, 3, DISPLAY_BLACK); + stat_area.fillRect(px-2, py-2, 18, 7, DISPLAY_BLACK); + stat_area.drawRect(px-2, py-2, 17, 7, DISPLAY_WHITE); + stat_area.drawLine(px+15, py, px+15, py+3, DISPLAY_WHITE); + if (battery_value > 7) stat_area.drawLine(px, py, px, py+2, DISPLAY_WHITE); + if (battery_value > 20) stat_area.drawLine(px+1*2, py, px+1*2, py+2, DISPLAY_WHITE); + if (battery_value > 33) stat_area.drawLine(px+2*2, py, px+2*2, py+2, DISPLAY_WHITE); + if (battery_value > 46) stat_area.drawLine(px+3*2, py, px+3*2, py+2, DISPLAY_WHITE); + if (battery_value > 59) stat_area.drawLine(px+4*2, py, px+4*2, py+2, DISPLAY_WHITE); + if (battery_value > 72) stat_area.drawLine(px+5*2, py, px+5*2, py+2, DISPLAY_WHITE); + if (battery_value > 85) stat_area.drawLine(px+6*2, py, px+6*2, py+2, DISPLAY_WHITE); #endif } } } else { - #if DISPLAY == OLED - stat_area.fillRect(px-2, py-2, 18, 7, SSD1306_BLACK); - stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px-2, py-2, 24, 9, GxEPD_BLACK); - stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.fillRect(px-2, py-2, 24, 9, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.fillRect(px-2, py-2, 18, 7, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } } else { - #if DISPLAY == OLED - stat_area.fillRect(px-2, py-2, 18, 7, SSD1306_BLACK); - stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px-2, py-2, 24, 9, GxEPD_BLACK); - stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.fillRect(px-2, py-2, 24, 9, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.fillRect(px-2, py-2, 18, 7, DISPLAY_BLACK); + stat_area.drawBitmap(px-2, py-2, bm_plug, 17, 7, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } @@ -524,145 +637,154 @@ void draw_battery_bars(int px, int py) { #define Q_SNR_STEP 2.0 #define Q_SNR_MIN_BASE -9.0 #define Q_SNR_MAX 6.0 -void draw_quality_bars(int px, int py) { - signed char t_snr = (signed int)last_snr_raw; - int snr_int = (int)t_snr; - float snr_min = Q_SNR_MIN_BASE-(int)interface_obj[interface_page]->getSpreadingFactor()*Q_SNR_STEP; - float snr_span = (Q_SNR_MAX-snr_min); - float snr = ((int)snr_int) * 0.25; - float quality = ((snr-snr_min)/(snr_span))*100; - if (quality > 100.0) quality = 100.0; - if (quality < 0.0) quality = 0.0; - #if DISPLAY == OLED - stat_area.fillRect(px, py, 13, 7, SSD1306_BLACK); - if (quality > 0) stat_area.drawLine(px+0*2, py+7, px+0*2, py+6, SSD1306_WHITE); - if (quality > 15) stat_area.drawLine(px+1*2, py+7, px+1*2, py+5, SSD1306_WHITE); - if (quality > 30) stat_area.drawLine(px+2*2, py+7, px+2*2, py+4, SSD1306_WHITE); - if (quality > 45) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, SSD1306_WHITE); - if (quality > 60) stat_area.drawLine(px+4*2, py+7, px+4*2, py+2, SSD1306_WHITE); - if (quality > 75) stat_area.drawLine(px+5*2, py+7, px+5*2, py+1, SSD1306_WHITE); - if (quality > 90) stat_area.drawLine(px+6*2, py+7, px+6*2, py+0, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px, py, 26, 14, GxEPD_BLACK); - if (quality > 0) { - stat_area.drawLine(px+0*4, py+14, px+0*4, py+6, GxEPD_WHITE); - stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+6, GxEPD_WHITE); - } - if (quality > 15) { - stat_area.drawLine(px+1*4, py+14, px+1*4, py+5, GxEPD_WHITE); - stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+5, GxEPD_WHITE); - } - if (quality > 30) { - stat_area.drawLine(px+2*4, py+14, px+2*4, py+4, GxEPD_WHITE); - stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+4, GxEPD_WHITE); - } - if (quality > 45) { - stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, GxEPD_WHITE); - stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, GxEPD_WHITE); - } - if (quality > 60) { - stat_area.drawLine(px+4*4, py+14, px+4*4, py+2, GxEPD_WHITE); - stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+2, GxEPD_WHITE); - } - if (quality > 75) { - stat_area.drawLine(px+5*4, py+14, px+5*4, py+1, GxEPD_WHITE); - stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+1, GxEPD_WHITE); - } - if (quality > 90) { - stat_area.drawLine(px+6*4, py+14, px+6*4, py+0, GxEPD_WHITE); - stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+0, GxEPD_WHITE); - } - #endif - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); +void draw_quality_bars(int px, int py) { + signed char t_snr = (signed int)last_snr_raw; + int snr_int = (int)t_snr; + float snr_min = Q_SNR_MIN_BASE-(int)interface_obj[interface_page]->getSpreadingFactor()*Q_SNR_STEP; + float snr_span = (Q_SNR_MAX-snr_min); + float snr = ((int)snr_int) * 0.25; + float quality = ((snr-snr_min)/(snr_span))*100; + if (quality > 100.0) quality = 100.0; + if (quality < 0.0) quality = 0.0; + +#if DISP_H == 122 + stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); + if (quality > 0) { + stat_area.drawLine(px+0*4, py+14, px+0*4, py+6, DISPLAY_WHITE); + stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+6, DISPLAY_WHITE); + } + if (quality > 15) { + stat_area.drawLine(px+1*4, py+14, px+1*4, py+5, DISPLAY_WHITE); + stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+5, DISPLAY_WHITE); + } + if (quality > 30) { + stat_area.drawLine(px+2*4, py+14, px+2*4, py+4, DISPLAY_WHITE); + stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+4, DISPLAY_WHITE); + } + if (quality > 45) { + stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); + stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); + } + if (quality > 60) { + stat_area.drawLine(px+4*4, py+14, px+4*4, py+2, DISPLAY_WHITE); + stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+2, DISPLAY_WHITE); + } + if (quality > 75) { + stat_area.drawLine(px+5*4, py+14, px+5*4, py+1, DISPLAY_WHITE); + stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+1, DISPLAY_WHITE); + } + if (quality > 90) { + stat_area.drawLine(px+6*4, py+14, px+6*4, py+0, DISPLAY_WHITE); + stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+0, DISPLAY_WHITE); + } +#else + stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); + if (quality > 0) stat_area.drawLine(px+0*2, py+7, px+0*2, py+6, DISPLAY_WHITE); + if (quality > 15) stat_area.drawLine(px+1*2, py+7, px+1*2, py+5, DISPLAY_WHITE); + if (quality > 30) stat_area.drawLine(px+2*2, py+7, px+2*2, py+4, DISPLAY_WHITE); + if (quality > 45) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); + if (quality > 60) stat_area.drawLine(px+4*2, py+7, px+4*2, py+2, DISPLAY_WHITE); + if (quality > 75) stat_area.drawLine(px+5*2, py+7, px+5*2, py+1, DISPLAY_WHITE); + if (quality > 90) stat_area.drawLine(px+6*2, py+7, px+6*2, py+0, DISPLAY_WHITE); +#endif + // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); } #define S_RSSI_MIN -135.0 #define S_RSSI_MAX -75.0 #define S_RSSI_SPAN (S_RSSI_MAX-S_RSSI_MIN) void draw_signal_bars(int px, int py) { - int rssi_val = last_rssi; - if (rssi_val < S_RSSI_MIN) rssi_val = S_RSSI_MIN; - if (rssi_val > S_RSSI_MAX) rssi_val = S_RSSI_MAX; - int signal = ((rssi_val - S_RSSI_MIN)*(1.0/S_RSSI_SPAN))*100.0; + int rssi_val = last_rssi; + if (rssi_val < S_RSSI_MIN) rssi_val = S_RSSI_MIN; + if (rssi_val > S_RSSI_MAX) rssi_val = S_RSSI_MAX; + int signal = ((rssi_val - S_RSSI_MIN)*(1.0/S_RSSI_SPAN))*100.0; - if (signal > 100.0) signal = 100.0; - if (signal < 0.0) signal = 0.0; + if (signal > 100.0) signal = 100.0; + if (signal < 0.0) signal = 0.0; - #if DISPLAY == OLED - stat_area.fillRect(px, py, 13, 7, SSD1306_BLACK); - if (signal > 85) stat_area.drawLine(px+0*2, py+7, px+0*2, py+0, SSD1306_WHITE); - if (signal > 72) stat_area.drawLine(px+1*2, py+7, px+1*2, py+1, SSD1306_WHITE); - if (signal > 59) stat_area.drawLine(px+2*2, py+7, px+2*2, py+2, SSD1306_WHITE); - if (signal > 46) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, SSD1306_WHITE); - if (signal > 33) stat_area.drawLine(px+4*2, py+7, px+4*2, py+4, SSD1306_WHITE); - if (signal > 20) stat_area.drawLine(px+5*2, py+7, px+5*2, py+5, SSD1306_WHITE); - if (signal > 7) stat_area.drawLine(px+6*2, py+7, px+6*2, py+6, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px, py, 26, 14, GxEPD_BLACK); - if (signal > 85) { - stat_area.drawLine(px+0*4, py+14, px+0*4, py+0, GxEPD_WHITE); - stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+0, GxEPD_WHITE); - } - if (signal > 72) { - stat_area.drawLine(px+1*4, py+14, px+1*4, py+1, GxEPD_WHITE); - stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+1, GxEPD_WHITE); - } - if (signal > 59) { - stat_area.drawLine(px+2*4, py+14, px+2*4, py+2, GxEPD_WHITE); - stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+2, GxEPD_WHITE); - } - if (signal > 46) { - stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, GxEPD_WHITE); - stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, GxEPD_WHITE); - } - if (signal > 33) { - stat_area.drawLine(px+4*4, py+14, px+4*4, py+4, GxEPD_WHITE); - stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+4, GxEPD_WHITE); - } - if (signal > 20) { - stat_area.drawLine(px+5*4, py+14, px+5*4, py+5, GxEPD_WHITE); - stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+5, GxEPD_WHITE); - } - if (signal > 7) { - stat_area.drawLine(px+6*4, py+14, px+6*4, py+6, GxEPD_WHITE); - stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+6, GxEPD_WHITE); - } - #endif - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); +#if DISP_H == 122 + stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); + if (signal > 85) { + stat_area.drawLine(px+0*4, py+14, px+0*4, py+0, DISPLAY_WHITE); + stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+0, DISPLAY_WHITE); + } + if (signal > 72) { + stat_area.drawLine(px+1*4, py+14, px+1*4, py+1, DISPLAY_WHITE); + stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+1, DISPLAY_WHITE); + } + if (signal > 59) { + stat_area.drawLine(px+2*4, py+14, px+2*4, py+2, DISPLAY_WHITE); + stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+2, DISPLAY_WHITE); + } + if (signal > 46) { + stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); + stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); + } + if (signal > 33) { + stat_area.drawLine(px+4*4, py+14, px+4*4, py+4, DISPLAY_WHITE); + stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+4, DISPLAY_WHITE); + } + if (signal > 20) { + stat_area.drawLine(px+5*4, py+14, px+5*4, py+5, DISPLAY_WHITE); + stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+5, DISPLAY_WHITE); + } + if (signal > 7) { + stat_area.drawLine(px+6*4, py+14, px+6*4, py+6, DISPLAY_WHITE); + stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+6, DISPLAY_WHITE); + } +#else + stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); + if (signal > 85) stat_area.drawLine(px+0*2, py+7, px+0*2, py+0, DISPLAY_WHITE); + if (signal > 72) stat_area.drawLine(px+1*2, py+7, px+1*2, py+1, DISPLAY_WHITE); + if (signal > 59) stat_area.drawLine(px+2*2, py+7, px+2*2, py+2, DISPLAY_WHITE); + if (signal > 46) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); + if (signal > 33) stat_area.drawLine(px+4*2, py+7, px+4*2, py+4, DISPLAY_WHITE); + if (signal > 20) stat_area.drawLine(px+5*2, py+7, px+5*2, py+5, DISPLAY_WHITE); + if (signal > 7) stat_area.drawLine(px+6*2, py+7, px+6*2, py+6, DISPLAY_WHITE); +#endif + // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); } +#define WF_TX_SIZE 5 +#define WF_TX_WIDTH 5 #define WF_RSSI_MAX -60 #define WF_RSSI_MIN -135 -#define WF_RSSI_SPAN (WF_RSSI_MAX-WF_RSSI_MIN) -#if DISPLAY == OLED -#define WF_PIXEL_WIDTH 10 -#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) +#define WF_RSSI_SPAN (WF_RSSI_MAX - WF_RSSI_MIN) +#if DISP_H == 122 #define WF_PIXEL_WIDTH 22 +#elif disp_mode == DISP_MODE_LANDSCAPE +#define WF_PIXEL_WIDTH (DISP_H / WF_RSSI_SPAN) +#else +#define WF_PIXEL_WIDTH (DISP_W / WF_RSSI_SPAN) #endif void draw_waterfall(int px, int py) { int rssi_val = interface_obj[interface_page]->currentRssi(); if (rssi_val < WF_RSSI_MIN) rssi_val = WF_RSSI_MIN; if (rssi_val > WF_RSSI_MAX) rssi_val = WF_RSSI_MAX; int rssi_normalised = ((rssi_val - WF_RSSI_MIN)*(1.0/WF_RSSI_SPAN))*WF_PIXEL_WIDTH; + if (display_tx) { + for (uint8_t i; i < WF_TX_SIZE; i++) { + waterfall[interface_page][waterfall_head[interface_page]++] = -1; + if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; + } + display_tx = false; + } else { + waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; + if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; + } - waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; - if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; - - #if DISPLAY == OLED - stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, GxEPD_BLACK); - #endif + stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, DISPLAY_BLACK); for (int i = 0; i < WATERFALL_SIZE; i++){ int wi = (waterfall_head[interface_page]+i)%WATERFALL_SIZE; int ws = waterfall[interface_page][wi]; if (ws > 0) { - #if DISPLAY == OLED - stat_area.drawLine(px, py+i, px+ws-1, py+i, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawLine(px, py+i, px+ws-1, py+i, GxEPD_WHITE); - #endif + stat_area.drawLine(px, py+i, px+ws-1, py+i, DISPLAY_WHITE); + } else if (ws == -1) { + uint8_t o = i%2; + for (uint8_t ti = 0; ti < WF_PIXEL_WIDTH/2; ti++) { + stat_area.drawPixel(px+ti*2+o, py+i, DISPLAY_WHITE); + } } } } @@ -670,10 +792,10 @@ void draw_waterfall(int px, int py) { void draw_stat_area() { if (device_init_done) { if (!stat_area_initialised) { - #if DISPLAY == OLED - stat_area.drawBitmap(0, 0, bm_frame, 64, 64, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - stat_area.drawBitmap(0, 0, bm_frame, stat_area.width(), stat_area.height(), GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + stat_area.drawBitmap(0, 0, bm_frame, stat_area.width(), stat_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); + #else + stat_area.drawBitmap(0, 0, bm_frame, 64, 64, DISPLAY_WHITE, DISPLAY_BLACK); #endif stat_area_initialised = true; } @@ -713,17 +835,7 @@ void draw_stat_area() { last_interface_page_flip = millis(); } - #if DISPLAY == OLED - draw_cable_icon(3, 8); - draw_bt_icon(3, 30); - draw_lora_icon(interface_obj[0], 45, 8); - - // todo, expand support to show more than two interfaces on screen - if (INTERFACE_COUNT > 1) { - draw_lora_icon(interface_obj[1], 45, 30); - } - draw_battery_bars(4, 58); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + #if DISP_H == 122 draw_cable_icon(6, 18); draw_bt_icon(6, 60); draw_lora_icon(interface_obj[0], 86, 18); @@ -733,6 +845,16 @@ void draw_stat_area() { draw_lora_icon(interface_obj[1], 86, 60); } draw_battery_bars(8, 113); + #else + draw_cable_icon(3, 8); + draw_bt_icon(3, 30); + draw_lora_icon(interface_obj[0], 45, 8); + + // todo, expand support to show more than two interfaces on screen + if (INTERFACE_COUNT > 1) { + draw_lora_icon(interface_obj[1], 45, 30); + } + draw_battery_bars(4, 58); #endif radio_online = false; for (int i = 0; i < INTERFACE_COUNT; i++) { @@ -742,14 +864,14 @@ void draw_stat_area() { } } if (radio_online) { - #if DISPLAY == OLED - draw_quality_bars(28, 56); - draw_signal_bars(44, 56); - draw_waterfall(27, 4); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + #if DISP_H == 122 draw_quality_bars(53, 109); draw_signal_bars(83, 109); draw_waterfall(50, 8); + #else + draw_quality_bars(28, 56); + draw_signal_bars(44, 56); + draw_waterfall(27, 4); #endif } } @@ -759,40 +881,19 @@ void update_stat_area() { if (eeprom_ok && !firmware_update_mode && !console_active) { draw_stat_area(); if (disp_mode == DISP_MODE_PORTRAIT) { - #if DISPLAY == OLED - display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), GxEPD_WHITE, GxEPD_BLACK); - #endif + display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); } else if (disp_mode == DISP_MODE_LANDSCAPE) { - #if DISPLAY == OLED - display.drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK); - if (device_init_done && !disp_ext_fb) display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), GxEPD_WHITE, GxEPD_BLACK); - if (device_init_done && !disp_ext_fb) display.drawLine(p_as_x, 0, p_as_x, DISP_W/2, GxEPD_WHITE); - #endif + display.drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); + if (device_init_done && !disp_ext_fb) display.drawLine(p_as_x, 0, p_as_x, DISP_W/2, DISPLAY_WHITE); } } else { if (firmware_update_mode) { - #if DISPLAY == OLED - display.drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), GxEPD_BLACK, GxEPD_WHITE); - #endif + display.drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), DISPLAY_BLACK, DISPLAY_WHITE); } else if (console_active && device_init_done) { - #if DISPLAY == OLED - display.drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), GxEPD_BLACK, GxEPD_WHITE); - #endif + display.drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), DISPLAY_BLACK, DISPLAY_WHITE); if (disp_mode == DISP_MODE_LANDSCAPE) { - #if DISPLAY == OLED - display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawLine(p_as_x, 0, p_as_x, DISP_W/2, GxEPD_WHITE); - #endif + display.drawLine(p_as_x, 0, p_as_x, DISP_W/2, DISPLAY_WHITE); } } } @@ -803,82 +904,22 @@ void draw_disp_area() { uint8_t p_by = 37; if (disp_mode == DISP_MODE_LANDSCAPE || firmware_update_mode) { p_by = 18; - #if DISPLAY == OLED - disp_area.fillRect(0, 0, disp_area.width(), disp_area.height(), SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.fillRect(0, 0, disp_area.width(), disp_area.height(), GxEPD_BLACK); - #endif + disp_area.fillRect(0, 0, disp_area.width(), disp_area.height(), DISPLAY_BLACK); } - #if DISPLAY == OLED - if (!device_init_done) disp_area.drawBitmap(0, p_by, bm_boot, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - if (firmware_update_mode) disp_area.drawBitmap(0, p_by, bm_fw_update, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - if (!device_init_done) disp_area.drawBitmap(0, p_by, bm_boot, disp_area.width(), 54, GxEPD_WHITE); - if (firmware_update_mode) disp_area.drawBitmap(0, p_by, bm_fw_update, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + if (!device_init_done) disp_area.drawBitmap(0, p_by, bm_boot, disp_area.width(), 54, DISPLAY_WHITE); + if (firmware_update_mode) disp_area.drawBitmap(0, p_by, bm_fw_update, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + if (!device_init_done) disp_area.drawBitmap(0, p_by, bm_boot, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + if (firmware_update_mode) disp_area.drawBitmap(0, p_by, bm_fw_update, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { if (!disp_ext_fb or bt_ssp_pin != 0) { if (radio_online && display_diagnostics) { - #if DISPLAY == OLED + #if DISP_H == 122 selected_radio = interface_obj[online_interface_list[interface_page]]; - disp_area.fillRect(0,8,disp_area.width(),37, SSD1306_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, SSD1306_WHITE); - disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(SSD1306_WHITE); - - disp_area.setCursor(2, 13); - disp_area.print("On"); - disp_area.setCursor(14, 13); - disp_area.print("@"); - disp_area.setCursor(21, 13); - disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0); - - disp_area.setCursor(2, 23-1); - disp_area.print("Airtime:"); - - disp_area.setCursor(11, 33-1); - if (selected_radio->getTotalChannelUtil() < 0.099) { - disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); - } else { - disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0); - } - - disp_area.drawBitmap(2, 26-1, bm_hg_low, 5, 9, SSD1306_WHITE, SSD1306_BLACK); - - disp_area.setCursor(32+11, 33-1); - - if (selected_radio->getLongtermChannelUtil() < 0.099) { - disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); - } else { - disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0); - } - disp_area.drawBitmap(32+2, 26-1, bm_hg_high, 5, 9, SSD1306_WHITE, SSD1306_BLACK); - - disp_area.setTextColor(SSD1306_BLACK); - - disp_area.setCursor(2, 46); - disp_area.print("Channel"); - disp_area.setCursor(38, 46); - disp_area.print("Load:"); - - disp_area.setCursor(11, 57); - if (selected_radio->getTotalChannelUtil() < 0.099) { - disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); - } else { - disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0); - } - disp_area.drawBitmap(2, 50, bm_hg_low, 5, 9, SSD1306_BLACK, SSD1306_WHITE); - - disp_area.setCursor(32+11, 57); - if (selected_radio->getLongtermChannelUtil() < 0.099) { - disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); - } else { - disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); - } - disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, SSD1306_BLACK, SSD1306_WHITE); - - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - selected_radio = interface_obj[online_interface_list[interface_page]]; - disp_area.fillRect(0,12,disp_area.width(),57, GxEPD_BLACK); disp_area.fillRect(0,69,disp_area.width(),56, GxEPD_WHITE); - disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(GxEPD_WHITE); + disp_area.fillRect(0,12,disp_area.width(),57, DISPLAY_BLACK); disp_area.fillRect(0,69,disp_area.width(),56, DISPLAY_WHITE); + disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(DISPLAY_WHITE); disp_area.setTextSize(2); // scale text 2x disp_area.setCursor(2, 22); @@ -898,7 +939,7 @@ void draw_disp_area() { disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0); } - disp_area.drawBitmap(2, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK); + disp_area.drawBitmap(2, 41, bm_hg_low, 10, 18, DISPLAY_WHITE, DISPLAY_BLACK); disp_area.setCursor(64+17, 53); if (selected_radio->getLongtermChannelUtil() < 0.099) { @@ -906,9 +947,9 @@ void draw_disp_area() { } else { disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0); } - disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK); + disp_area.drawBitmap(64, 41, bm_hg_high, 10, 18, DISPLAY_WHITE, DISPLAY_BLACK); - disp_area.setTextColor(GxEPD_BLACK); + disp_area.setTextColor(DISPLAY_BLACK); disp_area.setCursor(2, 88); disp_area.print("Channel"); @@ -921,7 +962,7 @@ void draw_disp_area() { } else { disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0); } - disp_area.drawBitmap(2, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE); + disp_area.drawBitmap(2, 98, bm_hg_low, 10, 18, DISPLAY_BLACK, DISPLAY_WHITE); disp_area.setCursor(64+17, 110); if (selected_radio->getLongtermChannelUtil() < 0.099) { @@ -929,44 +970,99 @@ void draw_disp_area() { } else { disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); } - disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE); + disp_area.drawBitmap(64, 98, bm_hg_high, 10, 18, DISPLAY_BLACK, DISPLAY_WHITE); + #else + selected_radio = interface_obj[online_interface_list[interface_page]]; + disp_area.fillRect(0,8,disp_area.width(),37, DISPLAY_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, DISPLAY_WHITE); + disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(DISPLAY_WHITE); + + disp_area.setCursor(2, 13); + disp_area.print("On"); + disp_area.setCursor(14, 13); + disp_area.print("@"); + disp_area.setCursor(21, 13); + disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0); + + disp_area.setCursor(2, 23-1); + disp_area.print("Airtime:"); + + disp_area.setCursor(11, 33-1); + if (selected_radio->getTotalChannelUtil() < 0.099) { + disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); + } else { + disp_area.printf("%.0f%%", selected_radio->getAirtime()*100.0); + } + + disp_area.drawBitmap(2, 26-1, bm_hg_low, 5, 9, DISPLAY_WHITE, DISPLAY_BLACK); + + disp_area.setCursor(32+11, 33-1); + + if (selected_radio->getLongtermChannelUtil() < 0.099) { + disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); + } else { + disp_area.printf("%.0f%%", selected_radio->getLongtermAirtime()*100.0); + } + disp_area.drawBitmap(32+2, 26-1, bm_hg_high, 5, 9, DISPLAY_WHITE, DISPLAY_BLACK); + + disp_area.setTextColor(DISPLAY_BLACK); + + disp_area.setCursor(2, 46); + disp_area.print("Channel"); + disp_area.setCursor(38, 46); + disp_area.print("Load:"); + + disp_area.setCursor(11, 57); + if (selected_radio->getTotalChannelUtil() < 0.099) { + disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); + } else { + disp_area.printf("%.0f%%", selected_radio->getTotalChannelUtil()*100.0); + } + disp_area.drawBitmap(2, 50, bm_hg_low, 5, 9, DISPLAY_BLACK, DISPLAY_WHITE); + + disp_area.setCursor(32+11, 57); + if (selected_radio->getLongtermChannelUtil() < 0.099) { + disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); + } else { + disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); + } + disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, DISPLAY_BLACK, DISPLAY_WHITE); #endif } else { if (device_signatures_ok()) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 37, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 71, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 71, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 37, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 37, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 71, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 71, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 37, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } if (!hw_ready || !device_firmware_ok()) { if (!device_firmware_ok()) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_fw_corrupt, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_fw_corrupt, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { if (!modems_installed) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_no_radio, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_no_radio, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_hwfail, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_hwfail, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_hwfail, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_hwfail, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } @@ -974,19 +1070,19 @@ void draw_disp_area() { char *pin_str = (char*)malloc(DISP_PIN_SIZE+1); sprintf(pin_str, "%06d", bt_ssp_pin); - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_pairing, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_pairing, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_pairing, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_pairing, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif for (int i = 0; i < DISP_PIN_SIZE; i++) { uint8_t numeric = pin_str[i]-48; - #if DISPLAY == OLED - uint8_t offset = numeric*5; - disp_area.drawBitmap(7+9*i, 37+16, bm_n_uh+offset, 8, 5, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + #if DISP_H == 122 uint8_t offset = numeric*20; - disp_area.drawBitmap(14+17*i, 71+32, bm_n_uh+offset, 10, 10, GxEPD_WHITE, GxEPD_BLACK); + disp_area.drawBitmap(14+17*i, 71+32, bm_n_uh+offset, 10, 10, DISPLAY_WHITE, DISPLAY_BLACK); + #else + uint8_t offset = numeric*5; + disp_area.drawBitmap(7+9*i, 37+16, bm_n_uh+offset, 8, 5, DISPLAY_WHITE, DISPLAY_BLACK); #endif } free(pin_str); @@ -999,155 +1095,147 @@ void draw_disp_area() { if (radio_online) { if (!display_diagnostics) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_online, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_online, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 37, bm_online, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 71, bm_online, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } else { if (disp_page == 0) { if (true || device_signatures_ok()) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_checks, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_checks, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_checks, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_checks, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_nfr, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_nfr, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_nfr, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_nfr, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } else if (disp_page == 1) { if (!console_active) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_hwok, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_hwok, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_hwok, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_hwok, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } else { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_console_active, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_console_active, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_console_active, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_console_active, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif } } else if (disp_page == 2) { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 37, bm_version, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 71, bm_version, disp_area.width(), 54, GxEPD_WHITE, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawBitmap(0, 71, bm_version, disp_area.width(), 54, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(0, 37, bm_version, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); #endif char *v_str = (char*)malloc(3+1); sprintf(v_str, "%01d%02d", MAJ_VERS, MIN_VERS); for (int i = 0; i < 3; i++) { - #if DISPLAY == OLED - uint8_t dxp = 20; - uint8_t numeric = v_str[i]-48; uint8_t bm_offset = numeric*5; - if (i == 2) dxp += 9*2+4; - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + #if DISP_H == 122 uint8_t dxp = 43; uint8_t numeric = v_str[i]-48; uint8_t bm_offset = numeric*20; if (i == 2) dxp += 9*2+6; + #else + uint8_t dxp = DISP_H * 0.32; + uint8_t numeric = v_str[i]-48; uint8_t bm_offset = numeric*20; + if (i == 2) dxp += 9*2+6; #endif if (i == 1) dxp += 9*1+4; - #if DISPLAY == OLED - disp_area.drawBitmap(dxp, 37+16, bm_n_uh+bm_offset, 8, 5, SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + #if DISP_H == 122 // add gap manually rather than oversizing bitmap, as the gfx lib fills in the extra space with black - disp_area.drawBitmap(dxp, 71+32, bm_n_uh+bm_offset, 10, 10, GxEPD_WHITE, GxEPD_BLACK); + disp_area.drawBitmap(dxp, 71+32, bm_n_uh+bm_offset, 10, 10, DISPLAY_WHITE, DISPLAY_BLACK); + #else + disp_area.drawBitmap(dxp, 37+16, bm_n_uh+bm_offset, 8, 5, DISPLAY_WHITE, DISPLAY_BLACK); #endif } free(v_str); - #if DISPLAY == OLED - disp_area.drawLine(27, 37+19, 28, 37+19, SSD1306_BLACK); - disp_area.drawLine(27, 37+19, 28, 37+19, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawLine(27, 37+20, 28, 37+20, GxEPD_BLACK); - disp_area.drawLine(27, 37+20, 28, 37+20, GxEPD_BLACK); + #if DISP_H == 122 + disp_area.drawLine(27, 37+20, 28, 37+20, DISPLAY_BLACK); + disp_area.drawLine(27, 37+20, 28, 37+20, DISPLAY_BLACK); + #else + disp_area.drawLine(27, 37+19, 28, 37+19, DISPLAY_BLACK); + disp_area.drawLine(27, 37+19, 28, 37+19, DISPLAY_BLACK); #endif } } } } else { - #if DISPLAY == OLED - disp_area.drawBitmap(0, 0, fb, disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - disp_area.drawBitmap(0, 0, fb, disp_area.width(), disp_area.height(), GxEPD_WHITE, GxEPD_BLACK); - #endif + disp_area.drawBitmap(0, 0, fb, disp_area.width(), disp_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); } } } void update_disp_area() { draw_disp_area(); - #if DISPLAY == OLED - display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), GxEPD_WHITE, GxEPD_BLACK); - #endif + display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); if (disp_mode == DISP_MODE_LANDSCAPE) { if (device_init_done && !firmware_update_mode && !disp_ext_fb) { - #if DISPLAY == OLED - display.drawLine(0, 0, 0, 63, SSD1306_WHITE); - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - display.drawLine(0, 0, 0, 63, GxEPD_WHITE); + #if DISP_H == 122 + display.drawLine(0, 0, 0, 63, DISPLAY_WHITE); + #else + display.drawLine(0, 0, 0, DISP_H / 2, DISPLAY_WHITE); #endif } } } +void do_screensaver(uint32_t current){ + #if DISPLAY == OLED + // Invert display to protect against OLED screen burn in + //TODO: Make this a option configurable through rnodeconf + //TODO: Implement other ways to do the screensaver, such as scrolling the screen. + if (screensaver_enabled) { + if (current-last_screensaver >= SCREENSAVER_INTERVAL+SCREENSAVER_TIME) { + display.invertDisplay(0); + last_screensaver = current; + screensaver_enabled = false; + } + } + else if (current-last_screensaver >= SCREENSAVER_INTERVAL) { + display.invertDisplay(1); + screensaver_enabled = true; + } + #endif +} + void update_display(bool blank = false) { - if (blank) { - #if DISPLAY == OLED + #if DISPLAY == OLED if (display_contrast != display_intensity) { display_contrast = display_intensity; set_contrast(&display, display_contrast); } display.clearDisplay(); - #endif + #endif + if (blank) { display.display(); } else { if (millis()-last_disp_update >= disp_update_interval) { - #if DISPLAY == OLED - if (display_contrast != display_intensity) { - display_contrast = display_intensity; - set_contrast(&display, display_contrast); - } - display.clearDisplay(); - update_stat_area(); - update_disp_area(); - display.display(); - uint32_t current = millis(); - // Invert display to protect against OLED screen burn in - if (screensaver_enabled) { - if (current-last_screensaver >= SCREENSAVER_INTERVAL+SCREENSAVER_TIME) { - display.invertDisplay(0); - last_screensaver = current; - screensaver_enabled = false; - } - } - else if (current-last_screensaver >= SCREENSAVER_INTERVAL) { - display.invertDisplay(1); - screensaver_enabled = true; - } - #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + do_screensaver(current); + #if DISPLAY == EINK_BW || DISPLAY == EINK_3C display.setFullWindow(); - display.fillScreen(GxEPD_WHITE); + display.fillScreen(DISPLAY_WHITE); + #endif update_stat_area(); update_disp_area(); - - uint32_t current = millis(); + #if DISPLAY == OLED + display.display(); + #else if (current-last_epd_refresh >= REFRESH_PERIOD) { - // Perform a full refresh after the correct time has elapsed - display.display(false); - last_epd_refresh = current; + // Perform a full refresh after the correct time has elapsed + display.display(false); + last_epd_refresh = current; } else { - // Only perform a partial refresh - display.display(true); + // Only perform a partial refresh + display.display(true); } #endif last_disp_update = current; diff --git a/Framing.h b/Framing.h index d696a8a..77bda39 100644 --- a/Framing.h +++ b/Framing.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -53,6 +53,8 @@ #define CMD_FB_READL 0x44 #define CMD_DISP_INT 0x45 #define CMD_DISP_ADDR 0x63 + #define CMD_DISP_BLNK 0x64 + #define CMD_NP_INT 0x65 #define CMD_BT_CTRL 0x46 #define CMD_BT_PIN 0x62 @@ -81,7 +83,7 @@ #define CMD_INT1_DATA 0x10 #define CMD_INT2_DATA 0x20 #define CMD_INT3_DATA 0x70 - #define CMD_INT4_DATA 0x80 + #define CMD_INT4_DATA 0x75 #define CMD_INT5_DATA 0x90 #define CMD_INT6_DATA 0xA0 #define CMD_INT7_DATA 0xB0 @@ -93,8 +95,8 @@ #define CMD_SEL_INT0 0x1E #define CMD_SEL_INT1 0x1F #define CMD_SEL_INT2 0x2F - #define CMD_SEL_INT3 0x7F - #define CMD_SEL_INT4 0x8F + #define CMD_SEL_INT3 0x74 + #define CMD_SEL_INT4 0x7F #define CMD_SEL_INT5 0x9F #define CMD_SEL_INT6 0xAF #define CMD_SEL_INT7 0xBF @@ -119,6 +121,8 @@ #define ERROR_TXFAILED 0x02 #define ERROR_EEPROM_LOCKED 0x03 #define ERROR_QUEUE_FULL 0x04 + #define ERROR_MEMORY_LOW 0x05 + #define ERROR_MODEM_TIMEOUT 0x06 // Serial framing variables size_t frame_len; diff --git a/Graphics.h b/Graphics.h index 049beb0..faf5f2f 100644 --- a/Graphics.h +++ b/Graphics.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -13,402 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#if DISP_H == UNSCALED_MAX -// use 64px wide graphics - -const unsigned char bm_cable [] PROGMEM = { - 0x00, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x07, 0xfc, 0x08, 0x38, 0x10, 0x1c, 0x10, 0x00, 0x08, 0x00, - 0x07, 0xc0, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x07, 0xc0, 0x08, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x80, 0x04, 0x43, 0x08, 0x46, - 0xf1, 0x8f, 0x02, 0x16, 0x02, 0x23, 0x01, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -const unsigned char bm_bt [] PROGMEM = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x40, - 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40, - 0x01, 0x80, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40, - 0x29, 0x94, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, - 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x11, 0x48, - 0x29, 0x94, 0x11, 0x48, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00 -}; - -const unsigned char bm_rf [] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xc4, - 0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x4e, 0xc4, - 0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x4e, - 0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x71, 0x4e, - 0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00 -}; - -const unsigned char bm_boot [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0x38, 0x66, 0x67, 0x1c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xe6, 0x66, 0x4c, 0xff, 0xff, - 0xff, 0xfc, 0x98, 0x70, 0xe6, 0x7c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xf0, 0xe6, 0x4c, 0xff, 0xff, - 0xff, 0xfc, 0x38, 0x79, 0xe7, 0x1c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x0c, 0x38, 0xe1, 0xc3, 0x33, 0x38, 0x7f, 0xfe, 0x7e, 0x72, 0x64, 0xe7, 0x31, 0x33, 0xff, - 0xff, 0x1e, 0x70, 0x61, 0xe7, 0x30, 0x32, 0x7f, 0xff, 0xce, 0x72, 0x61, 0xe7, 0x32, 0x32, 0x7f, - 0xfe, 0x1e, 0x72, 0x64, 0xe7, 0x33, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_no_radio [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc7, 0x0e, 0x71, 0xfc, 0xce, 0x38, 0x7f, - 0xc9, 0x93, 0x26, 0x64, 0xfc, 0x4c, 0x9c, 0xff, 0xc3, 0x83, 0x26, 0x64, 0xfc, 0x0c, 0x9c, 0xff, - 0xc3, 0x93, 0x26, 0x64, 0xfc, 0x8c, 0x9c, 0xff, 0xc9, 0x93, 0x0e, 0x71, 0xfc, 0xce, 0x3c, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x8e, 0x4c, 0xcc, 0x3f, 0xff, 0xfc, 0xff, - 0xcf, 0x26, 0x4c, 0x4c, 0x9f, 0xff, 0xfb, 0x7f, 0xc3, 0x26, 0x4c, 0x0c, 0x9f, 0xff, 0xfb, 0x7f, - 0xcf, 0x26, 0x4c, 0x8c, 0x9f, 0xff, 0xf7, 0xbf, 0xcf, 0x8f, 0x1c, 0xcc, 0x3f, 0xff, 0xf4, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xf7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_hwfail [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0xe3, 0x87, 0x0e, 0x73, 0x8e, 0x1c, 0x3f, - 0xe4, 0xc9, 0x93, 0x26, 0x53, 0x26, 0x4c, 0xff, 0xe0, 0xc1, 0x87, 0x26, 0x53, 0x06, 0x1c, 0x3f, - 0xe4, 0xc9, 0x87, 0x26, 0x03, 0x26, 0x1c, 0xff, 0xe4, 0xc9, 0x93, 0x0f, 0x27, 0x26, 0x4c, 0x3f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe1, 0xc7, 0x33, 0xc9, 0x87, 0x0f, 0xf9, 0xff, 0xe7, 0x93, 0x33, 0xc9, 0x93, 0x3f, 0xf6, 0xff, - 0xe1, 0x83, 0x33, 0xc9, 0x87, 0x0f, 0xf6, 0xff, 0xe7, 0x93, 0x33, 0xc9, 0x87, 0x3f, 0xef, 0x7f, - 0xe7, 0x93, 0x30, 0xe3, 0x93, 0x0f, 0xe9, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xef, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_console [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x1f, 0xcf, 0xff, 0xff, 0xf3, 0xf8, 0xff, - 0xfe, 0x3f, 0x9f, 0xff, 0xff, 0xf9, 0xfc, 0x7f, 0xfc, 0x7f, 0x99, 0xe6, 0x61, 0x99, 0xfe, 0x3f, - 0xf8, 0xe7, 0x99, 0x26, 0x67, 0x99, 0xe7, 0x1f, 0xf9, 0xc7, 0x99, 0x26, 0x61, 0x99, 0xe3, 0x9f, - 0xf1, 0x8f, 0x98, 0x06, 0x67, 0x99, 0xf1, 0x8f, 0xf3, 0x9f, 0x9c, 0xce, 0x67, 0x99, 0xf9, 0xcf, - 0xf3, 0x99, 0x9f, 0xff, 0xff, 0xf9, 0x99, 0xcf, 0xf3, 0x99, 0x9f, 0xff, 0xff, 0xf9, 0x99, 0xcf, - 0xf3, 0x9f, 0x9f, 0xe3, 0x83, 0xf9, 0xf9, 0xcf, 0xf1, 0x8f, 0x9f, 0xc9, 0x93, 0xf9, 0xf1, 0x8f, - 0xf9, 0xc7, 0x9f, 0xc1, 0x83, 0xf9, 0xe3, 0x9f, 0xf8, 0xe7, 0x9f, 0xc9, 0x9f, 0xf9, 0xe7, 0x1f, - 0xfc, 0x7f, 0x9f, 0xc9, 0x9f, 0xf9, 0xfe, 0x3f, 0xfe, 0x3f, 0x9f, 0xff, 0xff, 0xf9, 0xfc, 0x7f, - 0xff, 0x1f, 0xcf, 0xff, 0xff, 0xf3, 0xf8, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, - 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x78, 0x1e, 0x07, 0x81, 0xe0, 0x78, 0x1f, - 0xef, 0xbb, 0xee, 0xfb, 0xbe, 0xef, 0xbb, 0xef, 0xe8, 0xda, 0xb6, 0x9d, 0xb3, 0x6d, 0xda, 0x37, - 0xef, 0xda, 0xf6, 0xb5, 0xad, 0x6c, 0xdb, 0xf7, 0xe8, 0x5a, 0x36, 0x95, 0xad, 0x6c, 0xda, 0x97, - 0xef, 0xdb, 0xf6, 0x85, 0xb3, 0x6c, 0xda, 0x97, 0xea, 0x5a, 0x36, 0xb5, 0xb3, 0x6c, 0xdb, 0xf7, - 0xef, 0xda, 0xf6, 0xa5, 0xad, 0x6f, 0xda, 0x57, 0xe8, 0x5a, 0xb6, 0x85, 0xad, 0x6c, 0xda, 0x57, - 0xef, 0xdb, 0xf6, 0xfd, 0xbf, 0x6f, 0xdb, 0xf7, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x07, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x42, 0x7c, 0x60, 0xf0, 0x78, 0x3c, 0x7f, 0xfe, 0x4a, 0x7c, 0x64, 0xf2, 0x79, 0x3c, 0x7f, - 0xfe, 0x43, 0xfe, 0x64, 0xf2, 0x79, 0x3e, 0x7f, 0xfe, 0x4e, 0x7e, 0x64, 0x92, 0x49, 0x26, 0x7f, - 0xfe, 0x4e, 0x7e, 0x60, 0x90, 0x48, 0x26, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_pairing [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0xe3, 0x98, 0x73, 0x33, 0x87, 0xff, 0xff, 0xf2, 0xc9, 0x99, 0x33, 0x13, 0x3f, 0xff, - 0xff, 0xf0, 0xc1, 0x98, 0x73, 0x03, 0x27, 0xff, 0xff, 0xf3, 0xc9, 0x98, 0x73, 0x23, 0x27, 0xff, - 0xff, 0xf3, 0xc9, 0x99, 0x33, 0x33, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_fw_update [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x98, 0x70, 0xf1, 0xc3, 0x33, 0x38, 0x7f, 0xfc, 0x99, 0x32, 0x64, 0xe7, 0x31, 0x33, 0xff, - 0xfc, 0x98, 0x72, 0x60, 0xe7, 0x30, 0x32, 0x7f, 0xfc, 0x99, 0xf2, 0x64, 0xe7, 0x32, 0x32, 0x7f, - 0xfe, 0x39, 0xf0, 0xe4, 0xe7, 0x33, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0x66, 0x1c, 0xe6, 0x73, 0x8e, 0x1c, 0x3f, 0xf9, 0xe6, 0x4c, 0x46, 0x53, 0x26, 0x4c, 0xff, - 0xf8, 0x66, 0x1c, 0x06, 0x53, 0x06, 0x1c, 0x3f, 0xf9, 0xe6, 0x1c, 0xa6, 0x03, 0x26, 0x1c, 0xff, - 0xf9, 0xe6, 0x4c, 0xe7, 0x27, 0x26, 0x4c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_version [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x99, 0x86, 0x1e, 0x19, 0xc7, 0x33, 0xff, 0xff, 0x99, 0x9e, 0x4c, 0xf9, 0x93, 0x13, 0xff, - 0xff, 0xc3, 0x86, 0x1e, 0x39, 0x93, 0x03, 0xff, 0xff, 0xc3, 0x9e, 0x1f, 0x99, 0x93, 0x23, 0xff, - 0xff, 0xe7, 0x86, 0x4c, 0x39, 0xc7, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_updating [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0x71, 0x7f, 0xff, - 0xff, 0xff, 0x7f, 0xf5, 0xff, 0x75, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0x71, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x17, 0xd4, 0x7f, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0x57, 0xd5, 0x7f, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x17, 0xd4, 0x7f, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x44, 0x71, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0x57, 0x55, 0x75, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x47, 0x44, 0x71, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0x51, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x44, 0x51, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0x54, 0x45, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x14, 0x54, 0x45, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0xff, - 0xff, 0xff, 0x60, 0x00, 0x00, 0x03, 0x7f, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x07, 0x7f, 0xff, - 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x5c, 0x00, 0x00, 0x1c, 0x7f, 0xff, - 0xff, 0xff, 0x56, 0x00, 0x00, 0x35, 0x7f, 0xff, 0xff, 0xff, 0x57, 0x00, 0x00, 0x74, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xc0, 0x01, 0xd1, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x60, 0x03, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x44, 0x70, 0x07, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0x5c, 0x1d, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x56, 0x35, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x14, 0x57, 0xe5, 0x44, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, - 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -static unsigned char bm_def[] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x61, 0x10, 0x8c, 0x23, 0xc4, 0x3f, 0xff, - 0xb5, 0xa7, 0xb7, 0xb5, 0xed, 0xed, 0xbf, 0xff, 0xb5, 0xb9, 0xb4, 0xb4, 0x6d, 0xed, 0xbf, 0xff, - 0x85, 0xa1, 0x10, 0xb4, 0x21, 0x44, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0x1c, 0xfe, 0x7f, 0x8f, 0xf0, 0x00, - 0x1f, 0xf7, 0x9d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, 0x1c, 0x77, 0xfd, 0xc7, 0x73, 0xdc, 0x00, 0x00, - 0x1f, 0xe7, 0xfd, 0xc7, 0x71, 0xdf, 0x00, 0x00, 0x1f, 0xe7, 0x7d, 0xc7, 0x71, 0xdf, 0x00, 0x00, - 0x1c, 0x77, 0x3d, 0xc7, 0x73, 0xdc, 0x00, 0x00, 0x1c, 0x77, 0x1d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, - 0x1c, 0x77, 0x1c, 0xfe, 0x7f, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, - 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x62, 0x24, 0x49, 0x22, 0x4e, 0x44, - 0x00, 0x24, 0x93, 0x66, 0xc9, 0x32, 0x44, 0x28, 0x00, 0x20, 0x92, 0xa5, 0x49, 0x2a, 0x44, 0x10, - 0x00, 0x24, 0x92, 0x24, 0x49, 0x26, 0x44, 0x10, 0x00, 0x18, 0x62, 0x24, 0x46, 0x22, 0x44, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x1c, 0x9c, 0x44, 0x88, 0xc7, 0x1c, 0x00, 0x00, 0x10, 0x92, 0x6c, 0xa9, 0x24, 0x90, - 0x00, 0x00, 0x1c, 0x9c, 0x54, 0xa9, 0xe7, 0x1c, 0x00, 0x00, 0x10, 0x94, 0x44, 0xa9, 0x25, 0x10, - 0x00, 0x00, 0x10, 0x92, 0x44, 0x51, 0x24, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -const unsigned char bm_def_lc [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x61, 0x10, 0x8c, 0x23, 0xc4, 0x3f, 0xff, - 0xb5, 0xa7, 0xb7, 0xb5, 0xed, 0xed, 0xbf, 0xff, 0xb5, 0xb9, 0xb4, 0xb4, 0x6d, 0xed, 0xbf, 0xff, - 0x85, 0xa1, 0x10, 0xb4, 0x21, 0x44, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0x1c, 0xfe, 0x7f, 0x8f, 0xf0, 0x00, - 0x1f, 0xf7, 0x9d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, 0x1c, 0x77, 0xfd, 0xc7, 0x73, 0xdc, 0x00, 0x00, - 0x1f, 0xe7, 0xfd, 0xc7, 0x71, 0xdf, 0x00, 0x00, 0x1f, 0xe7, 0x7d, 0xc7, 0x71, 0xdf, 0x00, 0x00, - 0x1c, 0x77, 0x3d, 0xc7, 0x73, 0xdc, 0x00, 0x00, 0x1c, 0x77, 0x1d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, - 0x1c, 0x77, 0x1c, 0xfe, 0x7f, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, - 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x39, 0x10, 0x61, 0x88, 0x91, 0x1c, - 0x02, 0x49, 0x21, 0x90, 0x92, 0x4d, 0x9b, 0x20, 0x02, 0x4e, 0x39, 0x50, 0x82, 0x4a, 0x95, 0x18, - 0x02, 0x48, 0x21, 0x30, 0x92, 0x48, 0x91, 0x04, 0x01, 0x88, 0x39, 0x10, 0x61, 0x88, 0x91, 0x38, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0xc8, 0x8e, 0x73, 0x91, 0x1c, 0x00, 0x00, 0x02, 0x05, 0x10, 0x22, 0x1b, 0x20, - 0x00, 0x00, 0x01, 0x82, 0x0c, 0x23, 0x95, 0x18, 0x00, 0x00, 0x00, 0x42, 0x02, 0x22, 0x11, 0x04, - 0x00, 0x00, 0x03, 0x82, 0x1c, 0x23, 0x91, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -const unsigned char bm_hwok [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf2, 0x71, 0xc3, 0x87, 0x39, 0xc7, 0x0e, 0x1f, 0xf2, 0x64, 0xc9, 0x93, 0x29, 0x93, 0x26, 0x7f, - 0xf0, 0x60, 0xc3, 0x93, 0x29, 0x83, 0x0e, 0x1f, 0xf2, 0x64, 0xc3, 0x93, 0x01, 0x93, 0x0e, 0x7f, - 0xf2, 0x64, 0xc9, 0x87, 0x93, 0x93, 0x26, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x33, 0x30, 0xff, 0x8e, 0x4f, 0xff, - 0xff, 0xf3, 0x13, 0x39, 0xff, 0x26, 0x1f, 0xff, 0xff, 0xf3, 0x03, 0x39, 0xff, 0x26, 0x3f, 0xff, - 0xff, 0xf3, 0x23, 0x39, 0xff, 0x26, 0x1f, 0xff, 0xff, 0xf3, 0x33, 0x39, 0xff, 0x8e, 0x4f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc3, 0x0e, 0x67, 0xf8, 0x70, 0xe3, 0x87, 0x33, 0xe7, 0x27, 0x0f, 0xf9, 0x33, 0xc9, 0x93, 0x87, - 0xe7, 0x0f, 0x9f, 0xf8, 0x70, 0xc1, 0x93, 0xcf, 0xe7, 0x0f, 0x0f, 0xf8, 0x73, 0xc9, 0x93, 0xcf, - 0xe7, 0x26, 0x67, 0xf9, 0x30, 0xc9, 0x87, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_console_active [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x8e, 0x67, 0x0e, 0x39, 0xe1, 0xff, - 0xff, 0x93, 0x26, 0x26, 0x7c, 0x99, 0xe7, 0xff, 0xff, 0x9f, 0x26, 0x07, 0x1c, 0x99, 0xe1, 0xff, - 0xff, 0x93, 0x26, 0x47, 0xcc, 0x99, 0xe7, 0xff, 0xff, 0xc7, 0x8e, 0x66, 0x1e, 0x38, 0x61, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3c, 0x70, 0xcc, 0xcc, 0x3f, 0xff, - 0xff, 0xfc, 0x99, 0x39, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xfc, 0x19, 0xf9, 0xce, 0x1c, 0x3f, 0xff, - 0xff, 0xfc, 0x99, 0x39, 0xce, 0x1c, 0xff, 0xff, 0xff, 0xfc, 0x9c, 0x79, 0xcf, 0x3c, 0x3f, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_checks [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0x0c, 0x99, 0xc7, 0x0f, - 0xe6, 0x00, 0x7f, 0x93, 0x3c, 0x99, 0x93, 0x3f, 0xe6, 0x00, 0x7f, 0x93, 0x0e, 0x39, 0x9f, 0x0f, - 0xff, 0xff, 0xff, 0x93, 0x3e, 0x39, 0x93, 0x3f, 0xff, 0xff, 0xff, 0x87, 0x0f, 0x79, 0xc7, 0x0f, - 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x39, 0x30, 0xe3, 0x93, 0x87, - 0xe6, 0x00, 0x7c, 0x99, 0x33, 0xc9, 0x87, 0x3f, 0xe6, 0x00, 0x7c, 0xf8, 0x30, 0xcf, 0x8f, 0x8f, - 0xff, 0xff, 0xfc, 0x99, 0x33, 0xc9, 0x87, 0xe7, 0xff, 0xff, 0xfe, 0x39, 0x30, 0xe3, 0x93, 0x0f, - 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x9c, 0x3c, 0x78, 0x70, 0xc3, 0x0f, - 0xe6, 0x0d, 0x3c, 0x99, 0x33, 0xe7, 0xcf, 0x27, 0xe6, 0x04, 0x7c, 0x38, 0x38, 0xf1, 0xc3, 0x27, - 0xff, 0xfe, 0xfc, 0xf9, 0x3e, 0x7c, 0xcf, 0x27, 0xff, 0xff, 0xfc, 0xf9, 0x30, 0xe1, 0xc3, 0x0f, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_frame [] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x40, 0x02, 0x0f, 0xff, 0xfc, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x1e, 0x40, 0x02, 0x78, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x3f, 0xff, 0xf2, 0x40, 0x02, 0x4f, 0xff, 0xfc, - 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x3f, 0xff, 0xf2, 0x40, 0x02, 0x4f, 0xff, 0xfc, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, - 0x20, 0x00, 0x1e, 0x40, 0x02, 0x78, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, - 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x3f, 0xff, 0xf0, 0x40, 0x02, 0x0f, 0xff, 0xfc, - 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x1c, - 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x18, - 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x38, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaa, 0x8a, 0xaa, 0x80 -}; - -const unsigned char bm_online [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x1c, 0x66, 0x61, 0x8c, 0x24, 0x90, 0x87, - 0xe6, 0x49, 0x22, 0x4f, 0x24, 0xe4, 0x93, 0x93, 0xe6, 0x18, 0x20, 0x63, 0x3c, 0x26, 0x30, 0x87, - 0xe6, 0x19, 0x24, 0x79, 0x24, 0xe6, 0x33, 0x87, 0xe6, 0x49, 0x26, 0x43, 0x8c, 0x27, 0x70, 0x93, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xe6, 0x73, 0xe7, 0x33, 0x87, 0xff, - 0xff, 0xe4, 0xe2, 0x73, 0xe7, 0x13, 0x9f, 0xff, 0xff, 0xe4, 0xe0, 0x73, 0xe7, 0x03, 0x87, 0xff, - 0xff, 0xe4, 0xe4, 0x73, 0xe7, 0x23, 0x9f, 0xff, 0xff, 0xf1, 0xe6, 0x70, 0xe7, 0x33, 0x87, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_fw_corrupt [] PROGMEM = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x30, 0xe7, 0x33, 0x9c, 0x70, 0xe1, 0xff, - 0xcf, 0x32, 0x62, 0x32, 0x99, 0x32, 0x67, 0xff, 0xc3, 0x30, 0xe0, 0x32, 0x98, 0x30, 0xe1, 0xff, - 0xcf, 0x30, 0xe5, 0x30, 0x19, 0x30, 0xe7, 0xff, 0xcf, 0x32, 0x67, 0x39, 0x39, 0x32, 0x61, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xc7, 0x0e, 0x1c, 0x98, 0x70, 0xfc, 0xff, - 0xc9, 0x93, 0x26, 0x4c, 0x99, 0x39, 0xfb, 0x7f, 0xcf, 0x93, 0x0e, 0x1c, 0x98, 0x79, 0xfb, 0x7f, - 0xc9, 0x93, 0x0e, 0x1c, 0x99, 0xf9, 0xf7, 0xbf, 0xe3, 0xc7, 0x26, 0x4e, 0x39, 0xf9, 0xf4, 0xbf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xf7, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -const unsigned char bm_plug [] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x7f, 0x80, 0x55, 0xfc, 0x00, 0xaa, 0xfc, 0x00, 0x00, - 0x7f, 0x80, 0x00, 0x1c, 0x00 -}; - -const unsigned char bm_hg_low [] PROGMEM = { - 0xf8, 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0xf8, 0xf8 -}; - -const unsigned char bm_hg_high [] PROGMEM = { - 0xf8, 0x88, 0xf8, 0x70, 0x20, 0x70, 0xf8, 0xf8, 0xf8 -}; - -const unsigned char bm_n_uh [] PROGMEM = { - 0x07, 0x27, 0x27, 0x27, 0x07, 0x8f, 0x8f, 0xcf, 0xcf, 0xcf, 0x07, 0xe7, 0x07, 0x3f, 0x07, 0x07, - 0xe7, 0xc7, 0xe7, 0x07, 0x27, 0x27, 0x07, 0xe7, 0xe7, 0x07, 0x3f, 0x07, 0xe7, 0x07, 0x07, 0x3f, - 0x07, 0x27, 0x07, 0x07, 0xc7, 0xcf, 0x9f, 0x1f, 0x07, 0x27, 0x07, 0x27, 0x07, 0x07, 0x27, 0x07, - 0xe7, 0xe7 -}; - -const unsigned char bm_dot_sqr [] PROGMEM = { - 0xaa, 0xd5, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, - 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0xaa, 0xd5, 0x40 -}; - -#elif DISP_H == 122 +#if DISP_H == 122 // use 122px wide graphics const unsigned char bm_bt [] PROGMEM = { @@ -1710,6 +1315,401 @@ const unsigned char bm_dot_sqr [] PROGMEM = { 0xee, 0xdd, 0xdd, 0xc0 }; +#else + +// use 64px wide graphics + +const unsigned char bm_cable [] PROGMEM = { + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x07, 0xfc, 0x08, 0x38, 0x10, 0x1c, 0x10, 0x00, 0x08, 0x00, + 0x07, 0xc0, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x07, 0xc0, 0x08, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x80, 0x04, 0x43, 0x08, 0x46, + 0xf1, 0x8f, 0x02, 0x16, 0x02, 0x23, 0x01, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_bt [] PROGMEM = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x01, 0x40, + 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40, + 0x01, 0x80, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x01, 0x40, + 0x29, 0x94, 0x01, 0x40, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x80, 0x01, 0x40, 0x09, 0x20, 0x05, 0x10, 0x03, 0x20, 0x11, 0x48, + 0x29, 0x94, 0x11, 0x48, 0x03, 0x20, 0x05, 0x10, 0x09, 0x20, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00 +}; + +const unsigned char bm_rf [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xc4, + 0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x4e, 0xc4, + 0x4a, 0xaa, 0x4a, 0xce, 0x6e, 0xaa, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x4e, + 0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xe0, 0x08, 0x10, 0x13, 0xc8, 0x04, 0x20, 0x01, 0x80, 0x00, 0x00, 0x71, 0x4e, + 0x31, 0x48, 0x61, 0xca, 0x74, 0x4e, 0x00, 0x00, 0x01, 0x80, 0x04, 0x20, 0x03, 0xc0, 0x00, 0x00 +}; + +const unsigned char bm_boot [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x38, 0x66, 0x67, 0x1c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xe6, 0x66, 0x4c, 0xff, 0xff, + 0xff, 0xfc, 0x98, 0x70, 0xe6, 0x7c, 0x3f, 0xff, 0xff, 0xfc, 0x99, 0xf0, 0xe6, 0x4c, 0xff, 0xff, + 0xff, 0xfc, 0x38, 0x79, 0xe7, 0x1c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0c, 0x38, 0xe1, 0xc3, 0x33, 0x38, 0x7f, 0xfe, 0x7e, 0x72, 0x64, 0xe7, 0x31, 0x33, 0xff, + 0xff, 0x1e, 0x70, 0x61, 0xe7, 0x30, 0x32, 0x7f, 0xff, 0xce, 0x72, 0x61, 0xe7, 0x32, 0x32, 0x7f, + 0xfe, 0x1e, 0x72, 0x64, 0xe7, 0x33, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_no_radio [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc7, 0x0e, 0x71, 0xfc, 0xce, 0x38, 0x7f, + 0xc9, 0x93, 0x26, 0x64, 0xfc, 0x4c, 0x9c, 0xff, 0xc3, 0x83, 0x26, 0x64, 0xfc, 0x0c, 0x9c, 0xff, + 0xc3, 0x93, 0x26, 0x64, 0xfc, 0x8c, 0x9c, 0xff, 0xc9, 0x93, 0x0e, 0x71, 0xfc, 0xce, 0x3c, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x8e, 0x4c, 0xcc, 0x3f, 0xff, 0xfc, 0xff, + 0xcf, 0x26, 0x4c, 0x4c, 0x9f, 0xff, 0xfb, 0x7f, 0xc3, 0x26, 0x4c, 0x0c, 0x9f, 0xff, 0xfb, 0x7f, + 0xcf, 0x26, 0x4c, 0x8c, 0x9f, 0xff, 0xf7, 0xbf, 0xcf, 0x8f, 0x1c, 0xcc, 0x3f, 0xff, 0xf4, 0xbf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xf7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_hwfail [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe4, 0xe3, 0x87, 0x0e, 0x73, 0x8e, 0x1c, 0x3f, + 0xe4, 0xc9, 0x93, 0x26, 0x53, 0x26, 0x4c, 0xff, 0xe0, 0xc1, 0x87, 0x26, 0x53, 0x06, 0x1c, 0x3f, + 0xe4, 0xc9, 0x87, 0x26, 0x03, 0x26, 0x1c, 0xff, 0xe4, 0xc9, 0x93, 0x0f, 0x27, 0x26, 0x4c, 0x3f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe1, 0xc7, 0x33, 0xc9, 0x87, 0x0f, 0xf9, 0xff, 0xe7, 0x93, 0x33, 0xc9, 0x93, 0x3f, 0xf6, 0xff, + 0xe1, 0x83, 0x33, 0xc9, 0x87, 0x0f, 0xf6, 0xff, 0xe7, 0x93, 0x33, 0xc9, 0x87, 0x3f, 0xef, 0x7f, + 0xe7, 0x93, 0x30, 0xe3, 0x93, 0x0f, 0xe9, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xbf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_console [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x1f, 0xcf, 0xff, 0xff, 0xf3, 0xf8, 0xff, + 0xfe, 0x3f, 0x9f, 0xff, 0xff, 0xf9, 0xfc, 0x7f, 0xfc, 0x7f, 0x99, 0xe6, 0x61, 0x99, 0xfe, 0x3f, + 0xf8, 0xe7, 0x99, 0x26, 0x67, 0x99, 0xe7, 0x1f, 0xf9, 0xc7, 0x99, 0x26, 0x61, 0x99, 0xe3, 0x9f, + 0xf1, 0x8f, 0x98, 0x06, 0x67, 0x99, 0xf1, 0x8f, 0xf3, 0x9f, 0x9c, 0xce, 0x67, 0x99, 0xf9, 0xcf, + 0xf3, 0x99, 0x9f, 0xff, 0xff, 0xf9, 0x99, 0xcf, 0xf3, 0x99, 0x9f, 0xff, 0xff, 0xf9, 0x99, 0xcf, + 0xf3, 0x9f, 0x9f, 0xe3, 0x83, 0xf9, 0xf9, 0xcf, 0xf1, 0x8f, 0x9f, 0xc9, 0x93, 0xf9, 0xf1, 0x8f, + 0xf9, 0xc7, 0x9f, 0xc1, 0x83, 0xf9, 0xe3, 0x9f, 0xf8, 0xe7, 0x9f, 0xc9, 0x9f, 0xf9, 0xe7, 0x1f, + 0xfc, 0x7f, 0x9f, 0xc9, 0x9f, 0xf9, 0xfe, 0x3f, 0xfe, 0x3f, 0x9f, 0xff, 0xff, 0xf9, 0xfc, 0x7f, + 0xff, 0x1f, 0xcf, 0xff, 0xff, 0xf3, 0xf8, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, + 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, 0xfd, 0xff, 0x7f, 0xdf, 0xf7, 0xfd, 0xff, 0x7f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x78, 0x1e, 0x07, 0x81, 0xe0, 0x78, 0x1f, + 0xef, 0xbb, 0xee, 0xfb, 0xbe, 0xef, 0xbb, 0xef, 0xe8, 0xda, 0xb6, 0x9d, 0xb3, 0x6d, 0xda, 0x37, + 0xef, 0xda, 0xf6, 0xb5, 0xad, 0x6c, 0xdb, 0xf7, 0xe8, 0x5a, 0x36, 0x95, 0xad, 0x6c, 0xda, 0x97, + 0xef, 0xdb, 0xf6, 0x85, 0xb3, 0x6c, 0xda, 0x97, 0xea, 0x5a, 0x36, 0xb5, 0xb3, 0x6c, 0xdb, 0xf7, + 0xef, 0xda, 0xf6, 0xa5, 0xad, 0x6f, 0xda, 0x57, 0xe8, 0x5a, 0xb6, 0x85, 0xad, 0x6c, 0xda, 0x57, + 0xef, 0xdb, 0xf6, 0xfd, 0xbf, 0x6f, 0xdb, 0xf7, 0xe0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x42, 0x7c, 0x60, 0xf0, 0x78, 0x3c, 0x7f, 0xfe, 0x4a, 0x7c, 0x64, 0xf2, 0x79, 0x3c, 0x7f, + 0xfe, 0x43, 0xfe, 0x64, 0xf2, 0x79, 0x3e, 0x7f, 0xfe, 0x4e, 0x7e, 0x64, 0x92, 0x49, 0x26, 0x7f, + 0xfe, 0x4e, 0x7e, 0x60, 0x90, 0x48, 0x26, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_pairing [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0xe3, 0x98, 0x73, 0x33, 0x87, 0xff, 0xff, 0xf2, 0xc9, 0x99, 0x33, 0x13, 0x3f, 0xff, + 0xff, 0xf0, 0xc1, 0x98, 0x73, 0x03, 0x27, 0xff, 0xff, 0xf3, 0xc9, 0x98, 0x73, 0x23, 0x27, 0xff, + 0xff, 0xf3, 0xc9, 0x99, 0x33, 0x33, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_fw_update [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x98, 0x70, 0xf1, 0xc3, 0x33, 0x38, 0x7f, 0xfc, 0x99, 0x32, 0x64, 0xe7, 0x31, 0x33, 0xff, + 0xfc, 0x98, 0x72, 0x60, 0xe7, 0x30, 0x32, 0x7f, 0xfc, 0x99, 0xf2, 0x64, 0xe7, 0x32, 0x32, 0x7f, + 0xfe, 0x39, 0xf0, 0xe4, 0xe7, 0x33, 0x38, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x66, 0x1c, 0xe6, 0x73, 0x8e, 0x1c, 0x3f, 0xf9, 0xe6, 0x4c, 0x46, 0x53, 0x26, 0x4c, 0xff, + 0xf8, 0x66, 0x1c, 0x06, 0x53, 0x06, 0x1c, 0x3f, 0xf9, 0xe6, 0x1c, 0xa6, 0x03, 0x26, 0x1c, 0xff, + 0xf9, 0xe6, 0x4c, 0xe7, 0x27, 0x26, 0x4c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_version [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x99, 0x86, 0x1e, 0x19, 0xc7, 0x33, 0xff, 0xff, 0x99, 0x9e, 0x4c, 0xf9, 0x93, 0x13, 0xff, + 0xff, 0xc3, 0x86, 0x1e, 0x39, 0x93, 0x03, 0xff, 0xff, 0xc3, 0x9e, 0x1f, 0x99, 0x93, 0x23, 0xff, + 0xff, 0xe7, 0x86, 0x4c, 0x39, 0xc7, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_updating [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0x71, 0x7f, 0xff, + 0xff, 0xff, 0x7f, 0xf5, 0xff, 0x75, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0x71, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x17, 0xd4, 0x7f, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0x57, 0xd5, 0x7f, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x17, 0xd4, 0x7f, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x47, 0x44, 0x71, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0x57, 0x55, 0x75, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x47, 0x44, 0x71, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0x51, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x44, 0x51, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0x54, 0x45, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x14, 0x54, 0x45, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0xff, + 0xff, 0xff, 0x60, 0x00, 0x00, 0x03, 0x7f, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x07, 0x7f, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x5c, 0x00, 0x00, 0x1c, 0x7f, 0xff, + 0xff, 0xff, 0x56, 0x00, 0x00, 0x35, 0x7f, 0xff, 0xff, 0xff, 0x57, 0x00, 0x00, 0x74, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x44, 0xc0, 0x01, 0xd1, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x60, 0x03, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x44, 0x70, 0x07, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x14, 0x5c, 0x1d, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x56, 0x35, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x14, 0x57, 0xe5, 0x44, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0x7f, 0xff, 0xff, 0xff, 0x45, 0x44, 0x51, 0x51, 0x7f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +static unsigned char bm_def[] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x61, 0x10, 0x8c, 0x23, 0xc4, 0x3f, 0xff, + 0xb5, 0xa7, 0xb7, 0xb5, 0xed, 0xed, 0xbf, 0xff, 0xb5, 0xb9, 0xb4, 0xb4, 0x6d, 0xed, 0xbf, 0xff, + 0x85, 0xa1, 0x10, 0xb4, 0x21, 0x44, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0x1c, 0xfe, 0x7f, 0x8f, 0xf0, 0x00, + 0x1f, 0xf7, 0x9d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, 0x1c, 0x77, 0xfd, 0xc7, 0x73, 0xdc, 0x00, 0x00, + 0x1f, 0xe7, 0xfd, 0xc7, 0x71, 0xdf, 0x00, 0x00, 0x1f, 0xe7, 0x7d, 0xc7, 0x71, 0xdf, 0x00, 0x00, + 0x1c, 0x77, 0x3d, 0xc7, 0x73, 0xdc, 0x00, 0x00, 0x1c, 0x77, 0x1d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, + 0x1c, 0x77, 0x1c, 0xfe, 0x7f, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, + 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x62, 0x24, 0x49, 0x22, 0x4e, 0x44, + 0x00, 0x24, 0x93, 0x66, 0xc9, 0x32, 0x44, 0x28, 0x00, 0x20, 0x92, 0xa5, 0x49, 0x2a, 0x44, 0x10, + 0x00, 0x24, 0x92, 0x24, 0x49, 0x26, 0x44, 0x10, 0x00, 0x18, 0x62, 0x24, 0x46, 0x22, 0x44, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0x9c, 0x44, 0x88, 0xc7, 0x1c, 0x00, 0x00, 0x10, 0x92, 0x6c, 0xa9, 0x24, 0x90, + 0x00, 0x00, 0x1c, 0x9c, 0x54, 0xa9, 0xe7, 0x1c, 0x00, 0x00, 0x10, 0x94, 0x44, 0xa9, 0x25, 0x10, + 0x00, 0x00, 0x10, 0x92, 0x44, 0x51, 0x24, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_def_lc [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x61, 0x10, 0x8c, 0x23, 0xc4, 0x3f, 0xff, + 0xb5, 0xa7, 0xb7, 0xb5, 0xed, 0xed, 0xbf, 0xff, 0xb5, 0xb9, 0xb4, 0xb4, 0x6d, 0xed, 0xbf, 0xff, + 0x85, 0xa1, 0x10, 0xb4, 0x21, 0x44, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xe7, 0x1c, 0xfe, 0x7f, 0x8f, 0xf0, 0x00, + 0x1f, 0xf7, 0x9d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, 0x1c, 0x77, 0xfd, 0xc7, 0x73, 0xdc, 0x00, 0x00, + 0x1f, 0xe7, 0xfd, 0xc7, 0x71, 0xdf, 0x00, 0x00, 0x1f, 0xe7, 0x7d, 0xc7, 0x71, 0xdf, 0x00, 0x00, + 0x1c, 0x77, 0x3d, 0xc7, 0x73, 0xdc, 0x00, 0x00, 0x1c, 0x77, 0x1d, 0xff, 0x7f, 0x9f, 0xf0, 0x00, + 0x1c, 0x77, 0x1c, 0xfe, 0x7f, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, + 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0x39, 0x10, 0x61, 0x88, 0x91, 0x1c, + 0x02, 0x49, 0x21, 0x90, 0x92, 0x4d, 0x9b, 0x20, 0x02, 0x4e, 0x39, 0x50, 0x82, 0x4a, 0x95, 0x18, + 0x02, 0x48, 0x21, 0x30, 0x92, 0x48, 0x91, 0x04, 0x01, 0x88, 0x39, 0x10, 0x61, 0x88, 0x91, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xc8, 0x8e, 0x73, 0x91, 0x1c, 0x00, 0x00, 0x02, 0x05, 0x10, 0x22, 0x1b, 0x20, + 0x00, 0x00, 0x01, 0x82, 0x0c, 0x23, 0x95, 0x18, 0x00, 0x00, 0x00, 0x42, 0x02, 0x22, 0x11, 0x04, + 0x00, 0x00, 0x03, 0x82, 0x1c, 0x23, 0x91, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_hwok [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf2, 0x71, 0xc3, 0x87, 0x39, 0xc7, 0x0e, 0x1f, 0xf2, 0x64, 0xc9, 0x93, 0x29, 0x93, 0x26, 0x7f, + 0xf0, 0x60, 0xc3, 0x93, 0x29, 0x83, 0x0e, 0x1f, 0xf2, 0x64, 0xc3, 0x93, 0x01, 0x93, 0x0e, 0x7f, + 0xf2, 0x64, 0xc9, 0x87, 0x93, 0x93, 0x26, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x33, 0x30, 0xff, 0x8e, 0x4f, 0xff, + 0xff, 0xf3, 0x13, 0x39, 0xff, 0x26, 0x1f, 0xff, 0xff, 0xf3, 0x03, 0x39, 0xff, 0x26, 0x3f, 0xff, + 0xff, 0xf3, 0x23, 0x39, 0xff, 0x26, 0x1f, 0xff, 0xff, 0xf3, 0x33, 0x39, 0xff, 0x8e, 0x4f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc3, 0x0e, 0x67, 0xf8, 0x70, 0xe3, 0x87, 0x33, 0xe7, 0x27, 0x0f, 0xf9, 0x33, 0xc9, 0x93, 0x87, + 0xe7, 0x0f, 0x9f, 0xf8, 0x70, 0xc1, 0x93, 0xcf, 0xe7, 0x0f, 0x0f, 0xf8, 0x73, 0xc9, 0x93, 0xcf, + 0xe7, 0x26, 0x67, 0xf9, 0x30, 0xc9, 0x87, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_console_active [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x8e, 0x67, 0x0e, 0x39, 0xe1, 0xff, + 0xff, 0x93, 0x26, 0x26, 0x7c, 0x99, 0xe7, 0xff, 0xff, 0x9f, 0x26, 0x07, 0x1c, 0x99, 0xe1, 0xff, + 0xff, 0x93, 0x26, 0x47, 0xcc, 0x99, 0xe7, 0xff, 0xff, 0xc7, 0x8e, 0x66, 0x1e, 0x38, 0x61, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3c, 0x70, 0xcc, 0xcc, 0x3f, 0xff, + 0xff, 0xfc, 0x99, 0x39, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xfc, 0x19, 0xf9, 0xce, 0x1c, 0x3f, 0xff, + 0xff, 0xfc, 0x99, 0x39, 0xce, 0x1c, 0xff, 0xff, 0xff, 0xfc, 0x9c, 0x79, 0xcf, 0x3c, 0x3f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_checks [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0x0c, 0x99, 0xc7, 0x0f, + 0xe6, 0x00, 0x7f, 0x93, 0x3c, 0x99, 0x93, 0x3f, 0xe6, 0x00, 0x7f, 0x93, 0x0e, 0x39, 0x9f, 0x0f, + 0xff, 0xff, 0xff, 0x93, 0x3e, 0x39, 0x93, 0x3f, 0xff, 0xff, 0xff, 0x87, 0x0f, 0x79, 0xc7, 0x0f, + 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x39, 0x30, 0xe3, 0x93, 0x87, + 0xe6, 0x00, 0x7c, 0x99, 0x33, 0xc9, 0x87, 0x3f, 0xe6, 0x00, 0x7c, 0xf8, 0x30, 0xcf, 0x8f, 0x8f, + 0xff, 0xff, 0xfc, 0x99, 0x33, 0xc9, 0x87, 0xe7, 0xff, 0xff, 0xfe, 0x39, 0x30, 0xe3, 0x93, 0x0f, + 0xe6, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x00, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x9c, 0x3c, 0x78, 0x70, 0xc3, 0x0f, + 0xe6, 0x0d, 0x3c, 0x99, 0x33, 0xe7, 0xcf, 0x27, 0xe6, 0x04, 0x7c, 0x38, 0x38, 0xf1, 0xc3, 0x27, + 0xff, 0xfe, 0xfc, 0xf9, 0x3e, 0x7c, 0xcf, 0x27, 0xff, 0xff, 0xfc, 0xf9, 0x30, 0xe1, 0xc3, 0x0f, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_frame [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0x40, 0x02, 0x0f, 0xff, 0xfc, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x1e, 0x40, 0x02, 0x78, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x3f, 0xff, 0xf2, 0x40, 0x02, 0x4f, 0xff, 0xfc, + 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x03, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x40, 0x02, 0x40, 0x00, 0x00, 0x3f, 0xff, 0xf2, 0x40, 0x02, 0x4f, 0xff, 0xfc, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, 0x20, 0x00, 0x12, 0x40, 0x02, 0x48, 0x00, 0x04, + 0x20, 0x00, 0x1e, 0x40, 0x02, 0x78, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, + 0x20, 0x00, 0x10, 0x40, 0x02, 0x08, 0x00, 0x04, 0x3f, 0xff, 0xf0, 0x40, 0x02, 0x0f, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaa, 0x8a, 0xaa, 0x80 +}; + +const unsigned char bm_online [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x1c, 0x66, 0x61, 0x8c, 0x24, 0x90, 0x87, + 0xe6, 0x49, 0x22, 0x4f, 0x24, 0xe4, 0x93, 0x93, 0xe6, 0x18, 0x20, 0x63, 0x3c, 0x26, 0x30, 0x87, + 0xe6, 0x19, 0x24, 0x79, 0x24, 0xe6, 0x33, 0x87, 0xe6, 0x49, 0x26, 0x43, 0x8c, 0x27, 0x70, 0x93, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xe6, 0x73, 0xe7, 0x33, 0x87, 0xff, + 0xff, 0xe4, 0xe2, 0x73, 0xe7, 0x13, 0x9f, 0xff, 0xff, 0xe4, 0xe0, 0x73, 0xe7, 0x03, 0x87, 0xff, + 0xff, 0xe4, 0xe4, 0x73, 0xe7, 0x23, 0x9f, 0xff, 0xff, 0xf1, 0xe6, 0x70, 0xe7, 0x33, 0x87, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_fw_corrupt [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x30, 0xe7, 0x33, 0x9c, 0x70, 0xe1, 0xff, + 0xcf, 0x32, 0x62, 0x32, 0x99, 0x32, 0x67, 0xff, 0xc3, 0x30, 0xe0, 0x32, 0x98, 0x30, 0xe1, 0xff, + 0xcf, 0x30, 0xe5, 0x30, 0x19, 0x30, 0xe7, 0xff, 0xcf, 0x32, 0x67, 0x39, 0x39, 0x32, 0x61, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xc7, 0x0e, 0x1c, 0x98, 0x70, 0xfc, 0xff, + 0xc9, 0x93, 0x26, 0x4c, 0x99, 0x39, 0xfb, 0x7f, 0xcf, 0x93, 0x0e, 0x1c, 0x98, 0x79, 0xfb, 0x7f, + 0xc9, 0x93, 0x0e, 0x1c, 0x99, 0xf9, 0xf7, 0xbf, 0xe3, 0xc7, 0x26, 0x4e, 0x39, 0xf9, 0xf4, 0xbf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xec, 0xdf, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xef, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xf7, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfb, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +const unsigned char bm_plug [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x7f, 0x80, 0x55, 0xfc, 0x00, 0xaa, 0xfc, 0x00, 0x00, + 0x7f, 0x80, 0x00, 0x1c, 0x00 +}; + +const unsigned char bm_hg_low [] PROGMEM = { + 0xf8, 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0xf8, 0xf8 +}; + +const unsigned char bm_hg_high [] PROGMEM = { + 0xf8, 0x88, 0xf8, 0x70, 0x20, 0x70, 0xf8, 0xf8, 0xf8 +}; + +const unsigned char bm_n_uh [] PROGMEM = { + 0x07, 0x27, 0x27, 0x27, 0x07, 0x8f, 0x8f, 0xcf, 0xcf, 0xcf, 0x07, 0xe7, 0x07, 0x3f, 0x07, 0x07, + 0xe7, 0xc7, 0xe7, 0x07, 0x27, 0x27, 0x07, 0xe7, 0xe7, 0x07, 0x3f, 0x07, 0xe7, 0x07, 0x07, 0x3f, + 0x07, 0x27, 0x07, 0x07, 0xc7, 0xcf, 0x9f, 0x1f, 0x07, 0x27, 0x07, 0x27, 0x07, 0x07, 0x27, 0x07, + 0xe7, 0xe7 +}; + +const unsigned char bm_dot_sqr [] PROGMEM = { + 0xaa, 0xd5, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0xaa, 0xd5, 0x40 +}; #endif diff --git a/Graphics/Bitmaps/banner_boot.bmp b/Graphics/Bitmaps/banner_boot.bmp new file mode 100644 index 0000000..0004681 Binary files /dev/null and b/Graphics/Bitmaps/banner_boot.bmp differ diff --git a/Graphics/Bitmaps/banner_checks.bmp b/Graphics/Bitmaps/banner_checks.bmp new file mode 100644 index 0000000..b38c4ab Binary files /dev/null and b/Graphics/Bitmaps/banner_checks.bmp differ diff --git a/Graphics/Bitmaps/banner_console.bmp b/Graphics/Bitmaps/banner_console.bmp new file mode 100644 index 0000000..5fadff2 Binary files /dev/null and b/Graphics/Bitmaps/banner_console.bmp differ diff --git a/Graphics/Bitmaps/banner_fw_corrupt.bmp b/Graphics/Bitmaps/banner_fw_corrupt.bmp new file mode 100644 index 0000000..a576097 Binary files /dev/null and b/Graphics/Bitmaps/banner_fw_corrupt.bmp differ diff --git a/Graphics/Bitmaps/banner_fw_update.bmp b/Graphics/Bitmaps/banner_fw_update.bmp new file mode 100644 index 0000000..f975a65 Binary files /dev/null and b/Graphics/Bitmaps/banner_fw_update.bmp differ diff --git a/Graphics/Bitmaps/banner_hwfail.bmp b/Graphics/Bitmaps/banner_hwfail.bmp new file mode 100644 index 0000000..e79217b Binary files /dev/null and b/Graphics/Bitmaps/banner_hwfail.bmp differ diff --git a/Graphics/Bitmaps/banner_hwok.bmp b/Graphics/Bitmaps/banner_hwok.bmp new file mode 100644 index 0000000..4d546ba Binary files /dev/null and b/Graphics/Bitmaps/banner_hwok.bmp differ diff --git a/Graphics/Bitmaps/banner_nfr.bmp b/Graphics/Bitmaps/banner_nfr.bmp new file mode 100644 index 0000000..e89c41f Binary files /dev/null and b/Graphics/Bitmaps/banner_nfr.bmp differ diff --git a/Graphics/Bitmaps/banner_no_radio.bmp b/Graphics/Bitmaps/banner_no_radio.bmp new file mode 100644 index 0000000..e20ca74 Binary files /dev/null and b/Graphics/Bitmaps/banner_no_radio.bmp differ diff --git a/Graphics/Bitmaps/banner_online.bmp b/Graphics/Bitmaps/banner_online.bmp new file mode 100644 index 0000000..7906578 Binary files /dev/null and b/Graphics/Bitmaps/banner_online.bmp differ diff --git a/Graphics/Bitmaps/banner_pairing.bmp b/Graphics/Bitmaps/banner_pairing.bmp new file mode 100644 index 0000000..5dfd4bb Binary files /dev/null and b/Graphics/Bitmaps/banner_pairing.bmp differ diff --git a/Graphics/Bitmaps/banner_version.bmp b/Graphics/Bitmaps/banner_version.bmp new file mode 100644 index 0000000..da02744 Binary files /dev/null and b/Graphics/Bitmaps/banner_version.bmp differ diff --git a/Graphics/Bitmaps/bm_pairing.bmp b/Graphics/Bitmaps/bm_pairing.bmp new file mode 100644 index 0000000..c4e5fa5 Binary files /dev/null and b/Graphics/Bitmaps/bm_pairing.bmp differ diff --git a/Graphics/Bitmaps/bm_update.bmp b/Graphics/Bitmaps/bm_update.bmp new file mode 100644 index 0000000..db3a180 Binary files /dev/null and b/Graphics/Bitmaps/bm_update.bmp differ diff --git a/Graphics/Bitmaps/bt_icons.bmp b/Graphics/Bitmaps/bt_icons.bmp new file mode 100644 index 0000000..5da2aa9 Binary files /dev/null and b/Graphics/Bitmaps/bt_icons.bmp differ diff --git a/Graphics/Bitmaps/cable_icons.bmp b/Graphics/Bitmaps/cable_icons.bmp new file mode 100644 index 0000000..3521717 Binary files /dev/null and b/Graphics/Bitmaps/cable_icons.bmp differ diff --git a/Graphics/Bitmaps/console_icon.bmp b/Graphics/Bitmaps/console_icon.bmp new file mode 100644 index 0000000..fd3a015 Binary files /dev/null and b/Graphics/Bitmaps/console_icon.bmp differ diff --git a/Graphics/Bitmaps/default_fb.bmp b/Graphics/Bitmaps/default_fb.bmp new file mode 100644 index 0000000..01e472c Binary files /dev/null and b/Graphics/Bitmaps/default_fb.bmp differ diff --git a/Graphics/Bitmaps/default_fb_alt.bmp b/Graphics/Bitmaps/default_fb_alt.bmp new file mode 100644 index 0000000..fb9d03d Binary files /dev/null and b/Graphics/Bitmaps/default_fb_alt.bmp differ diff --git a/Graphics/Bitmaps/default_fb_lc.bmp b/Graphics/Bitmaps/default_fb_lc.bmp new file mode 100644 index 0000000..f6d4442 Binary files /dev/null and b/Graphics/Bitmaps/default_fb_lc.bmp differ diff --git a/Graphics/Bitmaps/frame.bmp b/Graphics/Bitmaps/frame.bmp new file mode 100644 index 0000000..d9d7ffc Binary files /dev/null and b/Graphics/Bitmaps/frame.bmp differ diff --git a/Graphics/Bitmaps/hourglass_high.png b/Graphics/Bitmaps/hourglass_high.png new file mode 100644 index 0000000..a149af7 Binary files /dev/null and b/Graphics/Bitmaps/hourglass_high.png differ diff --git a/Graphics/Bitmaps/hourglass_low.png b/Graphics/Bitmaps/hourglass_low.png new file mode 100644 index 0000000..ec199ec Binary files /dev/null and b/Graphics/Bitmaps/hourglass_low.png differ diff --git a/Graphics/Bitmaps/numbers_upheaval.bmp b/Graphics/Bitmaps/numbers_upheaval.bmp new file mode 100644 index 0000000..d50e1fb Binary files /dev/null and b/Graphics/Bitmaps/numbers_upheaval.bmp differ diff --git a/Graphics/Bitmaps/plug.bmp b/Graphics/Bitmaps/plug.bmp new file mode 100644 index 0000000..1258b5a Binary files /dev/null and b/Graphics/Bitmaps/plug.bmp differ diff --git a/Graphics/Bitmaps/rf_icons.bmp b/Graphics/Bitmaps/rf_icons.bmp new file mode 100644 index 0000000..7913a96 Binary files /dev/null and b/Graphics/Bitmaps/rf_icons.bmp differ diff --git a/Graphics/Bitmaps/sideband_fb.bmp b/Graphics/Bitmaps/sideband_fb.bmp new file mode 100644 index 0000000..24f12c5 Binary files /dev/null and b/Graphics/Bitmaps/sideband_fb.bmp differ diff --git a/Graphics/Design/Bluetooth.kra b/Graphics/Design/Bluetooth.kra new file mode 100644 index 0000000..241f24e Binary files /dev/null and b/Graphics/Design/Bluetooth.kra differ diff --git a/Graphics/Design/Text.xcf b/Graphics/Design/Text.xcf new file mode 100644 index 0000000..6686b09 Binary files /dev/null and b/Graphics/Design/Text.xcf differ diff --git a/Graphics/Design/banners.kra b/Graphics/Design/banners.kra new file mode 100644 index 0000000..230d6ab Binary files /dev/null and b/Graphics/Design/banners.kra differ diff --git a/Graphics/Design/cable_icons.kra b/Graphics/Design/cable_icons.kra new file mode 100644 index 0000000..a7f45de Binary files /dev/null and b/Graphics/Design/cable_icons.kra differ diff --git a/Graphics/Design/console_icon.kra b/Graphics/Design/console_icon.kra new file mode 100644 index 0000000..bdbf69f Binary files /dev/null and b/Graphics/Design/console_icon.kra differ diff --git a/Graphics/Design/cs.kra b/Graphics/Design/cs.kra new file mode 100644 index 0000000..e105cda Binary files /dev/null and b/Graphics/Design/cs.kra differ diff --git a/Graphics/Design/default_fb.kra b/Graphics/Design/default_fb.kra new file mode 100644 index 0000000..ef8d030 Binary files /dev/null and b/Graphics/Design/default_fb.kra differ diff --git a/Graphics/Design/default_fb_alt.kra b/Graphics/Design/default_fb_alt.kra new file mode 100644 index 0000000..4053839 Binary files /dev/null and b/Graphics/Design/default_fb_alt.kra differ diff --git a/Graphics/Design/firware_update_icon.kra b/Graphics/Design/firware_update_icon.kra new file mode 100644 index 0000000..b5ac329 Binary files /dev/null and b/Graphics/Design/firware_update_icon.kra differ diff --git a/Graphics/Design/frame.kra b/Graphics/Design/frame.kra new file mode 100644 index 0000000..5135fce Binary files /dev/null and b/Graphics/Design/frame.kra differ diff --git a/Graphics/Design/icons.kra b/Graphics/Design/icons.kra new file mode 100644 index 0000000..6626014 Binary files /dev/null and b/Graphics/Design/icons.kra differ diff --git a/Graphics/Design/numbers_silkscreen.kra b/Graphics/Design/numbers_silkscreen.kra new file mode 100644 index 0000000..f6910f3 Binary files /dev/null and b/Graphics/Design/numbers_silkscreen.kra differ diff --git a/Graphics/Design/numbers_upheaval.kra b/Graphics/Design/numbers_upheaval.kra new file mode 100644 index 0000000..2a6ee1e Binary files /dev/null and b/Graphics/Design/numbers_upheaval.kra differ diff --git a/Graphics/Design/plug.kra b/Graphics/Design/plug.kra new file mode 100644 index 0000000..777be0a Binary files /dev/null and b/Graphics/Design/plug.kra differ diff --git a/Graphics/Design/r_icon.kra b/Graphics/Design/r_icon.kra new file mode 100644 index 0000000..de91694 Binary files /dev/null and b/Graphics/Design/r_icon.kra differ diff --git a/Graphics/Design/rf_icons.kra b/Graphics/Design/rf_icons.kra new file mode 100644 index 0000000..3157b86 Binary files /dev/null and b/Graphics/Design/rf_icons.kra differ diff --git a/Graphics/Design/sideband_fb.kra b/Graphics/Design/sideband_fb.kra new file mode 100644 index 0000000..57c73c6 Binary files /dev/null and b/Graphics/Design/sideband_fb.kra differ diff --git a/Makefile b/Makefile index a57931d..8994971 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,179 +13,214 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -ESP_IDF_VER = 2.0.17 +# Version 2.0.17 of the Arduino ESP core is based on ESP-IDF v4.4.7 +ARDUINO_ESP_CORE_VER = 2.0.17 + +V ?= 0 +VFLAG = +ifeq "$(V)" "1" +VFLAG =-v +endif + +COMMON_BUILD_FLAGS = $(VFLAG) -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" +COMMON_ESP_UPLOAD_FlAGS = $(VFLAG) --chip esp32 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 all: release clean: - -rm -r ./build - -rm ./Release/rnode_firmware* + -rm -rf ./build + -rm -f ./Release/rnode_firmware* -prep: prep-esp32 prep-nrf prep-samd +prep: prep-esp32 prep-nrf + +prep-index: + arduino-cli core update-index --config-file arduino-cli.yaml prep-esp32: - arduino-cli core update-index --config-file arduino-cli.yaml - arduino-cli core install esp32:esp32@2.0.17 --config-file arduino-cli.yaml + arduino-cli core install esp32:esp32@$(ARDUINO_ESP_CORE_VER) --config-file arduino-cli.yaml arduino-cli lib install "Adafruit SSD1306" + arduino-cli lib install "Adafruit SH110X" + arduino-cli lib install "Adafruit ST7735 and ST7789 Library" + arduino-cli lib install "Adafruit NeoPixel" arduino-cli lib install "XPowersLib" arduino-cli lib install "Crypto" + arduino-cli lib install "Adafruit NeoPixel" pip install pyserial rns --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error. -prep-samd: - arduino-cli core update-index --config-file arduino-cli.yaml - arduino-cli core install adafruit:samd --config-file arduino-cli.yaml - prep-nrf: - arduino-cli core update-index --config-file arduino-cli.yaml arduino-cli core install adafruit:nrf52 --config-file arduino-cli.yaml arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml arduino-cli lib install "Crypto" arduino-cli lib install "Adafruit GFX Library" arduino-cli lib install "GxEPD2" - pip install pyserial rns --upgrade --user --break-system-packages + pip install pyserial rns --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error. pip install adafruit-nrfutil --upgrade --user --break-system-packages # This looks scary, but it's actually just telling pip to install packages as a user instead of trying to install them systemwide, which bypasses the "externally managed environment" error. console-site: make -C Console clean site -spiffs: console-site spiffs-image +spiffs: console-site spiffs-image spiffs-image: python3 Release/esptool/spiffsgen.py 1966080 ./Console/build Release/console_image.bin upload-spiffs: @echo Deploying SPIFFS image... - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin -firmware-tbeam: - arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" +firmware: $(shell grep ^firmware- Makefile | cut -d: -f1) -firmware-tbeam_sx126x: - arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\"" +check_bt_buffers: + @./esp32_btbufs.py ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/libraries/BluetoothSerial/src/BluetoothSerial.cpp + +firmware-tbeam: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE4\"" + +firmware-tbeam_sx1262: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE8\"" firmware-techo: firmware-techo4 firmware-techo9 firmware-techo4: - arduino-cli compile --fqbn adafruit:nrf52:pca10056 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x16\"" + arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x16\"" firmware-techo9: - arduino-cli compile --fqbn adafruit:nrf52:pca10056 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x17\"" + arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x17\"" -firmware-t3s3_sx1262: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA1\"" +firmware-t3s3: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xAB\"" + +firmware-t3s3_sx126x: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA1\"" firmware-t3s3_sx1280_pa: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA5\"" + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xAB\"" -firmware-lora32_v10: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" +firmware-e22_esp32: + arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DEXTERNAL_LEDS=true\"" -firmware-lora32_v10_extled: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\" \"-DEXTERNAL_LEDS=true\"" +firmware-lora32_v10: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" -firmware-lora32_v20: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\" \"-DEXTERNAL_LEDS=true\"" +firmware-lora32_v10_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\" \"-DEXTERNAL_LEDS=true\"" -firmware-lora32_v21: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" +firmware-lora32_v20: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\" \"-DEXTERNAL_LEDS=true\"" -firmware-lora32_v21_extled: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DEXTERNAL_LEDS=true\"" +firmware-lora32_v21: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" -firmware-lora32_v21_tcxo: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\"" +firmware-lora32_v21_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DEXTERNAL_LEDS=true\"" -firmware-heltec32_v2: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\"" +firmware-lora32_v21_tcxo: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\"" -firmware-heltec32_v2_extled: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\"" +firmware-heltec32_v2: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\"" + +firmware-heltec32_v2_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\"" firmware-heltec32_v3: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" -firmware-rnode_ng_20: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\"" +firmware-rnode_ng_20: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\"" -firmware-rnode_ng_21: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\"" +firmware-rnode_ng_21: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\"" -firmware-featheresp32: - arduino-cli compile --fqbn esp32:esp32:featheresp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" +firmware-featheresp32: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" -firmware-genericesp32: - arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" +firmware-genericesp32: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" firmware-rak4631: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" firmware-rak4631_sx1280: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x14\"" + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x14\"" -firmware-freenode: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x52\" \"-DBOARD_VARIANT=0x21\"" +firmware-opencom-xl: + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x52\" \"-DBOARD_VARIANT=0x21\"" upload-tbeam: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:t-beam @sleep 1 rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin upload-techo: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn adafruit:nrf52:pca10056 unzip -o build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.zip -d build/adafruit.nrf52.pca10056 - #rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.bin | grep -o '^\S*') - ../Reticulum/RNS/Utilities/rnodeconf.py $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.bin | grep -o '^\S*') + rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.bin | grep -o '^\S*') upload-lora32_v10: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-lora32_v20: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-lora32_v21: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-heltec32_v2: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V2 @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-heltec32_v3: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V3 @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32-s3 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + +upload-tdeck: + arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 + @sleep 1 + rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32-s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + +upload-tbeam_supreme: + arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 + @sleep 1 + rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32-s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin upload-rnode_ng_20: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-rnode_ng_21: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-t3s3: @echo @@ -193,7 +228,7 @@ upload-t3s3: @read arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 @sleep 2 - python3 ./Release/esptool/esptool.py --chip esp32s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python ./Release/esptool/esptool.py --chip esp32s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin @echo @echo Press the RESET button on the board now, and hit enter @read @@ -205,9 +240,9 @@ upload-featheresp32: @sleep 1 rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.featheresp32/opencom_xl_firmware.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32 --port $(or $(port), /dev/ttyUSB0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin -upload-freenode: +upload-opencom-xl: arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/opencom_xl_firmware.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/opencom_xl_firmware.ino.bin | grep -o '^\S*') @@ -218,15 +253,20 @@ upload-freenode: @sleep 3 python3 rnodeconf.py /dev/ttyACM0 --set-firmware-length $$(ls -l ./build/rakwireless.nrf52.WisCoreRAK4631Board/opencom_xl_firmware.ino.bin | awk '{print $$5}') -release: release-all +upload-e22_esp32: + arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:esp32 + @sleep 1 + rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin) + @sleep 3 + python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin -release-all: console-site spiffs-image release-tbeam release-tbeam_sx1262 release-lora32_v10 release-lora32_v20 release-lora32_v21 release-lora32_v10_extled release-lora32_v20_extled release-lora32_v21_extled release-lora32_v21_tcxo release-featheresp32 release-genericesp32 release-heltec32_v2 release-heltec32_v3 release-heltec32_v2_extled release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-hashes +release: console-site spiffs-image $(shell grep ^release- Makefile | cut -d: -f1) release-hashes: python3 ./release_hashes.py > ./Release/release.json -release-tbeam: - arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" +release-tbeam: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE4\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam.boot_app0 cp build/esp32.esp32.t-beam/opencom_xl_firmware.ino.bin build/rnode_firmware_tbeam.bin cp build/esp32.esp32.t-beam/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_tbeam.bootloader @@ -234,8 +274,8 @@ release-tbeam: zip --junk-paths ./Release/rnode_firmware_tbeam.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam.boot_app0 build/rnode_firmware_tbeam.bin build/rnode_firmware_tbeam.bootloader build/rnode_firmware_tbeam.partitions rm -r build -release-tbeam_sx1262: - arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\"" +release-tbeam_sx1262: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_MODEL=E8\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_sx1262.boot_app0 cp build/esp32.esp32.t-beam/opencom_xl_firmware.ino.bin build/rnode_firmware_tbeam_sx1262.bin cp build/esp32.esp32.t-beam/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_tbeam_sx1262.bootloader @@ -243,8 +283,8 @@ release-tbeam_sx1262: zip --junk-paths ./Release/rnode_firmware_tbeam_sx1262.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_sx1262.boot_app0 build/rnode_firmware_tbeam_sx1262.bin build/rnode_firmware_tbeam_sx1262.bootloader build/rnode_firmware_tbeam_sx1262.partitions rm -r build -release-lora32_v10: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" +release-lora32_v10: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v10.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v10.bootloader @@ -252,8 +292,8 @@ release-lora32_v10: zip --junk-paths ./Release/rnode_firmware_lora32v10.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v10.boot_app0 build/rnode_firmware_lora32v10.bin build/rnode_firmware_lora32v10.bootloader build/rnode_firmware_lora32v10.partitions rm -r build -release-lora32_v20: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\"" +release-lora32_v20: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v20.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v20.bootloader @@ -261,8 +301,8 @@ release-lora32_v20: zip --junk-paths ./Release/rnode_firmware_lora32v20.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v20.boot_app0 build/rnode_firmware_lora32v20.bin build/rnode_firmware_lora32v20.bootloader build/rnode_firmware_lora32v20.partitions rm -r build -release-lora32_v21: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" +release-lora32_v21: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v21.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v21.bootloader @@ -270,8 +310,8 @@ release-lora32_v21: zip --junk-paths ./Release/rnode_firmware_lora32v21.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21.boot_app0 build/rnode_firmware_lora32v21.bin build/rnode_firmware_lora32v21.bootloader build/rnode_firmware_lora32v21.partitions rm -r build -release-lora32_v10_extled: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\" \"-DEXTERNAL_LEDS=true\"" +release-lora32_v10_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v10.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v10.bootloader @@ -279,8 +319,8 @@ release-lora32_v10_extled: zip --junk-paths ./Release/rnode_firmware_lora32v10.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v10.boot_app0 build/rnode_firmware_lora32v10.bin build/rnode_firmware_lora32v10.bootloader build/rnode_firmware_lora32v10.partitions rm -r build -release-lora32_v20_extled: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\" \"-DEXTERNAL_LEDS=true\"" +release-lora32_v20_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v20.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v20.bootloader @@ -288,8 +328,8 @@ release-lora32_v20_extled: zip --junk-paths ./Release/rnode_firmware_lora32v20_extled.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v20.boot_app0 build/rnode_firmware_lora32v20.bin build/rnode_firmware_lora32v20.bootloader build/rnode_firmware_lora32v20.partitions rm -r build -release-lora32_v21_extled: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DEXTERNAL_LEDS=true\"" +release-lora32_v21_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v21.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v21.bootloader @@ -297,8 +337,8 @@ release-lora32_v21_extled: zip --junk-paths ./Release/rnode_firmware_lora32v21_extled.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21.boot_app0 build/rnode_firmware_lora32v21.bin build/rnode_firmware_lora32v21.bootloader build/rnode_firmware_lora32v21.partitions rm -r build -release-lora32_v21_tcxo: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\"" +release-lora32_v21_tcxo: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21_tcxo.boot_app0 cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_lora32v21_tcxo.bin cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_lora32v21_tcxo.bootloader @@ -306,53 +346,51 @@ release-lora32_v21_tcxo: zip --junk-paths ./Release/rnode_firmware_lora32v21_tcxo.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21_tcxo.boot_app0 build/rnode_firmware_lora32v21_tcxo.bin build/rnode_firmware_lora32v21_tcxo.bootloader build/rnode_firmware_lora32v21_tcxo.partitions rm -r build -release-heltec32_v2: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\"" +release-heltec32_v2: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0 - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.bin build/rnode_firmware_heltec32v2.bin - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions - zip --junk-paths ./Release/rnode_firmware_heltec32v2.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v2.boot_app0 build/rnode_firmware_heltec32v2.bin build/rnode_firmware_heltec32v2.bootloader build/rnode_firmware_heltec32v2.partitions - rm -r build + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltec32v2.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions release-heltec32_v3: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v3.boot_app0 - cp build/esp32.esp32.heltec_wifi_lora_32_V3/opencom_xl_firmware.ino.bin build/rnode_firmware_heltec32v3.bin - cp build/esp32.esp32.heltec_wifi_lora_32_V3/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader - cp build/esp32.esp32.heltec_wifi_lora_32_V3/opencom_xl_firmware.ino.partitions.bin build/rnode_firmware_heltec32v3.partitions + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v3.boot_app0 + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v3.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v3.partitions zip --junk-paths ./Release/rnode_firmware_heltec32v3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v3.boot_app0 build/rnode_firmware_heltec32v3.bin build/rnode_firmware_heltec32v3.bootloader build/rnode_firmware_heltec32v3.partitions rm -r build -release-heltec32_v2_extled: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0 - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.bin build/rnode_firmware_heltec32v2.bin - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader - cp build/esp32.esp32.heltec_wifi_lora_32_V2/opencom_xl_firmware.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions +release-heltec32_v2_extled: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0 + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v2.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions zip --junk-paths ./Release/rnode_firmware_heltec32v2.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v2.boot_app0 build/rnode_firmware_heltec32v2.bin build/rnode_firmware_heltec32v2.bootloader build/rnode_firmware_heltec32v2.partitions rm -r build -release-rnode_ng_20: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng20.boot_app0 - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_ng20.bin - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_ng20.bootloader - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.partitions.bin build/rnode_firmware_ng20.partitions +release-rnode_ng_20: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng20.boot_app0 + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng20.bin + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng20.bootloader + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng20.partitions zip --junk-paths ./Release/rnode_firmware_ng20.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng20.boot_app0 build/rnode_firmware_ng20.bin build/rnode_firmware_ng20.bootloader build/rnode_firmware_ng20.partitions rm -r build -release-rnode_ng_21: - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng21.boot_app0 - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bin build/rnode_firmware_ng21.bin - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_ng21.bootloader - cp build/esp32.esp32.ttgo-lora32/opencom_xl_firmware.ino.partitions.bin build/rnode_firmware_ng21.partitions +release-rnode_ng_21: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x41\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng21.boot_app0 + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng21.bin + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng21.bootloader + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng21.partitions zip --junk-paths ./Release/rnode_firmware_ng21.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng21.boot_app0 build/rnode_firmware_ng21.bin build/rnode_firmware_ng21.bootloader build/rnode_firmware_ng21.partitions rm -r build release-t3s3: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\"" + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_MODEL=0xAB\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3.boot_app0 cp build/esp32.esp32.esp32s3/opencom_xl_firmware.ino.bin build/rnode_firmware_t3s3.bin cp build/esp32.esp32.esp32s3/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_t3s3.bootloader @@ -360,8 +398,45 @@ release-t3s3: zip --junk-paths ./Release/rnode_firmware_t3s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3.boot_app0 build/rnode_firmware_t3s3.bin build/rnode_firmware_t3s3.bootloader build/rnode_firmware_t3s3.partitions rm -r build -release-featheresp32: - arduino-cli compile --fqbn esp32:esp32:featheresp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" +release-e22_esp32: + arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_e22.boot_app0 + cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin build/rnode_firmware_esp32_e22.bin + cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_esp32_e22.bootloader + cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_esp32_e22.partitions + zip --junk-paths ./Release/rnode_firmware_esp32_e22.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_esp32_e22.boot_app0 build/rnode_firmware_esp32_e22.bin build/rnode_firmware_esp32_e22.bootloader build/rnode_firmware_esp32_e22.partitions + rm -r build + +release-t3s3_sx126x: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_MODEL=0xA1\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx126x.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_t3s3_sx126x.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_t3s3_sx126x.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_t3s3_sx126x.partitions + zip --junk-paths ./Release/rnode_firmware_t3s3_sx126x.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx126x.boot_app0 build/rnode_firmware_t3s3_sx126x.bin build/rnode_firmware_t3s3_sx126x.bootloader build/rnode_firmware_t3s3_sx126x.partitions + rm -r build + +release-tdeck: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tdeck.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tdeck.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tdeck.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tdeck.partitions + zip --junk-paths ./Release/rnode_firmware_tdeck.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tdeck.boot_app0 build/rnode_firmware_tdeck.bin build/rnode_firmware_tdeck.bootloader build/rnode_firmware_tdeck.partitions + rm -r build + +release-tbeam_supreme: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3D\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_supreme.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tbeam_supreme.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tbeam_supreme.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tbeam_supreme.partitions + zip --junk-paths ./Release/rnode_firmware_tbeam_supreme.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_supreme.boot_app0 build/rnode_firmware_tbeam_supreme.bin build/rnode_firmware_tbeam_supreme.bootloader build/rnode_firmware_tbeam_supreme.partitions + rm -r build + + +release-featheresp32: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0 cp build/esp32.esp32.featheresp32/opencom_xl_firmware.ino.bin build/rnode_firmware_featheresp32.bin cp build/esp32.esp32.featheresp32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_featheresp32.bootloader @@ -369,8 +444,8 @@ release-featheresp32: zip --junk-paths ./Release/rnode_firmware_featheresp32.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_featheresp32.boot_app0 build/rnode_firmware_featheresp32.bin build/rnode_firmware_featheresp32.bootloader build/rnode_firmware_featheresp32.partitions rm -r build -release-genericesp32: - arduino-cli compile --fqbn esp32:esp32:esp32 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" +release-genericesp32: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_generic.boot_app0 cp build/esp32.esp32.esp32/opencom_xl_firmware.ino.bin build/rnode_firmware_esp32_generic.bin cp build/esp32.esp32.esp32/opencom_xl_firmware.ino.bootloader.bin build/rnode_firmware_esp32_generic.bootloader @@ -384,12 +459,16 @@ release-freenode: adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/opencom_xl_firmware.hex Release/rnode_firmware_opencom_xl.zip release-rak4631: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" - cp build/rakwireless.nrf52.WisCoreRAK4631Board/opencom_xl_firmware.ino.hex build/rnode_firmware_rak4631.hex + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" + cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_rak4631.hex adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_rak4631.hex Release/rnode_firmware_rak4631.zip release-rak4631_sx1280: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x14\"" - cp build/rakwireless.nrf52.WisCoreRAK4631Board/opencom_xl_firmware.ino.hex build/rnode_firmware_rak4631_sx1280.hex + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x14\"" + cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_rak4631_sx1280.hex adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_rak4631_sx1280.hex Release/rnode_firmware_rak4631_sx1280.zip +release-opencom-xl: + arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x52\" \"-DBOARD_VARIANT=0x21\"" + cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_opencom_xl.hex + adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_opencom_xl.hex Release/rnode_firmware_opencom_xl.zip diff --git a/Power.h b/Power.h index 2fa7ac7..e6d7ed6 100644 --- a/Power.h +++ b/Power.h @@ -1,9 +1,28 @@ -#if BOARD_MODEL == BOARD_TBEAM +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 #include XPowersLibInterface* PMU = NULL; #ifndef PMU_WIRE_PORT - #define PMU_WIRE_PORT Wire + #if BOARD_MODEL == BOARD_TBEAM_S_V1 + #define PMU_WIRE_PORT Wire1 + #else + #define PMU_WIRE_PORT Wire + #endif #endif #define BAT_V_MIN 3.15 @@ -28,8 +47,6 @@ pmuInterrupt = true; } #elif BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 - #define BAT_C_SAMPLES 7 - #define BAT_D_SAMPLES 2 #define BAT_V_MIN 3.15 #define BAT_V_MAX 4.3 #define BAT_V_CHG 4.48 @@ -44,26 +61,61 @@ int bat_charged_samples = 0; bool bat_voltage_dropping = false; float bat_delay_v = 0; -#elif BOARD_MODEL == BOARD_FREENODE -#include "nrfx_power.h" -#define BAT_C_SAMPLES 7 -#define BAT_D_SAMPLES 2 -#define BAT_V_MIN 2.75 -#define BAT_V_MAX 4.2 -#define BAT_V_FLOAT 4.22 -#define BAT_SAMPLES 5 -#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12 - bit ADC resolution = 3000mV / 4096 -#define VBAT_DIVIDER_COMP (1.73) // Compensation factor for the VBAT divider -#define VBAT_MV_PER_LSB_FIN (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) -#define PIN_VBAT WB_A0 -float bat_p_samples[BAT_SAMPLES]; -float bat_v_samples[BAT_SAMPLES]; -uint8_t bat_samples_count = 0; -int bat_discharging_samples = 0; -int bat_charging_samples = 0; -int bat_charged_samples = 0; -bool bat_voltage_dropping = false; -float bat_delay_v = 0; + float bat_state_change_v = 0; +#elif BOARD_MODEL == BOARD_OPENCOM_XL + #include "nrfx_power.h" + #define BAT_C_SAMPLES 7 + #define BAT_D_SAMPLES 2 + #define BAT_V_MIN 2.75 + #define BAT_V_MAX 4.2 + #define BAT_V_FLOAT 4.22 + #define BAT_SAMPLES 5 + #define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12 - bit ADC resolution = 3000mV / 4096 + #define VBAT_DIVIDER_COMP (1.73) // Compensation factor for the VBAT divider + #define VBAT_MV_PER_LSB_FIN (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) + #define PIN_VBAT WB_A0 + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; +#elif BOARD_MODEL == BOARD_TDECK + #define BAT_V_MIN 3.15 + #define BAT_V_MAX 4.3 + #define BAT_V_CHG 4.48 + #define BAT_V_FLOAT 4.33 + #define BAT_SAMPLES 5 + const uint8_t pin_vbat = 4; + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; + float bat_state_change_v = 0; +#elif BOARD_MODEL == BOARD_HELTEC32_V3 + #define BAT_V_MIN 3.15 + #define BAT_V_MAX 4.3 + #define BAT_V_CHG 4.48 + #define BAT_V_FLOAT 4.33 + #define BAT_SAMPLES 7 + const uint8_t pin_vbat = 1; + const uint8_t pin_ctrl = 37; + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; + float bat_state_change_v = 0; +>>>>>>> upstream/dev #endif uint32_t last_pmu_update = 0; @@ -74,10 +126,17 @@ uint8_t pmu_rc = 0; void kiss_indicate_battery(); void measure_battery() { - #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK battery_installed = true; battery_indeterminate = true; - bat_v_samples[bat_samples_count%BAT_SAMPLES] = (float)(analogRead(pin_vbat)) / 4095*2*3.3*1.1; + + #if BOARD_MODEL == BOARD_HELTEC32_V3 + float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041; + #else + float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*2.0*3.3*1.1; + #endif + + bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement; bat_p_samples[bat_samples_count%BAT_SAMPLES] = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0; bat_samples_count++; @@ -100,41 +159,60 @@ void measure_battery() { battery_voltage = battery_voltage/BAT_SAMPLES; if (bat_delay_v == 0) bat_delay_v = battery_voltage; + if (bat_state_change_v == 0) bat_state_change_v = battery_voltage; if (battery_percent > 100.0) battery_percent = 100.0; if (battery_percent < 0.0) battery_percent = 0.0; if (bat_samples_count%BAT_SAMPLES == 0) { + float bat_delay_diff = bat_state_change_v-battery_voltage; + if (bat_delay_diff < 0) { bat_delay_diff *= -1; } + if (battery_voltage < bat_delay_v && battery_voltage < BAT_V_FLOAT) { - bat_voltage_dropping = true; + if (bat_voltage_dropping == false) { + if (bat_delay_diff > 0.008) { + bat_voltage_dropping = true; + bat_state_change_v = battery_voltage; + // SerialBT.printf("STATE CHANGE to DISCHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); + } + } } else { - bat_voltage_dropping = false; + if (bat_voltage_dropping == true) { + if (bat_delay_diff > 0.01) { + bat_voltage_dropping = false; + bat_state_change_v = battery_voltage; + // SerialBT.printf("STATE CHANGE to CHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); + } + } } bat_samples_count = 0; + bat_delay_v = battery_voltage; } if (bat_voltage_dropping && battery_voltage < BAT_V_FLOAT) { battery_state = BATTERY_STATE_DISCHARGING; } else { - #if BOARD_MODEL == BOARD_RNODE_NG_21 + if (battery_percent < 100.0) { battery_state = BATTERY_STATE_CHARGING; - #else - battery_state = BATTERY_STATE_DISCHARGING; - #endif + } else { + battery_state = BATTERY_STATE_CHARGED; + } } - - // if (bt_state == BT_STATE_CONNECTED) { // SerialBT.printf("Bus voltage %.3fv. Unfiltered %.3fv.", battery_voltage, bat_v_samples[BAT_SAMPLES-1]); // if (bat_voltage_dropping) { - // SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.\n", battery_percent); + // SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent); // } else { - // SerialBT.print(" Voltage is not dropping.\n"); + // SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent); // } + // if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf(" Battery discharging. delay_v %.3fv", bat_delay_v); } + // if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf(" Battery charging. delay_v %.3fv", bat_delay_v); } + // if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print(" Battery is charged."); } + // SerialBT.print("\n"); // } } - #elif BOARD_MODEL == BOARD_TBEAM + #elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 if (PMU) { float discharge_current = 0; float charge_current = 0; @@ -172,7 +250,7 @@ void measure_battery() { } } } else { - battery_state = BATTERY_STATE_DISCHARGING; + battery_state = BATTERY_STATE_UNKNOWN; battery_percent = 0.0; battery_voltage = 0.0; } @@ -214,7 +292,7 @@ void measure_battery() { battery_ready = false; } - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_OPENCOM_XL battery_installed = true; battery_indeterminate = false; @@ -301,31 +379,29 @@ void update_pmu() { } bool init_pmu() { - #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK pinMode(pin_vbat, INPUT); return true; + #elif BOARD_MODEL == BOARD_HELTEC32_V3 + pinMode(pin_ctrl,OUTPUT); + digitalWrite(pin_ctrl, LOW); + return true; #elif BOARD_MODEL == BOARD_TBEAM Wire.begin(I2C_SDA, I2C_SCL); if (!PMU) { PMU = new XPowersAXP2101(PMU_WIRE_PORT); if (!PMU->init()) { - Serial.println("Warning: Failed to find AXP2101 power management"); delete PMU; PMU = NULL; - } else { - Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); } } if (!PMU) { PMU = new XPowersAXP192(PMU_WIRE_PORT); if (!PMU->init()) { - Serial.println("Warning: Failed to find AXP192 power management"); delete PMU; PMU = NULL; - } else { - Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); } } @@ -431,7 +507,7 @@ bool init_pmu() { PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); return true; - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_OPENCOM_XL // board doesn't have PMU but we can measure batt voltage // prep ADC for reading battery level @@ -446,6 +522,86 @@ bool init_pmu() { // Get a single ADC sample and throw it away float raw = analogRead(PIN_VBAT); return true; + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Wire1.begin(I2C_SDA, I2C_SCL); + + if (!PMU) { + PMU = new XPowersAXP2101(PMU_WIRE_PORT); + if (!PMU->init()) { + delete PMU; + PMU = NULL; + } + } + + if (!PMU) { + return false; + } + + /** + * gnss module power channel + * The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during + * initialization + */ + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // lora radio power channel + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + + // m.2 interface + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + /** + * ALDO2 cannot be turned off. + * It is a necessary condition for sensor communication. + * It must be turned on to properly access the sensor and screen + * It is also responsible for the power supply of PCF8563 + */ + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // 6-axis , magnetometer ,bme280 , oled screen power channel + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + // sdcard power channle + PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO1); + + // PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300); + // PMU->enablePowerOutput(XPOWERS_DCDC4); + + // not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited + PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited + PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist + PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist + PMU->disablePowerOutput(XPOWERS_VBACKUP); + + // Configure charging + PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); + // TODO: Reset + PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + // Set the time of pressing the button to turn off + PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + PMU->setPowerKeyPressOnTime(XPOWERS_POWERON_128MS); + + // disable all axp chip interrupt + PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU->clearIrqStatus(); + + // It is necessary to disable the detection function of the TS pin on the board + // without the battery temperature detection function, otherwise it will cause abnormal charging + PMU->disableTSPinMeasure(); + PMU->enableVbusVoltageMeasure(); + PMU->enableBattVoltageMeasure(); + + + return true; #else return false; #endif diff --git a/README.md b/README.md index e5016ba..6d26977 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ The latest release, installable through `rnodeconf`, is version `1.73`. This rel - Fix TNC EEPROM settings not being saved - courtesy of @attermann - Fix ESP32 linker errors - BSP version is now fixed at 2.0.17, using the older crosstool-ng linker from previous versions (2021r1) - You must have at least version `2.1.3` of `rnodeconf` installed to update the RNode Firmware to version `1.73`. Get it by updating the `rns` package to at least version `0.6.4`. ## Supported products and boards diff --git a/ROM.h b/ROM.h index 4ecd02a..9ab3a70 100644 --- a/ROM.h +++ b/ROM.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,79 +14,40 @@ // along with this program. If not, see . #ifndef ROM_H - #define ROM_H + #define ROM_H + #define CHECKSUMMED_SIZE 0x0B - #define CHECKSUMMED_SIZE 0x0B + // ROM address map /////////////// + #define ADDR_PRODUCT 0x00 + #define ADDR_MODEL 0x01 + #define ADDR_HW_REV 0x02 + #define ADDR_SERIAL 0x03 + #define ADDR_MADE 0x07 + #define ADDR_CHKSUM 0x0B + #define ADDR_SIGNATURE 0x1B + #define ADDR_INFO_LOCK 0x9B - #define PRODUCT_RNODE 0x03 - #define PRODUCT_HMBRW 0xF0 - #define PRODUCT_TBEAM 0xE0 - #define PRODUCT_T32_10 0xB2 - #define PRODUCT_T32_20 0xB0 - #define PRODUCT_T32_21 0xB1 - #define PRODUCT_H32_V2 0xC0 - #define PRODUCT_H32_V3 0xC1 - #define PRODUCT_RAK4631 0x10 - #define PRODUCT_FREENODE 0x20 - #define MODEL_11 0x11 - #define MODEL_12 0x12 - #define MODEL_13 0x13 // RAK4631 LF with WisBlock SX1280 module (LIBSYS002) - #define MODEL_14 0x14 // RAK4631 HF with WisBlock SX1280 module (LIBSYS002) - #define PRODUCT_TECHO 0x15 - #define MODEL_16 0x16 // T-Echo 433 - #define MODEL_17 0x17 // T-Echo 915 - #define MODEL_21 0x21 // European band, 868MHz - #define MODEL_A1 0xA1 - #define MODEL_A5 0xA5 // T3S3 SX1280 PA - #define MODEL_A6 0xA6 - #define MODEL_A4 0xA4 - #define MODEL_A9 0xA9 - #define MODEL_A3 0xA3 - #define MODEL_A8 0xA8 - #define MODEL_A2 0xA2 - #define MODEL_A7 0xA7 - #define MODEL_B3 0xB3 - #define MODEL_B8 0xB8 - #define MODEL_B4 0xB4 - #define MODEL_B9 0xB9 - #define MODEL_BA 0xBA - #define MODEL_BB 0xBB - #define MODEL_C4 0xC4 - #define MODEL_C9 0xC9 - #define MODEL_C5 0xC5 - #define MODEL_CA 0xCA - #define MODEL_E4 0xE4 - #define MODEL_E9 0xE9 - #define MODEL_E3 0xE3 - #define MODEL_E8 0xE8 - #define MODEL_FE 0xFE - #define MODEL_FF 0xFF + #define ADDR_CONF_SF 0x9C + #define ADDR_CONF_CR 0x9D + #define ADDR_CONF_TXP 0x9E + #define ADDR_CONF_BW 0x9F + #define ADDR_CONF_FREQ 0xA3 + #define ADDR_CONF_OK 0xA7 - #define ADDR_PRODUCT 0x00 - #define ADDR_MODEL 0x01 - #define ADDR_HW_REV 0x02 - #define ADDR_SERIAL 0x03 - #define ADDR_MADE 0x07 - #define ADDR_CHKSUM 0x0B - #define ADDR_SIGNATURE 0x1B - #define ADDR_INFO_LOCK 0x9B + #define ADDR_CONF_BT 0xB0 + #define ADDR_CONF_DSET 0xB1 + #define ADDR_CONF_DINT 0xB2 + #define ADDR_CONF_DADR 0xB3 + #define ADDR_CONF_DBLK 0xB4 + #define ADDR_CONF_PSET 0xB5 + #define ADDR_CONF_PINT 0xB6 + #define ADDR_CONF_BSET 0xB7 - #define ADDR_CONF_SF 0x9C - #define ADDR_CONF_CR 0x9D - #define ADDR_CONF_TXP 0x9E - #define ADDR_CONF_BW 0x9F - #define ADDR_CONF_FREQ 0xA3 - #define ADDR_CONF_OK 0xA7 - - #define ADDR_CONF_BT 0xB0 - #define ADDR_CONF_DSET 0xB1 - #define ADDR_CONF_DINT 0xB2 - #define ADDR_CONF_DADR 0xB3 + #define INFO_LOCK_BYTE 0x73 + #define CONF_OK_BYTE 0x73 + #define BT_ENABLE_BYTE 0x73 - #define INFO_LOCK_BYTE 0x73 - #define CONF_OK_BYTE 0x73 - #define BT_ENABLE_BYTE 0x73 - - #define EEPROM_RESERVED 200 + #define EEPROM_RESERVED 200 + ////////////////////////////////// #endif diff --git a/Radio.cpp b/Radio.cpp index 58035b3..473205a 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -119,7 +119,7 @@ sx126x::sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch, RadioInterface(index), _spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0), - _busy(busy), _rxen(rxen), _frequency(0), _txp(0), _sf(0x07), _bw(0x04), + _busy(busy), _rxen(rxen), _frequency(0), _sf(0x07), _bw(0x04), _cr(0x01), _ldro(0x00), _packetIndex(0), _implicitHeaderMode(0), _payloadLength(255), _crcMode(1), _fifo_tx_addr_ptr(0), _fifo_rx_addr_ptr(0), _preinit_done(false), _tcxo(tcxo), @@ -129,7 +129,7 @@ sx126x::sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch, setTimeout(0); // TODO, figure out why this has to be done. Using the index to reference the // interface_obj list causes a crash otherwise - _index = getIndex(); + //_index = getIndex(); } bool sx126x::preInit() { @@ -488,34 +488,34 @@ int sx126x::beginPacket(int implicitHeader) int sx126x::endPacket() { - setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); + setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); - // put in single TX mode - uint8_t timeout[3] = {0}; - executeOpcode(OP_TX_6X, timeout, 3); + // put in single TX mode + uint8_t timeout[3] = {0}; + executeOpcode(OP_TX_6X, timeout, 3); - uint8_t buf[2]; + uint8_t buf[2]; - buf[0] = 0x00; - buf[1] = 0x00; + buf[0] = 0x00; + buf[1] = 0x00; - executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); + executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); - // wait for TX done - while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) { + // wait for TX done + while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) { buf[0] = 0x00; buf[1] = 0x00; executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); yield(); - } + } - // clear IRQ's + // clear IRQ's - uint8_t mask[2]; - mask[0] = 0x00; - mask[1] = IRQ_TX_DONE_MASK_6X; - executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2); - return 1; + uint8_t mask[2]; + mask[0] = 0x00; + mask[1] = IRQ_TX_DONE_MASK_6X; + executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2); + return 1; } uint8_t sx126x::modemStatus() { @@ -561,7 +561,7 @@ uint8_t sx126x::packetRssiRaw() { return buf[2]; } -int ISR_VECT sx126x::packetRssi() { +int ISR_VECT sx126x::packetRssi(uint8_t pkt_snr_raw) { // may need more calculations here uint8_t buf[3] = {0}; executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3); @@ -740,7 +740,7 @@ void sx126x::sleep() void sx126x::enableTCXO() { if (_tcxo) { - #if BOARD_MODEL == BOARD_FREENODE || BOARD_MODEL == BOARD_HELTEC32_V3 + #if BOARD_MODEL == BOARD_OPENCOM_XL || BOARD_MODEL == BOARD_HELTEC32_V3 uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_TBEAM uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; @@ -748,6 +748,10 @@ void sx126x::enableTCXO() { uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_T3S3 uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; + #elif BOARD_MODEL == BOARD_TDECK + uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #else uint8_t buf[4] = {0}; #endif @@ -789,7 +793,7 @@ void sx126x::setTxPower(int level, int outputPin) { executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2); } -uint8_t sx126x::getTxPower() { +int8_t sx126x::getTxPower() { return _txp; } @@ -995,7 +999,9 @@ void sx126x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - //_csma_slot_ms = _lora_symbol_time_ms*10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; @@ -1092,7 +1098,7 @@ sx127x::sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int mis setTimeout(0); // TODO, figure out why this has to be done. Using the index to reference the // interface_obj list causes a crash otherwise - _index = getIndex(); + //_index = getIndex(); } void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } @@ -1246,23 +1252,27 @@ uint8_t sx127x::packetRssiRaw() { return pkt_rssi_value; } -int ISR_VECT sx127x::packetRssi() { - int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; - int pkt_snr = packetSnr(); - - if (_frequency < 820E6) pkt_rssi -= 7; - - if (pkt_snr < 0) { - pkt_rssi += pkt_snr; - } else { - // Slope correction is (16/15)*pkt_rssi, - // this estimation looses one floating point - // operation, and should be precise enough. - pkt_rssi = (int)(1.066 * pkt_rssi); - } - return pkt_rssi; +int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) { + int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; + int pkt_snr; + if (pkt_snr_raw == 0xFF) { + pkt_snr = packetSnr(); + } else { + pkt_snr = ((int8_t)pkt_snr_raw)*0.25; + } + if (_frequency < 820E6) pkt_rssi -= 7; + if (pkt_snr < 0) { + pkt_rssi += pkt_snr; + } else { + // Slope correction is (16/15)*pkt_rssi, + // this estimation looses one floating point + // operation, and should be precise enough. + pkt_rssi = (int)(1.066 * pkt_rssi); + } + return pkt_rssi; } + uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); } @@ -1374,9 +1384,10 @@ void sx127x::setTxPower(int level, int outputPin) { writeRegister(REG_PA_DAC_7X, 0x84); writeRegister(REG_PA_CONFIG_7X, PA_BOOST_7X | (level - 2)); } + _txp = level; } -uint8_t sx127x::getTxPower() { byte txp = readRegister(REG_PA_CONFIG_7X); return txp; } +int8_t sx127x::getTxPower() { return _txp; } void sx127x::setFrequency(uint32_t frequency) { _frequency = frequency; @@ -1531,7 +1542,9 @@ void sx127x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - //_csma_slot_ms = _lora_symbol_time_ms*10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; @@ -1605,7 +1618,7 @@ sx128x::sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mo _spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0), - _busy(busy), _rxen(rxen), _txen(txen), _frequency(0), _txp(0), _sf(0x05), + _busy(busy), _rxen(rxen), _txen(txen), _frequency(0), _sf(0x05), _bw(0x34), _cr(0x01), _packetIndex(0), _implicitHeaderMode(0), _payloadLength(255), _crcMode(0), _fifo_tx_addr_ptr(0), _fifo_rx_addr_ptr(0), _rxPacketLength(0), _preinit_done(false), @@ -1615,7 +1628,7 @@ sx128x::sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mo setTimeout(0); // TODO, figure out why this has to be done. Using the index to reference the // interface_obj list causes a crash otherwise - _index = getIndex(); + //_index = getIndex(); } bool sx128x::preInit() { @@ -2028,7 +2041,7 @@ uint8_t sx128x::packetRssiRaw() { return buf[0]; } -int ISR_VECT sx128x::packetRssi() { +int ISR_VECT sx128x::packetRssi(uint8_t pkt_snr_raw) { // may need more calculations here uint8_t buf[5] = {0}; executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); @@ -2333,7 +2346,7 @@ void sx128x::setTxPower(int level, int outputPin) { executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); - #elif BOARD_VARIANT == MODEL_A5 + #elif BOARD_VARIANT == MODEL_AB // T3S3 SX1280 PA if (level > 20) { level = 20; @@ -2414,7 +2427,7 @@ void sx128x::setTxPower(int level, int outputPin) { break; } - tx_buf[0] = reg_value + 18; + tx_buf[0] = reg_value; tx_buf[1] = 0xE0; // ramping time - 20 microseconds #else // For SX1280 boards with no specific PA requirements @@ -2432,7 +2445,7 @@ void sx128x::setTxPower(int level, int outputPin) { executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); } -uint8_t sx128x::getTxPower() { +int8_t sx128x::getTxPower() { return _txp; } @@ -2625,14 +2638,16 @@ void sx128x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - _csma_slot_ms = 10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols; - //if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) { + if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) { target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; - //} else { - /*target_preamble_symbols = (LORA_PREAMBLE_FAST_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; - }*/ + } else { + target_preamble_symbols = (LORA_PREAMBLE_FAST_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; + } if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; } else { diff --git a/Radio.hpp b/Radio.hpp index 8360a04..53648fc 100644 --- a/Radio.hpp +++ b/Radio.hpp @@ -1,7 +1,7 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. -// Modifications and additions copyright 2023 by Mark Qvist & Jacob Eva +// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva // Obviously still under the MIT license. #ifndef RADIO_H @@ -34,15 +34,17 @@ #define LORA_PREAMBLE_SYMBOLS_HW 4 #define LORA_PREAMBLE_SYMBOLS_MIN 18 #define LORA_PREAMBLE_TARGET_MS 15 -#define LORA_PREAMBLE_FAST_TARGET_MS 1 +#define LORA_PREAMBLE_FAST_TARGET_MS 4 #define LORA_FAST_BITRATE_THRESHOLD 40000 +#define CSMA_SLOT_MAX_MS 100 +#define CSMA_SLOT_MIN_MS 24 #define RSSI_OFFSET 157 #define PHY_HEADER_LORA_SYMBOLS 8 #define _e 2.71828183 -#define _S 10.0 +#define _S 12.5 // Status flags const uint8_t SIG_DETECT = 0x01; @@ -75,17 +77,17 @@ public: _stat_signal_detected(false), _stat_signal_synced(false),_stat_rx_ongoing(false), _last_dcd(0), _dcd_count(0), _dcd(false), _dcd_led(false), _dcd_waiting(false), _dcd_wait_until(0), _dcd_sample(0), - _post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p_min(0.1), - _csma_p_max(0.8), _preambleLength(6), _lora_symbol_time_ms(0.0), + _post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p(85), _csma_p_min(0.15), + _csma_p_max(0.333), _csma_b_speed(0.15), _preambleLength(6), _lora_symbol_time_ms(0.0), _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0), - _packet{0}, _onReceive(NULL) {}; + _packet{0}, _onReceive(NULL), _txp(0) {}; virtual int begin() = 0; virtual void end() = 0; virtual int beginPacket(int implicitHeader = false) = 0; virtual int endPacket() = 0; - virtual int packetRssi() = 0; + virtual int packetRssi(uint8_t pkt_snr_raw = 0xFF) = 0; virtual int currentRssi() = 0; virtual uint8_t packetRssiRaw() = 0; virtual uint8_t currentRssiRaw() = 0; @@ -110,7 +112,7 @@ public: virtual void sleep() = 0; virtual bool preInit() = 0; - virtual uint8_t getTxPower() = 0; + virtual int8_t getTxPower() = 0; virtual void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN) = 0; virtual uint32_t getFrequency() = 0; virtual void setFrequency(uint32_t frequency) = 0; @@ -288,8 +290,8 @@ public: float getLongtermChannelUtil() { return _longterm_channel_util; }; float CSMASlope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); }; void updateCSMAp() { - _csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime)))*255.0); - }; + _csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime+_csma_b_speed)))*255.0); + } uint8_t getCSMAp() { return _csma_p; }; void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; }; int getCSMASlotMS() { return _csma_slot_ms; }; @@ -301,6 +303,7 @@ protected: virtual void implicitHeaderMode() = 0; uint8_t _index; + int8_t _txp; bool _radio_locked; bool _radio_online; float _st_airtime_limit; @@ -330,6 +333,7 @@ protected: int _csma_slot_ms; float _csma_p_min; float _csma_p_max; + float _csma_b_speed; long _preambleLength; float _lora_symbol_time_ms; float _lora_symbol_rate; @@ -350,7 +354,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -375,7 +379,7 @@ public: void sleep(); bool preInit(); - uint8_t getTxPower(); + int8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -443,7 +447,6 @@ private: int _rxen; int _busy; uint32_t _frequency; - int _txp; uint8_t _sf; uint8_t _bw; uint8_t _cr; @@ -455,7 +458,6 @@ private: int _fifo_tx_addr_ptr; int _fifo_rx_addr_ptr; bool _preinit_done; - uint8_t _index; bool _tcxo; bool _dio2_as_rf_switch; }; @@ -470,7 +472,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -495,7 +497,7 @@ public: void sleep(); bool preInit(); - uint8_t getTxPower(); + int8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -549,7 +551,6 @@ private: int _packetIndex; int _implicitHeaderMode; bool _preinit_done; - uint8_t _index; uint8_t _sf; uint8_t _cr; }; @@ -564,7 +565,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -589,7 +590,7 @@ public: void sleep(); bool preInit(); - uint8_t getTxPower(); + int8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -657,7 +658,6 @@ private: int _busy; int _modem; uint32_t _frequency; - int _txp; uint8_t _sf; uint8_t _bw; uint8_t _cr; @@ -669,7 +669,6 @@ private: int _fifo_rx_addr_ptr; bool _preinit_done; int _rxPacketLength; - uint8_t _index; bool _tcxo; }; #endif diff --git a/Release/console_image.bin b/Release/console_image.bin index ee7e5b1..8fb621b 100644 Binary files a/Release/console_image.bin and b/Release/console_image.bin differ diff --git a/Utilities.h b/Utilities.h index 2878e10..1a3702e 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ #include "ROM.h" #include "Framing.h" -#include "MD5.h" +#include "src/misc/MD5.h" #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 uint8_t eeprom_read(uint32_t mapped_addr); @@ -45,6 +45,9 @@ uint8_t eeprom_read(uint32_t mapped_addr); #if HAS_DISPLAY == true #include "Display.h" +#else + void display_unblank() {} + bool display_blanked = false; #endif #if HAS_BLUETOOTH == true || HAS_BLE == true @@ -71,11 +74,11 @@ uint8_t eeprom_read(uint32_t mapped_addr); #if BOARD_MODEL == BOARD_HELTEC32_V3 //https://github.com/espressif/esp-idf/issues/8855 #include "hal/wdt_hal.h" - #elif BOARD_MODEL == BOARD_T3S3 - #include "hal/wdt_hal.h" - #else BOARD_MODEL != BOARD_T3S3 - #include "soc/rtc_wdt.h" - #endif + #elif BOARD_MODEL == BOARD_T3S3 + #include "hal/wdt_hal.h" + #else + #include "hal/wdt_hal.h" + #endif #define ISR_VECT IRAM_ATTR #else #define ISR_VECT @@ -98,7 +101,20 @@ uint8_t boot_vector = 0x00; uint8_t npr = 0; uint8_t npg = 0; uint8_t npb = 0; + float npi = NP_M; bool pixels_started = false; + + void led_set_intensity(uint8_t intensity) { + npi = (float)intensity/255.0; + } + + void led_init() { + if (EEPROM.read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) { + uint8_t int_val = EEPROM.read(eeprom_addr(ADDR_CONF_PINT)); + led_set_intensity(int_val); + } + } + void npset(uint8_t r, uint8_t g, uint8_t b) { if (pixels_started != true) { pixels.begin(); @@ -107,7 +123,7 @@ uint8_t boot_vector = 0x00; if (r != npr || g != npg || b != npb) { npr = r; npg = g; npb = b; - pixels.setPixelColor(0, pixels.Color(npr*NP_M, npg*NP_M, npb*NP_M)); + pixels.setPixelColor(0, pixels.Color(npr*npi, npg*npi, npb*npi)); pixels.show(); } } @@ -148,11 +164,26 @@ uint8_t boot_vector = 0x00; void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } void led_tx_off() { digitalWrite(pin_led_tx, LOW); } + #elif BOARD_MODEL == BOARD_E22_ESP32 + void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } + void led_rx_off() { digitalWrite(pin_led_rx, LOW); } + void led_tx_on() { digitalWrite(pin_led_tx, HIGH); } + void led_tx_off() { digitalWrite(pin_led_tx, LOW); } #elif BOARD_MODEL == BOARD_TBEAM void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_tx_on() { digitalWrite(pin_led_tx, LOW); } void led_tx_off() { digitalWrite(pin_led_tx, HIGH); } + #elif BOARD_MODEL == BOARD_TDECK + void led_rx_on() { } + void led_rx_off() { } + void led_tx_on() { } + void led_tx_off() { } + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + void led_rx_on() { } + void led_rx_off() { } + void led_tx_on() { } + void led_tx_off() { } #elif BOARD_MODEL == BOARD_LORA32_V1_0 #if defined(EXTERNAL_LEDS) void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } @@ -211,11 +242,11 @@ uint8_t boot_vector = 0x00; void led_tx_off() { digitalWrite(pin_led_tx, LOW); } #endif #elif MCU_VARIANT == MCU_NRF52 - #if BOARD_MODEL == BOARD_FREENODE - void led_rx_on() { analogWrite(pin_led_rx, 1); } - void led_rx_off() { analogWrite(pin_led_rx, 0); } - void led_tx_on() { analogWrite(pin_led_tx, 1); } - void led_tx_off() { analogWrite(pin_led_tx, 0); } + #if BOARD_MODEL == BOARD_OPENCOM_XL + void led_rx_on() { digitalWrite(pin_led_rx, 1); } + void led_rx_off() { digitalWrite(pin_led_rx, 0); } + void led_tx_on() { digitalWrite(pin_led_tx, 1); } + void led_tx_off() { digitalWrite(pin_led_tx, 0); } #endif #if BOARD_MODEL == BOARD_RAK4631 void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } @@ -383,8 +414,8 @@ unsigned long led_standby_ticks = 0; #if MCU_VARIANT == MCU_ESP32 #if HAS_NP == true - int led_standby_lng = 100; - int led_standby_cut = 200; + int led_standby_lng = 200; + int led_standby_cut = 100; int led_standby_min = 0; int led_standby_max = 375+led_standby_lng; int led_notready_min = 0; @@ -448,7 +479,7 @@ int8_t led_standby_direction = 0; } else { led_standby_intensity = led_standby_ti; } - npset(0x00, 0x00, led_standby_intensity); + npset(led_standby_intensity/3, led_standby_intensity/3, led_standby_intensity/3); } } @@ -595,18 +626,17 @@ void serial_write(uint8_t byte) { Serial.write(byte); } else { SerialBT.write(byte); - - #if MCU_VARIANT == MCU_NRF52 && HAS_BLE - // This ensures that the TX buffer is flushed after a frame is queued in serial. - // serial_in_frame is used to ensure that the flush only happens at the end of the frame - if (serial_in_frame && byte == FEND) { - SerialBT.flushTXD(); - serial_in_frame = false; - } - else if (!serial_in_frame && byte == FEND) { - serial_in_frame = true; - } - #endif + #if MCU_VARIANT == MCU_NRF52 && HAS_BLE + // This ensures that the TX buffer is flushed after a frame is queued in serial. + // serial_in_frame is used to ensure that the flush only happens at the end of the frame + if (serial_in_frame && byte == FEND) { + SerialBT.flushTXD(); + serial_in_frame = false; + } + else if (!serial_in_frame && byte == FEND) { + serial_in_frame = true; + } + #endif } #else Serial.write(byte); @@ -1029,6 +1059,8 @@ void setTXPower(RadioInterface* radio, int txp) { if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_AA) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_AB) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); @@ -1038,6 +1070,15 @@ void setTXPower(RadioInterface* radio, int txp) { if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_C5) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_CA) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + + if (model == MODEL_D4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_D9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + + if (model == MODEL_DB) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_DC) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); @@ -1223,11 +1264,11 @@ void promisc_disable() { #endif bool eeprom_info_locked() { - #if HAS_EEPROM - uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); - #elif MCU_VARIANT == MCU_NRF52 - uint8_t lock_byte = eeprom_read(eeprom_addr(ADDR_INFO_LOCK)); - #endif + #if HAS_EEPROM + uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); + #elif MCU_VARIANT == MCU_NRF52 + uint8_t lock_byte = eeprom_read(eeprom_addr(ADDR_INFO_LOCK)); + #endif if (lock_byte == INFO_LOCK_BYTE) { return true; } else { @@ -1304,15 +1345,15 @@ void eeprom_update(int mapped_addr, uint8_t byte) { written_bytes++; if (((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) || (mapped_addr - eeprom_addr(0)) == ADDR_CONF_OK) { - // have to do a flush because we're only writing 1 byte and it syncs after 4 - eeprom_flush(); + // have to do a flush because we're only writing 1 byte and it syncs after 4 + eeprom_flush(); } - if (written_bytes >= 4) { - eeprom_file.close(); - eeprom_file.open(EEPROM_FILE, FILE_O_WRITE); - written_bytes = 0; - } + if (written_bytes >= 4) { + eeprom_file.close(); + eeprom_file.open(EEPROM_FILE, FILE_O_WRITE); + written_bytes = 0; + } #endif } @@ -1344,16 +1385,16 @@ bool eeprom_lock_set() { } bool eeprom_product_valid() { - #if HAS_EEPROM - uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT)); - #elif MCU_VARIANT == MCU_NRF52 - uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); - #endif + #if HAS_EEPROM + uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT)); + #elif MCU_VARIANT == MCU_NRF52 + uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); + #endif #if PLATFORM == PLATFORM_ESP32 - if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) { + if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1) { #elif PLATFORM == PLATFORM_NRF52 - if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_FREENODE) { + if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_OPENCOM_XL) { #else if (false) { #endif @@ -1375,14 +1416,18 @@ bool eeprom_model_valid() { if (model == MODEL_A3 || model == MODEL_A8) { #elif BOARD_MODEL == BOARD_RNODE_NG_21 if (model == MODEL_A2 || model == MODEL_A7) { + #elif BOARD_MODEL == BOARD_RNODE_NG_22 + if (model == MODEL_A1 || model == MODEL_A6 || model == MODEL_A5 || model == MODEL_AA) { #elif BOARD_MODEL == BOARD_T3S3 if (model == MODEL_A1 || model == MODEL_A5 || model == MODEL_A6) { - #elif BOARD_MODEL == BOARD_HMBRW - if (model == MODEL_FF || model == MODEL_FE) { #elif BOARD_MODEL == BOARD_TBEAM if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) { #elif BOARD_MODEL == BOARD_TECHO if (model == MODEL_16 || model == MODEL_17) { + #elif BOARD_MODEL == BOARD_TDECK + if (model == MODEL_D4 || model == MODEL_D9) { + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + if (model == MODEL_DB || model == MODEL_DC) { #elif BOARD_MODEL == BOARD_LORA32_V1_0 if (model == MODEL_BA || model == MODEL_BB) { #elif BOARD_MODEL == BOARD_LORA32_V2_0 @@ -1393,10 +1438,12 @@ bool eeprom_model_valid() { if (model == MODEL_C4 || model == MODEL_C9) { #elif BOARD_MODEL == BOARD_HELTEC32_V3 if (model == MODEL_C5 || model == MODEL_CA) { - #elif BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_OPENCOM_XL if (model == MODEL_21) { #elif BOARD_MODEL == BOARD_HUZZAH32 if (model == MODEL_FF) { + #elif BOARD_MODEL == BOARD_HMBRW + if (model == MODEL_FF || model == MODEL_FE) { #elif BOARD_MODEL == BOARD_GENERIC_ESP32 if (model == MODEL_FF || model == MODEL_FE) { #else @@ -1454,16 +1501,16 @@ bool eeprom_checksum_valid() { void bt_conf_save(bool is_enabled) { if (is_enabled) { eeprom_update(eeprom_addr(ADDR_CONF_BT), BT_ENABLE_BYTE); - #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 - // have to do a flush because we're only writing 1 byte and it syncs after 8 - eeprom_flush(); - #endif + #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + // have to do a flush because we're only writing 1 byte and it syncs after 8 + eeprom_flush(); + #endif } else { eeprom_update(eeprom_addr(ADDR_CONF_BT), 0x00); - #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 - // have to do a flush because we're only writing 1 byte and it syncs after 8 - eeprom_flush(); - #endif + #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + // have to do a flush because we're only writing 1 byte and it syncs after 8 + eeprom_flush(); + #endif } } @@ -1475,6 +1522,25 @@ void da_conf_save(uint8_t dadr) { eeprom_update(eeprom_addr(ADDR_CONF_DADR), dadr); } +void db_conf_save(uint8_t val) { + #if HAS_DISPLAY + if (val == 0x00) { + display_blanking_enabled = false; + } else { + display_blanking_enabled = true; + //display_blanking_timeout = val*1000; + } + eeprom_update(eeprom_addr(ADDR_CONF_BSET), CONF_OK_BYTE); + eeprom_update(eeprom_addr(ADDR_CONF_DBLK), val); + #endif +} + +void np_int_conf_save(uint8_t p_int) { + eeprom_update(eeprom_addr(ADDR_CONF_PSET), CONF_OK_BYTE); + eeprom_update(eeprom_addr(ADDR_CONF_PINT), p_int); +} + + bool eeprom_have_conf() { #if HAS_EEPROM if (EEPROM.read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) { diff --git a/arduino-cli.yaml b/arduino-cli.yaml index 2f836f0..833fd7b 100644 --- a/arduino-cli.yaml +++ b/arduino-cli.yaml @@ -3,4 +3,3 @@ board_manager: - https://adafruit.github.io/arduino-board-index/package_adafruit_index.json - https://liberatedsystems.co.uk/rnode-firmware-ce/esp-custom-package.json - https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json - - http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json diff --git a/esp32_btbufs.py b/esp32_btbufs.py new file mode 100755 index 0000000..8a5b15e --- /dev/null +++ b/esp32_btbufs.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +import sys + +try: + target_path = sys.argv[1] + rxbuf_size = 0; rxbuf_minsize = 6144 + txbuf_size = 0; txbuf_minsize = 384 + line_index = 0 + rx_line_index = 0 + tx_line_index = 0 + with open(target_path) as sf: + for line in sf: + line_index += 1 + if line.startswith("#define RX_QUEUE_SIZE"): + ents = line.split(" ") + try: + rxbuf_size = int(ents[2]) + rx_line_index = line_index + except Exception as e: + print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}") + + if line.startswith("#define TX_QUEUE_SIZE"): + ents = line.split(" ") + try: + txbuf_size = int(ents[2]) + tx_line_index = line_index + except Exception as e: + print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}") + + if rxbuf_size != 0 and txbuf_size != 0: + break + + if rxbuf_size < rxbuf_minsize: + print(f"Error: The configured ESP32 Bluetooth RX buffer size is too small, please set it to at least {rxbuf_minsize} and try compiling again.") + print(f"The buffer configuration can be modified in line {rx_line_index} of: {target_path}") + exit(1) + + if txbuf_size < txbuf_minsize: + print(f"Error: The configured ESP32 Bluetooth TX buffer size is too small, please set it to at least {txbuf_minsize} and try compiling again.") + print(f"The buffer configuration can be modified in line {tx_line_index} of: {target_path}") + exit(1) + + exit(0) + +except Exception as e: + print(f"Could not determine ESP32 Bluetooth buffer configuration: {e}") + print("Please fix this error and try again") \ No newline at end of file diff --git a/opencom_xl_firmware.ino b/opencom_xl_firmware.ino index 8fa9fe6..3dae37b 100644 --- a/opencom_xl_firmware.ino +++ b/opencom_xl_firmware.ino @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ #if MCU_VARIANT == MCU_NRF52 #define INTERFACE_SPI - #if BOARD_MODEL == BOARD_FREENODE + #if BOARD_MODEL == BOARD_OPENCOM_XL // Required because on RAK4631, non-default SPI pins must be initialised when class is declared. SPIClass interface_spi[1] = { // SX1262 @@ -74,6 +74,16 @@ volatile bool serial_buffering = false; #include "Console.h" #endif +#define MODEM_QUEUE_SIZE 4*INTERFACE_COUNT +typedef struct { + size_t len; + int rssi; + int snr_raw; + uint8_t interface; + uint8_t data[]; +} modem_packet_t; +static xQueueHandle modem_packet_queue = NULL; + char sbuf[128]; uint8_t *packet_queue[INTERFACE_COUNT]; @@ -83,6 +93,18 @@ void setup() { boot_seq(); EEPROM.begin(EEPROM_SIZE); Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); + + #if BOARD_MODEL == BOARD_TDECK + pinMode(pin_poweron, OUTPUT); + digitalWrite(pin_poweron, HIGH); + + pinMode(SD_CS, OUTPUT); + pinMode(DISPLAY_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + digitalWrite(DISPLAY_CS, HIGH); + + pinMode(DISPLAY_BL_PIN, OUTPUT); + #endif #endif #if MCU_VARIANT == MCU_NRF52 @@ -109,9 +131,13 @@ void setup() { Serial.begin(serial_baudrate); - #if BOARD_MODEL != BOARD_FREENODE && BOARD_MODEL != BOARD_RNODE_NG_22 + #if HAS_NP + led_init(); + #endif + + #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_OPENCOM_XL // Some boards need to wait until the hardware UART is set up before booting - // the full firmware. In the case of the RAK4631, the line below will wait + // the full firmware. In the case of the RAK4631/TECHO, the line below will wait // until a serial connection is actually established with a master. Thus, it // is disabled on this platform. while (!Serial); @@ -145,6 +171,10 @@ void setup() { memset(packet_starts_buf, 0, sizeof(packet_starts_buf)); memset(packet_lengths_buf, 0, sizeof(packet_starts_buf)); + memset(seq, 0xFF, sizeof(seq)); + + modem_packet_queue = xQueueCreate(MODEM_QUEUE_SIZE, sizeof(modem_packet_t*)); + for (int i = 0; i < INTERFACE_COUNT; i++) { fifo16_init(&packet_starts[i], packet_starts_buf, CONFIG_QUEUE_MAX_LENGTH+1); fifo16_init(&packet_lengths[i], packet_lengths_buf, CONFIG_QUEUE_MAX_LENGTH+1); @@ -155,6 +185,8 @@ void setup() { fifo_init(&packet_rdy_interfaces, packet_rdy_interfaces_buf, MAX_INTERFACES); + // add call to init_channel_stats here? \todo + // Create and configure interface objects for (uint8_t i = 0; i < INTERFACE_COUNT; i++) { switch (interfaces[i]) { @@ -324,34 +356,76 @@ inline void kiss_write_packet(int index) { uint8_t cmd_byte = getInterfaceCommandByte(index); serial_write(FEND); - // Add index of interface the packet came from serial_write(cmd_byte); for (uint16_t i = 0; i < read_len; i++) { + #if MCU_VARIANT == MCU_NRF52 portENTER_CRITICAL(); - uint8_t byte = pbuf[i]; - portEXIT_CRITICAL(); + uint8_t byte = pbuf[i]; + portEXIT_CRITICAL(); + #else + uint8_t byte = pbuf[i]; + #endif + if (byte == FEND) { serial_write(FESC); byte = TFEND; } if (byte == FESC) { serial_write(FESC); byte = TFESC; } serial_write(byte); } + serial_write(FEND); read_len = 0; - packet_ready = false; + + #if MCU_VARIANT == MCU_ESP32 && HAS_BLE + bt_flush(); + #endif } inline void getPacketData(RadioInterface* radio, uint16_t len) { - BaseType_t mask = taskENTER_CRITICAL_FROM_ISR(); - while (len-- && read_len < MTU) { - pbuf[read_len++] = radio->read(); - } - taskEXIT_CRITICAL_FROM_ISR(mask); + #if MCU_VARIANT != MCU_NRF52 + while (len-- && read_len < MTU) { + pbuf[read_len++] = radio->read(); + } + #else + BaseType_t int_mask = taskENTER_CRITICAL_FROM_ISR(); + while (len-- && read_len < MTU) { + pbuf[read_len++] = radio->read(); + } + taskEXIT_CRITICAL_FROM_ISR(int_mask); + #endif } -void receive_callback(uint8_t index, int packet_size) { - selected_radio = interface_obj[index]; +inline bool queue_packet(RadioInterface* radio, uint8_t index) { + // Allocate packet struct, but abort if there + // is not enough memory available. + modem_packet_t *modem_packet = (modem_packet_t*)malloc(sizeof(modem_packet_t) + read_len); + if(!modem_packet) { memory_low = true; return false; } + + // Get packet RSSI and SNR + modem_packet->snr_raw = radio->packetSnrRaw(); + + // Pass raw SNR to get RSSI as SX127X driver requires it for calculations + modem_packet->rssi = radio->packetRssi(modem_packet->snr_raw); + + modem_packet->interface = index; + + // Send packet to event queue, but free the + // allocated memory again if the queue is + // unable to receive the packet. + modem_packet->len = read_len; + memcpy(modem_packet->data, pbuf, read_len); + if (!modem_packet_queue || xQueueSendFromISR(modem_packet_queue, &modem_packet, NULL) != pdPASS) { + free(modem_packet); + return false; + } + return true; +} + +void ISR_VECT receive_callback(uint8_t index, int packet_size) { + selected_radio = interface_obj[index]; bool ready = false; + + BaseType_t int_mask; if (!promisc) { // The standard operating mode allows large // packets with a payload up to 500 bytes, @@ -362,37 +436,41 @@ void receive_callback(uint8_t index, int packet_size) { uint8_t header = selected_radio->read(); packet_size--; uint8_t sequence = packetSequence(header); - if (isSplitPacket(header) && seq == SEQ_UNSET) { + if (isSplitPacket(header) && seq[index] == SEQ_UNSET) { // This is the first part of a split // packet, so we set the seq variable // and add the data to the buffer - BaseType_t mask = taskENTER_CRITICAL_FROM_ISR(); - read_len = 0; - seq = sequence; - taskEXIT_CRITICAL_FROM_ISR(mask); + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + + seq[index] = sequence; getPacketData(selected_radio, packet_size); - } else if (isSplitPacket(header) && seq == sequence) { + } else if (isSplitPacket(header) && seq[index] == sequence) { // This is the second part of a split // packet, so we add it to the buffer // and set the ready flag. getPacketData(selected_radio, packet_size); - seq = SEQ_UNSET; - packet_interface = index; - packet_ready = true; + seq[index] = SEQ_UNSET; + ready = true; - } else if (isSplitPacket(header) && seq != sequence) { + } else if (isSplitPacket(header) && seq[index] != sequence) { // This split packet does not carry the // same sequence id, so we must assume // that we are seeing the first part of // a new split packet. - BaseType_t mask = taskENTER_CRITICAL_FROM_ISR(); - read_len = 0; - seq = sequence; - taskEXIT_CRITICAL_FROM_ISR(mask); + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + seq[index] = sequence; getPacketData(selected_radio, packet_size); @@ -401,31 +479,33 @@ void receive_callback(uint8_t index, int packet_size) { // just read it and set the ready // flag to true. - if (seq != SEQ_UNSET) { + if (seq[index] != SEQ_UNSET) { // If we already had part of a split // packet in the buffer, we clear it. - BaseType_t mask = taskENTER_CRITICAL_FROM_ISR(); - read_len = 0; - seq = SEQ_UNSET; - taskEXIT_CRITICAL_FROM_ISR(mask); + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + seq[index] = SEQ_UNSET; } getPacketData(selected_radio, packet_size); - packet_interface = index; - packet_ready = true; + ready = true; } } else { // In promiscuous mode, raw packets are // output directly to the host - BaseType_t mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; - taskEXIT_CRITICAL_FROM_ISR(mask); getPacketData(selected_radio, packet_size); - packet_interface = index; - packet_ready = true; + ready = true; + } + + if (ready) { + queue_packet(selected_radio, index); } last_rx = millis(); @@ -536,6 +616,9 @@ void flushQueue(RadioInterface* radio) { queued_bytes[index] = 0; selected_radio->updateAirtime(); queue_flushing = false; + #if HAS_DISPLAY + display_tx = true; + #endif } void transmit(RadioInterface* radio, uint16_t size) { @@ -557,7 +640,9 @@ void transmit(RadioInterface* radio, uint16_t size) { written++; - if (written == 255) { + // Only start a new packet if this is a split packet and it has + // exceeded the length of a single packet + if (written == 255 && header & 0x0F) { radio->endPacket(); radio->addAirtime(written); radio->beginPacket(); radio->write(header); @@ -565,7 +650,14 @@ void transmit(RadioInterface* radio, uint16_t size) { } } - radio->endPacket(); radio->addAirtime(written); + if (!radio->endPacket()) { + kiss_indicate_error(ERROR_MODEM_TIMEOUT); + kiss_indicate_error(ERROR_TXFAILED); + led_indicate_error(5); + hard_reset(); + } + radio->addAirtime(written); + } else { // In promiscuous mode, we only send out // plain raw LoRa packets with a maximum @@ -800,6 +892,7 @@ void serialCallback(uint8_t sbyte) { kiss_indicate_implicit_length(); } else if (command == CMD_LEAVE) { if (sbyte == 0xFF) { + //display_unblank(); cable_state = CABLE_STATE_DISCONNECTED; //current_rssi = -292; last_rssi = -292; @@ -1041,7 +1134,13 @@ void serialCallback(uint8_t sbyte) { bt_start(); bt_conf_save(true); } else if (sbyte == 0x02) { - bt_enable_pairing(); + if (bt_state == BT_STATE_OFF) { + bt_start(); + bt_conf_save(true); + } + if (bt_state != BT_STATE_CONNECTED) { + bt_enable_pairing(); + } } #endif } else if (command == CMD_DISP_INT) { @@ -1056,6 +1155,7 @@ void serialCallback(uint8_t sbyte) { } display_intensity = sbyte; di_conf_save(display_intensity); + //display_unblank(); } #endif @@ -1089,6 +1189,37 @@ void serialCallback(uint8_t sbyte) { if (frame_len == FW_LENGTH_LEN) { set_fw_length(cmdbuf); } + } else if (command == CMD_DISP_BLNK) { + #if HAS_DISPLAY + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + db_conf_save(sbyte); + //display_unblank(); + } + + #endif + } else if (command == CMD_NP_INT) { + #if HAS_NP + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + sbyte; + led_set_intensity(sbyte); + np_int_conf_save(sbyte); + } + + #endif } } } @@ -1154,7 +1285,7 @@ void validate_status() { } } else { hw_ready = false; - Serial.write("No valid radio module found\r\n"); + Serial.write("No radio module found\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1164,6 +1295,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Invalid EEPROM checksum\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1173,6 +1305,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Invalid EEPROM configuration\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1182,6 +1315,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Device unprovisioned, no device configuration found in EEPROM\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1203,23 +1337,38 @@ void validate_status() { } void loop() { - if (packet_ready) { - #if MCU_VARIANT == MCU_ESP32 - portENTER_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portENTER_CRITICAL(); - #endif - last_rssi = selected_radio->packetRssi(); - last_snr_raw = selected_radio->packetSnrRaw(); - #if MCU_VARIANT == MCU_ESP32 - portEXIT_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portEXIT_CRITICAL(); - #endif + #if MCU_VARIANT == MCU_ESP32 + modem_packet_t *modem_packet = NULL; + if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) { + read_len = modem_packet->len; + last_rssi = modem_packet->rssi; + last_snr_raw = modem_packet->snr_raw; + packet_interface = modem_packet->interface; + memcpy(&pbuf, modem_packet->data, modem_packet->len); + free(modem_packet); + modem_packet = NULL; + kiss_indicate_stat_rssi(); kiss_indicate_stat_snr(); kiss_write_packet(packet_interface); - } + } + + #elif MCU_VARIANT == MCU_NRF52 + modem_packet_t *modem_packet = NULL; + if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) { + memcpy(&pbuf, modem_packet->data, modem_packet->len); + read_len = modem_packet->len; + last_rssi = modem_packet->rssi; + last_snr_raw = modem_packet->snr_raw; + packet_interface = modem_packet->interface; + free(modem_packet); + modem_packet = NULL; + + kiss_indicate_stat_rssi(); + kiss_indicate_stat_snr(); + kiss_write_packet(packet_interface); + } + #endif bool ready = false; for (int i = 0; i < INTERFACE_COUNT; i++) { @@ -1240,19 +1389,6 @@ void loop() { continue; } - // If a higher data rate interface has received a packet after its - // loop, it still needs to be the first to transmit, so check if this - // is the case. - for (int j = 0; j < INTERFACE_COUNT; j++) { - if (!interface_obj_sorted[j]->calculateALock() && interface_obj_sorted[j]->getRadioOnline()) { - if (interface_obj_sorted[j]->getBitrate() > selected_radio->getBitrate()) { - if (queue_height[interface_obj_sorted[j]->getIndex()] > 0) { - selected_radio = interface_obj_sorted[j]; - } - } - } - } - if (queue_height[selected_radio->getIndex()] > 0) { uint32_t check_time = millis(); if (check_time > selected_radio->getPostTxYieldTimeout()) { @@ -1335,6 +1471,17 @@ void loop() { #if HAS_BUZZER update_buzzer_notone(); #endif + if (memory_low) { + #if PLATFORM == PLATFORM_ESP32 + if (esp_get_free_heap_size() < 8192) { + kiss_indicate_error(ERROR_MEMORY_LOW); memory_low = false; + } else { + memory_low = false; + } + #else + kiss_indicate_error(ERROR_MEMORY_LOW); memory_low = false; + #endif + } } void process_serial() { @@ -1347,6 +1494,7 @@ void button_event(uint8_t event, unsigned long duration) { if (duration > BUTTON_MIN_DURATION) { if (duration > BUTTON_6S_DURATION) { bt_stop(); + bt_conf_save(false); } else if (duration > BUTTON_3S_DURATION) { bt_enable_pairing(); } else { diff --git a/partition_hashes b/partition_hashes index d6b81fe..fa60868 100755 --- a/partition_hashes +++ b/partition_hashes @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/release_hashes.py b/release_hashes.py index c54a9d1..e1608d8 100644 --- a/release_hashes.py +++ b/release_hashes.py @@ -1,6 +1,6 @@ #!/bin/python3 -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/ble/BLESerial.cpp b/src/ble/BLESerial.cpp new file mode 100644 index 0000000..94cbb2f --- /dev/null +++ b/src/ble/BLESerial.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This class is for BLE serial functionality on ESP32 boards ONLY + +#include +#include "../../Boards.h" + +#if PLATFORM != PLATFORM_NRF52 +#if HAS_BLE + +#include "BLESerial.h" + +uint32_t bt_passkey_callback(); +void bt_passkey_notify_callback(uint32_t passkey); +bool bt_security_request_callback(); +void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result); +bool bt_confirm_pin_callback(uint32_t pin); +void bt_connect_callback(BLEServer *server); +void bt_disconnect_callback(BLEServer *server); +bool bt_client_authenticated(); + +uint32_t BLESerial::onPassKeyRequest() { return bt_passkey_callback(); } +void BLESerial::onPassKeyNotify(uint32_t passkey) { bt_passkey_notify_callback(passkey); } +bool BLESerial::onSecurityRequest() { return bt_security_request_callback(); } +void BLESerial::onAuthenticationComplete(esp_ble_auth_cmpl_t auth_result) { bt_authentication_complete_callback(auth_result); } +void BLESerial::onConnect(BLEServer *server) { bt_connect_callback(server); } +void BLESerial::onDisconnect(BLEServer *server) { bt_disconnect_callback(server); ble_server->startAdvertising(); } +bool BLESerial::onConfirmPIN(uint32_t pin) { return bt_confirm_pin_callback(pin); }; +bool BLESerial::connected() { return ble_server->getConnectedCount() > 0; } + +int BLESerial::read() { + int result = this->rx_buffer.pop(); + if (result == '\n') { this->numAvailableLines--; } + return result; +} + +size_t BLESerial::readBytes(uint8_t *buffer, size_t bufferSize) { + int i = 0; + while (i < bufferSize && available()) { buffer[i] = (uint8_t)this->rx_buffer.pop(); i++; } + return i; +} + +int BLESerial::peek() { + if (this->rx_buffer.getLength() == 0) return -1; + return this->rx_buffer.get(0); +} + +int BLESerial::available() { return this->rx_buffer.getLength(); } + +size_t BLESerial::print(const char *str) { + if (ble_server->getConnectedCount() <= 0) return 0; + size_t written = 0; for (size_t i = 0; str[i] != '\0'; i++) { written += this->write(str[i]); } + flush(); + + return written; +} + +size_t BLESerial::write(const uint8_t *buffer, size_t bufferSize) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + size_t written = 0; for (int i = 0; i < bufferSize; i++) { written += this->write(buffer[i]); } + flush(); + + return written; + } +} + +size_t BLESerial::write(uint8_t byte) { + if (bt_client_authenticated()) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + this->transmitBuffer[this->transmitBufferLength] = byte; + this->transmitBufferLength++; + if (this->transmitBufferLength == maxTransferSize) { flush(); } + return 1; + } + } else { + return 0; + } +} + +void BLESerial::flush() { + if (this->transmitBufferLength > 0) { + TxCharacteristic->setValue(this->transmitBuffer, this->transmitBufferLength); + this->transmitBufferLength = 0; + this->lastFlushTime = millis(); + TxCharacteristic->notify(true); + } +} + +void BLESerial::begin(const char *name) { + ConnectedDeviceCount = 0; + BLEDevice::init(name); + + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9); + + ble_server = BLEDevice::createServer(); + ble_server->setCallbacks(this); + BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM); + BLEDevice::setSecurityCallbacks(this); + + SetupSerialService(); + + ble_adv = BLEDevice::getAdvertising(); + ble_adv->addServiceUUID(BLE_SERIAL_SERVICE_UUID); + ble_adv->setMinPreferred(0x20); + ble_adv->setMaxPreferred(0x40); + ble_adv->setScanResponse(true); + ble_adv->start(); +} + +void BLESerial::end() { BLEDevice::deinit(); } + +void BLESerial::onWrite(BLECharacteristic *characteristic) { + if (characteristic->getUUID().toString() == BLE_RX_UUID) { + auto value = characteristic->getValue(); + for (int i = 0; i < value.length(); i++) { rx_buffer.push(value[i]); } + } +} + +void BLESerial::SetupSerialService() { + SerialService = ble_server->createService(BLE_SERIAL_SERVICE_UUID); + + RxCharacteristic = SerialService->createCharacteristic(BLE_RX_UUID, BLECharacteristic::PROPERTY_WRITE); + RxCharacteristic->setAccessPermissions(ESP_GATT_PERM_WRITE_ENC_MITM); + RxCharacteristic->addDescriptor(new BLE2902()); + RxCharacteristic->setWriteProperty(true); + RxCharacteristic->setCallbacks(this); + + TxCharacteristic = SerialService->createCharacteristic(BLE_TX_UUID, BLECharacteristic::PROPERTY_NOTIFY); + TxCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENC_MITM); + TxCharacteristic->addDescriptor(new BLE2902()); + TxCharacteristic->setNotifyProperty(true); + TxCharacteristic->setReadProperty(true); + + SerialService->start(); +} + +BLESerial::BLESerial() { } + +#endif +#endif diff --git a/src/ble/BLESerial.h b/src/ble/BLESerial.h new file mode 100644 index 0000000..1ad2e25 --- /dev/null +++ b/src/ble/BLESerial.h @@ -0,0 +1,135 @@ +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This class is for BLE serial functionality on ESP32 boards ONLY + +#include "../../Boards.h" + +#if PLATFORM != PLATFORM_NRF52 +#if HAS_BLE + +#include + +#include +#include +#include +#include + +template +class BLEFIFO { +private: + uint8_t buffer[n]; + int head = 0; + int tail = 0; + +public: + void push(uint8_t value) { + buffer[head] = value; + head = (head + 1) % n; + if (head == tail) { tail = (tail + 1) % n; } + } + + int pop() { + if (head == tail) { + return -1; + } else { + uint8_t value = buffer[tail]; + tail = (tail + 1) % n; + return value; + } + } + + void clear() { head = 0; tail = 0; } + + int get(size_t index) { + if (index >= this->getLength()) { + return -1; + } else { + return buffer[(tail + index) % n]; + } + } + + size_t getLength() { + if (head >= tail) { + return head - tail; + } else { + return n - tail + head; + } + } +}; + +#define RX_BUFFER_SIZE 6144 +#define BLE_BUFFER_SIZE 512 // Must fit in max GATT attribute length +#define MIN_MTU 50 + +class BLESerial : public BLECharacteristicCallbacks, public BLEServerCallbacks, public BLESecurityCallbacks, public Stream { +public: + BLESerial(); + + void begin(const char *name); + void end(); + void onWrite(BLECharacteristic *characteristic); + int available(); + int peek(); + int read(); + size_t readBytes(uint8_t *buffer, size_t bufferSize); + size_t write(uint8_t byte); + size_t write(const uint8_t *buffer, size_t bufferSize); + size_t print(const char *value); + void flush(); + void onConnect(BLEServer *server); + void onDisconnect(BLEServer *server); + + uint32_t onPassKeyRequest(); + void onPassKeyNotify(uint32_t passkey); + bool onSecurityRequest(); + void onAuthenticationComplete(esp_ble_auth_cmpl_t); + bool onConfirmPIN(uint32_t pin); + + bool connected(); + + BLEServer *ble_server; + BLEAdvertising *ble_adv; + BLEService *SerialService; + BLECharacteristic *TxCharacteristic; + BLECharacteristic *RxCharacteristic; + size_t transmitBufferLength; + unsigned long long lastFlushTime; + +private: + BLESerial(BLESerial const &other) = delete; + void operator=(BLESerial const &other) = delete; + + BLEFIFO rx_buffer; + size_t numAvailableLines; + uint8_t transmitBuffer[BLE_BUFFER_SIZE]; + + int ConnectedDeviceCount; + void SetupSerialService(); + + uint16_t peerMTU; + uint16_t maxTransferSize = BLE_BUFFER_SIZE; + + bool checkMTU(); + + const char *BLE_SERIAL_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_RX_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_TX_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; + + bool started = false; +}; + +#endif +#endif diff --git a/MD5.cpp b/src/misc/MD5.cpp similarity index 100% rename from MD5.cpp rename to src/misc/MD5.cpp diff --git a/MD5.h b/src/misc/MD5.h similarity index 100% rename from MD5.h rename to src/misc/MD5.h