diff --git a/.github/ISSUE_TEMPLATE/🐛-bug-report.md b/.github/ISSUE_TEMPLATE/🐛-bug-report.md deleted file mode 100644 index ddb78fc..0000000 --- a/.github/ISSUE_TEMPLATE/🐛-bug-report.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: "\U0001F41B Bug Report" -about: Report a reproducible bug -title: '' -labels: '' -assignees: '' - ---- - -**Read the Contribution Guidelines** -Before creating a bug report on this issue tracker, you **must** read the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md). Issues that do not follow the contribution guidelines **will be deleted without comment**. - -- The issue tracker is used by developers of this project. **Do not use it to ask general questions, or for support requests**. -- Ideas and feature requests can be made on the [Discussions](https://github.com/markqvist/Reticulum/discussions). **Only** feature requests accepted by maintainers and developers are tracked and included on the issue tracker. **Do not post feature requests here**. -- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), delete this section from your bug report. - -**Describe the Bug** -First of all: Is this really a bug? Is it reproducible? - -If this is a request for help because something is not working as you expected, stop right here, and go to the [discussions](https://github.com/markqvist/Reticulum/discussions) instead, where you can post your questions and get help from other users. - -If this really is a bug or issue with the software, remove this section of the template, and provide **a clear and concise description of what the bug is**. - -**To Reproduce** -Describe in detail how to reproduce the bug. - -**Expected Behavior** -A clear and concise description of what you expected to happen. - -**Logs & Screenshots** -Please include any relevant log output. If applicable, also add screenshots to help explain your problem. In most cases, without any relevant log output, we will not be able to determine the cause of the bug, or reproduce it. - -**System Information** -- OS and version -- Python version -- Program version - -**Additional context** -Add any other context about the problem here. diff --git a/.gitignore b/.gitignore index b879ff5..c585a06 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ Release/*.zip Release/*.json Console/build build/* -.vscode \ No newline at end of file diff --git a/Bluetooth.h b/Bluetooth.h index e596ae9..d1d339a 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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,22 +22,19 @@ #elif HAS_BLE == true #include "esp_bt_main.h" #include "esp_bt_device.h" - #include "src/ble/BLESerial.h" - BLESerial SerialBT; + // TODO: Remove + #define SerialBT Serial #endif #elif MCU_VARIANT == MCU_NRF52 #include #include - #define BLE_RX_BUF 6144 - BLEUart SerialBT(BLE_RX_BUF); + BLEUart SerialBT; BLEDis bledis; BLEBas blebas; - bool SerialBT_init = false; #endif #define BT_PAIRING_TIMEOUT 35000 -#define BLE_FLUSH_TIMEOUT 20 uint32_t bt_pairing_started = 0; #define BT_DEV_ADDR_LEN 6 @@ -61,7 +58,6 @@ char bt_devname[11]; } void bt_stop() { - display_unblank(); if (bt_state != BT_STATE_OFF) { SerialBT.end(); bt_allow_pairing = false; @@ -70,7 +66,6 @@ char bt_devname[11]; } void bt_start() { - display_unblank(); if (bt_state == BT_STATE_OFF) { SerialBT.begin(bt_devname); bt_state = BT_STATE_ON; @@ -78,7 +73,6 @@ 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(); @@ -86,14 +80,12 @@ 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 { @@ -101,8 +93,7 @@ char bt_devname[11]; } } - void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { - display_unblank(); + void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){ if(event == ESP_SPP_SRV_OPEN_EVT) { bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; @@ -165,155 +156,29 @@ char bt_devname[11]; } #elif HAS_BLE == true - bool bt_setup_hw(); void bt_security_setup(); - 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_start() { - // Serial.println("BT start"); - display_unblank(); - if (bt_state == BT_STATE_OFF) { - bt_state = BT_STATE_ON; - SerialBT.begin(bt_devname); - SerialBT.setTimeout(10); - } - } - void bt_stop() { - // Serial.println("BT stop"); - display_unblank(); if (bt_state != BT_STATE_OFF) { bt_allow_pairing = false; bt_state = BT_STATE_OFF; - SerialBT.end(); } } - bool bt_init() { - // Serial.println("BT init"); - bt_state = BT_STATE_OFF; - if (bt_setup_hw()) { - if (bt_enabled && !console_active) bt_start(); - return true; - } else { - return false; - } - } - - 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_enable_pairing() { - // Serial.println("BT enable pairing"); - display_unblank(); - if (bt_state == BT_STATE_OFF) bt_start(); - - bt_security_setup(); - - bt_allow_pairing = true; - bt_pairing_started = millis(); - bt_state = BT_STATE_PAIRING; - bt_ssp_pin = pairing_pin; - } - void bt_disable_pairing() { - // Serial.println("BT disable pairing"); - display_unblank(); bt_allow_pairing = false; bt_ssp_pin = 0; bt_state = BT_STATE_ON; } - void bt_passkey_notify_callback(uint32_t passkey) { - // Serial.printf("Got passkey notification: %d\n", passkey); - if (bt_allow_pairing) { - bt_ssp_pin = passkey; - bt_pairing_started = millis(); - kiss_indicate_btpin(); - } else { - // Serial.println("Pairing not allowed, re-init"); - SerialBT.disconnect(); - } - } - - bool bt_confirm_pin_callback(uint32_t pin) { - // Serial.printf("Confirm PIN callback: %d\n", pin); - return true; - } - - 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; - } - - 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; - if (bt_state == BT_STATE_PAIRING) { - // Serial.println("Pairing complete, disconnecting"); - delay(2000); SerialBT.disconnect(); - } else { bt_state = BT_STATE_CONNECTED; } - } else { - // Serial.println("Authentication fail"); - ble_authenticated = false; - bt_state = BT_STATE_ON; - bt_update_passkey(); - 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; - if (bt_state != BT_STATE_PAIRING) { bt_state = BT_STATE_CONNECTED; } + void bt_connect_callback(uint16_t conn_handle) { + bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; } - void bt_disconnect_callback(BLEServer *server) { - uint16_t conn_id = server->getConnId(); - // Serial.printf("Disconnected: %d\n", conn_id); - display_unblank(); - ble_authenticated = false; + void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { bt_state = BT_STATE_ON; } bool bt_setup_hw() { - // Serial.println("BT setup hw"); if (!bt_ready) { if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { bt_enabled = true; @@ -334,8 +199,8 @@ char bt_devname[11]; sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); free(data); - bt_security_setup(); - + // TODO: Implement GAP & GATT for RNode comms over BLE + bt_ready = true; return true; @@ -345,237 +210,151 @@ char bt_devname[11]; } else { return false; } } - void bt_security_setup() { - // Serial.println("Executing BT security setup"); - if (pairing_pin == 0) { bt_update_passkey(); } - uint32_t passkey = pairing_pin; - // Serial.printf("Passkey is %d\n", passkey); + void bt_start() { + if (bt_state == BT_STATE_OFF) { + bt_state = BT_STATE_ON; + // TODO: Implement + } + } - 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; + bool bt_init() { + bt_state = BT_STATE_OFF; + if (bt_setup_hw()) { + if (bt_enabled && !console_active) bt_start(); + return true; + } else { + return false; + } + } - 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)); + 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(); } - if (bt_state == BT_STATE_CONNECTED && millis()-SerialBT.lastFlushTime >= BLE_FLUSH_TIMEOUT) { - if (SerialBT.transmitBufferLength > 0) { - bt_flush(); - } - } } #endif #elif MCU_VARIANT == MCU_NRF52 - uint32_t pairing_pin = 0; +uint8_t eeprom_read(uint32_t mapped_addr); - uint8_t eeprom_read(uint32_t mapped_addr); - - void bt_stop() { - // Serial.println("BT Stop"); - if (bt_state != BT_STATE_OFF) { - bt_allow_pairing = false; - bt_state = BT_STATE_OFF; - } - } - - void bt_disable_pairing() { - // Serial.println("BT Disable pairing"); +void bt_stop() { + if (bt_state != BT_STATE_OFF) { bt_allow_pairing = false; - pairing_pin = 0; - bt_ssp_pin = 0; - bt_state = BT_STATE_ON; + bt_state = BT_STATE_OFF; } +} - void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flushTXD(); } } +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) { - // Serial.println("BT pairing complete"); - BLEConnection* connection = Bluefruit.Connection(conn_handle); +void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { - ble_gap_conn_sec_mode_t security = connection->getSecureMode(); - // Serial.println("Bonding success"); - - // On the NRF52 it is not possible with the Arduino library to reject - // requests from devices with no IO capabilities, which would allow - // bypassing pin entry through pairing using the "just works" mode. - // Therefore, we must check the security level of the connection after - // pairing to ensure "just works" has not been used. If it has, we need - // to disconnect, unpair and delete any bonding information immediately. - // Settings on the SerialBT service should prevent unauthorised access to - // the serial port anyway, but this is still wise to do regardless. - // - // Note: It may be nice to have this done in the BLESecurity class in the - // future, but as it stands right now I'd have to fork the BSP to do - // that, which I don't fancy doing. Impact on security is likely minimal. - // Requires investigation. - - if (security.sm == 1 && security.lv >= 3) { - // Serial.println("Auth level success"); - bt_state = BT_STATE_CONNECTED; - cable_state = CABLE_STATE_DISCONNECTED; - connection->disconnect(); - bt_disable_pairing(); - } else { - // Serial.println("Auth level failure, debonding"); - if (connection->bonded()) { connection->removeBondKey(); } - connection->disconnect(); - bt_disable_pairing(); - } - } else { - // Serial.println("Bonding failure"); - connection->disconnect(); + bt_state = BT_STATE_CONNECTED; + cable_state = CABLE_STATE_DISCONNECTED; bt_disable_pairing(); + } else { + bt_ssp_pin = 0; } - } +} - bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { - // Serial.println("Passkey callback"); - if (bt_allow_pairing) { - return true; +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); + } + kiss_indicate_btpin(); + if (match_request) { + if (bt_allow_pairing) { + return true; + } } return false; - } +} - void bt_connect_callback(uint16_t conn_handle) { - // Serial.println("Connect callback"); - bt_state = BT_STATE_CONNECTED; - cable_state = CABLE_STATE_DISCONNECTED; +void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { + bt_state = BT_STATE_ON; +} - BLEConnection* conn = Bluefruit.Connection(conn_handle); - conn->requestPHY(BLE_GAP_PHY_2MBPS); - conn->requestMtuExchange(512+3); - conn->requestDataLengthUpdate(); - } - - void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { - // Serial.println("Disconnect callback"); - if (reason != BLE_GAP_SEC_STATUS_SUCCESS) { - bt_state = BT_STATE_ON; +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; } - } - - void bt_update_passkey() { - // Serial.println("Update passkey"); - pairing_pin = random(899999)+100000; - bt_ssp_pin = pairing_pin; - } - - uint32_t bt_get_passkey() { - // Serial.println("API passkey request"); - if (pairing_pin == 0) { bt_update_passkey(); } - return pairing_pin; - } - - bool bt_setup_hw() { - // Serial.println("Setup HW"); - if (!bt_ready) { + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.autoConnLed(false); + if (Bluefruit.begin()) { + Bluefruit.setTxPower(8); // Check bluefruit.h for supported values + Bluefruit.Security.setIOCaps(true, true, false); + Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); + Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); + Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); + 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 - if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { + data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); #else - if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { + data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); #endif - bt_enabled = true; - } else { - bt_enabled = false; - } - Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); - Bluefruit.autoConnLed(false); - if (Bluefruit.begin()) { - uint32_t pin = bt_get_passkey(); - char pin_char[6]; - sprintf(pin_char,"%lu", pin); + unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); + memcpy(bt_dh, hash, BT_DEV_HASH_LEN); + sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); + free(data); - 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.Security.setPIN(pin_char); - 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, "RNode %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() { - // Serial.println("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(); - blebas.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(); - // Guard to ensure SerialBT service is not duplicated through BT being power cycled - if (!SerialBT_init) { - SerialBT.bufferTXD(true); // enable buffering + SerialBT.begin(); - SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial - SerialBT.begin(); - SerialBT_init = true; - } + 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() { - // Serial.println("BT init"); +bool bt_init() { bt_state = BT_STATE_OFF; if (bt_setup_hw()) { if (bt_enabled && !console_active) bt_start(); @@ -583,28 +362,18 @@ char bt_devname[11]; } 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() { - // Serial.println("BT enable pairing"); - if (bt_state == BT_STATE_OFF) bt_start(); - - uint32_t pin = bt_get_passkey(); - char pin_char[6]; - sprintf(pin_char,"%lu", pin); - Bluefruit.Security.setPIN(pin_char); - - bt_allow_pairing = true; - bt_pairing_started = millis(); - bt_state = BT_STATE_PAIRING; - kiss_indicate_btpin(); - } - - void bt_debond_all() { } - - 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 3a41183..3d0a80c 100644 --- a/Boards.h +++ b/Boards.h @@ -14,7 +14,6 @@ // along with this program. If not, see . #include "Interfaces.h" -#include "ROM.h" #ifndef BOARDS_H #define BOARDS_H @@ -25,123 +24,30 @@ #define MCU_ESP32 0x81 #define MCU_NRF52 0x71 - // 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_T3S3 0x42 // T3S3 devices - #define MODEL_A1 0xA1 // T3S3, 433 MHz with SX1268 - #define MODEL_A5 0xA5 // T3S3, 433 MHz with SX1278 - #define MODEL_A6 0xA6 // T3S3, 868 MHz with SX1262 - #define MODEL_AA 0xAA // T3S3, 868 MHz with SX1276 - #define MODEL_AC 0xAC // T3S3, 2.4 GHz with SX1280 and PA - - #define PRODUCT_TBEAM 0xE0 // T-Beam devices - #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_XIAO_S3 0xEB - #define BOARD_XIAO_S3 0x3E - #define MODEL_DE 0xDE // Xiao ESP32S3 with Wio-SX1262 module, 433 MHz - #define MODEL_DD 0xDD // Xiao ESP32S3 with Wio-SX1262 module, 868 MHz - - #define PRODUCT_T32_10 0xB2 - #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 - #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 PRODUCT_H32_V2 0xC0 // Board code 0x38 - #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 - #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_H_W_PAPER 0xC3 - #define BOARD_H_W_PAPER 0x3F - #define MODEL_C8 0xC8 - - #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 rev 1.3) - #define MODEL_14 0x14 // RAK4631, 868/915 MHz with WisBlock SX1280 module (LIBSYS002 rev 1.3) - - #define PRODUCT_OPENCOM_XL 0x20 // openCom XL - sold by Liberated Embedded Systems - #define BOARD_OPENCOM_XL 0x52 - #define MODEL_21 0x21 // openCom XL v1, 868/915 MHz - - #define BOARD_E22_ESP32 0x45 // 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_HELTEC_T114 0xC2 // Heltec Mesh Node T114 - #define BOARD_HELTEC_T114 0x3C - #define MODEL_C6 0xC6 // Heltec Mesh Node T114, 470-510 MHz - #define MODEL_C7 0xC7 // Heltec Mesh Node T114, 863-928 MHz - #define MODEL_CB 0xCB // Heltec Mesh Node T114, 863-928 MHz + GPS - - #define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices - #define BOARD_TECHO 0x44 - #define MODEL_16 0x16 // T-Echo 433 MHz - #define MODEL_17 0x17 // T-Echo 868/915 MHz - - #define PRODUCT_HMBRW 0xF0 + #define BOARD_RNODE 0x31 #define BOARD_HMBRW 0x32 + #define BOARD_TBEAM 0x33 #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_RNODE_NG_22 0x42 #define BOARD_GENERIC_NRF52 0x50 - #define MODEL_FE 0xFE // Homebrew board, max 17dBm output power - #define MODEL_FF 0xFF // Homebrew board, max 14dBm output power + #define BOARD_RAK4631 0x51 - // Displays #define OLED 0x01 #define EINK_BW 0x02 #define EINK_3C 0x03 - #define MONO_OLED 0x04 - #define TFT 0x05 #if defined(ESP32) #define PLATFORM PLATFORM_ESP32 #define MCU_VARIANT MCU_ESP32 - #elif defined(NRF52840_XXAA) || defined(_VARIANT_PCA10056_) + #elif defined(NRF52840_XXAA) #include #define PLATFORM PLATFORM_NRF52 #define MCU_VARIANT MCU_NRF52 @@ -166,9 +72,11 @@ #endif #if MCU_VARIANT == MCU_ESP32 - // Board models for ESP32 based builds are defined by the build target in - // the makefile. If you are not using make to compile this firmware, you - // can manually define the model here. + + // Board models for ESP32 based builds are + // defined by the build target in the makefile. + // If you are not using make to compile this + // firmware, you can manually define model here. // // #define BOARD_MODEL BOARD_GENERIC_ESP32 #define CONFIG_UART_BUFFER_SIZE 6144 @@ -189,7 +97,7 @@ #define INTERFACE_COUNT 1 const int pin_led_rx = 14; const int pin_led_tx = 32; - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { @@ -219,6 +127,7 @@ #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 @@ -226,39 +135,9 @@ #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; - #if BOARD_VARIANT == MODEL_E4 || BOARD_VARIANT == MODEL_E9 - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; - 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 - #define OCP_TUNED 0x38 const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX1262 @@ -283,7 +162,6 @@ -1 // pin_tcxo_enable } }; - #endif #elif BOARD_MODEL == BOARD_HUZZAH32 #define HAS_BLUETOOTH true @@ -293,7 +171,7 @@ const int pin_led_rx = 14; const int pin_led_tx = 32; - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { @@ -303,7 +181,7 @@ }, }; const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX127X + // SX1262 { 4, // pin_ss -1, // pin_sclk @@ -322,6 +200,7 @@ #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 @@ -365,6 +244,7 @@ #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 @@ -380,7 +260,7 @@ #endif - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { @@ -409,15 +289,13 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true + #define HAS_BLE true #define HAS_PMU true - #define HAS_NP true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 - - const int pin_np = 12; - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; #if HAS_TCXO == true const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X @@ -485,13 +363,6 @@ #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; @@ -500,7 +371,7 @@ const int pin_led_tx = 25; #endif - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { @@ -528,18 +399,15 @@ #elif BOARD_MODEL == BOARD_HELTEC32_V3 #define IS_ESP32S3 true #define HAS_DISPLAY true - #define DISPLAY OLED #define HAS_BLUETOOTH false #define HAS_BLE true - #define HAS_PMU true - #define HAS_CONSOLE true + #define HAS_CONSOLE false #define HAS_EEPROM true #define HAS_INPUT true #define HAS_SLEEP true #define PIN_WAKEUP GPIO_NUM_0 #define WAKEUP_LEVEL 0 #define INTERFACE_COUNT 1 - #define OCP_TUNED 0x38 const int pin_btn_usr1 = 0; @@ -576,68 +444,6 @@ } }; - #elif BOARD_MODEL == BOARD_H_W_PAPER - // Heltec Wireless Paper. Basically the Heltec LoRa32 v3 with an eink display. - // TODO, need to confirm that the display is a 213BN - #define IS_ESP32S3 true - #define HAS_DISPLAY true - #define HAS_BLUETOOTH false - #define HAS_BLE true - #define HAS_PMU true - #define HAS_CONSOLE true - #define HAS_EEPROM true - #define HAS_INPUT true - #define HAS_SLEEP true - #define DISPLAY EINK_BW - #define DISPLAY_SCALE_OVERRIDE true - #define DISPLAY_SCALE 1.90625 - #define DISPLAY_MODEL GxEPD2_213_BN - #define PIN_WAKEUP GPIO_NUM_0 - #define WAKEUP_LEVEL 0 - #define INTERFACE_COUNT 1 - #define OCP_TUNED 0x38 - - const int pin_btn_usr1 = 0; - - #if defined(EXTERNAL_LEDS) - const int pin_led_rx = 13; - const int pin_led_tx = 14; - #else - const int pin_led_rx = 35; - const int pin_led_tx = 35; - #endif - - 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 - { - 8, // pin_ss - 9, // pin_sclk - 10, // pin_mosi - 11, // pin_miso - 13, // pin_busy - 14, // pin_dio - 12, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - - const int pin_disp_cs = 4; - const int pin_disp_dc = 5; - const int pin_disp_reset = 6; - const int pin_disp_busy = 7; - const int pin_disp_en = 45; - #elif BOARD_MODEL == BOARD_RNODE_NG_20 #define HAS_DISPLAY true #define DISPLAY OLED @@ -713,7 +519,8 @@ #endif #endif - const uint8_t interfaces[INTERFACE_COUNT] = {SX1276}; + + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX127X { @@ -737,12 +544,13 @@ -1 // pin_tcxo_enable } }; - - #elif BOARD_MODEL == BOARD_T3S3 + + #elif BOARD_MODEL == BOARD_RNODE_NG_22 #define IS_ESP32S3 true + #define HAS_DISPLAY true #define DISPLAY OLED - #define HAS_CONSOLE true + #define HAS_CONSOLE false #define HAS_BLUETOOTH false #define HAS_BLE true #define HAS_PMU true @@ -754,87 +562,10 @@ #define HAS_SLEEP true #define PIN_WAKEUP GPIO_NUM_0 #define WAKEUP_LEVEL 0 - #define INTERFACE_COUNT 1 + // #define PIN_DISP_SLEEP 21 + // #define DISP_SLEEP_LEVEL HIGH const int pin_btn_usr1 = 0; - - #if BOARD_VARIANT == MODEL_A1 || BOARD_VARIANT == MODEL_A6 - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - }, - }; - const uint8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 7, // pin_ss - 5, // pin_sclk - 6, // pin_mosi - 3, // pin_miso - 34, // pin_busy - 33, // pin_dio - 8, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - #elif BOARD_VARIANT == MODEL_A5 || BOARD_VARIANT == MODEL_AA - const uint8_t interfaces[INTERFACE_COUNT] = {SX1278}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1278 - { - false, // DEFAULT_SPI - false, // HAS_TCXO - false // DIO2_AS_RF_SWITCH - }, - }; - const uint8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1278 - { - 7, // pin_ss - 5, // pin_sclk - 6, // pin_mosi - 3, // pin_miso - 34, // pin_busy - 33, // pin_dio - 8, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - #elif BOARD_VARIANT == MODEL_AC // SX1280 with PA - #define CONFIG_QUEUE_0_SIZE 6144 - 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 const int pin_np = 38; const int pin_dac = 25; @@ -844,7 +575,6 @@ 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; @@ -855,39 +585,6 @@ #endif #endif - #elif BOARD_MODEL == BOARD_TDECK - #define IS_ESP32S3 true - #define HAS_DISPLAY false - #define DISPLAY TFT // to be tested... - #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 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; - - #define INTERFACE_COUNT 1 const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; const bool interface_cfg[INTERFACE_COUNT][3] = { @@ -901,298 +598,28 @@ const uint8_t interface_pins[INTERFACE_COUNT][10] = { // SX1262 { - 9, // pin_ss - 40, // pin_sclk - 41, // pin_mosi - 38, // pin_miso - 13, // pin_busy - 45, // pin_dio - 17, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - - #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 OCP_TUNED 0x38 - - #define HAS_DISPLAY true - #define DISPLAY MONO_OLED - #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 SD_MISO = 37; - const int SD_MOSI = 35; - const int SD_CLK = 36; - const int SD_CS = 47; - - const int IMU_CS = 34; - - #define INTERFACE_COUNT 1 - - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - }, - }; - const uint8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 10, // pin_ss - 12, // pin_sclk - 11, // pin_mosi - 13, // pin_miso - 4, // pin_busy - 1, // pin_dio - 5, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - - #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_E22_ESP32 - #define HAS_DISPLAY true - #define DISPLAY OLED - // currently there is only support for using one Bluetooth type, - // Bluetooth has been chosen over BLE as it is less experimental - #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 - { - false, // 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 + 7, // pin_ss + 5, // pin_sclk + 6, // pin_mosi + 3, // pin_miso + 34, // pin_busy 33, // pin_dio - 23, // pin_reset - -1, // pin_txen - 14, // pin_rxen - -1 // pin_tcxo_enable - } - }; - #elif BOARD_MODEL == BOARD_XIAO_S3 - #define IS_ESP32S3 true - - #define HAS_DISPLAY true - #define DISPLAY OLED - //#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 true - #define PIN_WAKEUP GPIO_NUM_21 - #define WAKEUP_LEVEL 0 - - #define INTERFACE_COUNT 1 - -// #define PMU_IRQ 40 -// #define I2C_SCL 41 -// #define I2C_SDA 42 - - // Wio-SX1262 button pulls down GPIO21 - // THis is shared with the Yellow LED - // on the ESP32S3 (also active Low) - const int pin_btn_usr1 = 21; - - 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 - { - 41, // pin_ss - 7, // pin_sclk - 9, // pin_mosi - 8, // pin_miso - 40, // pin_busy - 39, // pin_dio - 42, // pin_reset + 8, // pin_reset -1, // pin_txen -1, // pin_rxen -1 // pin_tcxo_enable } }; -// 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; - - // HAS LED/tx on Wio board - 48 Hi/ON - // LED 21 on ESP board - Lo/ON/Yellow - // shared with button input. - #if HAS_NP == false - #if defined(EXTERNAL_LEDS) - const int pin_led_rx = 48; - const int pin_led_tx = 48; //47; - #else - const int pin_led_rx = 48; - const int pin_led_tx = 48; //47; - #endif - #endif #else #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. #endif #elif MCU_VARIANT == MCU_NRF52 - #define CONFIG_UART_BUFFER_SIZE 6144 - #define CONFIG_QUEUE_0_SIZE 6144 - #define CONFIG_QUEUE_MAX_LENGTH 200 - - #if BOARD_MODEL == BOARD_TECHO - #define _PINNUM(port, pin) ((port) * 32 + (pin)) - #define HAS_INPUT true - #define EEPROM_SIZE 296 - #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED + #if BOARD_MODEL == BOARD_RAK4631 #define HAS_EEPROM false - #define HAS_SD false #define HAS_DISPLAY true #define DISPLAY EINK_BW - #define DISPLAY_MODEL GxEPD2_154_D67 - #define BLE_MANUFACTURER "LilyGO" - #define BLE_MODEL "T-Echo" - #define HAS_CONSOLE false - #define HAS_BLE true - #define HAS_PMU true - #define CONFIG_UART_BUFFER_SIZE 32768 - #define CONFIG_QUEUE_0_SIZE 6144 - #define CONFIG_QUEUE_MAX_LENGTH 200 - #define INTERFACE_COUNT 1 - //#define I2C_SDA 26 - //#define I2C_SCL 27 - #define CONFIG_QUEUE_1_SIZE 40000 - #define HAS_BACKLIGHT true - // first interface in list is the primary - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - } - }; - - const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 24, // pin_ss - 19, // pin_sclk - 22, // pin_mosi - 23, // pin_miso - 17, // pin_busy - 20, // pin_dio - 25, // pin_reset - -1, // pin_txen - -1, // pin_rxen - 21 // pin_tcxo_enable - } - }; - - const int pin_disp_cs = 30; - const int pin_disp_dc = 28; - 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 GPS_BAUD_RATE 115200 - //#define PIN_GPS_TX 41 - //#define PIN_GPS_RX 40 - - const int pin_btn_usr1 = _PINNUM(1, 10); - const int pin_btn_touch = _PINNUM(0, 11); - - const int pin_backlight = 43; - - #define LED_ON LOW - #define LED_OFF HIGH - #define PIN_LED_GREEN _PINNUM(1, 1) - #define PIN_LED_RED _PINNUM(1, 3) - #define PIN_LED_BLUE _PINNUM(0, 14) - #define PIN_VEXT_EN _PINNUM(0, 12) - const int pin_led_rx = PIN_LED_BLUE; - const int pin_led_tx = PIN_LED_RED; - - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL - #define HAS_EEPROM false - #define HAS_DISPLAY false #define HAS_BLUETOOTH false #define HAS_BLE true #define HAS_CONSOLE false @@ -1201,18 +628,16 @@ #define HAS_SD false #define CONFIG_UART_BUFFER_SIZE 6144 #define CONFIG_QUEUE_0_SIZE 6144 - #define HAS_INPUT true #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" - #if BOARD_VARIANT == MODEL_11 || BOARD_VARIANT == MODEL_12 #define INTERFACE_COUNT 1 // first interface in list is the primary - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; + const uint8_t interfaces[INTERFACE_COUNT] = {SX126X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX1262 { @@ -1236,64 +661,18 @@ -1 // pin_tcxo_enable } }; - #elif BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21 - #define HAS_DISPLAY true - #define DISPLAY EINK_BW - #define DISPLAY_SCALE_OVERRIDE true - #define DISPLAY_SCALE 1.90625 - #define DISPLAY_MODEL GxEPD2_213_BN - #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] = {SX1262, SX1280}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - }, - // SX1280 - { - true, // DEFAULT_SPI - false,// HAS_TCXO - false // DIO2_AS_RF_SWITCH - } + #define INTERFACE_SPI + // Required because on RAK4631, non-default SPI pins must be initialised when class is declared. + const SPIClass interface_spi[1] = { + // SX1262 + SPIClass( + NRF_SPIM2, + interface_pins[0][3], + interface_pins[0][1], + interface_pins[0][2] + ) }; - const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 42, // pin_ss - 43, // pin_sclk - 44, // pin_mosi - 45, // pin_miso - 46, // pin_busy - 47, // pin_dio - 38, // pin_reset - -1, // pin_txen - 37, // pin_rxen - -1 // pin_tcxo_enable - }, - // SX1280 - { - 24, // pin_ss - 3, // pin_sclk - 30, // pin_mosi - 29, // pin_miso - 25, // pin_busy - 15, // pin_dio - 16, // pin_reset - 20, // pin_txen - 19, // pin_rxen - -1 // pin_tcxo_enable - } - }; - - #endif - const int pin_disp_cs = SS; const int pin_disp_dc = WB_IO1; @@ -1301,124 +680,17 @@ 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; - #elif BOARD_MODEL == BOARD_HELTEC_T114 - #define HAS_EEPROM false - #define HAS_DISPLAY true - #define DISPLAY TFT - #define DISPLAY_SCALE_OVERRIDE true - #define DISPLAY_SCALE 2 - #define HAS_BLUETOOTH false - #define HAS_BLE true - #define HAS_CONSOLE false - #define HAS_PMU true - #define HAS_NP true - #define HAS_SD false - #define HAS_TCXO true - #define HAS_BUSY true - #define HAS_INPUT true - #define HAS_SLEEP true - #define CONFIG_UART_BUFFER_SIZE 6144 - #define CONFIG_QUEUE_SIZE 6144 - #define CONFIG_QUEUE_MAX_LENGTH 200 - #define EEPROM_SIZE 296 - #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED - #define BLE_MANUFACTURER "Heltec" - #define BLE_MODEL "T114" - - #define PIN_T114_ADC_EN 6 - #define PIN_VEXT_EN 21 - - // LED - #define LED_T114_GREEN 3 - #define PIN_T114_LED 14 - #define NP_M 1 - const int pin_np = PIN_T114_LED; - - - // pins for buttons on Heltec T114 - const int pin_btn_usr1 = 42; - - const int pin_led_rx = 35; - const int pin_led_tx = 35; - - #define PIN_T114_TFT_BLGT 15 - #define PIN_T114_TFT_EN 3 - - // pins for ST7789 display on Heltec T114 - const int DISPLAY_DC = 12; - const int DISPLAY_CS = 11; - const int DISPLAY_MISO = 11; // not connected - const int DISPLAY_MOSI = 9; - const int DISPLAY_CLK = 8; - const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT; - const int DISPLAY_RST = 2; - - #define INTERFACE_COUNT 1 - - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - } - }; - const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 24, // pin_ss - 19, // pin_sclk - 22, // pin_mosi - 23, // pin_miso - 17, // pin_busy - 20, // pin_dio - 25, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - - #if BOARD_VARIANT == MODEL_CB - #define HAS_GPS true - #define GPS_BAUD_RATE 9600 - #define PIN_GPS_RX 37 - #define PIN_GPS_TX 39 - #endif #else #error An unsupported nRF board was selected. Cannot compile RNode firmware. #endif #endif - - #ifndef DISPLAY_SCALE - #define DISPLAY_SCALE 1 - #endif - - #ifndef HAS_BUSY - const int pin_busy = -1; - #endif - - #ifndef LED_ON - #define LED_ON HIGH - #endif - - #ifndef LED_OFF - #define LED_OFF LOW - #endif - - // Default OCP value if not specified - // in board configuration - #ifndef OCP_TUNED - #define OCP_TUNED 0x38 - #endif - - #ifndef NP_M - #define NP_M 0.15 + #ifndef INTERFACE_SPI + // Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors. + #define INTERFACE_SPI + const SPIClass interface_spi[1]; #endif #endif diff --git a/Config.h b/Config.h index 90c6b20..aa862ba 100644 --- a/Config.h +++ b/Config.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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 0x4b + #define MIN_VERS 0x49 #define MODE_HOST 0x11 #define MODE_TNC 0x12 @@ -28,8 +28,6 @@ #define CABLE_STATE_DISCONNECTED 0x00 #define CABLE_STATE_CONNECTED 0x01 uint8_t cable_state = CABLE_STATE_DISCONNECTED; - - #define MAX_INTERFACES 12 #define BT_STATE_NA 0xff #define BT_STATE_OFF 0x00 @@ -65,6 +63,12 @@ // 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; + #define LORA_CAD_SYMBOLS 3 + // Operational variables bool community_fw = true; bool hw_ready = false; @@ -72,25 +76,17 @@ bool pmu_ready = false; bool promisc = false; bool implicit = false; - bool memory_low = false; uint8_t implicit_l = 0; uint8_t op_mode = MODE_HOST; uint8_t model = 0x00; uint8_t hwrev = 0x00; - int current_rssi = -292; int last_rssi = -292; uint8_t last_rssi_raw = 0x00; uint8_t last_snr_raw = 0x80; - uint8_t seq[INTERFACE_COUNT]; - uint16_t read_len[INTERFACE_COUNT]; - - bool serial_in_frame = false; - - FIFOBuffer packet_rdy_interfaces; - - uint8_t packet_rdy_interfaces_buf[MAX_INTERFACES]; + uint8_t seq = 0xFF; + uint16_t read_len = 0; // Incoming packet buffer uint8_t pbuf[MTU]; @@ -104,27 +100,13 @@ uint32_t stat_rx = 0; uint32_t stat_tx = 0; - bool stat_signal_detected = false; - bool stat_signal_synced = false; - bool stat_rx_ongoing = false; - bool dcd = false; - bool dcd_led = false; - bool dcd_waiting = false; - long dcd_wait_until = 0; - uint16_t dcd_count = 0; - uint16_t dcd_threshold = 2; - - uint32_t last_status_update = 0; - uint32_t last_dcd = 0; - - uint32_t last_rx = 0; - uint32_t last_tx = 0; + unsigned long last_tx = 0; + 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; @@ -134,8 +116,6 @@ uint8_t battery_state = 0x00; uint8_t display_intensity = 0xFF; uint8_t display_addr = 0xFF; - volatile bool display_updating = false; - bool display_blanking_enabled = false; bool display_diagnostics = true; bool device_init_done = false; bool eeprom_ok = false; @@ -143,9 +123,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 c59d348..4321d9f 100644 --- a/Console.h +++ b/Console.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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 e782db0..d3158ae 100644 --- a/Console/Makefile +++ b/Console/Makefile @@ -1,6 +1,5 @@ -# These paths will have to be changed according to where you store these directories on your system PATH_RETICULUM_WEBSITE=../../sites/reticulum.network -PATH_PACKAGES=../../../rns_build +PATH_PACKAGES=../../dist_archive clean: @echo Cleaning... @@ -15,14 +14,14 @@ dirs: @mkdir -p ./build/images pages: - python3 ./build.py + python ./build.py pages-debug: - python3 ./build.py --no-gz --no-remap + python ./build.py --no-gz --no-remap sourcepack: @echo Packing firmware sources... - cd .. && zip -r Console/build/pkg/rnode_firmware.zip * -x Builds/\* Console/\* Documentation/images/\* Documentation/RNode_v1_Manual.pdf Documentation/rnfw_1.jpg Graphics/\* Python\ Module/\* Release/\* build/\* partition_hashes + 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 data: @echo Including assets... @@ -30,7 +29,7 @@ data: @cp assets/gfx/* build/gfx/ @cp assets/images/* build/images/ @cp assets/stl/* build/3d/ - # @cp assets/pkg/* build/pkg/ + #@cp assets/pkg/* build/pkg/ # @cp assets/scripts/* build/scripts/ # @cp -r ../../Reticulum/docs/manual/* build/reticulum_manual/ # @cp -r ../../Reticulum/docs/Reticulum\ Manual.pdf build/reticulum_manual/ @@ -45,4 +44,4 @@ site: clean external dirs data sourcepack pages local: clean external dirs data sourcepack pages-debug serve: - python3 -m http.server 7777 --bind 127.0.0.1 --directory ./build + python -m http.server 7777 --bind 127.0.0.1 --directory ./build diff --git a/Console/assets/images/bg_h_1.webp b/Console/assets/images/bg_h_1.webp index 9fa57e3..e650d09 100644 Binary files a/Console/assets/images/bg_h_1.webp and b/Console/assets/images/bg_h_1.webp differ diff --git a/Console/assets/stl/Handheld_RNode_Parts.7z b/Console/assets/stl/Handheld_RNode_Parts.7z index df861b6..52288ce 100644 Binary files a/Console/assets/stl/Handheld_RNode_Parts.7z and b/Console/assets/stl/Handheld_RNode_Parts.7z differ diff --git a/Console/build.py b/Console/build.py index a3f3225..5d8a119 100644 --- a/Console/build.py +++ b/Console/build.py @@ -4,20 +4,17 @@ import sys import shutil packages = { - "rns": "rns-0.9.1-py3-none-any.whl", - "nomadnet": "nomadnet-0.6.0-py3-none-any.whl", - "lxmf": "lxmf-0.6.2-py3-none-any.whl", - "rnsh": "rnsh-0.1.5-py3-none-any.whl", + "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", + "rnsh": "rnsh-0.1.4-py3-none-any.whl", } DEFAULT_TITLE = "RNode Bootstrap Console" SOURCES_PATH="./source" BUILD_PATH="./build" - -# These paths may have to be changed depending on where you store these directories on your system -PACKAGES_PATH = "../../../rns_build" +PACKAGES_PATH = "../../dist_archive" RNS_SOURCE_PATH = "../../Reticulum" - INPUT_ENCODING="utf-8" OUTPUT_ENCODING="utf-8" @@ -177,34 +174,26 @@ mf.write(help_redirect) mf.close() def optimise_manual(path): - pm = 45 + pm = 110 scale_imgs = [ ("_images/board_rnodev2.png", pm), ("_images/board_rnode.png", pm), - ("_images/board_heltec32v20.png", pm), - ("_images/board_heltec32v30.png", pm), + ("_images/board_heltec32.png", pm), ("_images/board_t3v21.png", pm), ("_images/board_t3v20.png", 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/board_tbeam.png", 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+" -quality 25 -resize "+str(s)+" "+fp + resize = "convert "+fp+" -resize "+str(s)+" "+fp print(resize) subprocess.call(shlex.split(resize), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -216,7 +205,6 @@ 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/Console/source/guides/make_rnodes.md b/Console/source/guides/make_rnodes.md index 6190b3f..46a63f6 100644 --- a/Console/source/guides/make_rnodes.md +++ b/Console/source/guides/make_rnodes.md @@ -2,6 +2,7 @@ [title]: <> (How To Make Your Own RNodes) [image]: <> (images/g3p.webp) [excerpt]: <> (This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a commercially purchased board.) + # How To Make Your Own RNodes This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a purchased device. @@ -30,9 +31,10 @@ Currently, the RNode firmware supports a variety of different microcontrollers, Regarding the LoRa transceiver module, there is going to be an almost overwhelming amount of options to choose from. To narrow it down, here are the essential characteristics to look for: -- The RNode firmware needs a module based on the **Semtech SX1276**, **Semtech SX1278**, **SX1262**, **SX1268** and **SX1280** LoRa transceiver ICs. These come in several different variants, for all frequency bands from about 150 MHz to 2500 MHz. +- The RNode firmware needs a module based on the **Semtech SX1276** or **Semtech SX1278** LoRa transceiver IC. These come in several different variants, for all frequency bands from about 150 MHz to about 1100 MHz. +- Support for **SX1262**, **SX1268** and **SX1280**-based modules is coming soon, but until that is released, only **SX1276** and **SX1278** modules will work. - The module *must* expose the direct SPI bus to the transceiver chip. UART based modules that add their own communications layer will not work. -- The module must also expose the *reset* line of the chip, and provide the **DIO0** (or other relevant) interrupt signal *from* the chip. +- The module must also expose the *reset* line of the chip, and provide the **DIO0** interrupt signal *from* the chip. - As mentioned above, the module must be logic-level compatible with the microcontroller you are using, unless you want to add a level-shifter. Resistor divider arrays will most likely not work here, due to the bus speeds required. Keeping those things in mind, you should be able to select a suitable combination of microcontroller board and transceiver module. @@ -54,17 +56,12 @@ In the photo above I used an Adafruit Feather ESP32 board and a ModTronix inAir4 9. Connect the *DIO0* pin of the transceiver module to the *DIO0 interrupt pin* of the microcontroller board. 10. You can optionally connect transmit and receiver LEDs to the corresponding pins of the microcontroller board. -The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the [Config.h](https://github.com/markqvist/RNode_Firmware/blob/master/Config.h) file of the [RNode Firmware](https://unsigned.io/rnode_firmware). +The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the `Config.h` file of the [RNode Firmware]({ASSET_PATH}pkg/rnode_firmware.zip). -### Loading the Firmware -Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility](https://markqvist.github.io/Reticulum/manual/using.html#the-rnodeconf-utility). To prepare for loading the firmware, make sure that `python` and `pip` is installed on your system, then install the `rns` package (which includes the `rnodeconf` program) by issuing the command: +## Loading the Firmware +Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility]({ASSET_PATH}m/using.html#the-rnodeconf-utility). - -```txt -pip install rns -``` - -If installation goes well, you can now move on to the next step. +The `rnodeconf` program is included in the `rns` package. Please read [these instructions]({ASSET_PATH}s_rns.html) for more information on how to install it from this repository, or from the Internet. If installation goes well, you can now move on to the next step. > *Take Care*: A LoRa transceiver module **must** be connected to the board for the firmware to start and accept commands. If the firmware does not verify that the correct transceiver is available on the SPI bus, execution is stopped, and the board will not accept commands. If you find the board unresponsive after installing the firmware, or EEPROM configuration fails, double-check your transceiver module wiring! @@ -76,6 +73,24 @@ rnodeconf --autoinstall The installer will now ask you to insert the device you want to set up, scan for connected serial ports, and ask you a number of questions regarding the device. When it has the information it needs, it will install the correct firmware and configure the necessary parameters in the device EEPROM for it to function properly. +> **Please Note!** If you are connected to the Internet while installing, the autoinstaller will automatically download any needed firmware files to a local cache before installing. + +> If you do not have an active Internet connection while installing, you can extract and use the firmware from this device instead. This will **only** work if you are building the same type of RNode as the device you are extracting from, as the firmware has to match the targeted board and hardware configuration. + +If you need to extract the firmware from an existing RNode, run the following command: + +``` +rnodeconf --extract +``` + +If `rnodeconf` finds a working RNode, it will extract and save the firmware from the device for later use. You can then run the auto-installer with the `--use-extracted` option to use the locally extracted file: + +``` +rnodeconf --autoinstall --use-extracted +``` + +This also works for updating the firmware on existing RNodes, so you can extract a newer firmware from one RNode, and deploy it onto other RNodes using the same method. Just use the `--update` option instead of `--autoinstall`. + If the install goes well, you will be greated with a success message telling you that your device is now ready. To confirm everything is OK, you can query the device info with: ```txt diff --git a/Device.h b/Device.h index fb250f4..944479d 100644 --- a/Device.h +++ b/Device.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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 @@ -36,8 +36,6 @@ #define APPLICATION_START 0x26000 #define USER_DATA_START 0xED000 - -#define IMG_SIZE_START 0xFF008 #endif #endif @@ -143,13 +141,6 @@ void device_save_firmware_hash() { } #if MCU_VARIANT == MCU_NRF52 -uint32_t retrieve_application_size() { - uint8_t bytes[4]; - memcpy(bytes, (const void*)IMG_SIZE_START, 4); - uint32_t fw_len = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; - return fw_len; -} - void calculate_region_hash(unsigned long long start, unsigned long long end, uint8_t* return_hash) { // this function calculates the hash digest of a region of memory, // currently it is only designed to work for the application region @@ -161,12 +152,16 @@ void calculate_region_hash(unsigned long long start, unsigned long long end, uin hash.begin(CRYS_HASH_SHA256_mode); + bool finish = false; uint8_t size; + bool application = true; + int end_count = 0; + unsigned long length = 0; - while (start < end ) { + while (start < end - 1 ) { const void* src = (const void*)start; if (start + CHUNK_SIZE >= end) { - size = end - start; + size = (end - 1) - start; } else { size = CHUNK_SIZE; @@ -174,9 +169,74 @@ void calculate_region_hash(unsigned long long start, unsigned long long end, uin memcpy(chunk, src, CHUNK_SIZE); - hash.update(chunk, size); + // check if we've reached the end of the program + // if we're checking the application region + if (application) { + for (int i = 0; i < CHUNK_SIZE; i++) { + if (chunk[i] == 0xFF) { + bool matched = true; + end_count = 1; + // check if rest of chunk is FFs as well, only if FF is not + // at the end of chunk + if (i < CHUNK_SIZE - 1) { + for (int x = 0; x < CHUNK_SIZE - i; x++) { + if (chunk[i+x] != 0xFF) { + matched = false; + break; + } + end_count++; + } + } + + if (matched) { + while (end_count < END_SECTION_SIZE) { + // check if bytes in next chunk up to total + // required are also FFs + for (int x = 1; x <= ceil(END_SECTION_SIZE / CHUNK_SIZE); x++) { + const void* src_next = (const void*)start + CHUNK_SIZE*x; + if ((END_SECTION_SIZE - end_count) > CHUNK_SIZE) { + size = CHUNK_SIZE; + } else { + size = END_SECTION_SIZE - end_count; + } + memcpy(chunk_next, src_next, size); + for (int y = 0; y < size; y++) { + if (chunk_next[y] != 0xFF) { + matched = false; + break; + } + end_count++; + } + + if (!matched) { + break; + } + } + if (!matched) { + break; + } + } + + if (matched) { + finish = true; + size = i; + break; + } + } + } + } + } + + if (finish) { + hash.update(chunk, size); + length += size; + break; + } else { + hash.update(chunk, size); + } start += CHUNK_SIZE; + length += CHUNK_SIZE; } hash.end(return_hash); } @@ -197,14 +257,16 @@ void device_validate_partitions() { esp_partition_get_sha256(esp_ota_get_running_partition(), dev_firmware_hash); #elif MCU_VARIANT == MCU_NRF52 // todo, add bootloader, partition table, or softdevice? - calculate_region_hash(APPLICATION_START, APPLICATION_START+retrieve_application_size(), dev_firmware_hash); + calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash); #endif + #if VALIDATE_FIRMWARE for (uint8_t i = 0; i < DEV_HASH_LEN; i++) { if (dev_firmware_hash_target[i] != dev_firmware_hash[i]) { fw_signature_validated = false; break; } } + #endif } bool device_firmware_ok() { @@ -213,7 +275,6 @@ bool device_firmware_ok() { #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 bool device_init() { - #if VALIDATE_FIRMWARE if (bt_ready) { #if MCU_VARIANT == MCU_ESP32 for (uint8_t i=0; i. -#include -#define DISP_W 128 -#define DISP_H 64 +#include #if DISPLAY == OLED #include #include -#define DISPLAY_BLACK SSD1306_BLACK -#define DISPLAY_WHITE SSD1306_WHITE - +#define DISP_W 128 +#define DISP_H 64 #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C void (*display_callback)(); -void display_add_callback(void (*callback)()) { display_callback = callback; } -void busyCallback(const void* p) { display_callback(); } -#define DISPLAY_BLACK GxEPD_BLACK -#define DISPLAY_WHITE GxEPD_WHITE - -#elif DISPLAY == ADAFRUIT_TFT - // t-deck - #include - #define DISPLAY_WHITE ST77XX_WHITE - #define DISPLAY_BLACK ST77XX_BLACK - -#elif DISPLAY == TFT - // t114 - #include "src/display/ST7789.h" - #define DISPLAY_WHITE ST77XX_WHITE - #define DISPLAY_BLACK ST77XX_BLACK - #define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)) - -#elif DISPLAY == MONO_OLED - // tbeam_s - #include - #define DISPLAY_WHITE SH110X_WHITE - #define DISPLAY_BLACK SH110X_BLACK +void display_add_callback(void (*callback)()) { + display_callback = callback; +} +void busyCallback(const void* p) { + display_callback(); +} #endif - #if DISPLAY == EINK_BW // use GxEPD2 because adafruit EPD support for partial refresh is bad #include @@ -61,7 +40,6 @@ void busyCallback(const void* p) { display_callback(); } #endif #include "Fonts/Org_01.h" - #if BOARD_MODEL == BOARD_RNODE_NG_20 || BOARD_MODEL == BOARD_LORA32_V2_0 #if DISPLAY == OLED #define DISP_RST -1 @@ -90,115 +68,67 @@ void busyCallback(const void* p) { display_callback(); } #define DISP_RST -1 #define DISP_ADDR 0x3C #endif -#elif BOARD_MODEL == BOARD_T3S3 +#elif BOARD_MODEL == BOARD_RNODE_NG_22 #if DISPLAY == OLED #define DISP_RST 21 #define DISP_ADDR 0x3C #define SCL_OLED 17 #define SDA_OLED 18 #endif -#elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL +#elif BOARD_MODEL == BOARD_RAK4631 #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 + #define DISPLAY_MODEL GxEPD2_213_BN #elif DISPLAY == EINK_3C #define DISP_W 250 #define DISP_H 122 #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 -#elif BOARD_MODEL == BOARD_H_W_PAPER - #define DISP_W 250 - #define DISP_H 122 - #define DISP_ADDR -1 -#elif BOARD_MODEL == BOARD_XIAO_S3 - #define DISP_RST -1 - #define DISP_ADDR 0x3C - #define SCL_OLED 6 - #define SDA_OLED 5 - #define DISP_CUSTOM_ADDR true #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_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL || BOARD_MODEL == BOARD_H_W_PAPER - #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.5; - uint32_t last_epd_refresh = 0; - uint32_t last_epd_full_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 - uint32_t last_epd_refresh = 0; - uint32_t last_epd_full_refresh = 0; - #define REFRESH_PERIOD 600000 // 10 minutes in ms - #endif -#elif BOARD_MODEL == BOARD_TECHO +#if BOARD_MODEL != BOARD_RAK4631 +// support for BOARD_RAK4631 OLED not implemented yet +#if DISPLAY == OLED +Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); +float disp_target_fps = 7; +#endif +#endif +#if BOARD_MODEL == BOARD_RAK4631 +#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; -uint32_t last_epd_full_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 4x the refresh period +#endif #else - #if DISPLAY == OLED - Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); - #elif 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); - #elif BOARD_MODEL == BOARD_HELTEC_T114 - ST7789Spi display(&SPI1, DISPLAY_RST, DISPLAY_DC, DISPLAY_CS); - #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; +// add more eink compatible boards here #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; -uint32_t last_unblank_event = 0; -uint32_t display_blanking_timeout = DISPLAY_BLANKING_TIMEOUT; -uint8_t display_unblank_intensity = display_intensity; -bool display_blanked = false; -bool display_tx[INTERFACE_COUNT] = {false}; -bool recondition_display = false; int disp_update_interval = 1000/disp_target_fps; -int epd_update_interval = 1000/disp_target_fps; uint32_t last_page_flip = 0; uint32_t last_interface_page_flip = 0; int page_interval = 4000; @@ -217,7 +147,13 @@ uint8_t online_interface_list[INTERFACE_COUNT] = {0}; uint8_t online_interfaces = 0; +#if DISPLAY == OLED #define WATERFALL_SIZE 46 +#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) +#define WATERFALL_SIZE 92 +#else +// add more eink compatible boards here +#endif int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0}; int waterfall_head[INTERFACE_COUNT] = {0}; @@ -227,95 +163,34 @@ 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); - -void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour); +#elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) +GFXcanvas1 stat_area(DISP_H, DISP_W/2); +GFXcanvas1 disp_area(DISP_H, DISP_W/2); +#endif void update_area_positions() { - #if BOARD_MODEL == BOARD_HELTEC_T114 - if (disp_mode == DISP_MODE_PORTRAIT) { - p_ad_x = 16; - p_ad_y = 64; - p_as_x = 16; - p_as_y = p_ad_y+126; - } else if (disp_mode == DISP_MODE_LANDSCAPE) { - p_ad_x = 0; - p_ad_y = 96; - p_as_x = 126; - p_as_y = p_ad_y; - } - #elif BOARD_MODEL == BOARD_TECHO - if (disp_mode == DISP_MODE_PORTRAIT) { - p_ad_x = 61; - p_ad_y = 36; - p_as_x = 64; - p_as_y = 64+36; - } else if (disp_mode == DISP_MODE_LANDSCAPE) { - p_ad_x = 0; - p_ad_y = 0; - p_as_x = 64; - p_as_y = 0; - } - #else - if (disp_mode == DISP_MODE_PORTRAIT) { - p_ad_x = 0 * DISPLAY_SCALE; - p_ad_y = 0 * DISPLAY_SCALE; - p_as_x = 0 * DISPLAY_SCALE; - p_as_y = 64 * DISPLAY_SCALE; - } else if (disp_mode == DISP_MODE_LANDSCAPE) { - p_ad_x = 0 * DISPLAY_SCALE; - p_ad_y = 0 * DISPLAY_SCALE; - p_as_x = 64 * DISPLAY_SCALE; - p_as_y = 0 * DISPLAY_SCALE; - } - #endif + if (disp_mode == DISP_MODE_PORTRAIT) { + p_ad_x = 0; + p_ad_y = 0; + p_as_x = 0; + p_as_y = DISP_H; + } else if (disp_mode == DISP_MODE_LANDSCAPE) { + p_ad_x = 0; + p_ad_y = 0; + p_as_x = DISP_H; + p_as_y = 0; + } } uint8_t display_contrast = 0x00; -#if BOARD_MODEL == BOARD_TBEAM_S_V1 - void set_contrast(Adafruit_SH1106G *display, uint8_t value) { - } -#elif BOARD_MODEL == BOARD_HELTEC_T114 - void set_contrast(ST7789Spi *display, uint8_t value) { } -#elif BOARD_MODEL == BOARD_TECHO - void set_contrast(void *display, uint8_t value) { - if (value == 0) { analogWrite(pin_backlight, 0); } - else { analogWrite(pin_backlight, 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; - } -#elif BOARD_MODEL == BOARD_OPENCOM_XL || BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_H_W_PAPER - // no backlight on these displays - void set_contrast (void* display, uint8_t contrast) {}; -#else - void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { +#if DISPLAY == OLED +void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { display->ssd1306_command(SSD1306_SETCONTRAST); display->ssd1306_command(contrast); - } +} #endif bool display_init() { @@ -325,7 +200,7 @@ bool display_init() { digitalWrite(pin_display_en, LOW); delay(50); digitalWrite(pin_display_en, HIGH); - #elif BOARD_MODEL == BOARD_T3S3 + #elif BOARD_MODEL == BOARD_RNODE_NG_22 Wire.begin(SDA_OLED, SCL_OLED); #elif BOARD_MODEL == BOARD_HELTEC32_V2 Wire.begin(SDA_OLED, SCL_OLED); @@ -347,7 +222,7 @@ bool display_init() { delay(50); digitalWrite(pin_display_en, HIGH); Wire.begin(SDA_OLED, SCL_OLED); - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL + #elif BOARD_MODEL == BOARD_RAK4631 #if DISPLAY == OLED #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C pinMode(pin_disp_en, INPUT_PULLUP); @@ -355,185 +230,86 @@ bool display_init() { display.init(0, true, 10, false, SPI, 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); #endif - #elif BOARD_MODEL == BOARD_H_W_PAPER - pinMode(pin_disp_en, OUTPUT); - digitalWrite(pin_disp_en, LOW); - display.init(0, true, 10, false, SPI, SPISettings(4000000, MSBFIRST, SPI_MODE0)); - display.setPartialWindow(0, 0, DISP_W, DISP_H); - - display.epd2.setBusyCallback(busyCallback); - #elif BOARD_MODEL == BOARD_HELTEC_T114 - pinMode(PIN_T114_TFT_EN, OUTPUT); - digitalWrite(PIN_T114_TFT_EN, LOW); - #elif BOARD_MODEL == BOARD_TECHO - display.init(0, true, 10, false, displaySPI, SPISettings(4000000, MSBFIRST, SPI_MODE0)); - display.setPartialWindow(0, 0, DISP_W, DISP_H); - display.epd2.setBusyCallback(busyCallback); - #if HAS_BACKLIGHT - pinMode(pin_backlight, OUTPUT); - analogWrite(pin_backlight, 0); - #endif - #elif BOARD_MODEL == BOARD_TBEAM_S_V1 - Wire.begin(SDA_OLED, SCL_OLED); - #elif BOARD_MODEL == BOARD_XIAO_S3 - Wire.begin(SDA_OLED, SCL_OLED); #endif - #if HAS_EEPROM - uint8_t display_rotation = EEPROM.read(eeprom_addr(ADDR_CONF_DROT)); - #elif MCU_VARIANT == MCU_NRF52 - uint8_t display_rotation = eeprom_read(eeprom_addr(ADDR_CONF_DROT)); - #endif - if (display_rotation < 0 or display_rotation > 3) display_rotation = 0xFF; - #if DISP_CUSTOM_ADDR == true #if HAS_EEPROM - uint8_t display_address = EEPROM.read(eeprom_addr(ADDR_CONF_DADR)); + uint8_t display_address = EEPROM.read(eeprom_addr(ADDR_CONF_DADR)); #elif MCU_VARIANT == MCU_NRF52 - uint8_t display_address = eeprom_read(eeprom_addr(ADDR_CONF_DADR)); + uint8_t display_address = eeprom_read(eeprom_addr(ADDR_CONF_DADR)); #endif if (display_address == 0xFF) display_address = DISP_ADDR; #else uint8_t display_address = DISP_ADDR; #endif - #if HAS_EEPROM - if (EEPROM.read(eeprom_addr(ADDR_CONF_BSET)) == CONF_OK_BYTE) { - uint8_t db_timeout = EEPROM.read(eeprom_addr(ADDR_CONF_DBLK)); - if (db_timeout == 0x00) { - display_blanking_enabled = false; - } else { - display_blanking_enabled = true; - display_blanking_timeout = db_timeout*1000; - } - } - #elif MCU_VARIANT == MCU_NRF52 - if (eeprom_read(eeprom_addr(ADDR_CONF_BSET)) == CONF_OK_BYTE) { - uint8_t db_timeout = eeprom_read(eeprom_addr(ADDR_CONF_DBLK)); - if (db_timeout == 0x00) { - display_blanking_enabled = false; - } else { - display_blanking_enabled = true; - display_blanking_timeout = db_timeout*1000; - } - } - #endif - - #if DISPLAY == EINK_BW || DISPLAY == EINK_3C + + #if DISPLAY == OLED + if(!display.begin(SSD1306_SWITCHCAPVCC, display_address)) { + #elif 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); - #elif BOARD_MODEL == BOARD_HELTEC_T114 - display.init(); - // set white as default pixel colour for Heltec T114 - display.setRGB(COLOR565(0xFF, 0xFF, 0xFF)); - 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 { #if DISPLAY == OLED set_contrast(&display, display_contrast); #endif - if (display_rotation != 0xFF) { - if (display_rotation == 0 || display_rotation == 2) { - disp_mode = DISP_MODE_LANDSCAPE; - } else { - disp_mode = DISP_MODE_PORTRAIT; - } - display.setRotation(display_rotation); - } else { - #if BOARD_MODEL == BOARD_RNODE_NG_20 - disp_mode = DISP_MODE_PORTRAIT; - display.setRotation(3); - #elif BOARD_MODEL == BOARD_RNODE_NG_21 - disp_mode = DISP_MODE_PORTRAIT; - display.setRotation(3); - #elif BOARD_MODEL == BOARD_LORA32_V1_0 - disp_mode = DISP_MODE_PORTRAIT; - display.setRotation(3); - #elif BOARD_MODEL == BOARD_LORA32_V2_0 - disp_mode = DISP_MODE_PORTRAIT; - display.setRotation(3); - #elif BOARD_MODEL == BOARD_LORA32_V2_1 - disp_mode = DISP_MODE_LANDSCAPE; - display.setRotation(0); - #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_RAK4631 || 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; - display.setRotation(1); - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL - 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); - #endif - } + #if BOARD_MODEL == BOARD_RNODE_NG_20 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); + #elif BOARD_MODEL == BOARD_RNODE_NG_21 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); + #elif BOARD_MODEL == BOARD_LORA32_V1_0 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); + #elif BOARD_MODEL == BOARD_LORA32_V2_0 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); + #elif BOARD_MODEL == BOARD_LORA32_V2_1 + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(0); + #elif BOARD_MODEL == BOARD_TBEAM + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(0); + #elif BOARD_MODEL == BOARD_HELTEC32_V2 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(1); + #elif BOARD_MODEL == BOARD_RAK4631 + #if DISPLAY == OLED + #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C + disp_mode = DISP_MODE_PORTRAIT; + #endif + #elif BOARD_MODEL == BOARD_HELTEC32_V3 + disp_mode = DISP_MODE_PORTRAIT; + // Antenna conx up + display.setRotation(1); + // USB-C up + // display.setRotation(3); + #else + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); + #endif update_area_positions(); - for (int i = 0; i < INTERFACE_COUNT; i++) { - for (int j = 0; j < WATERFALL_SIZE; j++) { waterfall[i][j] = 0; } - } last_page_flip = millis(); stat_area.cp437(true); disp_area.cp437(true); - - #if BOARD_MODEL != BOARD_HELTEC_T114 display.cp437(true); - #endif #if HAS_EEPROM - display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); + display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); #elif MCU_VARIANT == MCU_NRF52 - display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); - #endif - display_unblank_intensity = display_intensity; - - #if BOARD_MODEL == BOARD_TECHO - #if HAS_BACKLIGHT - if (display_intensity == 0) { analogWrite(pin_backlight, 0); } - else { analogWrite(pin_backlight, display_intensity); } - #endif - #endif - - #if BOARD_MODEL == BOARD_TDECK - display.fillScreen(DISPLAY_BLACK); - #endif - - #if BOARD_MODEL == BOARD_HELTEC_T114 - // Enable backlight led (display is always black without this) - fillRect(p_ad_x, p_ad_y, 128, 128, DISPLAY_BLACK); - fillRect(p_as_x, p_as_y, 128, 128, DISPLAY_BLACK); - pinMode(PIN_T114_TFT_BLGT, OUTPUT); - digitalWrite(PIN_T114_TFT_BLGT, LOW); + display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); #endif return true; @@ -543,110 +319,114 @@ bool display_init() { #endif } -// Draws a line on the screen -void drawLine(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) { - #if BOARD_MODEL == BOARD_HELTEC_T114 - if(colour == DISPLAY_WHITE){ - display.setColor(WHITE); - } else if(colour == DISPLAY_BLACK) { - display.setColor(BLACK); - } - display.drawLine(x, y, width, height); - #else - display.drawLine(x, y, width, height, colour); - #endif -} - -// Draws a filled rectangle on the screen -void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) { - #if BOARD_MODEL == BOARD_HELTEC_T114 - if(colour == DISPLAY_WHITE){ - display.setColor(WHITE); - } else if(colour == DISPLAY_BLACK) { - display.setColor(BLACK); - } - display.fillRect(x, y, width, height); - #else - display.fillRect(x, y, width, height, colour); - #endif -} - -// Draws a bitmap to the display and auto scales it based on the boards configured DISPLAY_SCALE -void drawBitmap(int16_t startX, int16_t startY, const uint8_t* bitmap, int16_t bitmapWidth, int16_t bitmapHeight, uint16_t foregroundColour, uint16_t backgroundColour) { - #if !DISPLAY_SCALE_OVERRIDE - display.drawBitmap(startX, startY, bitmap, bitmapWidth, bitmapHeight, foregroundColour, backgroundColour); - #else - for(int16_t row = 0; row < bitmapHeight; row++){ - for(int16_t col = 0; col < bitmapWidth; col++){ - - // determine index and bitmask - int16_t index = row * ((bitmapWidth + 7) / 8) + (col / 8); - uint8_t bitmask = 1 << (7 - (col % 8)); - - // check if the current pixel is set in the bitmap - if(bitmap[index] & bitmask){ - // draw a scaled rectangle for the foreground pixel - fillRect(ceil(startX + col * DISPLAY_SCALE), ceil(startY + row * DISPLAY_SCALE), ceil(DISPLAY_SCALE), ceil(DISPLAY_SCALE), foregroundColour); - } else { - // draw a scaled rectangle for the background pixel - fillRect(ceil(startX + col * DISPLAY_SCALE), ceil(startY + row * DISPLAY_SCALE), ceil(DISPLAY_SCALE), ceil(DISPLAY_SCALE), backgroundColour); - } - - } - } - #endif -} - void draw_cable_icon(int px, int py) { if (cable_state == CABLE_STATE_DISCONNECTED) { - stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else if (cable_state == CABLE_STATE_CONNECTED) { - stat_area.drawBitmap(px, py, bm_cable+1*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } void draw_bt_icon(int px, int py) { if (bt_state == BT_STATE_OFF) { - stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else if (bt_state == BT_STATE_ON) { - stat_area.drawBitmap(px, py, bm_bt+1*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else if (bt_state == BT_STATE_PAIRING) { - stat_area.drawBitmap(px, py, bm_bt+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else if (bt_state == BT_STATE_CONNECTED) { - stat_area.drawBitmap(px, py, bm_bt+3*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - stat_area.drawBitmap(px, py, bm_bt+0*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } void draw_lora_icon(RadioInterface* radio, int px, int py) { // todo: make display show other interfaces if (radio_online) { - if (online_interface_list[interface_page] != radio->getIndex()) { - stat_area.drawBitmap(px - 1, py - 1, bm_dot_sqr, 18, 19, DISPLAY_WHITE, DISPLAY_BLACK); + #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); - // 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); - } - } else { - stat_area.drawBitmap(px, py, bm_rf+0*32, 16, 16, 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, 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 + } } void draw_mw_icon(int px, int py) { if (INTERFACE_COUNT >= 2) { if (interface_obj[1]->getRadioOnline()) { - stat_area.drawBitmap(px, py, bm_rf+3*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } else { - stat_area.drawBitmap(px, py, bm_rf+2*32, 16, 16, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } @@ -655,147 +435,225 @@ void draw_battery_bars(int px, int py) { if (pmu_ready) { if (battery_ready) { if (battery_installed) { - 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; - } + float battery_value = battery_percent; - if (battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { + if (battery_state == BATTERY_STATE_CHARGING) { battery_value = charge_tick; charge_tick += 3; if (charge_tick > 100) charge_tick = 0; } - if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { - 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); + 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); + #endif } else { if (battery_state == BATTERY_STATE_CHARGED) { - 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); + #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); + #endif } 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); + #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); + #endif } } } 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); + #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); + #endif } } } 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); + #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); + #endif } } #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; + 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; - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); - 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); - //} + #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); } -#if MODEM == SX1280 - #define S_RSSI_MIN -105.0 - #define S_RSSI_MAX -65.0 -#else - #define S_RSSI_MIN -135.0 - #define S_RSSI_MAX -75.0 -#endif +#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) { - stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); + 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 (radio_online) { - 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; - - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); - -#define WF_TX_SIZE 5 -#define WF_TX_WIDTH 5 - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); - 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); + #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); } -#define WF_TX_SIZE 5 #define WF_RSSI_MAX -60 #define WF_RSSI_MIN -135 -#define WF_RSSI_SPAN (WF_RSSI_MAX - WF_RSSI_MIN) +#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_PIXEL_WIDTH 22 +#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[interface_page]) { - 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[interface_page] = false; - } else { - waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; - if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; - } - stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, DISPLAY_BLACK); + 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 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) { - 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); - } + #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 } } } @@ -803,7 +661,11 @@ void draw_waterfall(int px, int py) { void draw_stat_area() { if (device_init_done) { if (!stat_area_initialised) { - stat_area.drawBitmap(0, 0, bm_frame, 64, 64, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif stat_area_initialised = true; } @@ -842,6 +704,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); @@ -851,6 +714,17 @@ void draw_stat_area() { draw_lora_icon(interface_obj[1], 45, 30); } draw_battery_bars(4, 58); + #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + draw_cable_icon(6, 18); + draw_bt_icon(6, 60); + draw_lora_icon(interface_obj[0], 86, 18); + + // todo, expand support to show more than two interfaces on screen + if (INTERFACE_COUNT > 1) { + draw_lora_icon(interface_obj[1], 86, 60); + } + draw_battery_bars(8, 113); + #endif radio_online = false; for (int i = 0; i < INTERFACE_COUNT; i++) { if (interface_obj[i]->getRadioOnline()) { @@ -858,10 +732,16 @@ void draw_stat_area() { break; } } - draw_quality_bars(28, 56); - draw_signal_bars(44, 56); 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) + draw_quality_bars(53, 109); + draw_signal_bars(83, 109); + draw_waterfall(50, 8); + #endif } } } @@ -870,143 +750,235 @@ void update_stat_area() { if (eeprom_ok && !firmware_update_mode && !console_active) { draw_stat_area(); if (disp_mode == DISP_MODE_PORTRAIT) { - drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); + #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 } else if (disp_mode == DISP_MODE_LANDSCAPE) { - 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) drawLine(p_as_x, 0, p_as_x, DISP_W/2, DISPLAY_WHITE); + #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 } } else { if (firmware_update_mode) { - drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), DISPLAY_BLACK, DISPLAY_WHITE); + #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 } else if (console_active && device_init_done) { - drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), DISPLAY_BLACK, DISPLAY_WHITE); + #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 if (disp_mode == DISP_MODE_LANDSCAPE) { - drawLine(p_as_x, 0, p_as_x, DISP_W/2, DISPLAY_WHITE); + #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 } } } } -extern char bt_devname[11]; -extern char bt_dh[16]; - void draw_disp_area() { if (!device_init_done || firmware_update_mode) { uint8_t p_by = 37; if (disp_mode == DISP_MODE_LANDSCAPE || firmware_update_mode) { p_by = 18; - disp_area.fillRect(0, 0, disp_area.width(), disp_area.height(), DISPLAY_BLACK); + #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 } - 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); + #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); + #endif } else { if (!disp_ext_fb or bt_ssp_pin != 0) { if (radio_online && display_diagnostics) { + #if DISPLAY == OLED + 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.fillRect(0,8,disp_area.width(),37, DISPLAY_BLACK); disp_area.fillRect(0,37,disp_area.width(),27, 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.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setTextColor(DISPLAY_WHITE); disp_area.setTextSize(1); + disp_area.setCursor(2, 23-1); + disp_area.print("Airtime:"); - selected_radio = interface_obj[online_interface_list[interface_page]]; + 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.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.drawBitmap(2, 26-1, bm_hg_low, 5, 9, SSD1306_WHITE, SSD1306_BLACK); - //disp_area.setCursor(31, 23-1); - disp_area.setCursor(2, 23-1); - disp_area.print("Airtime:"); + 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(11, 33-1); - if (selected_radio->getAirtime() < 0.099) { - //disp_area.printf("%.1f%%", total_channel_util*100.0); - disp_area.printf("%.1f%%", selected_radio->getAirtime()*100.0); - } else { - //disp_area.printf("%.0f%%", total_channel_util*100.0); - 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, 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); - disp_area.setCursor(32+11, 33-1); - if (selected_radio->getLongtermAirtime() < 0.099) { - //disp_area.printf("%.1f%%", longterm_channel_util*100.0); - disp_area.printf("%.1f%%", selected_radio->getLongtermAirtime()*100.0); - } else { - //disp_area.printf("%.0f%%", longterm_channel_util*100.0); - 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); + #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.setTextSize(2); // scale text 2x + disp_area.setCursor(2, 22); + disp_area.print("On"); + disp_area.setCursor(14*2, 22); + disp_area.print("@"); + disp_area.setCursor(21*2, 22); + disp_area.printf("%.1fKbps", (float)(selected_radio->getBitrate())/1000.0); - 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(2, 36); + disp_area.print("Airtime:"); + + disp_area.setCursor(7+12, 53); + 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, 41, bm_hg_low, 10, 18, GxEPD_WHITE, GxEPD_BLACK); + + disp_area.setCursor(64+17, 53); + 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(64, 41, bm_hg_high, 10, 18, GxEPD_WHITE, GxEPD_BLACK); + + disp_area.setTextColor(GxEPD_BLACK); + + disp_area.setCursor(2, 88); + disp_area.print("Channel"); + disp_area.setCursor(38*2, 88); + disp_area.print("Load:"); - disp_area.setCursor(11, 57); - if (selected_radio->getTotalChannelUtil() < 0.099) { - //disp_area.printf("%.1f%%", airtime*100.0); - disp_area.printf("%.1f%%", selected_radio->getTotalChannelUtil()*100.0); - } else { - //disp_area.printf("%.0f%%", airtime*100.0); - 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(7+12, 110); + 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, 98, bm_hg_low, 10, 18, GxEPD_BLACK, GxEPD_WHITE); - disp_area.setCursor(32+11, 57); - if (selected_radio->getLongtermChannelUtil() < 0.099) { - //disp_area.printf("%.1f%%", longterm_airtime*100.0); - disp_area.printf("%.1f%%", selected_radio->getLongtermChannelUtil()*100.0); - } else { - //disp_area.printf("%.0f%%", longterm_airtime*100.0); - disp_area.printf("%.0f%%", selected_radio->getLongtermChannelUtil()*100.0); - } - disp_area.drawBitmap(32+2, 50, bm_hg_high, 5, 9, DISPLAY_BLACK, DISPLAY_WHITE); - - disp_area.setTextColor(DISPLAY_BLACK); disp_area.setTextSize(1); - - // TODO, for some reason there is a weird artifact at the top of the screen if this line isn't here. Need to investigate. - disp_area.fillRect(0,0,disp_area.width(),8,DISPLAY_WHITE); - - // display device ID on top bar - disp_area.setCursor(4, 5); disp_area.print(bt_devname); + disp_area.setCursor(64+17, 110); + 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(64, 98, bm_hg_high, 10, 18, GxEPD_BLACK, GxEPD_WHITE); + #endif } else { if (device_signatures_ok()) { - disp_area.drawBitmap(0, 0, bm_def_lc, disp_area.width(), 37, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - disp_area.drawBitmap(0, 0, bm_def, disp_area.width(), 37, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } - - // display device ID beneath header - disp_area.setFont(SMALL_FONT); disp_area.setTextWrap(false); disp_area.setCursor(13, 32); disp_area.setTextColor(DISPLAY_WHITE); disp_area.setTextSize(2); - disp_area.printf("%02X%02X", bt_dh[14], bt_dh[15]); } if (!hw_ready || !device_firmware_ok()) { if (!device_firmware_ok()) { - disp_area.drawBitmap(0, 37, bm_fw_corrupt, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { if (!modems_installed) { - disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - disp_area.drawBitmap(0, 37, bm_conf_missing, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } } else if (bt_state == BT_STATE_PAIRING and bt_ssp_pin != 0) { char *pin_str = (char*)malloc(DISP_PIN_SIZE+1); sprintf(pin_str, "%06d", bt_ssp_pin); - disp_area.drawBitmap(0, 37, bm_pairing, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif for (int i = 0; i < DISP_PIN_SIZE; i++) { uint8_t numeric = pin_str[i]-48; - uint8_t offset = numeric*5; - disp_area.drawBitmap(7+9*i, 37+16, bm_n_uh+offset, 8, 5, DISPLAY_WHITE, DISPLAY_BLACK); + #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) + uint8_t offset = numeric*20; + disp_area.drawBitmap(14+17*i, 71+32, bm_n_uh+offset, 10, 10, GxEPD_WHITE, GxEPD_BLACK); + #endif } free(pin_str); } else { @@ -1018,182 +990,137 @@ void draw_disp_area() { if (radio_online) { if (!display_diagnostics) { - disp_area.drawBitmap(0, 37, bm_online, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } else { if (disp_page == 0) { if (true || device_signatures_ok()) { - disp_area.drawBitmap(0, 37, bm_checks, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - disp_area.drawBitmap(0, 37, bm_nfr, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } else if (disp_page == 1) { if (!console_active) { - disp_area.drawBitmap(0, 37, bm_hwok, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } else { - disp_area.drawBitmap(0, 37, bm_console_active, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif } } else if (disp_page == 2) { - disp_area.drawBitmap(0, 37, bm_version, disp_area.width(), 27, DISPLAY_WHITE, DISPLAY_BLACK); + #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); + #endif char *v_str = (char*)malloc(3+1); sprintf(v_str, "%01d%02d", MAJ_VERS, MIN_VERS); for (int i = 0; i < 3; i++) { - uint8_t numeric = v_str[i]-48; uint8_t bm_offset = numeric*5; + #if DISPLAY == OLED uint8_t dxp = 20; - if (i == 1) dxp += 9*1+4; + uint8_t numeric = v_str[i]-48; uint8_t bm_offset = numeric*5; if (i == 2) dxp += 9*2+4; - disp_area.drawBitmap(dxp, 37+16, bm_n_uh+bm_offset, 8, 5, DISPLAY_WHITE, DISPLAY_BLACK); + #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + uint8_t dxp = 43; + 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) + // 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); + #endif } free(v_str); - disp_area.drawLine(27, 37+19, 28, 37+19, DISPLAY_BLACK); - disp_area.drawLine(27, 37+20, 28, 37+20, DISPLAY_BLACK); + #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); + #endif } } } } else { - disp_area.drawBitmap(0, 0, fb, disp_area.width(), disp_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); + #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 } } } void update_disp_area() { draw_disp_area(); - - drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); + #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 if (disp_mode == DISP_MODE_LANDSCAPE) { if (device_init_done && !firmware_update_mode && !disp_ext_fb) { - drawLine(0, 0, 0, 63, DISPLAY_WHITE); + #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); + #endif } } } -void display_recondition() { - #if DISPLAY == OLED - for (uint8_t iy = 0; iy < disp_area.height(); iy++) { - unsigned char rand_seg [] = {random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF)}; - stat_area.drawBitmap(0, iy, rand_seg, 64, 1, DISPLAY_WHITE, DISPLAY_BLACK); - disp_area.drawBitmap(0, iy, rand_seg, 64, 1, DISPLAY_WHITE, DISPLAY_BLACK); - } - - 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_PORTRAIT) { - 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) { - drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), DISPLAY_WHITE, DISPLAY_BLACK); - } - #endif -} - -bool epd_blanked = false; -#if DISPLAY == EINK_3C || DISPLAY == EINK_BW - void epd_blank(bool full_update = true) { - display.setFullWindow(); - display.fillScreen(DISPLAY_WHITE); - display.display(full_update); - } - - void epd_black(bool full_update = true) { - display.setFullWindow(); - display.fillScreen(DISPLAY_BLACK); - display.display(full_update); - } -#endif - void update_display(bool blank = false) { - display_updating = true; - if (blank == true) { - last_disp_update = millis()-disp_update_interval-1; - } else { - if (display_blanking_enabled && millis()-last_unblank_event >= display_blanking_timeout) { - blank = true; - display_blanked = true; - if (display_intensity != 0) { - display_unblank_intensity = display_intensity; - } - display_intensity = 0; - } else { - display_blanked = false; - if (display_unblank_intensity != 0x00) { - display_intensity = display_unblank_intensity; - display_unblank_intensity = 0x00; - } - } - } - if (blank) { - if (millis()-last_disp_update >= disp_update_interval) { - if (display_contrast != display_intensity) { - display_contrast = display_intensity; - set_contrast(&display, display_contrast); - } - - #if DISPLAY == EINK_3C || DISPLAY == EINK_BW - if (!epd_blanked) { - epd_blank(); - epd_blanked = true; - } - #endif - - #if BOARD_MODEL == BOARD_HELTEC_T114 - display.clear(); - display.display(); - #elif BOARD_MODEL != BOARD_TDECK && DISPLAY != EINK_3C && DISPLAY != EINK_BW - display.clearDisplay(); - display.display(); - #else - // TODO: Clear screen - #endif - - last_disp_update = millis(); + #if DISPLAY == OLED + if (display_contrast != display_intensity) { + display_contrast = display_intensity; + set_contrast(&display, display_contrast); } - + display.clearDisplay(); + #endif + display.display(); } else { if (millis()-last_disp_update >= disp_update_interval) { - uint32_t current = millis(); + #if DISPLAY == OLED if (display_contrast != display_intensity) { display_contrast = display_intensity; set_contrast(&display, display_contrast); } - - #if BOARD_MODEL == BOARD_HELTEC_T114 - display.clear(); - #elif BOARD_MODEL != BOARD_TDECK && DISPLAY != EINK_3C && DISPLAY != EINK_BW - display.clearDisplay(); + display.clearDisplay(); + update_stat_area(); + update_disp_area(); + display.display(); + #elif DISP_H == 122 && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) + display.setFullWindow(); + display.fillScreen(GxEPD_WHITE); + update_stat_area(); + update_disp_area(); + display.display(true); #endif - - if (recondition_display) { - disp_target_fps = 30; - disp_update_interval = 1000/disp_target_fps; - display_recondition(); - } else { - #if DISPLAY == EINK_BW || DISPLAY == EINK_3C - display.setFullWindow(); - display.fillScreen(DISPLAY_WHITE); - #endif - - update_stat_area(); - update_disp_area(); - } - - #if DISPLAY == EINK_BW || DISPLAY == EINK_3C - if (current-last_epd_refresh >= epd_update_interval) { - if (current-last_epd_full_refresh >= REFRESH_PERIOD) { display.display(false); last_epd_full_refresh = millis(); } - else { display.display(true); } - last_epd_refresh = millis(); - epd_blanked = false; - } - #elif BOARD_MODEL != BOARD_TDECK - display.display(); - #endif - last_disp_update = millis(); } } - display_updating = false; -} - -void display_unblank() { - last_unblank_event = millis(); } void ext_fb_enable() { diff --git a/Documentation/BRANCHES.md b/Documentation/BRANCHES.md deleted file mode 100644 index ab9afae..0000000 --- a/Documentation/BRANCHES.md +++ /dev/null @@ -1,11 +0,0 @@ -# Branches - -There are two main branches involved in developments & releases: -* master -* dev - -All PRs will be merged to the dev branch, but must be written against the master branch to make merging easier. - -Changes to the dev branch are merged once a new firmware release is imminent. - -Things have been organised this way for the sake of stability and sanity. diff --git a/Documentation/BUILDING.md b/Documentation/BUILDING.md index d995d31..e1381b7 100644 --- a/Documentation/BUILDING.md +++ b/Documentation/BUILDING.md @@ -1,6 +1,6 @@ # Building ## Prerequisites -The build system of this repository is based on GNU Make. The `Makefile` is in the base of the repository. Please ensure you have `arduino-cli`, `python3` and `make` installed before proceeding. +The build system of this repository is based on Make. The `Makefile` is in the base of the repository. Please ensure you have `arduino-cli` installed before proceeding. Firstly, figure out which MCU platform your supported board is based on. The table below can help you. @@ -54,60 +54,6 @@ Ensure you replace [target] with the target you selected. For example: `make upload-rak4631` -If you are flashing a custom board, you will need to generate a signing key in rnodeconf prior to flashing if you do not already have one by running: - -`rnodeconf -k` - -After flashing a custom board, you will also need to provision the EEPROM before use: - -`rnodeconf /dev/ttyACM0 -r --platform ESP32 --model a9 --product f0 --hwrev 3` - -- platform must either be AVR, ESP32 or NRF52 -- hwrev is required (any integer between 1 and 255) -- model should be something from the list below without the leading `0x` and in lowercase (example `e8`): -``` -0x11: [430000000, 510000000, 22, "430 - 510 MHz", "rnode_firmware_rak4631.zip", "SX1262"], -0x12: [779000000, 928000000, 22, "779 - 928 MHz", "rnode_firmware_rak4631.zip", "SX1262"], -0xA4: [410000000, 525000000, 14, "410 - 525 MHz", "rnode_firmware.hex", "SX1278"], -0xA9: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware.hex", "SX1276"], -0xA1: [410000000, 525000000, 22, "410 - 525 MHz", "rnode_firmware_t3s3.zip", "SX1268"], -0xA6: [820000000, 1020000000, 22, "820 - 960 MHz", "rnode_firmware_t3s3.zip", "SX1262"], -0xA2: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng21.zip", "SX1278"], -0xA7: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware_ng21.zip", "SX1276"], -0xA3: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng20.zip", "SX1278"], -0xA8: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware_ng20.zip", "SX1276"], -0xB3: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v20.zip", "SX1278"], -0xB8: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v20.zip", "SX1276"], -0xB4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v21.zip", "SX1278"], -0xB9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v21.zip", "SX1276"], -0x04: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v21_tcxo.zip", "SX1278"], -0x09: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v21_tcxo.zip", "SX1276"], -0xBA: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_lora32v10.zip", "SX1278"], -0xBB: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v10.zip", "SX1276"], -0xC4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_heltec32v2.zip", "SX1278"], -0xC9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_heltec32v2.zip", "SX1276"], -0xC5: [470000000, 510000000, 21, "470 - 510 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"], -0xCA: [863000000, 928000000, 21, "863 - 928 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"], -0xE4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_tbeam.zip", "SX1278"], -0xE9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_tbeam.zip", "SX1276"], -0xE3: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1268"], -0xE8: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_tbeam_sx1262.zip", "SX1262"], -0xFE: [100000000, 1100000000, 17, "(Band capabilities unknown)", None, "Unknown"], -0xFF: [100000000, 1100000000, 14, "(Band capabilities unknown)", None, "Unknown"], -``` -- product should be a code from the following list below without the leading `0x` and in lowercase (example `f0`): -``` -PRODUCT_RAK4631 = 0x10 -PRODUCT_RNODE = 0x03 -PRODUCT_T32_10 = 0xB2 -PRODUCT_T32_20 = 0xB0 -PRODUCT_T32_21 = 0xB1 -PRODUCT_H32_V2 = 0xC0 -PRODUCT_H32_V3 = 0xC1 -PRODUCT_TBEAM = 0xE0 -PRODUCT_HMBRW = 0xF0 -``` - **Please note**, you must re-compile the firmware each time you make changes **before** you flash it, else you will just be flashing the previous version of the firmware without the new changes! These commands can also be run as a one liner. For example: diff --git a/Documentation/CONTRIBUTING.md b/Documentation/CONTRIBUTING.md index 1024f61..3a8d1ac 100644 --- a/Documentation/CONTRIBUTING.md +++ b/Documentation/CONTRIBUTING.md @@ -1,78 +1,47 @@ # Board support -If you wish to add support for a specific board to the project, all you have to do (if it's ESP32 or nRF52), is write an additional entry for `Boards.h` and `Utilities.h` and the `Makefile` . +If you wish to add support for a specific board to the project, all you have to do (if it's ESP32 or nRF52), is write an additional entry for `Boards.h`. -### Boards.h -This entry in `Boards.h` should include, at a minimum, the following: +This entry should include, at a minimum, the following: * whether the device has bluetooth / BLE * whether the device has a PMU * whether the device has an EEPROM (false in all cases for nRF52, true for ESP32) * pin mappings for SPI NSS, SCLK, MOSI, MISO, modem reset and dio0 -* the type of modem on the board -* the number of interfaces (modems) +* the type of modem on the board (if undefined it defaults to SX127x) * whether the modem has a busy pin * RX and TX leds (preferably LEDs of different colours) -You should also define a unique name for your board (with a unique value) near the beginning of the file, along with a product and model value. For example: -``` -#define BOARD_MY_WICKED_BOARD 0x3B -#define PRODUCT_MY_WICKED_BOARD 0x98 -#define MODEL_99 0x99 -``` -**Check your chosen values are not in use** in `Boards.h` first! Please also ensure you have one model per variation of the board, such as 868mhz and 915mhz variants for example. -The board definition should look as follows: +# Check this area... +see https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39 +Effectively, there are multiple SPI buses we can map to pins on these +devices (including the hardware SPI bus) + +An example of a minimal entry can be seen below: ``` #elif BOARD_MODEL == BOARD_MY_WICKED_BOARD - #define HAS_BLUETOOTH false - #define HAS_CONSOLE true - #define HAS_EEPROM true - #define INTERFACE_COUNT 1 - const int pin_led_rx = 9; - const int pin_led_tx = 8; - 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 - { - 7, // pin_ss - 4, // pin_sclk - 6, // pin_mosi - 5, // pin_miso - -1, // pin_busy - 2, // pin_dio - 3, // pin_reset - -1, // pin_txen - -1, // pin_rxen - -1 // pin_tcxo_enable - } - }; - + #define HAS_BLUETOOTH true + #define HAS_PMU true + #define HAS_EEPROM true + #define EEPROM_SIZE 296 // minimum EEPROM size + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED + const int pin_cs = 20; + const int pin_reset = 19; + // const int pin_cs = 1; not needed here + // const int pin_sclk = 2; not needed here + // const int pin_mosi = 3; not needed here + // const int pin_miso = 4; not needed here + const int pin_dio = 18; + // const int pin_busy = 0; not present + const int pin_led_rx = 5; + const int pin_led_tx = 6; ``` -Note, this will have to be pasted in the section according to the MCU variant, -e.g. nRF52 or ESP32. Find the section by searching for the comparison where -`MCU_VARIANT` is checked for your MCU variant. **Do not change the order of the -pins or options in any of the interface_cfg or interface_pins arrays.** You -have been warned. - -[There are multiple SPI -buses](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-spi.h#L39) -we can map to pins on these devices (including the hardware SPI bus). - In some cases the SPI pins will not be required, as they will be the default pins for the SPI library supporting the board anyway, and therefore do not need overriding in the config. If the SX1262 is being used the following should also be considered: -* the modem busy pin * whether DIO2 should be used as the RF switch (DIO2_AS_RF_SWITCH) -* whether an RF on/off switch also has to be operated (through the pin pin_rxen) -* whether a TCXO is connected to the modem (HAS_TCXO and pin_tcxo_enable to enable the TCXO if present) -* whether the SPI pins are the default used by the SPI library +* whether an rf on/off switch also has to be operated (through the pin pin_rxen) +* whether a TCXO is connected to the modem (HAS_TCXO) +* the enable pin for the TCXO (if present) An example of an entry using the SX1262 modem can be seen below: ``` @@ -82,34 +51,22 @@ An example of an entry using the SX1262 modem can be seen below: #define HAS_EEPROM true #define EEPROM_SIZE 296 // minimum EEPROM size #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED + #define MODEM SX1262 + #define DIO2_AS_RF_SWITCH true + #define HAS_TCXO true + #define HAS_BUSY true + const int pin_cs = 20; + const int pin_reset = 19; + const int pin_rxen = 10; + // const int pin_cs = 1; not needed here + // const int pin_sclk = 2; not needed here + // const int pin_mosi = 3; not needed here + // const int pin_miso = 4; not needed here + const int pin_dio = 18; + const int pin_busy = 7; + const int pin_tcxo_enable = -1; const int pin_led_rx = 5; const int pin_led_tx = 6; - #define INTERFACE_COUNT 1 - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1262 - { - false, // DEFAULT_SPI - true, // HAS_TCXO - true // DIO2_AS_RF_SWITCH - } - }; - const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1262 - { - 42, // pin_ss - 43, // pin_sclk - 44, // pin_mosi - 45, // pin_miso - 46, // pin_busy - 47, // pin_dio - 38, // pin_reset - -1, // pin_txen - 37, // pin_rxen - -1 // pin_tcxo_enable - } - }; - ``` If the SX1280 is being used, the following should also be added: @@ -123,132 +80,24 @@ An example of an entry using the SX1280 modem can be seen below: #define HAS_EEPROM true #define EEPROM_SIZE 296 // minimum EEPROM size #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED + #define MODEM SX1280 + #define HAS_BUSY true + #define HAS_RF_SWITCH_RX_TX true + const int pin_cs = 20; + const int pin_reset = 19; + const int pin_rxen = 10; + const int pin_txen = 11; + // const int pin_cs = 1; not needed here + // const int pin_sclk = 2; not needed here + // const int pin_mosi = 3; not needed here + // const int pin_miso = 4; not needed here + const int pin_dio = 18; + const int pin_busy = 7; + const int pin_tcxo_enable = -1; const int pin_led_rx = 5; const int pin_led_tx = 6; - #define INTERFACE_COUNT 1 - const uint8_t interfaces[INTERFACE_COUNT] = {SX1280}; - const bool interface_cfg[INTERFACE_COUNT][3] = { - // SX1280 - { - true, // DEFAULT_SPI - false,// HAS_TCXO - false // DIO2_AS_RF_SWITCH - } - }; - const int8_t interface_pins[INTERFACE_COUNT][10] = { - // SX1280 - { - 24, // pin_ss - 3, // pin_sclk - 30, // pin_mosi - 29, // pin_miso - 25, // pin_busy - 15, // pin_dio - 16, // pin_reset - 20, // pin_txen - 19, // pin_rxen - -1 // pin_tcxo_enable - } - }; ``` -#### INTERFACE_SPI (nRF52 only) -If you are using non-default SPI pins on an nRF52 MCU variant, you **must** ensure that you add this section to the bottom of your board config: -``` - // Required because on nRF52, non-default SPI pins must be initialised when class is declared. - const SPIClass interface_spi[1] = { - // SX1262 - SPIClass( - NRF_SPIM2, - interface_pins[0][3], - interface_pins[0][1], - interface_pins[0][2] - ) - }; -``` -This will ensure the pins are set correctly in the SPI class. - -### Utilities.h -You should add something similar to the following to drive the LEDs depending on your configuration: -``` -#elif BOARD_MODEL == BOARD_MY_WICKED_BOARD - 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); } -``` -Note: this will again have to be pasted in the correct section according to -your MCU variant. Please search for the other definitions of `led_rx_on()` to -find the correct section, then find the final section by searching for the -comparison where `MCU_VARIANT` is checked for your MCU variant. - -You also need to add entries to the `setTxPower()`, `eeprom_product_valid()` and `eeprom_model_valid()` functions in the same file. - -In `setTxPower()`, you simply need to add an if statement for your model, e.g: -``` -if (model == MODEL_99) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); -``` - -There is no difference between `PA_OUTPUT_PA_BOOST_PIN` and `PA_OUTPUT_RFO_PIN` on boards which do not have an SX1276/8. - -For `eeprom_product_valid()` you simply need to add your product value to the relevant if statment depending on what MCU variant your board uses. For example: -``` -if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_OPENCOM_XL || rval == PRODUCT_TECHO || rval == PRODUCT_MY_WICKED_BOARD || rval == PRODUCT_HMBRW) { -``` - -Finally, for `eeprom_model_valid`, you must add an elif with the correct model number for the board, e.g: -``` -#elif BOARD_MODEL == BOARD_MY_WICKED_BOARD - if (model == MODEL_99) { -``` - -### Makefile -You can add the example target below to the makefile for your board, but **you must replace the FQBN** in the arduino-cli command with the correct one for your board. -``` -firmware-wicked_esp32: - arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\"" -``` -Pay attention the the DBOARD_MODEL= value as you must insert the one you chose earlier here. - -Another entry to upload to the board. Again substitute your FQBN, and you may have to experiment with the commands to get it to flash: -#### ESP32 -``` -upload-wicked_esp32: - arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32c3 - @sleep 1 - rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bin) - @sleep 3 - python3 ./Release/esptool/esptool.py --chip esp32c3 --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 -``` -#### nRF52 -``` -upload-wicked_nrf52: - arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board - unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board - rnodeconf /dev/ttyACM0 --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*') -``` - -And one final entry to make a release for the firmware: -#### ESP32 -``` -release-wicked_esp32: - arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_wicked_esp32.boot_app0 - cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bin build/rnode_firmware_wicked_esp32.bin - cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_wicked_esp32.bootloader - cp build/esp32.esp32.esp32c3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_wicked_esp32.partitions - zip --junk-paths ./Release/rnode_firmware_wicked_esp32.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_wicked_esp32.boot_app0 build/rnode_firmware_wicked_esp32.bin build/rnode_firmware_wicked_esp32.bootloader build/rnode_firmware_wicked_esp32.partitions - rm -r build -``` -#### nRF52 -``` -release-wicked_nrf52: - 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=0x3B\"" - cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_wicked_nrf52.hex - adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_wicked_nrf52.hex Release/rnode_firmware_wicked_nrf52.zip -``` -You can of course replace the ESP32 target with the nRF52 target, if you are building for that MCU variant, as seen in previous instructions. - Please submit this, and any other support in different areas of the project your board may require, as a PR for my consideration. # Feature request diff --git a/Framing.h b/Framing.h index 47a8eeb..0dfb1ce 100644 --- a/Framing.h +++ b/Framing.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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 @@ -44,7 +44,6 @@ #define CMD_STAT_CHTM 0x25 #define CMD_STAT_PHYPRM 0x26 #define CMD_STAT_BAT 0x27 - #define CMD_STAT_CSMA 0x28 #define CMD_BLINK 0x30 #define CMD_RANDOM 0x40 @@ -52,17 +51,10 @@ #define CMD_FB_READ 0x42 #define CMD_FB_WRITE 0x43 #define CMD_FB_READL 0x44 - #define CMD_DISP_READ 0x66 #define CMD_DISP_INT 0x45 #define CMD_DISP_ADDR 0x63 - #define CMD_DISP_BLNK 0x64 - #define CMD_DISP_ROT 0x67 - #define CMD_DISP_RCND 0x68 - #define CMD_NP_INT 0x65 #define CMD_BT_CTRL 0x46 - #define CMD_BT_UNPAIR 0x70 #define CMD_BT_PIN 0x62 - #define CMD_DIS_IA 0x69 #define CMD_BOARD 0x47 #define CMD_PLATFORM 0x48 @@ -83,14 +75,32 @@ #define CMD_RESET_BYTE 0xF8 #define CMD_INTERFACES 0x64 - - #define CMD_DATA 0x00 - #define CMD_SEL_INT 0x1F - #define CMD_LOG 0x80 - #define CMD_TIME 0x81 - #define CMD_MUX_CHAIN 0x82 - #define CMD_MUX_DSCVR 0x83 + #define CMD_INT0_DATA 0x00 + #define CMD_INT1_DATA 0x10 + #define CMD_INT2_DATA 0x20 + #define CMD_INT3_DATA 0x70 + #define CMD_INT4_DATA 0x80 + #define CMD_INT5_DATA 0x90 + #define CMD_INT6_DATA 0xA0 + #define CMD_INT7_DATA 0xB0 + #define CMD_INT8_DATA 0xC0 + #define CMD_INT9_DATA 0xD0 + #define CMD_INT10_DATA 0xE0 + #define CMD_INT11_DATA 0xF0 + + #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_INT5 0x9F + #define CMD_SEL_INT6 0xAF + #define CMD_SEL_INT7 0xBF + #define CMD_SEL_INT8 0xCF + #define CMD_SEL_INT9 0xDF + #define CMD_SEL_INT10 0xEF + #define CMD_SEL_INT11 0xFF #define DETECT_REQ 0x73 #define DETECT_RESP 0x46 @@ -108,21 +118,6 @@ #define ERROR_TXFAILED 0x02 #define ERROR_EEPROM_LOCKED 0x03 #define ERROR_QUEUE_FULL 0x04 - #define ERROR_MEMORY_LOW 0x05 - #define ERROR_MODEM_TIMEOUT 0x06 - - #define CMD_GPS 0xA0 - - #define GPS_CMD_LAT 0x00 - #define GPS_CMD_LNG 0x01 - - // Serial logging - #define LOG_MSG 0x2F - - #define MSG_INFO 0x01 - #define MSG_ERR 0x02 - #define MSG_DBG 0x03 - #define MSG_TRACE 0x04 // Serial framing variables size_t frame_len; diff --git a/Graphics.h b/Graphics.h index efd7480..049beb0 100644 --- a/Graphics.h +++ b/Graphics.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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,6 +13,9 @@ // 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, @@ -20,17 +23,6 @@ const unsigned char bm_cable [] PROGMEM = { 0xf1, 0x8f, 0x02, 0x16, 0x02, 0x23, 0x01, 0x20, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 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_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, @@ -42,6 +34,17 @@ const unsigned char bm_bt [] PROGMEM = { 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, @@ -59,6 +62,92 @@ const unsigned char bm_boot [] PROGMEM = { 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, @@ -76,20 +165,20 @@ const unsigned char bm_fw_update [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -const unsigned char bm_console_active [] PROGMEM = { +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, 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, 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 }; @@ -128,73 +217,26 @@ const unsigned char bm_updating [] PROGMEM = { 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_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 -}; - static unsigned char bm_def[] 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, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 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 + 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 = { @@ -219,6 +261,57 @@ const unsigned char bm_def_lc [] PROGMEM = { 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, @@ -254,102 +347,32 @@ const unsigned char bm_frame [] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xaa, 0x8a, 0xaa, 0x80 }; -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, +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, - 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_checks [] PROGMEM = { + 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, 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_hwfail [] PROGMEM = { +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, 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, 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, - 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_conf_missing [] 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, 0xe7, 0x33, 0x87, 0x0c, 0xcc, 0xe1, 0xff, 0xff, - 0xe2, 0x33, 0x3e, 0x7c, 0xc4, 0xcf, 0xff, 0xff, 0xe0, 0x33, 0x8f, 0x1c, 0xc0, 0xc9, 0xff, 0xff, - 0xe5, 0x33, 0xe7, 0xcc, 0xc8, 0xc9, 0xff, 0xff, 0xe7, 0x33, 0x0e, 0x1c, 0xcc, 0xe3, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf1, 0xe3, 0x99, 0x86, 0x70, 0xff, 0xf6, 0xff, - 0xe4, 0xc9, 0x89, 0x9e, 0x67, 0xff, 0xf6, 0xff, 0xe7, 0xc9, 0x81, 0x86, 0x64, 0xff, 0xef, 0x7f, - 0xe4, 0xc9, 0x91, 0x9e, 0x64, 0xff, 0xe9, 0x7f, 0xf1, 0xe3, 0x99, 0x9e, 0x71, 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_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, 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, @@ -358,23 +381,1338 @@ const unsigned char bm_no_radio [] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -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_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 +// use 122px wide graphics + +const unsigned char bm_bt [] PROGMEM = { + // 30 x 128px + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x60, 0x00, 0x02, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x60, 0x00, 0x02, 0x06, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x0d, 0x87, 0x84, 0xc0, + 0x0d, 0x87, 0x84, 0xc0, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x02, 0x06, 0x63, 0x00, 0x02, 0x06, 0x63, 0x00, 0x0d, 0x87, 0x84, 0xc0, + 0x0d, 0x87, 0x84, 0xc0, 0x02, 0x06, 0x63, 0x00, 0x02, 0x06, 0x63, 0x00, 0x00, 0x1e, 0x18, 0x00, + 0x00, 0x1e, 0x18, 0x00, 0x00, 0x66, 0x04, 0x00, 0x00, 0x66, 0x04, 0x00, 0x01, 0x86, 0x18, 0x00, + 0x01, 0x86, 0x18, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_rf [] PROGMEM = { + // 30 x 128px + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf9, 0xe0, 0xc0, 0x30, 0xf9, 0xe0, 0xc0, + 0x30, 0x99, 0x99, 0x30, 0x30, 0x99, 0x99, 0x30, 0x30, 0x99, 0xe1, 0xf0, 0x30, 0x99, 0xe1, 0xf0, + 0x3c, 0xf9, 0x99, 0x30, 0x3c, 0xf9, 0x99, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x7f, 0xf8, 0x00, + 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x06, 0x00, 0x03, 0x1f, 0xe1, 0x00, 0x03, 0x1f, 0xe1, 0x00, + 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf9, 0xe0, 0xc0, 0x30, 0xf9, 0xe0, 0xc0, + 0x30, 0x99, 0x99, 0x30, 0x30, 0x99, 0x99, 0x30, 0x30, 0x99, 0xe1, 0xf0, 0x30, 0x99, 0xe1, 0xf0, + 0x3c, 0xf9, 0x99, 0x30, 0x3c, 0xf9, 0x99, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, + 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x06, 0x61, 0xf0, 0x3f, 0x06, 0x61, 0xf0, + 0x0f, 0x06, 0x61, 0x00, 0x0f, 0x06, 0x61, 0x00, 0x3c, 0x07, 0xe1, 0x30, 0x3c, 0x07, 0xe1, 0x30, + 0x3f, 0x60, 0x61, 0xf0, 0x3f, 0x60, 0x61, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x7f, 0xf8, 0x00, + 0x00, 0x80, 0x06, 0x00, 0x00, 0x80, 0x06, 0x00, 0x03, 0x1f, 0xe1, 0x00, 0x03, 0x1f, 0xe1, 0x00, + 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x06, 0x61, 0xf0, 0x3f, 0x06, 0x61, 0xf0, + 0x0f, 0x06, 0x61, 0x00, 0x0f, 0x06, 0x61, 0x00, 0x3c, 0x07, 0xe1, 0x30, 0x3c, 0x07, 0xe1, 0x30, + 0x3f, 0x60, 0x61, 0xf0, 0x3f, 0x60, 0x61, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, + 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +const unsigned char bm_cable [] PROGMEM = { + // 30 x 64px + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xc0, + 0x01, 0x80, 0x1f, 0x00, 0x01, 0x80, 0x1f, 0x00, 0x02, 0x00, 0x07, 0xc0, 0x02, 0x00, 0x07, 0xc0, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, + 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x7f, 0xe0, 0x00, + 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x61, 0x80, 0x00, 0x00, 0x61, 0x80, 0x00, + 0x00, 0x60, 0x60, 0x3c, 0x00, 0x60, 0x60, 0x3c, 0x01, 0x80, 0x60, 0xf0, 0x01, 0x80, 0x60, 0xf0, + 0xfe, 0x07, 0x83, 0xfc, 0xfe, 0x07, 0x83, 0xfc, 0x00, 0x18, 0x04, 0xf0, 0x00, 0x18, 0x04, 0xf0, + 0x00, 0x18, 0x18, 0x3c, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x06, 0x18, 0x00, 0x00, 0x06, 0x18, 0x00, + 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_boot [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x3f, 0x00, 0xf1, 0xe1, 0xe3, 0xf0, 0x3f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x07, 0xe1, 0xe1, 0xe1, 0xe0, 0x1f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0f, 0xf0, 0xe1, 0xe1, 0xc3, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x00, 0xf8, 0x07, 0xe1, 0xc3, 0xff, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x07, 0xf8, 0x07, 0xe1, 0xc3, 0x9f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0f, 0xfc, 0x07, 0xe1, 0xe1, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x3f, 0x00, 0xfe, 0x1f, 0xe1, 0xf0, 0x3f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x01, 0xe0, 0x3f, 0x03, 0xe0, 0x1f, 0x80, 0x70, 0xf0, 0xf1, 0xf8, 0x07, 0xff, 0xc0, + 0xff, 0xfc, 0x3f, 0xf0, 0x7e, 0x21, 0xe0, 0x87, 0xc1, 0xf0, 0xf0, 0x71, 0xf1, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x3f, 0xf8, 0x7c, 0x00, 0xe0, 0x87, 0xe1, 0xf0, 0xf0, 0x21, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x07, 0xf8, 0x7c, 0x00, 0xe0, 0x1f, 0xe1, 0xf0, 0xf0, 0x01, 0xe1, 0x87, 0xff, 0xc0, + 0xff, 0xff, 0xe1, 0xf8, 0x7c, 0x20, 0xe0, 0x1f, 0xe1, 0xf0, 0xf0, 0x81, 0xe1, 0x87, 0xff, 0xc0, + 0xff, 0xff, 0xe3, 0xf8, 0x7c, 0x30, 0xe0, 0x0f, 0xe1, 0xf0, 0xf0, 0xc1, 0xf0, 0x0f, 0xff, 0xc0, + 0xff, 0xf8, 0x07, 0xf8, 0xfc, 0x30, 0xf1, 0x87, 0xe1, 0xf0, 0xf0, 0xf1, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_fw_update [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xf1, 0xc7, 0x80, 0xfc, 0x03, 0xfc, 0x1f, 0x80, 0xf8, 0xf1, 0xf1, 0xf8, 0x0f, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x80, 0x7c, 0x03, 0xf8, 0x1f, 0x80, 0xf0, 0xf0, 0xf1, 0xf8, 0x0f, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x84, 0x3c, 0x31, 0xf0, 0x87, 0xc1, 0xf0, 0xf0, 0x71, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x84, 0x3c, 0x30, 0xe0, 0x87, 0xe1, 0xf0, 0xf0, 0x21, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x80, 0x7c, 0x30, 0xe0, 0x07, 0xe1, 0xf0, 0xf0, 0x01, 0xe1, 0x8f, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x80, 0xfc, 0x30, 0xe0, 0x07, 0xe1, 0xf0, 0xf0, 0x01, 0xe1, 0x87, 0xff, 0xc0, + 0xff, 0xe1, 0x87, 0x87, 0xfc, 0x30, 0xe0, 0x87, 0xe1, 0xf0, 0xf0, 0x81, 0xe1, 0x87, 0xff, 0xc0, + 0xff, 0xf0, 0x87, 0x87, 0xfc, 0x31, 0xe1, 0x87, 0xe1, 0xf0, 0xf0, 0xc1, 0xe1, 0x8f, 0xff, 0xc0, + 0xff, 0xf8, 0x1f, 0x87, 0xfc, 0x03, 0xe1, 0x87, 0xe1, 0xf0, 0xf0, 0xe1, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xfc, 0x1f, 0x8f, 0xfc, 0x03, 0xf1, 0xc7, 0xe3, 0xf8, 0xf1, 0xf1, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xc0, 0x78, 0x78, 0x0f, 0xc3, 0xf1, 0xe1, 0xf8, 0xfe, 0x0f, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xff, 0xc0, 0x78, 0x78, 0x07, 0xc3, 0xe1, 0xe1, 0xf8, 0x7c, 0x0f, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xff, 0xc3, 0xf8, 0x78, 0x43, 0xc1, 0xc1, 0xe1, 0xb8, 0x78, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xff, 0xc3, 0xf8, 0x78, 0x43, 0xc0, 0x81, 0xe1, 0x98, 0x70, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xff, 0xc0, 0x78, 0x78, 0x07, 0xc0, 0x01, 0xe1, 0x98, 0x70, 0x03, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xff, 0xc0, 0x78, 0x78, 0x0f, 0xc0, 0x01, 0xe1, 0x90, 0x70, 0x03, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xff, 0xc3, 0xf8, 0x78, 0x0f, 0xc2, 0x21, 0xe0, 0x00, 0x70, 0xc3, 0xc0, 0x7e, 0x1f, 0xff, 0xc0, + 0xff, 0xc7, 0xf8, 0x78, 0x07, 0xc3, 0x61, 0xe0, 0x00, 0xf0, 0xc3, 0xc0, 0x3e, 0x1f, 0xff, 0xc0, + 0xff, 0xc7, 0xf8, 0x78, 0x43, 0xc3, 0xe1, 0xf8, 0x41, 0xf0, 0xc3, 0xc2, 0x1e, 0x03, 0xff, 0xc0, + 0xff, 0xc7, 0xf8, 0x78, 0xe3, 0xc3, 0xf1, 0xf8, 0x63, 0xf8, 0xc3, 0xc7, 0x1e, 0x03, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_version [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc7, 0x8f, 0x80, 0xf0, 0x1f, 0xe0, 0x3e, 0x3f, 0x03, 0xf1, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x87, 0x87, 0x00, 0xf0, 0x0f, 0xe0, 0x3e, 0x3f, 0x03, 0xf0, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x87, 0x87, 0x07, 0xf0, 0x87, 0xc7, 0xfe, 0x3e, 0x31, 0xf0, 0x61, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc7, 0x8f, 0x07, 0xf0, 0x87, 0xc7, 0xfe, 0x3c, 0x30, 0xf0, 0x21, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x1f, 0x00, 0xf0, 0x0f, 0xe0, 0x7e, 0x3c, 0x30, 0xf0, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x1f, 0x00, 0xf0, 0x0f, 0xe0, 0x7e, 0x3c, 0x30, 0xf0, 0x01, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x1f, 0x07, 0xf0, 0x0f, 0xfe, 0x3e, 0x3c, 0x30, 0xf0, 0x81, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x3f, 0x07, 0xf0, 0x0f, 0xfe, 0x3e, 0x3e, 0x31, 0xf1, 0xc1, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x7f, 0x00, 0xf0, 0x87, 0xc0, 0x7e, 0x3f, 0x03, 0xf1, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x7f, 0x80, 0xf1, 0xc7, 0xc0, 0x7e, 0x3f, 0x03, 0xf1, 0xe1, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_def [] PROGMEM = { +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xcf, 0x70, 0x78, 0x0e, 0x0c, 0x03, 0x07, 0x80, 0x60, 0xff, 0x03, 0x01, 0xff, 0xff, 0xff, 0xc0, +0xcf, 0x20, 0x78, 0x0e, 0x0c, 0x07, 0x07, 0x80, 0xe0, 0xff, 0x87, 0x01, 0xff, 0xff, 0xff, 0xc0, +0xcf, 0x23, 0x98, 0x7f, 0x1c, 0xff, 0x39, 0x9f, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, +0xcf, 0x27, 0x98, 0x7f, 0x3c, 0xff, 0x39, 0x8f, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, +0xcf, 0x27, 0x9f, 0x8f, 0x3c, 0xc3, 0x39, 0x81, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, +0xce, 0x27, 0x9f, 0x07, 0x1c, 0x03, 0x39, 0x80, 0xe7, 0x3f, 0x87, 0x39, 0xff, 0xff, 0xff, 0xc0, +0xc0, 0x27, 0x98, 0x06, 0x0c, 0x03, 0x39, 0x80, 0x60, 0x33, 0x03, 0x01, 0xff, 0xff, 0xff, 0xc0, +0xe0, 0x77, 0xfc, 0x0e, 0x1e, 0x07, 0x7d, 0xc0, 0xe0, 0x3f, 0x87, 0x01, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf0, 0x7c, 0x07, 0x83, 0xff, 0xc0, 0xff, 0xfc, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf8, 0x7e, 0x0f, 0xc3, 0xff, 0xe1, 0xff, 0xfc, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xff, 0xfc, 0x7f, 0x0f, 0xcf, 0xff, 0xf1, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xff, 0xfe, 0x7f, 0x8f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xf0, 0x7e, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0xf0, 0x7e, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf8, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf8, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf8, 0x7e, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, +0x03, 0xff, 0xf8, 0x7e, 0x7f, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, +0x03, 0xf0, 0x7e, 0x7e, 0x3f, 0xcf, 0xc1, 0xf9, 0xf8, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0xe0, 0x7e, 0x7e, 0x1f, 0xcf, 0xc1, 0xf9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, +0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xcf, 0xff, 0xf1, 0xff, 0xfc, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xc3, 0xff, 0xe1, 0xff, 0xf0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, +0x03, 0xe0, 0x3c, 0x3c, 0x07, 0x83, 0xff, 0xc0, 0xff, 0xf0, 0x07, 0xff, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x33, 0x26, 0x66, 0x66, 0xcc, 0xcc, 0xd9, 0x99, 0x99, 0x33, 0x33, 0x26, 0x66, 0x66, 0xcc, 0x00, +0x0c, 0x89, 0x99, 0x99, 0x33, 0x33, 0x26, 0x66, 0x64, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x32, 0x00, +0x0c, 0x89, 0x99, 0x99, 0x33, 0x33, 0x26, 0x66, 0x64, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x33, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x07, 0x00, 0x70, 0x20, 0x20, 0x81, 0x04, 0x10, 0x40, 0x82, 0x0f, 0x04, 0x04, 0x00, +0x00, 0x00, 0x07, 0x80, 0xf0, 0x30, 0x61, 0x81, 0x86, 0x30, 0xc0, 0xc6, 0x1f, 0x86, 0x0c, 0x00, +0x00, 0x00, 0x18, 0x41, 0x0c, 0x38, 0xe1, 0xe7, 0x86, 0x30, 0xf0, 0xc6, 0x06, 0x01, 0x10, 0x00, +0x00, 0x00, 0x18, 0x41, 0x0c, 0x3c, 0xe1, 0xe7, 0x86, 0x30, 0xf0, 0xc6, 0x06, 0x01, 0x30, 0x00, +0x00, 0x00, 0x18, 0x01, 0x0c, 0x33, 0x61, 0x99, 0x86, 0x30, 0xc8, 0xc6, 0x06, 0x00, 0xc0, 0x00, +0x00, 0x00, 0x18, 0x01, 0x0c, 0x32, 0x21, 0x89, 0x86, 0x30, 0xcd, 0xc6, 0x06, 0x00, 0xc0, 0x00, +0x00, 0x00, 0x18, 0x41, 0x0c, 0x30, 0x21, 0x81, 0x86, 0x30, 0xc3, 0xc6, 0x06, 0x00, 0xc0, 0x00, +0x00, 0x00, 0x08, 0x41, 0x0c, 0x30, 0x21, 0x81, 0x86, 0x30, 0xc3, 0xc6, 0x06, 0x00, 0xc0, 0x00, +0x00, 0x00, 0x07, 0x80, 0xf0, 0x30, 0x21, 0x81, 0x81, 0xc0, 0xc0, 0xc6, 0x06, 0x00, 0xc0, 0x00, +0x00, 0x00, 0x03, 0x00, 0x70, 0x00, 0x20, 0x80, 0x01, 0xc0, 0x00, 0x82, 0x00, 0x00, 0x40, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0f, 0xc3, 0x1f, 0x81, 0x81, 0x0c, 0x0c, 0x0e, 0x07, 0xe0, 0xfc, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x1c, 0x01, 0xc3, 0x0c, 0x0c, 0x00, 0x07, 0x00, 0xe0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x18, 0x61, 0xe7, 0x0c, 0xcc, 0x31, 0x86, 0x18, 0xc0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0f, 0x83, 0x1f, 0x81, 0xdb, 0x0c, 0xcc, 0x3f, 0x87, 0xe0, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0f, 0xc3, 0x1f, 0x81, 0x99, 0x0c, 0xcc, 0x3f, 0x87, 0xe0, 0xfc, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x1d, 0x81, 0x81, 0x0c, 0xcc, 0x31, 0x87, 0xe0, 0xe0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x19, 0x81, 0x81, 0x0c, 0xcc, 0x21, 0x86, 0x60, 0xc0, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x18, 0x61, 0x81, 0x03, 0x30, 0x21, 0x86, 0x10, 0xfc, 0x00, +0x00, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x08, 0x61, 0x81, 0x03, 0x30, 0x20, 0x86, 0x10, 0x7c, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_def_lc [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xcf, 0x70, 0x78, 0x0e, 0x0c, 0x03, 0x07, 0xc0, 0x60, 0xff, 0x03, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xcf, 0x20, 0x78, 0x0e, 0x0c, 0x07, 0x07, 0x80, 0xe0, 0x7f, 0x87, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xcf, 0x23, 0x98, 0x7f, 0x1c, 0xff, 0x39, 0x9f, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, + 0xcf, 0x27, 0x98, 0x7f, 0x3c, 0xff, 0x39, 0x8f, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, + 0xcf, 0x27, 0x9f, 0x8f, 0x3c, 0xc3, 0x39, 0x81, 0xe7, 0x3f, 0xcf, 0x39, 0xff, 0xff, 0xff, 0xc0, + 0xce, 0x27, 0x9f, 0x07, 0x1c, 0x03, 0x39, 0x80, 0xe7, 0x3f, 0x8f, 0x39, 0xff, 0xff, 0xff, 0xc0, + 0xc0, 0x27, 0x98, 0x06, 0x0c, 0x03, 0x39, 0x80, 0x60, 0x33, 0x03, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xe0, 0x77, 0xfc, 0x0e, 0x0e, 0x07, 0x7d, 0xc0, 0xf0, 0x3f, 0x87, 0x81, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xff, 0xf0, 0x3c, 0x07, 0x81, 0xff, 0xc0, 0xff, 0xf8, 0x07, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x7e, 0x0f, 0xc3, 0xff, 0xe1, 0xff, 0xfc, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xfc, 0x7f, 0x0f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xfe, 0x7f, 0x8f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xf0, 0x7e, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xf0, 0x7e, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x7f, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x7e, 0xff, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xff, 0xf8, 0x7e, 0x7f, 0xcf, 0xc1, 0xf9, 0xf8, 0x3f, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xf0, 0x7e, 0x7e, 0x3f, 0xcf, 0xc1, 0xf9, 0xf8, 0x7f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x7e, 0x7e, 0x1f, 0xcf, 0xc1, 0xf9, 0xf8, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xcf, 0xff, 0xf9, 0xff, 0xfc, 0x1f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x7e, 0x7e, 0x0f, 0xc3, 0xff, 0xe1, 0xff, 0xf0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x03, 0xe0, 0x3c, 0x7c, 0x07, 0x83, 0xff, 0xe0, 0xff, 0xf0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x26, 0x66, 0x66, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x33, 0x33, 0x32, 0x66, 0x66, 0x4c, 0x00, + 0x0c, 0xc9, 0x99, 0x99, 0x33, 0x33, 0x26, 0x66, 0x66, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x32, 0x00, + 0x0c, 0xc9, 0x99, 0x99, 0x33, 0x33, 0x26, 0x66, 0x66, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x33, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x81, 0xf0, 0x1f, 0x08, 0x08, 0x01, 0xc0, 0x1c, 0x08, 0x08, 0x20, 0x40, 0x7c, 0x00, + 0x00, 0x07, 0x81, 0xf8, 0x3f, 0x0c, 0x08, 0x01, 0xe0, 0x3c, 0x0c, 0x18, 0x60, 0x60, 0x7c, 0x00, + 0x00, 0x08, 0x61, 0x84, 0x38, 0x0e, 0x08, 0x06, 0x10, 0x43, 0x0e, 0x38, 0x79, 0xe1, 0x00, 0x00, + 0x00, 0x08, 0x61, 0x84, 0x38, 0x0f, 0x08, 0x06, 0x10, 0x43, 0x0f, 0x38, 0x79, 0xe1, 0x00, 0x00, + 0x00, 0x08, 0x61, 0xf8, 0x3f, 0x0c, 0x88, 0x06, 0x00, 0x43, 0x0c, 0xd8, 0x66, 0x60, 0x70, 0x00, + 0x00, 0x08, 0x61, 0xf0, 0x3f, 0x0c, 0xd8, 0x06, 0x00, 0x43, 0x0c, 0x88, 0x66, 0x60, 0x70, 0x00, + 0x00, 0x08, 0x61, 0x80, 0x30, 0x0c, 0x38, 0x06, 0x18, 0x43, 0x0c, 0x08, 0x60, 0x60, 0x0c, 0x00, + 0x00, 0x08, 0x61, 0x80, 0x38, 0x0c, 0x38, 0x06, 0x10, 0x43, 0x0c, 0x08, 0x60, 0x60, 0x0c, 0x00, + 0x00, 0x07, 0x81, 0x80, 0x3f, 0x0c, 0x18, 0x01, 0xe0, 0x3c, 0x0c, 0x08, 0x60, 0x61, 0xf0, 0x00, + 0x00, 0x03, 0x81, 0x00, 0x1f, 0x08, 0x08, 0x00, 0xc0, 0x1c, 0x08, 0x08, 0x20, 0x41, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc6, 0x06, 0x07, 0xc3, 0xf0, 0xf8, 0x60, 0x60, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xe0, 0x70, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x98, 0x18, 0x00, 0xc0, 0xc0, 0x79, 0xe1, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x70, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x60, 0x07, 0x00, 0xc0, 0xf8, 0x66, 0x60, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x40, 0xc0, 0xc0, 0x60, 0x60, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x00, 0x40, 0xc0, 0xc0, 0x60, 0x60, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x60, 0x1f, 0x00, 0xc0, 0xf8, 0x60, 0x61, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x60, 0x1f, 0x00, 0xc0, 0xf8, 0x60, 0x61, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_hwok [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0x1c, 0x7e, 0x0f, 0xe0, 0x3f, 0x01, 0xf8, 0x7e, 0x3f, 0x03, 0xf0, 0x1f, 0x80, 0xff, 0xc0, + 0xff, 0x08, 0x7e, 0x07, 0xc0, 0x3f, 0x00, 0xf8, 0x7e, 0x3f, 0x03, 0xf0, 0x1f, 0x80, 0xff, 0xc0, + 0xff, 0x08, 0x78, 0x43, 0xc3, 0x0f, 0x08, 0x78, 0x6e, 0x3e, 0x31, 0xf0, 0x87, 0x87, 0xff, 0xc0, + 0xff, 0x08, 0x78, 0x41, 0xc3, 0x0f, 0x08, 0x78, 0x66, 0x3c, 0x30, 0xf0, 0x87, 0x87, 0xff, 0xc0, + 0xff, 0x00, 0x78, 0x01, 0xc0, 0x3f, 0x08, 0x78, 0x66, 0x3c, 0x00, 0xf0, 0x1f, 0x80, 0xff, 0xc0, + 0xff, 0x00, 0x78, 0x01, 0xc0, 0x3f, 0x08, 0x78, 0x44, 0x3c, 0x00, 0xf0, 0x1f, 0x80, 0xff, 0xc0, + 0xff, 0x08, 0x78, 0x41, 0xc0, 0x3f, 0x08, 0x78, 0x00, 0x3c, 0x30, 0xf0, 0x1f, 0x87, 0xff, 0xc0, + 0xff, 0x08, 0x78, 0x61, 0xc0, 0x3f, 0x08, 0x78, 0x00, 0x3c, 0x30, 0xf0, 0x1f, 0x87, 0xff, 0xc0, + 0xff, 0x08, 0x78, 0x61, 0xc3, 0x0f, 0x00, 0xfe, 0x10, 0x7c, 0x30, 0xf0, 0x87, 0x80, 0xff, 0xc0, + 0xff, 0x1c, 0x78, 0x63, 0xe3, 0x0f, 0x01, 0xfe, 0x38, 0xfe, 0x31, 0xf1, 0xc7, 0x80, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x3e, 0x3c, 0x3c, 0x7c, 0x07, 0xff, 0xfe, 0x0f, 0xc7, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x1c, 0x3c, 0x3c, 0x07, 0xff, 0xfc, 0x0f, 0xc2, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x0c, 0x3c, 0x3e, 0x1f, 0xff, 0xf8, 0xc3, 0xc0, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x04, 0x3c, 0x3e, 0x1f, 0xff, 0xf0, 0xc3, 0xc0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x00, 0x3c, 0x3e, 0x1f, 0xff, 0xf0, 0xc3, 0xc0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x00, 0x3c, 0x3e, 0x1f, 0xff, 0xf0, 0xc3, 0xc0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x10, 0x3c, 0x3e, 0x1f, 0xff, 0xf0, 0xc3, 0xc0, 0x7f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x38, 0x3c, 0x3e, 0x1f, 0xff, 0xf8, 0xc3, 0xc0, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1e, 0x3c, 0x3c, 0x3e, 0x1f, 0xff, 0xfc, 0x0f, 0xc2, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x3e, 0x3c, 0x3c, 0x7f, 0x1f, 0xff, 0xfe, 0x0f, 0xc7, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xf0, 0x1f, 0x01, 0xf8, 0xf8, 0xff, 0xff, 0x01, 0xf8, 0x0f, 0xc1, 0xfc, 0x07, 0xe3, 0xe3, 0xc0, + 0xf0, 0x1e, 0x01, 0xf8, 0x70, 0xff, 0xfe, 0x01, 0xf8, 0x0f, 0xc0, 0xf8, 0x07, 0xe1, 0xc3, 0xc0, + 0xf8, 0x3e, 0x18, 0x7c, 0x03, 0xff, 0xfe, 0x18, 0x78, 0x7f, 0x0c, 0x78, 0x21, 0xf0, 0x07, 0xc0, + 0xfc, 0x3e, 0x18, 0x7e, 0x03, 0xff, 0xfe, 0x18, 0x78, 0x7f, 0x0c, 0x38, 0x61, 0xf8, 0x0f, 0xc0, + 0xfc, 0x3e, 0x01, 0xff, 0x07, 0xff, 0xfe, 0x01, 0xf8, 0x0f, 0x00, 0x38, 0x61, 0xfc, 0x1f, 0xc0, + 0xfc, 0x3e, 0x01, 0xff, 0x07, 0xff, 0xfe, 0x01, 0xf8, 0x0f, 0x00, 0x38, 0x61, 0xfe, 0x3f, 0xc0, + 0xfc, 0x3e, 0x01, 0xfe, 0x03, 0xff, 0xfe, 0x01, 0xf8, 0x7f, 0x0c, 0x38, 0x61, 0xfe, 0x3f, 0xc0, + 0xfc, 0x3e, 0x01, 0xfc, 0x03, 0xff, 0xfe, 0x01, 0xf8, 0x7f, 0x0c, 0x38, 0x21, 0xfe, 0x3f, 0xc0, + 0xfc, 0x3e, 0x18, 0x78, 0x70, 0xff, 0xfe, 0x18, 0x78, 0x0f, 0x0c, 0x38, 0x07, 0xfe, 0x3f, 0xc0, + 0xfc, 0x7f, 0x18, 0x78, 0xf8, 0xff, 0xff, 0x18, 0x78, 0x0f, 0x0c, 0x7c, 0x07, 0xfe, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_console_active [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7f, 0x83, 0xf1, 0xf1, 0xf8, 0x0f, 0xe0, 0xfc, 0x7f, 0xc0, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7f, 0x03, 0xf0, 0xe1, 0xf8, 0x0f, 0xc0, 0xfc, 0x3f, 0x80, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0xc6, 0x3e, 0x10, 0xf0, 0x61, 0xe1, 0xff, 0x84, 0x3c, 0x3f, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x86, 0x3e, 0x30, 0xf0, 0x21, 0xe1, 0xff, 0x0c, 0x3c, 0x3f, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0x87, 0xfe, 0x30, 0xf0, 0x01, 0xf8, 0x3f, 0x0c, 0x3c, 0x3f, 0x80, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0x87, 0xfe, 0x30, 0xf0, 0x01, 0xf8, 0x1f, 0x0c, 0x3c, 0x3f, 0x80, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0x86, 0x3e, 0x30, 0xf0, 0x81, 0xff, 0x8f, 0x0c, 0x3c, 0x3f, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xc6, 0x3e, 0x10, 0xf0, 0xc1, 0xff, 0x8f, 0x84, 0x3c, 0x3f, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7f, 0x03, 0xf0, 0xe1, 0xe0, 0x1f, 0xc0, 0xfc, 0x07, 0x80, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0xe0, 0x7f, 0x83, 0xf1, 0xf1, 0xe0, 0x3f, 0xe0, 0xfc, 0x07, 0xc0, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xc1, 0xfc, 0x07, 0x8f, 0x8f, 0x0f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xc0, 0xfc, 0x07, 0x87, 0x0f, 0x0f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0c, 0x7e, 0x1f, 0x87, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0c, 0x7e, 0x1f, 0x87, 0x87, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x0f, 0x0f, 0xfe, 0x1f, 0x87, 0xc0, 0x3f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe0, 0x0f, 0x0f, 0xfe, 0x1f, 0x87, 0xc0, 0x3f, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0c, 0x7e, 0x1f, 0x87, 0xc0, 0x3f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0x0c, 0x7e, 0x1f, 0x87, 0xe0, 0x3f, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe1, 0x0f, 0xc0, 0xfe, 0x1f, 0x87, 0xf0, 0xff, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xe3, 0x8f, 0xc1, 0xff, 0x1f, 0x8f, 0xf8, 0xff, 0x01, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_checks [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0x0f, 0x8e, 0x3c, 0x7f, 0x07, 0xe0, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf8, 0x0f, 0x0c, 0x3c, 0x3e, 0x07, 0xe0, 0x3f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xff, 0x08, 0x78, 0x7f, 0x0c, 0x3c, 0x3c, 0x21, 0xe1, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xff, 0x08, 0x78, 0x7f, 0x84, 0x3c, 0x38, 0x61, 0xe1, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xff, 0x08, 0x78, 0x0f, 0xc0, 0xfc, 0x38, 0x7f, 0xe0, 0x3f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xff, 0x08, 0x78, 0x0f, 0xc0, 0xfc, 0x38, 0x7f, 0xe0, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x78, 0x7f, 0xc0, 0xfc, 0x38, 0x61, 0xe1, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x78, 0x7f, 0xe0, 0xfc, 0x3c, 0x21, 0xe1, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf8, 0x0f, 0xf1, 0xfc, 0x3e, 0x07, 0xe0, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf8, 0x0f, 0xfb, 0xfc, 0x7f, 0x07, 0xe0, 0x3f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0x18, 0x78, 0x0f, 0xc1, 0xfc, 0x61, 0xf8, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3e, 0x18, 0x78, 0x0f, 0xc0, 0xf8, 0x21, 0xf0, 0x0f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xc2, 0x1e, 0x18, 0x78, 0x7f, 0x0c, 0x78, 0x07, 0xe1, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xc3, 0x1e, 0x18, 0x78, 0x7f, 0x0c, 0x78, 0x07, 0xe1, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xc3, 0xfe, 0x00, 0x78, 0x0f, 0x0f, 0xf8, 0x1f, 0xf0, 0x3f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xc3, 0xfe, 0x00, 0x78, 0x0f, 0x0f, 0xf8, 0x1f, 0xf8, 0x1f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x1e, 0x18, 0x78, 0x7f, 0x0c, 0x78, 0x07, 0xff, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x1e, 0x18, 0x78, 0x7f, 0x0c, 0x78, 0x07, 0xff, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3e, 0x18, 0x78, 0x0f, 0xc0, 0xf8, 0x21, 0xe0, 0x1f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0x18, 0x78, 0x0f, 0xc1, 0xfc, 0x61, 0xe0, 0x3f, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x38, 0x00, 0x00, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x7c, 0x00, 0x00, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0x8f, 0x87, 0xc0, 0x7f, 0xc1, 0xfe, 0x03, 0xf0, 0x1f, 0x01, 0xe0, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0x87, 0x0f, 0xc0, 0x3f, 0x81, 0xfc, 0x03, 0xf0, 0x1e, 0x01, 0xe0, 0x1f, 0xc0, + 0xfc, 0x7c, 0x01, 0xc6, 0x1f, 0xc2, 0x1f, 0x18, 0x78, 0x7f, 0xc3, 0xfe, 0x1f, 0xe1, 0x0f, 0xc0, + 0xfc, 0x38, 0x01, 0xe4, 0x3f, 0xc2, 0x1e, 0x18, 0x78, 0x7f, 0xc3, 0xfe, 0x1f, 0xe1, 0x0f, 0xc0, + 0xfc, 0x38, 0x00, 0x60, 0x7f, 0xc0, 0x3e, 0x00, 0x7c, 0x0f, 0xf0, 0x7e, 0x01, 0xe1, 0x0f, 0xc0, + 0xfc, 0x7c, 0x00, 0x60, 0xff, 0xc0, 0x7e, 0x00, 0x7e, 0x07, 0xf0, 0x3e, 0x01, 0xe1, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xf1, 0xff, 0xc3, 0xfe, 0x18, 0x7f, 0xc3, 0xfe, 0x1e, 0x1f, 0xe1, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xfb, 0xff, 0xc3, 0xfe, 0x18, 0x7f, 0xc3, 0xfe, 0x1e, 0x1f, 0xe1, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xfe, 0x18, 0x78, 0x07, 0xc0, 0x3e, 0x01, 0xe0, 0x1f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xff, 0x18, 0x78, 0x0f, 0xc0, 0x7f, 0x01, 0xe0, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0xc0, 0x00, 0x00, 0xc3, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0xc0, 0x00, 0x00, 0xc3, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0xc0, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0xc0, 0x00, 0x00, 0xc3, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0xc0, 0x00, 0x00, 0xc3, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x66, 0x66, 0x66, 0x19, 0x99, 0x99, 0x98, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x66, 0x66, 0x66, 0x19, 0x99, 0x99, 0x98, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const unsigned char bm_updating [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf3, 0xf0, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf8, 0x1f, 0xff, 0xf3, 0xf0, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf8, 0x9f, 0xff, 0xf3, 0xf3, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf8, 0x9f, 0xff, 0xf3, 0xf2, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xf8, 0x1f, 0xff, 0xf3, 0xf0, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xfb, 0xf0, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xff, 0xd9, 0x81, 0xff, 0xf3, 0x03, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xff, 0xc9, 0x81, 0xff, 0xf3, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xff, 0xc9, 0x99, 0xff, 0xf3, 0x33, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xff, 0xc9, 0x81, 0xff, 0xf3, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xff, 0xc9, 0x81, 0xff, 0xf3, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xc3, 0xff, 0xff, 0x87, 0x87, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe1, 0xff, 0xe3, 0xc3, 0xfc, 0x3f, 0xf8, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xfc, 0xc1, 0x81, 0xf8, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xfc, 0xc9, 0x81, 0xf9, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xfc, 0xc9, 0x99, 0xf9, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xfc, 0xc1, 0x81, 0xf8, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xc0, 0xfc, 0xc1, 0x81, 0xf8, 0x33, 0x30, 0x37, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xe1, 0xdc, 0x1f, 0xb8, 0x3b, 0xf0, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xc0, 0xc8, 0x19, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x44, 0xc8, 0xc8, 0x99, 0x99, 0x33, 0x32, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xc8, 0x99, 0x99, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xc0, 0xc8, 0x19, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xc0, 0xdc, 0x19, 0x98, 0x33, 0x30, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0e, 0xc1, 0xdd, 0xc1, 0x83, 0xbb, 0x87, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc0, 0xc9, 0x81, 0x81, 0x33, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xc9, 0x99, 0x91, 0x33, 0x33, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xc9, 0x99, 0x91, 0x33, 0x33, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc0, 0xc9, 0x81, 0x81, 0x33, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc1, 0xdd, 0xc1, 0x83, 0xbb, 0x03, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x44, 0xcc, 0xc9, 0x89, 0x99, 0x33, 0x32, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xfd, 0xc1, 0xc3, 0xb8, 0x3b, 0xf0, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf3, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf7, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xef, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x87, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x77, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xf3, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xec, 0xfc, 0x00, 0x00, 0x00, 0x03, 0xf3, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xc7, 0x80, 0x00, 0x00, 0x1f, 0xb0, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xc3, 0xc0, 0x00, 0x00, 0x3f, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x44, 0xcd, 0xe0, 0x00, 0x00, 0x7b, 0x32, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x44, 0xcc, 0xf0, 0x00, 0x00, 0xf3, 0x32, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xc0, 0xf8, 0x00, 0x01, 0xf3, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xc1, 0xfc, 0x00, 0x03, 0xfb, 0x30, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc1, 0xdf, 0x80, 0x1f, 0xbb, 0x03, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc0, 0xcf, 0xc0, 0x3f, 0x33, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xcd, 0xe0, 0x7b, 0x33, 0x33, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xc8, 0xc9, 0xf0, 0xf1, 0x33, 0x33, 0x23, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0c, 0xc0, 0xc9, 0xff, 0xe1, 0x33, 0x03, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x0e, 0xc1, 0xdd, 0xff, 0xe3, 0xbb, 0x87, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe0, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x4c, 0xcc, 0xc9, 0x99, 0x99, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xcc, 0xc9, 0x81, 0x99, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x40, 0xcc, 0xc1, 0x81, 0x98, 0x33, 0x30, 0x33, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0xe1, 0xff, 0xc1, 0xc3, 0xf8, 0x3f, 0xf8, 0x77, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_fw_corrupt [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xf0, 0x1f, 0x1e, 0x03, 0xf8, 0xfc, 0x7c, 0x7e, 0x3f, 0x83, 0xf0, 0x1f, 0xc0, 0x7f, 0xff, 0xc0, + 0xf0, 0x1e, 0x1e, 0x01, 0xf0, 0xfc, 0x38, 0x7e, 0x1f, 0x01, 0xf0, 0x0f, 0x80, 0x7f, 0xff, 0xc0, + 0xf0, 0xfe, 0x1e, 0x10, 0xf0, 0x30, 0x38, 0x66, 0x1e, 0x10, 0xf0, 0x87, 0x87, 0xff, 0xff, 0xc0, + 0xf0, 0xfe, 0x1e, 0x10, 0xf0, 0x30, 0x38, 0x66, 0x1e, 0x10, 0xf0, 0x87, 0x87, 0xff, 0xff, 0xc0, + 0xf0, 0x1e, 0x1e, 0x01, 0xf0, 0x00, 0x38, 0x66, 0x1e, 0x00, 0xf0, 0x0f, 0x80, 0x7f, 0xff, 0xc0, + 0xf0, 0x1e, 0x1e, 0x01, 0xf0, 0x00, 0x38, 0x26, 0x1e, 0x00, 0xf0, 0x0f, 0x80, 0x7f, 0xff, 0xc0, + 0xf0, 0xfe, 0x1e, 0x01, 0xf0, 0xcc, 0x38, 0x00, 0x1e, 0x10, 0xf0, 0x0f, 0x87, 0xff, 0xff, 0xc0, + 0xf0, 0xfe, 0x1e, 0x01, 0xf0, 0xcc, 0x3c, 0x00, 0x3e, 0x30, 0xf0, 0x0f, 0x87, 0xff, 0xff, 0xc0, + 0xf0, 0xfe, 0x1e, 0x10, 0xf0, 0xfc, 0x3e, 0x18, 0x7e, 0x30, 0xf0, 0x87, 0x80, 0x7f, 0xff, 0xc0, + 0xf1, 0xff, 0x1e, 0x38, 0xf8, 0xfc, 0x7f, 0x18, 0x7e, 0x38, 0xf1, 0xc7, 0xc0, 0x7f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x1f, 0xe0, 0x7e, 0x03, 0xf0, 0x1f, 0xc6, 0x3e, 0x03, 0xf0, 0x1f, 0xfe, 0x1f, 0xff, 0xc0, + 0xf8, 0x0f, 0xe0, 0x7e, 0x03, 0xf0, 0x0f, 0x86, 0x1e, 0x01, 0xf0, 0x1f, 0xfe, 0x1f, 0xff, 0xc0, + 0xf0, 0x87, 0xc6, 0x3e, 0x10, 0xf0, 0x87, 0x86, 0x1e, 0x10, 0xfc, 0x3f, 0xf9, 0xef, 0xff, 0xc0, + 0xf0, 0xc7, 0x86, 0x1e, 0x10, 0xf0, 0x87, 0x86, 0x1e, 0x10, 0xfc, 0x3f, 0xf9, 0xe7, 0xff, 0xc0, + 0xf0, 0xff, 0x86, 0x1e, 0x03, 0xf0, 0x0f, 0x86, 0x1e, 0x01, 0xfc, 0x3f, 0xf9, 0xe7, 0xff, 0xc0, + 0xf0, 0xff, 0x86, 0x1e, 0x03, 0xf0, 0x0f, 0x86, 0x1e, 0x03, 0xfc, 0x3f, 0xf9, 0xe7, 0xff, 0xc0, + 0xf0, 0xc7, 0x86, 0x1e, 0x03, 0xf0, 0x0f, 0x86, 0x1e, 0x1f, 0xfc, 0x3f, 0xe7, 0xfb, 0xff, 0xc0, + 0xf0, 0x87, 0xc6, 0x3e, 0x03, 0xf0, 0x0f, 0xc6, 0x3e, 0x3f, 0xfc, 0x3f, 0xe7, 0xf9, 0xff, 0xc0, + 0xf8, 0x0f, 0xe0, 0x7e, 0x10, 0xf0, 0x87, 0xe0, 0x7e, 0x3f, 0xfc, 0x3f, 0xe6, 0x19, 0xff, 0xc0, + 0xfc, 0x1f, 0xe0, 0x7e, 0x38, 0xf1, 0xc7, 0xe0, 0x7e, 0x3f, 0xfc, 0x7f, 0xe6, 0x19, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xde, 0x1e, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x1e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x1e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9e, 0x1e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x1f, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7e, 0x1f, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7e, 0x1f, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7e, 0x1f, 0xbf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x1f, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0x1f, 0xef, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xfe, 0x1f, 0xf3, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xfe, 0x1f, 0xf3, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xf3, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xf3, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_pairing [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x03, 0xf8, 0x3f, 0x1f, 0x01, 0xf8, 0xf8, 0xf1, 0xfc, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x01, 0xf0, 0x3f, 0x0e, 0x01, 0xf8, 0x70, 0xf0, 0xf8, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x11, 0xe3, 0x0f, 0x0e, 0x18, 0x78, 0x70, 0x30, 0xf0, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x11, 0xc3, 0x0f, 0x0e, 0x18, 0x78, 0x70, 0x30, 0xf1, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x01, 0xc0, 0x0f, 0x0e, 0x01, 0xf8, 0x70, 0x00, 0xf1, 0xc7, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x03, 0xc0, 0x0f, 0x0e, 0x01, 0xf8, 0x70, 0x00, 0xf1, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1f, 0xc3, 0x0f, 0x0e, 0x01, 0xf8, 0x70, 0xc0, 0xf1, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1f, 0xc3, 0x0f, 0x0e, 0x01, 0xf8, 0x70, 0xc0, 0xf0, 0x87, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x1f, 0xc3, 0x0f, 0x0e, 0x18, 0x78, 0x70, 0xf0, 0xf8, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x3f, 0xe3, 0x0f, 0x1f, 0x18, 0x78, 0xf8, 0xf1, 0xfc, 0x1f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_online [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xf0, 0x1c, 0x07, 0xe0, 0xf8, 0xf1, 0xf0, 0x1e, 0x0f, 0x80, 0xc3, 0x1c, 0x60, 0x18, 0x0f, 0xc0, + 0xf0, 0x18, 0x07, 0xc0, 0x70, 0xf0, 0xe0, 0x1e, 0x07, 0x00, 0xc3, 0x08, 0x60, 0x18, 0x07, 0xc0, + 0xf8, 0x38, 0x21, 0x84, 0x30, 0x30, 0xc3, 0xf8, 0x43, 0x07, 0xc3, 0x08, 0x61, 0xf8, 0x43, 0xc0, + 0xfc, 0x38, 0x21, 0x84, 0x30, 0x30, 0xc3, 0xf8, 0x63, 0x07, 0xc3, 0x08, 0x61, 0xf8, 0x43, 0xc0, + 0xfc, 0x38, 0x07, 0x80, 0x30, 0x00, 0xe0, 0x78, 0x7f, 0x00, 0xc3, 0x80, 0xe0, 0x18, 0x07, 0xc0, + 0xfc, 0x38, 0x07, 0x80, 0x30, 0x00, 0xf0, 0x38, 0x7f, 0x00, 0xc3, 0xc1, 0xe0, 0x18, 0x0f, 0xc0, + 0xfc, 0x38, 0x07, 0x84, 0x30, 0xc0, 0xfe, 0x18, 0x63, 0x07, 0xc3, 0xc1, 0xe1, 0xf8, 0x0f, 0xc0, + 0xfc, 0x38, 0x07, 0x86, 0x30, 0xc0, 0xfe, 0x18, 0x43, 0x07, 0xc3, 0xc1, 0xe1, 0xf8, 0x07, 0xc0, + 0xfc, 0x38, 0x21, 0x86, 0x30, 0xf0, 0xc0, 0x3e, 0x07, 0x00, 0xc3, 0xe3, 0xe0, 0x18, 0x43, 0xc0, + 0xfc, 0x7c, 0x61, 0x8e, 0x38, 0xf1, 0xc0, 0x7e, 0x0f, 0x80, 0xc3, 0xf7, 0xe0, 0x18, 0xe3, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x0f, 0xf8, 0xf1, 0xfc, 0x7f, 0xe3, 0xf8, 0xf1, 0xfc, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x07, 0xf0, 0xf0, 0xf8, 0x7f, 0xe1, 0xf0, 0xf0, 0xf8, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x43, 0xf0, 0x30, 0xf8, 0x7f, 0xe1, 0xf0, 0x30, 0xf8, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x61, 0xf0, 0x30, 0xf8, 0x7f, 0xe1, 0xf0, 0x30, 0xf8, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x61, 0xf0, 0x00, 0xf8, 0x7f, 0xe1, 0xf0, 0x00, 0xf8, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x61, 0xf0, 0x00, 0xf8, 0x7f, 0xe1, 0xf0, 0x00, 0xf8, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x61, 0xf0, 0xc0, 0xf8, 0x7f, 0xe1, 0xf0, 0xc0, 0xf8, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xf8, 0x43, 0xf0, 0xc0, 0xf8, 0x3f, 0xe1, 0xf0, 0xc0, 0xf8, 0x3f, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x07, 0xf0, 0xf0, 0xf8, 0x07, 0xe1, 0xf0, 0xf0, 0xf8, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xfe, 0x0f, 0xf8, 0xf1, 0xfc, 0x07, 0xe3, 0xf8, 0xf1, 0xfc, 0x07, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_console [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfe, 0x07, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xfe, 0x0f, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xfc, 0x1f, 0xff, 0xc0, + 0xff, 0xf8, 0x1f, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xfe, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0x07, 0xff, 0xc0, + 0xff, 0xf0, 0x7f, 0xff, 0x0f, 0x0f, 0xf1, 0xe1, 0xe0, 0x3c, 0x3c, 0x3f, 0xff, 0x81, 0xff, 0xc0, + 0xff, 0xe0, 0xff, 0xff, 0x0f, 0x0f, 0xe1, 0xe1, 0xe0, 0x3c, 0x3c, 0x3f, 0xff, 0xc1, 0xff, 0xc0, + 0xff, 0xc1, 0xf8, 0x7f, 0x0f, 0x0c, 0x21, 0xe1, 0xe1, 0xfc, 0x3c, 0x3f, 0x87, 0xe0, 0xff, 0xc0, + 0xff, 0xc3, 0xf0, 0x7f, 0x0f, 0x0c, 0x21, 0xe1, 0xe0, 0x3c, 0x3c, 0x3f, 0x83, 0xf0, 0x7f, 0xc0, + 0xff, 0xc7, 0xe0, 0x7f, 0x0f, 0x0c, 0x21, 0xe1, 0xe0, 0x3c, 0x3c, 0x3f, 0x81, 0xf8, 0x7f, 0xc0, + 0xff, 0x87, 0xc0, 0xff, 0x0f, 0x00, 0x01, 0xe1, 0xe0, 0x3c, 0x3c, 0x3f, 0xc0, 0xf8, 0x3f, 0xc0, + 0xff, 0x07, 0x81, 0xff, 0x0f, 0x00, 0x01, 0xe1, 0xe1, 0xfc, 0x3c, 0x3f, 0xe0, 0x78, 0x3f, 0xc0, + 0xff, 0x07, 0x83, 0xff, 0x0f, 0x80, 0x03, 0xe1, 0xe1, 0xfc, 0x3c, 0x3f, 0xf0, 0x7c, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0xff, 0x0f, 0xc3, 0xc7, 0xe1, 0xe1, 0xfc, 0x3c, 0x3f, 0xf8, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0xcf, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3c, 0x78, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0x87, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x38, 0x78, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0x87, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x38, 0x78, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0x87, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3c, 0x78, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0xff, 0x0f, 0xff, 0xf0, 0x7f, 0x00, 0xff, 0xfc, 0x3f, 0xf8, 0x7e, 0x3f, 0xc0, + 0xff, 0x0f, 0x87, 0xff, 0x0f, 0xff, 0xe0, 0x7e, 0x00, 0x7f, 0xfc, 0x3f, 0xf8, 0x7c, 0x3f, 0xc0, + 0xff, 0x07, 0x83, 0xff, 0x0f, 0xff, 0xc2, 0x1e, 0x10, 0x7f, 0xfc, 0x3f, 0xf0, 0x78, 0x3f, 0xc0, + 0xff, 0x07, 0x81, 0xff, 0x0f, 0xff, 0xc2, 0x1e, 0x18, 0x7f, 0xfc, 0x3f, 0xe0, 0x78, 0x3f, 0xc0, + 0xff, 0x87, 0xe0, 0xff, 0x0f, 0xff, 0xc0, 0x1e, 0x00, 0x7f, 0xfc, 0x3f, 0xc0, 0xf8, 0x7f, 0xc0, + 0xff, 0xc3, 0xe0, 0x7f, 0x0f, 0xff, 0xc0, 0x1e, 0x00, 0xff, 0xfc, 0x3f, 0x81, 0xf8, 0x7f, 0xc0, + 0xff, 0xc1, 0xf8, 0x7f, 0x0f, 0xff, 0xc2, 0x1e, 0x1f, 0xff, 0xfc, 0x3f, 0x83, 0xe0, 0x7f, 0xc0, + 0xff, 0xc1, 0xf8, 0x7f, 0x0f, 0xff, 0xc6, 0x1e, 0x1f, 0xff, 0xfc, 0x3f, 0x87, 0xe0, 0xff, 0xc0, + 0xff, 0xe0, 0x7f, 0xff, 0x0f, 0xff, 0xc6, 0x1e, 0x1f, 0xff, 0xfc, 0x3f, 0xff, 0x81, 0xff, 0xc0, + 0xff, 0xf0, 0x7f, 0xff, 0x0f, 0xff, 0xc7, 0x1e, 0x1f, 0xff, 0xfc, 0x3f, 0xff, 0x83, 0xff, 0xc0, + 0xff, 0xf8, 0x1f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xfe, 0x07, 0xff, 0xc0, + 0xff, 0xfc, 0x1f, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xfe, 0x0f, 0xff, 0xc0, + 0xff, 0xfe, 0x07, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0x07, 0xff, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xf8, 0x1f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xc0, + 0xff, 0xe7, 0xff, 0xfe, 0x7f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xff, 0x3f, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xe7, 0xff, 0xfe, 0x7f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xff, 0x3f, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xe7, 0xff, 0xfe, 0x7f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xff, 0x3f, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xe7, 0xff, 0xfe, 0x7f, 0xff, 0xcf, 0xff, 0xf9, 0xff, 0xff, 0x3f, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xf7, 0xff, 0xfe, 0xff, 0xff, 0xdf, 0xff, 0xf9, 0xff, 0xff, 0x3f, 0xff, 0xe7, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfe, 0x00, 0xff, 0xc0, 0x0f, 0xf8, 0x01, 0xff, 0x00, 0x3f, 0xe0, 0x07, 0xfc, 0x00, 0xff, 0xc0, + 0xfc, 0x00, 0x7f, 0x80, 0x0f, 0xf0, 0x01, 0xfe, 0x00, 0x3f, 0xc0, 0x03, 0xf8, 0x00, 0x7f, 0xc0, + 0xfc, 0xff, 0x9f, 0x9f, 0xf3, 0xf3, 0xfe, 0x7e, 0x7f, 0xcf, 0xcf, 0xf9, 0xf8, 0xff, 0x3f, 0xc0, + 0xfc, 0xff, 0x9f, 0x9f, 0xf3, 0xf3, 0xff, 0x7e, 0x7f, 0xef, 0xcf, 0xfd, 0xf9, 0xff, 0xbf, 0xc0, + 0xfc, 0xc1, 0xef, 0x9b, 0xbc, 0xf3, 0x1f, 0x9e, 0x78, 0xf3, 0xcf, 0x7e, 0x79, 0x83, 0xcf, 0xc0, + 0xfc, 0xc1, 0xe7, 0x99, 0xbc, 0xf3, 0x1f, 0x9e, 0x78, 0x73, 0xcf, 0x3e, 0x79, 0x83, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x99, 0xfc, 0xf3, 0x3d, 0x9e, 0x67, 0x33, 0xcf, 0x1e, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x99, 0xfc, 0xf3, 0x39, 0x9e, 0x67, 0x33, 0xcf, 0x0e, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0xc0, 0x67, 0x98, 0x3c, 0xf3, 0x19, 0x9e, 0x67, 0x33, 0xcf, 0x0e, 0x79, 0xb8, 0xcf, 0xc0, + 0xfc, 0xc0, 0x67, 0x98, 0x3c, 0xf3, 0x09, 0x9e, 0x67, 0x33, 0xcf, 0x0e, 0x79, 0x98, 0x4f, 0xc0, + 0xfc, 0xff, 0xe7, 0x9f, 0xfc, 0xf3, 0x01, 0x9e, 0x78, 0x73, 0xcf, 0x0e, 0x79, 0x98, 0x4f, 0xc0, + 0xfc, 0xff, 0xe7, 0x9f, 0xfc, 0xf3, 0x01, 0x9e, 0x78, 0x73, 0xcf, 0x0e, 0x79, 0x98, 0xcf, 0xc0, + 0xfc, 0xdc, 0x67, 0x98, 0x3c, 0xf3, 0x39, 0x9e, 0x78, 0x73, 0xcf, 0x0e, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0xdc, 0x67, 0x98, 0x3c, 0xf3, 0x39, 0x9e, 0x78, 0x73, 0xcf, 0x1e, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x99, 0xfc, 0xf3, 0x31, 0x9e, 0x67, 0x33, 0xcf, 0xfe, 0x79, 0x8e, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x99, 0xfc, 0xf3, 0x21, 0x9e, 0x67, 0x33, 0xcf, 0xfe, 0x79, 0x86, 0x4f, 0xc0, + 0xfc, 0xc0, 0x67, 0x99, 0xbc, 0xf3, 0x01, 0x9e, 0x67, 0x33, 0xcf, 0x1e, 0x79, 0x86, 0x4f, 0xc0, + 0xfc, 0xc0, 0x67, 0x9b, 0xbc, 0xf3, 0x01, 0x9e, 0x6f, 0xb3, 0xcf, 0x1e, 0x79, 0x8e, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x9f, 0xfc, 0xf3, 0xff, 0x9e, 0x7f, 0xf3, 0xcf, 0xfe, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0xff, 0xe7, 0x9f, 0xfc, 0xf3, 0xff, 0x9e, 0x7f, 0xf3, 0xcf, 0xfe, 0x79, 0xff, 0xcf, 0xc0, + 0xfc, 0x00, 0x07, 0x80, 0x00, 0xf0, 0x00, 0x1e, 0x00, 0x03, 0xc0, 0x00, 0x78, 0x00, 0x0f, 0xc0, + 0xfc, 0x00, 0x07, 0x80, 0x00, 0xf0, 0x00, 0x1e, 0x00, 0x03, 0xc0, 0x00, 0x7c, 0x00, 0x0f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xfc, 0xf0, 0x3c, 0xff, 0xe1, 0xf0, 0x0f, 0xfc, 0x07, 0xfe, 0x03, 0xff, 0x0f, 0xff, 0xc0, + 0xff, 0xf8, 0x60, 0x18, 0x7f, 0xc0, 0xe0, 0x07, 0xf8, 0x03, 0xfc, 0x01, 0xfe, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x60, 0x18, 0x7f, 0xc0, 0xe0, 0x07, 0xf8, 0x03, 0xfc, 0x01, 0xfe, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x61, 0x98, 0x7f, 0xc0, 0xe1, 0x87, 0xf8, 0x43, 0xfc, 0x31, 0xfe, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x60, 0x1f, 0xff, 0xe0, 0xe1, 0x87, 0xf8, 0x43, 0xfc, 0x31, 0xff, 0x07, 0xff, 0xc0, + 0xff, 0xf8, 0x60, 0x1f, 0xff, 0xf0, 0xe1, 0x87, 0xf8, 0x43, 0xfc, 0x31, 0xff, 0x87, 0xff, 0xc0, + 0xff, 0xf8, 0x60, 0xf8, 0xff, 0xf0, 0xe1, 0x87, 0x38, 0x43, 0x9c, 0x31, 0xcf, 0x87, 0xff, 0xc0, + 0xff, 0xf8, 0x61, 0xf8, 0x7f, 0xf0, 0xe1, 0x86, 0x18, 0x43, 0x0c, 0x31, 0x87, 0x87, 0xff, 0xc0, + 0xff, 0xf8, 0x61, 0xf8, 0x7f, 0xf0, 0xe0, 0x06, 0x18, 0x03, 0x0c, 0x01, 0x87, 0x87, 0xff, 0xc0, + 0xff, 0xf8, 0x61, 0xf8, 0xff, 0xf0, 0xf0, 0x06, 0x18, 0x03, 0x0c, 0x01, 0x87, 0x87, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_hwfail [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x71, 0xf8, 0x3f, 0x80, 0xfc, 0x07, 0xe1, 0xf8, 0xfe, 0x0f, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xf8, 0x1f, 0x00, 0xfc, 0x03, 0xe1, 0xf8, 0x7c, 0x0f, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x8f, 0x04, 0x3c, 0x21, 0xe1, 0xb8, 0x78, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x04, 0x3c, 0x21, 0xe1, 0x98, 0x70, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xfc, 0x01, 0xe0, 0x07, 0x00, 0xfc, 0x21, 0xe1, 0x98, 0x70, 0x03, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xfc, 0x01, 0xe0, 0x07, 0x00, 0xfc, 0x21, 0xe1, 0x90, 0x70, 0x03, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x00, 0xfc, 0x21, 0xe0, 0x00, 0x70, 0xc3, 0xc0, 0x7e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x00, 0xfc, 0x21, 0xe0, 0x00, 0xf0, 0xc3, 0xc0, 0x3e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x04, 0x3c, 0x03, 0xf8, 0x41, 0xf0, 0xc3, 0xc2, 0x1e, 0x03, 0xff, 0xc0, + 0xfc, 0x71, 0xe1, 0x8f, 0x8c, 0x3c, 0x07, 0xf8, 0x63, 0xf8, 0xc3, 0xc7, 0x1e, 0x03, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x07, 0xe0, 0x7e, 0x3c, 0x3f, 0xc7, 0x1e, 0x03, 0xf8, 0x0f, 0xff, 0xf8, 0x7f, 0xff, 0xc0, + 0xfc, 0x07, 0xe0, 0x7e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xf8, 0x7f, 0xff, 0xc0, + 0xfc, 0x3f, 0xc6, 0x3e, 0x3c, 0x3f, 0xc6, 0x1e, 0x10, 0xf0, 0xff, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x10, 0xf0, 0xff, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x07, 0x80, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x07, 0x80, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0xff, 0xff, 0xdf, 0xef, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc2, 0x1e, 0x01, 0xf0, 0xff, 0xff, 0x9f, 0xe7, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x03, 0xe0, 0x3e, 0x10, 0xf0, 0x0f, 0xff, 0x98, 0x67, 0xff, 0xc0, + 0xfc, 0x7f, 0xc6, 0x3e, 0x3c, 0x03, 0xf0, 0x7e, 0x38, 0xf8, 0x0f, 0xff, 0x98, 0x67, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x7b, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf8, 0x7e, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, 0x7f, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf8, 0x7f, 0xbf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xf8, 0x7f, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xf8, 0x7f, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_no_radio [] PROGMEM = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x71, 0xf8, 0x3f, 0x80, 0xfc, 0x07, 0xe1, 0xf8, 0xfe, 0x0f, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xf8, 0x1f, 0x00, 0xfc, 0x03, 0xe1, 0xf8, 0x7c, 0x0f, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x8f, 0x04, 0x3c, 0x21, 0xe1, 0xb8, 0x78, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x04, 0x3c, 0x21, 0xe1, 0x98, 0x70, 0xc3, 0xc2, 0x1e, 0x1f, 0xff, 0xc0, + 0xfc, 0x01, 0xe0, 0x07, 0x00, 0xfc, 0x21, 0xe1, 0x98, 0x70, 0x03, 0xc0, 0x3e, 0x03, 0xff, 0xc0, + 0xfc, 0x01, 0xe0, 0x07, 0x00, 0xfc, 0x21, 0xe1, 0x90, 0x70, 0x03, 0xc0, 0x7e, 0x03, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x00, 0xfc, 0x21, 0xe0, 0x00, 0x70, 0xc3, 0xc0, 0x7e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x00, 0xfc, 0x21, 0xe0, 0x00, 0xf0, 0xc3, 0xc0, 0x3e, 0x1f, 0xff, 0xc0, + 0xfc, 0x21, 0xe1, 0x87, 0x04, 0x3c, 0x03, 0xf8, 0x41, 0xf0, 0xc3, 0xc2, 0x1e, 0x03, 0xff, 0xc0, + 0xfc, 0x71, 0xe1, 0x8f, 0x8c, 0x3c, 0x07, 0xf8, 0x63, 0xf8, 0xc3, 0xc7, 0x1e, 0x03, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xfc, 0x07, 0xe0, 0x7e, 0x3c, 0x3f, 0xc7, 0x1e, 0x03, 0xf8, 0x0f, 0xff, 0xf8, 0x7f, 0xff, 0xc0, + 0xfc, 0x07, 0xe0, 0x7e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xf8, 0x7f, 0xff, 0xc0, + 0xfc, 0x3f, 0xc6, 0x3e, 0x3c, 0x3f, 0xc6, 0x1e, 0x10, 0xf0, 0xff, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x10, 0xf0, 0xff, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x07, 0x80, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x07, 0x80, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0x0f, 0xff, 0xe7, 0x9f, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc6, 0x1e, 0x01, 0xf0, 0xff, 0xff, 0xdf, 0xef, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x3f, 0xc2, 0x1e, 0x01, 0xf0, 0xff, 0xff, 0x9f, 0xe7, 0xff, 0xc0, + 0xfc, 0x3f, 0x86, 0x1e, 0x3c, 0x03, 0xe0, 0x3e, 0x10, 0xf0, 0x0f, 0xff, 0x98, 0x67, 0xff, 0xc0, + 0xfc, 0x7f, 0xc6, 0x3e, 0x3c, 0x03, 0xf0, 0x7e, 0x38, 0xf8, 0x0f, 0xff, 0x98, 0x67, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x78, 0x7b, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x78, 0x79, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xf8, 0x7e, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0x7e, 0x7f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xf8, 0x7f, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf8, 0x7f, 0xbf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xf8, 0x7f, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xf8, 0x7f, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xcf, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 +}; + +const unsigned char bm_plug [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, + 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x33, 0x33, + 0xff, 0xf0, 0x00, 0x33, 0x33, 0xff, 0xf0, 0x00, 0xcc, 0xcc, 0xff, 0xf0, 0x00, 0xcc, 0xcc, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00 +}; + +const unsigned char bm_hg_low [] PROGMEM = { + 0xff, 0xc0, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x33, 0x00, 0x33, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x33, 0x00, 0x33, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0 +}; + +const unsigned char bm_hg_high [] PROGMEM = { + 0xff, 0xc0, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0x3f, 0x00, 0x3f, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff, 0xc0, + 0xff, 0xc0, 0xff, 0xc0 +}; + +const unsigned char bm_n_uh [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, // 0 + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0, 0xc0, 0xf0, 0xc0, 0xf0, 0xc0, 0xf0, 0xc0, + 0xf0, 0xc0, 0xf0, 0xc0, // 1 + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, + 0x00, 0x00, 0x00, 0x00, // 2 + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, // 3 + 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, + 0xfc, 0x00, 0xfc, 0x00, // 4 + 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, // 5 + 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, // 6 + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0xc0, 0xf0, 0xc0, 0xc3, 0xc0, 0xc3, 0xc0, + 0x03, 0xc0, 0x03, 0xc0, // 7 + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, // 8 + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, + 0xfc, 0x00, 0xfc, 0x00 // 9 +}; + +const unsigned char bm_dot_sqr [] PROGMEM = { + 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0xee, 0xee, 0xdd, 0xdd, 0xc0, 0xee, + 0xee, 0xdd, 0xdd, 0xc0 +}; + +#endif + + const unsigned char bm_nfr [] 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, @@ -391,64 +1729,3 @@ const unsigned char bm_nfr [] 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 }; - -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_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_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_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_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 -}; diff --git a/Graphics/Bitmaps/banner_boot.bmp b/Graphics/Bitmaps/banner_boot.bmp deleted file mode 100644 index 0004681..0000000 Binary files a/Graphics/Bitmaps/banner_boot.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_checks.bmp b/Graphics/Bitmaps/banner_checks.bmp deleted file mode 100644 index b38c4ab..0000000 Binary files a/Graphics/Bitmaps/banner_checks.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_console.bmp b/Graphics/Bitmaps/banner_console.bmp deleted file mode 100644 index 5fadff2..0000000 Binary files a/Graphics/Bitmaps/banner_console.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_fw_corrupt.bmp b/Graphics/Bitmaps/banner_fw_corrupt.bmp deleted file mode 100644 index a576097..0000000 Binary files a/Graphics/Bitmaps/banner_fw_corrupt.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_fw_update.bmp b/Graphics/Bitmaps/banner_fw_update.bmp deleted file mode 100644 index f975a65..0000000 Binary files a/Graphics/Bitmaps/banner_fw_update.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_hwfail.bmp b/Graphics/Bitmaps/banner_hwfail.bmp deleted file mode 100644 index e79217b..0000000 Binary files a/Graphics/Bitmaps/banner_hwfail.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_hwok.bmp b/Graphics/Bitmaps/banner_hwok.bmp deleted file mode 100644 index 4d546ba..0000000 Binary files a/Graphics/Bitmaps/banner_hwok.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_nfr.bmp b/Graphics/Bitmaps/banner_nfr.bmp deleted file mode 100644 index e89c41f..0000000 Binary files a/Graphics/Bitmaps/banner_nfr.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_no_radio.bmp b/Graphics/Bitmaps/banner_no_radio.bmp deleted file mode 100644 index e20ca74..0000000 Binary files a/Graphics/Bitmaps/banner_no_radio.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_online.bmp b/Graphics/Bitmaps/banner_online.bmp deleted file mode 100644 index 7906578..0000000 Binary files a/Graphics/Bitmaps/banner_online.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_pairing.bmp b/Graphics/Bitmaps/banner_pairing.bmp deleted file mode 100644 index 5dfd4bb..0000000 Binary files a/Graphics/Bitmaps/banner_pairing.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/banner_version.bmp b/Graphics/Bitmaps/banner_version.bmp deleted file mode 100644 index da02744..0000000 Binary files a/Graphics/Bitmaps/banner_version.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/bm_pairing.bmp b/Graphics/Bitmaps/bm_pairing.bmp deleted file mode 100644 index c4e5fa5..0000000 Binary files a/Graphics/Bitmaps/bm_pairing.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/bm_update.bmp b/Graphics/Bitmaps/bm_update.bmp deleted file mode 100644 index db3a180..0000000 Binary files a/Graphics/Bitmaps/bm_update.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/bt_icons.bmp b/Graphics/Bitmaps/bt_icons.bmp deleted file mode 100644 index 5da2aa9..0000000 Binary files a/Graphics/Bitmaps/bt_icons.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/cable_icons.bmp b/Graphics/Bitmaps/cable_icons.bmp deleted file mode 100644 index 3521717..0000000 Binary files a/Graphics/Bitmaps/cable_icons.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/console_icon.bmp b/Graphics/Bitmaps/console_icon.bmp deleted file mode 100644 index fd3a015..0000000 Binary files a/Graphics/Bitmaps/console_icon.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/default_fb.bmp b/Graphics/Bitmaps/default_fb.bmp deleted file mode 100644 index f2b48f0..0000000 Binary files a/Graphics/Bitmaps/default_fb.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/default_fb_alt.bmp b/Graphics/Bitmaps/default_fb_alt.bmp deleted file mode 100644 index fb9d03d..0000000 Binary files a/Graphics/Bitmaps/default_fb_alt.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/default_fb_lc.bmp b/Graphics/Bitmaps/default_fb_lc.bmp deleted file mode 100644 index f6d4442..0000000 Binary files a/Graphics/Bitmaps/default_fb_lc.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/frame.bmp b/Graphics/Bitmaps/frame.bmp deleted file mode 100644 index d9d7ffc..0000000 Binary files a/Graphics/Bitmaps/frame.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/hourglass_high.png b/Graphics/Bitmaps/hourglass_high.png deleted file mode 100644 index a149af7..0000000 Binary files a/Graphics/Bitmaps/hourglass_high.png and /dev/null differ diff --git a/Graphics/Bitmaps/hourglass_low.png b/Graphics/Bitmaps/hourglass_low.png deleted file mode 100644 index ec199ec..0000000 Binary files a/Graphics/Bitmaps/hourglass_low.png and /dev/null differ diff --git a/Graphics/Bitmaps/numbers_upheaval.bmp b/Graphics/Bitmaps/numbers_upheaval.bmp deleted file mode 100644 index d50e1fb..0000000 Binary files a/Graphics/Bitmaps/numbers_upheaval.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/plug.bmp b/Graphics/Bitmaps/plug.bmp deleted file mode 100644 index 1258b5a..0000000 Binary files a/Graphics/Bitmaps/plug.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/rf_icons.bmp b/Graphics/Bitmaps/rf_icons.bmp deleted file mode 100644 index 7913a96..0000000 Binary files a/Graphics/Bitmaps/rf_icons.bmp and /dev/null differ diff --git a/Graphics/Bitmaps/sideband_fb.bmp b/Graphics/Bitmaps/sideband_fb.bmp deleted file mode 100644 index 24f12c5..0000000 Binary files a/Graphics/Bitmaps/sideband_fb.bmp and /dev/null differ diff --git a/Graphics/Design/Bluetooth.kra b/Graphics/Design/Bluetooth.kra deleted file mode 100644 index 241f24e..0000000 Binary files a/Graphics/Design/Bluetooth.kra and /dev/null differ diff --git a/Graphics/Design/Text.xcf b/Graphics/Design/Text.xcf deleted file mode 100644 index 6686b09..0000000 Binary files a/Graphics/Design/Text.xcf and /dev/null differ diff --git a/Graphics/Design/banners.kra b/Graphics/Design/banners.kra deleted file mode 100644 index 230d6ab..0000000 Binary files a/Graphics/Design/banners.kra and /dev/null differ diff --git a/Graphics/Design/cable_icons.kra b/Graphics/Design/cable_icons.kra deleted file mode 100644 index a7f45de..0000000 Binary files a/Graphics/Design/cable_icons.kra and /dev/null differ diff --git a/Graphics/Design/console_icon.kra b/Graphics/Design/console_icon.kra deleted file mode 100644 index bdbf69f..0000000 Binary files a/Graphics/Design/console_icon.kra and /dev/null differ diff --git a/Graphics/Design/cs.kra b/Graphics/Design/cs.kra deleted file mode 100644 index e105cda..0000000 Binary files a/Graphics/Design/cs.kra and /dev/null differ diff --git a/Graphics/Design/default_fb.kra b/Graphics/Design/default_fb.kra deleted file mode 100644 index ef8d030..0000000 Binary files a/Graphics/Design/default_fb.kra and /dev/null differ diff --git a/Graphics/Design/default_fb_alt.kra b/Graphics/Design/default_fb_alt.kra deleted file mode 100644 index 4053839..0000000 Binary files a/Graphics/Design/default_fb_alt.kra and /dev/null differ diff --git a/Graphics/Design/firware_update_icon.kra b/Graphics/Design/firware_update_icon.kra deleted file mode 100644 index b5ac329..0000000 Binary files a/Graphics/Design/firware_update_icon.kra and /dev/null differ diff --git a/Graphics/Design/frame.kra b/Graphics/Design/frame.kra deleted file mode 100644 index 5135fce..0000000 Binary files a/Graphics/Design/frame.kra and /dev/null differ diff --git a/Graphics/Design/icons.kra b/Graphics/Design/icons.kra deleted file mode 100644 index 6626014..0000000 Binary files a/Graphics/Design/icons.kra and /dev/null differ diff --git a/Graphics/Design/numbers_silkscreen.kra b/Graphics/Design/numbers_silkscreen.kra deleted file mode 100644 index f6910f3..0000000 Binary files a/Graphics/Design/numbers_silkscreen.kra and /dev/null differ diff --git a/Graphics/Design/numbers_upheaval.kra b/Graphics/Design/numbers_upheaval.kra deleted file mode 100644 index 2a6ee1e..0000000 Binary files a/Graphics/Design/numbers_upheaval.kra and /dev/null differ diff --git a/Graphics/Design/plug.kra b/Graphics/Design/plug.kra deleted file mode 100644 index 777be0a..0000000 Binary files a/Graphics/Design/plug.kra and /dev/null differ diff --git a/Graphics/Design/r_icon.kra b/Graphics/Design/r_icon.kra deleted file mode 100644 index de91694..0000000 Binary files a/Graphics/Design/r_icon.kra and /dev/null differ diff --git a/Graphics/Design/rf_icons.kra b/Graphics/Design/rf_icons.kra deleted file mode 100644 index 3157b86..0000000 Binary files a/Graphics/Design/rf_icons.kra and /dev/null differ diff --git a/Graphics/Design/sideband_fb.kra b/Graphics/Design/sideband_fb.kra deleted file mode 100644 index 57c73c6..0000000 Binary files a/Graphics/Design/sideband_fb.kra and /dev/null differ diff --git a/Interfaces.h b/Interfaces.h index 2341851..1d8e6a4 100644 --- a/Interfaces.h +++ b/Interfaces.h @@ -1,6 +1,7 @@ -#define SX1276 0x00 -#define SX1278 0x01 -#define SX1261 0x10 +#define SX127X 0x00 +#define SX1276 0x01 +#define SX1278 0x02 +#define SX126X 0x10 #define SX1262 0x11 -#define SX1268 0x12 -#define SX1280 0x20 +#define SX128X 0x20 +#define SX1280 0x21 diff --git a/src/misc/MD5.cpp b/MD5.cpp similarity index 100% rename from src/misc/MD5.cpp rename to MD5.cpp diff --git a/src/misc/MD5.h b/MD5.h similarity index 100% rename from src/misc/MD5.h rename to MD5.h diff --git a/Makefile b/Makefile index 3a86441..37b74ba 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2024, Mark Qvist +# Copyright (C) 2023, 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,518 +13,364 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# 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 +ESP_IDF_VER = 2.0.17 all: release clean: - -rm -rf ./build - -rm -f ./Release/rnode_firmware* + -rm -r ./build + -rm ./Release/rnode_firmware* -prep: prep-esp32 prep-nrf +prep: prep-avr prep-esp32 prep-samd -prep-index: +prep-avr: arduino-cli core update-index --config-file arduino-cli.yaml + arduino-cli core install arduino:avr --config-file arduino-cli.yaml + arduino-cli core install unsignedio:avr --config-file arduino-cli.yaml prep-esp32: - arduino-cli core install esp32:esp32@$(ARDUINO_ESP_CORE_VER) --config-file arduino-cli.yaml + 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 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 install adafruit:nrf52 --config-file arduino-cli.yaml + arduino-cli core update-index --config-file arduino-cli.yaml arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml - arduino-cli core install Heltec_nRF52:Heltec_nRF52 --config-file arduino-cli.yaml arduino-cli lib install "Crypto" arduino-cli lib install "Adafruit GFX Library" arduino-cli lib install "GxEPD2" - arduino-cli lib install "TinyGPSPlus" - arduino-cli config set library.enable_unsafe_install true - arduino-cli lib install --git-url https://github.com/liamcottle/esp8266-oled-ssd1306#e16cee124fe26490cb14880c679321ad8ac89c95 - 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. + pip install adafruit-nrfutil --upgrade 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 + python Release/esptool/spiffsgen.py 1966080 ./Console/build Release/console_image.bin upload-spiffs: @echo Deploying SPIFFS image... - python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin + python ./Release/esptool/esptool.py --chip esp32 --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 -firmware: $(shell grep ^firmware- Makefile | cut -d: -f1) +firmware: + arduino-cli compile --fqbn unsignedio:avr:rnode -check_bt_buffers: - @./esp32_btbufs.py ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/libraries/BluetoothSerial/src/BluetoothSerial.cpp +firmware-mega2560: + arduino-cli compile --fqbn arduino:avr:mega -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: + 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-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: - arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\"" +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\"" 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\"" + 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\"" -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-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-t3s3_sx1280_pa: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xAC\"" +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-e22_esp32: - arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x45\" \"-DEXTERNAL_LEDS=true\"" +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: 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_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_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_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_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_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: check_bt_buffers - arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" +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_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-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: 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_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_v3: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" + 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\"" -firmware-heltec_w_paper: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\"" +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-xiao_s3: - arduino-cli compile --fqbn esp32:esp32:XIAO_ESP32S3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\"" +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_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-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-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: check_bt_buffers - arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" - -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-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-rak4631: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" + 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\"" -firmware-rak4631_sx1280: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x14\"" +upload: + arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode -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\"" - -firmware-heltec_t114: - arduino-cli compile --log --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\"" - -firmware-heltec_t114_gps: - arduino-cli compile --log --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\" \"-DBOARD_VARIANT=0xCB\"" +upload-mega2560: + arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:avr:mega 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/RNode_Firmware_CE.ino.bin) - @sleep 3 - python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin - -upload-tbeam_sx1262: arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:t-beam @sleep 1 rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.bin) - #@sleep 3 - #python ./Release/esptool/esptool.py --chip esp32 --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 + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32 --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-lora32_v10: - arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 + arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/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 + python ./Release/esptool/esptool.py --chip esp32 --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 upload-lora32_v20: - arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 + arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/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 + python ./Release/esptool/esptool.py --chip esp32 --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 upload-lora32_v21: - arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32 + arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:ttgo-lora32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin + python ./Release/esptool/esptool.py --chip esp32 --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-heltec32_v2: - arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V2 + arduino-cli upload -p /dev/ttyUSB1 --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/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB1 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V2/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 + python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB1 --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-heltec_w_paper upload-heltec32_v3: - arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:heltec_wifi_lora_32_V3 +upload-heltec32_v3: + arduino-cli upload -p /dev/ttyUSB1 --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/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB1 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin) @sleep 3 - 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-xiao_s3: - arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:XIAO_ESP32S3 - @sleep 1 - rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware_CE.ino.bin) - @sleep 3 - python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) --chip esp32-s3 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 8MB 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 --port $(or $(port), /dev/ttyACM0) --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-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 --port $(or $(port), /dev/ttyACM0) --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 + python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB1 --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 + arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/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 + python ./Release/esptool/esptool.py --chip esp32 --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 upload-rnode_ng_21: - arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:ttgo-lora32 + arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:ttgo-lora32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin) @sleep 3 - python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FLAGS) ./Release/console_image.bin + python ./Release/esptool/esptool.py --chip esp32 --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-t3s3: - arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 + @echo + @echo Put board into flashing mode by holding BOOT button while momentarily pressing the RESET button. Hit enter when done. + @read + arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3 + @sleep 2 + python ./Release/esptool/esptool.py --chip esp32s3 --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 @sleep 1 - python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) --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 - @sleep 3 - rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) upload-featheresp32: - arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:featheresp32 + arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:featheresp32 @sleep 1 - rnodeconf $(or $(port), /dev/ttyUSB0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bin) + rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bin) @sleep 3 - python ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_UPLOAD_FLAGS) ./Release/console_image.bin + python ./Release/esptool/esptool.py --chip esp32 --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 -upload-opencom-xl upload-rak4631: - arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn rakwireless:nrf52:WisCoreRAK4631Board +upload-rak4631: + arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board unzip -o build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.zip -d build/rakwireless.nrf52.WisCoreRAK4631Board - rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*') + rnodeconf /dev/ttyACM0 --firmware-hash $$(sha256sum ./build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.bin | grep -o '^\S*') -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 -upload-heltec_t114: - arduino-cli upload -p /dev/ttyACM0 --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 - @sleep 1 - rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0) -upload-techo: - arduino-cli upload -p /dev/ttyACM0 --fqbn adafruit:nrf52:pca10056 - @sleep 6 - rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0) +release: release-all -release: console-site spiffs-image $(shell grep ^release- Makefile | cut -d: -f1) +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-hashes: - python3 ./release_hashes.py > ./Release/release.json + python ./release_hashes.py > ./Release/release.json -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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_tbeam.bin cp build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tbeam.bootloader cp build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_tbeam.partitions 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: 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\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_sx1262.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_tbeam_sx1262.bin cp build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tbeam_sx1262.bootloader cp build/esp32.esp32.t-beam/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_tbeam_sx1262.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v10.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v10.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v10.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v20.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v20.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v20.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v21.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v21.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v10.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v10.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v10.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v20.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v20.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v20.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v21.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v21.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21_tcxo.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21_tcxo.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_lora32v21_tcxo.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_lora32v21_tcxo.partitions 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: 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/$(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_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 $(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_CE.ino.bin build/rnode_firmware_heltec32v3.bin - cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader - cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.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-heltec_w_paper: - arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltecwpaper.boot_app0 - cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltecwpaper.bin - cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltecwpaper.bootloader - cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_heltecwpaper.partitions - zip --junk-paths ./Release/rnode_firmware_heltecwpaper.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltecwpaper.boot_app0 build/rnode_firmware_heltecwpaper.bin build/rnode_firmware_heltecwpaper.bootloader build/rnode_firmware_heltecwpaper.partitions - rm -r build - -release-xiao_s3: - arduino-cli compile --fqbn esp32:esp32:XIAO_ESP32S3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3E\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_xiao_esp32s3.boot_app0 - cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware_CE.ino.bin build/rnode_firmware_xiao_esp32s3.bin - cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_xiao_esp32s3.bootloader - cp build/esp32.esp32.XIAO_ESP32S3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_xiao_esp32s3.partitions - zip --junk-paths ./Release/rnode_firmware_xiao_esp32s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_xiao_esp32s3.boot_app0 build/rnode_firmware_xiao_esp32s3.bin build/rnode_firmware_xiao_esp32s3.bootloader build/rnode_firmware_xiao_esp32s3.partitions - rm -r build - -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 +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\"" + 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/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 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: 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 +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/RNode_Firmware_CE.ino.bin build/rnode_firmware_heltec32v3.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware_CE.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/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 + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_ng20.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_ng20.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.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: 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 +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/RNode_Firmware_CE.ino.bin build/rnode_firmware_ng21.bin cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_ng21.bootloader cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.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-techo: - arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\"" - cp build/adafruit.nrf52.pca10056/RNode_Firmware_CE.ino.hex build/rnode_firmware_techo.hex - adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo.hex Release/rnode_firmware_techo.zip - rm -r build - release-t3s3: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=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_CE.ino.bin build/rnode_firmware_t3s3_sx126x.bin - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx126x.bootloader - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.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 + 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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3.partitions + 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-t3s3_sx127x: - 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\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx127x.boot_app0 - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3_sx127x.bin - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx127x.bootloader - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3_sx127x.partitions - zip --junk-paths ./Release/rnode_firmware_t3s3_sx127x.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx127x.boot_app0 build/rnode_firmware_t3s3_sx127x.bin build/rnode_firmware_t3s3_sx127x.bootloader build/rnode_firmware_t3s3_sx127x.partitions - rm -r build - -release-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=0xAC\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0 - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin build/rnode_firmware_t3s3_sx1280_pa.bin - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_t3s3_sx1280_pa.partitions - zip --junk-paths ./Release/rnode_firmware_t3s3_sx1280_pa.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0 build/rnode_firmware_t3s3_sx1280_pa.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader build/rnode_firmware_t3s3_sx1280_pa.partitions - rm -r build - -release-e22_esp32: - arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x45\"" - cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_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-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_CE.ino.bin build/rnode_firmware_tdeck.bin - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tdeck.bootloader - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.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_CE.ino.bin build/rnode_firmware_tbeam_supreme.bin - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_tbeam_supreme.bootloader - cp build/esp32.esp32.esp32s3/RNode_Firmware_CE.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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_featheresp32.bin cp build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_featheresp32.bootloader cp build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_featheresp32.partitions 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: 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/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_generic.boot_app0 +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\"" + 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/RNode_Firmware_CE.ino.bin build/rnode_firmware_esp32_generic.bin cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_esp32_generic.bootloader cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.partitions.bin build/rnode_firmware_esp32_generic.partitions zip --junk-paths ./Release/rnode_firmware_esp32_generic.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_esp32_generic.boot_app0 build/rnode_firmware_esp32_generic.bin build/rnode_firmware_esp32_generic.bootloader build/rnode_firmware_esp32_generic.partitions rm -r build +release-mega2560: + arduino-cli compile --fqbn arduino:avr:mega -e --build-property "compiler.cpp.extra_flags=\"-DMODEM=0x01\"" + cp build/arduino.avr.mega/RNode_Firmware_CE.ino.hex Release/rnode_firmware_m2560.hex + rm -r build + release-rak4631: - arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x12\"" + 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\"" 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 - rm -r build - -release-rak4631_sx1280: - 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 - rm -r build - -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 - rm -r build - -release-heltec_t114: - arduino-cli compile --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\"" - cp build/Heltec_nRF52.Heltec_nRF52.HT-n5262/RNode_Firmware_CE.ino.hex build/rnode_firmware_heltec_t114.hex - adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_heltec_t114.hex Release/rnode_firmware_heltec_t114.zip - rm -r build diff --git a/Power.h b/Power.h index 8856316..395f629 100644 --- a/Power.h +++ b/Power.h @@ -1,28 +1,9 @@ -// 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 +#if BOARD_MODEL == BOARD_TBEAM #include XPowersLibInterface* PMU = NULL; #ifndef PMU_WIRE_PORT - #if BOARD_MODEL == BOARD_TBEAM_S_V1 - #define PMU_WIRE_PORT Wire1 - #else - #define PMU_WIRE_PORT Wire - #endif + #define PMU_WIRE_PORT Wire #endif #define BAT_V_MIN 3.15 @@ -47,6 +28,8 @@ 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 @@ -61,109 +44,26 @@ 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_RAK4631 || 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_T3S3 - #define BAT_V_MIN 3.15 - #define BAT_V_MAX 4.217 - #define BAT_V_CHG 4.48 - #define BAT_V_FLOAT 4.33 - #define BAT_SAMPLES 5 - const uint8_t pin_vbat = 1; - 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_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; -#elif BOARD_MODEL == BOARD_HELTEC_T114 - #define BAT_V_MIN 3.15 - #define BAT_V_MAX 4.165 - #define BAT_V_CHG 4.48 - #define BAT_V_FLOAT 4.33 - #define BAT_SAMPLES 7 - const uint8_t pin_vbat = 4; - const uint8_t pin_ctrl = 6; - 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_TECHO - #define BAT_V_MIN 3.15 - #define BAT_V_MAX 4.16 - #define BAT_V_CHG 4.48 - #define BAT_V_FLOAT 4.33 - #define BAT_SAMPLES 7 - 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_RAK4631 +#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; #endif uint32_t last_pmu_update = 0; @@ -174,23 +74,10 @@ 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 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 battery_installed = true; battery_indeterminate = true; - - #if BOARD_MODEL == BOARD_HELTEC32_V3 - float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041; - #elif BOARD_MODEL == BOARD_T3S3 - float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*6.7828; - #elif BOARD_MODEL == BOARD_HELTEC_T114 - float battery_measurement = (float)(analogRead(pin_vbat)) * 0.017165; - #elif BOARD_MODEL == BOARD_TECHO - float battery_measurement = (float)(analogRead(pin_vbat)) * 0.007067; - #else - float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*7.26; - #endif - - bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement; + bat_v_samples[bat_samples_count%BAT_SAMPLES] = (float)(analogRead(pin_vbat)) / 4095*2*3.3*1.1; bat_p_samples[bat_samples_count%BAT_SAMPLES] = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0; bat_samples_count++; @@ -213,61 +100,41 @@ 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) { - 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); - } - } + bat_voltage_dropping = true; } else { - 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_voltage_dropping = false; } 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 (battery_percent < 100.0) { + #if BOARD_MODEL == BOARD_RNODE_NG_21 battery_state = BATTERY_STATE_CHARGING; - } else { - battery_state = BATTERY_STATE_CHARGED; - } + #else + battery_state = BATTERY_STATE_DISCHARGING; + #endif } - #if MCU_VARIANT == MCU_NRF52 - if (bt_state != BT_STATE_OFF) { blebas.write(battery_percent); } - #endif + // 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%%.", battery_percent); } - // else { 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"); + // if (bat_voltage_dropping) { + // SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.\n", battery_percent); + // } else { + // SerialBT.print(" Voltage is not dropping.\n"); + // } // } } - #elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 + #elif BOARD_MODEL == BOARD_TBEAM if (PMU) { float discharge_current = 0; float charge_current = 0; @@ -305,7 +172,7 @@ void measure_battery() { } } } else { - battery_state = BATTERY_STATE_UNKNOWN; + battery_state = BATTERY_STATE_DISCHARGING; battery_percent = 0.0; battery_voltage = 0.0; } @@ -347,7 +214,7 @@ void measure_battery() { battery_ready = false; } - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL + #elif BOARD_MODEL == BOARD_RAK4631 battery_installed = true; battery_indeterminate = false; @@ -406,16 +273,6 @@ void measure_battery() { if (battery_percent >= 98) { battery_state = BATTERY_STATE_CHARGED; } - - #if HAS_BLE - if ((bt_state == BT_STATE_ON) || bt_state == BT_STATE_CONNECTED) { - if (battery_state != BATTERY_STATE_CHARGING) { - blebas.write(battery_percent); - } else { - blebas.write(100); - } - } - #endif #endif if (battery_ready) { @@ -434,33 +291,31 @@ void update_pmu() { } bool init_pmu() { - #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 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_HELTEC_T114 - pinMode(pin_ctrl,OUTPUT); - digitalWrite(pin_ctrl, HIGH); - 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"); } } @@ -566,7 +421,7 @@ bool init_pmu() { PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); return true; - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL + #elif BOARD_MODEL == BOARD_RAK4631 // board doesn't have PMU but we can measure batt voltage // prep ADC for reading battery level @@ -581,86 +436,6 @@ 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 5688c70..8b3b1f7 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,15 @@ The RNode system is primarily software, which *transforms* different kinds of av ## Latest Release -The latest release, installable through `rnodeconf`, is version `1.75`. This release brings the following changes: +The latest release, installable through `rnodeconf`, is version `1.72`. This release brings the following changes: -- Set correct flash size for Xiao esp32s3 by @easytarget in #72 -- Add NeoPixel support for LILYGO LoRa32 by @0x62 in #71 -- Fixed a bug causing infinite reception detection, making the RNode unusable -- Updated WisBlock SX1280 module PA curve -- Fixed builds for the LilyGO T-Echo -- Incorporated changes from upstream v1.82 +- Added support for flashing T3S3 boards +- Added deep sleep support on T3S3 +- Various quality updates for nRF / RAK4631 +- Fixed a bug with antenna switch utilisation on RAK4631 +- Updated console image to include latest packages -You must have at least version `2.1.3` of `rnodeconf` installed to update your RNode Firmware install to version `1.75`. **YOU MUST USE AN RNS VERSION HIGHER THAN `0.9.3` IF YOU ARE USING A MULTI-INTERFACE RNODE!** +You must have at least version `2.1.3` of `rnodeconf` installed to update the RNode Firmware to version `1.72`. Get it by updating the `rns` package to at least version `0.6.4`. ## Supported products and boards @@ -31,29 +30,21 @@ You must have at least version `2.1.3` of `rnodeconf` installed to update your R | Name | Manufacturer | Link | Transceiver | MCU | Description | | :---: | :---: | :---: | :---: | :---: | :---: | | Handheld v2.x RNodes | [Mark Qvist](https://unsigned.io) | [Buy here](https://unsigned.io/shop/product/handheld-rnode) | SX1276 | ESP32 | -| openCom XL | [Liberated Embedded Systems](https://liberatedsystems.co.uk) | [Buy here](https://store.liberatedsystems.co.uk/product/opencom-xl/) | SX1262 & SX1280 | nRF52 | Supports utilisation of both modems at once | ### Homebrew devices | Board name | Link | Transceiver | MCU | Description | | :--- | :---: | :---: | :---: | :---: | | RAK4631 | [Buy here](https://store.rakwireless.com/products/rak4631-lpwan-node?m=5&h=wisblock-core) | SX1262 | nRF52 | | LilyGO T-BEAM v1.1 | [Buy here](https://www.lilygo.cc/products/t-beam-v1-1-esp32-lora-module) | SX1276/8 or SX1262 | ESP32 | -| LilyGO T-Beam Supreme | [Buy here](https://lilygo.cc/products/t-beam-supreme) | SX1262 | ESP32-S3 | | LilyGO LoRa32 v1.0 | [Buy here](https://www.lilygo.cc/products/lora32-v1-0) | SX1276/8 | ESP32 | | LilyGO LoRa32 v2.0 | No link | SX1276/8 | ESP32 | Discontinued? | | LilyGO LoRa32 v2.1 | [Buy here](https://www.lilygo.cc/products/lora3) | SX1276/8 | ESP32 | With and without TCXO | | Heltec LoRa32 v2 | No link | SX1276/8 | ESP32 | Discontinued? | | Heltec LoRa32 v3 | [Buy here](https://heltec.org/project/wifi-lora-32-v3/) | SX1262 | ESP32 | -| LilyGo T3S3 v1.0 | [Buy here](https://lilygo.cc/products/t3s3-v1-0) | SX1262 or SX1276 or SX1280 | ESP32-S3 | -| LilyGo T-Echo | [Buy here](https://lilygo.cc/products/t-echo-lilygo) | SX1262 | nRF52 | -| Heltec T114 | [Buy here](https://heltec.org/project/mesh-node-t114/) | SX1262 | nRF52 | | Homebrew ESP32 boards | | Any supported | ESP32 | This can be any board with an Adafruit Feather (or generic) ESP32 chip | It's easy to create your own RNodes from one of the supported development boards and devices. If a device or board you want to use is not yet supported, you are welcome to [join the effort](Documentation/CONTRIBUTING.md) and help create a board definition and pin mapping for it! - - - ## Supported Transceiver Modules @@ -63,7 +54,7 @@ The RNode Firmware supports all transceiver modules based on the following chips * Semtech SX1278 * Semtech SX1280 -These also must have an **SPI interface** and **DIO_0 (sometimes called DIO_1)** pin connected to the MCU directly. +These also must have an **SPI interface** and **DIO_0** pin connected to the MCU directly. ## One Tool, Many Uses @@ -102,6 +93,7 @@ The production of one particular RNode device is not an end, but the potential s This tree fits into the larger biome of Free & Open Communications Systems, which I hope that you - by using communications tools like RNode - will help grow and prosper. + ## Getting Started Fast You can download and flash the firmware to all the supported boards using [rnodeconf](https://github.com/markqvist/Reticulum). All firmware releases are handled and installed directly through the `rnodeconf` utility, which is included in the `rns` package. It can be installed via `pip`: @@ -113,8 +105,6 @@ pip install rns --upgrade rnodeconf --autoinstall ``` -For most of the supported device types, it is also possible to use [Liam Cottle's Web-based RNode Flasher](https://liamcottle.github.io/rnode-flasher/). This option may be easier if you're not familiar with using a command line interface. - For more detailed instruction and in-depth guides, you can have a look at some of these resources: - Create a [basic RNode from readily available development boards](https://unsigned.io/guides/2022_01_25_installing-rnode-firmware-on-supported-devices.html) @@ -142,13 +132,13 @@ You can help support the continued development of open, free and private communi ``` 84FpY1QbxHcgdseePYNmhTHcrgMX4nFfBYtz2GKYToqHVVhJp8Eaw1Z1EedRnKD19b3B8NiLCGVxzKV17UMmmeEsCrPyA5w ``` -- Bitcoin - ``` - bc1p4a6axuvl7n9hpapfj8sv5reqj8kz6uxa67d5en70vzrttj0fmcusgxsfk5 - ``` - Ethereum ``` - 0xae89F3B94fC4AD6563F0864a55F9a697a90261ff + 0xFDabC71AC4c0C78C95aDDDe3B4FA19d6273c5E73 + ``` +- Bitcoin + ``` + 35G9uWVzrpJJibzUwpNUQGQNFzLirhrYAH ``` - Ko-Fi: https://ko-fi.com/markqvist @@ -163,7 +153,7 @@ The source code includes an SX1276 driver that is released under MIT License, an You can obtain the source code from [my business Git instance](https://git.liberatedsystems.co.uk/jacob.eva/RNode_Firmware_CE) or [GitHub](https://github.com/liberatedsystems/RNode_Firmware_CE). -Every RNode which supports the console functionality also includes an internal copy of it's own firmware source code, that can be downloaded through the [RNode Bootstrap Console](https://unsigned.io/rnode_bootstrap_console), by putting the RNode into Console Mode (which can be activated by holding the user button for 10 seconds and releasing it). +Every RNode which supports the console functionality also includes an internal copy of it's own firmware source code, that can be downloaded through the [RNode Bootstrap Console](https://unsigned.io/rnode_bootstrap_console), by putting the RNode into Console Mode (which can be activated by pressing the reset button two times within two seconds). The RNode Ecosystem is free and non-proprietary, and actively seeks to distribute it's ownership and control. If you want to build RNodes for commercial purposes, including selling them, you must do so adhering to the Open Source licenses that the various parts of the RNode project is released under, and under your own responsibility. diff --git a/RNode_Firmware_CE.ino b/RNode_Firmware_CE.ino index d02da4c..5686ac7 100644 --- a/RNode_Firmware_CE.ino +++ b/RNode_Firmware_CE.ino @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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 @@ -17,49 +17,10 @@ #include #include "Utilities.h" -#if MCU_VARIANT == MCU_NRF52 - #if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL - #define INTERFACE_SPI - // Required because on RAK4631, non-default SPI pins must be initialised when class is declared. - SPIClass interface_spi[1] = { - // SX1262 - SPIClass( - NRF_SPIM2, - interface_pins[0][3], - interface_pins[0][1], - interface_pins[0][2] - ) - }; - #elif BOARD_MODEL == BOARD_TECHO - #define INTERFACE_SPI - SPIClass interface_spi[1] = { - // SX1262 - SPIClass( - NRF_SPIM3, - interface_pins[0][3], - interface_pins[0][1], - interface_pins[0][2] - ) - }; - #elif BOARD_MODEL == BOARD_HELTEC_T114 - #define INTERFACE_SPI - SPIClass interface_spi[1] = { - // SX1262 - SPIClass( - NRF_SPIM1, - interface_pins[0][3], - interface_pins[0][1], - interface_pins[0][2] - ) - }; - #endif -#endif - -#ifndef INTERFACE_SPI -// INTERFACE_SPI is only required on NRF52 platforms, as the SPI pins are set in the class constructor and not by a setter method. -// Even if custom SPI interfaces are not needed, the array must exist to prevent compilation errors. -#define INTERFACE_SPI -SPIClass interface_spi[1]; +#if BOARD_MODEL == BOARD_HELTEC32_V3 +// Default stack size for loop function on Heltec32 V3 is not large enough, +// must be increased to 11kb to prevent crashes. +SET_LOOP_TASK_STACK_SIZE(11 * 1024); // 11KB #endif FIFOBuffer serialFIFO; @@ -78,9 +39,6 @@ volatile uint16_t queued_bytes[INTERFACE_COUNT] = {0}; volatile uint16_t queue_cursor[INTERFACE_COUNT] = {0}; volatile uint16_t current_packet_start[INTERFACE_COUNT] = {0}; volatile bool serial_buffering = false; - -extern void setup_interfaces(); // from /src/misc/ModemISR.h - #if HAS_BLUETOOTH || HAS_BLE == true bool bt_init_ran = false; #endif @@ -89,18 +47,13 @@ extern void setup_interfaces(); // from /src/misc/ModemISR.h #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]; +bool packet_ready = false; + +volatile bool process_packet = false; +volatile uint8_t packet_interface = 0; + uint8_t *packet_queue[INTERFACE_COUNT]; void setup() { @@ -108,60 +61,23 @@ void setup() { boot_seq(); EEPROM.begin(EEPROM_SIZE); Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); + #endif - #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 - - #elif MCU_VARIANT == MCU_NRF52 - #if BOARD_MODEL == BOARD_TECHO - delay(200); - pinMode(PIN_VEXT_EN, OUTPUT); - digitalWrite(PIN_VEXT_EN, HIGH); - pinMode(pin_btn_usr1, INPUT_PULLUP); - pinMode(pin_btn_touch, INPUT_PULLUP); - pinMode(PIN_LED_RED, OUTPUT); - pinMode(PIN_LED_GREEN, OUTPUT); - pinMode(PIN_LED_BLUE, OUTPUT); - delay(200); - #elif BOARD_MODEL == BOARD_HELTEC_T114 - delay(200); - pinMode(PIN_VEXT_EN, OUTPUT); - digitalWrite(PIN_VEXT_EN, HIGH); - delay(100); - #endif - - - if (!eeprom_begin()) { Serial.write("EEPROM initialisation failed.\r\n"); } + #if MCU_VARIANT == MCU_NRF52 + if (!eeprom_begin()) { + Serial.write("EEPROM initialisation failed.\r\n"); + } #endif // Seed the PRNG for CSMA R-value selection - #if MCU_VARIANT == MCU_ESP32 + # if MCU_VARIANT == MCU_ESP32 // On ESP32, get the seed value from the // hardware RNG - unsigned long seed_val = (unsigned long)esp_random(); - #elif MCU_VARIANT == MCU_NRF52 - // On nRF, get the seed value from the - // hardware RNG - unsigned long seed_val = get_rng_seed(); + int seed_val = (int)esp_random(); #else // Otherwise, get a pseudo-random seed // value from an unconnected analog pin - // - // CAUTION! If you are implementing the - // firmware on a platform that does not - // have a hardware RNG, you MUST take - // care to get a seed value with enough - // entropy at each device reset! - unsigned long seed_val = analogRead(0); + int seed_val = analogRead(0); #endif randomSeed(seed_val); @@ -171,17 +87,9 @@ void setup() { Serial.begin(serial_baudrate); - #if HAS_NP - led_init(); - #endif - - #if MCU_VARIANT == MCU_NRF52 && HAS_NP == true - boot_seq(); - #endif - - #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_OPENCOM_XL + #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 // Some boards need to wait until the hardware UART is set up before booting - // the full firmware. In the case of the RAK4631/TECHO, the line below will wait + // the full firmware. In the case of the RAK4631, the line below will wait // until a serial connection is actually established with a master. Thus, it // is disabled on this platform. while (!Serial); @@ -211,45 +119,28 @@ 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)); - memset(read_len, 0, sizeof(read_len)); - - setup_interfaces(); - - 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); fifo16_init(&packet_lengths[i], packet_lengths_buf, CONFIG_QUEUE_MAX_LENGTH); - packet_queue[i] = (uint8_t*)malloc(getQueueSize(i)+1); + packet_queue[i] = (uint8_t*)malloc(getQueueSize(i)); } - memset(packet_rdy_interfaces_buf, 0, sizeof(packet_rdy_interfaces_buf)); - - fifo_init(&packet_rdy_interfaces, packet_rdy_interfaces_buf, MAX_INTERFACES); - - #if HAS_GPS - // init GPS - gps_s.begin(GPS_BAUD_RATE); - #endif - - // 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]) { + case SX126X: case SX1262: { sx126x* obj; // if default spi enabled if (interface_cfg[i][0]) { - obj = new sx126x(i, &SPI, interface_cfg[i][1], + obj = new sx126x(i, SPI, interface_cfg[i][1], interface_cfg[i][2], interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]); } else { - obj = new sx126x(i, &interface_spi[i], interface_cfg[i][1], + obj = new sx126x(i, interface_spi[i], interface_cfg[i][1], interface_cfg[i][2], interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], interface_pins[i][4], interface_pins[i][8]); @@ -259,18 +150,19 @@ void setup() { break; } + case SX127X: case SX1276: case SX1278: { sx127x* obj; // if default spi enabled if (interface_cfg[i][0]) { - obj = new sx127x(i, &SPI, interface_pins[i][0], + obj = new sx127x(i, SPI, interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], interface_pins[i][4]); } else { - obj = new sx127x(i, &interface_spi[i], interface_pins[i][0], + obj = new sx127x(i, interface_spi[i], interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], interface_pins[i][4]); } @@ -279,21 +171,22 @@ void setup() { break; } + case SX128X: case SX1280: { sx128x* obj; // if default spi enabled - if (interface_cfg[i][0]) { - obj = new sx128x(i, &SPI, interface_cfg[i][1], - interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], - interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], - interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); + if (interface_cfg[i][0]) { + obj = new sx128x(i, SPI, interface_cfg[i][1], + interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], + interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], + interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); } else { - obj = new sx128x(i, &interface_spi[i], interface_cfg[i][1], - interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], - interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], - interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); + obj = new sx128x(i, interface_spi[i], interface_cfg[i][1], + interface_pins[i][0], interface_pins[i][1], interface_pins[i][2], + interface_pins[i][3], interface_pins[i][6], interface_pins[i][5], + interface_pins[i][4], interface_pins[i][8], interface_pins[i][7]); } interface_obj[i] = obj; interface_obj_sorted[i] = obj; @@ -305,20 +198,16 @@ void setup() { } } - #if BOARD_MODEL == BOARD_T3S3 && BOARD_VARIANT == MODEL_AC - // Fix weird radio not found bug on T3S3 SX1280 - delay(300); - interface_obj[0]->reset(); - delay(100); - #endif - // Check installed transceiver chip(s) and probe boot parameters. If any of // the configured modems cannot be initialised, do not boot for (int i = 0; i < INTERFACE_COUNT; i++) { switch (interfaces[i]) { + case SX126X: case SX1262: + case SX127X: case SX1276: case SX1278: + case SX128X: case SX1280: selected_radio = interface_obj[i]; break; @@ -329,24 +218,20 @@ void setup() { } if (selected_radio->preInit()) { modems_installed = true; - #if HAS_INPUT - // Skip quick-reset console activation - #else - uint32_t lfr = selected_radio->getFrequency(); - if (lfr == 0) { - // Normal boot - } else if (lfr == M_FRQ_R) { - // Quick reboot - #if HAS_CONSOLE - if (rtc_get_reset_reason(0) == POWERON_RESET) { - console_active = true; - } - #endif - } else { - // Unknown boot + uint32_t lfr = selected_radio->getFrequency(); + if (lfr == 0) { + // Normal boot + } else if (lfr == M_FRQ_R) { + // Quick reboot + #if HAS_CONSOLE + if (rtc_get_reset_reason(0) == POWERON_RESET) { + console_active = true; } - selected_radio->setFrequency(M_FRQ_S); - #endif + #endif + } else { + // Unknown boot + } + selected_radio->setFrequency(M_FRQ_S); } else { modems_installed = false; } @@ -362,25 +247,15 @@ void setup() { if (eeprom_read(eeprom_addr(ADDR_CONF_DSET)) != CONF_OK_BYTE) { #endif eeprom_update(eeprom_addr(ADDR_CONF_DSET), CONF_OK_BYTE); - #if BOARD_MODEL == BOARD_TECHO - eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0x03); - #else - eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF); - #endif + eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF); } - #if BOARD_MODEL == BOARD_OPENCOM_XL && (DISPLAY == EINK_BW || DISPLAY == EINK_3C) - // On this board it isn't possible to run the main loop whilst the - // display is updating as the SPI pins are shared between the display and - // secondary modem. Because running the main loop causes a lockup, we - // just run the serial poll loop instead. - display_add_callback(process_serial); - #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C - display_add_callback(process_serial); // todo: get this working with work_while_waiting again + #if DISPLAY == EINK_BW || DISPLAY == EINK_3C + // Poll and process incoming serial commands whilst e-ink display is + // refreshing to make device still seem responsive + display_add_callback(process_serial); #endif - - display_unblank(); disp_ready = display_init(); - if (disp_ready) update_display(); + update_display(); #endif #if HAS_PMU == true @@ -402,25 +277,6 @@ void setup() { kiss_indicate_reset(); } - for (int i = 0; i < INTERFACE_COUNT; i++) { - selected_radio = interface_obj[i]; - if (interfaces[i] == SX1280) { - selected_radio->setAvdInterference(false); - } - if (selected_radio->getAvdInterference()) { - #if HAS_EEPROM - uint8_t ia_conf = EEPROM.read(eeprom_addr(ADDR_CONF_DIA)); - if (ia_conf == 0x00) { selected_radio->setAvdInterference(true); } - else { selected_radio->setAvdInterference(false); } - #elif MCU_VARIANT == MCU_NRF52 - uint8_t ia_conf = eeprom_read(eeprom_addr(ADDR_CONF_DIA)); - if (ia_conf == 0x00) { selected_radio->setAvdInterference(true); } - else { selected_radio->setAvdInterference(false); } - #endif - } - } - - // Validate board health, EEPROM and config validate_status(); } @@ -434,128 +290,70 @@ void lora_receive(RadioInterface* radio) { } inline void kiss_write_packet(int index) { - // Print index of interface the packet came from - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(index); - serial_write(FEND); + // We need to convert the interface index to the command byte representation + uint8_t cmd_byte = getInterfaceCommandByte(index); serial_write(FEND); - serial_write(CMD_DATA); - for (uint16_t i = 0; i < read_len[index]; i++) { - #if MCU_VARIANT == MCU_NRF52 - portENTER_CRITICAL(); - uint8_t byte = pbuf[i]; - portEXIT_CRITICAL(); - #else - uint8_t byte = pbuf[i]; - #endif + // Add index of interface the packet came from + serial_write(cmd_byte); + for (uint16_t i = 0; i < read_len; i++) { + uint8_t byte = pbuf[i]; if (byte == FEND) { serial_write(FESC); byte = TFEND; } if (byte == FESC) { serial_write(FESC); byte = TFESC; } serial_write(byte); } - serial_write(FEND); - read_len[index] = 0; - - #if MCU_VARIANT == MCU_ESP32 && HAS_BLE - bt_flush(); - #endif + read_len = 0; + packet_ready = false; } inline void getPacketData(RadioInterface* radio, uint16_t len) { - uint8_t index = radio->getIndex(); - #if MCU_VARIANT != MCU_NRF52 - while (len-- && read_len[index] < MTU) { - pbuf[read_len[index]++] = radio->read(); - } - #else - BaseType_t int_mask = taskENTER_CRITICAL_FROM_ISR(); - while (len-- && read_len[index] < MTU) { - pbuf[read_len[index]++] = radio->read(); - } - taskEXIT_CRITICAL_FROM_ISR(int_mask); - #endif -} - -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[index]); - 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[index]; - memcpy(modem_packet->data, pbuf, read_len[index]); - if (!modem_packet_queue || xQueueSendFromISR(modem_packet_queue, &modem_packet, NULL) != pdPASS) { - free(modem_packet); - return false; - } - return true; + while (len-- && read_len < MTU) { + pbuf[read_len++] = radio->read(); + } } 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) { + selected_radio = interface_obj[index]; + // The standard operating mode allows large // packets with a payload up to 500 bytes, // by combining two raw LoRa packets. // We read the 1-byte header and extract // packet sequence number and split flags - uint8_t header = selected_radio->read(); packet_size--; uint8_t sequence = packetSequence(header); + bool ready = false; - if (isSplitPacket(header) && seq[index] == SEQ_UNSET) { + if (isSplitPacket(header) && seq == SEQ_UNSET) { // This is the first part of a split // packet, so we set the seq variable // and add the data to the buffer - #if MCU_VARIANT == MCU_NRF52 - int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len[index] = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); - #else - read_len[index] = 0; - #endif - - seq[index] = sequence; + read_len = 0; + seq = sequence; getPacketData(selected_radio, packet_size); - } else if (isSplitPacket(header) && seq[index] == sequence) { + } else if (isSplitPacket(header) && seq == 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[index] = SEQ_UNSET; + seq = SEQ_UNSET; ready = true; - } else if (isSplitPacket(header) && seq[index] != sequence) { + } else if (isSplitPacket(header) && seq != 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. - #if MCU_VARIANT == MCU_NRF52 - int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len[index] = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); - #else - read_len[index] = 0; - #endif - seq[index] = sequence; + read_len = 0; + seq = sequence; getPacketData(selected_radio, packet_size); @@ -564,41 +362,28 @@ void ISR_VECT receive_callback(uint8_t index, int packet_size) { // just read it and set the ready // flag to true. - if (seq[index] != SEQ_UNSET) { + if (seq != SEQ_UNSET) { // If we already had part of a split // packet in the buffer, we clear it. - #if MCU_VARIANT == MCU_NRF52 - int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len[index] = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); - #else - read_len[index] = 0; - #endif - seq[index] = SEQ_UNSET; + read_len = 0; + seq = SEQ_UNSET; } getPacketData(selected_radio, packet_size); - ready = true; } + + if (ready) { + packet_ready = true; + } } else { // In promiscuous mode, raw packets are // output directly to the host - read_len[index] = 0; + read_len = 0; getPacketData(selected_radio, packet_size); - - ready = true; + packet_ready = true; } - - #if MCU_VARIANT == MCU_NRF52 - // Temporary fix for permanent preamble detected bug - // TODO: figure out how to prevent the timing issue which causes the IRQ to never be cleared - interface_obj[0]->getPacketValidity(); - #endif - - if (ready) { - queue_packet(selected_radio, index); - } - last_rx = millis(); } @@ -606,57 +391,51 @@ bool startRadio(RadioInterface* radio) { update_radio_lock(radio); if (modems_installed && !console_active) { - if (!radio->getRadioOnline()) { - if (!radio->getRadioLock() && hw_ready) { - if (!radio->begin()) { - // The radio could not be started. - // Indicate this failure over both the - // serial port and with the onboard LEDs - kiss_indicate_error(ERROR_INITRADIO); - led_indicate_error(0); - return false; - } else { - radio->enableCrc(); - - radio->onReceive(receive_callback); - - radio->updateBitrate(); - sort_interfaces(); - kiss_indicate_phy_stats(radio); - - lora_receive(radio); - - // Flash an info pattern to indicate - // that the radio is now on - kiss_indicate_radiostate(radio); - led_indicate_info(3); - return true; - } - - } else { - // Flash a warning pattern to indicate - // that the radio was locked, and thus - // not started - kiss_indicate_radiostate(radio); - led_indicate_warning(3); - return false; - } + if (!radio->getRadioLock() && hw_ready) { + if (!radio->begin()) { + // The radio could not be started. + // Indicate this failure over both the + // serial port and with the onboard LEDs + kiss_indicate_error(ERROR_INITRADIO); + led_indicate_error(0); + return false; } else { - // If radio is already on, we silently - // ignore the request. + radio->enableCrc(); + + radio->onReceive(receive_callback); + + radio->updateBitrate(); + sort_interfaces(); + kiss_indicate_phy_stats(radio); + + lora_receive(radio); + + // Flash an info pattern to indicate + // that the radio is now on kiss_indicate_radiostate(radio); + led_indicate_info(3); return true; } + + } else { + // Flash a warning pattern to indicate + // that the radio was locked, and thus + // not started + kiss_indicate_radiostate(radio); + led_indicate_warning(3); + return false; + } + } else { + // If radio is already on, we silently + // ignore the request. + kiss_indicate_radiostate(radio); + return true; } - return false; } void stopRadio(RadioInterface* radio) { - if (radio->getRadioOnline()) { - radio->end(); - sort_interfaces(); - kiss_indicate_radiostate(radio); - } + radio->end(); + sort_interfaces(); } void update_radio_lock(RadioInterface* radio) { @@ -669,14 +448,14 @@ void update_radio_lock(RadioInterface* radio) { // Check if the queue is full for the selected radio. // Returns true if full, false if not -bool queue_full(RadioInterface* radio) { +bool queueFull(RadioInterface* radio) { return (queue_height[radio->getIndex()] >= (CONFIG_QUEUE_MAX_LENGTH) || queued_bytes[radio->getIndex()] >= (getQueueSize(radio->getIndex()))); } volatile bool queue_flushing = false; // Flushes all packets for the interface -void flush_queue(RadioInterface* radio) { +void flushQueue(RadioInterface* radio) { uint8_t index = radio->getIndex(); if (!queue_flushing) { queue_flushing = true; @@ -702,52 +481,13 @@ void flush_queue(RadioInterface* radio) { lora_receive(radio); led_tx_off(); + radio->setPostTxYieldTimeout(millis()+(lora_post_tx_yield_slots*selected_radio->getCSMASlotMS())); } - queue_flushing = false; queue_height[index] = 0; queued_bytes[index] = 0; - radio->updateAirtime(); - - #if HAS_DISPLAY - display_tx[radio->getIndex()] = true; - #endif -} - -void pop_queue(RadioInterface* radio) { - uint8_t index = radio->getIndex(); - if (!queue_flushing) { - queue_flushing = true; - led_tx_on(); uint16_t processed = 0; - - if (!fifo16_isempty(&packet_starts[index])) { - - uint16_t start = fifo16_pop(&packet_starts[index]); - uint16_t length = fifo16_pop(&packet_lengths[index]); - if (length >= MIN_L && length <= MTU) { - for (uint16_t i = 0; i < length; i++) { - uint16_t pos = (start+i)%getQueueSize(index); - tbuf[i] = packet_queue[index][pos]; - } - - transmit(radio, length); processed++; - } - - queue_height[index] -= processed; - queued_bytes[index] -= length; - } - - lora_receive(radio); led_tx_off(); - } - - radio->updateAirtime(); - + selected_radio->updateAirtime(); queue_flushing = false; - - #if HAS_DISPLAY - display_tx[radio->getIndex()] = true; - #endif - } void transmit(RadioInterface* radio, uint16_t size) { @@ -769,31 +509,15 @@ void transmit(RadioInterface* radio, uint16_t size) { written++; - // Only start a new packet if this is a split packet and it has - // exceeded the length of a single packet - if (written == 255 && isSplitPacket(header)) { - if (!radio->endPacket()) { - kiss_indicate_error(ERROR_MODEM_TIMEOUT); - kiss_indicate_error(ERROR_TXFAILED); - led_indicate_error(5); - hard_reset(); - } - - radio->addAirtime(); + if (written == 255) { + radio->endPacket(); radio->addAirtime(written); radio->beginPacket(); radio->write(header); written = 1; } } - if (!radio->endPacket()) { - kiss_indicate_error(ERROR_MODEM_TIMEOUT); - kiss_indicate_error(ERROR_TXFAILED); - led_indicate_error(5); - hard_reset(); - } - radio->addAirtime(); - + radio->endPacket(); radio->addAirtime(written); } else { // In promiscuous mode, we only send out // plain raw LoRa packets with a maximum @@ -819,7 +543,7 @@ void transmit(RadioInterface* radio, uint16_t size) { written++; } - radio->endPacket(); radio->addAirtime(); + radio->endPacket(); radio->addAirtime(written); } last_tx = millis(); } else { @@ -828,29 +552,41 @@ void transmit(RadioInterface* radio, uint16_t size) { } } -void serial_callback(uint8_t sbyte) { +void serialCallback(uint8_t sbyte) { if (IN_FRAME && sbyte == FEND && - command == CMD_DATA) { + (command == CMD_INT0_DATA + || command == CMD_INT1_DATA + || command == CMD_INT2_DATA + || command == CMD_INT3_DATA + || command == CMD_INT4_DATA + || command == CMD_INT5_DATA + || command == CMD_INT6_DATA + || command == CMD_INT7_DATA + || command == CMD_INT8_DATA + || command == CMD_INT9_DATA + || command == CMD_INT10_DATA + || command == CMD_INT11_DATA)) { IN_FRAME = false; - if (interface < INTERFACE_COUNT) { - if (!fifo16_isfull(&packet_starts[interface]) && (queued_bytes[interface] < (getQueueSize(interface)))) { - uint16_t s = current_packet_start[interface]; - int32_t e = queue_cursor[interface]-1; if (e == -1) e = (getQueueSize(interface))-1; + if (getInterfaceIndex(command) < INTERFACE_COUNT) { + uint8_t index = getInterfaceIndex(command); + if (!fifo16_isfull(&packet_starts[index]) && queued_bytes[index] < (getQueueSize(index))) { + uint16_t s = current_packet_start[index]; + int16_t e = queue_cursor[index]-1; if (e == -1) e = (getQueueSize(index))-1; uint16_t l; if (s != e) { - l = (s < e) ? e - s + 1: (getQueueSize(interface)) - s + e + 1; + l = (s < e) ? e - s + 1: (getQueueSize(index)) - s + e + 1; } else { l = 1; } if (l >= MIN_L) { - queue_height[interface]++; + queue_height[index]++; - fifo16_push(&packet_starts[interface], s); - fifo16_push(&packet_lengths[interface], l); - current_packet_start[interface] = queue_cursor[interface]; + fifo16_push(&packet_starts[index], s); + fifo16_push(&packet_lengths[index], l); + current_packet_start[index] = queue_cursor[index]; } } @@ -864,10 +600,33 @@ void serial_callback(uint8_t sbyte) { // Have a look at the command byte first if (frame_len == 0 && command == CMD_UNKNOWN) { command = sbyte; + if (command == CMD_SEL_INT0 + || command == CMD_SEL_INT1 + || command == CMD_SEL_INT2 + || command == CMD_SEL_INT3 + || command == CMD_SEL_INT4 + || command == CMD_SEL_INT5 + || command == CMD_SEL_INT6 + || command == CMD_SEL_INT7 + || command == CMD_SEL_INT8 + || command == CMD_SEL_INT9 + || command == CMD_SEL_INT10 + || command == CMD_SEL_INT11) { + interface = getInterfaceIndex(command); + } - } else if (command == CMD_SEL_INT) { - interface = sbyte; - } else if (command == CMD_DATA) { + } else if (command == CMD_INT0_DATA + || command == CMD_INT1_DATA + || command == CMD_INT2_DATA + || command == CMD_INT3_DATA + || command == CMD_INT4_DATA + || command == CMD_INT5_DATA + || command == CMD_INT6_DATA + || command == CMD_INT7_DATA + || command == CMD_INT8_DATA + || command == CMD_INT9_DATA + || command == CMD_INT10_DATA + || command == CMD_INT11_DATA) { if (bt_state != BT_STATE_CONNECTED) cable_state = CABLE_STATE_CONNECTED; if (sbyte == FESC) { ESCAPE = true; @@ -878,11 +637,12 @@ void serial_callback(uint8_t sbyte) { ESCAPE = false; } - if (interface < INTERFACE_COUNT) { - if (queue_height[interface] < CONFIG_QUEUE_MAX_LENGTH && queued_bytes[interface] < (getQueueSize(interface))) { - queued_bytes[interface]++; - packet_queue[interface][queue_cursor[interface]++] = sbyte; - if (queue_cursor[interface] == (getQueueSize(interface))) queue_cursor[interface] = 0; + if (getInterfaceIndex(command) < INTERFACE_COUNT) { + uint8_t index = getInterfaceIndex(command); + if (queue_height[index] < CONFIG_QUEUE_MAX_LENGTH && queued_bytes[index] < (getQueueSize(index))) { + queued_bytes[index]++; + packet_queue[index][queue_cursor[index]++] = sbyte; + if (queue_cursor[index] == (getQueueSize(index))) queue_cursor[index] = 0; } } } @@ -903,9 +663,9 @@ void serial_callback(uint8_t sbyte) { } if (frame_len == 4) { - selected_radio = interface_obj[interface]; uint32_t freq = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3]; + selected_radio = interface_obj[interface]; if (freq == 0) { kiss_indicate_frequency(selected_radio); } else { @@ -925,20 +685,20 @@ void serial_callback(uint8_t sbyte) { } if (frame_len < CMD_L) cmdbuf[frame_len++] = sbyte; } - if (frame_len == 4) { - selected_radio = interface_obj[interface]; uint32_t bw = (uint32_t)cmdbuf[0] << 24 | (uint32_t)cmdbuf[1] << 16 | (uint32_t)cmdbuf[2] << 8 | (uint32_t)cmdbuf[3]; + selected_radio = interface_obj[interface]; + if (bw == 0) { kiss_indicate_bandwidth(selected_radio); } else { if (op_mode == MODE_HOST) selected_radio->setSignalBandwidth(bw); selected_radio->updateBitrate(); sort_interfaces(); - kiss_indicate_bandwidth(selected_radio); kiss_indicate_phy_stats(selected_radio); + kiss_indicate_bandwidth(selected_radio); } interface = 0; } @@ -948,7 +708,7 @@ void serial_callback(uint8_t sbyte) { if (sbyte == 0xFF) { kiss_indicate_txpower(selected_radio); } else { - int8_t txp = (int8_t)sbyte; + int txp = sbyte; if (op_mode == MODE_HOST) setTXPower(selected_radio, txp); kiss_indicate_txpower(selected_radio); @@ -967,8 +727,8 @@ void serial_callback(uint8_t sbyte) { if (op_mode == MODE_HOST) selected_radio->setSpreadingFactor(sf); selected_radio->updateBitrate(); sort_interfaces(); - kiss_indicate_spreadingfactor(selected_radio); kiss_indicate_phy_stats(selected_radio); + kiss_indicate_spreadingfactor(selected_radio); } interface = 0; } else if (command == CMD_CR) { @@ -983,8 +743,8 @@ void serial_callback(uint8_t sbyte) { if (op_mode == MODE_HOST) selected_radio->setCodingRate4(cr); selected_radio->updateBitrate(); sort_interfaces(); - kiss_indicate_codingrate(selected_radio); kiss_indicate_phy_stats(selected_radio); + kiss_indicate_codingrate(selected_radio); } interface = 0; } else if (command == CMD_IMPLICIT) { @@ -992,7 +752,6 @@ void serial_callback(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; @@ -1006,11 +765,14 @@ void serial_callback(uint8_t sbyte) { kiss_indicate_radiostate(selected_radio); } else if (sbyte == 0x00) { stopRadio(selected_radio); + kiss_indicate_radiostate(selected_radio); } else if (sbyte == 0x01) { startRadio(selected_radio); + kiss_indicate_radiostate(selected_radio); } interface = 0; } else if (command == CMD_ST_ALOCK) { + selected_radio = interface_obj[interface]; if (sbyte == FESC) { ESCAPE = true; } else { @@ -1023,7 +785,6 @@ void serial_callback(uint8_t sbyte) { } if (frame_len == 2) { - selected_radio = interface_obj[interface]; uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1]; if (at == 0) { @@ -1034,9 +795,10 @@ void serial_callback(uint8_t sbyte) { selected_radio->setSTALock(st_airtime_limit); } kiss_indicate_st_alock(selected_radio); - interface = 0; } + interface = 0; } else if (command == CMD_LT_ALOCK) { + selected_radio = interface_obj[interface]; if (sbyte == FESC) { ESCAPE = true; } else { @@ -1049,7 +811,6 @@ void serial_callback(uint8_t sbyte) { } if (frame_len == 2) { - selected_radio = interface_obj[interface]; uint16_t at = (uint16_t)cmdbuf[0] << 8 | (uint16_t)cmdbuf[1]; if (at == 0) { @@ -1060,14 +821,14 @@ void serial_callback(uint8_t sbyte) { selected_radio->setLTALock(lt_airtime_limit); } kiss_indicate_lt_alock(selected_radio); - interface = 0; } + interface = 0; } else if (command == CMD_STAT_RX) { kiss_indicate_stat_rx(); } else if (command == CMD_STAT_TX) { kiss_indicate_stat_tx(); } else if (command == CMD_STAT_RSSI) { - kiss_indicate_stat_rssi(interface_obj[interface]); + kiss_indicate_stat_rssi(); } else if (command == CMD_RADIO_LOCK) { selected_radio = interface_obj[interface]; update_radio_lock(selected_radio); @@ -1095,7 +856,7 @@ void serial_callback(uint8_t sbyte) { kiss_indicate_promisc(); } else if (command == CMD_READY) { selected_radio = interface_obj[interface]; - if (!queue_full(selected_radio)) { + if (!queueFull(selected_radio)) { kiss_indicate_ready(); } else { kiss_indicate_not_ready(); @@ -1173,8 +934,6 @@ void serial_callback(uint8_t sbyte) { if (sbyte != 0x00) { kiss_indicate_fb(); } - } else if (command == CMD_DISP_READ) { - if (sbyte != 0x00) { kiss_indicate_disp(); } } else if (command == CMD_DEV_HASH) { if (sbyte != 0x00) { kiss_indicate_device_hash(); @@ -1236,19 +995,9 @@ void serial_callback(uint8_t sbyte) { bt_start(); bt_conf_save(true); } else if (sbyte == 0x02) { - if (bt_state == BT_STATE_OFF) { - bt_start(); - bt_conf_save(true); - } - if (bt_state != BT_STATE_CONNECTED) { - bt_enable_pairing(); - } + bt_enable_pairing(); } #endif - } else if (command == CMD_BT_UNPAIR) { - #if HAS_BLE - if (sbyte == 0x01) { bt_debond_all(); } - #endif } else if (command == CMD_DISP_INT) { #if HAS_DISPLAY if (sbyte == FESC) { @@ -1261,7 +1010,6 @@ void serial_callback(uint8_t sbyte) { } display_intensity = sbyte; di_conf_save(display_intensity); - display_unblank(); } #endif @@ -1279,75 +1027,6 @@ void serial_callback(uint8_t sbyte) { da_conf_save(display_addr); } - #endif - } 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_DISP_ROT) { - #if HAS_DISPLAY - if (sbyte == FESC) { - ESCAPE = true; - } else { - if (ESCAPE) { - if (sbyte == TFEND) sbyte = FEND; - if (sbyte == TFESC) sbyte = FESC; - ESCAPE = false; - } - drot_conf_save(sbyte); - display_unblank(); - } - #endif - } else if (command == CMD_DIS_IA) { - if (sbyte == FESC) { - ESCAPE = true; - } else { - if (ESCAPE) { - if (sbyte == TFEND) sbyte = FEND; - if (sbyte == TFESC) sbyte = FESC; - ESCAPE = false; - } - dia_conf_save(sbyte); - } - } else if (command == CMD_DISP_RCND) { - #if HAS_DISPLAY - if (sbyte == FESC) { - ESCAPE = true; - } else { - if (ESCAPE) { - if (sbyte == TFEND) sbyte = FEND; - if (sbyte == TFESC) sbyte = FESC; - ESCAPE = false; - } - if (sbyte > 0x00) recondition_display = true; - } - #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 } } @@ -1357,12 +1036,6 @@ void serial_callback(uint8_t sbyte) { portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED; #endif -bool medium_free(RadioInterface* radio) { - radio->updateModemStatus(); - if (radio->getAvdInterference() && radio->getInterference()) { return false; } - return !radio->getDCD(); -} - void validate_status() { #if MCU_VARIANT == MCU_ESP32 // TODO: Get ESP32 boot flags @@ -1413,14 +1086,14 @@ void validate_status() { if (eeprom_checksum_valid()) { eeprom_ok = true; if (modems_installed) { - if (device_init()) { - hw_ready = true; - } else { - hw_ready = false; - } + if (device_init()) { + hw_ready = true; + } else { + hw_ready = false; + } } else { hw_ready = false; - Serial.write("No radio module found\r\n"); + Serial.write("No valid radio module found\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1430,7 +1103,6 @@ void validate_status() { } } else { hw_ready = false; - Serial.write("Invalid EEPROM checksum\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1440,7 +1112,6 @@ void validate_status() { } } else { hw_ready = false; - Serial.write("Invalid EEPROM configuration\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1450,7 +1121,6 @@ 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; @@ -1471,76 +1141,14 @@ void validate_status() { } } -void tx_queue_handler(RadioInterface* radio) { - if (queue_height[radio->getIndex()] > 0) { - if (radio->getCW() == -1) { - radio->setCW(random(radio->getCWMin(), radio->getCWMax())); - radio->setCWWaitTarget(radio->getCW() * radio->getCSMASlotMS()); - } - - if (radio->getDifsWaitStart() == 0) { // DIFS wait not yet started - if (medium_free(radio)) { radio->setDifsWaitStart(millis()); return; } // Set DIFS wait start time - else { return; } } // Medium not yet free, continue waiting - - else { // We are waiting for DIFS or CW to pass - if (!medium_free(radio)) { radio->setDifsWaitStart(0); radio->setCWWaitStart(0); return; } // Medium became occupied while in DIFS wait, restart waiting when free again - else { // Medium is free, so continue waiting - if (millis() < radio->getDifsWaitStart()+radio->getDifsMS()) { return; } // DIFS has not yet passed, continue waiting - else { // DIFS has passed, and we are now in CW wait - if (radio->getCWWaitStart() == 0) { radio->setCWWaitStart(millis()); return; } // If we haven't started counting CW wait time, do it from now - else { // If we are already counting CW wait time, add it to the counter - radio->addCWWaitPassed(millis()-radio->getCWWaitStart()); radio->setCWWaitStart(millis()); - if (radio->getCWWaitStatus()) { return; } // Contention window wait time has not yet passed, continue waiting - else { // Wait time has passed, flush the queue - if (!radio->getLimitRate()) { flush_queue(radio); } else { pop_queue(radio); } - radio->resetCWWaitPassed(); radio->setCW(-1); radio->setDifsWaitStart(0); } - } - } - } - } - } -} - -void work_while_waiting() { loop(); } - void loop() { - #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) { - uint8_t packet_interface = modem_packet->interface; - read_len[packet_interface] = modem_packet->len; - last_rssi = modem_packet->rssi; - last_snr_raw = modem_packet->snr_raw; - memcpy(&pbuf, modem_packet->data, modem_packet->len); - free(modem_packet); - modem_packet = NULL; - - kiss_indicate_stat_rssi(interface_obj[packet_interface]); - kiss_indicate_stat_snr(interface_obj[packet_interface]); - 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) { - uint8_t packet_interface = modem_packet->interface; - read_len[packet_interface] = modem_packet->len; - last_rssi = modem_packet->rssi; - last_snr_raw = modem_packet->snr_raw; - memcpy(&pbuf, modem_packet->data, modem_packet->len); - free(modem_packet); - modem_packet = NULL; - - kiss_indicate_stat_rssi(interface_obj[packet_interface]); - kiss_indicate_stat_snr(interface_obj[packet_interface]); - kiss_write_packet(packet_interface); - } - #endif + packet_poll(); bool ready = false; for (int i = 0; i < INTERFACE_COUNT; i++) { selected_radio = interface_obj[i]; if (selected_radio->getRadioOnline()) { + selected_radio->checkModemStatus(); ready = true; } } @@ -1548,6 +1156,25 @@ void loop() { // If at least one radio is online then we can continue if (ready) { + if (packet_ready) { + selected_radio = interface_obj[packet_interface]; + #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 + kiss_indicate_stat_rssi(); + kiss_indicate_stat_snr(); + kiss_write_packet(packet_interface); + } + for (int i = 0; i < INTERFACE_COUNT; i++) { selected_radio = interface_obj_sorted[i]; @@ -1555,8 +1182,43 @@ void loop() { // skip this interface continue; } - tx_queue_handler(selected_radio); - selected_radio->checkModemStatus(); + + // 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) { + long check_time = millis(); + if (check_time > selected_radio->getPostTxYieldTimeout()) { + if (selected_radio->getDCDWaiting() && (check_time >= selected_radio->getDCDWaitUntil())) { selected_radio->setDCDWaiting(false); } + if (!selected_radio->getDCDWaiting()) { + // todo, will the delay here slow down transmission with + // multiple interfaces? needs investigation + for (uint8_t dcd_i = 0; dcd_i < DCD_THRESHOLD*2; dcd_i++) { + delay(STATUS_INTERVAL_MS); selected_radio->updateModemStatus(); + } + + if (!selected_radio->getDCD()) { + uint8_t csma_r = (uint8_t)random(256); + if (selected_radio->getCSMAp() >= csma_r) { + flushQueue(selected_radio); + } else { + selected_radio->setDCDWaiting(true); + selected_radio->setDCDWaitUntil(millis()+selected_radio->getCSMASlotMS()); + } + } + } + } + } } } else { @@ -1577,10 +1239,11 @@ void loop() { } } - process_serial(); + buffer_serial(); + if (!fifo_isempty(&serialFIFO)) serial_poll(); #if HAS_DISPLAY - #if DISPLAY == OLED || DISPLAY == TFT || DISPLAY == ADAFRUIT_TFT + #if DISPLAY == OLED if (disp_ready) update_display(); #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C // Display refreshes take so long on e-paper displays that they can disrupt @@ -1611,32 +1274,6 @@ void loop() { #if HAS_INPUT input_read(); #endif - - #if HAS_GPS - while (gps_s.available() > 0) { - if (gps.encode(gps_s.read()) && millis() - last_gps >= GPS_INTERVAL) { - kiss_indicate_location(); - last_gps = millis(); - } - } - if (millis() > 5000 && gps.charsProcessed() < 10) { - while (true) { - Serial.println(F("No GPS detected: check wiring.")); - } - } - #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() { @@ -1646,93 +1283,56 @@ void process_serial() { void sleep_now() { #if HAS_SLEEP == true - for (int i = 0; i < INTERFACE_COUNT; i++) { - stopRadio(interface_obj[i]); // TODO: Check this on all platforms - } - #if PLATFORM == PLATFORM_ESP32 - #if BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_XIAO_S3 - display_intensity = 0; - update_display(true); - #endif - #if PIN_DISP_SLEEP >= 0 - pinMode(PIN_DISP_SLEEP, OUTPUT); - digitalWrite(PIN_DISP_SLEEP, DISP_SLEEP_LEVEL); - #endif - #if HAS_BLUETOOTH - if (bt_state == BT_STATE_CONNECTED) { - bt_stop(); - delay(100); - } - #endif - esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL); - esp_deep_sleep_start(); - #elif PLATFORM == PLATFORM_NRF52 - #if BOARD_MODEL == BOARD_HELTEC_T114 - npset(0,0,0); - digitalWrite(PIN_VEXT_EN, LOW); - digitalWrite(PIN_T114_TFT_BLGT, HIGH); - digitalWrite(PIN_T114_TFT_EN, HIGH); - #elif BOARD_MODEL == BOARD_TECHO - for (uint8_t i = display_intensity; i > 0; i--) { analogWrite(pin_backlight, i-1); delay(1); } - epd_black(true); delay(300); epd_black(true); delay(300); epd_black(false); - delay(2000); - analogWrite(PIN_VEXT_EN, 0); - delay(100); - #endif - sd_power_gpregret_set(0, 0x6d); - nrf_gpio_cfg_sense_input(pin_btn_usr1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW); - NRF_POWER->SYSTEMOFF = 1; + #if BOARD_MODEL == BOARD_RNODE_NG_22 + display_intensity = 0; + update_display(true); #endif + #if PIN_DISP_SLEEP >= 0 + pinMode(PIN_DISP_SLEEP, OUTPUT); + digitalWrite(PIN_DISP_SLEEP, DISP_SLEEP_LEVEL); + #endif + esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL); + esp_deep_sleep_start(); #endif } void button_event(uint8_t event, unsigned long duration) { - if (display_blanked) { - display_unblank(); - } else { - if (duration > 10000) { - #if HAS_CONSOLE - #if HAS_BLUETOOTH || HAS_BLE - bt_stop(); - #endif - console_active = true; - console_start(); - #endif - } else if (duration > 5000) { - #if HAS_BLUETOOTH || HAS_BLE - if (bt_state != BT_STATE_CONNECTED) { bt_enable_pairing(); } - #endif - } else if (duration > 700) { - #if HAS_SLEEP - sleep_now(); - #endif - } else { - #if HAS_BLUETOOTH || HAS_BLE - if (bt_state != BT_STATE_CONNECTED) { - if (bt_state == BT_STATE_OFF) { - bt_start(); - bt_conf_save(true); - } else { - bt_stop(); - bt_conf_save(false); - } - } - #endif - } - } + if (duration > 2000) { + sleep_now(); + } } void poll_buffers() { process_serial(); } +void packet_poll() { + #if MCU_VARIANT == MCU_ESP32 + portENTER_CRITICAL(&update_lock); + #elif MCU_VARIANT == MCU_NRF52 + portENTER_CRITICAL(); + #endif + // If we have received a packet on an interface which needs to be processed + if (process_packet) { + selected_radio = interface_obj[packet_interface]; + selected_radio->clearIRQStatus(); + selected_radio->handleDio0Rise(); + process_packet = false; + } + #if MCU_VARIANT == MCU_ESP32 + portEXIT_CRITICAL(&update_lock); + #elif MCU_VARIANT == MCU_NRF52 + portEXIT_CRITICAL(); + #endif +} + volatile bool serial_polling = false; void serial_poll() { serial_polling = true; while (!fifo_isempty(&serialFIFO)) { char sbyte = fifo_pop(&serialFIFO); - serial_callback(sbyte); + serialCallback(sbyte); } serial_polling = false; diff --git a/ROM.h b/ROM.h index 9840f34..7a343c0 100644 --- a/ROM.h +++ b/ROM.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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,45 +14,71 @@ // along with this program. If not, see . #ifndef ROM_H - #define ROM_H - #define CHECKSUMMED_SIZE 0x0B + #define ROM_H - // 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 CHECKSUMMED_SIZE 0x0B - #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 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 MODEL_11 0x11 + #define MODEL_12 0x12 + #define MODEL_A1 0xA1 + #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_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_DROT 0xB8 - #define ADDR_CONF_PSET 0xB5 - #define ADDR_CONF_PINT 0xB6 - #define ADDR_CONF_BSET 0xB7 - #define ADDR_CONF_DIA 0xB9 + #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 INFO_LOCK_BYTE 0x73 - #define CONF_OK_BYTE 0x73 - #define BT_ENABLE_BYTE 0x73 + #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 EEPROM_RESERVED 200 - ////////////////////////////////// + #define INFO_LOCK_BYTE 0x73 + #define CONF_OK_BYTE 0x73 + #define BT_ENABLE_BYTE 0x73 + + #define EEPROM_RESERVED 200 #endif diff --git a/Radio.cpp b/Radio.cpp index 52364dd..33b46a9 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -4,8 +4,7 @@ // Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva // Obviously still under the MIT license. -#include "Radio.hpp" -#include "src/misc/ModemISR.h" +#include "Radio.h" #if PLATFORM == PLATFORM_ESP32 #if defined(ESP32) and !defined(CONFIG_IDF_TARGET_ESP32S3) @@ -89,15 +88,30 @@ #define FREQ_DIV_6X (double)pow(2.0, 25.0) #define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X) -extern FIFOBuffer packet_rdy_interfaces; +extern bool process_packet; +extern uint8_t packet_interface; extern RadioInterface* interface_obj[]; -sx126x::sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen) : +// ISRs cannot provide parameters to the functions they call. Since we have +// multiple interfaces, we have to read each dio0 pin for each one and see +// which one is high. We can then use the index of this pin in the 2D array to +// signal the correct interface to the main loop +void ISR_VECT onDio0Rise() { + for (int i = 0; i < INTERFACE_COUNT; i++) { + if (digitalRead(interface_pins[i][5]) == HIGH) { + process_packet = true; + packet_interface = i; + break; + } + } +} + +sx126x::sx126x(uint8_t index, SPIClass spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen) : 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), _bw(0x04), - _cr(0x01), _packetIndex(0), _implicitHeaderMode(0), + _busy(busy), _rxen(rxen), _frequency(0), _txp(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), _dio2_as_rf_switch(dio2_as_rf_switch) @@ -106,7 +120,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() { @@ -116,12 +130,12 @@ bool sx126x::preInit() { // todo: check if this change causes issues on any platforms #if MCU_VARIANT == MCU_ESP32 if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { - _spiModem->begin(_sclk, _miso, _mosi, _ss); + _spiModem.begin(_sclk, _miso, _mosi, _ss); } else { - _spiModem->begin(); + _spiModem.begin(); } #else - _spiModem->begin(); + _spiModem.begin(); #endif // check version (retry for up to 2 seconds) @@ -163,15 +177,15 @@ uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); - _spiModem->transfer((address & 0xFF00) >> 8); - _spiModem->transfer(address & 0x00FF); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); + _spiModem.transfer((address & 0xFF00) >> 8); + _spiModem.transfer(address & 0x00FF); if (opcode == OP_READ_REGISTER_6X) { - _spiModem->transfer(0x00); + _spiModem.transfer(0x00); } - response = _spiModem->transfer(value); - _spiModem->endTransaction(); + response = _spiModem.transfer(value); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); @@ -193,11 +207,12 @@ void sx126x::loraMode() { void sx126x::waitOnBusy() { unsigned long time = millis(); - if (_busy != -1) { - while (digitalRead(_busy) == HIGH) - { - if (millis() >= (time + 100)) { break; } + while (digitalRead(_busy) == HIGH) + { + if (millis() >= (time + 100)) { + break; } + // do nothing } } @@ -207,15 +222,15 @@ void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); for (int i = 0; i < size; i++) { - _spiModem->transfer(buffer[i]); + _spiModem.transfer(buffer[i]); } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -226,16 +241,16 @@ void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); - _spiModem->transfer(0x00); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); + _spiModem.transfer(0x00); for (int i = 0; i < size; i++) { - buffer[i] = _spiModem->transfer(0x00); + buffer[i] = _spiModem.transfer(0x00); } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -246,13 +261,17 @@ void sx126x::writeBuffer(const uint8_t* buffer, size_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(OP_FIFO_WRITE_6X); - _spiModem->transfer(_fifo_tx_addr_ptr); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(OP_FIFO_WRITE_6X); + _spiModem.transfer(_fifo_tx_addr_ptr); - for (int i = 0; i < size; i++) {_spiModem->transfer(buffer[i]); _fifo_tx_addr_ptr++;} + for (int i = 0; i < size; i++) + { + _spiModem.transfer(buffer[i]); + _fifo_tx_addr_ptr++; + } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -263,20 +282,23 @@ void sx126x::readBuffer(uint8_t* buffer, size_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(OP_FIFO_READ_6X); - _spiModem->transfer(_fifo_rx_addr_ptr); - _spiModem->transfer(0x00); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(OP_FIFO_READ_6X); + _spiModem.transfer(_fifo_rx_addr_ptr); + _spiModem.transfer(0x00); - for (int i = 0; i < size; i++) {buffer[i] = _spiModem->transfer(0x00);} + for (int i = 0; i < size; i++) + { + buffer[i] = _spiModem.transfer(0x00); + } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) { - // Because there is no access to these registers on the sx1262, we have + // because there is no access to these registers on the sx1262, we have // to set all these parameters at once or not at all. uint8_t buf[8]; @@ -295,7 +317,7 @@ void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) { } void sx126x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) { - // Because there is no access to these registers on the sx1262, we have + // because there is no access to these registers on the sx1262, we have // to set all these parameters at once or not at all. uint8_t buf[9]; @@ -342,11 +364,27 @@ void sx126x::calibrate(void) { void sx126x::calibrate_image(uint32_t frequency) { uint8_t image_freq[2] = {0}; - if (frequency >= 430E6 && frequency <= 440E6) { image_freq[0] = 0x6B; image_freq[1] = 0x6F; } - else if (frequency >= 470E6 && frequency <= 510E6) { image_freq[0] = 0x75; image_freq[1] = 0x81; } - else if (frequency >= 779E6 && frequency <= 787E6) { image_freq[0] = 0xC1; image_freq[1] = 0xC5; } - else if (frequency >= 863E6 && frequency <= 870E6) { image_freq[0] = 0xD7; image_freq[1] = 0xDB; } - else if (frequency >= 902E6 && frequency <= 928E6) { image_freq[0] = 0xE1; image_freq[1] = 0xE9; } + if (frequency >= 430E6 && frequency <= 440E6) { + image_freq[0] = 0x6B; + image_freq[1] = 0x6F; + } + else if (frequency >= 470E6 && frequency <= 510E6) { + image_freq[0] = 0x75; + image_freq[1] = 0x81; + } + else if (frequency >= 779E6 && frequency <= 787E6) { + image_freq[0] = 0xC1; + image_freq[1] = 0xC5; + } + else if (frequency >= 863E6 && frequency <= 870E6) { + image_freq[0] = 0xD7; + image_freq[1] = 0xDB; + } + else if (frequency >= 902E6 && frequency <= 928E6) { + image_freq[0] = 0xE1; + image_freq[1] = 0xE9; + } + executeOpcode(OP_CALIBRATE_IMAGE_6X, image_freq, 2); waitOnBusy(); } @@ -355,7 +393,9 @@ int sx126x::begin() { reset(); - if (_busy != -1) { pinMode(_busy, INPUT); } + if (_busy != -1) { + pinMode(_busy, INPUT); + } if (!_preinit_done) { if (!preInit()) { @@ -363,7 +403,9 @@ int sx126x::begin() } } - if (_rxen != -1) { pinMode(_rxen, OUTPUT); } + if (_rxen != -1) { + pinMode(_rxen, OUTPUT); + } calibrate(); calibrate_image(_frequency); @@ -409,7 +451,7 @@ void sx126x::end() sleep(); // stop SPI - _spiModem->end(); + _spiModem.end(); _bitrate = 0; @@ -437,70 +479,60 @@ 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 - bool timed_out = false; - uint32_t w_timeout = millis()+(getAirtime(_payloadLength)* MODEM_TIMEOUT_MULT); - while ((millis() < w_timeout) && ((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(); - } + } - if (millis() > w_timeout) { timed_out = true; } + // 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 !timed_out; + 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() { + // imitate the register status from the sx1276 / 78 + uint8_t buf[2] = {0}; -bool sx126x::dcd() { - bool false_preamble_detected = false; - uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); - uint32_t now = millis(); + executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); + uint8_t clearbuf[2] = {0}; + uint8_t byte = 0x00; - bool header_detected = false; - bool carrier_detected = false; - - if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) { header_detected = true; carrier_detected = true; } - else { header_detected = false; } - - if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) { - carrier_detected = true; - if (_preamble_detected_at == 0) { _preamble_detected_at = now; } - if (now - _preamble_detected_at > _lora_preamble_time_ms + _lora_header_time_ms) { - _preamble_detected_at = 0; - if (!header_detected) { false_preamble_detected = true; } - uint8_t clearbuf[2] = {0}; + if ((buf[1] & IRQ_PREAMBLE_DET_MASK_6X) != 0) { + byte = byte | 0x01 | 0x04; + // clear register after reading clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X; - executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2); } - } - // TODO: Maybe there's a way of unlatching the RSSI - // status without re-activating receive mode? - if (false_preamble_detected) { receive(); false_preamble_detected = false; } - return carrier_detected; + if ((buf[1] & IRQ_HEADER_DET_MASK_6X) != 0) { + byte = byte | 0x02 | 0x04; + } + + executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2); + + return byte; } + uint8_t sx126x::currentRssiRaw() { uint8_t byte = 0; executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1); @@ -520,7 +552,7 @@ uint8_t sx126x::packetRssiRaw() { return buf[2]; } -int ISR_VECT sx126x::packetRssi(uint8_t pkt_snr_raw) { +int ISR_VECT sx126x::packetRssi() { // may need more calculations here uint8_t buf[3] = {0}; executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3); @@ -573,7 +605,9 @@ int ISR_VECT sx126x::available() int ISR_VECT sx126x::read() { - if (!available()) { return -1; } + if (!available()) { + return -1; + } // if received new packet if (_packetIndex == 0) { @@ -642,16 +676,16 @@ void sx126x::onReceive(void(*callback)(uint8_t, int)) executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8); #ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0)); + _spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); #endif // make function available - extern void (*onIntRise[INTERFACE_COUNT])(void); + extern void onDio0Rise(); - attachInterrupt(digitalPinToInterrupt(_dio0), onIntRise[_index], RISING); + attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING); } else { detachInterrupt(digitalPinToInterrupt(_dio0)); #ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0)); + _spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); #endif } } @@ -697,21 +731,11 @@ void sx126x::sleep() void sx126x::enableTCXO() { if (_tcxo) { - #if BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_XIAO_ESP32S3 + #if BOARD_MODEL == BOARD_RAK4631 || 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}; - #elif BOARD_MODEL == BOARD_TECHO - 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}; - #elif BOARD_MODEL == BOARD_HELTEC_T114 - uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; - #elif BOARD_MODEL == BOARD_E22_ESP32 + #elif BOARD_MODEL == BOARD_RNODE_NG_22 uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #else uint8_t buf[4] = {0}; @@ -744,7 +768,7 @@ void sx126x::setTxPower(int level, int outputPin) { _txp = level; - writeRegister(REG_OCP_6X, OCP_TUNED); // 160mA limit, overcurrent protection + writeRegister(REG_OCP_6X, 0x38); // 160mA limit, overcurrent protection uint8_t tx_buf[2]; @@ -754,7 +778,7 @@ void sx126x::setTxPower(int level, int outputPin) { executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2); } -int8_t sx126x::getTxPower() { +uint8_t sx126x::getTxPower() { return _txp; } @@ -887,7 +911,7 @@ void sx126x::setPreambleLength(long length) void sx126x::setSyncWord(uint16_t sw) { - // TODO: Why was this hardcoded instead of using the config value? + // TODO: Fix // writeRegister(REG_SYNC_WORD_MSB_6X, (sw & 0xFF00) >> 8); // writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF); writeRegister(REG_SYNC_WORD_MSB_6X, 0x14); @@ -906,7 +930,7 @@ void sx126x::disableCrc() setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } -uint8_t sx126x::random() +byte sx126x::random() { return readRegister(REG_RANDOM_GEN_6X); } @@ -941,20 +965,6 @@ void sx126x::implicitHeaderMode() void sx126x::handleDio0Rise() { - // received a packet - _packetIndex = 0; - - // read packet length - uint8_t rxbuf[2] = {0}; - executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2); - int packetLength = rxbuf[0]; - - if (_onReceive) { - _onReceive(_index, packetLength); - } -} - -bool ISR_VECT sx126x::getPacketValidity() { uint8_t buf[2]; buf[0] = 0x00; @@ -965,10 +975,54 @@ bool ISR_VECT sx126x::getPacketValidity() { executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2); if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) { - return true; - } else { - return false; + // received a packet + _packetIndex = 0; + + // read packet length + uint8_t rxbuf[2] = {0}; + executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2); + int packetLength = rxbuf[0]; + + if (_onReceive) { + _onReceive(_index, packetLength); + } } + // else { + // Serial.println("CRCE"); + // Serial.println(buf[0]); + // Serial.println(buf[1]); + // } +} + +void sx126x::updateBitrate() { + if (_radio_online) { + _lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf)); + _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; + 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; + } else { + target_preamble_symbols = ceil(target_preamble_symbols); + } + _preambleLength = (long)target_preamble_symbols; + setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); + } else { + _bitrate = 0; + } +} + +void sx126x::clearIRQStatus() { + uint8_t buf[2]; + + buf[0] = 0x00; + buf[1] = 0x00; + + executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); + + executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2); } // SX127x registers #define REG_FIFO_7X 0x00 @@ -1027,19 +1081,25 @@ bool ISR_VECT sx126x::getPacketValidity() { #define SYNC_WORD_7X 0x12 -sx127x::sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy) : +sx127x::sx127x(uint8_t index, SPIClass spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy) : RadioInterface(index), _spiSettings(8E6, MSBFIRST, SPI_MODE0), _spiModem(spi), _ss(ss), _sclk(sclk), _mosi(mosi), _miso(miso), _reset(reset), _dio0(dio0), - _busy(busy), _frequency(0), _packetIndex(0), _preinit_done(false), _bw(7800) -{ setTimeout(0); } + _busy(busy), _frequency(0), _packetIndex(0), _preinit_done(false) +{ + 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(); +} void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } uint8_t ISR_VECT sx127x::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); } void sx127x::writeRegister(uint8_t address, uint8_t value) { singleTransfer(address | 0x80, value); } void sx127x::standby() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_STDBY_7X); } void sx127x::sleep() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_SLEEP_7X); } +uint8_t sx127x::modemStatus() { return readRegister(REG_MODEM_STAT_7X); } void sx127x::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD_7X, sw); } void sx127x::enableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) | 0x04); } void sx127x::disableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) & 0xfb); } @@ -1047,7 +1107,7 @@ void sx127x::enableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeR void sx127x::disableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg & 0xEF); } void sx127x::explicitHeaderMode() { _implicitHeaderMode = 0; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) & 0xfe); } void sx127x::implicitHeaderMode() { _implicitHeaderMode = 1; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) | 0x01); } -uint8_t sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); } +byte sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); } void sx127x::flush() { } bool sx127x::preInit() { @@ -1056,12 +1116,12 @@ bool sx127x::preInit() { // todo: check if this change causes issues on any platforms #if MCU_VARIANT == MCU_ESP32 if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { - _spiModem->begin(_sclk, _miso, _mosi, _ss); + _spiModem.begin(_sclk, _miso, _mosi, _ss); } else { - _spiModem->begin(); + _spiModem.begin(); } #else - _spiModem->begin(); + _spiModem.begin(); #endif // Check modem version @@ -1083,31 +1143,25 @@ uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) { uint8_t response; digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(address); - response = _spiModem->transfer(value); - _spiModem->endTransaction(); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(address); + response = _spiModem.transfer(value); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); return response; } -void sx127x::reset() { - if (_reset != -1) { - pinMode(_reset, OUTPUT); - - // Perform reset - digitalWrite(_reset, LOW); - delay(10); - digitalWrite(_reset, HIGH); - delay(10); - } -} - int sx127x::begin() { - reset(); + if (_reset != -1) { + pinMode(_reset, OUTPUT); - sleep(); + // Perform reset + digitalWrite(_reset, LOW); + delay(10); + digitalWrite(_reset, HIGH); + delay(10); + } if (_busy != -1) { pinMode(_busy, INPUT); } @@ -1115,22 +1169,20 @@ int sx127x::begin() { if (!preInit()) { return false; } } + sleep(); setFrequency(_frequency); - setSignalBandwidth(_bw); - setSpreadingFactor(_sf); - setCodingRate4(_cr); - setTxPower(_txp); - // Set base addresses + // set base addresses writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0); writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0); - // Set LNA boost and auto AGC + // set LNA boost and auto AGC writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03); writeRegister(REG_MODEM_CONFIG_3_7X, 0x04); setSyncWord(SYNC_WORD_7X); enableCrc(); + setTxPower(2); standby(); @@ -1141,8 +1193,10 @@ int sx127x::begin() { void sx127x::end() { sleep(); + _spiModem.end(); _bitrate = 0; _radio_online = false; + _preinit_done = false; } int sx127x::beginPacket(int implicitHeader) { @@ -1175,15 +1229,6 @@ int sx127x::endPacket() { return 1; } - -bool sx127x::dcd() { - bool carrier_detected = false; - uint8_t status = readRegister(REG_MODEM_STAT_7X); - if ((status & SIG_DETECT) == SIG_DETECT) { carrier_detected = true; } - if ((status & SIG_SYNCED) == SIG_SYNCED) { carrier_detected = true; } - return carrier_detected; -} - uint8_t sx127x::currentRssiRaw() { uint8_t rssi = readRegister(REG_RSSI_VALUE_7X); return rssi; @@ -1200,9 +1245,9 @@ uint8_t sx127x::packetRssiRaw() { return pkt_rssi_value; } -int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) { +int ISR_VECT sx127x::packetRssi() { int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; - int pkt_snr = ((int8_t)pkt_snr_raw)*0.25; + int pkt_snr = packetSnr(); if (_frequency < 820E6) pkt_rssi -= 7; @@ -1217,26 +1262,13 @@ int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) { return pkt_rssi; } -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; +uint8_t ISR_VECT sx127x::packetSnrRaw() { + return readRegister(REG_PKT_SNR_VALUE_7X); } - -uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); } - -float ISR_VECT sx127x::packetSnr() { return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; } +float ISR_VECT sx127x::packetSnr() { + return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; +} long sx127x::packetFrequencyError() { int32_t freqError = 0; @@ -1260,9 +1292,13 @@ size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); } size_t sx127x::write(const uint8_t *buffer, size_t size) { int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X); - if ((currentLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; } + if ((currentLength + size) > MAX_PKT_LENGTH) { + size = MAX_PKT_LENGTH - currentLength; + } - for (size_t i = 0; i < size; i++) { writeRegister(REG_FIFO_7X, buffer[i]); } + for (size_t i = 0; i < size; i++) { + writeRegister(REG_FIFO_7X, buffer[i]); + } writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size); return size; @@ -1295,18 +1331,19 @@ void sx127x::onReceive(void(*callback)(uint8_t, int)) { writeRegister(REG_DIO_MAPPING_1_7X, 0x00); #ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0)); + _spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); #endif // make function available - extern void (*onIntRise[INTERFACE_COUNT])(void); + extern void onDio0Rise(); - attachInterrupt(digitalPinToInterrupt(_dio0), onIntRise[_index], RISING); + attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING); + } else { detachInterrupt(digitalPinToInterrupt(_dio0)); #ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0)); + _spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); #endif } } @@ -1328,22 +1365,20 @@ void sx127x::setTxPower(int level, int outputPin) { writeRegister(REG_PA_DAC_7X, 0x84); writeRegister(REG_PA_CONFIG_7X, 0x70 | level); - _txp = level; + } else { if (level < 2) { level = 2; } else if (level > 17) { level = 17; } writeRegister(REG_PA_DAC_7X, 0x84); writeRegister(REG_PA_CONFIG_7X, PA_BOOST_7X | (level - 2)); - _txp = level; } } -int8_t sx127x::getTxPower() { return readRegister(REG_PA_CONFIG_7X) - 126; } +uint8_t sx127x::getTxPower() { byte txp = readRegister(REG_PA_CONFIG_7X); return txp; } void sx127x::setFrequency(uint32_t frequency) { _frequency = frequency; - uint32_t frf = ((uint64_t)frequency << 19) / 32000000; writeRegister(REG_FRF_MSB_7X, (uint8_t)(frf >> 16)); @@ -1354,23 +1389,30 @@ void sx127x::setFrequency(uint32_t frequency) { } uint32_t sx127x::getFrequency() { - return _frequency; + uint8_t msb = readRegister(REG_FRF_MSB_7X); + uint8_t mid = readRegister(REG_FRF_MID_7X); + uint8_t lsb = readRegister(REG_FRF_LSB_7X); + + uint32_t frf = ((uint32_t)msb << 16) | ((uint32_t)mid << 8) | (uint32_t)lsb; + uint64_t frm = (uint64_t)frf*32000000; + uint32_t frequency = (frm >> 19); + + return frequency; } void sx127x::setSpreadingFactor(int sf) { if (sf < 6) { sf = 6; } else if (sf > 12) { sf = 12; } - _sf = sf; - if (sf == 6) { - writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc5); - writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0c); + writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc5); + writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0c); } else { - writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc3); - writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0a); + writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc3); + writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0a); } + _sf = sf; writeRegister(REG_MODEM_CONFIG_2_7X, (readRegister(REG_MODEM_CONFIG_2_7X) & 0x0f) | ((sf << 4) & 0xf0)); handleLowDataRate(); @@ -1382,7 +1424,20 @@ uint8_t sx127x::getSpreadingFactor() } uint32_t sx127x::getSignalBandwidth() { - return _bw; + byte bw = (readRegister(REG_MODEM_CONFIG_1_7X) >> 4); + switch (bw) { + case 0: return 7.8E3; + case 1: return 10.4E3; + case 2: return 15.6E3; + case 3: return 20.8E3; + case 4: return 31.25E3; + case 5: return 41.7E3; + case 6: return 62.5E3; + case 7: return 125E3; + case 8: return 250E3; + case 9: return 500E3; } + + return 0; } void sx127x::setSignalBandwidth(uint32_t sbw) { @@ -1410,7 +1465,6 @@ void sx127x::setSignalBandwidth(uint32_t sbw) { } writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0x0f) | (bw << 4)); - _bw = sbw; handleLowDataRate(); optimizeModemSensitivity(); } @@ -1439,11 +1493,9 @@ void sx127x::handleLowDataRate() { if ( long( (1< 16) { // Set auto AGC and LowDataRateOptimize writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2)); - _ldro = true; } else { // Only set auto AGC writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2)); - _ldro = false; } } @@ -1463,32 +1515,47 @@ void sx127x::optimizeModemSensitivity() { } void sx127x::handleDio0Rise() { - int irqFlags = readRegister(REG_IRQ_FLAGS_7X); - - // Clear IRQs - writeRegister(REG_IRQ_FLAGS_7X, irqFlags); - if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) { - _packetIndex = 0; - int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X); - writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X)); - if (_onReceive) { _onReceive(_index, packetLength); } - writeRegister(REG_FIFO_ADDR_PTR_7X, 0); - } -} - -bool ISR_VECT sx127x::getPacketValidity() { int irqFlags = readRegister(REG_IRQ_FLAGS_7X); // Clear IRQs writeRegister(REG_IRQ_FLAGS_7X, irqFlags); - if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) { - return true; - } else { - return false; + _packetIndex = 0; + int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X); + writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X)); + if (_onReceive) { + _onReceive(_index, packetLength); + } + writeRegister(REG_FIFO_ADDR_PTR_7X, 0); } } +void sx127x::updateBitrate() { + if (_radio_online) { + _lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf)); + _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; + 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; + } else { + target_preamble_symbols = ceil(target_preamble_symbols); + } + _preambleLength = (long)target_preamble_symbols; + } else { + _bitrate = 0; + } +} + +void sx127x::clearIRQStatus() { + int irqFlags = readRegister(REG_IRQ_FLAGS_7X); + + // Clear IRQs + writeRegister(REG_IRQ_FLAGS_7X, irqFlags); +} + // SX128x registers #define OP_RF_FREQ_8X 0x86 #define OP_SLEEP_8X 0x84 @@ -1532,22 +1599,22 @@ bool ISR_VECT sx127x::getPacketValidity() { #define FREQ_DIV_8X (double)pow(2.0, 18.0) #define FREQ_STEP_8X (double)(XTAL_FREQ_8X / FREQ_DIV_8X) -sx128x::sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen) : +sx128x::sx128x(uint8_t index, SPIClass spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen) : 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), _txen(txen), _frequency(0), + _busy(busy), _rxen(rxen), _txen(txen), _frequency(0), _txp(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), - _tcxo(tcxo), _preamble_e(1), _preamble_m(1), _last_preamble(0) + _tcxo(tcxo) { // overide Stream timeout value 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() { @@ -1559,29 +1626,33 @@ bool sx128x::preInit() { // todo: check if this change causes issues on any platforms #if MCU_VARIANT == MCU_ESP32 if (_sclk != -1 && _miso != -1 && _mosi != -1 && _ss != -1) { - _spiModem->begin(_sclk, _miso, _mosi, _ss); + _spiModem.begin(_sclk, _miso, _mosi, _ss); } else { - _spiModem->begin(); + _spiModem.begin(); } #else - _spiModem->begin(); + _spiModem.begin(); #endif - // check version (retry for up to 500 ms) + // check version (retry for up to 2 seconds) long start = millis(); uint8_t version_msb; uint8_t version_lsb; - while (((millis() - start) < 500) && (millis() >= start)) { + while (((millis() - start) < 2000) && (millis() >= start)) { version_msb = readRegister(REG_FIRM_VER_MSB); version_lsb = readRegister(REG_FIRM_VER_LSB); - if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) { break; } + if ((version_msb == 0xB7 && version_lsb == 0xA9) || (version_msb == 0xB5 && version_lsb == 0xA9)) { + break; + } delay(100); } - if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) { return false; } + if ((version_msb != 0xB7 || version_lsb != 0xA9) && (version_msb != 0xB5 || version_lsb != 0xA9)) { + return false; + } _preinit_done = true; return true; @@ -1605,13 +1676,15 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); - _spiModem->transfer((address & 0xFF00) >> 8); - _spiModem->transfer(address & 0x00FF); - if (opcode == OP_READ_REGISTER_8X) { _spiModem->transfer(0x00); } - response = _spiModem->transfer(value); - _spiModem->endTransaction(); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); + _spiModem.transfer((address & 0xFF00) >> 8); + _spiModem.transfer(address & 0x00FF); + if (opcode == OP_READ_REGISTER_8X) { + _spiModem.transfer(0x00); + } + response = _spiModem.transfer(value); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); @@ -1620,17 +1693,26 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ void sx128x::rxAntEnable() { - if (_txen != -1) { digitalWrite(_txen, LOW); } - if (_rxen != -1) { digitalWrite(_rxen, HIGH); } + if (_txen != -1) { + digitalWrite(_txen, LOW); + } + if (_rxen != -1) { + digitalWrite(_rxen, HIGH); + } } void sx128x::txAntEnable() { - if (_txen != -1) { digitalWrite(_txen, HIGH); } - if (_rxen != -1) { digitalWrite(_rxen, LOW); } + if (_txen != -1) { + digitalWrite(_txen, HIGH); + } + if (_rxen != -1) { + digitalWrite(_rxen, LOW); + } } void sx128x::loraMode() { + // enable lora mode on the SX1262 chip uint8_t mode = MODE_LONG_RANGE_MODE_8X; executeOpcode(OP_PACKET_TYPE_8X, &mode, 1); } @@ -1639,7 +1721,10 @@ void sx128x::waitOnBusy() { unsigned long time = millis(); while (digitalRead(_busy) == HIGH) { - if (millis() >= (time + 100)) { break; } + if (millis() >= (time + 100)) { + break; + } + // do nothing } } @@ -1649,15 +1734,15 @@ void sx128x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); for (int i = 0; i < size; i++) { - _spiModem->transfer(buffer[i]); + _spiModem.transfer(buffer[i]); } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -1668,16 +1753,16 @@ void sx128x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(opcode); - _spiModem->transfer(0x00); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(opcode); + _spiModem.transfer(0x00); for (int i = 0; i < size; i++) { - buffer[i] = _spiModem->transfer(0x00); + buffer[i] = _spiModem.transfer(0x00); } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -1688,17 +1773,17 @@ void sx128x::writeBuffer(const uint8_t* buffer, size_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(OP_FIFO_WRITE_8X); - _spiModem->transfer(_fifo_tx_addr_ptr); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(OP_FIFO_WRITE_8X); + _spiModem.transfer(_fifo_tx_addr_ptr); for (int i = 0; i < size; i++) { - _spiModem->transfer(buffer[i]); + _spiModem.transfer(buffer[i]); _fifo_tx_addr_ptr++; } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -1709,17 +1794,17 @@ void sx128x::readBuffer(uint8_t* buffer, size_t size) digitalWrite(_ss, LOW); - _spiModem->beginTransaction(_spiSettings); - _spiModem->transfer(OP_FIFO_READ_8X); - _spiModem->transfer(_fifo_rx_addr_ptr); - _spiModem->transfer(0x00); + _spiModem.beginTransaction(_spiSettings); + _spiModem.transfer(OP_FIFO_READ_8X); + _spiModem.transfer(_fifo_rx_addr_ptr); + _spiModem.transfer(0x00); for (int i = 0; i < size; i++) { - buffer[i] = _spiModem->transfer(0x00); + buffer[i] = _spiModem.transfer(0x00); } - _spiModem->endTransaction(); + _spiModem.endTransaction(); digitalWrite(_ss, HIGH); } @@ -1734,38 +1819,37 @@ void sx128x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr) { buf[2] = cr; executeOpcode(OP_MODULATION_PARAMS_8X, buf, 3); - if (sf <= 6) { writeRegister(0x925, 0x1E); } - else if (sf <= 8) { writeRegister(0x925, 0x37); } - else if (sf >= 9) { writeRegister(0x925, 0x32); } + if (sf <= 6) { + writeRegister(0x925, 0x1E); + } else if (sf <= 8) { + writeRegister(0x925, 0x37); + } else if (sf >= 9) { + writeRegister(0x925, 0x32); + } writeRegister(0x093C, 0x1); } -void sx128x::setPacketParams(uint32_t target_preamble, uint8_t headermode, uint8_t length, uint8_t crc) { +void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc) { // because there is no access to these registers on the sx1280, we have // to set all these parameters at once or not at all. uint8_t buf[7]; - uint32_t calc_preamble; + // calculate exponent and mantissa values for modem + uint8_t e = 1; + uint8_t m = 1; + uint32_t preamblelen; - // Cap max preamble length - if (target_preamble >= 0xF000) target_preamble = 0xF000; - - if (_last_preamble != target_preamble) { - _preamble_e = 1; - _preamble_m = 1; - // calculate exponent and mantissa values for modem - while (_preamble_e <= 15) { - while (_preamble_m <= 15) { - calc_preamble = _preamble_m * (pow(2,_preamble_e)); - if (calc_preamble >= target_preamble - 4) break; - _preamble_m++; - } - if (calc_preamble >= target_preamble - 4) break; - _preamble_m = 1; - _preamble_e++; + while (e <= 15) { + while (m <= 15) { + preamblelen = m * (pow(2,e)); + if (preamblelen >= preamble) break; + m++; } + if (preamblelen >= preamble) break; + m = 0; + e++; } - buf[0] = (_preamble_e << 4) | _preamble_m; + buf[0] = (e << 4) | m; buf[1] = headermode; buf[2] = length; buf[3] = crc; @@ -1776,11 +1860,9 @@ void sx128x::setPacketParams(uint32_t target_preamble, uint8_t headermode, uint8 buf[6] = 0x00; executeOpcode(OP_PACKET_PARAMS_8X, buf, 7); - - _last_preamble = target_preamble; } -void sx128x::reset() +int sx128x::begin() { if (_reset != -1) { pinMode(_reset, OUTPUT); @@ -1791,11 +1873,6 @@ void sx128x::reset() digitalWrite(_reset, HIGH); delay(10); } -} - -int sx128x::begin() -{ - reset(); if (_rxen != -1) { pinMode(_rxen, OUTPUT); @@ -1844,7 +1921,7 @@ void sx128x::end() sleep(); // stop SPI - _spiModem->end(); + _spiModem.end(); _bitrate = 0; @@ -1857,8 +1934,11 @@ int sx128x::beginPacket(int implicitHeader) // put in standby mode standby(); - if (implicitHeader) { implicitHeaderMode(); } - else { explicitHeaderMode(); } + if (implicitHeader) { + implicitHeaderMode(); + } else { + explicitHeaderMode(); + } _payloadLength = 0; _fifo_tx_addr_ptr = 0; @@ -1884,17 +1964,14 @@ int sx128x::endPacket() executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); - // Wait for TX done - bool timed_out = false; - uint32_t w_timeout = millis()+(getAirtime(_payloadLength)* MODEM_TIMEOUT_MULT); - while ((millis() < w_timeout) && ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0)) { + // wait for TX done + while ((buf[1] & IRQ_TX_DONE_MASK_8X) == 0) { buf[0] = 0x00; buf[1] = 0x00; executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); yield(); } - if (millis() > w_timeout) { timed_out = true; } // clear IRQ's @@ -1902,37 +1979,35 @@ int sx128x::endPacket() mask[0] = 0x00; mask[1] = IRQ_TX_DONE_MASK_8X; executeOpcode(OP_CLEAR_IRQ_STATUS_8X, mask, 2); - return !timed_out; + return 1; } -bool sx128x::dcd() { - bool false_preamble_detected = false; - uint8_t buf[2] = {0}; executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); - uint32_t now = millis(); +uint8_t sx128x::modemStatus() { + // imitate the register status from the sx1276 / 78 + uint8_t buf[2] = {0}; - bool header_detected = false; - bool carrier_detected = false; + executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); - if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) { header_detected = true; carrier_detected = true; } - else { header_detected = false; } + uint8_t clearbuf[2] = {0}; + + uint8_t byte = 0x00; if ((buf[0] & IRQ_PREAMBLE_DET_MASK_8X) != 0) { - carrier_detected = true; - if (_preamble_detected_at == 0) { _preamble_detected_at = now; } - if (now - _preamble_detected_at > _lora_preamble_time_ms + _lora_header_time_ms) { - _preamble_detected_at = 0; - if (!header_detected) { false_preamble_detected = true; } - uint8_t clearbuf[2] = {0}; clearbuf[0] = IRQ_PREAMBLE_DET_MASK_8X; - executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2); - } + byte = byte | 0x01 | 0x04; + // clear register after reading + clearbuf[0] = IRQ_PREAMBLE_DET_MASK_8X; } - // TODO: Maybe there's a way of unlatching the RSSI - // status without re-activating receive mode? - if (false_preamble_detected) { receive(); } - return carrier_detected; + if ((buf[1] & IRQ_HEADER_DET_MASK_8X) != 0) { + byte = byte | 0x02 | 0x04; + } + + executeOpcode(OP_CLEAR_IRQ_STATUS_8X, clearbuf, 2); + + return byte; } + uint8_t sx128x::currentRssiRaw() { uint8_t byte = 0; executeOpcodeRead(OP_CURRENT_RSSI_8X, &byte, 1); @@ -1952,7 +2027,7 @@ uint8_t sx128x::packetRssiRaw() { return buf[0]; } -int ISR_VECT sx128x::packetRssi(uint8_t pkt_snr_raw) { +int ISR_VECT sx128x::packetRssi() { // may need more calculations here uint8_t buf[5] = {0}; executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); @@ -1968,7 +2043,7 @@ uint8_t ISR_VECT sx128x::packetSnrRaw() { float ISR_VECT sx128x::packetSnr() { uint8_t buf[5] = {0}; - executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); + executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 3); return float(buf[1]) * 0.25; } @@ -2004,37 +2079,20 @@ int ISR_VECT sx128x::available() int ISR_VECT sx128x::read() { - if (!available()) { - return -1; - } + if (!available()) { + return -1; + } - // if received new packet - if (_packetIndex == 0) { - uint8_t rxbuf[2] = {0}; - executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); - int size; - // If implicit header mode is enabled, read packet length as payload length instead. - // See SX1280 datasheet v3.2, page 92 - if (_implicitHeaderMode == 0x80) { - size = _payloadLength; - } else { - size = rxbuf[0]; - } - _fifo_rx_addr_ptr = rxbuf[1]; - - if (size > 255) { size = 255; } - - readBuffer(_packet, size); - } - - uint8_t byte = _packet[_packetIndex]; - _packetIndex++; - return byte; + uint8_t byte = _packet[_packetIndex]; + _packetIndex++; + return byte; } int sx128x::peek() { - if (!available()) { return -1; } + if (!available()) { + return -1; + } uint8_t b = _packet[_packetIndex]; return b; @@ -2058,16 +2116,9 @@ void sx128x::onReceive(void(*callback)(uint8_t, int)) buf[0] = 0xFF; buf[1] = 0xFF; - // On the SX1280, no RxDone IRQ is generated if a packet is received with - // an invalid header, but the modem will be taken out of single RX mode. - // This can cause the modem to not receive packets until it is reset - // again. This is documented as Errata 16.2 in the SX1280 datasheet v3.2 - // (page 150) Below, the header error IRQ is mapped to dio0 so that the - // modem can be set into RX mode again on reception of a corrupted - // header. // set dio0 masks buf[2] = 0x00; - buf[3] = IRQ_RX_DONE_MASK_8X | IRQ_HEADER_ERROR_MASK_8X; + buf[3] = IRQ_RX_DONE_MASK_8X; // set dio1 masks buf[4] = 0x00; @@ -2078,19 +2129,19 @@ void sx128x::onReceive(void(*callback)(uint8_t, int)) buf[7] = 0x00; executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0)); -#endif +//#ifdef SPI_HAS_NOTUSINGINTERRUPT +// _spiModem.usingInterrupt(digitalPinToInterrupt(_dio0)); +//#endif // make function available - extern void (*onIntRise[INTERFACE_COUNT])(void); + extern void onDio0Rise(); - attachInterrupt(digitalPinToInterrupt(_dio0), onIntRise[_index], RISING); + attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING); } else { detachInterrupt(digitalPinToInterrupt(_dio0)); -#ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->notUsingInterrupt(digitalPinToInterrupt(_dio0)); -#endif +//#ifdef SPI_HAS_NOTUSINGINTERRUPT +// _spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0)); +//#endif } } @@ -2109,12 +2160,7 @@ void sx128x::receive(int size) rxAntEnable(); - // On the SX1280, there is a bug which can cause the busy line - // to remain high if a high amount of packets are received when - // in continuous RX mode. This is documented as Errata 16.1 in - // the SX1280 datasheet v3.2 (page 149) - // Therefore, the modem is set to single RX mode below instead. - uint8_t mode[3] = {0}; // single RX mode + uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode executeOpcode(OP_RX_8X, mode, 3); } @@ -2146,113 +2192,14 @@ void sx128x::disableTCXO() { } void sx128x::setTxPower(int level, int outputPin) { - uint8_t tx_buf[2]; - #if BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_14 || BOARD_VARIANT == MODEL_21 - // RAK4631 with WisBlock SX1280 module (LIBSYS002 rev 1.3) - // Power range on this model is roughly -6 dBm to 20 dBm - if (level > 20) { level = 20; } - else if (level < -6) { level = -6; } - - _txp = level; - - int reg_value; - - switch (level) { - case -6: - reg_value = -18; // -6.3 dBm - break; - case -5: - reg_value = -17; // -5.4 dBm - break; - case -4: - reg_value = -16; // -3.9 dBm - break; - case -3: - reg_value = -15; // -2.9 dBm - break; - case -2: - reg_value = -14; // -2 dBm - break; - case -1: - reg_value = -13; // CANNOT SET, BUG?? - break; - case 0: - reg_value = -12; // -0.4 dBm - break; - case 1: - reg_value = -10; // 1.1 dBm - break; - case 2: - reg_value = -9; // 2.4 dBm - break; - case 3: - reg_value = -8; // 3 dBm - break; - case 4: - reg_value = -7; // 4.1 dBm - break; - case 5: - reg_value = -6; // 5.1 dBm - break; - case 6: - reg_value = -5; // 6 dBm - break; - case 7: - reg_value = -4; // 7.3 dBm - break; - case 8: - reg_value = -3; // 8.3 dBm - break; - case 9: - reg_value = -2; // 9.2 dBm - break; - case 10: - reg_value = -1; // 10.3 dBm - break; - case 11: - reg_value = 0; // 11.4 dBm - break; - case 12: - reg_value = 1; // 12.4 dBm - break; - case 13: - reg_value = 2; // 13.5 dBm - break; - case 14: - reg_value = 2; // 13.5 dBm - break; - case 15: - reg_value = 3; // 14.3 dBm - break; - case 16: - reg_value = 5; // 16.4 dBm - break; - case 17: - reg_value = 6; // 17.1 dBm - break; - case 18: - reg_value = 8; // 18.5 dBm - break; - case 19: - reg_value = 10; // 19.2 dBm - break; - case 20: - reg_value = 13; // 20.1 dBm - break; - default: - reg_value = -18; - break; - } - - tx_buf[0] = reg_value + 18; - tx_buf[1] = 0xE0; // ramping time - 20 microseconds - - executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); - - #elif BOARD_VARIANT == MODEL_AC - // T3S3 SX1280 PA - if (level > 20) { level = 20; } - else if (level < 0) { level = 0; } + // PA calculation currently only works for the LoRa1280F27. Support for + // other assemblies would be appreciated in a PR. + if (outputPin == PA_OUTPUT_PA_BOOST_PIN) { + if (level > 27) { + level = 27; + } else if (level < 0) { + level = 0; + } _txp = level; @@ -2322,30 +2269,56 @@ void sx128x::setTxPower(int level, int outputPin) { case 20: reg_value = 3; break; - default: - reg_value = 0; + case 21: + reg_value = 4; + break; + case 22: + reg_value = 5; + break; + case 23: + reg_value = 6; + break; + case 24: + reg_value = 8; + break; + case 25: + reg_value = 9; + break; + case 26: + reg_value = 12; + break; + case 27: + reg_value = 13; break; } + + uint8_t tx_buf[2]; + tx_buf[0] = reg_value; tx_buf[1] = 0xE0; // ramping time - 20 microseconds - #else - // For SX1280 boards with no specific PA requirements + + executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); + } else { if (level > 13) { level = 13; } else if (level < -18) { level = -18; } - _txp = level; - tx_buf[0] = level + 18; + level = level + 18; + + uint8_t tx_buf[2]; + + tx_buf[0] = level; tx_buf[1] = 0xE0; // ramping time - 20 microseconds - #endif - executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); + + executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); + } } -int8_t sx128x::getTxPower() { +uint8_t sx128x::getTxPower() { return _txp; } @@ -2403,8 +2376,7 @@ uint32_t sx128x::getSignalBandwidth() } void sx128x::handleLowDataRate(){ - if (_sf > 10) { _ldro = true; } - else { _ldro = false; } + // todo: do i need this?? } void sx128x::optimizeModemSensitivity(){ @@ -2413,10 +2385,15 @@ void sx128x::optimizeModemSensitivity(){ void sx128x::setSignalBandwidth(uint32_t sbw) { - if (sbw <= 203.125E3) { _bw = 0x34; } - else if (sbw <= 406.25E3) { _bw = 0x26; } - else if (sbw <= 812.5E3) { _bw = 0x18; } - else { _bw = 0x0A; } + if (sbw <= 203.125E3) { + _bw = 0x34; + } else if (sbw <= 406.25E3) { + _bw = 0x26; + } else if (sbw <= 812.5E3) { + _bw = 0x18; + } else { + _bw = 0x0A; + } setModulationParams(_sf, _bw, _cr); @@ -2424,8 +2401,8 @@ void sx128x::setSignalBandwidth(uint32_t sbw) optimizeModemSensitivity(); } -void sx128x::setCodingRate4(int denominator) { - // TODO: add support for new interleaving scheme, see page 117 of sx1280 datasheet +void sx128x::setCodingRate4(int denominator) +{ if (denominator < 5) { denominator = 5; } else if (denominator > 8) { @@ -2470,12 +2447,9 @@ void sx128x::disableCrc() setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } -uint8_t sx128x::random() +byte sx128x::random() { // todo: implement - return 0x4; //chosen by fair die roll - //guarenteed to be random - //https://xkcd.com/221/ } void sx128x::setSPIFrequency(uint32_t frequency) @@ -2509,26 +2483,6 @@ void sx128x::implicitHeaderMode() void sx128x::handleDio0Rise() { - // received a packet - _packetIndex = 0; - - uint8_t rxbuf[2] = {0}; - executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); - - // If implicit header mode is enabled, read packet length as payload length instead. - // See SX1280 datasheet v3.2, page 92 - if (_implicitHeaderMode == 0x80) { - _rxPacketLength = _payloadLength; - } else { - _rxPacketLength = rxbuf[0]; - } - - if (_onReceive) { - _onReceive(_index, _rxPacketLength); - } -} - -bool ISR_VECT sx128x::getPacketValidity() { uint8_t buf[2]; buf[0] = 0x00; @@ -2539,8 +2493,55 @@ bool ISR_VECT sx128x::getPacketValidity() { executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2); if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_8X) == 0) { - return true; - } else { - return false; + // received a packet + _packetIndex = 0; + + uint8_t rxbuf[2] = {0}; + executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); + _rxPacketLength = rxbuf[0]; + _fifo_rx_addr_ptr = rxbuf[1]; + readBuffer(_packet, _rxPacketLength); + + if (_onReceive) { + _onReceive(_index, _rxPacketLength); + } + } } + +void sx128x::updateBitrate() { + if (_radio_online) { + _lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf)); + _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; + + float target_preamble_symbols; + 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; + } + if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { + target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; + } else { + target_preamble_symbols = ceil(target_preamble_symbols); + } + _preambleLength = (long)target_preamble_symbols; + setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); + } else { + _bitrate = 0; + } +} + +void sx128x::clearIRQStatus() { + uint8_t buf[2]; + + buf[0] = 0x00; + buf[1] = 0x00; + + executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); + + executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2); +} diff --git a/Radio.hpp b/Radio.h similarity index 56% rename from Radio.hpp rename to Radio.h index f798e92..13bb0da 100644 --- a/Radio.hpp +++ b/Radio.h @@ -1,7 +1,7 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. -// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva +// Modifications and additions copyright 2023 by Mark Qvist & Jacob Eva // Obviously still under the MIT license. #ifndef RADIO_H @@ -11,7 +11,6 @@ #include #include "Interfaces.h" #include "Boards.h" -#include "src/misc/FIFOBuffer.h" #define MAX_PKT_LENGTH 255 @@ -19,15 +18,6 @@ #define PA_OUTPUT_RFO_PIN 0 #define PA_OUTPUT_PA_BOOST_PIN 1 -// Default LoRa settings -#define PHY_HEADER_LORA_SYMBOLS 20 -#define PHY_CRC_LORA_BITS 16 -#define LORA_PREAMBLE_SYMBOLS_MIN 18 -#define LORA_PREAMBLE_TARGET_MS 24 -#define LORA_PREAMBLE_FAST_DELTA 18 -#define LORA_FAST_THRESHOLD_BPS 30E3 -#define LORA_LIMIT_THRESHOLD_BPS 60E3 - // DCD #define STATUS_INTERVAL_MS 3 #define DCD_SAMPLES 2500 @@ -38,31 +28,20 @@ #define AIRTIME_BINLEN_MS (STATUS_INTERVAL_MS*DCD_SAMPLES) #define AIRTIME_BINS ((AIRTIME_LONGTERM*1000)/AIRTIME_BINLEN_MS) #define current_airtime_bin(void) (millis()%AIRTIME_LONGTERM_MS)/AIRTIME_BINLEN_MS - - -// CSMA Parameters -#define CSMA_SIFS_MS 0 -#define CSMA_POST_TX_YIELD_SLOTS 3 -#define CSMA_SLOT_MAX_MS 100 -#define CSMA_SLOT_MIN_MS 24 -#define CSMA_SLOT_MIN_FAST_DELTA 18 -#define CSMA_SLOT_SYMBOLS 12 -#define CSMA_CW_BANDS 4 -#define CSMA_CW_MIN 0 -#define CSMA_CW_PER_BAND_WINDOWS 15 -#define CSMA_BAND_1_MAX_AIRTIME 7 -#define CSMA_BAND_N_MIN_AIRTIME 85 -#define CSMA_INFR_THRESHOLD_DB 12 - -#define LED_ID_TRIG 16 - -#define NOISE_FLOOR_SAMPLES 64 +#define DCD_THRESHOLD 2 +#define DCD_LED_STEP_D 3 +#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_FAST_BITRATE_THRESHOLD 40000 #define RSSI_OFFSET 157 #define PHY_HEADER_LORA_SYMBOLS 8 -#define MODEM_TIMEOUT_MULT 1.5 +#define _e 2.71828183 +#define _S 10.0 // Status flags const uint8_t SIG_DETECT = 0x01; @@ -71,13 +50,9 @@ const uint8_t RX_ONGOING = 0x04; // forward declare Utilities.h LED functions void led_rx_on(); -void led_rx_off(); -void led_id_on(); -void led_id_off(); -void led_indicate_airtime_lock(); -void kiss_indicate_channel_stats(uint8_t index); -void kiss_indicate_csma_stats(uint8_t index); +void led_rx_off(); +void led_indicate_airtime_lock(); #if PLATFORM == PLATFORM_ESP32 // get update_lock for ESP32 @@ -87,28 +62,25 @@ extern portMUX_TYPE update_lock; class RadioInterface : public Stream { public: // todo: in the future define _spiModem and _spiSettings from here for inheritence by child classes - RadioInterface(uint8_t index) : _index(index), _sf(0x07), _radio_locked(false), + RadioInterface(uint8_t index) : _index(index), _radio_locked(false), _radio_online(false), _st_airtime_limit(0.0), _lt_airtime_limit(0.0), - _airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0), _last_packet_cost(0.0), + _airtime_lock(false), _airtime(0.0), _longterm_airtime(0.0), _local_channel_util(0.0), _total_channel_util(0.0), _longterm_channel_util(0.0), _last_status_update(0), _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_sample(0), - _csma_slot_ms(CSMA_SLOT_MIN_MS), - _preambleLength(LORA_PREAMBLE_SYMBOLS_MIN), _lora_symbol_time_ms(0.0), - _lora_preamble_time_ms(0), _lora_header_time_ms(0), _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0), - _packet{0}, _onReceive(NULL), _txp(0), _ldro(false), _limit_rate(false), _interference_detected(false), _avoid_interference(true), _difs_ms(CSMA_SIFS_MS + 2 * _csma_slot_ms), _difs_wait_start(0), _cw_wait_start(0), _cw_wait_target(0), _cw_wait_passed(0), _csma_cw(-1), _cw_band(1), _cw_min(0), _cw_max(CSMA_CW_PER_BAND_WINDOWS), _noise_floor_sampled(false), _noise_floor_sample(0), _noise_floor_buffer({0}), _noise_floor(-292), _led_id_filter(0), _preamble_detected_at(0) {}; - - virtual void reset() = 0; - + _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), + _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0), + _packet{0}, _onReceive(NULL) {}; virtual int begin() = 0; virtual void end() = 0; virtual int beginPacket(int implicitHeader = false) = 0; virtual int endPacket() = 0; - virtual int packetRssi(uint8_t pkt_snr_raw = 0xFF) = 0; + virtual int packetRssi() = 0; virtual int currentRssi() = 0; virtual uint8_t packetRssiRaw() = 0; virtual uint8_t currentRssiRaw() = 0; @@ -133,7 +105,7 @@ public: virtual void sleep() = 0; virtual bool preInit() = 0; - virtual int8_t getTxPower() = 0; + virtual uint8_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; @@ -144,49 +116,19 @@ public: virtual void setCodingRate4(int denominator) = 0; virtual uint8_t getCodingRate4() = 0; virtual void setPreambleLength(long length) = 0; - virtual bool dcd() = 0; + virtual uint8_t modemStatus() = 0; virtual void enableCrc() = 0; virtual void disableCrc() = 0; virtual void enableTCXO() = 0; virtual void disableTCXO() = 0; - virtual uint8_t random() = 0; + virtual byte random() = 0; virtual void setSPIFrequency(uint32_t frequency) = 0; - void updateBitrate() { - if (!_radio_online) { _bitrate = 0; } - else { - _lora_symbol_rate = (float)getSignalBandwidth()/(float)(pow(2, _sf)); - _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; - _bitrate = (uint32_t)(_sf * ( (4.0/(float)getCodingRate4()) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); - _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - - bool fast_rate = _bitrate > LORA_FAST_THRESHOLD_BPS; - _limit_rate = _bitrate > LORA_LIMIT_THRESHOLD_BPS; - - int csma_slot_min_ms = CSMA_SLOT_MIN_MS; - float lora_preamble_target_ms = LORA_PREAMBLE_TARGET_MS; - if (fast_rate) { csma_slot_min_ms -= CSMA_SLOT_MIN_FAST_DELTA; - lora_preamble_target_ms -= LORA_PREAMBLE_FAST_DELTA; } - - _csma_slot_ms = _lora_symbol_time_ms*CSMA_SLOT_SYMBOLS; - 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; } - _difs_ms = CSMA_SIFS_MS + 2*_csma_slot_ms; - - float target_preamble_symbols = lora_preamble_target_ms/_lora_symbol_time_ms; - if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; } - else { target_preamble_symbols = (ceil)(target_preamble_symbols); } - - setPreambleLength(target_preamble_symbols); - _lora_preamble_time_ms = (ceil)(_preambleLength * _lora_symbol_time_ms); - _lora_header_time_ms = (ceil)(PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms); - - } - } + virtual void updateBitrate() = 0; virtual void handleDio0Rise() = 0; - virtual bool getPacketValidity() = 0; + virtual void clearIRQStatus() = 0; uint32_t getBitrate() { return _bitrate; }; uint8_t getIndex() { return _index; }; void setRadioLock(bool lock) { _radio_locked = lock; }; @@ -226,182 +168,131 @@ public: } _longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS; - updateCSMAParameters(); - kiss_indicate_channel_stats(_index); + updateCSMAp(); + + //kiss_indicate_channel_stats(); // todo: enable me! }; - float getAirtime(uint16_t written) { - float lora_symbols = 0; + void addAirtime(uint16_t written) { float packet_cost_ms = 0.0; - - if (interfaces[_index] == SX1276 || interfaces[_index] == SX1278) { - lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS); - lora_symbols /= 4*(_sf-2*_ldro); - lora_symbols *= getCodingRate4(); - lora_symbols += _preambleLength + 0.25 + 8; - packet_cost_ms += lora_symbols * _lora_symbol_time_ms; - } - else if (interfaces[_index] == SX1262 || interfaces[_index] == SX1280) { - if (_sf < 7) { - lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + PHY_HEADER_LORA_SYMBOLS); - lora_symbols /= 4*_sf; - lora_symbols *= getCodingRate4(); - lora_symbols += _preambleLength + 2.25 + 8; - packet_cost_ms += lora_symbols * _lora_symbol_time_ms; - - } else { - lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*_sf + 8 + PHY_HEADER_LORA_SYMBOLS); - lora_symbols /= 4*(_sf-2*_ldro); - lora_symbols *= getCodingRate4(); - lora_symbols += _preambleLength + 0.25 + 8; - packet_cost_ms += lora_symbols * _lora_symbol_time_ms; - } - } - _last_packet_cost = packet_cost_ms; - return packet_cost_ms; - } - void addAirtime() { + float payload_cost_ms = ((float)written * _lora_us_per_byte)/1000.0; + packet_cost_ms += payload_cost_ms; + packet_cost_ms += (_preambleLength+4.25)*_lora_symbol_time_ms; + packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * _lora_symbol_time_ms; uint16_t cb = current_airtime_bin(); uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; } - _airtime_bins[cb] += _last_packet_cost; + _airtime_bins[cb] += packet_cost_ms; _airtime_bins[nb] = 0; }; - void updateModemStatus() { - #if MCU_VARIANT == MCU_ESP32 - portENTER_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portENTER_CRITICAL(); - #endif - - bool carrier_detected = dcd(); - int current_rssi = currentRssi(); - _last_status_update = millis(); - - #if MCU_VARIANT == MCU_ESP32 - portEXIT_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portEXIT_CRITICAL(); - #endif - - _interference_detected = !carrier_detected && (current_rssi > (_noise_floor+CSMA_INFR_THRESHOLD_DB)); - if (_interference_detected) { if (_led_id_filter < LED_ID_TRIG) { _led_id_filter += 1; } } - else { if (_led_id_filter > 0) {_led_id_filter -= 1; } } - - if (carrier_detected) { _dcd = true; } else { _dcd = false; } - - _dcd_led = _dcd; - if (_dcd_led) { led_rx_on(); } - else { - if (_interference_detected) { - if (_led_id_filter >= LED_ID_TRIG && _noise_floor_sampled) { led_id_on(); } - } else { - if (_airtime_lock) { led_indicate_airtime_lock(); } - else { led_rx_off(); led_id_off(); } - } - } - } - void updateNoiseFloor() { - int current_rssi = currentRssi(); - if (!_dcd) { - if (!_noise_floor_sampled || current_rssi < _noise_floor + CSMA_INFR_THRESHOLD_DB) { - _noise_floor_buffer[_noise_floor_sample] = current_rssi; - _noise_floor_sample = _noise_floor_sample+1; - if (_noise_floor_sample >= NOISE_FLOOR_SAMPLES) { - _noise_floor_sample %= NOISE_FLOOR_SAMPLES; - _noise_floor_sampled = true; - } - - if (_noise_floor_sampled) { - _noise_floor = 0; - for (int ni = 0; ni < NOISE_FLOOR_SAMPLES; ni++) { _noise_floor += _noise_floor_buffer[ni]; } - _noise_floor /= NOISE_FLOOR_SAMPLES; - } - } - } - } void checkModemStatus() { if (millis()-_last_status_update >= STATUS_INTERVAL_MS) { updateModemStatus(); - updateNoiseFloor(); - - _util_samples[_dcd_sample] = _dcd; - _dcd_sample = (_dcd_sample+1)%DCD_SAMPLES; - if (_dcd_sample % UTIL_UPDATE_INTERVAL == 0) { + + _util_samples[_dcd_sample] = _dcd; + _dcd_sample = (_dcd_sample+1)%DCD_SAMPLES; + if (_dcd_sample % UTIL_UPDATE_INTERVAL == 0) { int util_count = 0; for (int ui = 0; ui < DCD_SAMPLES; ui++) { - if (_util_samples[ui]) util_count++; + if (_util_samples[ui]) util_count++; } _local_channel_util = (float)util_count / (float)DCD_SAMPLES; _total_channel_util = _local_channel_util + _airtime; if (_total_channel_util > 1.0) _total_channel_util = 1.0; - + int16_t cb = current_airtime_bin(); uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; } if (_total_channel_util > _longterm_bins[cb]) _longterm_bins[cb] = _total_channel_util; _longterm_bins[nb] = 0.0; - + updateAirtime(); - } + } } }; - void updateCSMAParameters() { - int airtime_pct = (int)(_airtime*100); - int new_cw_band = _cw_band; + void updateModemStatus() { + #if PLATFORM == PLATFORM_ESP32 + portENTER_CRITICAL(&update_lock); + #elif PLATFORM == PLATFORM_NRF52 + portENTER_CRITICAL(); + #endif + + uint8_t status = modemStatus(); + + _last_status_update = millis(); + + #if PLATFORM == PLATFORM_ESP32 + portEXIT_CRITICAL(&update_lock); + #elif PLATFORM == PLATFORM_NRF52 + portEXIT_CRITICAL(); + #endif + + if ((status & SIG_DETECT) == SIG_DETECT) { _stat_signal_detected = true; } else { _stat_signal_detected = false; } + if ((status & SIG_SYNCED) == SIG_SYNCED) { _stat_signal_synced = true; } else { _stat_signal_synced = false; } + if ((status & RX_ONGOING) == RX_ONGOING) { _stat_rx_ongoing = true; } else { _stat_rx_ongoing = false; } + + // if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) { + if (_stat_signal_detected || _stat_signal_synced) { + if (_stat_rx_ongoing) { + if (_dcd_count < DCD_THRESHOLD) { + _dcd_count++; + } else { + _last_dcd = _last_status_update; + _dcd_led = true; + _dcd = true; + } + } + } else { + if (_dcd_count == 0) { + _dcd_led = false; + } else if (_dcd_count > DCD_LED_STEP_D) { + _dcd_count -= DCD_LED_STEP_D; + } else { + _dcd_count = 0; + } + + if (_last_status_update > _last_dcd+_csma_slot_ms) { + _dcd = false; + _dcd_led = false; + _dcd_count = 0; + } + } - if (airtime_pct <= CSMA_BAND_1_MAX_AIRTIME) { new_cw_band = 1; } - else { - int at = airtime_pct + CSMA_BAND_1_MAX_AIRTIME; - new_cw_band = map(at, CSMA_BAND_1_MAX_AIRTIME, CSMA_BAND_N_MIN_AIRTIME, 2, CSMA_CW_BANDS); - } - - if (new_cw_band > CSMA_CW_BANDS) { new_cw_band = CSMA_CW_BANDS; } - if (new_cw_band != _cw_band) { - _cw_band = (uint8_t)(new_cw_band); - _cw_min = (_cw_band-1) * CSMA_CW_PER_BAND_WINDOWS; - _cw_max = (_cw_band) * CSMA_CW_PER_BAND_WINDOWS - 1; - kiss_indicate_csma_stats(_index); - } - } + + if (_dcd_led) { + led_rx_on(); + } else { + if (_airtime_lock) { + led_indicate_airtime_lock(); + } else { + led_rx_off(); + } + } + }; + void setPostTxYieldTimeout(uint32_t timeout) { _post_tx_yield_timeout = timeout; }; + uint32_t getPostTxYieldTimeout() { return _post_tx_yield_timeout; }; void setDCD(bool dcd) { _dcd = dcd; }; bool getDCD() { return _dcd; }; void setDCDWaiting(bool dcd_waiting) { _dcd_waiting = dcd_waiting; }; bool getDCDWaiting() { return _dcd_waiting; }; + void setDCDWaitUntil(uint32_t dcd_wait_until) { _dcd_wait_until = dcd_wait_until; }; + bool getDCDWaitUntil() { return _dcd_wait_until; }; float getAirtime() { return _airtime; }; float getLongtermAirtime() { return _longterm_airtime; }; float getTotalChannelUtil() { return _total_channel_util; }; 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); + }; + uint8_t getCSMAp() { return _csma_p; }; void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; }; int getCSMASlotMS() { return _csma_slot_ms; }; float getSymbolTime() { return _lora_symbol_time_ms; }; float getSymbolRate() { return _lora_symbol_rate; }; long getPreambleLength() { return _preambleLength; }; - void setAvdInterference(bool cfg) { _avoid_interference = cfg; }; - bool getAvdInterference() { return _avoid_interference; }; - bool getInterference() { return _interference_detected; }; - int getNoiseFloor() { return _noise_floor; }; - unsigned long getDifsMS() { return _difs_ms; }; - uint8_t getCWBand() { return _cw_band; }; - uint8_t getCWMin() { return _cw_min; }; - uint8_t getCWMax() { return _cw_max; }; - uint8_t getCW() { return _csma_cw; }; - void setCW(uint8_t cw) { _csma_cw = cw; }; - void setCWWaitTarget(unsigned long target) { _cw_wait_target = target; }; - unsigned long getCWWaitTarget() { return _cw_wait_target; }; - unsigned long getDifsWaitStart() { return _difs_wait_start; }; - void setDifsWaitStart(unsigned long start) { _difs_wait_start = start; }; - unsigned long getCWWaitStart() { return _cw_wait_start; }; - void setCWWaitStart(unsigned long start) { _cw_wait_start = start; }; - void addCWWaitPassed(unsigned long start) { _cw_wait_passed += start; }; - void resetCWWaitPassed() { _cw_wait_passed = 0; }; - bool getCWWaitStatus() { return _cw_wait_passed < _cw_wait_target; }; - bool getLimitRate() { return _limit_rate; }; protected: virtual void explicitHeaderMode() = 0; virtual void implicitHeaderMode() = 0; uint8_t _index; - uint32_t _bitrate; - int8_t _txp; - uint8_t _sf; bool _radio_locked; bool _radio_online; float _st_airtime_limit; @@ -411,7 +302,6 @@ protected: uint16_t _longterm_bins[AIRTIME_BINS] = {0}; float _airtime; float _longterm_airtime; - float _last_packet_cost; float _local_channel_util; float _total_channel_util; float _longterm_channel_util; @@ -424,53 +314,35 @@ protected: bool _dcd; bool _dcd_led; bool _dcd_waiting; + long _dcd_wait_until; bool _util_samples[DCD_SAMPLES] = {false}; int _dcd_sample; + uint32_t _post_tx_yield_timeout; + uint8_t _csma_p; + int _csma_slot_ms; + float _csma_p_min; + float _csma_p_max; long _preambleLength; float _lora_symbol_time_ms; float _lora_symbol_rate; float _lora_us_per_byte; - long _lora_preamble_time_ms; - long _lora_header_time_ms; - bool _ldro; - bool _limit_rate; - bool _interference_detected; - bool _avoid_interference; - int _csma_slot_ms; - unsigned long _difs_ms; - unsigned long _difs_wait_start; - unsigned long _cw_wait_start; - unsigned long _cw_wait_target; - unsigned long _cw_wait_passed; - int _csma_cw; - uint8_t _cw_band; - uint8_t _cw_min; - uint8_t _cw_max; - bool _noise_floor_sampled; - int _noise_floor_sample; - int _noise_floor_buffer[NOISE_FLOOR_SAMPLES]; - int _noise_floor; - uint8_t _led_id_filter; - unsigned long _preamble_detected_at; - - uint8_t _packet[255]; + uint32_t _bitrate; + uint8_t _packet[255]; void (*_onReceive)(uint8_t, int); }; class sx126x : public RadioInterface { public: - sx126x(uint8_t index, SPIClass* spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int + sx126x(uint8_t index, SPIClass spi, bool tcxo, bool dio2_as_rf_switch, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen); - void reset(); - int begin(); void end(); int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(uint8_t pkt_snr_raw = 0xFF); + int packetRssi(); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -495,7 +367,7 @@ public: void sleep(); bool preInit(); - int8_t getTxPower(); + uint8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -506,7 +378,7 @@ public: void setCodingRate4(int denominator); uint8_t getCodingRate4(); void setPreambleLength(long length); - bool dcd(); + uint8_t modemStatus(); void enableCrc(); void disableCrc(); void enableTCXO(); @@ -519,6 +391,8 @@ public: void dumpRegisters(Stream& out); + void updateBitrate(); + void handleDio0Rise(); private: void writeBuffer(const uint8_t* buffer, size_t size); @@ -544,13 +418,14 @@ private: void handleLowDataRate(); void optimizeModemSensitivity(); + void reset(void); void calibrate(void); void calibrate_image(uint32_t frequency); - bool getPacketValidity(); + void clearIRQStatus(); private: SPISettings _spiSettings; - SPIClass* _spiModem; + SPIClass _spiModem; int _ss; int _sclk; int _mosi; @@ -560,8 +435,11 @@ private: int _rxen; int _busy; uint32_t _frequency; + int _txp; + uint8_t _sf; uint8_t _bw; uint8_t _cr; + uint8_t _ldro; int _packetIndex; int _implicitHeaderMode; int _payloadLength; @@ -569,15 +447,14 @@ private: int _fifo_tx_addr_ptr; int _fifo_rx_addr_ptr; bool _preinit_done; + uint8_t _index; bool _tcxo; bool _dio2_as_rf_switch; }; class sx127x : public RadioInterface { public: - sx127x(uint8_t index, SPIClass* spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy); - - void reset(); + sx127x(uint8_t index, SPIClass spi, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy); int begin(); void end(); @@ -585,7 +462,6 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(uint8_t pkt_snr_raw = 0xFF); int packetRssi(); int currentRssi(); uint8_t packetRssiRaw(); @@ -611,7 +487,7 @@ public: void sleep(); bool preInit(); - int8_t getTxPower(); + uint8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -622,7 +498,7 @@ public: void setCodingRate4(int denominator); uint8_t getCodingRate4(); void setPreambleLength(long length); - bool dcd(); + uint8_t modemStatus(); void enableCrc(); void disableCrc(); void enableTCXO(); @@ -632,8 +508,10 @@ public: void setSPIFrequency(uint32_t frequency); + void updateBitrate(); + void handleDio0Rise(); - bool getPacketValidity(); + void clearIRQStatus(); private: void setSyncWord(uint8_t sw); void explicitHeaderMode(); @@ -651,7 +529,7 @@ private: private: SPISettings _spiSettings; - SPIClass* _spiModem; + SPIClass _spiModem; int _ss; int _sclk; int _mosi; @@ -663,15 +541,14 @@ private: int _packetIndex; int _implicitHeaderMode; bool _preinit_done; + uint8_t _index; + uint8_t _sf; uint8_t _cr; - uint32_t _bw; }; class sx128x : public RadioInterface { public: - sx128x(uint8_t index, SPIClass* spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen); - - void reset(); + sx128x(uint8_t index, SPIClass spi, bool tcxo, int ss, int sclk, int mosi, int miso, int reset, int dio0, int busy, int rxen, int txen); int begin(); void end(); @@ -679,7 +556,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(uint8_t pkt_snr_raw = 0xFF); + int packetRssi(); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -704,7 +581,7 @@ public: void sleep(); bool preInit(); - int8_t getTxPower(); + uint8_t getTxPower(); void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN); uint32_t getFrequency(); void setFrequency(uint32_t frequency); @@ -715,7 +592,7 @@ public: void setCodingRate4(int denominator); uint8_t getCodingRate4(); void setPreambleLength(long length); - bool dcd(); + uint8_t modemStatus(); void enableCrc(); void disableCrc(); void enableTCXO(); @@ -727,10 +604,11 @@ public: void dumpRegisters(Stream& out); + void updateBitrate(); + void handleDio0Rise(); - bool getPacketValidity(); - + void clearIRQStatus(); private: void writeBuffer(const uint8_t* buffer, size_t size); void readBuffer(uint8_t* buffer, size_t size); @@ -758,7 +636,7 @@ private: private: SPISettings _spiSettings; - SPIClass* _spiModem; + SPIClass _spiModem; int _ss; int _sclk; int _mosi; @@ -770,6 +648,8 @@ private: int _busy; int _modem; uint32_t _frequency; + int _txp; + uint8_t _sf; uint8_t _bw; uint8_t _cr; int _packetIndex; @@ -780,9 +660,7 @@ private: int _fifo_rx_addr_ptr; bool _preinit_done; int _rxPacketLength; + uint8_t _index; bool _tcxo; - uint8_t _preamble_e; - uint8_t _preamble_m; - uint32_t _last_preamble; }; #endif diff --git a/Release/README.md b/Release/README.md index 7152606..bb773ca 100644 --- a/Release/README.md +++ b/Release/README.md @@ -1,5 +1,5 @@ # Precompiled Firmware -The firmware is now handled and installed to RNodes directly through `rnodeconf`, which is inclueded in the `rns` package. It can be installed via `pip`: +You can download and flash the firmware to supported boards using the [RNode Config Utility](https://github.com/markqvist/rnodeconfigutil). All firmware releases are now handled and installed directly through `rnodeconf`, which is inclueded in the `rns` package. It can be installed via `pip`: ``` # Install rnodeconf via rns package diff --git a/Release/console_image.bin b/Release/console_image.bin index 708d901..ee7e5b1 100644 Binary files a/Release/console_image.bin and b/Release/console_image.bin differ diff --git a/Release/esptool/esptool.py b/Release/esptool/esptool.py index e2ec3a0..d1d62b4 100755 --- a/Release/esptool/esptool.py +++ b/Release/esptool/esptool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton, Espressif Systems (Shanghai) CO LTD, other contributors as noted. # diff --git a/Release/esptool/gen_esp32part.py b/Release/esptool/gen_esp32part.py index 3168aa6..273f4e3 100644 --- a/Release/esptool/gen_esp32part.py +++ b/Release/esptool/gen_esp32part.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # ESP32 partition table generation tool # diff --git a/Release/esptool/spiffsgen.py b/Release/esptool/spiffsgen.py index 75ebd61..45f8449 100644 --- a/Release/esptool/spiffsgen.py +++ b/Release/esptool/spiffsgen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # # spiffsgen is a tool used to generate a spiffs image from a directory # diff --git a/Utilities.h b/Utilities.h index 3c0f06e..bd55d4a 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1,4 +1,4 @@ -// Copyright (C) 2024, Mark Qvist +// Copyright (C) 2023, 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,7 +13,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Radio.hpp" +#include "Radio.h" #include "Config.h" // Included for sorting @@ -23,7 +23,6 @@ #if HAS_EEPROM #include #elif PLATFORM == PLATFORM_NRF52 - #include #include #include using namespace Adafruit_LittleFS_Namespace; @@ -36,7 +35,7 @@ #include "ROM.h" #include "Framing.h" -#include "src/misc/MD5.h" +#include "MD5.h" #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 uint8_t eeprom_read(uint32_t mapped_addr); @@ -44,9 +43,6 @@ 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 @@ -62,10 +58,6 @@ uint8_t eeprom_read(uint32_t mapped_addr); #include "Input.h" #endif -#if HAS_GPS - #include "src/misc/gps.h" -#endif - #if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 #include "Device.h" #endif @@ -73,10 +65,10 @@ 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 + #elif BOARD_MODEL == BOARD_RNODE_NG_22 #include "hal/wdt_hal.h" + #else BOARD_MODEL != BOARD_RNODE_NG_22 + #include "soc/rtc_wdt.h" #endif #define ISR_VECT IRAM_ATTR #else @@ -91,63 +83,16 @@ uint8_t boot_vector = 0x00; // TODO: Get NRF52 boot flags #endif -#if MCU_VARIANT == MCU_NRF52 - unsigned long get_rng_seed() { - nrf_rng_error_correction_enable(NRF_RNG); - nrf_rng_shorts_disable(NRF_RNG, NRF_RNG_SHORT_VALRDY_STOP_MASK); - nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START); - while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY)); - uint8_t rb_a = nrf_rng_random_value_get(NRF_RNG); - nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY); - while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY)); - uint8_t rb_b = nrf_rng_random_value_get(NRF_RNG); - nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY); - while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY)); - uint8_t rb_c = nrf_rng_random_value_get(NRF_RNG); - nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY); - while (!nrf_rng_event_check(NRF_RNG, NRF_RNG_EVENT_VALRDY)); - uint8_t rb_d = nrf_rng_random_value_get(NRF_RNG); - nrf_rng_event_clear(NRF_RNG, NRF_RNG_EVENT_VALRDY); - nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP); - return rb_a << 24 | rb_b << 16 | rb_c << 8 | rb_d; - } -#endif - #if HAS_NP == true #include #define NUMPIXELS 1 + #define NP_M 0.15 Adafruit_NeoPixel pixels(NUMPIXELS, pin_np, NEO_GRB + NEO_KHZ800); 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 BOARD_MODEL == BOARD_HELTEC_T114 - // Enable vext power supply to neopixel - pinMode(PIN_VEXT_EN, OUTPUT); - digitalWrite(PIN_VEXT_EN, HIGH); - #endif - - #if MCU_VARIANT == MCU_NRF52 - 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); - } - #else - 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); - } - #endif - } - void npset(uint8_t r, uint8_t g, uint8_t b) { if (pixels_started != true) { pixels.begin(); @@ -156,7 +101,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*npi, npg*npi, npb*npi)); + pixels.setPixelColor(0, pixels.Color(npr*NP_M, npg*NP_M, npb*NP_M)); pixels.show(); } } @@ -182,72 +127,37 @@ uint8_t boot_vector = 0x00; void led_rx_off() { npset(0, 0, 0); } void led_tx_on() { npset(0xFF, 0x50, 0x00); } void led_tx_off() { npset(0, 0, 0); } - void led_id_on() { npset(0x90, 0, 0x70); } - void led_id_off() { npset(0, 0, 0); } #elif BOARD_MODEL == BOARD_RNODE_NG_20 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); } - void led_id_on() { } - void led_id_off() { } #elif BOARD_MODEL == BOARD_RNODE_NG_21 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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_T3S3 + #elif BOARD_MODEL == BOARD_RNODE_NG_22 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); } - void led_id_on() { } - void led_id_off() { } - #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); } - void led_id_on() { } - void led_id_off() { } #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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_TDECK - void led_rx_on() { } - void led_rx_off() { } - void led_tx_on() { } - void led_tx_off() { } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_TBEAM_S_V1 - void led_rx_on() { } - void led_rx_off() { } - void led_tx_on() { } - void led_tx_off() { } - void led_id_on() { } - void led_id_off() { } #elif BOARD_MODEL == BOARD_LORA32_V1_0 #if defined(EXTERNAL_LEDS) 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); } - void led_id_on() { } - void led_id_off() { } #else 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); } - void led_id_on() { } - void led_id_off() { } #endif #elif BOARD_MODEL == BOARD_LORA32_V2_0 #if defined(EXTERNAL_LEDS) @@ -255,15 +165,11 @@ 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); } - void led_id_on() { } - void led_id_off() { } #else void led_rx_on() { digitalWrite(pin_led_rx, LOW); } void led_rx_off() { digitalWrite(pin_led_rx, HIGH); } void led_tx_on() { digitalWrite(pin_led_tx, LOW); } void led_tx_off() { digitalWrite(pin_led_tx, HIGH); } - void led_id_on() { } - void led_id_off() { } #endif #elif BOARD_MODEL == BOARD_HELTEC32_V2 #if defined(EXTERNAL_LEDS) @@ -271,104 +177,47 @@ 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); } - void led_id_on() { } - void led_id_off() { } #else 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); } - void led_id_on() { } - void led_id_off() { } #endif #elif BOARD_MODEL == BOARD_HELTEC32_V3 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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_H_W_PAPER - 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); } - void led_id_on() { } - void led_id_off() { } #elif BOARD_MODEL == BOARD_LORA32_V2_1 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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_XIAO_S3 - void led_rx_on() { digitalWrite(pin_led_rx, LED_ON); } - void led_rx_off() { digitalWrite(pin_led_rx, LED_OFF); } - void led_tx_on() { digitalWrite(pin_led_tx, LED_ON); } - void led_tx_off() { digitalWrite(pin_led_tx, LED_OFF); } - void led_id_on() { } - void led_id_off() { } #elif BOARD_MODEL == BOARD_HUZZAH32 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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_XIAO_S3 - void led_rx_on() {} - void led_rx_off() {} - void led_tx_on() { digitalWrite(pin_led_tx, LED_ON); } - void led_tx_off() { digitalWrite(pin_led_tx, LED_OFF); } - void led_id_on() {} - void led_id_off() {} #elif BOARD_MODEL == BOARD_GENERIC_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); } - void led_id_on() { } - void led_id_off() { } #endif #elif MCU_VARIANT == MCU_NRF52 - #if HAS_NP == true - void led_rx_on() { npset(0, 0, 0xFF); } - void led_rx_off() { npset(0, 0, 0); } - void led_tx_on() { npset(0xFF, 0x50, 0x00); } - void led_tx_off() { npset(0, 0, 0); } - void led_id_on() { npset(0x90, 0, 0x70); } - void led_id_off() { npset(0, 0, 0); } - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL + #if BOARD_MODEL == BOARD_RAK4631 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); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_HELTEC_T114 - // Heltec T114 pulls pins LOW to turn on - void led_rx_on() { digitalWrite(pin_led_rx, LOW); } - void led_rx_off() { digitalWrite(pin_led_rx, HIGH); } - void led_tx_on() { digitalWrite(pin_led_tx, LOW); } - void led_tx_off() { digitalWrite(pin_led_tx, HIGH); } - void led_id_on() { } - void led_id_off() { } - #elif BOARD_MODEL == BOARD_TECHO - void led_rx_on() { digitalWrite(pin_led_rx, LED_ON); } - void led_rx_off() { digitalWrite(pin_led_rx, LED_OFF); } - void led_tx_on() { digitalWrite(pin_led_tx, LED_ON); } - void led_tx_off() { digitalWrite(pin_led_tx, LED_OFF); } - void led_id_on() { } - void led_id_off() { } - #endif + #endif #endif void hard_reset(void) { #if MCU_VARIANT == MCU_ESP32 ESP.restart(); #elif MCU_VARIANT == MCU_NRF52 - NVIC_SystemReset(); + NVIC_SystemReset(); #endif } @@ -496,19 +345,6 @@ void led_indicate_warning(int cycles) { } led_rx_off(); } - #elif BOARD_MODEL == BOARD_TECHO - void led_indicate_info(int cycles) { - bool forever = (cycles == 0) ? true : false; - cycles = forever ? 1 : cycles; - while(cycles > 0) { - led_rx_off(); - delay(100); - led_rx_on(); - delay(100); - if (!forever) cycles--; - } - led_rx_off(); - } #else void led_indicate_info(int cycles) { bool forever = (cycles == 0) ? true : false; @@ -530,8 +366,8 @@ unsigned long led_standby_ticks = 0; #if MCU_VARIANT == MCU_ESP32 #if HAS_NP == true - int led_standby_lng = 200; - int led_standby_cut = 100; + int led_standby_lng = 100; + int led_standby_cut = 200; int led_standby_min = 0; int led_standby_max = 375+led_standby_lng; int led_notready_min = 0; @@ -556,8 +392,6 @@ unsigned long led_standby_ticks = 0; #endif #elif MCU_VARIANT == MCU_NRF52 - int led_standby_lng = 200; - int led_standby_cut = 100; uint8_t led_standby_min = 200; uint8_t led_standby_max = 255; uint8_t led_notready_min = 0; @@ -572,162 +406,158 @@ unsigned long led_standby_ticks = 0; unsigned long led_standby_value = led_standby_min; int8_t led_standby_direction = 0; -#if HAS_NP == true - void led_indicate_standby() { - led_standby_ticks++; +#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 + #if HAS_NP == true + void led_indicate_standby() { + led_standby_ticks++; - if (led_standby_ticks > led_standby_wait) { - led_standby_ticks = 0; - - if (led_standby_value <= led_standby_min) { - led_standby_direction = 1; - } else if (led_standby_value >= led_standby_max) { - led_standby_direction = -1; - } + if (led_standby_ticks > led_standby_wait) { + led_standby_ticks = 0; + + if (led_standby_value <= led_standby_min) { + led_standby_direction = 1; + } else if (led_standby_value >= led_standby_max) { + led_standby_direction = -1; + } - uint8_t led_standby_intensity; - led_standby_value += led_standby_direction; - int led_standby_ti = led_standby_value - led_standby_lng; + uint8_t led_standby_intensity; + led_standby_value += led_standby_direction; + int led_standby_ti = led_standby_value - led_standby_lng; - if (led_standby_ti < 0) { - led_standby_intensity = 0; - } else if (led_standby_ti > led_standby_cut) { - led_standby_intensity = led_standby_cut; - } else { - led_standby_intensity = led_standby_ti; - } - npset(led_standby_intensity/3, led_standby_intensity/3, led_standby_intensity/3); - } - } + if (led_standby_ti < 0) { + led_standby_intensity = 0; + } else if (led_standby_ti > led_standby_cut) { + led_standby_intensity = led_standby_cut; + } else { + led_standby_intensity = led_standby_ti; + } + npset(0x00, 0x00, led_standby_intensity); + } + } - void led_indicate_console() { - npset(0x60, 0x00, 0x60); - // led_standby_ticks++; + void led_indicate_console() { + npset(0x60, 0x00, 0x60); + // led_standby_ticks++; - // if (led_standby_ticks > led_console_wait) { - // led_standby_ticks = 0; - - // if (led_standby_value <= led_standby_min) { - // led_standby_direction = 1; - // } else if (led_standby_value >= led_standby_max) { - // led_standby_direction = -1; - // } + // if (led_standby_ticks > led_console_wait) { + // led_standby_ticks = 0; + + // if (led_standby_value <= led_standby_min) { + // led_standby_direction = 1; + // } else if (led_standby_value >= led_standby_max) { + // led_standby_direction = -1; + // } - // uint8_t led_standby_intensity; - // led_standby_value += led_standby_direction; - // int led_standby_ti = led_standby_value - led_standby_lng; + // uint8_t led_standby_intensity; + // led_standby_value += led_standby_direction; + // int led_standby_ti = led_standby_value - led_standby_lng; - // if (led_standby_ti < 0) { - // led_standby_intensity = 0; - // } else if (led_standby_ti > led_standby_cut) { - // led_standby_intensity = led_standby_cut; - // } else { - // led_standby_intensity = led_standby_ti; - // } -// npset(led_standby_intensity, 0x00, led_standby_intensity); - // } - } + // if (led_standby_ti < 0) { + // led_standby_intensity = 0; + // } else if (led_standby_ti > led_standby_cut) { + // led_standby_intensity = led_standby_cut; + // } else { + // led_standby_intensity = led_standby_ti; + // } + // npset(led_standby_intensity, 0x00, led_standby_intensity); + // } + } -#else - void led_indicate_standby() { - led_standby_ticks++; - if (led_standby_ticks > led_standby_wait) { - led_standby_ticks = 0; - if (led_standby_value <= led_standby_min) { - led_standby_direction = 1; - } else if (led_standby_value >= led_standby_max) { - led_standby_direction = -1; - } - led_standby_value += led_standby_direction; - if (led_standby_value > 253) { - #if BOARD_MODEL == BOARD_TECHO - led_rx_on(); - #else - led_tx_on(); - #endif - } else { - #if BOARD_MODEL == BOARD_TECHO - led_rx_off(); - #else - led_tx_off(); - #endif - } - #if BOARD_MODEL == BOARD_LORA32_V2_1 - #if defined(EXTERNAL_LEDS) - led_rx_off(); - #endif - #elif BOARD_MODEL == BOARD_LORA32_V2_0 - #if defined(EXTERNAL_LEDS) - led_rx_off(); - #endif - #else - led_rx_off(); - #endif - } - } + #else + void led_indicate_standby() { + led_standby_ticks++; + if (led_standby_ticks > led_standby_wait) { + led_standby_ticks = 0; + if (led_standby_value <= led_standby_min) { + led_standby_direction = 1; + } else if (led_standby_value >= led_standby_max) { + led_standby_direction = -1; + } + led_standby_value += led_standby_direction; + if (led_standby_value > 253) { + led_tx_on(); + } else { + led_tx_off(); + } + #if BOARD_MODEL == BOARD_LORA32_V2_1 + #if defined(EXTERNAL_LEDS) + led_rx_off(); + #endif + #elif BOARD_MODEL == BOARD_LORA32_V2_0 + #if defined(EXTERNAL_LEDS) + led_rx_off(); + #endif + #else + led_rx_off(); + #endif + } + } - void led_indicate_console() { - led_indicate_standby(); - } + void led_indicate_console() { + led_indicate_standby(); + } + #endif #endif -#if HAS_NP == true -void led_indicate_not_ready() { - led_standby_ticks++; - - if (led_standby_ticks > led_notready_wait) { - led_standby_ticks = 0; - - if (led_standby_value <= led_standby_min) { - led_standby_direction = 1; - } else if (led_standby_value >= led_standby_max) { - led_standby_direction = -1; - } - - uint8_t led_standby_intensity; - led_standby_value += led_standby_direction; - int led_standby_ti = led_standby_value - led_standby_lng; - - if (led_standby_ti < 0) { - led_standby_intensity = 0; - } else if (led_standby_ti > led_standby_cut) { - led_standby_intensity = led_standby_cut; - } else { - led_standby_intensity = led_standby_ti; - } - - npset(led_standby_intensity, 0x00, 0x00); - } - } -#else +#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 + #if HAS_NP == true void led_indicate_not_ready() { - led_notready_ticks++; - if (led_notready_ticks > led_notready_wait) { - led_notready_ticks = 0; - if (led_notready_value <= led_notready_min) { - led_notready_direction = 1; - } else if (led_notready_value >= led_notready_max) { - led_notready_direction = -1; - } - led_notready_value += led_notready_direction; - if (led_notready_value > 128) { - led_tx_on(); - } else { - led_tx_off(); - } - #if BOARD_MODEL == BOARD_LORA32_V2_1 - #if defined(EXTERNAL_LEDS) - led_rx_off(); - #endif - #elif BOARD_MODEL == BOARD_LORA32_V2_0 - #if defined(EXTERNAL_LEDS) - led_rx_off(); - #endif - #else - led_rx_off(); - #endif - } - } + led_standby_ticks++; + + if (led_standby_ticks > led_notready_wait) { + led_standby_ticks = 0; + + if (led_standby_value <= led_standby_min) { + led_standby_direction = 1; + } else if (led_standby_value >= led_standby_max) { + led_standby_direction = -1; + } + + uint8_t led_standby_intensity; + led_standby_value += led_standby_direction; + int led_standby_ti = led_standby_value - led_standby_lng; + + if (led_standby_ti < 0) { + led_standby_intensity = 0; + } else if (led_standby_ti > led_standby_cut) { + led_standby_intensity = led_standby_cut; + } else { + led_standby_intensity = led_standby_ti; + } + + npset(led_standby_intensity, 0x00, 0x00); + } + } + #else + void led_indicate_not_ready() { + led_notready_ticks++; + if (led_notready_ticks > led_notready_wait) { + led_notready_ticks = 0; + if (led_notready_value <= led_notready_min) { + led_notready_direction = 1; + } else if (led_notready_value >= led_notready_max) { + led_notready_direction = -1; + } + led_notready_value += led_notready_direction; + if (led_notready_value > 128) { + led_tx_on(); + } else { + led_tx_off(); + } + #if BOARD_MODEL == BOARD_LORA32_V2_1 + #if defined(EXTERNAL_LEDS) + led_rx_off(); + #endif + #elif BOARD_MODEL == BOARD_LORA32_V2_0 + #if defined(EXTERNAL_LEDS) + led_rx_off(); + #endif + #else + led_rx_off(); + #endif + } + } + #endif #endif @@ -748,12 +578,6 @@ 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 } #else Serial.write(byte); @@ -782,10 +606,6 @@ void kiss_indicate_error(uint8_t error_code) { void kiss_indicate_radiostate(RadioInterface* radio) { serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_RADIO_STATE); serial_write(radio->getRadioOnline()); serial_write(FEND); @@ -813,11 +633,7 @@ void kiss_indicate_stat_tx() { //serial_write(FEND); } -void kiss_indicate_stat_rssi(RadioInterface* radio) { - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); +void kiss_indicate_stat_rssi() { uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset); serial_write(FEND); serial_write(CMD_STAT_RSSI); @@ -825,11 +641,7 @@ void kiss_indicate_stat_rssi(RadioInterface* radio) { serial_write(FEND); } -void kiss_indicate_stat_snr(RadioInterface* radio) { - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); +void kiss_indicate_stat_snr() { serial_write(FEND); serial_write(CMD_STAT_SNR); escaped_serial_write(last_snr_raw); @@ -838,10 +650,6 @@ void kiss_indicate_stat_snr(RadioInterface* radio) { void kiss_indicate_radio_lock(RadioInterface* radio) { serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_RADIO_LOCK); serial_write(radio->getRadioLock()); serial_write(FEND); @@ -849,10 +657,6 @@ void kiss_indicate_radio_lock(RadioInterface* radio) { void kiss_indicate_spreadingfactor(RadioInterface* radio) { serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_SF); serial_write(radio->getSpreadingFactor()); serial_write(FEND); @@ -860,10 +664,6 @@ void kiss_indicate_spreadingfactor(RadioInterface* radio) { void kiss_indicate_codingrate(RadioInterface* radio) { serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_CR); serial_write(radio->getCodingRate4()); serial_write(FEND); @@ -877,11 +677,7 @@ void kiss_indicate_implicit_length() { } void kiss_indicate_txpower(RadioInterface* radio) { - int8_t txp = radio->getTxPower(); - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); + uint8_t txp = radio->getTxPower(); serial_write(FEND); serial_write(CMD_TXPOWER); serial_write(txp); @@ -891,10 +687,6 @@ void kiss_indicate_txpower(RadioInterface* radio) { void kiss_indicate_bandwidth(RadioInterface* radio) { uint32_t bw = radio->getSignalBandwidth(); serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_BANDWIDTH); escaped_serial_write(bw>>24); escaped_serial_write(bw>>16); @@ -906,10 +698,6 @@ void kiss_indicate_bandwidth(RadioInterface* radio) { void kiss_indicate_frequency(RadioInterface* radio) { uint32_t freq = radio->getFrequency(); serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_FREQUENCY); escaped_serial_write(freq>>24); escaped_serial_write(freq>>16); @@ -930,10 +718,6 @@ void kiss_indicate_interface(int index) { void kiss_indicate_st_alock(RadioInterface* radio) { uint16_t at = (uint16_t)(radio->getSTALock()*100*100); serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_ST_ALOCK); escaped_serial_write(at>>8); escaped_serial_write(at); @@ -943,30 +727,17 @@ void kiss_indicate_st_alock(RadioInterface* radio) { void kiss_indicate_lt_alock(RadioInterface* radio) { uint16_t at = (uint16_t)(radio->getLTALock()*100*100); serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); - serial_write(FEND); serial_write(CMD_LT_ALOCK); escaped_serial_write(at>>8); escaped_serial_write(at); serial_write(FEND); } -void kiss_indicate_channel_stats(uint8_t index) { - RadioInterface* radio = interface_obj[index]; - int current_rssi = radio->currentRssi(); +void kiss_indicate_channel_stats(RadioInterface* radio) { uint16_t ats = (uint16_t)(radio->getAirtime()*100*100); uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100); uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100); uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*100*100); - uint8_t crs = (uint8_t)(current_rssi+rssi_offset); - uint8_t nfl = (uint8_t)(radio->getNoiseFloor()+rssi_offset); - uint8_t ntf = 0xFF; if (radio->getInterference()) { ntf = (uint8_t)(current_rssi+rssi_offset); } - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); serial_write(FEND); serial_write(CMD_STAT_CHTM); escaped_serial_write(ats>>8); @@ -977,9 +748,6 @@ void kiss_indicate_channel_stats(uint8_t index) { escaped_serial_write(cls); escaped_serial_write(cll>>8); escaped_serial_write(cll); - escaped_serial_write(crs); - escaped_serial_write(nfl); - escaped_serial_write(ntf); serial_write(FEND); } @@ -989,42 +757,29 @@ void kiss_indicate_phy_stats(RadioInterface* radio) { uint16_t prs = (uint16_t)(radio->getPreambleLength()+4); uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime()); uint16_t cst = (uint16_t)(radio->getCSMASlotMS()); - uint16_t dft = (uint16_t)(radio->getDifsMS()); - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(radio->getIndex()); - serial_write(FEND); serial_write(FEND); serial_write(CMD_STAT_PHYPRM); - escaped_serial_write(lst>>8); escaped_serial_write(lst); - escaped_serial_write(lsr>>8); escaped_serial_write(lsr); - escaped_serial_write(prs>>8); escaped_serial_write(prs); - escaped_serial_write(prt>>8); escaped_serial_write(prt); - escaped_serial_write(cst>>8); escaped_serial_write(cst); - escaped_serial_write(dft>>8); escaped_serial_write(dft); - serial_write(FEND); -} - -void kiss_indicate_csma_stats(uint8_t index) { - selected_radio = interface_obj[index]; - serial_write(FEND); - serial_write(CMD_SEL_INT); - serial_write(index); - serial_write(FEND); - serial_write(FEND); - serial_write(CMD_STAT_CSMA); - escaped_serial_write(selected_radio->getCWBand()); - escaped_serial_write(selected_radio->getCWMin()); - escaped_serial_write(selected_radio->getCWMax()); + escaped_serial_write(lst>>8); + escaped_serial_write(lst); + escaped_serial_write(lsr>>8); + escaped_serial_write(lsr); + escaped_serial_write(prs>>8); + escaped_serial_write(prs); + escaped_serial_write(prt>>8); + escaped_serial_write(prt); + escaped_serial_write(cst>>8); + escaped_serial_write(cst); serial_write(FEND); } void kiss_indicate_battery() { + #if MCU_VARIANT == MCU_ESP32 serial_write(FEND); serial_write(CMD_STAT_BAT); escaped_serial_write(battery_state); escaped_serial_write((uint8_t)int(battery_percent)); serial_write(FEND); + #endif } void kiss_indicate_btpin() { @@ -1061,6 +816,7 @@ void kiss_indicate_fbstate() { serial_write(FEND); } +#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52 void kiss_indicate_device_hash() { serial_write(FEND); serial_write(CMD_DEV_HASH); @@ -1114,6 +870,7 @@ void kiss_indicate_fbstate() { } serial_write(FEND); } +#endif void kiss_indicate_fb() { serial_write(FEND); @@ -1129,20 +886,6 @@ void kiss_indicate_fb() { serial_write(FEND); } -void kiss_indicate_disp() { - serial_write(FEND); - serial_write(CMD_DISP_READ); - #if HAS_DISPLAY - uint8_t *da = disp_area.getBuffer(); - uint8_t *sa = stat_area.getBuffer(); - for (int i = 0; i < 512; i++) { escaped_serial_write(da[i]); } - for (int i = 0; i < 512; i++) { escaped_serial_write(sa[i]); } - #else - serial_write(0xFF); - #endif - serial_write(FEND); -} - void kiss_indicate_ready() { serial_write(FEND); serial_write(CMD_READY); @@ -1222,69 +965,37 @@ void set_implicit_length(uint8_t len) { } void setTXPower(RadioInterface* radio, int txp) { - // Todo, revamp this function. The current parameters for setTxPower are - // suboptimal, as some chips have power amplifiers which means that the max - // dBm is not always the same. + if (model == MODEL_11) { + if (interfaces[radio->getIndex()] == SX128X) { + radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + } else { + radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); + } + } if (model == MODEL_12) { - if (interfaces[radio->getIndex()] == SX1280) { + if (interfaces[radio->getIndex()] == SX128X) { radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); } else { radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); } } - if (model == MODEL_13) { - if (interfaces[radio->getIndex()] == SX1280) { - radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - } else { - radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); - } - } - - if (model == MODEL_21) { - if (interfaces[radio->getIndex()] == SX1280) { - radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - } else { - radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); - } - } - - if (model == MODEL_16) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - if (model == MODEL_17) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A1) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A2) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A3) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); if (model == MODEL_A4) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); - if (model == MODEL_A5) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); if (model == MODEL_A6) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); 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_AC) 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); if (model == MODEL_B8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_B9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - if (model == MODEL_BA) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - if (model == MODEL_BB) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); 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_C6) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN); - if (model == MODEL_C7) radio->setTxPower(txp, PA_OUTPUT_RFO_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_DD) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); - if (model == MODEL_DE) 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); @@ -1303,7 +1014,81 @@ uint8_t getRandom(RadioInterface* radio) { } } -uint16_t getQueueSize(uint8_t index) { +uint8_t getInterfaceIndex(uint8_t byte) { + switch (byte) { + case CMD_INT0_DATA: + case CMD_SEL_INT0: + return 0; + case CMD_INT1_DATA: + case CMD_SEL_INT1: + return 1; + case CMD_INT2_DATA: + case CMD_SEL_INT2: + return 2; + case CMD_INT3_DATA: + case CMD_SEL_INT3: + return 3; + case CMD_INT4_DATA: + case CMD_SEL_INT4: + return 4; + case CMD_INT5_DATA: + case CMD_SEL_INT5: + return 5; + case CMD_INT6_DATA: + case CMD_SEL_INT6: + return 6; + case CMD_INT7_DATA: + case CMD_SEL_INT7: + return 7; + case CMD_INT8_DATA: + case CMD_SEL_INT8: + return 8; + case CMD_INT9_DATA: + case CMD_SEL_INT9: + return 9; + case CMD_INT10_DATA: + case CMD_SEL_INT10: + return 10; + case CMD_INT11_DATA: + case CMD_SEL_INT11: + return 11; + default: + return 0; + } +} + +uint8_t getInterfaceCommandByte(uint8_t index) { + switch (index) { + case 0: + return CMD_INT0_DATA; + case 1: + return CMD_INT1_DATA; + case 2: + return CMD_INT2_DATA; + case 3: + return CMD_INT3_DATA; + case 4: + return CMD_INT4_DATA; + case 5: + return CMD_INT5_DATA; + case 6: + return CMD_INT6_DATA; + case 7: + return CMD_INT7_DATA; + case 8: + return CMD_INT8_DATA; + case 9: + return CMD_INT9_DATA; + case 10: + return CMD_INT10_DATA; + case 11: + return CMD_INT11_DATA; + default: + return 0; + } +} + +uint32_t getQueueSize(uint8_t index) { switch (index) { case 0: return CONFIG_QUEUE_0_SIZE; @@ -1351,8 +1136,6 @@ uint16_t getQueueSize(uint8_t index) { case 11: return CONFIG_QUEUE_11_SIZE; #endif - default: - return CONFIG_QUEUE_0_SIZE; } } @@ -1365,40 +1148,43 @@ void promisc_disable() { } #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 - bool eeprom_begin() { - InternalFS.begin(); + bool eeprom_begin() { + InternalFS.begin(); - file.open(EEPROM_FILE, FILE_O_READ); - if (!file) { - if (file.open(EEPROM_FILE, FILE_O_WRITE)) { - for (uint32_t mapped_addr = 0; mapped_addr < EEPROM_SIZE; mapped_addr++) { file.seek(mapped_addr); file.write(0xFF); } - eeprom_flush(); - return true; - } else { - return false; - } - } else { - file.close(); - file.open(EEPROM_FILE, FILE_O_WRITE); - return true; + file.open(EEPROM_FILE, FILE_O_READ); + + // if file doesn't exist + if (!file) { + if (file.open(EEPROM_FILE, FILE_O_WRITE)) { + // initialise the file with empty content + uint8_t empty_content[EEPROM_SIZE] = {0}; + file.write(empty_content, EEPROM_SIZE); + return true; + } else { + return false; + } + } else { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + return true; + } } - } - uint8_t eeprom_read(uint32_t mapped_addr) { - uint8_t byte; - void* byte_ptr = &byte; - file.seek(mapped_addr); - file.read(byte_ptr, 1); - return byte; - } + uint8_t eeprom_read(uint32_t mapped_addr) { + uint8_t byte; + void* byte_ptr = &byte; + file.seek(mapped_addr); + file.read(byte_ptr, 1); + return byte; + } #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 { @@ -1448,6 +1234,7 @@ void kiss_dump_eeprom() { #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 void eeprom_flush() { + // sync file contents to flash file.close(); file.open(EEPROM_FILE, FILE_O_WRITE); written_bytes = 0; @@ -1460,19 +1247,29 @@ void eeprom_update(int mapped_addr, uint8_t byte) { EEPROM.write(mapped_addr, byte); EEPROM.commit(); } - #elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 - // todo: clean up this implementation, writing one byte and syncing - // each time is really slow - uint8_t read_byte; - void* read_byte_ptr = &read_byte; - file.seek(mapped_addr); - file.read(read_byte_ptr, 1); - file.seek(mapped_addr); - if (read_byte != byte) { - file.write(byte); - } - written_bytes++; - eeprom_flush(); + #elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 + // todo: clean up this implementation, writing one byte and syncing + // each time is really slow, but this is also suboptimal + uint8_t read_byte; + void* read_byte_ptr = &read_byte; + file.seek(mapped_addr); + file.read(read_byte_ptr, 1); + file.seek(mapped_addr); + if (read_byte != byte) { + file.write(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(); + } + + if (written_bytes >= 4) { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + written_bytes = 0; + } #endif } @@ -1485,13 +1282,9 @@ void eeprom_write(uint8_t addr, uint8_t byte) { } void eeprom_erase() { - #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 - InternalFS.format(); - #else - for (int addr = 0; addr < EEPROM_RESERVED; addr++) { - eeprom_update(eeprom_addr(addr), 0xFF); - } - #endif + for (int addr = 0; addr < EEPROM_RESERVED; addr++) { + eeprom_update(eeprom_addr(addr), 0xFF); + } hard_reset(); } @@ -1508,16 +1301,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 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1 || rval == PRODUCT_H_W_PAPER || rval == PRODUCT_XIAO_S3) { + 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) { #elif PLATFORM == PLATFORM_NRF52 - if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_OPENCOM_XL || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) { + if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) { #else if (false) { #endif @@ -1539,20 +1332,12 @@ 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_T3S3 - if (model == MODEL_A1 || model == MODEL_A6 || model == MODEL_A5 || model == MODEL_AA || model == MODEL_AC) { + #elif BOARD_MODEL == BOARD_RNODE_NG_22 + if (model == MODEL_A1 || 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_TDECK - if (model == MODEL_D4 || model == MODEL_D9) { - #elif BOARD_MODEL == BOARD_TECHO - if (model == MODEL_16 || model == MODEL_17) { - #elif BOARD_MODEL == BOARD_TBEAM_S_V1 - if (model == MODEL_DB || model == MODEL_DC) { - #elif BOARD_MODEL == BOARD_XIAO_S3 - if (model == MODEL_DD || model == MODEL_DE) { #elif BOARD_MODEL == BOARD_LORA32_V1_0 if (model == MODEL_BA || model == MODEL_BB) { #elif BOARD_MODEL == BOARD_LORA32_V2_0 @@ -1563,20 +1348,10 @@ 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_H_W_PAPER - if (model == MODEL_C8) { - #elif BOARD_MODEL == BOARD_HELTEC_T114 - if (model == MODEL_C6 || model == MODEL_C7) { #elif BOARD_MODEL == BOARD_RAK4631 - if (model == MODEL_11 || model == MODEL_12 || model == MODEL_13 || model == MODEL_14) { - #elif BOARD_MODEL == BOARD_OPENCOM_XL - if (model == MODEL_21) { + if (model == MODEL_11 || model == MODEL_12) { #elif BOARD_MODEL == BOARD_HUZZAH32 if (model == MODEL_FF) { - #elif BOARD_MODEL == BOARD_E22_ESP32 - if (model == MODEL_FF || model == MODEL_FE) { - #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 @@ -1634,16 +1409,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 } } @@ -1655,40 +1430,6 @@ 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 drot_conf_save(uint8_t val) { - #if HAS_DISPLAY - if (val >= 0x00 and val <= 0x03) { - eeprom_update(eeprom_addr(ADDR_CONF_DROT), val); - hard_reset(); - } - #endif -} - -void dia_conf_save(uint8_t val) { - if (val > 0x00) { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x01); } - else { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x00); } - hard_reset(); -} - -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) { @@ -1763,53 +1504,168 @@ void unlock_rom() { eeprom_erase(); } -void kiss_indicate_location() { - #if HAS_GPS - char location[10]; - int len; - int32_t val; - if (gps.location.isValid()) { - serial_write(FEND); - serial_write(CMD_GPS); - serial_write(GPS_CMD_LAT); - val = gps.location.lat() * 1000000; - escaped_serial_write(val>>24); - escaped_serial_write(val>>16); - escaped_serial_write(val>>8); - escaped_serial_write(val); - serial_write(FEND); +typedef struct FIFOBuffer +{ + unsigned char *begin; + unsigned char *end; + unsigned char * volatile head; + unsigned char * volatile tail; +} FIFOBuffer; - serial_write(FEND); - serial_write(CMD_GPS); - serial_write(GPS_CMD_LNG); - val = gps.location.lng() * 1000000; - escaped_serial_write(val>>24); - escaped_serial_write(val>>16); - escaped_serial_write(val>>8); - escaped_serial_write(val); - serial_write(FEND); - } - #endif +inline bool fifo_isempty(const FIFOBuffer *f) { + return f->head == f->tail; } -void log_debug(const char* msg) { - serial_write(FEND); - serial_write(LOG_MSG); - serial_write(MSG_DBG); - for (int i = 0; i < strlen(msg); i++) { - escaped_serial_write(msg[i]); - } - serial_write(FEND); +inline bool fifo_isfull(const FIFOBuffer *f) { + return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); } -void log_debug(char* msg) { - serial_write(FEND); - serial_write(LOG_MSG); - serial_write(MSG_DBG); - for (int i = 0; i < strlen(msg); i++) { - escaped_serial_write(msg[i]); - } - serial_write(FEND); +inline void fifo_push(FIFOBuffer *f, unsigned char c) { + *(f->tail) = c; + + if (f->tail == f->end) { + f->tail = f->begin; + } else { + f->tail++; + } } -#include "src/misc/FIFOBuffer.h" +inline unsigned char fifo_pop(FIFOBuffer *f) { + if(f->head == f->end) { + f->head = f->begin; + return *(f->end); + } else { + return *(f->head++); + } +} + +inline void fifo_flush(FIFOBuffer *f) { + f->head = f->tail; +} + +#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52 + static inline bool fifo_isempty_locked(const FIFOBuffer *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo_isempty(f); + } + return result; + } + + static inline bool fifo_isfull_locked(const FIFOBuffer *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo_isfull(f); + } + return result; + } + + static inline void fifo_push_locked(FIFOBuffer *f, unsigned char c) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + fifo_push(f, c); + } + } +#endif + +/* +static inline unsigned char fifo_pop_locked(FIFOBuffer *f) { + unsigned char c; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + c = fifo_pop(f); + } + return c; +} +*/ + +inline void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) { + f->head = f->tail = f->begin = buffer; + f->end = buffer + size; +} + +inline size_t fifo_len(FIFOBuffer *f) { + return f->end - f->begin; +} + +typedef struct FIFOBuffer16 +{ + uint16_t *begin; + uint16_t *end; + uint16_t * volatile head; + uint16_t * volatile tail; +} FIFOBuffer16; + +inline bool fifo16_isempty(const FIFOBuffer16 *f) { + return f->head == f->tail; +} + +inline bool fifo16_isfull(const FIFOBuffer16 *f) { + return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); +} + +inline void fifo16_push(FIFOBuffer16 *f, uint16_t c) { + *(f->tail) = c; + + if (f->tail == f->end) { + f->tail = f->begin; + } else { + f->tail++; + } +} + +inline uint16_t fifo16_pop(FIFOBuffer16 *f) { + if(f->head == f->end) { + f->head = f->begin; + return *(f->end); + } else { + return *(f->head++); + } +} + +inline void fifo16_flush(FIFOBuffer16 *f) { + f->head = f->tail; +} + +#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52 + static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo16_isempty(f); + } + + return result; + } +#endif + +/* +static inline bool fifo16_isfull_locked(const FIFOBuffer16 *f) { + bool result; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + result = fifo16_isfull(f); + } + return result; +} + + +static inline void fifo16_push_locked(FIFOBuffer16 *f, uint16_t c) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + fifo16_push(f, c); + } +} + +static inline size_t fifo16_pop_locked(FIFOBuffer16 *f) { + size_t c; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + c = fifo16_pop(f); + } + return c; +} +*/ + +inline void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) { + f->head = f->tail = f->begin = buffer; + f->end = buffer + size; +} + +inline uint16_t fifo16_len(FIFOBuffer16 *f) { + return (f->end - f->begin); +} diff --git a/arduino-cli.yaml b/arduino-cli.yaml index 237acf9..a8ad233 100644 --- a/arduino-cli.yaml +++ b/arduino-cli.yaml @@ -1,6 +1,5 @@ board_manager: additional_urls: - - 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 - - https://github.com/HelTecAutomation/Heltec_nRF52/releases/download/1.7.0/package_heltec_nrf_index.json + - http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json diff --git a/esp32_btbufs.py b/esp32_btbufs.py deleted file mode 100755 index ad0ae70..0000000 --- a/esp32_btbufs.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python3 -import sys -import re - -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 = re.sub(" +", " ", 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 = re.sub(" +", " ", line).split(" ") - try: - txbuf_size = int(ents[2]) - tx_line_index = line_index - except Exception as e: - print(f"Could not parse Bluetooth TX_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/partition_hashes b/partition_hashes index 18c61ff..b520250 100755 --- a/partition_hashes +++ b/partition_hashes @@ -1,6 +1,6 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python -# Copyright (C) 2024, Mark Qvist +# Copyright (C) 2023, 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,6 @@ import sys import RNS import json import hashlib -import subprocess major_version = None minor_version = None @@ -28,23 +27,9 @@ target_version = None target_file = os.path.join(sys.argv[1]) -if sys.argv[1] == "from_device": - from_device = True -else: - from_device = False +firmware_data = open(target_file, "rb").read() +calc_hash = hashlib.sha256(firmware_data[0:-32]).digest() +part_hash = firmware_data[-32:] -if not from_device: - firmware_data = open(target_file, "rb").read() - calc_hash = hashlib.sha256(firmware_data[0:-32]).digest() - part_hash = firmware_data[-32:] - - if calc_hash == part_hash: - print(RNS.hexrep(part_hash, delimit=False)) - -else: - try: - cmdresult = subprocess.run(["rnodeconf", sys.argv[2], "-L"], stdout=subprocess.PIPE).stdout.decode('utf-8') - part_hash = cmdresult.split("The actual firmware hash is: ")[1].replace("\n", "") - print(part_hash) - except Exception as e: - print("Could not get partition hash from device: "+str(e)) +if calc_hash == part_hash: + print(RNS.hexrep(part_hash, delimit=False)) diff --git a/release_hashes.py b/release_hashes.py index e1608d8..ce28a0c 100644 --- a/release_hashes.py +++ b/release_hashes.py @@ -1,6 +1,6 @@ -#!/bin/python3 +#!/bin/python -# Copyright (C) 2024, Mark Qvist +# Copyright (C) 2023, 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 @@ -47,4 +47,4 @@ for filename in files: "version": target_version } -print(json.dumps(release_hashes)) +print(json.dumps(release_hashes)) \ No newline at end of file diff --git a/src/ble/BLESerial.cpp b/src/ble/BLESerial.cpp deleted file mode 100644 index 555144b..0000000 --- a/src/ble/BLESerial.cpp +++ /dev/null @@ -1,172 +0,0 @@ -// 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 . - -#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::disconnect() { - if (ble_server->getConnectedCount() > 0) { - uint16_t conn_id = ble_server->getConnId(); - // Serial.printf("Have connected: %d\n", conn_id); - ble_server->disconnect(conn_id); - // Serial.println("Disconnected"); - } else { - // Serial.println("No connected"); - } -} - -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(); - this->startAdvertising(); -} - -void BLESerial::startAdvertising() { - 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::stopAdvertising() { - ble_adv = BLEDevice::getAdvertising(); - ble_adv->stop(); -} - -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 deleted file mode 100644 index e7e0d0f..0000000 --- a/src/ble/BLESerial.h +++ /dev/null @@ -1,136 +0,0 @@ -// 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 . - -#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 disconnect(); - void startAdvertising(); - void stopAdvertising(); - 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/src/display/ST7789.h b/src/display/ST7789.h deleted file mode 100644 index 85012e8..0000000 --- a/src/display/ST7789.h +++ /dev/null @@ -1,440 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2018 by ThingPulse, Daniel Eichhorn - * Copyright (c) 2018 by Fabrice Weinberg - * Copyright (c) 2024 by Heltec AutoMation - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * ThingPulse invests considerable time and money to develop these open source libraries. - * Please support us by buying our products (and not the clones) from - * https://thingpulse.com - * - */ - -#ifndef ST7789Spi_h -#define ST7789Spi_h - -#include "OLEDDisplay.h" -#include - - -#define ST_CMD_DELAY 0x80 // special signifier for command lists - -#define ST77XX_NOP 0x00 -#define ST77XX_SWRESET 0x01 -#define ST77XX_RDDID 0x04 -#define ST77XX_RDDST 0x09 - -#define ST77XX_SLPIN 0x10 -#define ST77XX_SLPOUT 0x11 -#define ST77XX_PTLON 0x12 -#define ST77XX_NORON 0x13 - -#define ST77XX_INVOFF 0x20 -#define ST77XX_INVON 0x21 -#define ST77XX_DISPOFF 0x28 -#define ST77XX_DISPON 0x29 -#define ST77XX_CASET 0x2A -#define ST77XX_RASET 0x2B -#define ST77XX_RAMWR 0x2C -#define ST77XX_RAMRD 0x2E - -#define ST77XX_PTLAR 0x30 -#define ST77XX_TEOFF 0x34 -#define ST77XX_TEON 0x35 -#define ST77XX_MADCTL 0x36 -#define ST77XX_COLMOD 0x3A - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_RGB 0x00 - -#define ST77XX_RDID1 0xDA -#define ST77XX_RDID2 0xDB -#define ST77XX_RDID3 0xDC -#define ST77XX_RDID4 0xDD - -// Some ready-made 16-bit ('565') color settings: -#define ST77XX_BLACK 0x0000 -#define ST77XX_WHITE 0xFFFF -#define ST77XX_RED 0xF800 -#define ST77XX_GREEN 0x07E0 -#define ST77XX_BLUE 0x001F -#define ST77XX_CYAN 0x07FF -#define ST77XX_MAGENTA 0xF81F -#define ST77XX_YELLOW 0xFFE0 -#define ST77XX_ORANGE 0xFC00 - -#define LED_A_ON LOW - -#ifdef ESP_PLATFORM -#undef LED_A_ON -#define LED_A_ON HIGH -#define rtos_free free -#define rtos_malloc malloc -//SPIClass SPI1(HSPI); -#endif -class ST7789Spi : public OLEDDisplay { - private: - uint8_t _rst; - uint8_t _dc; - uint8_t _cs; - uint8_t _ledA; - int _miso; - int _mosi; - int _clk; - SPIClass * _spi; - SPISettings _spiSettings; - uint16_t _RGB=0xFFFF; - uint8_t _buffheight; - public: - /* pass _cs as -1 to indicate "do not use CS pin", for cases where it is hard wired low */ - ST7789Spi(SPIClass *spiClass,uint8_t _rst, uint8_t _dc, uint8_t _cs, OLEDDISPLAY_GEOMETRY g = GEOMETRY_RAWMODE,uint16_t width=240,uint16_t height=320,int mosi=-1,int miso=-1,int clk=-1) { - this->_spi = spiClass; - this->_rst = _rst; - this->_dc = _dc; - this->_cs = _cs; - this->_mosi=mosi; - this->_miso=miso; - this->_clk=clk; - //this->_ledA = _ledA; - _spiSettings = SPISettings(40000000, MSBFIRST, SPI_MODE0); - setGeometry(g,width,height); - } - - bool connect(){ - this->_buffheight=displayHeight / 8; - this->_buffheight+=displayHeight % 8 ? 1:0; - pinMode(_cs, OUTPUT); - pinMode(_dc, OUTPUT); - //pinMode(_ledA, OUTPUT); - if (_cs != (uint8_t) -1) { - pinMode(_cs, OUTPUT); - } - pinMode(_rst, OUTPUT); - -#ifdef ESP_PLATFORM - _spi->begin(_clk,_miso,_mosi,-1); -#else - _spi->begin(); -#endif - _spi->setClockDivider (SPI_CLOCK_DIV2); - - // Pulse Reset low for 10ms - digitalWrite(_rst, HIGH); - delay(1); - digitalWrite(_rst, LOW); - delay(10); - digitalWrite(_rst, HIGH); - _spi->begin (); - //digitalWrite(_ledA, LED_A_ON); - return true; - } - - void display(void) { - #ifdef OLEDDISPLAY_DOUBLE_BUFFER - - uint16_t minBoundY = UINT16_MAX; - uint16_t maxBoundY = 0; - - uint16_t minBoundX = UINT16_MAX; - uint16_t maxBoundX = 0; - - uint16_t x, y; - - // Calculate the Y bounding box of changes - // and copy buffer[pos] to buffer_back[pos]; - for (y = 0; y < _buffheight; y++) { - for (x = 0; x < displayWidth; x++) { - //Serial.printf("x %d y %d\r\n",x,y); - uint16_t pos = x + y * displayWidth; - if (buffer[pos] != buffer_back[pos]) { - minBoundY = min(minBoundY, y); - maxBoundY = max(maxBoundY, y); - minBoundX = min(minBoundX, x); - maxBoundX = max(maxBoundX, x); - } - buffer_back[pos] = buffer[pos]; - } - yield(); - } - - // If the minBoundY wasn't updated - // we can savely assume that buffer_back[pos] == buffer[pos] - // holdes true for all values of pos - if (minBoundY == UINT16_MAX) return; - - set_CS(LOW); - _spi->beginTransaction(_spiSettings); - - for (y = minBoundY; y <= maxBoundY; y++) - { - for(int temp = 0; temp<8;temp++) - { - //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1); - setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1); - //setAddrWindow(y*8+temp,minBoundX,1,maxBoundX-minBoundX+1); - uint32_t const pixbufcount = maxBoundX-minBoundX+1; - uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount); - for (x = minBoundX; x <= maxBoundX; x++) - { - pixbuf[x-minBoundX] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0; - } -#ifdef ESP_PLATFORM - _spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount); -#else - _spi->transfer(pixbuf, NULL, 2 * pixbufcount); -#endif - rtos_free(pixbuf); - } - } - _spi->endTransaction(); - set_CS(HIGH); - - #else - set_CS(LOW); - _spi->beginTransaction(_spiSettings); - uint8_t x, y; - for (y = 0; y < _buffheight; y++) - { - for(int temp = 0; temp<8;temp++) - { - //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1); - //setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1); - setAddrWindow(y*8+temp,0,1,displayWidth); - uint32_t const pixbufcount = displayWidth; - uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount); - for (x = 0; x < displayWidth; x++) - { - pixbuf[x] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0; - } -#ifdef ESP_PLATFORM - _spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount); -#else - _spi->transfer(pixbuf, NULL, 2 * pixbufcount); -#endif - rtos_free(pixbuf); - } - } - _spi->endTransaction(); - set_CS(HIGH); - - #endif - } - - virtual void resetOrientation() { - uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX; - sendCommand(ST77XX_MADCTL); - WriteData(madctl); - delay(10); - } - - virtual void flipScreenVertically() { - uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY; - sendCommand(ST77XX_MADCTL); - WriteData(madctl); - delay(10); - } - - virtual void mirrorScreen() { - uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX|ST77XX_MADCTL_MY; - sendCommand(ST77XX_MADCTL); - WriteData(madctl); - delay(10); - } - - virtual void setRotation(uint8_t r) { - uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX; - if (r == 1) { madctl = 0xC0; } - if (r == 2) { madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY; } - if (r == 3) { madctl = 0x00; } - sendCommand(ST77XX_MADCTL); - WriteData(madctl); - delay(10); - } - - void setRGB(uint16_t c) - { - - this->_RGB=0x00|c>>8|c<<8&0xFF00; - } - - void displayOn(void) { - //sendCommand(DISPLAYON); - } - - void displayOff(void) { - //sendCommand(DISPLAYOFF); - } - -//#define ST77XX_MADCTL_MY 0x80 -//#define ST77XX_MADCTL_MX 0x40 -//#define ST77XX_MADCTL_MV 0x20 -//#define ST77XX_MADCTL_ML 0x10 - protected: - // Send all the init commands - virtual void sendInitCommands() - { - sendCommand(ST77XX_SWRESET); // 1: Software reset, no args, w/delay - delay(150); - - sendCommand(ST77XX_SLPOUT); // 2: Out of sleep mode, no args, w/delay - delay(10); - - sendCommand(ST77XX_COLMOD); // 3: Set color mode, 16-bit color - WriteData(0x55); - delay(10); - - sendCommand(ST77XX_MADCTL); // 4: Mem access ctrl (directions), Row/col addr, bottom-top refresh - WriteData(0x08); - - sendCommand(ST77XX_CASET); // 5: Column addr set, - WriteData(0x00); - WriteData(0x00); // XSTART = 0 - WriteData(0x00); - WriteData(240); // XEND = 240 - - sendCommand(ST77XX_RASET); // 6: Row addr set, - WriteData(0x00); - WriteData(0x00); // YSTART = 0 - WriteData(320>>8); - WriteData(320&0xFF); // YSTART = 320 - - sendCommand(ST77XX_SLPOUT); // 7: hack - delay(10); - - sendCommand(ST77XX_NORON); // 8: Normal display on, no args, w/delay - delay(10); - - sendCommand(ST77XX_DISPON); // 9: Main screen turn on, no args, delay - delay(10); - - sendCommand(ST77XX_INVON); // 10: invert - delay(10); - - //uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MX; - uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX; - sendCommand(ST77XX_MADCTL); - WriteData(madctl); - delay(10); - setRGB(ST77XX_GREEN); - } - - - private: - - void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { - x += (320-displayWidth)/2; - y += (240-displayHeight)/2; - uint32_t xa = ((uint32_t)x << 16) | (x + w - 1); - uint32_t ya = ((uint32_t)y << 16) | (y + h - 1); - - writeCommand(ST77XX_CASET); // Column addr set - SPI_WRITE32(xa); - - writeCommand(ST77XX_RASET); // Row addr set - SPI_WRITE32(ya); - - writeCommand(ST77XX_RAMWR); // write to RAM - } - int getBufferOffset(void) { - return 0; - } - inline void set_CS(bool level) { - if (_cs != (uint8_t) -1) { - digitalWrite(_cs, level); - } - }; - inline void sendCommand(uint8_t com) __attribute__((always_inline)){ - set_CS(HIGH); - digitalWrite(_dc, LOW); - set_CS(LOW); - _spi->beginTransaction(_spiSettings); - _spi->transfer(com); - _spi->endTransaction(); - set_CS(HIGH); - digitalWrite(_dc, HIGH); - } - - inline void WriteData(uint8_t data) __attribute__((always_inline)){ - digitalWrite(_cs, LOW); - _spi->beginTransaction(_spiSettings); - _spi->transfer(data); - _spi->endTransaction(); - digitalWrite(_cs, HIGH); - } - void SPI_WRITE32(uint32_t l) - { - _spi->transfer(l >> 24); - _spi->transfer(l >> 16); - _spi->transfer(l >> 8); - _spi->transfer(l); - } - void writeCommand(uint8_t cmd) { - digitalWrite(_dc, LOW); - _spi->transfer(cmd); - digitalWrite(_dc, HIGH); - } - -// Private functions - void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) { - this->geometry = g; - - switch (g) { - case GEOMETRY_128_128: - this->displayWidth = 128; - this->displayHeight = 128; - break; - case GEOMETRY_128_64: - this->displayWidth = 128; - this->displayHeight = 64; - break; - case GEOMETRY_128_32: - this->displayWidth = 128; - this->displayHeight = 32; - break; - case GEOMETRY_64_48: - this->displayWidth = 64; - this->displayHeight = 48; - break; - case GEOMETRY_64_32: - this->displayWidth = 64; - this->displayHeight = 32; - break; - case GEOMETRY_RAWMODE: - this->displayWidth = width > 0 ? width : 128; - this->displayHeight = height > 0 ? height : 64; - break; - } - uint8_t tmp=displayHeight % 8; - uint8_t _buffheight=displayHeight / 8; - - if(tmp!=0) - _buffheight++; - this->displayBufferSize = displayWidth * _buffheight ; - } - - - -}; - -#endif \ No newline at end of file diff --git a/src/misc/FIFOBuffer.c b/src/misc/FIFOBuffer.c deleted file mode 100644 index 86fa0ca..0000000 --- a/src/misc/FIFOBuffer.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#include "FIFOBuffer.h" - -#ifdef __cplusplus - extern "C" { -#endif - - bool fifo_isempty(const FIFOBuffer *f) { - return f->head == f->tail; -} - - bool fifo_isfull(const FIFOBuffer *f) { - return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); -} - - void fifo_push(FIFOBuffer *f, unsigned char c) { - *(f->tail) = c; - - if (f->tail == f->end) { - f->tail = f->begin; - } else { - f->tail++; - } -} - - unsigned char fifo_pop(FIFOBuffer *f) { - if(f->head == f->end) { - f->head = f->begin; - return *(f->end); - } else { - return *(f->head++); - } -} - - void fifo_flush(FIFOBuffer *f) { - f->head = f->tail; -} - - - void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) { - f->head = f->tail = f->begin = buffer; - f->end = buffer + size; -} - -// todo, fix this so it actually displays the amount of data in the fifo -// buffer, not just the size allocated for the buffer - size_t fifo_len(FIFOBuffer *f) { - return f->end - f->begin; -} - - bool fifo16_isempty(const FIFOBuffer16 *f) { - return f->head == f->tail; -} - - bool fifo16_isfull(const FIFOBuffer16 *f) { - return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1); -} - - void fifo16_push(FIFOBuffer16 *f, uint16_t c) { - *(f->tail) = c; - - if (f->tail == f->end) { - f->tail = f->begin; - } else { - f->tail++; - } -} - - uint16_t fifo16_pop(FIFOBuffer16 *f) { - if(f->head == f->end) { - f->head = f->begin; - return *(f->end); - } else { - return *(f->head++); - } -} - - void fifo16_flush(FIFOBuffer16 *f) { - f->head = f->tail; -} - - void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) { - f->head = f->tail = f->begin = buffer; - f->end = buffer + size; -} - - uint16_t fifo16_len(FIFOBuffer16 *f) { - return (f->end - f->begin); -} - -#ifdef __cplusplus -} -#endif diff --git a/src/misc/FIFOBuffer.h b/src/misc/FIFOBuffer.h deleted file mode 100644 index bdc6d00..0000000 --- a/src/misc/FIFOBuffer.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef FIFOBUFFER_H - -#define FIFOBUFFER_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* An 8 bit FIFO buffer implementation */ -typedef struct FIFOBuffer -{ - unsigned char *begin; - unsigned char *end; - unsigned char * volatile head; - unsigned char * volatile tail; -} FIFOBuffer; - -bool fifo_isempty(const FIFOBuffer *f); - -bool fifo_isfull(const FIFOBuffer *f); - -void fifo_push(FIFOBuffer *f, unsigned char c); - -unsigned char fifo_pop(FIFOBuffer *f); - -void fifo_flush(FIFOBuffer *f); - -void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size); - -size_t fifo_len(FIFOBuffer *f); - -/* A 16-bit implementation of the same FIFO buffer. */ -typedef struct FIFOBuffer16 -{ - uint16_t *begin; - uint16_t *end; - uint16_t * volatile head; - uint16_t * volatile tail; -} FIFOBuffer16; - -bool fifo16_isempty(const FIFOBuffer16 *f); - -bool fifo16_isfull(const FIFOBuffer16 *f); - -void fifo16_push(FIFOBuffer16 *f, uint16_t c); - -uint16_t fifo16_pop(FIFOBuffer16 *f); - -void fifo16_flush(FIFOBuffer16 *f); - -void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size); - -uint16_t fifo16_len(FIFOBuffer16 *f); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/misc/ModemISR.h b/src/misc/ModemISR.h deleted file mode 100644 index 4c02dc7..0000000 --- a/src/misc/ModemISR.h +++ /dev/null @@ -1,45 +0,0 @@ -extern RadioInterface* interface_obj[INTERFACE_COUNT]; -void (*onIntRise[INTERFACE_COUNT]) (void); - -#if INTERFACE_COUNT == 1 -void onInt0Rise() { - if (interfaces[0] == SX1280) { - // On the SX1280, there is a bug which can cause the busy line - // to remain high if a high amount of packets are received when - // in continuous RX mode. This is documented as Errata 16.1 in - // the SX1280 datasheet v3.2 (page 149) - // Therefore, the modem is set into receive mode each time a packet is received. - interface_obj[0]->receive(); - } - if (interface_obj[0]->getPacketValidity()) { - interface_obj[0]->handleDio0Rise(); - } -} - -void setup_interfaces() { - onIntRise[0] = onInt0Rise; -} -#elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL -void onInt0Rise() { - if (interface_obj[0]->getPacketValidity()) { - interface_obj[0]->handleDio0Rise(); - } -} - -void onInt1Rise() { - // On the SX1280, there is a bug which can cause the busy line - // to remain high if a high amount of packets are received when - // in continuous RX mode. This is documented as Errata 16.1 in - // the SX1280 datasheet v3.2 (page 149) - // Therefore, the modem is set into receive mode each time a packet is received. - interface_obj[1]->receive(); - if (interface_obj[1]->getPacketValidity()) { - interface_obj[1]->handleDio0Rise(); - } -} - -void setup_interfaces() { - onIntRise[0] = onInt0Rise; - onIntRise[1] = onInt1Rise; -} -#endif diff --git a/src/misc/gps.h b/src/misc/gps.h deleted file mode 100644 index cdbdb65..0000000 --- a/src/misc/gps.h +++ /dev/null @@ -1,8 +0,0 @@ -#include -#include - -#define GPS_INTERVAL 5000 // ms - -unsigned long last_gps = 0; -TinyGPSPlus gps; -SoftwareSerial gps_s(PIN_GPS_RX, PIN_GPS_TX);