diff --git a/Bluetooth.h b/Bluetooth.h index 4761e24..ee3964e 100644 --- a/Bluetooth.h +++ b/Bluetooth.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -22,8 +22,8 @@ #elif HAS_BLE == true #include "esp_bt_main.h" #include "esp_bt_device.h" - // TODO: Remove - #define SerialBT Serial + #include "src/ble/BLESerial.h" + BLESerial SerialBT; #endif #elif MCU_VARIANT == MCU_NRF52 @@ -35,6 +35,7 @@ #endif #define BT_PAIRING_TIMEOUT 35000 +#define BLE_FLUSH_TIMEOUT 20 uint32_t bt_pairing_started = 0; #define BT_DEV_ADDR_LEN 6 @@ -58,6 +59,7 @@ char bt_devname[11]; } void bt_stop() { + //display_unblank(); if (bt_state != BT_STATE_OFF) { SerialBT.end(); bt_allow_pairing = false; @@ -66,6 +68,7 @@ char bt_devname[11]; } void bt_start() { + //display_unblank(); if (bt_state == BT_STATE_OFF) { SerialBT.begin(bt_devname); bt_state = BT_STATE_ON; @@ -73,6 +76,7 @@ char bt_devname[11]; } void bt_enable_pairing() { + //display_unblank(); if (bt_state == BT_STATE_OFF) bt_start(); bt_allow_pairing = true; bt_pairing_started = millis(); @@ -80,12 +84,14 @@ char bt_devname[11]; } void bt_disable_pairing() { + //display_unblank(); bt_allow_pairing = false; bt_ssp_pin = 0; bt_state = BT_STATE_ON; } void bt_pairing_complete(boolean success) { + //display_unblank(); if (success) { bt_disable_pairing(); } else { @@ -93,7 +99,8 @@ char bt_devname[11]; } } - void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){ + void bt_connection_callback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param) { + //display_unblank(); if(event == ESP_SPP_SRV_OPEN_EVT) { bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; @@ -156,25 +163,122 @@ char bt_devname[11]; } #elif HAS_BLE == true - void bt_stop() { - if (bt_state != BT_STATE_OFF) { - bt_allow_pairing = false; - bt_state = BT_STATE_OFF; - } - } + BLESecurity *ble_security = new BLESecurity(); + bool ble_authenticated = false; + uint32_t pairing_pin = 0; + + void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flush(); } } void bt_disable_pairing() { + //display_unblank(); bt_allow_pairing = false; bt_ssp_pin = 0; bt_state = BT_STATE_ON; } - void bt_connect_callback(uint16_t conn_handle) { + void bt_passkey_notify_callback(uint32_t passkey) { + // Serial.printf("Got passkey notification: %d\n", passkey); + bt_ssp_pin = passkey; + bt_state = BT_STATE_PAIRING; + bt_allow_pairing = true; + bt_pairing_started = millis(); + kiss_indicate_btpin(); + } + + bool bt_confirm_pin_callback(uint32_t pin) { + // Serial.printf("Confirm PIN callback: %d\n", pin); + return true; + } + + void bt_debond_all() { + // Serial.println("Debonding all"); + int dev_num = esp_ble_get_bond_device_num(); + esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num); + esp_ble_get_bond_device_list(&dev_num, dev_list); + for (int i = 0; i < dev_num; i++) { esp_ble_remove_bond_device(dev_list[i].bd_addr); } + free(dev_list); + } + + void bt_update_passkey() { + // Serial.println("Updating passkey"); + pairing_pin = random(899999)+100000; + bt_ssp_pin = pairing_pin; + } + + uint32_t bt_passkey_callback() { + // Serial.println("API passkey request"); + if (pairing_pin == 0) { bt_update_passkey(); } + return pairing_pin; + } + + bool bt_client_authenticated() { + return ble_authenticated; + } + + void bt_security_setup() { + uint32_t passkey = bt_passkey_callback(); + + // Serial.printf("Executing BT security setup, passkey is %d\n", passkey); + + uint8_t key_size = 16; + uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK; + + esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; + uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_ENABLE; + uint8_t oob_support = ESP_BLE_OOB_DISABLE; + + esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; + + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t)); + esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t)); + } + + bool bt_security_request_callback() { + if (bt_allow_pairing) { + // Serial.println("Accepting security request"); + return true; + } else { + // Serial.println("Rejecting security request"); + return false; + } + } + + void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result) { + if (auth_result.success == true) { + // Serial.println("Authentication success"); + ble_authenticated = true; + bt_state = BT_STATE_CONNECTED; + } else { + // Serial.println("Authentication fail"); + ble_authenticated = false; + bt_state = BT_STATE_ON; + bt_security_setup(); + } + bt_allow_pairing = false; + bt_ssp_pin = 0; + } + + void bt_connect_callback(BLEServer *server) { + // uint16_t conn_id = server->getConnId(); + // Serial.printf("Connected: %d\n", conn_id); + //display_unblank(); + ble_authenticated = false; bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; } - void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { + void bt_disconnect_callback(BLEServer *server) { + // uint16_t conn_id = server->getConnId(); + // Serial.printf("Disconnected: %d\n", conn_id); + //display_unblank(); + ble_authenticated = false; bt_state = BT_STATE_ON; } @@ -199,8 +303,8 @@ char bt_devname[11]; sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); free(data); - // TODO: Implement GAP & GATT for RNode comms over BLE - + bt_security_setup(); + bt_ready = true; return true; @@ -211,9 +315,20 @@ char bt_devname[11]; } void bt_start() { + //display_unblank(); if (bt_state == BT_STATE_OFF) { bt_state = BT_STATE_ON; - // TODO: Implement + SerialBT.begin(bt_devname); + SerialBT.setTimeout(10); + } + } + + void bt_stop() { + //display_unblank(); + if (bt_state != BT_STATE_OFF) { + bt_allow_pairing = false; + bt_state = BT_STATE_OFF; + SerialBT.end(); } } @@ -228,7 +343,13 @@ char bt_devname[11]; } void bt_enable_pairing() { + //display_unblank(); if (bt_state == BT_STATE_OFF) bt_start(); + + bt_security_setup(); + //bt_debond_all(); + //bt_update_passkey(); + bt_allow_pairing = true; bt_pairing_started = millis(); bt_state = BT_STATE_PAIRING; @@ -238,26 +359,31 @@ char bt_devname[11]; if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { bt_disable_pairing(); } + if (bt_state == BT_STATE_CONNECTED && millis()-SerialBT.lastFlushTime >= BLE_FLUSH_TIMEOUT) { + if (SerialBT.transmitBufferLength > 0) { + bt_flush(); + } + } } #endif #elif MCU_VARIANT == MCU_NRF52 -uint8_t eeprom_read(uint32_t mapped_addr); + uint8_t eeprom_read(uint32_t mapped_addr); -void bt_stop() { - if (bt_state != BT_STATE_OFF) { - bt_allow_pairing = false; - bt_state = BT_STATE_OFF; + void bt_stop() { + if (bt_state != BT_STATE_OFF) { + bt_allow_pairing = false; + bt_state = BT_STATE_OFF; + } } -} -void bt_disable_pairing() { - bt_allow_pairing = false; - bt_ssp_pin = 0; - bt_state = BT_STATE_ON; -} + void bt_disable_pairing() { + bt_allow_pairing = false; + bt_ssp_pin = 0; + bt_state = BT_STATE_ON; + } -void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { + void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) { BLEConnection* connection = Bluefruit.Connection(conn_handle); @@ -290,24 +416,23 @@ void bt_pairing_complete(uint16_t conn_handle, uint8_t auth_status) { } else { bt_ssp_pin = 0; } -} + } -bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { + bool bt_passkey_callback(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { for (int i = 0; i < 6; i++) { - // multiply by tens however many times needed to make numbers appear in order - bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); + // multiply by tens however many times needed to make numbers appear in order + bt_ssp_pin += ((int)passkey[i] - 48) * pow(10, 5-i); } kiss_indicate_btpin(); if (bt_allow_pairing) { - return true; + return true; } return false; -} + } -void bt_connect_callback(uint16_t conn_handle) { + void bt_connect_callback(uint16_t conn_handle) { bt_state = BT_STATE_CONNECTED; cable_state = CABLE_STATE_DISCONNECTED; - BLEConnection* conn = Bluefruit.Connection(conn_handle); conn->requestPHY(BLE_GAP_PHY_2MBPS); conn->requestMtuExchange(512+3); @@ -320,89 +445,87 @@ void bt_disconnect_callback(uint16_t conn_handle, uint8_t reason) { } } -bool bt_setup_hw() { - if (!bt_ready) { - #if HAS_EEPROM - if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { - #else - if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { - #endif - bt_enabled = true; - } else { - bt_enabled = false; - } - Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); - Bluefruit.autoConnLed(false); - if (Bluefruit.begin()) { - Bluefruit.setTxPower(8); // Check bluefruit.h for supported values - Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no - // This device is indeed capable of yes / no through the pairing mode - // being set, but I have chosen to set it thus to force the input of the - // pin on the device initiating the pairing. This prevents it from being - // paired with automatically by a hypothetical malicious device nearby - // without physical access to the RNode. - - Bluefruit.Security.setMITM(true); - Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); - Bluefruit.Security.setSecuredCallback(bt_connect_callback); - Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); - Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); - Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms - - const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); - char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); - for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { - data[i] = gap_addr.addr[i]; - } + bool bt_setup_hw() { + if (!bt_ready) { #if HAS_EEPROM - data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); + if (EEPROM.read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { #else - data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); + if (eeprom_read(eeprom_addr(ADDR_CONF_BT)) == BT_ENABLE_BYTE) { #endif - unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); - memcpy(bt_dh, hash, BT_DEV_HASH_LEN); - sprintf(bt_devname, "RNode %02X%02X", bt_dh[14], bt_dh[15]); - free(data); + bt_enabled = true; + } else { + bt_enabled = false; + } + Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); + Bluefruit.autoConnLed(false); + if (Bluefruit.begin()) { + Bluefruit.setTxPower(8); // Check bluefruit.h for supported values + Bluefruit.Security.setIOCaps(true, false, false); // display, yes; yes / no, no; keyboard, no + // This device is indeed capable of yes / no through the pairing mode + // being set, but I have chosen to set it thus to force the input of the + // pin on the device initiating the pairing. - bt_ready = true; - return true; + Bluefruit.Security.setMITM(true); + Bluefruit.Security.setPairPasskeyCallback(bt_passkey_callback); + Bluefruit.Security.setSecuredCallback(bt_connect_callback); + Bluefruit.Periph.setDisconnectCallback(bt_disconnect_callback); + Bluefruit.Security.setPairCompleteCallback(bt_pairing_complete); + Bluefruit.Periph.setConnInterval(6, 12); // 7.5 - 15 ms + const ble_gap_addr_t gap_addr = Bluefruit.getAddr(); + char *data = (char*)malloc(BT_DEV_ADDR_LEN+1); + for (int i = 0; i < BT_DEV_ADDR_LEN; i++) { + data[i] = gap_addr.addr[i]; + } + #if HAS_EEPROM + data[BT_DEV_ADDR_LEN] = EEPROM.read(eeprom_addr(ADDR_SIGNATURE)); + #else + data[BT_DEV_ADDR_LEN] = eeprom_read(eeprom_addr(ADDR_SIGNATURE)); + #endif + unsigned char *hash = MD5::make_hash(data, BT_DEV_ADDR_LEN); + memcpy(bt_dh, hash, BT_DEV_HASH_LEN); + sprintf(bt_devname, "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() { - if (bt_state == BT_STATE_OFF) { - Bluefruit.setName(bt_devname); - bledis.setManufacturer(BLE_MANUFACTURER); - bledis.setModel(BLE_MODEL); - // start device information service - bledis.begin(); + void bt_start() { + if (bt_state == BT_STATE_OFF) { + Bluefruit.setName(bt_devname); + bledis.setManufacturer(BLE_MANUFACTURER); + bledis.setModel(BLE_MODEL); + // start device information service + bledis.begin(); - SerialBT.bufferTXD(true); // enable buffering + SerialBT.bufferTXD(true); // enable buffering - SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial - SerialBT.begin(); + SerialBT.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // enable encryption for BLE serial + SerialBT.begin(); - blebas.begin(); + blebas.begin(); - Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); - // Include bleuart 128-bit uuid - Bluefruit.Advertising.addService(SerialBT); + // Include bleuart 128-bit uuid + Bluefruit.Advertising.addService(SerialBT); - // There is no room for Name in Advertising packet - // Use Scan response for Name - Bluefruit.ScanResponse.addName(); + // There is no room for Name in Advertising packet + // Use Scan response for Name + Bluefruit.ScanResponse.addName(); - Bluefruit.Advertising.start(0); + Bluefruit.Advertising.start(0); - bt_state = BT_STATE_ON; - } -} + bt_state = BT_STATE_ON; + } + } -bool bt_init() { + bool bt_init() { bt_state = BT_STATE_OFF; if (bt_setup_hw()) { if (bt_enabled && !console_active) bt_start(); @@ -410,18 +533,18 @@ bool bt_init() { } else { return false; } -} - -void bt_enable_pairing() { - if (bt_state == BT_STATE_OFF) bt_start(); - bt_allow_pairing = true; - bt_pairing_started = millis(); - bt_state = BT_STATE_PAIRING; -} - -void update_bt() { - if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { - bt_disable_pairing(); } -} + + void bt_enable_pairing() { + if (bt_state == BT_STATE_OFF) bt_start(); + bt_allow_pairing = true; + bt_pairing_started = millis(); + bt_state = BT_STATE_PAIRING; + } + + void update_bt() { + if (bt_allow_pairing && millis()-bt_pairing_started >= BT_PAIRING_TIMEOUT) { + bt_disable_pairing(); + } + } #endif diff --git a/Boards.h b/Boards.h index 12e8783..481866d 100644 --- a/Boards.h +++ b/Boards.h @@ -25,24 +25,100 @@ #define MCU_ESP32 0x81 #define MCU_NRF52 0x71 - // Boards - #define BOARD_RNODE 0x31 - #define BOARD_HMBRW 0x32 + // Products, boards and models. Grouped by manufacturer. + // Below are the original RNodes, sold by Mark Qvist. + #define PRODUCT_RNODE 0x03 // RNode devices + #define BOARD_RNODE 0x31 // Original v1.0 RNode + #define MODEL_A4 0xA4 // RNode v1.0, 433 MHz + #define MODEL_A9 0xA9 // RNode v1.0, 868 MHz + + #define BOARD_RNODE_NG_20 0x40 // RNode hardware revision v2.0 + #define MODEL_A3 0xA3 // RNode v2.0, 433 MHz + #define MODEL_A8 0xA8 // RNode v2.0, 868 MHz + + #define BOARD_RNODE_NG_21 0x41 // RNode hardware revision v2.1 + #define MODEL_A2 0xA2 // RNode v2.1, 433 MHz + #define MODEL_A7 0xA7 // RNode v2.1, 868 MHz + + #define BOARD_RNODE_NG_22 0x42 // RNode hardware revision v2.2 (T3S3) + #define MODEL_A1 0xA1 // RNode v2.2, 433 MHz with SX1268 + #define MODEL_A5 0xA5 // RNode v2.2, 433 MHz with SX1278 + #define MODEL_A6 0xA6 // RNode v2.2, 868 MHz with SX1262 + #define MODEL_AA 0xAA // RNode v2.2, 868 MHz with SX1276 + + #define PRODUCT_TBEAM 0xE0 // T-Beam - sold by LilyGO #define BOARD_TBEAM 0x33 + #define MODEL_E4 0xE4 // T-Beam SX1278, 433 Mhz + #define MODEL_E9 0xE9 // T-Beam SX1276, 868 Mhz + #define MODEL_E3 0xE3 // T-Beam SX1268, 433 Mhz + #define MODEL_E8 0xE8 // T-Beam SX1262, 868 Mhz + + #define PRODUCT_TDECK_V1 0xD0 // T-Deck - sold by LilyGO + #define BOARD_TDECK 0x3B + #define MODEL_D4 0xD4 // LilyGO T-Deck, 433 MHz + #define MODEL_D9 0xD9 // LilyGO T-Deck, 868 MHz + + #define PRODUCT_TBEAM_S_V1 0xEA // T-Beam Supreme - sold by LilyGO + #define BOARD_TBEAM_S_V1 0x3D + #define MODEL_DB 0xDB // LilyGO T-Beam Supreme, 433 MHz + #define MODEL_DC 0xDC // LilyGO T-Beam Supreme, 868 MHz + + #define PRODUCT_T32_10 0xB2 // T3 v1.0 - sold by LilyGO + #define BOARD_LORA32_V1_0 0x39 + #define MODEL_BA 0xBA // LilyGO T3 v1.0, 433 MHz + #define MODEL_BB 0xBB // LilyGO T3 v1.0, 868 MHz + + #define PRODUCT_T32_20 0xB0 // T3 v2.0 - sold by LilyGO + #define BOARD_LORA32_V2_0 0x36 + #define MODEL_B3 0xB3 // LilyGO T3 v2.0, 433 MHz + #define MODEL_B8 0xB8 // LilyGO T3 v2.0, 868 MHz + + #define PRODUCT_T32_21 0xB1 // T3 v2.1 - sold by LilyGO + #define BOARD_LORA32_V2_1 0x37 + #define MODEL_B4 0xB4 // LilyGO T3 v2.1, 433 MHz + #define MODEL_B9 0xB9 // LilyGO T3 v2.1, 868 MHz + + #define BOARD_T3S3 0x42 // T3S3 - sold by LilyGO + #define MODEL_A1 0xA1 // T3S3 SX1262 868/915 MHz + #define MODEL_AB 0xAB // T3S3 SX1276 868/915 MHz + #define MODEL_A5 0xA5 // T3S3 SX1280 PA (2.4GHz) + + #define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices + #define BOARD_TECHO 0x43 + #define MODEL_16 0x16 // T-Echo 433 MHz + #define MODEL_17 0x17 // T-Echo 868/915 MHz + + + #define PRODUCT_H32_V2 0xC0 // LoRa32 v2 - sold by Heltec + #define BOARD_HELTEC32_V2 0x38 + #define MODEL_C4 0xC4 // Heltec Lora32 v2, 433 MHz + #define MODEL_C9 0xC9 // Heltec Lora32 v2, 868 MHz + + #define PRODUCT_H32_V3 0xC1 // LoRa32 v3 - sold by Heltec + #define BOARD_HELTEC32_V3 0x3A + #define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz + #define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz + + #define PRODUCT_RAK4631 0x10 // RAK4631 - sold by RAKWireless + #define BOARD_RAK4631 0x51 + #define MODEL_11 0x11 // RAK4631, 433 MHz + #define MODEL_12 0x12 // RAK4631, 868 MHz + #define MODEL_13 0x13 // RAK4631, 433MHz with WisBlock SX1280 module (LIBSYS002) + #define MODEL_14 0x14 // RAK4631, 868/915 MHz with WisBlock SX1280 module (LIBSYS002) + + #define PRODUCT_OPENCOM_XL 0x20 // openCom XL - sold by Liberated Embedded Systems + #define MODEL_21 0x21 // openCom XL, 868/915 MHz + + #define BOARD_E22_ESP32 0x44 // Custom Ebyte E22 board design for meshtastic, source: + // https://github.com/NanoVHF/Meshtastic-DIY/blob/main/Schematics/E-Byte_E22/Mesh_Ebyte_E22-XXXM30S.pdf + + #define PRODUCT_HMBRW 0xF0 + #define BOARD_HMBRW 0x32 #define BOARD_HUZZAH32 0x34 #define BOARD_GENERIC_ESP32 0x35 - #define BOARD_LORA32_V2_0 0x36 - #define BOARD_LORA32_V2_1 0x37 - #define BOARD_LORA32_V1_0 0x39 - #define BOARD_HELTEC32_V2 0x38 - #define BOARD_HELTEC32_V3 0x3A - #define BOARD_RNODE_NG_20 0x40 - #define BOARD_RNODE_NG_21 0x41 - #define BOARD_T3S3 0x42 - #define BOARD_TECHO 0x43 - #define BOARD_E22_ESP32 0x44 #define BOARD_GENERIC_NRF52 0x50 - #define BOARD_RAK4631 0x51 + #define MODEL_FE 0xFE // Homebrew board, max 17dBm output power + #define MODEL_FF 0xFF // Homebrew board, max 14dBm output power // Displays #define OLED 0x01 @@ -132,7 +208,6 @@ #define DISPLAY OLED #define HAS_PMU true #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_SD false #define HAS_EEPROM true @@ -140,10 +215,39 @@ #define I2C_SCL 22 #define PMU_IRQ 35 #define INTERFACE_COUNT 1 + #define HAS_INPUT true + const int pin_btn_usr1 = 38; const int pin_led_rx = 2; const int pin_led_tx = 4; - const uint8_t interfaces[INTERFACE_COUNT] = {SX1262}; + #if BOARD_VARIANT == MODEL_E4 || BOARD_VARIANT == MODEL_E9 + const uint8_t interfaces[INTERFACE_COUNT] = {SX127X}; + const bool interface_cfg[INTERFACE_COUNT][3] = { + // SX127X + { + true, // DEFAULT_SPI + false, // HAS_TCXO + false // DIO2_AS_RF_SWITCH + }, + }; + const int8_t interface_pins[INTERFACE_COUNT][10] = { + // SX127X + { + 18, // pin_ss + -1, // pin_sclk + -1, // pin_mosi + -1, // pin_miso + -1, // pin_busy + 26, // pin_dio + 23, // pin_reset + -1, // pin_txen + -1, // pin_rxen + -1 // pin_tcxo_enable + } + }; + + #elif BOARD_VARIANT == MODEL_E3 || BOARD_VARIANT == MODEL_E8 + const uint8_t interfaces[INTERFACE_COUNT] = {SX126X}; const bool interface_cfg[INTERFACE_COUNT][3] = { // SX1262 { @@ -167,6 +271,7 @@ -1 // pin_tcxo_enable } }; + #endif #elif BOARD_MODEL == BOARD_HUZZAH32 #define HAS_BLUETOOTH true @@ -205,7 +310,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 @@ -249,7 +353,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 @@ -294,7 +397,6 @@ #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_BLUETOOTH true - #define HAS_BLE true #define HAS_PMU true #define HAS_CONSOLE true #define HAS_EEPROM true @@ -368,6 +470,13 @@ #define HAS_CONSOLE true #define HAS_EEPROM true #define INTERFACE_COUNT 1 + #define HAS_INPUT true + #define HAS_SLEEP true + #define PIN_WAKEUP GPIO_NUM_0 + #define WAKEUP_LEVEL 0 + + const int pin_btn_usr1 = 0; + #if defined(EXTERNAL_LEDS) const int pin_led_rx = 36; const int pin_led_tx = 37; @@ -406,7 +515,8 @@ #define HAS_DISPLAY true #define HAS_BLUETOOTH false #define HAS_BLE true - #define HAS_CONSOLE false + #define HAS_PMU true + #define HAS_CONSOLE true #define HAS_EEPROM true #define HAS_INPUT true #define HAS_SLEEP true @@ -552,7 +662,6 @@ #elif BOARD_MODEL == BOARD_T3S3 #define IS_ESP32S3 true - #define HAS_DISPLAY true #define DISPLAY OLED #define HAS_CONSOLE false @@ -580,6 +689,7 @@ const int SD_MOSI = 11; const int SD_CLK = 14; const int SD_CS = 13; + #if HAS_NP == false #if defined(EXTERNAL_LEDS) const int pin_led_rx = 37; @@ -665,9 +775,114 @@ -1 // pin_tcxo_enable } }; - #else - #error An unsupported ESP32 board was selected. Cannot compile RNode firmware. - #endif + + #elif BOARD_MODEL == BOARD_TDECK + #define IS_ESP32S3 true + #define MODEM SX1262 + #define DIO2_AS_RF_SWITCH true + #define HAS_BUSY true + #define HAS_TCXO true + + #define HAS_DISPLAY false + #define HAS_CONSOLE false + #define HAS_BLUETOOTH false + #define HAS_BLE true + #define HAS_PMU true + #define HAS_NP false + #define HAS_SD false + #define HAS_EEPROM true + + #define HAS_INPUT true + #define HAS_SLEEP true + #define PIN_WAKEUP GPIO_NUM_0 + #define WAKEUP_LEVEL 0 + + const int pin_poweron = 10; + const int pin_btn_usr1 = 0; + + const int pin_cs = 9; + const int pin_reset = 17; + const int pin_sclk = 40; + const int pin_mosi = 41; + const int pin_miso = 38; + const int pin_tcxo_enable = -1; + const int pin_dio = 45; + const int pin_busy = 13; + + const int SD_MISO = 38; + const int SD_MOSI = 41; + const int SD_CLK = 40; + const int SD_CS = 39; + + const int DISPLAY_DC = 11; + const int DISPLAY_CS = 12; + const int DISPLAY_MISO = 38; + const int DISPLAY_MOSI = 41; + const int DISPLAY_CLK = 40; + const int DISPLAY_BL_PIN = 42; + + #if HAS_NP == false + #if defined(EXTERNAL_LEDS) + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #else + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #endif + #endif + + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #define IS_ESP32S3 true + #define MODEM SX1262 + #define DIO2_AS_RF_SWITCH true + #define HAS_BUSY true + #define HAS_TCXO true + + #define HAS_DISPLAY true + #define HAS_CONSOLE true + #define HAS_BLUETOOTH false + #define HAS_BLE true + #define HAS_PMU true + #define HAS_NP false + #define HAS_SD false + #define HAS_EEPROM true + + #define HAS_INPUT true + #define HAS_SLEEP false + + #define PMU_IRQ 40 + #define I2C_SCL 41 + #define I2C_SDA 42 + + const int pin_btn_usr1 = 0; + + const int pin_cs = 10; + const int pin_reset = 5; + const int pin_sclk = 12; + const int pin_mosi = 11; + const int pin_miso = 13; + const int pin_tcxo_enable = -1; + const int pin_dio = 1; + const int pin_busy = 4; + + const int SD_MISO = 37; + const int SD_MOSI = 35; + const int SD_CLK = 36; + const int SD_CS = 47; + + const int IMU_CS = 34; + + #if HAS_NP == false + #if defined(EXTERNAL_LEDS) + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #else + const int pin_led_rx = 43; + const int pin_led_tx = 43; + #endif + #endif + #endif + #elif MCU_VARIANT == MCU_NRF52 #if BOARD_MODEL == BOARD_TECHO @@ -738,7 +953,7 @@ const int pin_led_rx = LED_BLUE; const int pin_led_tx = LED_RED; - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL #define HAS_EEPROM false #define HAS_DISPLAY true #define DISPLAY EINK_BW @@ -748,8 +963,9 @@ #define HAS_PMU true #define HAS_NP false #define HAS_SD false - #define CONFIG_UART_BUFFER_SIZE 40000 + #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 @@ -788,6 +1004,7 @@ #define INTERFACE_COUNT 2 #define CONFIG_QUEUE_1_SIZE 40000 + #define CONFIG_UART_BUFFER_SIZE 40000 // \todo, does it have to be this big? // first interface in list is the primary const uint8_t interfaces[INTERFACE_COUNT] = {SX126X, SX128X}; @@ -842,6 +1059,7 @@ const int pin_disp_busy = WB_IO4; const int pin_disp_en = WB_IO2; + const int pin_btn_usr1 = 9; const int pin_led_rx = LED_BLUE; const int pin_led_tx = LED_GREEN; diff --git a/Config.h b/Config.h index 9a46878..4798062 100644 --- a/Config.h +++ b/Config.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,7 +20,7 @@ #define CONFIG_H #define MAJ_VERS 0x01 - #define MIN_VERS 0x49 + #define MIN_VERS 0x4e #define MODE_HOST 0x11 #define MODE_TNC 0x12 @@ -65,7 +65,6 @@ // packet RSSI register const int rssi_offset = 157; - // Default LoRa settings const int lora_rx_turnaround_ms = 66; const int lora_post_tx_yield_slots = 6; @@ -78,6 +77,7 @@ bool pmu_ready = false; bool promisc = false; bool implicit = false; + bool memory_low = false; uint8_t implicit_l = 0; volatile bool packet_ready = false; @@ -90,7 +90,7 @@ int last_rssi = -292; uint8_t last_rssi_raw = 0x00; uint8_t last_snr_raw = 0x80; - uint8_t seq = 0xFF; + uint8_t seq[INTERFACE_COUNT]; uint16_t read_len = 0; bool serial_in_frame = false; @@ -115,9 +115,10 @@ unsigned long last_rx = 0; // Power management + #define BATTERY_STATE_UNKNOWN 0x00 #define BATTERY_STATE_DISCHARGING 0x01 - #define BATTERY_STATE_CHARGING 0x02 - #define BATTERY_STATE_CHARGED 0x03 + #define BATTERY_STATE_CHARGING 0x02 + #define BATTERY_STATE_CHARGED 0x03 bool battery_installed = false; bool battery_indeterminate = false; bool external_power = false; @@ -127,6 +128,7 @@ uint8_t battery_state = 0x00; uint8_t display_intensity = 0xFF; uint8_t display_addr = 0xFF; + bool display_blanking_enabled = false; bool display_diagnostics = true; bool device_init_done = false; bool eeprom_ok = false; @@ -134,9 +136,9 @@ // Boot flags #define START_FROM_BOOTLOADER 0x01 - #define START_FROM_POWERON 0x02 - #define START_FROM_BROWNOUT 0x03 - #define START_FROM_JTAG 0x04 + #define START_FROM_POWERON 0x02 + #define START_FROM_BROWNOUT 0x03 + #define START_FROM_JTAG 0x04 // Subinterfaces // select interface 0 by default diff --git a/Console.h b/Console.h index 4321d9f..c59d348 100644 --- a/Console.h +++ b/Console.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/Console/Makefile b/Console/Makefile index 6fdfc65..15d06d2 100644 --- a/Console/Makefile +++ b/Console/Makefile @@ -21,7 +21,7 @@ pages-debug: sourcepack: @echo Packing firmware sources... - zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h ../Input.h ../LICENSE ../Makefile ../MD5.cpp ../MD5.h ../Modem.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../sx126x.cpp ../sx126x.h ../sx127x.cpp ../sx127x.h ../sx128x.cpp ../sx128x.h ../Utilities.h + zip --junk-paths -r build/pkg/rnode_firmware.zip ../arduino-cli.yaml ../src/ble/BLESerial.cpp ../src/ble/BLESerial.h ../Bluetooth.h ../Boards.h ../Config.h ../Console.h ../Device.h ../Display.h ../Framing.h ../Graphics.h .../Input.h ../Interfaces.h ../LICENSE ../Makefile ../src/misc/FIFOBuffer.c ../src/misc/FIFOBuffer.h ../src/misc/MD5.cpp ../src/misc/MD5.h ../partition_hashes ../Power.h ../README.md ../release_hashes.py ../RNode_Firmware_CE.ino ../ROM.h ../Radio.cpp ../Radio.hpp ../Utilities.h ../esp32_btbufs.py data: @echo Including assets... diff --git a/Console/build.py b/Console/build.py index 5d8a119..f61fc04 100644 --- a/Console/build.py +++ b/Console/build.py @@ -4,9 +4,9 @@ import sys import shutil packages = { - "rns": "rns-0.7.5-py3-none-any.whl", - "nomadnet": "nomadnet-0.4.9-py3-none-any.whl", - "lxmf": "lxmf-0.4.3-py3-none-any.whl", + "rns": "rns-0.8.2-py3-none-any.whl", + "nomadnet": "nomadnet-0.5.4-py3-none-any.whl", + "lxmf": "lxmf-0.5.5-py3-none-any.whl", "rnsh": "rnsh-0.1.4-py3-none-any.whl", } @@ -174,26 +174,34 @@ mf.write(help_redirect) mf.close() def optimise_manual(path): - pm = 110 + pm = 60 scale_imgs = [ ("_images/board_rnodev2.png", pm), ("_images/board_rnode.png", pm), - ("_images/board_heltec32.png", pm), + ("_images/board_heltec32v20.png", pm), + ("_images/board_heltec32v30.png", pm), ("_images/board_t3v21.png", pm), ("_images/board_t3v20.png", pm), - ("_images/sideband_devices.webp", pm), + ("_images/board_t3v10.png", pm), + ("_images/board_t3s3.png", pm), ("_images/board_tbeam.png", pm), + ("_images/board_tdeck.png", pm), + ("_images/board_rak4631.png", pm), + ("_images/board_tbeam_supreme.png", pm), + ("_images/sideband_devices.webp", pm), ("_images/nomadnet_3.png", pm), + ("_images/meshchat_1.webp", pm), ("_images/radio_is5ac.png", pm), ("_images/radio_rblhg5.png", pm), ("_static/rns_logo_512.png", 256), + ("../images/bg_h_1.webp", pm), ] import subprocess import shlex for i,s in scale_imgs: fp = path+"/"+i - resize = "convert "+fp+" -resize "+str(s)+" "+fp + resize = "convert "+fp+" -quality 25 -resize "+str(s)+" "+fp print(resize) subprocess.call(shlex.split(resize), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) @@ -205,6 +213,7 @@ def optimise_manual(path): "_static/scripts/furo.js.map", "_static/jquery-3.6.0.js", "_static/jquery.js", + "static/underscore-1.13.1.js", "_static/_sphinx_javascript_frameworks_compat.js", "_static/scripts/furo.js.LICENSE.txt", "_static/styles/furo-extensions.css.map", diff --git a/Device.h b/Device.h index a149221..ab84196 100644 --- a/Device.h +++ b/Device.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/Display.h b/Display.h index 0aa6a7f..4bfaf56 100644 --- a/Display.h +++ b/Display.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -13,16 +13,31 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . - #include #if DISPLAY == OLED #include #include -#define DISP_W 128 -#define DISP_H 64 #define DISPLAY_BLACK SSD1306_BLACK #define DISPLAY_WHITE SSD1306_WHITE + +#if BOARD_MODEL == BOARD_TDECK + #include + #define DISPLAY_BLACK ST77XX_BLACK + #define DISPLAY_WHITE ST77XX_WHITE +#elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #include + #define DISPLAY_BLACK ST77XX_BLACK + #define DISPLAY_WHITE ST77XX_WHITE +#else + #include + #include +#endif + +#include "Fonts/Org_01.h" + +#define DISP_W 128 +#define DISP_H 64 #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C void (*display_callback)(); void display_add_callback(void (*callback)()) { @@ -81,6 +96,11 @@ void busyCallback(const void* p) { #endif #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 @@ -99,6 +119,12 @@ void busyCallback(const void* p) { #define DISP_W 128 #define DISP_H 64 #define DISP_ADDR -1 +#elif BOARD_MODEL == BOARD_TBEAM_S_V1 + #define DISP_RST -1 + #define DISP_ADDR 0x3C + #define SCL_OLED 18 + #define SDA_OLED 17 + #define DISP_CUSTOM_ADDR false #else #define DISP_RST -1 #define DISP_ADDR 0x3C @@ -128,7 +154,13 @@ uint32_t last_epd_refresh = 0; #define REFRESH_PERIOD 300000 // 5 minutes in ms #else #if DISPLAY == OLED - Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); + #if BOARD_MODEL == BOARD_TDECK + Adafruit_ST7789 display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1); + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Adafruit_SH1106G display = Adafruit_SH1106G(DISP_W, DISP_H, &Wire, -1); + #else + Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST); + #endif float disp_target_fps = 7; #define SCREENSAVER_TIME 500 // ms uint32_t last_screensaver = 0; @@ -141,10 +173,12 @@ uint32_t last_epd_refresh = 0; #define DISP_MODE_LANDSCAPE 0x01 #define DISP_MODE_PORTRAIT 0x02 #define DISP_PIN_SIZE 6 +#define DISPLAY_BLANKING_TIMEOUT 15*1000 uint8_t disp_mode = DISP_MODE_UNKNOWN; uint8_t disp_ext_fb = false; unsigned char fb[512]; uint32_t last_disp_update = 0; +bool display_tx = false; int disp_update_interval = 1000/disp_target_fps; uint32_t last_page_flip = 0; @@ -171,7 +205,6 @@ uint8_t online_interfaces = 0; #define WATERFALL_SIZE 92 #else #define WATERFALL_SIZE int(DISP_H * 0.75) // default to 75% of the display height -// add more eink compatible boards here #endif int waterfall[INTERFACE_COUNT][WATERFALL_SIZE] = {0}; @@ -206,10 +239,40 @@ void update_area_positions() { uint8_t display_contrast = 0x00; #if DISPLAY == OLED -void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { +#if BOARD_MODEL == BOARD_TBEAM_S_V1 +void set_contrast(Adafruit_SH1106G *display, uint8_t value) { +} +#elif BOARD_MODEL == BOARD_TDECK +void set_contrast(Adafruit_ST7789 *display, uint8_t value) { +static uint8_t level = 0; +static uint8_t steps = 16; +if (value > 15) value = 15; +if (value == 0) { + digitalWrite(DISPLAY_BL_PIN, 0); + delay(3); + level = 0; + return; +} +if (level == 0) { + digitalWrite(DISPLAY_BL_PIN, 1); + level = steps; + delayMicroseconds(30); +} +int from = steps - level; +int to = steps - value; +int num = (steps + to - from) % steps; +for (int i = 0; i < num; i++) { + digitalWrite(DISPLAY_BL_PIN, 0); + digitalWrite(DISPLAY_BL_PIN, 1); +} +level = value; +} +#else + void set_contrast(Adafruit_SSD1306 *display, uint8_t contrast) { display->ssd1306_command(SSD1306_SETCONTRAST); display->ssd1306_command(contrast); -} + } +#endif #endif bool display_init() { @@ -267,6 +330,8 @@ bool display_init() { // check for any commands from the host. display.epd2.setBusyCallback(busyCallback); #endif + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Wire.begin(SDA_OLED, SCL_OLED); #endif #if DISP_CUSTOM_ADDR == true @@ -280,12 +345,17 @@ bool display_init() { uint8_t display_address = DISP_ADDR; #endif - - #if DISPLAY == OLED - if(!display.begin(SSD1306_SWITCHCAPVCC, display_address)) { - #elif DISPLAY == EINK_BW || DISPLAY == EINK_3C + #if DISPLAY == EINK_BW || DISPLAY == EINK_3C // don't check if display is actually connected if(false) { + #elif BOARD_MODEL == BOARD_TDECK + display.init(240, 320); + display.setSPISpeed(80e6); + if (false) { + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + if (!display.begin(display_address, true)) { + #else + if (!display.begin(SSD1306_SWITCHCAPVCC, display_address)) { #endif return false; } else { @@ -310,6 +380,9 @@ bool display_init() { #elif BOARD_MODEL == BOARD_TBEAM disp_mode = DISP_MODE_LANDSCAPE; display.setRotation(0); + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(1); #elif BOARD_MODEL == BOARD_HELTEC32_V2 disp_mode = DISP_MODE_PORTRAIT; display.setRotation(1); @@ -323,10 +396,13 @@ bool display_init() { display.setRotation(3); #elif BOARD_MODEL == BOARD_HELTEC32_V3 disp_mode = DISP_MODE_PORTRAIT; - // Antenna conx up display.setRotation(1); - // USB-C up - // display.setRotation(3); + #elif BOARD_MODEL == BOARD_RAK4631 + disp_mode = DISP_MODE_LANDSCAPE; + display.setRotation(0); + #elif BOARD_MODEL == BOARD_TDECK + disp_mode = DISP_MODE_PORTRAIT; + display.setRotation(3); #else disp_mode = DISP_MODE_PORTRAIT; display.setRotation(3); @@ -340,10 +416,14 @@ bool display_init() { disp_area.cp437(true); display.cp437(true); - #if HAS_EEPROM - display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); - #elif MCU_VARIANT == MCU_NRF52 - display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); + #if MCU_VARIANT != MCU_NRF52 + display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT)); + #else + display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT)); + #endif + + #if BOARD_MODEL == BOARD_TDECK + display.fillScreen(DISPLAY_BLACK); #endif return true; @@ -469,15 +549,23 @@ void draw_battery_bars(int px, int py) { if (pmu_ready) { if (battery_ready) { if (battery_installed) { - float battery_value = battery_percent; + float battery_value = battery_percent; + + // Disable charging state display for now, since + // boards without dedicated PMU are completely + // unreliable for determining actual charging state. + bool disable_charge_status = false; + if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING) { + disable_charge_status = true; + } - if (battery_state == BATTERY_STATE_CHARGING) { + if (battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { battery_value = charge_tick; charge_tick += 3; if (charge_tick > 100) charge_tick = 0; } - if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING) { + if (battery_indeterminate && battery_state == BATTERY_STATE_CHARGING && !disable_charge_status) { #if DISP_H == 122 stat_area.fillRect(px-2, py-2, 24, 9, DISPLAY_BLACK); stat_area.drawBitmap(px-2, py-5, bm_plug, 34, 13, DISPLAY_WHITE, DISPLAY_BLACK); @@ -551,113 +639,115 @@ void draw_battery_bars(int px, int py) { #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; - #if DISP_H == 122 - stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); - if (quality > 0) { - stat_area.drawLine(px+0*4, py+14, px+0*4, py+6, DISPLAY_WHITE); - stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+6, DISPLAY_WHITE); - } - if (quality > 15) { - stat_area.drawLine(px+1*4, py+14, px+1*4, py+5, DISPLAY_WHITE); - stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+5, DISPLAY_WHITE); - } - if (quality > 30) { - stat_area.drawLine(px+2*4, py+14, px+2*4, py+4, DISPLAY_WHITE); - stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+4, DISPLAY_WHITE); - } - if (quality > 45) { - stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); - stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); - } - if (quality > 60) { - stat_area.drawLine(px+4*4, py+14, px+4*4, py+2, DISPLAY_WHITE); - stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+2, DISPLAY_WHITE); - } - if (quality > 75) { - stat_area.drawLine(px+5*4, py+14, px+5*4, py+1, DISPLAY_WHITE); - stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+1, DISPLAY_WHITE); - } - if (quality > 90) { - stat_area.drawLine(px+6*4, py+14, px+6*4, py+0, DISPLAY_WHITE); - stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+0, DISPLAY_WHITE); - } - #else - stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); - if (quality > 0) stat_area.drawLine(px+0*2, py+7, px+0*2, py+6, DISPLAY_WHITE); - if (quality > 15) stat_area.drawLine(px+1*2, py+7, px+1*2, py+5, DISPLAY_WHITE); - if (quality > 30) stat_area.drawLine(px+2*2, py+7, px+2*2, py+4, DISPLAY_WHITE); - if (quality > 45) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); - if (quality > 60) stat_area.drawLine(px+4*2, py+7, px+4*2, py+2, DISPLAY_WHITE); - if (quality > 75) stat_area.drawLine(px+5*2, py+7, px+5*2, py+1, DISPLAY_WHITE); - if (quality > 90) stat_area.drawLine(px+6*2, py+7, px+6*2, py+0, DISPLAY_WHITE); - #endif - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); +#if DISP_H == 122 + stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); + if (quality > 0) { + stat_area.drawLine(px+0*4, py+14, px+0*4, py+6, DISPLAY_WHITE); + stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+6, DISPLAY_WHITE); + } + if (quality > 15) { + stat_area.drawLine(px+1*4, py+14, px+1*4, py+5, DISPLAY_WHITE); + stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+5, DISPLAY_WHITE); + } + if (quality > 30) { + stat_area.drawLine(px+2*4, py+14, px+2*4, py+4, DISPLAY_WHITE); + stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+4, DISPLAY_WHITE); + } + if (quality > 45) { + stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); + stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); + } + if (quality > 60) { + stat_area.drawLine(px+4*4, py+14, px+4*4, py+2, DISPLAY_WHITE); + stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+2, DISPLAY_WHITE); + } + if (quality > 75) { + stat_area.drawLine(px+5*4, py+14, px+5*4, py+1, DISPLAY_WHITE); + stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+1, DISPLAY_WHITE); + } + if (quality > 90) { + stat_area.drawLine(px+6*4, py+14, px+6*4, py+0, DISPLAY_WHITE); + stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+0, DISPLAY_WHITE); + } +#else + stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); + if (quality > 0) stat_area.drawLine(px+0*2, py+7, px+0*2, py+6, DISPLAY_WHITE); + if (quality > 15) stat_area.drawLine(px+1*2, py+7, px+1*2, py+5, DISPLAY_WHITE); + if (quality > 30) stat_area.drawLine(px+2*2, py+7, px+2*2, py+4, DISPLAY_WHITE); + if (quality > 45) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); + if (quality > 60) stat_area.drawLine(px+4*2, py+7, px+4*2, py+2, DISPLAY_WHITE); + if (quality > 75) stat_area.drawLine(px+5*2, py+7, px+5*2, py+1, DISPLAY_WHITE); + if (quality > 90) stat_area.drawLine(px+6*2, py+7, px+6*2, py+0, DISPLAY_WHITE); +#endif + // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); } #define S_RSSI_MIN -135.0 #define S_RSSI_MAX -75.0 #define S_RSSI_SPAN (S_RSSI_MAX-S_RSSI_MIN) void draw_signal_bars(int px, int py) { - int rssi_val = last_rssi; - if (rssi_val < S_RSSI_MIN) rssi_val = S_RSSI_MIN; - if (rssi_val > S_RSSI_MAX) rssi_val = S_RSSI_MAX; - int signal = ((rssi_val - S_RSSI_MIN)*(1.0/S_RSSI_SPAN))*100.0; + int rssi_val = last_rssi; + if (rssi_val < S_RSSI_MIN) rssi_val = S_RSSI_MIN; + if (rssi_val > S_RSSI_MAX) rssi_val = S_RSSI_MAX; + int signal = ((rssi_val - S_RSSI_MIN)*(1.0/S_RSSI_SPAN))*100.0; - if (signal > 100.0) signal = 100.0; - if (signal < 0.0) signal = 0.0; + if (signal > 100.0) signal = 100.0; + if (signal < 0.0) signal = 0.0; - #if DISP_H == 122 - stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); - if (signal > 85) { - stat_area.drawLine(px+0*4, py+14, px+0*4, py+0, DISPLAY_WHITE); - stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+0, DISPLAY_WHITE); - } - if (signal > 72) { - stat_area.drawLine(px+1*4, py+14, px+1*4, py+1, DISPLAY_WHITE); - stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+1, DISPLAY_WHITE); - } - if (signal > 59) { - stat_area.drawLine(px+2*4, py+14, px+2*4, py+2, DISPLAY_WHITE); - stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+2, DISPLAY_WHITE); - } - if (signal > 46) { - stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); - stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); - } - if (signal > 33) { - stat_area.drawLine(px+4*4, py+14, px+4*4, py+4, DISPLAY_WHITE); - stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+4, DISPLAY_WHITE); - } - if (signal > 20) { - stat_area.drawLine(px+5*4, py+14, px+5*4, py+5, DISPLAY_WHITE); - stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+5, DISPLAY_WHITE); - } - if (signal > 7) { - stat_area.drawLine(px+6*4, py+14, px+6*4, py+6, DISPLAY_WHITE); - stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+6, DISPLAY_WHITE); - } - #else - stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); - if (signal > 85) stat_area.drawLine(px+0*2, py+7, px+0*2, py+0, DISPLAY_WHITE); - if (signal > 72) stat_area.drawLine(px+1*2, py+7, px+1*2, py+1, DISPLAY_WHITE); - if (signal > 59) stat_area.drawLine(px+2*2, py+7, px+2*2, py+2, DISPLAY_WHITE); - if (signal > 46) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); - if (signal > 33) stat_area.drawLine(px+4*2, py+7, px+4*2, py+4, DISPLAY_WHITE); - if (signal > 20) stat_area.drawLine(px+5*2, py+7, px+5*2, py+5, DISPLAY_WHITE); - if (signal > 7) stat_area.drawLine(px+6*2, py+7, px+6*2, py+6, DISPLAY_WHITE); - #endif - // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); +#if DISP_H == 122 + stat_area.fillRect(px, py, 26, 14, DISPLAY_BLACK); + if (signal > 85) { + stat_area.drawLine(px+0*4, py+14, px+0*4, py+0, DISPLAY_WHITE); + stat_area.drawLine(px+0*4+1, py+14, px+0*4+1, py+0, DISPLAY_WHITE); + } + if (signal > 72) { + stat_area.drawLine(px+1*4, py+14, px+1*4, py+1, DISPLAY_WHITE); + stat_area.drawLine(px+1*4+1, py+14, px+1*4+1, py+1, DISPLAY_WHITE); + } + if (signal > 59) { + stat_area.drawLine(px+2*4, py+14, px+2*4, py+2, DISPLAY_WHITE); + stat_area.drawLine(px+2*4+1, py+14, px+2*4+1, py+2, DISPLAY_WHITE); + } + if (signal > 46) { + stat_area.drawLine(px+3*4, py+14, px+3*4, py+3, DISPLAY_WHITE); + stat_area.drawLine(px+3*4+1, py+14, px+3*4+1, py+3, DISPLAY_WHITE); + } + if (signal > 33) { + stat_area.drawLine(px+4*4, py+14, px+4*4, py+4, DISPLAY_WHITE); + stat_area.drawLine(px+4*4+1, py+14, px+4*4+1, py+4, DISPLAY_WHITE); + } + if (signal > 20) { + stat_area.drawLine(px+5*4, py+14, px+5*4, py+5, DISPLAY_WHITE); + stat_area.drawLine(px+5*4+1, py+14, px+5*4+1, py+5, DISPLAY_WHITE); + } + if (signal > 7) { + stat_area.drawLine(px+6*4, py+14, px+6*4, py+6, DISPLAY_WHITE); + stat_area.drawLine(px+6*4+1, py+14, px+6*4+1, py+6, DISPLAY_WHITE); + } +#else + stat_area.fillRect(px, py, 13, 7, DISPLAY_BLACK); + if (signal > 85) stat_area.drawLine(px+0*2, py+7, px+0*2, py+0, DISPLAY_WHITE); + if (signal > 72) stat_area.drawLine(px+1*2, py+7, px+1*2, py+1, DISPLAY_WHITE); + if (signal > 59) stat_area.drawLine(px+2*2, py+7, px+2*2, py+2, DISPLAY_WHITE); + if (signal > 46) stat_area.drawLine(px+3*2, py+7, px+3*2, py+3, DISPLAY_WHITE); + if (signal > 33) stat_area.drawLine(px+4*2, py+7, px+4*2, py+4, DISPLAY_WHITE); + if (signal > 20) stat_area.drawLine(px+5*2, py+7, px+5*2, py+5, DISPLAY_WHITE); + if (signal > 7) stat_area.drawLine(px+6*2, py+7, px+6*2, py+6, DISPLAY_WHITE); +#endif + // Serial.printf("Last SNR: %.2f\n, quality: %.2f\n", snr, quality); } +#define WF_TX_SIZE 5 +#define WF_TX_WIDTH 5 #define WF_RSSI_MAX -60 #define WF_RSSI_MIN -135 #define WF_RSSI_SPAN (WF_RSSI_MAX - WF_RSSI_MIN) @@ -673,9 +763,16 @@ void draw_waterfall(int px, int py) { 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; - - waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; - if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; + if (display_tx) { + for (uint8_t i; i < WF_TX_SIZE; i++) { + waterfall[interface_page][waterfall_head[interface_page]++] = -1; + if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; + } + display_tx = false; + } else { + waterfall[interface_page][waterfall_head[interface_page]++] = rssi_normalised; + if (waterfall_head[interface_page] >= WATERFALL_SIZE) waterfall_head[interface_page] = 0; + } stat_area.fillRect(px,py,WF_PIXEL_WIDTH, WATERFALL_SIZE, DISPLAY_BLACK); for (int i = 0; i < WATERFALL_SIZE; i++){ @@ -683,6 +780,11 @@ void draw_waterfall(int px, int py) { 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); + } } } } @@ -1117,9 +1219,7 @@ void update_display(bool blank = false) { } else { if (millis()-last_disp_update >= disp_update_interval) { uint32_t current = millis(); - #if screensaver_enabled - do_screensaver(current); - #endif + do_screensaver(current); #if DISPLAY == EINK_BW || DISPLAY == EINK_3C display.setFullWindow(); display.fillScreen(DISPLAY_WHITE); diff --git a/Framing.h b/Framing.h index 7b1c930..980edbd 100644 --- a/Framing.h +++ b/Framing.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -53,6 +53,8 @@ #define CMD_FB_READL 0x44 #define CMD_DISP_INT 0x45 #define CMD_DISP_ADDR 0x63 + #define CMD_DISP_BLNK 0x64 + #define CMD_NP_INT 0x65 #define CMD_BT_CTRL 0x46 #define CMD_BT_PIN 0x62 @@ -118,6 +120,8 @@ #define ERROR_TXFAILED 0x02 #define ERROR_EEPROM_LOCKED 0x03 #define ERROR_QUEUE_FULL 0x04 + #define ERROR_MEMORY_LOW 0x05 + #define ERROR_MODEM_TIMEOUT 0x06 // Serial framing variables size_t frame_len; diff --git a/Graphics.h b/Graphics.h index 3d74c0f..faf5f2f 100644 --- a/Graphics.h +++ b/Graphics.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/Makefile b/Makefile index cd4df9c..ec202e3 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,7 +13,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -ESP_IDF_VER = 2.0.17 +# Version 2.0.17 of the Arduino ESP core is based on ESP-IDF v4.4.7 +ARDUINO_ESP_CORE_VER = 2.0.17 V ?= 0 VFLAG = @@ -36,8 +37,11 @@ prep-index: arduino-cli core update-index --config-file arduino-cli.yaml prep-esp32: - arduino-cli core install esp32:esp32@$(ESP_IDF_VER) --config-file arduino-cli.yaml + arduino-cli core install esp32:esp32@$(ARDUINO_ESP_CORE_VER) --config-file arduino-cli.yaml arduino-cli lib install "Adafruit SSD1306" + arduino-cli lib install "Adafruit SH110X" + arduino-cli lib install "Adafruit ST7735 and ST7789 Library" + arduino-cli lib install "Adafruit NeoPixel" arduino-cli lib install "XPowersLib" arduino-cli lib install "Crypto" arduino-cli lib install "Adafruit NeoPixel" @@ -66,11 +70,14 @@ upload-spiffs: firmware: $(shell grep ^firmware- Makefile | cut -d: -f1) -firmware-tbeam: - arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" +check_bt_buffers: + @./esp32_btbufs.py ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/libraries/BluetoothSerial/src/BluetoothSerial.cpp -firmware-tbeam_sx126x: - arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\"" +firmware-tbeam: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE4\"" + +firmware-tbeam_sx1262: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE8\"" firmware-techo: firmware-techo4 firmware-techo9 @@ -80,7 +87,10 @@ firmware-techo4: firmware-techo9: arduino-cli compile --fqbn adafruit:nrf52:pca10056 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x43\" \"-DBOARD_VARIANT=0x17\"" -firmware-t3s3_sx1262: +firmware-t3s3: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xAB\"" + +firmware-t3s3_sx126x: arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_VARIANT=0xA1\"" firmware-t3s3_sx1280_pa: @@ -89,43 +99,43 @@ firmware-t3s3_sx1280_pa: firmware-e22_esp32: arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\" \"-DEXTERNAL_LEDS=true\"" -firmware-lora32_v10: +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_v10_extled: +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_v20: +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: +firmware-lora32_v21: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" -firmware-lora32_v21_extled: +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: +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: +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: +firmware-heltec32_v2_extled: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\" \"-DEXTERNAL_LEDS=true\"" firmware-heltec32_v3: arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V3 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3A\"" -firmware-rnode_ng_20: +firmware-rnode_ng_20: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x40\"" -firmware-rnode_ng_21: +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: +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: +firmware-genericesp32: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" firmware-rak4631: @@ -134,9 +144,10 @@ firmware-rak4631: 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\"" -firmware-freenode: +firmware-opencom-xl: arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x21\"" + upload-tbeam: arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:t-beam @sleep 1 @@ -184,6 +195,20 @@ upload-heltec32_v3: @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-tdeck: + arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 + @sleep 1 + rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32-s3 $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + +upload-tbeam_supreme: + arduino-cli upload -p $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 + @sleep 1 + rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32-s3 $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin + upload-rnode_ng_20: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:ttgo-lora32 @sleep 1 @@ -199,17 +224,11 @@ upload-rnode_ng_21: python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyACM0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin upload-t3s3: - @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 $(or $(port), /dev/ttyACM0) --fqbn esp32:esp32:esp32s3 - @sleep 2 - python3 ./Release/esptool/esptool.py --chip esp32s3 --port $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin - @echo - @echo Press the RESET button on the board now, and hit enter - @read @sleep 1 rnodeconf $(or $(port), /dev/ttyACM0) --firmware-hash $$(./partition_hashes ./build/esp32.esp32.esp32s3/RNode_Firmware_CE.ino.bin) + @sleep 3 + python ./Release/esptool/esptool.py --chip esp32s3 $(or $(port), /dev/ttyACM0) --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin upload-featheresp32: arduino-cli upload -p $(or $(port), /dev/ttyUSB0) --fqbn esp32:esp32:featheresp32 @@ -230,15 +249,13 @@ upload-e22_esp32: @sleep 3 python3 ./Release/esptool/esptool.py --port $(or $(port), /dev/ttyUSB0) $(COMMON_ESP_UPLOAD_FlAGS) ./Release/console_image.bin -release: release-all - -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-e22_esp32 release-hashes +release: console-site spiffs-image $(shell grep ^release- Makefile | cut -d: -f1) release-hashes: python3 ./release_hashes.py > ./Release/release.json -release-tbeam: - arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\"" +release-tbeam: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_VARIANT=0xE4\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam.boot_app0 cp build/esp32.esp32.t-beam/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 @@ -246,8 +263,8 @@ release-tbeam: zip --junk-paths ./Release/rnode_firmware_tbeam.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam.boot_app0 build/rnode_firmware_tbeam.bin build/rnode_firmware_tbeam.bootloader build/rnode_firmware_tbeam.partitions rm -r build -release-tbeam_sx1262: - arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\"" +release-tbeam_sx1262: check_bt_buffers + arduino-cli compile --fqbn esp32:esp32:t-beam $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DBOARD_MODEL=E8\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_sx1262.boot_app0 cp build/esp32.esp32.t-beam/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 @@ -255,7 +272,7 @@ release-tbeam_sx1262: zip --junk-paths ./Release/rnode_firmware_tbeam_sx1262.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_sx1262.boot_app0 build/rnode_firmware_tbeam_sx1262.bin build/rnode_firmware_tbeam_sx1262.bootloader build/rnode_firmware_tbeam_sx1262.partitions rm -r build -release-lora32_v10: +release-lora32_v10: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v10.bin @@ -264,7 +281,7 @@ release-lora32_v10: zip --junk-paths ./Release/rnode_firmware_lora32v10.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v10.boot_app0 build/rnode_firmware_lora32v10.bin build/rnode_firmware_lora32v10.bootloader build/rnode_firmware_lora32v10.partitions rm -r build -release-lora32_v20: +release-lora32_v20: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v20.bin @@ -273,7 +290,7 @@ release-lora32_v20: zip --junk-paths ./Release/rnode_firmware_lora32v20.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v20.boot_app0 build/rnode_firmware_lora32v20.bin build/rnode_firmware_lora32v20.bootloader build/rnode_firmware_lora32v20.partitions rm -r build -release-lora32_v21: +release-lora32_v21: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21.bin @@ -282,7 +299,7 @@ release-lora32_v21: zip --junk-paths ./Release/rnode_firmware_lora32v21.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21.boot_app0 build/rnode_firmware_lora32v21.bin build/rnode_firmware_lora32v21.bootloader build/rnode_firmware_lora32v21.partitions rm -r build -release-lora32_v10_extled: +release-lora32_v10_extled: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x39\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v10.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v10.bin @@ -291,7 +308,7 @@ release-lora32_v10_extled: zip --junk-paths ./Release/rnode_firmware_lora32v10.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v10.boot_app0 build/rnode_firmware_lora32v10.bin build/rnode_firmware_lora32v10.bootloader build/rnode_firmware_lora32v10.partitions rm -r build -release-lora32_v20_extled: +release-lora32_v20_extled: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x36\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v20.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v20.bin @@ -300,7 +317,7 @@ release-lora32_v20_extled: zip --junk-paths ./Release/rnode_firmware_lora32v20_extled.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v20.boot_app0 build/rnode_firmware_lora32v20.bin build/rnode_firmware_lora32v20.bootloader build/rnode_firmware_lora32v20.partitions rm -r build -release-lora32_v21_extled: +release-lora32_v21_extled: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DEXTERNAL_LEDS=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21.bin @@ -309,7 +326,7 @@ release-lora32_v21_extled: zip --junk-paths ./Release/rnode_firmware_lora32v21_extled.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21.boot_app0 build/rnode_firmware_lora32v21.bin build/rnode_firmware_lora32v21.bootloader build/rnode_firmware_lora32v21.partitions rm -r build -release-lora32_v21_tcxo: +release-lora32_v21_tcxo: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:ttgo-lora32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x37\" \"-DENABLE_TCXO=true\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_lora32v21_tcxo.boot_app0 cp build/esp32.esp32.ttgo-lora32/RNode_Firmware_CE.ino.bin build/rnode_firmware_lora32v21_tcxo.bin @@ -318,53 +335,51 @@ release-lora32_v21_tcxo: zip --junk-paths ./Release/rnode_firmware_lora32v21_tcxo.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_lora32v21_tcxo.boot_app0 build/rnode_firmware_lora32v21_tcxo.bin build/rnode_firmware_lora32v21_tcxo.bootloader build/rnode_firmware_lora32v21_tcxo.partitions rm -r build -release-heltec32_v2: +release-heltec32_v2: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:heltec_wifi_lora_32_V2 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x38\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0 cp build/esp32.esp32.heltec_wifi_lora_32_V2/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-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/$(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 + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v3.boot_app0 + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v3.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v3.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v3.partitions zip --junk-paths ./Release/rnode_firmware_heltec32v3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v3.boot_app0 build/rnode_firmware_heltec32v3.bin build/rnode_firmware_heltec32v3.bootloader build/rnode_firmware_heltec32v3.partitions rm -r build -release-heltec32_v2_extled: +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/$(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 + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_heltec32v2.boot_app0 + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bin build/rnode_firmware_heltec32v2.bin + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_heltec32v2.bootloader + cp build/esp32.esp32.heltec_wifi_lora_32_V2/RNode_Firmware.ino.partitions.bin build/rnode_firmware_heltec32v2.partitions zip --junk-paths ./Release/rnode_firmware_heltec32v2.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_heltec32v2.boot_app0 build/rnode_firmware_heltec32v2.bin build/rnode_firmware_heltec32v2.bootloader build/rnode_firmware_heltec32v2.partitions rm -r build -release-rnode_ng_20: +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/$(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 + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng20.boot_app0 + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng20.bin + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng20.bootloader + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng20.partitions zip --junk-paths ./Release/rnode_firmware_ng20.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng20.boot_app0 build/rnode_firmware_ng20.bin build/rnode_firmware_ng20.bootloader build/rnode_firmware_ng20.partitions rm -r build -release-rnode_ng_21: +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/$(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 + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_ng21.boot_app0 + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bin build/rnode_firmware_ng21.bin + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_ng21.bootloader + cp build/esp32.esp32.ttgo-lora32/RNode_Firmware.ino.partitions.bin build/rnode_firmware_ng21.partitions zip --junk-paths ./Release/rnode_firmware_ng21.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_ng21.boot_app0 build/rnode_firmware_ng21.bin build/rnode_firmware_ng21.bootloader build/rnode_firmware_ng21.partitions rm -r build release-t3s3: - arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\"" + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_MODEL=0xAB\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3.boot_app0 cp build/esp32.esp32.esp32s3/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 @@ -373,7 +388,7 @@ release-t3s3: rm -r build release-e22_esp32: - 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=0x44\"" + arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_e22.boot_app0 cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin build/rnode_firmware_esp32_e22.bin cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bootloader.bin build/rnode_firmware_esp32_e22.bootloader @@ -381,7 +396,35 @@ release-e22_esp32: 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-featheresp32: +release-t3s3_sx126x: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DBOARD_MODEL=0xA1\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx126x.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_t3s3_sx126x.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_t3s3_sx126x.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_t3s3_sx126x.partitions + zip --junk-paths ./Release/rnode_firmware_t3s3_sx126x.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx126x.boot_app0 build/rnode_firmware_t3s3_sx126x.bin build/rnode_firmware_t3s3_sx126x.bootloader build/rnode_firmware_t3s3_sx126x.partitions + rm -r build + +release-tdeck: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tdeck.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tdeck.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tdeck.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tdeck.partitions + zip --junk-paths ./Release/rnode_firmware_tdeck.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tdeck.boot_app0 build/rnode_firmware_tdeck.bin build/rnode_firmware_tdeck.bootloader build/rnode_firmware_tdeck.partitions + rm -r build + +release-tbeam_supreme: + arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3D\"" + cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_supreme.boot_app0 + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_tbeam_supreme.bin + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tbeam_supreme.bootloader + cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tbeam_supreme.partitions + zip --junk-paths ./Release/rnode_firmware_tbeam_supreme.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_supreme.boot_app0 build/rnode_firmware_tbeam_supreme.bin build/rnode_firmware_tbeam_supreme.bootloader build/rnode_firmware_tbeam_supreme.partitions + rm -r build + + +release-featheresp32: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:featheresp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x34\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_featheresp32.boot_app0 cp build/esp32.esp32.featheresp32/RNode_Firmware_CE.ino.bin build/rnode_firmware_featheresp32.bin @@ -390,7 +433,7 @@ release-featheresp32: zip --junk-paths ./Release/rnode_firmware_featheresp32.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_featheresp32.boot_app0 build/rnode_firmware_featheresp32.bin build/rnode_firmware_featheresp32.bootloader build/rnode_firmware_featheresp32.partitions rm -r build -release-genericesp32: +release-genericesp32: check_bt_buffers arduino-cli compile --fqbn esp32:esp32:esp32 $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x35\"" cp ~/.arduino15/packages/esp32/hardware/esp32/$(ESP_IDF_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_esp32_generic.boot_app0 cp build/esp32.esp32.esp32/RNode_Firmware_CE.ino.bin build/rnode_firmware_esp32_generic.bin @@ -409,7 +452,7 @@ release-rak4631_sx1280: cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_rak4631_sx1280.hex adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_rak4631_sx1280.hex Release/rnode_firmware_rak4631_sx1280.zip -release-freenode: +release-opencom-xl: arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board $(COMMON_BUILD_FLAGS) --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\" \"-DBOARD_VARIANT=0x21\"" - cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_freenode.hex - adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_freenode.hex Release/rnode_firmware_freenode.zip + cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware_CE.ino.hex build/rnode_firmware_opencom_xl.hex + adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_opencom_xl.hex Release/rnode_firmware_opencom_xl.zip diff --git a/Power.h b/Power.h index 56bcf16..0aec818 100644 --- a/Power.h +++ b/Power.h @@ -1,9 +1,28 @@ -#if BOARD_MODEL == BOARD_TBEAM +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#if BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 #include XPowersLibInterface* PMU = NULL; #ifndef PMU_WIRE_PORT - #define PMU_WIRE_PORT Wire + #if BOARD_MODEL == BOARD_TBEAM_S_V1 + #define PMU_WIRE_PORT Wire1 + #else + #define PMU_WIRE_PORT Wire + #endif #endif #define BAT_V_MIN 3.15 @@ -28,8 +47,6 @@ pmuInterrupt = true; } #elif BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 - #define BAT_C_SAMPLES 7 - #define BAT_D_SAMPLES 2 #define BAT_V_MIN 3.15 #define BAT_V_MAX 4.3 #define BAT_V_CHG 4.48 @@ -44,26 +61,60 @@ 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; + #include "nrfx_power.h" + #define BAT_C_SAMPLES 7 + #define BAT_D_SAMPLES 2 + #define BAT_V_MIN 2.75 + #define BAT_V_MAX 4.2 + #define BAT_V_FLOAT 4.22 + #define BAT_SAMPLES 5 + #define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12 - bit ADC resolution = 3000mV / 4096 + #define VBAT_DIVIDER_COMP (1.73) // Compensation factor for the VBAT divider + #define VBAT_MV_PER_LSB_FIN (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) + #define PIN_VBAT WB_A0 + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; +#elif BOARD_MODEL == BOARD_TDECK + #define BAT_V_MIN 3.15 + #define BAT_V_MAX 4.3 + #define BAT_V_CHG 4.48 + #define BAT_V_FLOAT 4.33 + #define BAT_SAMPLES 5 + const uint8_t pin_vbat = 4; + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; + float bat_state_change_v = 0; +#elif BOARD_MODEL == BOARD_HELTEC32_V3 + #define BAT_V_MIN 3.15 + #define BAT_V_MAX 4.3 + #define BAT_V_CHG 4.48 + #define BAT_V_FLOAT 4.33 + #define BAT_SAMPLES 7 + const uint8_t pin_vbat = 1; + const uint8_t pin_ctrl = 37; + float bat_p_samples[BAT_SAMPLES]; + float bat_v_samples[BAT_SAMPLES]; + uint8_t bat_samples_count = 0; + int bat_discharging_samples = 0; + int bat_charging_samples = 0; + int bat_charged_samples = 0; + bool bat_voltage_dropping = false; + float bat_delay_v = 0; + float bat_state_change_v = 0; #endif uint32_t last_pmu_update = 0; @@ -74,10 +125,17 @@ uint8_t pmu_rc = 0; void kiss_indicate_battery(); void measure_battery() { - #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK battery_installed = true; battery_indeterminate = true; - bat_v_samples[bat_samples_count%BAT_SAMPLES] = (float)(analogRead(pin_vbat)) / 4095*2*3.3*1.1; + + #if BOARD_MODEL == BOARD_HELTEC32_V3 + float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041; + #else + float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*2.0*3.3*1.1; + #endif + + bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement; bat_p_samples[bat_samples_count%BAT_SAMPLES] = ((battery_voltage-BAT_V_MIN) / (BAT_V_MAX-BAT_V_MIN))*100.0; bat_samples_count++; @@ -100,41 +158,60 @@ void measure_battery() { battery_voltage = battery_voltage/BAT_SAMPLES; if (bat_delay_v == 0) bat_delay_v = battery_voltage; + if (bat_state_change_v == 0) bat_state_change_v = battery_voltage; if (battery_percent > 100.0) battery_percent = 100.0; if (battery_percent < 0.0) battery_percent = 0.0; if (bat_samples_count%BAT_SAMPLES == 0) { + float bat_delay_diff = bat_state_change_v-battery_voltage; + if (bat_delay_diff < 0) { bat_delay_diff *= -1; } + if (battery_voltage < bat_delay_v && battery_voltage < BAT_V_FLOAT) { - bat_voltage_dropping = true; + if (bat_voltage_dropping == false) { + if (bat_delay_diff > 0.008) { + bat_voltage_dropping = true; + bat_state_change_v = battery_voltage; + // SerialBT.printf("STATE CHANGE to DISCHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); + } + } } else { - bat_voltage_dropping = false; + if (bat_voltage_dropping == true) { + if (bat_delay_diff > 0.01) { + bat_voltage_dropping = false; + bat_state_change_v = battery_voltage; + // SerialBT.printf("STATE CHANGE to CHARGE at delta=%.3fv. State change v is now %.3fv.\n", bat_delay_diff, bat_state_change_v); + } + } } bat_samples_count = 0; + bat_delay_v = battery_voltage; } if (bat_voltage_dropping && battery_voltage < BAT_V_FLOAT) { battery_state = BATTERY_STATE_DISCHARGING; } else { - #if BOARD_MODEL == BOARD_RNODE_NG_21 + if (battery_percent < 100.0) { battery_state = BATTERY_STATE_CHARGING; - #else - battery_state = BATTERY_STATE_DISCHARGING; - #endif + } else { + battery_state = BATTERY_STATE_CHARGED; + } } - - // if (bt_state == BT_STATE_CONNECTED) { // SerialBT.printf("Bus voltage %.3fv. Unfiltered %.3fv.", battery_voltage, bat_v_samples[BAT_SAMPLES-1]); // if (bat_voltage_dropping) { - // SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.\n", battery_percent); + // SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent); // } else { - // SerialBT.print(" Voltage is not dropping.\n"); + // SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent); // } + // if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf(" Battery discharging. delay_v %.3fv", bat_delay_v); } + // if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf(" Battery charging. delay_v %.3fv", bat_delay_v); } + // if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print(" Battery is charged."); } + // SerialBT.print("\n"); // } } - #elif BOARD_MODEL == BOARD_TBEAM + #elif BOARD_MODEL == BOARD_TBEAM || BOARD_MODEL == BOARD_TBEAM_S_V1 if (PMU) { float discharge_current = 0; float charge_current = 0; @@ -172,7 +249,7 @@ void measure_battery() { } } } else { - battery_state = BATTERY_STATE_DISCHARGING; + battery_state = BATTERY_STATE_UNKNOWN; battery_percent = 0.0; battery_voltage = 0.0; } @@ -301,31 +378,29 @@ void update_pmu() { } bool init_pmu() { - #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 + #if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK pinMode(pin_vbat, INPUT); return true; + #elif BOARD_MODEL == BOARD_HELTEC32_V3 + pinMode(pin_ctrl,OUTPUT); + digitalWrite(pin_ctrl, LOW); + return true; #elif BOARD_MODEL == BOARD_TBEAM Wire.begin(I2C_SDA, I2C_SCL); if (!PMU) { PMU = new XPowersAXP2101(PMU_WIRE_PORT); if (!PMU->init()) { - Serial.println("Warning: Failed to find AXP2101 power management"); delete PMU; PMU = NULL; - } else { - Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); } } if (!PMU) { PMU = new XPowersAXP192(PMU_WIRE_PORT); if (!PMU->init()) { - Serial.println("Warning: Failed to find AXP192 power management"); delete PMU; PMU = NULL; - } else { - Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); } } @@ -431,7 +506,7 @@ bool init_pmu() { PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); return true; - #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_FREENODE + #elif BOARD_MODEL == BOARD_RAK4631 || BOARD_MODEL == BOARD_OPENCOM_XL // board doesn't have PMU but we can measure batt voltage // prep ADC for reading battery level @@ -446,6 +521,86 @@ bool init_pmu() { // Get a single ADC sample and throw it away float raw = analogRead(PIN_VBAT); return true; + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + Wire1.begin(I2C_SDA, I2C_SCL); + + if (!PMU) { + PMU = new XPowersAXP2101(PMU_WIRE_PORT); + if (!PMU->init()) { + delete PMU; + PMU = NULL; + } + } + + if (!PMU) { + return false; + } + + /** + * gnss module power channel + * The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during + * initialization + */ + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // lora radio power channel + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + + // m.2 interface + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + /** + * ALDO2 cannot be turned off. + * It is a necessary condition for sensor communication. + * It must be turned on to properly access the sensor and screen + * It is also responsible for the power supply of PCF8563 + */ + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // 6-axis , magnetometer ,bme280 , oled screen power channel + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + // sdcard power channle + PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO1); + + // PMU->setPowerChannelVoltage(XPOWERS_DCDC4, 3300); + // PMU->enablePowerOutput(XPOWERS_DCDC4); + + // not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); // not elicited + PMU->disablePowerOutput(XPOWERS_DCDC5); // not elicited + PMU->disablePowerOutput(XPOWERS_DLDO1); // Invalid power channel, it does not exist + PMU->disablePowerOutput(XPOWERS_DLDO2); // Invalid power channel, it does not exist + PMU->disablePowerOutput(XPOWERS_VBACKUP); + + // Configure charging + PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); + // TODO: Reset + PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + // Set the time of pressing the button to turn off + PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + PMU->setPowerKeyPressOnTime(XPOWERS_POWERON_128MS); + + // disable all axp chip interrupt + PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU->clearIrqStatus(); + + // It is necessary to disable the detection function of the TS pin on the board + // without the battery temperature detection function, otherwise it will cause abnormal charging + PMU->disableTSPinMeasure(); + PMU->enableVbusVoltageMeasure(); + PMU->enableBattVoltageMeasure(); + + + return true; #else return false; #endif diff --git a/README.md b/README.md index e5016ba..6d26977 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ The latest release, installable through `rnodeconf`, is version `1.73`. This rel - Fix TNC EEPROM settings not being saved - courtesy of @attermann - Fix ESP32 linker errors - BSP version is now fixed at 2.0.17, using the older crosstool-ng linker from previous versions (2021r1) - You must have at least version `2.1.3` of `rnodeconf` installed to update the RNode Firmware to version `1.73`. Get it by updating the `rns` package to at least version `0.6.4`. ## Supported products and boards diff --git a/RNode_Firmware_CE.ino b/RNode_Firmware_CE.ino index 5a83845..48c38e4 100644 --- a/RNode_Firmware_CE.ino +++ b/RNode_Firmware_CE.ino @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -74,6 +74,16 @@ volatile bool serial_buffering = false; #include "Console.h" #endif +#define MODEM_QUEUE_SIZE 4*INTERFACE_COUNT +typedef struct { + size_t len; + int rssi; + int snr_raw; + uint8_t data[]; + uint8_t interface; +} modem_packet_t; +static xQueueHandle modem_packet_queue = NULL; + char sbuf[128]; uint8_t *packet_queue[INTERFACE_COUNT]; @@ -83,6 +93,18 @@ void setup() { boot_seq(); EEPROM.begin(EEPROM_SIZE); Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE); + + #if BOARD_MODEL == BOARD_TDECK + pinMode(pin_poweron, OUTPUT); + digitalWrite(pin_poweron, HIGH); + + pinMode(SD_CS, OUTPUT); + pinMode(DISPLAY_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + digitalWrite(DISPLAY_CS, HIGH); + + pinMode(DISPLAY_BL_PIN, OUTPUT); + #endif #endif #if MCU_VARIANT == MCU_NRF52 @@ -109,7 +131,11 @@ void setup() { Serial.begin(serial_baudrate); - #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TECHO + #if HAS_NP + led_init(); + #endif + + #if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 && BOARD_MODEL != BOARD_TBEAM_S_V1 && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TECHO // 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 // until a serial connection is actually established with a master. Thus, it @@ -141,6 +167,10 @@ void setup() { memset(packet_starts_buf, 0, sizeof(packet_starts_buf)); memset(packet_lengths_buf, 0, sizeof(packet_starts_buf)); + memset(seq, 0xFF, sizeof(seq)); + + modem_packet_queue = xQueueCreate(MODEM_QUEUE_SIZE, sizeof(modem_packet_t*)); + for (int i = 0; i < INTERFACE_COUNT; i++) { fifo16_init(&packet_starts[i], packet_starts_buf, CONFIG_QUEUE_MAX_LENGTH+1); fifo16_init(&packet_lengths[i], packet_lengths_buf, CONFIG_QUEUE_MAX_LENGTH+1); @@ -151,6 +181,8 @@ void setup() { fifo_init(&packet_rdy_interfaces, packet_rdy_interfaces_buf, MAX_INTERFACES); + // add call to init_channel_stats here? \todo + // Create and configure interface objects for (uint8_t i = 0; i < INTERFACE_COUNT; i++) { switch (interfaces[i]) { @@ -320,30 +352,75 @@ inline void kiss_write_packet(int index) { uint8_t cmd_byte = getInterfaceCommandByte(index); serial_write(FEND); - // Add index of interface the packet came from serial_write(cmd_byte); for (uint16_t i = 0; i < read_len; i++) { - uint8_t byte = pbuf[i]; + #if MCU_VARIANT == MCU_NRF52 + portENTER_CRITICAL(); + uint8_t byte = pbuf[i]; + portEXIT_CRITICAL(); + #else + uint8_t byte = pbuf[i]; + #endif + if (byte == FEND) { serial_write(FESC); byte = TFEND; } if (byte == FESC) { serial_write(FESC); byte = TFESC; } serial_write(byte); } + serial_write(FEND); read_len = 0; packet_ready = false; + + #if MCU_VARIANT == MCU_ESP32 && HAS_BLE + bt_flush(); + #endif } inline void getPacketData(RadioInterface* radio, uint16_t len) { - while (len-- && read_len < MTU) { - pbuf[read_len++] = radio->read(); - } + #if MCU_VARIANT != MCU_NRF52 + while (len-- && read_len < MTU) { + pbuf[read_len++] = radio->read(); + } + #else + BaseType_t int_mask = taskENTER_CRITICAL_FROM_ISR(); + while (len-- && read_len < MTU) { + pbuf[read_len++] = radio->read(); + } + taskEXIT_CRITICAL_FROM_ISR(int_mask); + #endif } -void receive_callback(uint8_t index, int packet_size) { - selected_radio = interface_obj[index]; +inline bool queuePacket(RadioInterface* radio, uint8_t index) { + // Allocate packet struct, but abort if there + // is not enough memory available. + modem_packet_t *modem_packet = (modem_packet_t*)malloc(sizeof(modem_packet_t) + read_len); + if(!modem_packet) { memory_low = true; return false; } + + // Get packet RSSI and SNR + modem_packet->snr_raw = radio->packetSnrRaw(); + + // Pass raw SNR to get RSSI as SX127X driver requires it for calculations + modem_packet->rssi = radio->packetRssi(modem_packet->snr_raw); + + modem_packet->interface = index; + + // Send packet to event queue, but free the + // allocated memory again if the queue is + // unable to receive the packet. + modem_packet->len = read_len; + memcpy(modem_packet->data, pbuf, read_len); + if (!modem_packet_queue || xQueueSendFromISR(modem_packet_queue, &modem_packet, NULL) != pdPASS) { + free(modem_packet); + } +} + +void ISR_VECT receive_callback(uint8_t index, int packet_size) { + selected_radio = interface_obj[index]; bool ready = false; + + BaseType_t int_mask; if (!promisc) { // The standard operating mode allows large // packets with a payload up to 500 bytes, @@ -354,33 +431,41 @@ void receive_callback(uint8_t index, int packet_size) { uint8_t header = selected_radio->read(); packet_size--; uint8_t sequence = packetSequence(header); - if (isSplitPacket(header) && seq == SEQ_UNSET) { + if (isSplitPacket(header) && seq[index] == SEQ_UNSET) { // This is the first part of a split // packet, so we set the seq variable // and add the data to the buffer - read_len = 0; - seq = sequence; + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + + seq[index] = sequence; getPacketData(selected_radio, packet_size); - } else if (isSplitPacket(header) && seq == sequence) { + } else if (isSplitPacket(header) && seq[index] == sequence) { // This is the second part of a split // packet, so we add it to the buffer // and set the ready flag. getPacketData(selected_radio, packet_size); - seq = SEQ_UNSET; - packet_interface = index; - packet_ready = true; + seq[index] = SEQ_UNSET; + ready = true; - } else if (isSplitPacket(header) && seq != sequence) { + } else if (isSplitPacket(header) && seq[index] != sequence) { // This split packet does not carry the // same sequence id, so we must assume // that we are seeing the first part of // a new split packet. - read_len = 0; - seq = sequence; + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + seq[index] = sequence; getPacketData(selected_radio, packet_size); @@ -389,17 +474,20 @@ void receive_callback(uint8_t index, int packet_size) { // just read it and set the ready // flag to true. - if (seq != SEQ_UNSET) { + if (seq[index] != SEQ_UNSET) { // If we already had part of a split // packet in the buffer, we clear it. - read_len = 0; - seq = SEQ_UNSET; + #if MCU_VARIANT == MCU_NRF52 + int_mask = taskENTER_CRITICAL_FROM_ISR(); read_len = 0; taskEXIT_CRITICAL_FROM_ISR(int_mask); + #else + read_len = 0; + #endif + seq[index] = SEQ_UNSET; } getPacketData(selected_radio, packet_size); - packet_interface = index; - packet_ready = true; + ready = true; } } else { // In promiscuous mode, raw packets are @@ -408,8 +496,11 @@ void receive_callback(uint8_t index, int packet_size) { getPacketData(selected_radio, packet_size); - packet_interface = index; - packet_ready = true; + ready = true; + } + + if (ready) { + queuePacket(selected_radio, index); } last_rx = millis(); @@ -517,6 +608,9 @@ void flushQueue(RadioInterface* radio) { queued_bytes[index] = 0; selected_radio->updateAirtime(); queue_flushing = false; + #if HAS_DISPLAY + display_tx = true; + #endif } void transmit(RadioInterface* radio, uint16_t size) { @@ -548,7 +642,14 @@ void transmit(RadioInterface* radio, uint16_t size) { } } - radio->endPacket(); radio->addAirtime(written); + if (!radio->endPacket()) { + kiss_indicate_error(ERROR_MODEM_TIMEOUT); + kiss_indicate_error(ERROR_TXFAILED); + led_indicate_error(5); + hard_reset(); + } + radio->addAirtime(written); + } else { // In promiscuous mode, we only send out // plain raw LoRa packets with a maximum @@ -783,6 +884,7 @@ void serialCallback(uint8_t sbyte) { kiss_indicate_implicit_length(); } else if (command == CMD_LEAVE) { if (sbyte == 0xFF) { + //display_unblank(); cable_state = CABLE_STATE_DISCONNECTED; //current_rssi = -292; last_rssi = -292; @@ -1024,7 +1126,13 @@ void serialCallback(uint8_t sbyte) { bt_start(); bt_conf_save(true); } else if (sbyte == 0x02) { - bt_enable_pairing(); + if (bt_state == BT_STATE_OFF) { + bt_start(); + bt_conf_save(true); + } + if (bt_state != BT_STATE_CONNECTED) { + bt_enable_pairing(); + } } #endif } else if (command == CMD_DISP_INT) { @@ -1039,6 +1147,7 @@ void serialCallback(uint8_t sbyte) { } display_intensity = sbyte; di_conf_save(display_intensity); + //display_unblank(); } #endif @@ -1056,6 +1165,37 @@ void serialCallback(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_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 } } @@ -1122,7 +1262,7 @@ void validate_status() { } } else { hw_ready = false; - Serial.write("No valid radio module found\r\n"); + Serial.write("No radio module found\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1132,6 +1272,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Invalid EEPROM checksum\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1141,6 +1282,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Invalid EEPROM configuration\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1150,6 +1292,7 @@ void validate_status() { } } else { hw_ready = false; + Serial.write("Device unprovisioned, no device configuration found in EEPROM\r\n"); #if HAS_DISPLAY if (disp_ready) { device_init_done = true; @@ -1171,23 +1314,38 @@ void validate_status() { } void loop() { - if (packet_ready) { - #if MCU_VARIANT == MCU_ESP32 - portENTER_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portENTER_CRITICAL(); - #endif - last_rssi = selected_radio->packetRssi(); - last_snr_raw = selected_radio->packetSnrRaw(); - #if MCU_VARIANT == MCU_ESP32 - portEXIT_CRITICAL(&update_lock); - #elif MCU_VARIANT == MCU_NRF52 - portEXIT_CRITICAL(); - #endif + #if MCU_VARIANT == MCU_ESP32 + modem_packet_t *modem_packet = NULL; + if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) { + read_len = modem_packet->len; + last_rssi = modem_packet->rssi; + last_snr_raw = modem_packet->snr_raw; + packet_interface = modem_packet->interface; + memcpy(&pbuf, modem_packet->data, modem_packet->len); + free(modem_packet); + modem_packet = NULL; + kiss_indicate_stat_rssi(); kiss_indicate_stat_snr(); kiss_write_packet(packet_interface); - } + } + + #elif MCU_VARIANT == MCU_NRF52 + modem_packet_t *modem_packet = NULL; + if(modem_packet_queue && xQueueReceive(modem_packet_queue, &modem_packet, 0) == pdTRUE && modem_packet) { + memcpy(&pbuf, modem_packet->data, modem_packet->len); + read_len = modem_packet->len; + last_rssi = modem_packet->rssi; + last_snr_raw = modem_packet->snr_raw; + packet_interface = modem_packet->interface; + free(modem_packet); + modem_packet = NULL; + + kiss_indicate_stat_rssi(); + kiss_indicate_stat_snr(); + kiss_write_packet(packet_interface); + } + #endif bool ready = false; for (int i = 0; i < INTERFACE_COUNT; i++) { @@ -1209,19 +1367,6 @@ void loop() { continue; } - // If a higher data rate interface has received a packet after its - // loop, it still needs to be the first to transmit, so check if this - // is the case. - for (int j = 0; j < INTERFACE_COUNT; j++) { - if (!interface_obj_sorted[j]->calculateALock() && interface_obj_sorted[j]->getRadioOnline()) { - if (interface_obj_sorted[j]->getBitrate() > selected_radio->getBitrate()) { - if (queue_height[interface_obj_sorted[j]->getIndex()] > 0) { - selected_radio = interface_obj_sorted[j]; - } - } - } - } - if (queue_height[selected_radio->getIndex()] > 0) { uint32_t check_time = millis(); if (check_time > selected_radio->getPostTxYieldTimeout()) { @@ -1300,6 +1445,18 @@ void loop() { #if HAS_INPUT input_read(); #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() { @@ -1317,15 +1474,51 @@ void sleep_now() { 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(); #endif } void button_event(uint8_t event, unsigned long duration) { - if (duration > 2000) { - sleep_now(); - } + //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 + } + //} } void poll_buffers() { diff --git a/ROM.h b/ROM.h index 4ecd02a..9ab3a70 100644 --- a/ROM.h +++ b/ROM.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -14,79 +14,40 @@ // along with this program. If not, see . #ifndef ROM_H - #define ROM_H + #define ROM_H + #define CHECKSUMMED_SIZE 0x0B - #define CHECKSUMMED_SIZE 0x0B + // ROM address map /////////////// + #define ADDR_PRODUCT 0x00 + #define ADDR_MODEL 0x01 + #define ADDR_HW_REV 0x02 + #define ADDR_SERIAL 0x03 + #define ADDR_MADE 0x07 + #define ADDR_CHKSUM 0x0B + #define ADDR_SIGNATURE 0x1B + #define ADDR_INFO_LOCK 0x9B - #define PRODUCT_RNODE 0x03 - #define PRODUCT_HMBRW 0xF0 - #define PRODUCT_TBEAM 0xE0 - #define PRODUCT_T32_10 0xB2 - #define PRODUCT_T32_20 0xB0 - #define PRODUCT_T32_21 0xB1 - #define PRODUCT_H32_V2 0xC0 - #define PRODUCT_H32_V3 0xC1 - #define PRODUCT_RAK4631 0x10 - #define PRODUCT_FREENODE 0x20 - #define MODEL_11 0x11 - #define MODEL_12 0x12 - #define MODEL_13 0x13 // RAK4631 LF with WisBlock SX1280 module (LIBSYS002) - #define MODEL_14 0x14 // RAK4631 HF with WisBlock SX1280 module (LIBSYS002) - #define PRODUCT_TECHO 0x15 - #define MODEL_16 0x16 // T-Echo 433 - #define MODEL_17 0x17 // T-Echo 915 - #define MODEL_21 0x21 // European band, 868MHz - #define MODEL_A1 0xA1 - #define MODEL_A5 0xA5 // T3S3 SX1280 PA - #define MODEL_A6 0xA6 - #define MODEL_A4 0xA4 - #define MODEL_A9 0xA9 - #define MODEL_A3 0xA3 - #define MODEL_A8 0xA8 - #define MODEL_A2 0xA2 - #define MODEL_A7 0xA7 - #define MODEL_B3 0xB3 - #define MODEL_B8 0xB8 - #define MODEL_B4 0xB4 - #define MODEL_B9 0xB9 - #define MODEL_BA 0xBA - #define MODEL_BB 0xBB - #define MODEL_C4 0xC4 - #define MODEL_C9 0xC9 - #define MODEL_C5 0xC5 - #define MODEL_CA 0xCA - #define MODEL_E4 0xE4 - #define MODEL_E9 0xE9 - #define MODEL_E3 0xE3 - #define MODEL_E8 0xE8 - #define MODEL_FE 0xFE - #define MODEL_FF 0xFF + #define ADDR_CONF_SF 0x9C + #define ADDR_CONF_CR 0x9D + #define ADDR_CONF_TXP 0x9E + #define ADDR_CONF_BW 0x9F + #define ADDR_CONF_FREQ 0xA3 + #define ADDR_CONF_OK 0xA7 - #define ADDR_PRODUCT 0x00 - #define ADDR_MODEL 0x01 - #define ADDR_HW_REV 0x02 - #define ADDR_SERIAL 0x03 - #define ADDR_MADE 0x07 - #define ADDR_CHKSUM 0x0B - #define ADDR_SIGNATURE 0x1B - #define ADDR_INFO_LOCK 0x9B + #define ADDR_CONF_BT 0xB0 + #define ADDR_CONF_DSET 0xB1 + #define ADDR_CONF_DINT 0xB2 + #define ADDR_CONF_DADR 0xB3 + #define ADDR_CONF_DBLK 0xB4 + #define ADDR_CONF_PSET 0xB5 + #define ADDR_CONF_PINT 0xB6 + #define ADDR_CONF_BSET 0xB7 - #define ADDR_CONF_SF 0x9C - #define ADDR_CONF_CR 0x9D - #define ADDR_CONF_TXP 0x9E - #define ADDR_CONF_BW 0x9F - #define ADDR_CONF_FREQ 0xA3 - #define ADDR_CONF_OK 0xA7 - - #define ADDR_CONF_BT 0xB0 - #define ADDR_CONF_DSET 0xB1 - #define ADDR_CONF_DINT 0xB2 - #define ADDR_CONF_DADR 0xB3 + #define INFO_LOCK_BYTE 0x73 + #define CONF_OK_BYTE 0x73 + #define BT_ENABLE_BYTE 0x73 - #define INFO_LOCK_BYTE 0x73 - #define CONF_OK_BYTE 0x73 - #define BT_ENABLE_BYTE 0x73 - - #define EEPROM_RESERVED 200 + #define EEPROM_RESERVED 200 + ////////////////////////////////// #endif diff --git a/Radio.cpp b/Radio.cpp index fe45ceb..f512b75 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -488,34 +488,34 @@ int sx126x::beginPacket(int implicitHeader) int sx126x::endPacket() { - setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); + setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); - // put in single TX mode - uint8_t timeout[3] = {0}; - executeOpcode(OP_TX_6X, timeout, 3); + // put in single TX mode + uint8_t timeout[3] = {0}; + executeOpcode(OP_TX_6X, timeout, 3); - uint8_t buf[2]; + uint8_t buf[2]; - buf[0] = 0x00; - buf[1] = 0x00; + buf[0] = 0x00; + buf[1] = 0x00; - executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); + executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); - // wait for TX done - while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) { + // wait for TX done + while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) { buf[0] = 0x00; buf[1] = 0x00; executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2); yield(); - } + } - // clear IRQ's + // clear IRQ's - uint8_t mask[2]; - mask[0] = 0x00; - mask[1] = IRQ_TX_DONE_MASK_6X; - executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2); - return 1; + uint8_t mask[2]; + mask[0] = 0x00; + mask[1] = IRQ_TX_DONE_MASK_6X; + executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2); + return 1; } uint8_t sx126x::modemStatus() { @@ -561,7 +561,7 @@ uint8_t sx126x::packetRssiRaw() { return buf[2]; } -int ISR_VECT sx126x::packetRssi() { +int ISR_VECT sx126x::packetRssi(uint8_t pkt_snr_raw) { // may need more calculations here uint8_t buf[3] = {0}; executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3); @@ -748,6 +748,10 @@ void sx126x::enableTCXO() { uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #elif BOARD_MODEL == BOARD_T3S3 uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; + #elif BOARD_MODEL == BOARD_TDECK + uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + uint8_t buf[4] = {MODE_TCXO_1_8V_6X, 0x00, 0x00, 0xFF}; #else uint8_t buf[4] = {0}; #endif @@ -995,7 +999,9 @@ void sx126x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - //_csma_slot_ms = _lora_symbol_time_ms*10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; @@ -1246,23 +1252,27 @@ uint8_t sx127x::packetRssiRaw() { return pkt_rssi_value; } -int ISR_VECT sx127x::packetRssi() { - int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; - int pkt_snr = packetSnr(); - - if (_frequency < 820E6) pkt_rssi -= 7; - - if (pkt_snr < 0) { - pkt_rssi += pkt_snr; - } else { - // Slope correction is (16/15)*pkt_rssi, - // this estimation looses one floating point - // operation, and should be precise enough. - pkt_rssi = (int)(1.066 * pkt_rssi); - } - return pkt_rssi; +int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) { + int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; + int pkt_snr; + if (pkt_snr_raw == 0xFF) { + pkt_snr = packetSnr(); + } else { + pkt_snr = ((int8_t)pkt_snr_raw)*0.25; + } + if (_frequency < 820E6) pkt_rssi -= 7; + if (pkt_snr < 0) { + pkt_rssi += pkt_snr; + } else { + // Slope correction is (16/15)*pkt_rssi, + // this estimation looses one floating point + // operation, and should be precise enough. + pkt_rssi = (int)(1.066 * pkt_rssi); + } + return pkt_rssi; } + uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); } @@ -1531,7 +1541,9 @@ void sx127x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - //_csma_slot_ms = _lora_symbol_time_ms*10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/_lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW; if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; @@ -2028,7 +2040,7 @@ uint8_t sx128x::packetRssiRaw() { return buf[0]; } -int ISR_VECT sx128x::packetRssi() { +int ISR_VECT sx128x::packetRssi(uint8_t pkt_snr_raw) { // may need more calculations here uint8_t buf[5] = {0}; executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); @@ -2626,7 +2638,9 @@ void sx128x::updateBitrate() { _lora_symbol_time_ms = (1.0/_lora_symbol_rate)*1000.0; _bitrate = (uint32_t)(_sf * ( (4.0/(float)(_cr+4)) / ((float)(pow(2, _sf))/((float)getSignalBandwidth()/1000.0)) ) * 1000.0); _lora_us_per_byte = 1000000.0/((float)_bitrate/8.0); - _csma_slot_ms = 10; + _csma_slot_ms = _lora_symbol_time_ms*12; + if (_csma_slot_ms > CSMA_SLOT_MAX_MS) { _csma_slot_ms = CSMA_SLOT_MAX_MS; } + if (_csma_slot_ms < CSMA_SLOT_MIN_MS) { _csma_slot_ms = CSMA_SLOT_MIN_MS; } float target_preamble_symbols; //if (_bitrate <= LORA_FAST_BITRATE_THRESHOLD) { diff --git a/Radio.hpp b/Radio.hpp index 681db4f..43abef3 100644 --- a/Radio.hpp +++ b/Radio.hpp @@ -1,7 +1,7 @@ // Copyright (c) Sandeep Mistry. All rights reserved. // Licensed under the MIT license. -// Modifications and additions copyright 2023 by Mark Qvist & Jacob Eva +// Modifications and additions copyright 2024 by Mark Qvist & Jacob Eva // Obviously still under the MIT license. #ifndef RADIO_H @@ -36,13 +36,15 @@ #define LORA_PREAMBLE_TARGET_MS 15 #define LORA_PREAMBLE_FAST_TARGET_MS 1 #define LORA_FAST_BITRATE_THRESHOLD 40000 +#define CSMA_SLOT_MAX_MS 100 +#define CSMA_SLOT_MIN_MS 24 #define RSSI_OFFSET 157 #define PHY_HEADER_LORA_SYMBOLS 8 #define _e 2.71828183 -#define _S 10.0 +#define _S 12.5 // Status flags const uint8_t SIG_DETECT = 0x01; @@ -71,8 +73,8 @@ public: _stat_signal_detected(false), _stat_signal_synced(false),_stat_rx_ongoing(false), _last_dcd(0), _dcd_count(0), _dcd(false), _dcd_led(false), _dcd_waiting(false), _dcd_wait_until(0), _dcd_sample(0), - _post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p_min(0.1), - _csma_p_max(0.8), _preambleLength(6), _lora_symbol_time_ms(0.0), + _post_tx_yield_timeout(0), _csma_slot_ms(50), _csma_p(85), _csma_p_min(0.15), + _csma_p_max(0.333), _csma_b_speed(0.15), _preambleLength(6), _lora_symbol_time_ms(0.0), _lora_symbol_rate(0.0), _lora_us_per_byte(0.0), _bitrate(0), _packet{0}, _onReceive(NULL) {}; virtual int begin() = 0; @@ -81,7 +83,7 @@ public: virtual int beginPacket(int implicitHeader = false) = 0; virtual int endPacket() = 0; - virtual int packetRssi() = 0; + virtual int packetRssi(uint8_t pkt_snr_raw = 0xFF) = 0; virtual int currentRssi() = 0; virtual uint8_t packetRssiRaw() = 0; virtual uint8_t currentRssiRaw() = 0; @@ -281,8 +283,8 @@ public: float getLongtermChannelUtil() { return _longterm_channel_util; }; float CSMASlope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); }; void updateCSMAp() { - _csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime)))*255.0); - }; + _csma_p = (uint8_t)((1.0-(_csma_p_min+(_csma_p_max-_csma_p_min)*CSMASlope(_airtime+_csma_b_speed)))*255.0); + } uint8_t getCSMAp() { return _csma_p; }; void setCSMASlotMS(int slot_size) { _csma_slot_ms = slot_size; }; int getCSMASlotMS() { return _csma_slot_ms; }; @@ -323,6 +325,7 @@ protected: int _csma_slot_ms; float _csma_p_min; float _csma_p_max; + float _csma_b_speed; long _preambleLength; float _lora_symbol_time_ms; float _lora_symbol_rate; @@ -343,7 +346,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -463,7 +466,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); @@ -557,7 +560,7 @@ public: int beginPacket(int implicitHeader = false); int endPacket(); - int packetRssi(); + int packetRssi(uint8_t pkt_snr_raw = 0xFF); int currentRssi(); uint8_t packetRssiRaw(); uint8_t currentRssiRaw(); diff --git a/Release/console_image.bin b/Release/console_image.bin index ee7e5b1..8fb621b 100644 Binary files a/Release/console_image.bin and b/Release/console_image.bin differ diff --git a/Utilities.h b/Utilities.h index 36138f6..c260999 100644 --- a/Utilities.h +++ b/Utilities.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023, Mark Qvist +// Copyright (C) 2024, Mark Qvist // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -35,7 +35,7 @@ #include "ROM.h" #include "Framing.h" -#include "MD5.h" +#include "src/misc/MD5.h" #if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52 uint8_t eeprom_read(uint32_t mapped_addr); @@ -43,6 +43,9 @@ uint8_t eeprom_read(uint32_t mapped_addr); #if HAS_DISPLAY == true #include "Display.h" +#else + void display_unblank() {} + bool display_blanked = false; #endif #if HAS_BLUETOOTH == true || HAS_BLE == true @@ -65,11 +68,11 @@ uint8_t eeprom_read(uint32_t mapped_addr); #if BOARD_MODEL == BOARD_HELTEC32_V3 //https://github.com/espressif/esp-idf/issues/8855 #include "hal/wdt_hal.h" - #elif BOARD_MODEL == BOARD_T3S3 - #include "hal/wdt_hal.h" - #else BOARD_MODEL != BOARD_T3S3 - #include "soc/rtc_wdt.h" - #endif + #elif BOARD_MODEL == BOARD_T3S3 + #include "hal/wdt_hal.h" + #else + #include "hal/wdt_hal.h" + #endif #define ISR_VECT IRAM_ATTR #else #define ISR_VECT @@ -92,7 +95,20 @@ uint8_t boot_vector = 0x00; uint8_t npr = 0; uint8_t npg = 0; uint8_t npb = 0; + float npi = NP_M; bool pixels_started = false; + + void led_set_intensity(uint8_t intensity) { + npi = (float)intensity/255.0; + } + + void led_init() { + if (EEPROM.read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) { + uint8_t int_val = EEPROM.read(eeprom_addr(ADDR_CONF_PINT)); + led_set_intensity(int_val); + } + } + void npset(uint8_t r, uint8_t g, uint8_t b) { if (pixels_started != true) { pixels.begin(); @@ -101,7 +117,7 @@ uint8_t boot_vector = 0x00; if (r != npr || g != npg || b != npb) { npr = r; npg = g; npb = b; - pixels.setPixelColor(0, pixels.Color(npr*NP_M, npg*NP_M, npb*NP_M)); + pixels.setPixelColor(0, pixels.Color(npr*npi, npg*npi, npb*npi)); pixels.show(); } } @@ -152,6 +168,16 @@ uint8_t boot_vector = 0x00; void led_rx_off() { digitalWrite(pin_led_rx, LOW); } void led_tx_on() { digitalWrite(pin_led_tx, LOW); } void led_tx_off() { digitalWrite(pin_led_tx, HIGH); } + #elif BOARD_MODEL == BOARD_TDECK + void led_rx_on() { } + void led_rx_off() { } + void led_tx_on() { } + void led_tx_off() { } + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + void led_rx_on() { } + void led_rx_off() { } + void led_tx_on() { } + void led_tx_off() { } #elif BOARD_MODEL == BOARD_LORA32_V1_0 #if defined(EXTERNAL_LEDS) void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } @@ -376,8 +402,8 @@ unsigned long led_standby_ticks = 0; #if MCU_VARIANT == MCU_ESP32 #if HAS_NP == true - int led_standby_lng = 100; - int led_standby_cut = 200; + int led_standby_lng = 200; + int led_standby_cut = 100; int led_standby_min = 0; int led_standby_max = 375+led_standby_lng; int led_notready_min = 0; @@ -441,7 +467,7 @@ int8_t led_standby_direction = 0; } else { led_standby_intensity = led_standby_ti; } - npset(0x00, 0x00, led_standby_intensity); + npset(led_standby_intensity/3, led_standby_intensity/3, led_standby_intensity/3); } } @@ -588,18 +614,17 @@ void serial_write(uint8_t byte) { Serial.write(byte); } else { SerialBT.write(byte); - - #if MCU_VARIANT == MCU_NRF52 && HAS_BLE - // This ensures that the TX buffer is flushed after a frame is queued in serial. - // serial_in_frame is used to ensure that the flush only happens at the end of the frame - if (serial_in_frame && byte == FEND) { - SerialBT.flushTXD(); - serial_in_frame = false; - } - else if (!serial_in_frame && byte == FEND) { - serial_in_frame = true; - } - #endif + #if MCU_VARIANT == MCU_NRF52 && HAS_BLE + // This ensures that the TX buffer is flushed after a frame is queued in serial. + // serial_in_frame is used to ensure that the flush only happens at the end of the frame + if (serial_in_frame && byte == FEND) { + SerialBT.flushTXD(); + serial_in_frame = false; + } + else if (!serial_in_frame && byte == FEND) { + serial_in_frame = true; + } + #endif } #else Serial.write(byte); @@ -1022,6 +1047,8 @@ void setTXPower(RadioInterface* radio, int txp) { if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_AA) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_AB) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); @@ -1031,6 +1058,12 @@ void setTXPower(RadioInterface* radio, int txp) { if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_D4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_D9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + + if (model == MODEL_DB) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_DC) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); + if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN); @@ -1216,11 +1249,11 @@ void promisc_disable() { #endif bool eeprom_info_locked() { - #if HAS_EEPROM - uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); - #elif MCU_VARIANT == MCU_NRF52 - uint8_t lock_byte = eeprom_read(eeprom_addr(ADDR_INFO_LOCK)); - #endif + #if HAS_EEPROM + uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); + #elif MCU_VARIANT == MCU_NRF52 + uint8_t lock_byte = eeprom_read(eeprom_addr(ADDR_INFO_LOCK)); + #endif if (lock_byte == INFO_LOCK_BYTE) { return true; } else { @@ -1297,15 +1330,15 @@ void eeprom_update(int mapped_addr, uint8_t byte) { written_bytes++; if (((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) || (mapped_addr - eeprom_addr(0)) == ADDR_CONF_OK) { - // have to do a flush because we're only writing 1 byte and it syncs after 4 - eeprom_flush(); + // have to do a flush because we're only writing 1 byte and it syncs after 4 + eeprom_flush(); } - if (written_bytes >= 4) { - file.close(); - file.open(EEPROM_FILE, FILE_O_WRITE); - written_bytes = 0; - } + if (written_bytes >= 4) { + file.close(); + file.open(EEPROM_FILE, FILE_O_WRITE); + written_bytes = 0; + } #endif } @@ -1337,16 +1370,16 @@ bool eeprom_lock_set() { } bool eeprom_product_valid() { - #if HAS_EEPROM - uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT)); - #elif MCU_VARIANT == MCU_NRF52 - uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); - #endif + #if HAS_EEPROM + uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT)); + #elif MCU_VARIANT == MCU_NRF52 + uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT)); + #endif #if PLATFORM == PLATFORM_ESP32 - if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) { + if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1) { #elif PLATFORM == PLATFORM_NRF52 - if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_FREENODE) { + if (rval == PRODUCT_TECHO || rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW || rval == PRODUCT_OPENCOM_XL) { #else if (false) { #endif @@ -1368,14 +1401,18 @@ bool eeprom_model_valid() { if (model == MODEL_A3 || model == MODEL_A8) { #elif BOARD_MODEL == BOARD_RNODE_NG_21 if (model == MODEL_A2 || model == MODEL_A7) { + #elif BOARD_MODEL == BOARD_RNODE_NG_22 + if (model == MODEL_A1 || model == MODEL_A6 || model == MODEL_A5 || model == MODEL_AA) { #elif BOARD_MODEL == BOARD_T3S3 if (model == MODEL_A1 || model == MODEL_A5 || model == MODEL_A6) { - #elif BOARD_MODEL == BOARD_HMBRW - if (model == MODEL_FF || model == MODEL_FE) { #elif BOARD_MODEL == BOARD_TBEAM if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) { #elif BOARD_MODEL == BOARD_TECHO if (model == MODEL_16 || model == MODEL_17) { + #elif BOARD_MODEL == BOARD_TDECK + if (model == MODEL_D4 || model == MODEL_D9) { + #elif BOARD_MODEL == BOARD_TBEAM_S_V1 + if (model == MODEL_DB || model == MODEL_DC) { #elif BOARD_MODEL == BOARD_LORA32_V1_0 if (model == MODEL_BA || model == MODEL_BB) { #elif BOARD_MODEL == BOARD_LORA32_V2_0 @@ -1390,6 +1427,8 @@ bool eeprom_model_valid() { if (model == MODEL_11 || model == MODEL_12 || model == MODEL_13 || model == MODEL_14 || model == MODEL_21) { #elif BOARD_MODEL == BOARD_HUZZAH32 if (model == MODEL_FF) { + #elif BOARD_MODEL == BOARD_HMBRW + if (model == MODEL_FF || model == MODEL_FE) { #elif BOARD_MODEL == BOARD_GENERIC_ESP32 if (model == MODEL_FF || model == MODEL_FE) { #else @@ -1447,16 +1486,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 } } @@ -1468,6 +1507,25 @@ void da_conf_save(uint8_t dadr) { eeprom_update(eeprom_addr(ADDR_CONF_DADR), dadr); } +void db_conf_save(uint8_t val) { + #if HAS_DISPLAY + if (val == 0x00) { + display_blanking_enabled = false; + } else { + display_blanking_enabled = true; + //display_blanking_timeout = val*1000; + } + eeprom_update(eeprom_addr(ADDR_CONF_BSET), CONF_OK_BYTE); + eeprom_update(eeprom_addr(ADDR_CONF_DBLK), val); + #endif +} + +void np_int_conf_save(uint8_t p_int) { + eeprom_update(eeprom_addr(ADDR_CONF_PSET), CONF_OK_BYTE); + eeprom_update(eeprom_addr(ADDR_CONF_PINT), p_int); +} + + bool eeprom_have_conf() { #if HAS_EEPROM if (EEPROM.read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) { @@ -1542,4 +1600,4 @@ void unlock_rom() { eeprom_erase(); } -#include "src/misc/FIFOBuffer.h" \ No newline at end of file +#include "src/misc/FIFOBuffer.h" diff --git a/esp32_btbufs.py b/esp32_btbufs.py new file mode 100755 index 0000000..8a5b15e --- /dev/null +++ b/esp32_btbufs.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +import sys + +try: + target_path = sys.argv[1] + rxbuf_size = 0; rxbuf_minsize = 6144 + txbuf_size = 0; txbuf_minsize = 384 + line_index = 0 + rx_line_index = 0 + tx_line_index = 0 + with open(target_path) as sf: + for line in sf: + line_index += 1 + if line.startswith("#define RX_QUEUE_SIZE"): + ents = line.split(" ") + try: + rxbuf_size = int(ents[2]) + rx_line_index = line_index + except Exception as e: + print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}") + + if line.startswith("#define TX_QUEUE_SIZE"): + ents = line.split(" ") + try: + txbuf_size = int(ents[2]) + tx_line_index = line_index + except Exception as e: + print(f"Could not parse Bluetooth RX_QUEUE_SIZE: {e}") + + if rxbuf_size != 0 and txbuf_size != 0: + break + + if rxbuf_size < rxbuf_minsize: + print(f"Error: The configured ESP32 Bluetooth RX buffer size is too small, please set it to at least {rxbuf_minsize} and try compiling again.") + print(f"The buffer configuration can be modified in line {rx_line_index} of: {target_path}") + exit(1) + + if txbuf_size < txbuf_minsize: + print(f"Error: The configured ESP32 Bluetooth TX buffer size is too small, please set it to at least {txbuf_minsize} and try compiling again.") + print(f"The buffer configuration can be modified in line {tx_line_index} of: {target_path}") + exit(1) + + exit(0) + +except Exception as e: + print(f"Could not determine ESP32 Bluetooth buffer configuration: {e}") + print("Please fix this error and try again") \ No newline at end of file diff --git a/partition_hashes b/partition_hashes index d6b81fe..fa60868 100755 --- a/partition_hashes +++ b/partition_hashes @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/release_hashes.py b/release_hashes.py index c54a9d1..e1608d8 100644 --- a/release_hashes.py +++ b/release_hashes.py @@ -1,6 +1,6 @@ #!/bin/python3 -# Copyright (C) 2023, Mark Qvist +# Copyright (C) 2024, Mark Qvist # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/ble/BLESerial.cpp b/src/ble/BLESerial.cpp new file mode 100644 index 0000000..94cbb2f --- /dev/null +++ b/src/ble/BLESerial.cpp @@ -0,0 +1,155 @@ +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This class is for BLE serial functionality on ESP32 boards ONLY + +#include +#include "../../Boards.h" + +#if PLATFORM != PLATFORM_NRF52 +#if HAS_BLE + +#include "BLESerial.h" + +uint32_t bt_passkey_callback(); +void bt_passkey_notify_callback(uint32_t passkey); +bool bt_security_request_callback(); +void bt_authentication_complete_callback(esp_ble_auth_cmpl_t auth_result); +bool bt_confirm_pin_callback(uint32_t pin); +void bt_connect_callback(BLEServer *server); +void bt_disconnect_callback(BLEServer *server); +bool bt_client_authenticated(); + +uint32_t BLESerial::onPassKeyRequest() { return bt_passkey_callback(); } +void BLESerial::onPassKeyNotify(uint32_t passkey) { bt_passkey_notify_callback(passkey); } +bool BLESerial::onSecurityRequest() { return bt_security_request_callback(); } +void BLESerial::onAuthenticationComplete(esp_ble_auth_cmpl_t auth_result) { bt_authentication_complete_callback(auth_result); } +void BLESerial::onConnect(BLEServer *server) { bt_connect_callback(server); } +void BLESerial::onDisconnect(BLEServer *server) { bt_disconnect_callback(server); ble_server->startAdvertising(); } +bool BLESerial::onConfirmPIN(uint32_t pin) { return bt_confirm_pin_callback(pin); }; +bool BLESerial::connected() { return ble_server->getConnectedCount() > 0; } + +int BLESerial::read() { + int result = this->rx_buffer.pop(); + if (result == '\n') { this->numAvailableLines--; } + return result; +} + +size_t BLESerial::readBytes(uint8_t *buffer, size_t bufferSize) { + int i = 0; + while (i < bufferSize && available()) { buffer[i] = (uint8_t)this->rx_buffer.pop(); i++; } + return i; +} + +int BLESerial::peek() { + if (this->rx_buffer.getLength() == 0) return -1; + return this->rx_buffer.get(0); +} + +int BLESerial::available() { return this->rx_buffer.getLength(); } + +size_t BLESerial::print(const char *str) { + if (ble_server->getConnectedCount() <= 0) return 0; + size_t written = 0; for (size_t i = 0; str[i] != '\0'; i++) { written += this->write(str[i]); } + flush(); + + return written; +} + +size_t BLESerial::write(const uint8_t *buffer, size_t bufferSize) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + size_t written = 0; for (int i = 0; i < bufferSize; i++) { written += this->write(buffer[i]); } + flush(); + + return written; + } +} + +size_t BLESerial::write(uint8_t byte) { + if (bt_client_authenticated()) { + if (ble_server->getConnectedCount() <= 0) { return 0; } else { + this->transmitBuffer[this->transmitBufferLength] = byte; + this->transmitBufferLength++; + if (this->transmitBufferLength == maxTransferSize) { flush(); } + return 1; + } + } else { + return 0; + } +} + +void BLESerial::flush() { + if (this->transmitBufferLength > 0) { + TxCharacteristic->setValue(this->transmitBuffer, this->transmitBufferLength); + this->transmitBufferLength = 0; + this->lastFlushTime = millis(); + TxCharacteristic->notify(true); + } +} + +void BLESerial::begin(const char *name) { + ConnectedDeviceCount = 0; + BLEDevice::init(name); + + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9); + + ble_server = BLEDevice::createServer(); + ble_server->setCallbacks(this); + BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT_MITM); + BLEDevice::setSecurityCallbacks(this); + + SetupSerialService(); + + ble_adv = BLEDevice::getAdvertising(); + ble_adv->addServiceUUID(BLE_SERIAL_SERVICE_UUID); + ble_adv->setMinPreferred(0x20); + ble_adv->setMaxPreferred(0x40); + ble_adv->setScanResponse(true); + ble_adv->start(); +} + +void BLESerial::end() { BLEDevice::deinit(); } + +void BLESerial::onWrite(BLECharacteristic *characteristic) { + if (characteristic->getUUID().toString() == BLE_RX_UUID) { + auto value = characteristic->getValue(); + for (int i = 0; i < value.length(); i++) { rx_buffer.push(value[i]); } + } +} + +void BLESerial::SetupSerialService() { + SerialService = ble_server->createService(BLE_SERIAL_SERVICE_UUID); + + RxCharacteristic = SerialService->createCharacteristic(BLE_RX_UUID, BLECharacteristic::PROPERTY_WRITE); + RxCharacteristic->setAccessPermissions(ESP_GATT_PERM_WRITE_ENC_MITM); + RxCharacteristic->addDescriptor(new BLE2902()); + RxCharacteristic->setWriteProperty(true); + RxCharacteristic->setCallbacks(this); + + TxCharacteristic = SerialService->createCharacteristic(BLE_TX_UUID, BLECharacteristic::PROPERTY_NOTIFY); + TxCharacteristic->setAccessPermissions(ESP_GATT_PERM_READ_ENC_MITM); + TxCharacteristic->addDescriptor(new BLE2902()); + TxCharacteristic->setNotifyProperty(true); + TxCharacteristic->setReadProperty(true); + + SerialService->start(); +} + +BLESerial::BLESerial() { } + +#endif +#endif diff --git a/src/ble/BLESerial.h b/src/ble/BLESerial.h new file mode 100644 index 0000000..1ad2e25 --- /dev/null +++ b/src/ble/BLESerial.h @@ -0,0 +1,135 @@ +// Copyright (C) 2024, Mark Qvist + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// This class is for BLE serial functionality on ESP32 boards ONLY + +#include "../../Boards.h" + +#if PLATFORM != PLATFORM_NRF52 +#if HAS_BLE + +#include + +#include +#include +#include +#include + +template +class BLEFIFO { +private: + uint8_t buffer[n]; + int head = 0; + int tail = 0; + +public: + void push(uint8_t value) { + buffer[head] = value; + head = (head + 1) % n; + if (head == tail) { tail = (tail + 1) % n; } + } + + int pop() { + if (head == tail) { + return -1; + } else { + uint8_t value = buffer[tail]; + tail = (tail + 1) % n; + return value; + } + } + + void clear() { head = 0; tail = 0; } + + int get(size_t index) { + if (index >= this->getLength()) { + return -1; + } else { + return buffer[(tail + index) % n]; + } + } + + size_t getLength() { + if (head >= tail) { + return head - tail; + } else { + return n - tail + head; + } + } +}; + +#define RX_BUFFER_SIZE 6144 +#define BLE_BUFFER_SIZE 512 // Must fit in max GATT attribute length +#define MIN_MTU 50 + +class BLESerial : public BLECharacteristicCallbacks, public BLEServerCallbacks, public BLESecurityCallbacks, public Stream { +public: + BLESerial(); + + void begin(const char *name); + void end(); + void onWrite(BLECharacteristic *characteristic); + int available(); + int peek(); + int read(); + size_t readBytes(uint8_t *buffer, size_t bufferSize); + size_t write(uint8_t byte); + size_t write(const uint8_t *buffer, size_t bufferSize); + size_t print(const char *value); + void flush(); + void onConnect(BLEServer *server); + void onDisconnect(BLEServer *server); + + uint32_t onPassKeyRequest(); + void onPassKeyNotify(uint32_t passkey); + bool onSecurityRequest(); + void onAuthenticationComplete(esp_ble_auth_cmpl_t); + bool onConfirmPIN(uint32_t pin); + + bool connected(); + + BLEServer *ble_server; + BLEAdvertising *ble_adv; + BLEService *SerialService; + BLECharacteristic *TxCharacteristic; + BLECharacteristic *RxCharacteristic; + size_t transmitBufferLength; + unsigned long long lastFlushTime; + +private: + BLESerial(BLESerial const &other) = delete; + void operator=(BLESerial const &other) = delete; + + BLEFIFO rx_buffer; + size_t numAvailableLines; + uint8_t transmitBuffer[BLE_BUFFER_SIZE]; + + int ConnectedDeviceCount; + void SetupSerialService(); + + uint16_t peerMTU; + uint16_t maxTransferSize = BLE_BUFFER_SIZE; + + bool checkMTU(); + + const char *BLE_SERIAL_SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_RX_UUID = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; + const char *BLE_TX_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; + + bool started = false; +}; + +#endif +#endif diff --git a/MD5.cpp b/src/misc/MD5.cpp similarity index 100% rename from MD5.cpp rename to src/misc/MD5.cpp diff --git a/MD5.h b/src/misc/MD5.h similarity index 100% rename from MD5.h rename to src/misc/MD5.h