Compare commits

...

131 Commits
1.78 ... master

Author SHA1 Message Date
Mark Qvist
de35a9dda0 Updated readme 2025-01-24 13:21:24 +01:00
Mark Qvist
e230c73ee0 Updated console build 2025-01-19 22:14:15 +01:00
Mark Qvist
6bbcaa0ba9 Report battery percentage over BLE battery service 2025-01-18 15:20:58 +01:00
Mark Qvist
9473b9df82 Updated readme 2025-01-18 13:12:02 +01:00
Mark Qvist
2ee0e4eb13 Updated console build 2025-01-17 17:25:24 +01:00
Mark Qvist
926e32ec99 Updated console build 2025-01-17 17:04:27 +01:00
Mark Qvist
16090f73e4 Updated readme 2025-01-17 14:38:55 +01:00
Mark Qvist
919bddb703 Cleanup 2025-01-17 10:44:46 +01:00
Mark Qvist
458e40ce9a SX1262 register hang debug 2025-01-17 10:44:16 +01:00
Mark Qvist
3ae8982e93 False preamble detection on SX1262 2025-01-16 23:33:49 +01:00
Mark Qvist
4bdd30daac Cleanup 2025-01-16 23:15:17 +01:00
Mark Qvist
49d023379f Work around for SX1280 modem RSSI status latch on invalid preamble lengths 2025-01-16 23:01:46 +01:00
Mark Qvist
01a27cfd9b Display sleep on T-Echo 2025-01-16 12:20:01 +01:00
Mark Qvist
48bce4ea15 Actually, use SPIM3 for SX1262 on T-Echo 2025-01-16 12:19:38 +01:00
Mark Qvist
3379217e19 Sensible e-ink backlight default 2025-01-16 11:15:31 +01:00
Mark Qvist
9b792862b9 Improved T-Echo e-ink sleep 2025-01-16 11:00:39 +01:00
Mark Qvist
68349aaa70 Fixed T-Echo build paths 2025-01-16 10:19:34 +01:00
Mark Qvist
3e98ea14d2 Fixed T-Echo build paths 2025-01-16 09:46:30 +01:00
Mark Qvist
01e346f21f Added T-Echo to release 2025-01-15 23:57:38 +01:00
Mark Qvist
3fab6d4cdb Blank T-Echo display on sleep 2025-01-15 21:43:13 +01:00
Mark Qvist
ebf5b54957 Power init for T-Echo 2025-01-15 21:20:43 +01:00
Mark Qvist
4e627d6e6b Implemented backlight control and display blanking for T-Echo 2025-01-15 21:19:58 +01:00
Mark Qvist
113b2f1081 Battery management for T-Echo 2025-01-15 21:18:52 +01:00
Mark Qvist
733a792d72 Don't use SPIM3 for LoRa on T-Echo 2025-01-15 21:11:19 +01:00
Mark Qvist
ea33f0cba7 T-Echo pin definitions 2025-01-15 21:10:01 +01:00
Mark Qvist
7066b4de6f Fixed single-byte configuration changes not working on nRF 2025-01-15 21:09:30 +01:00
Mark Qvist
6b815c47d4 LED config on T-Echo 2025-01-15 21:00:02 +01:00
Mark Qvist
f447998c35 Initial T-Echo support 2025-01-15 18:38:34 +01:00
Mark Qvist
2d2d90847a Initial T-Echo support 2025-01-15 18:38:14 +01:00
Mark Qvist
13266c96db Cleanup 2025-01-15 14:03:35 +01:00
Mark Qvist
7e30648968 Fixed nRF52 soft-brick on device EEPROM wipe 2025-01-15 12:42:24 +01:00
Mark Qvist
32fc5afee2 Added missing config graphic 2025-01-15 12:41:15 +01:00
Mark Qvist
3073677b82 Added sleep and wake support on T114 2025-01-15 11:01:26 +01:00
Mark Qvist
2119d381b3 Refactored T3S3 board name variable 2025-01-15 10:21:15 +01:00
Mark Qvist
cbe95b10d6 Fixed incorrect display initialisation on T114 causing display noise on startup 2025-01-15 10:20:25 +01:00
Mark Qvist
6f0c849cb3 Fixed missing check in interference avoidance 2025-01-13 21:12:39 +01:00
Mark Qvist
6eaacb7f99 Cleanup 2025-01-13 20:06:51 +01:00
Mark Qvist
8cf6e9cb40 Added battery support to Heltec T114 2025-01-13 18:05:35 +01:00
Mark Qvist
7a505f73e3 Added signalling of detected interference. Added channel stats output on nRF. 2025-01-13 17:02:07 +01:00
Mark Qvist
b4b1d13dc9 Cleanup 2025-01-13 11:38:17 +01:00
Mark Qvist
becc3d0e3d Implemented display rotation on Heltec T114 2025-01-13 11:37:46 +01:00
Mark Qvist
95895f3756 Set firmware hashes on nRF 2025-01-13 11:37:29 +01:00
Mark Qvist
c1b3b4f416 Updated version 2025-01-13 11:36:42 +01:00
Mark Qvist
62cd3977c7 Added modified ST7789 driver for Heltec T114 2025-01-13 11:36:28 +01:00
Mark Qvist
7235fa6c3f Updated readme 2025-01-09 21:00:02 +01:00
Mark Qvist
7720fa5192 Updated readme 2025-01-09 20:57:41 +01:00
Mark Qvist
d0041281bd Updated release 2025-01-09 20:49:22 +01:00
Mark Qvist
71e73580f7 Cleanup 2025-01-09 18:41:35 +01:00
Mark Qvist
6e7370acdc Added interference avoidance option 2025-01-09 17:58:46 +01:00
Mark Qvist
434f55b240 Increased noise floor samples 2025-01-09 15:00:06 +01:00
Mark Qvist
06b4fba603 Added noise floor monitoring and reporting to host 2025-01-09 14:46:13 +01:00
Mark Qvist
c5ed792280 Scale waterfall dynamic range depending on band 2025-01-09 14:44:49 +01:00
Mark Qvist
5671cd7288 Typing 2025-01-09 12:54:57 +01:00
Mark Qvist
f466cabe61 Cleanup 2025-01-09 00:37:39 +01:00
Mark Qvist
8b8502e8e0 Cleanup 2025-01-09 00:34:22 +01:00
Mark Qvist
dbebb4080a Cleanup 2025-01-09 00:28:18 +01:00
Mark Qvist
7adc3e2a0d Cleanup 2025-01-09 00:13:27 +01:00
Mark Qvist
218a38adb7 Optimise packet handling for SX1280 fast data rates 2025-01-09 00:01:49 +01:00
Mark Qvist
729a4099e5 Correct invalid IRQ index for SX1280 2025-01-08 22:16:07 +01:00
Mark Qvist
9c7a04b66c Always use external crystal oscillator on SX1280 2025-01-08 21:26:37 +01:00
Mark Qvist
2b93b1b9e7 SX1280 parameter modifications 2025-01-08 20:58:12 +01:00
Mark Qvist
58f6a3d6a3 Reworked DCD methods for SX1276 and SX1280 2025-01-08 17:45:23 +01:00
Mark Qvist
a796e56dd9 Cleanup 2025-01-08 17:44:30 +01:00
Mark Qvist
aa7bb49b30 Cleanup 2025-01-08 16:52:50 +01:00
Mark Qvist
254225e917 Cleanup 2025-01-08 16:50:29 +01:00
Mark Qvist
ae47b89b53 Added banded contention window allocation 2025-01-08 16:46:16 +01:00
Mark Qvist
498652f583 Added CSMA stats command to host 2025-01-08 16:44:33 +01:00
Mark Qvist
c04067446d Configuration parameters for new CSMA scheme 2025-01-08 16:44:06 +01:00
Mark Qvist
4ab42c4269 Cleanup 2025-01-07 20:43:15 +01:00
Mark Qvist
7ce2ed6155 Cleanup 2025-01-07 20:33:20 +01:00
Mark Qvist
5ec063c939 Reworked CSMA algorithm 2025-01-07 20:15:26 +01:00
Mark Qvist
08651f92f7 Reworked SX1262 LoRa carrier detection 2025-01-07 15:14:44 +01:00
Mark Qvist
e40532ed35 Revert min preamble symbols 2025-01-06 14:21:09 +01:00
Mark Qvist
1dab538d8f Updated console image 2025-01-06 14:20:45 +01:00
Mark Qvist
c39164e272 Accurate preamble and airtime calculations on SX1280. Fix airtime calculation on SX1262 when LDRO is enabled. 2025-01-05 22:55:32 +01:00
Mark Qvist
b667e825f8 Cleanup 2025-01-05 22:47:28 +01:00
Mark Qvist
0545847e40 Cleanup 2025-01-05 21:05:51 +01:00
Mark Qvist
df6463144f Temporarily disabled Heltec T114 from release artifacts 2025-01-05 16:07:32 +01:00
Mark Qvist
42be6640de Updated issue template 2025-01-05 16:06:37 +01:00
Mark Qvist
01fcaadea5 Heltec T114 build config 2025-01-05 15:50:29 +01:00
Mark Qvist
bc9ce056ee Add Heltec T114 to release artifacts 2025-01-05 15:05:49 +01:00
Mark Qvist
0057852b6c Battery management for T3S3 2025-01-05 14:53:28 +01:00
Mark Qvist
b7b9fb0c04 Battery management for T3S3 2025-01-05 12:03:27 +01:00
Mark Qvist
564e2f26f3 Fixed intermittent radio init failure on T3S3 SX1280 2025-01-04 22:08:04 +01:00
Mark Qvist
9ba243ee1f Fixed intermittent radio init failure on T3S3 SX1280 2025-01-04 22:07:43 +01:00
Mark Qvist
eb168d4734 Cleanup 2025-01-04 21:05:11 +01:00
Mark Qvist
217db4bcd3 Update release builds to include T3S3 SX1280 PA 2025-01-04 20:20:35 +01:00
Mark Qvist
b9cd4d7751 Update version 2025-01-03 21:59:20 +01:00
Mark Qvist
b02989e07a Cleanup 2025-01-03 21:58:59 +01:00
Mark Qvist
b891932353 Add T3S3 SX1280 PA release 2025-01-03 21:58:43 +01:00
Mark Qvist
35a4b6ff4e Added support for T3S3 SX1280 2025-01-03 21:23:23 +01:00
Mark Qvist
4e251cd186 T3S3 SX1280 model codes 2025-01-03 21:22:37 +01:00
Mark Qvist
a663707a69 Waterfall TX width on SX1280 2025-01-03 21:21:11 +01:00
Mark Qvist
a5a3ca28fa T3S3 SX1280 initial driver support 2025-01-03 19:20:10 +01:00
Mark Qvist
421f2d5db3 Cleanup 2025-01-03 19:16:37 +01:00
Mark Qvist
6bf06ca94e T3S3 SX1280 support 2025-01-03 19:16:19 +01:00
Mark Qvist
315bcb02a0 SX1280 EEPROM checks 2025-01-03 12:52:01 +01:00
Mark Qvist
52fbe558d4 Only scale bitmaps if scaling factor != 1 2025-01-03 12:10:09 +01:00
Mark Qvist
470f4f4d09 Merge branch 'master' of github.com:markqvist/RNode_Firmware 2025-01-03 12:01:33 +01:00
markqvist
653845ad31
Merge pull request #98 from liamcottle/board/heltec-t114
Add support for Heltec T114
2025-01-03 12:01:10 +01:00
Mark Qvist
9174dbd34a Board defines for T3S3-SX1280 2025-01-03 11:54:48 +01:00
liamcottle
abde6561b5 use neopixel on heltec t114 2025-01-02 23:39:54 +13:00
liamcottle
6a43bf51ef remove unused rx switch 2025-01-02 15:28:10 +13:00
liamcottle
f9234733e2 add support for heltec t114 2025-01-02 15:14:18 +13:00
Mark Qvist
6c82de161c Added display reconditioning function 2024-12-31 14:20:43 +01:00
Mark Qvist
571e7d7105 Added display reconditioning function 2024-12-31 14:13:52 +01:00
Mark Qvist
2604b44d64 Added ability to configure display rotation 2024-12-31 13:23:48 +01:00
Mark Qvist
786c9990fb Updated console image 2024-12-12 12:41:55 +01:00
Mark Qvist
2263b20b81 Set default OCP 2024-12-10 18:42:13 +01:00
Mark Qvist
d599109562 Set default OCP 2024-12-10 16:37:55 +01:00
Mark Qvist
aba9a317dd Set default OCP 2024-12-10 16:05:08 +01:00
Mark Qvist
d88f231332 Added ability to specify per-board transceiver OCP limit 2024-12-10 15:35:29 +01:00
Mark Qvist
d012c37146 Added missing PA output pin configs 2024-12-10 15:34:57 +01:00
Mark Qvist
3e4bb282f8 Updated readme 2024-12-10 00:13:52 +01:00
Mark Qvist
315bc1c037 Updated console image 2024-12-10 00:05:52 +01:00
Mark Qvist
9445fc8992 Updated console build 2024-12-09 23:51:55 +01:00
Mark Qvist
33f7dde92e Updated readme 2024-12-08 14:09:02 +01:00
Mark Qvist
df7410e683 Updated readme 2024-12-08 14:06:09 +01:00
Mark Qvist
9f6f2fc000 Merge branch 'master' of github.com:markqvist/RNode_Firmware 2024-12-08 13:49:23 +01:00
Mark Qvist
4b48f41c38 Added display read command 2024-12-08 13:49:07 +01:00
markqvist
9fdd886d00
Merge pull request #96 from jacobeva/hash-fix
Retrieve firmware image length from bootloader cfg, fix #95
2024-12-07 22:37:03 +01:00
jacob.eva
5ac30b0fa7
Retrieve firmware image length from bootloader cfg, fix #95 2024-12-07 20:39:09 +00:00
markqvist
ead6b41259
Merge pull request #94 from jacobeva/ble-fix
Fix BLE packet corruption on nRF52
2024-10-23 22:07:48 +02:00
jacob.eva
5fbac58550
Increase BLE RX fifo buffer size on nRF52 2024-10-23 17:27:23 +01:00
Mark Qvist
9edc2224e7 Use built-in split-packet check in transmit function 2024-10-12 14:10:33 +02:00
Mark Qvist
7f998e6436 Merge branch 'master' of github.com:markqvist/RNode_Firmware 2024-10-12 14:07:25 +02:00
markqvist
711f9c6eac
Merge pull request #90 from jacobeva/transmit-fix
Improve checks around split packet handling in transmit()
2024-10-12 14:06:56 +02:00
markqvist
707608fd33
Merge pull request #89 from jacobeva/master
Decrease connection interval on BLE to increase throughput
2024-10-12 14:04:13 +02:00
jacob.eva
982a755464
Improve checks around split packet handling in transmit() 2024-10-12 13:00:52 +01:00
jacob.eva
34e872b25d
Decrease connection interval on BLE to increase throughput 2024-10-12 12:55:35 +01:00
Mark Qvist
a3e15bed1b Updated console image 2024-10-11 17:46:13 +02:00
27 changed files with 2734 additions and 1749 deletions

View File

@ -15,7 +15,11 @@ Before creating a bug report on this issue tracker, you **must** read the [Contr
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), delete this section from your bug report.
**Describe the Bug**
A clear and concise description of what the bug is.
First of all: Is this really a bug? Is it reproducible?
If this is a request for help because something is not working as you expected, stop right here, and go to the [discussions](https://github.com/markqvist/Reticulum/discussions) instead, where you can post your questions and get help from other users.
If this really is a bug or issue with the software, remove this section of the template, and provide **a clear and concise description of what the bug is**.
**To Reproduce**
Describe in detail how to reproduce the bug.
@ -24,7 +28,7 @@ Describe in detail how to reproduce the bug.
A clear and concise description of what you expected to happen.
**Logs & Screenshots**
Please include any relevant log output. If applicable, also add screenshots to help explain your problem.
Please include any relevant log output. If applicable, also add screenshots to help explain your problem. In most cases, without any relevant log output, we will not be able to determine the cause of the bug, or reproduce it.
**System Information**
- OS and version

View File

@ -34,7 +34,8 @@
#elif MCU_VARIANT == MCU_NRF52
#include <bluefruit.h>
#include <math.h>
BLEUart SerialBT;
#define BLE_RX_BUF 6144
BLEUart SerialBT(BLE_RX_BUF);
BLEDis bledis;
BLEBas blebas;
#endif
@ -382,6 +383,8 @@ char bt_devname[11];
}
}
void bt_flush() { if (bt_state == BT_STATE_CONNECTED) { SerialBT.flushTXD(); } }
void bt_disable_pairing() {
bt_allow_pairing = false;
bt_ssp_pin = 0;
@ -476,7 +479,7 @@ char bt_devname[11];
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
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);

204
Boards.h
View File

@ -41,11 +41,12 @@
#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 BOARD_T3S3 0x42 // T3S3 devices
#define MODEL_A1 0xA1 // T3S3, 433 MHz with SX1268
#define MODEL_A5 0xA5 // T3S3, 433 MHz with SX1278
#define MODEL_A6 0xA6 // T3S3, 868 MHz with SX1262
#define MODEL_AA 0xAA // T3S3, 868 MHz with SX1276
#define MODEL_AC 0xAC // T3S3, 2.4 GHz with SX1280 and PA
#define PRODUCT_TBEAM 0xE0 // T-Beam devices
#define BOARD_TBEAM 0x33
@ -89,6 +90,16 @@
#define MODEL_C5 0xC5 // Heltec Lora32 v3, 433 MHz
#define MODEL_CA 0xCA // Heltec Lora32 v3, 868 MHz
#define PRODUCT_HELTEC_T114 0xC2 // Heltec Mesh Node T114
#define BOARD_HELTEC_T114 0x3C
#define MODEL_C6 0xC6 // Heltec Mesh Node T114, 470-510 MHz
#define MODEL_C7 0xC7 // Heltec Mesh Node T114, 863-928 MHz
#define PRODUCT_TECHO 0x15 // LilyGO T-Echo devices
#define BOARD_TECHO 0x44
#define MODEL_16 0x16 // T-Echo 433 MHz
#define MODEL_17 0x17 // T-Echo 868/915 MHz
#define PRODUCT_RAK4631 0x10
#define BOARD_RAK4631 0x51
#define MODEL_11 0x11 // RAK4631, 433 Mhz
@ -227,6 +238,7 @@
#define HAS_TCXO true
#define HAS_BUSY true
#define DIO2_AS_RF_SWITCH true
#define OCP_TUNED 0x38
const int pin_busy = 32;
const int pin_dio = 33;
const int pin_tcxo_enable = -1;
@ -331,6 +343,7 @@
#define HAS_SLEEP true
#define PIN_WAKEUP GPIO_NUM_0
#define WAKEUP_LEVEL 0
#define OCP_TUNED 0x38
const int pin_btn_usr1 = 0;
@ -405,10 +418,10 @@
#endif
#endif
#elif BOARD_MODEL == BOARD_RNODE_NG_22
#elif BOARD_MODEL == BOARD_T3S3
#define IS_ESP32S3 true
#define HAS_DISPLAY true
#define HAS_CONSOLE false
#define HAS_CONSOLE true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_PMU true
@ -435,6 +448,21 @@
const int pin_busy = 34;
const int pin_dio = 33;
const int pin_tcxo_enable = -1;
#elif MODEM == SX1280
#define CONFIG_QUEUE_SIZE 6144
#define DIO2_AS_RF_SWITCH false
#define HAS_BUSY true
#define HAS_TCXO true
#define HAS_PA true
const int pa_max_input = 3;
#define HAS_RF_SWITCH_RX_TX true
const int pin_rxen = 21;
const int pin_txen = 10;
const int pin_busy = 36;
const int pin_dio = 9;
const int pin_tcxo_enable = -1;
#else
const int pin_dio = 9;
#endif
@ -519,6 +547,7 @@
#define DIO2_AS_RF_SWITCH true
#define HAS_BUSY true
#define HAS_TCXO true
#define OCP_TUNED 0x38
#define HAS_DISPLAY true
#define HAS_CONSOLE true
@ -595,6 +624,7 @@
// Following pins are for the sx1262
const int pin_rxen = 37;
const int pin_txen = -1;
const int pin_reset = 38;
const int pin_cs = 42;
const int pin_sclk = 43;
@ -606,12 +636,154 @@
const int pin_led_tx = LED_GREEN;
const int pin_tcxo_enable = -1;
#elif BOARD_MODEL == BOARD_TECHO
#define _PINNUM(port, pin) ((port) * 32 + (pin))
#define MODEM SX1262
#define HAS_EEPROM false
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_CONSOLE false
#define HAS_PMU true
#define HAS_NP false
#define HAS_SD false
#define HAS_TCXO true
#define HAS_BUSY true
#define HAS_INPUT true
#define HAS_SLEEP true
#define BLE_MANUFACTURER "LilyGO"
#define BLE_MODEL "T-Echo"
#define HAS_INPUT true
#define EEPROM_SIZE 296
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define CONFIG_UART_BUFFER_SIZE 32768
#define CONFIG_QUEUE_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define HAS_DISPLAY true
#define HAS_BACKLIGHT true
#define DISPLAY_SCALE 1
#define LED_ON LOW
#define LED_OFF HIGH
#define PIN_LED_GREEN _PINNUM(1, 1)
#define PIN_LED_RED _PINNUM(1, 3)
#define PIN_LED_BLUE _PINNUM(0, 14)
#define PIN_VEXT_EN _PINNUM(0, 12)
const int pin_disp_cs = 30;
const int pin_disp_dc = 28;
const int pin_disp_reset = 2;
const int pin_disp_busy = 3;
const int pin_disp_en = -1;
const int pin_disp_sck = 31;
const int pin_disp_mosi = 29;
const int pin_disp_miso = -1;
const int pin_backlight = 43;
const int pin_btn_usr1 = _PINNUM(1, 10);
const int pin_btn_touch = _PINNUM(0, 11);
const int pin_reset = 25;
const int pin_cs = 24;
const int pin_sclk = 19;
const int pin_mosi = 22;
const int pin_miso = 23;
const int pin_busy = 17;
const int pin_dio = 20;
const int pin_tcxo_enable = 21;
const int pin_led_rx = PIN_LED_BLUE;
const int pin_led_tx = PIN_LED_RED;
#elif BOARD_MODEL == BOARD_HELTEC_T114
#define MODEM SX1262
#define HAS_EEPROM false
#define HAS_DISPLAY true
#define HAS_BLUETOOTH false
#define HAS_BLE true
#define HAS_CONSOLE false
#define HAS_PMU true
#define HAS_NP true
#define HAS_SD false
#define HAS_TCXO true
#define HAS_BUSY true
#define HAS_INPUT true
#define HAS_SLEEP true
#define DIO2_AS_RF_SWITCH true
#define CONFIG_UART_BUFFER_SIZE 6144
#define CONFIG_QUEUE_SIZE 6144
#define CONFIG_QUEUE_MAX_LENGTH 200
#define EEPROM_SIZE 296
#define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
#define BLE_MANUFACTURER "Heltec"
#define BLE_MODEL "T114"
#define PIN_T114_ADC_EN 6
#define PIN_VEXT_EN 21
// LED
#define LED_T114_GREEN 3
#define PIN_T114_LED 14
#define NP_M 1
const int pin_np = PIN_T114_LED;
// SPI
#define PIN_T114_MOSI 22
#define PIN_T114_MISO 23
#define PIN_T114_SCK 19
#define PIN_T114_SS 24
// SX1262
#define PIN_T114_RST 25
#define PIN_T114_DIO1 20
#define PIN_T114_BUSY 17
// TFT
#define DISPLAY_SCALE 2
#define PIN_T114_TFT_MOSI 9
#define PIN_T114_TFT_MISO 11 // not connected
#define PIN_T114_TFT_SCK 8
#define PIN_T114_TFT_SS 11
#define PIN_T114_TFT_DC 12
#define PIN_T114_TFT_RST 2
#define PIN_T114_TFT_EN 3
#define PIN_T114_TFT_BLGT 15
// pins for buttons on Heltec T114
const int pin_btn_usr1 = 42;
// pins for sx1262 on Heltec T114
const int pin_reset = PIN_T114_RST;
const int pin_cs = PIN_T114_SS;
const int pin_sclk = PIN_T114_SCK;
const int pin_mosi = PIN_T114_MOSI;
const int pin_miso = PIN_T114_MISO;
const int pin_busy = PIN_T114_BUSY;
const int pin_dio = PIN_T114_DIO1;
const int pin_led_rx = 35;
const int pin_led_tx = 35;
const int pin_tcxo_enable = -1;
// pins for ST7789 display on Heltec T114
const int DISPLAY_DC = PIN_T114_TFT_DC;
const int DISPLAY_CS = PIN_T114_TFT_SS;
const int DISPLAY_MISO = PIN_T114_TFT_MISO;
const int DISPLAY_MOSI = PIN_T114_TFT_MOSI;
const int DISPLAY_CLK = PIN_T114_TFT_SCK;
const int DISPLAY_BL_PIN = PIN_T114_TFT_BLGT;
const int DISPLAY_RST = PIN_T114_TFT_RST;
#else
#error An unsupported nRF board was selected. Cannot compile RNode firmware.
#endif
#endif
#ifndef DISPLAY_SCALE
#define DISPLAY_SCALE 1
#endif
#ifndef HAS_RF_SWITCH_RX_TX
const int pin_rxen = -1;
const int pin_txen = -1;
@ -621,8 +793,26 @@
const int pin_busy = -1;
#endif
#ifndef LED_ON
#define LED_ON HIGH
#endif
#ifndef LED_OFF
#define LED_OFF LOW
#endif
#ifndef DIO2_AS_RF_SWITCH
#define DIO2_AS_RF_SWITCH false
#endif
// Default OCP value if not specified
// in board configuration
#ifndef OCP_TUNED
#define OCP_TUNED 0x38
#endif
#ifndef NP_M
#define NP_M 0.15
#endif
#endif

View File

@ -20,7 +20,7 @@
#define CONFIG_H
#define MAJ_VERS 0x01
#define MIN_VERS 0x4e
#define MIN_VERS 0x51
#define MODE_HOST 0x11
#define MODE_TNC 0x12
@ -67,31 +67,55 @@
const int rssi_offset = 157;
// Default LoRa settings
const int lora_rx_turnaround_ms = 66;
const int lora_post_tx_yield_slots = 6;
uint32_t post_tx_yield_timeout = 0;
#define LORA_PREAMBLE_SYMBOLS_HW 4
#define LORA_PREAMBLE_SYMBOLS_MIN 18
#define LORA_PREAMBLE_TARGET_MS 15
#define LORA_CAD_SYMBOLS 3
#define CSMA_SLOT_MAX_MS 100
#define CSMA_SLOT_MIN_MS 24
int csma_slot_ms = 50;
float csma_p_min = 0.15;
float csma_p_max = 0.333;
float csma_b_speed = 0.15;
uint8_t csma_p = 85;
#define PHY_HEADER_LORA_SYMBOLS 20
#define PHY_CRC_LORA_BITS 16
#define LORA_PREAMBLE_SYMBOLS_MIN 18
#define LORA_PREAMBLE_TARGET_MS 24
#define LORA_PREAMBLE_FAST_DELTA 18
#define LORA_FAST_THRESHOLD_BPS 30E3
#define LORA_LIMIT_THRESHOLD_BPS 60E3
long lora_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
long lora_preamble_time_ms = 0;
long lora_header_time_ms = 0;
float lora_symbol_time_ms = 0.0;
float lora_symbol_rate = 0.0;
float lora_us_per_byte = 0.0;
bool lora_low_datarate = false;
bool lora_limit_rate = false;
int lora_sf = 0;
int lora_cr = 5;
int lora_txp = 0xFF;
uint32_t lora_bw = 0;
uint32_t lora_freq = 0;
uint32_t lora_bitrate = 0;
long lora_preamble_symbols = 6;
float lora_symbol_time_ms = 0.0;
float lora_symbol_rate = 0.0;
float lora_us_per_byte = 0.0;
// CSMA Parameters
#define CSMA_SIFS_MS 0
#define CSMA_POST_TX_YIELD_SLOTS 3
#define CSMA_SLOT_MAX_MS 100
#define CSMA_SLOT_MIN_MS 24
#define CSMA_SLOT_MIN_FAST_DELTA 18
#define CSMA_SLOT_SYMBOLS 12
#define CSMA_CW_BANDS 4
#define CSMA_CW_MIN 0
#define CSMA_CW_PER_BAND_WINDOWS 15
#define CSMA_BAND_1_MAX_AIRTIME 7
#define CSMA_BAND_N_MIN_AIRTIME 85
#define CSMA_INFR_THRESHOLD_DB 12
bool interference_detected = false;
bool avoid_interference = true;
int csma_slot_ms = CSMA_SLOT_MIN_MS;
unsigned long difs_ms = CSMA_SIFS_MS + 2*csma_slot_ms;
unsigned long difs_wait_start = -1;
unsigned long cw_wait_start = -1;
unsigned long cw_wait_target = -1;
unsigned long cw_wait_passed = 0;
int csma_cw = -1;
uint8_t cw_band = 1;
uint8_t cw_min = 0;
uint8_t cw_max = CSMA_CW_PER_BAND_WINDOWS;
// LoRa settings
int lora_sf = 0;
int lora_cr = 5;
int lora_txp = 0xFF;
uint32_t lora_bw = 0;
uint32_t lora_freq = 0;
uint32_t lora_bitrate = 0;
// Operational variables
bool radio_locked = true;
@ -110,6 +134,8 @@
uint8_t model = 0x00;
uint8_t hwrev = 0x00;
#define NOISE_FLOOR_SAMPLES 64
int noise_floor = -292;
int current_rssi = -292;
int last_rssi = -292;
uint8_t last_rssi_raw = 0x00;
@ -167,11 +193,6 @@
uint32_t last_status_update = 0;
uint32_t last_dcd = 0;
// Status flags
const uint8_t SIG_DETECT = 0x01;
const uint8_t SIG_SYNCED = 0x02;
const uint8_t RX_ONGOING = 0x04;
// Power management
#define BATTERY_STATE_UNKNOWN 0x00
#define BATTERY_STATE_DISCHARGING 0x01
@ -186,6 +207,7 @@
uint8_t battery_state = 0x00;
uint8_t display_intensity = 0xFF;
uint8_t display_addr = 0xFF;
volatile bool display_updating = false;
bool display_blanking_enabled = false;
bool display_diagnostics = true;
bool device_init_done = false;

View File

@ -4,10 +4,10 @@ import sys
import shutil
packages = {
"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",
"rns": "rns-0.9.1-py3-none-any.whl",
"nomadnet": "nomadnet-0.5.7-py3-none-any.whl",
"lxmf": "lxmf-0.6.0-py3-none-any.whl",
"rnsh": "rnsh-0.1.5-py3-none-any.whl",
}
DEFAULT_TITLE = "RNode Bootstrap Console"
@ -174,7 +174,7 @@ mf.write(help_redirect)
mf.close()
def optimise_manual(path):
pm = 60
pm = 90
scale_imgs = [
("_images/board_rnodev2.png", pm),
("_images/board_rnode.png", pm),

View File

@ -2,7 +2,6 @@
[title]: <> (How To Make Your Own RNodes)
[image]: <> (images/g3p.webp)
[excerpt]: <> (This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a commercially purchased board.)
<div class="article_date">{DATE}</div>
# How To Make Your Own RNodes
This article will outline the general process, and provide the information you need, for building your own RNode from a few basic modules. The RNode will be functionally identical to a purchased device.
@ -31,10 +30,9 @@ Currently, the RNode firmware supports a variety of different microcontrollers,
Regarding the LoRa transceiver module, there is going to be an almost overwhelming amount of options to choose from. To narrow it down, here are the essential characteristics to look for:
- The RNode firmware needs a module based on the **Semtech SX1276** or **Semtech SX1278** LoRa transceiver IC. These come in several different variants, for all frequency bands from about 150 MHz to about 1100 MHz.
- Support for **SX1262**, **SX1268** and **SX1280**-based modules is coming soon, but until that is released, only **SX1276** and **SX1278** modules will work.
- The RNode firmware needs a module based on the **Semtech SX1276**, **Semtech SX1278**, **SX1262**, **SX1268** and **SX1280** LoRa transceiver ICs. These come in several different variants, for all frequency bands from about 150 MHz to 2500 MHz.
- The module *must* expose the direct SPI bus to the transceiver chip. UART based modules that add their own communications layer will not work.
- The module must also expose the *reset* line of the chip, and provide the **DIO0** interrupt signal *from* the chip.
- The module must also expose the *reset* line of the chip, and provide the **DIO0** (or other relevant) interrupt signal *from* the chip.
- As mentioned above, the module must be logic-level compatible with the microcontroller you are using, unless you want to add a level-shifter. Resistor divider arrays will most likely not work here, due to the bus speeds required.
Keeping those things in mind, you should be able to select a suitable combination of microcontroller board and transceiver module.
@ -56,12 +54,17 @@ In the photo above I used an Adafruit Feather ESP32 board and a ModTronix inAir4
9. Connect the *DIO0* pin of the transceiver module to the *DIO0 interrupt pin* of the microcontroller board.
10. You can optionally connect transmit and receiver LEDs to the corresponding pins of the microcontroller board.
The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the `Config.h` file of the [RNode Firmware]({ASSET_PATH}pkg/rnode_firmware.zip).
The pin layouts of your transceiver module and microcontroller board will vary, but you can look up the correct pin assignments for your processor type and board layout in the [Config.h](https://github.com/markqvist/RNode_Firmware/blob/master/Config.h) file of the [RNode Firmware](https://unsigned.io/rnode_firmware).
## Loading the Firmware
Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility]({ASSET_PATH}m/using.html#the-rnodeconf-utility).
### Loading the Firmware
Once the hardware is assembled, you are ready to load the firmware onto the board and configure the configuration parameters in the boards EEPROM. Luckily, this process is completely automated by the [RNode Configuration Utility](https://markqvist.github.io/Reticulum/manual/using.html#the-rnodeconf-utility). To prepare for loading the firmware, make sure that `python` and `pip` is installed on your system, then install the `rns` package (which includes the `rnodeconf` program) by issuing the command:
The `rnodeconf` program is included in the `rns` package. Please read [these instructions]({ASSET_PATH}s_rns.html) for more information on how to install it from this repository, or from the Internet. If installation goes well, you can now move on to the next step.
```txt
pip install rns
```
If installation goes well, you can now move on to the next step.
> *Take Care*: A LoRa transceiver module **must** be connected to the board for the firmware to start and accept commands. If the firmware does not verify that the correct transceiver is available on the SPI bus, execution is stopped, and the board will not accept commands. If you find the board unresponsive after installing the firmware, or EEPROM configuration fails, double-check your transceiver module wiring!
@ -73,24 +76,6 @@ rnodeconf --autoinstall
The installer will now ask you to insert the device you want to set up, scan for connected serial ports, and ask you a number of questions regarding the device. When it has the information it needs, it will install the correct firmware and configure the necessary parameters in the device EEPROM for it to function properly.
> **Please Note!** If you are connected to the Internet while installing, the autoinstaller will automatically download any needed firmware files to a local cache before installing.
> If you do not have an active Internet connection while installing, you can extract and use the firmware from this device instead. This will **only** work if you are building the same type of RNode as the device you are extracting from, as the firmware has to match the targeted board and hardware configuration.
If you need to extract the firmware from an existing RNode, run the following command:
```
rnodeconf --extract
```
If `rnodeconf` finds a working RNode, it will extract and save the firmware from the device for later use. You can then run the auto-installer with the `--use-extracted` option to use the locally extracted file:
```
rnodeconf --autoinstall --use-extracted
```
This also works for updating the firmware on existing RNodes, so you can extract a newer firmware from one RNode, and deploy it onto other RNodes using the same method. Just use the `--update` option instead of `--autoinstall`.
If the install goes well, you will be greated with a success message telling you that your device is now ready. To confirm everything is OK, you can query the device info with:
```txt

View File

@ -36,6 +36,8 @@
#define APPLICATION_START 0x26000
#define USER_DATA_START 0xED000
#define IMG_SIZE_START 0xFF008
#endif
#endif
@ -141,6 +143,13 @@ void device_save_firmware_hash() {
}
#if MCU_VARIANT == MCU_NRF52
uint32_t retrieve_application_size() {
uint8_t bytes[4];
memcpy(bytes, (const void*)IMG_SIZE_START, 4);
uint32_t fw_len = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24;
return fw_len;
}
void calculate_region_hash(unsigned long long start, unsigned long long end, uint8_t* return_hash) {
// this function calculates the hash digest of a region of memory,
// currently it is only designed to work for the application region
@ -152,16 +161,12 @@ void calculate_region_hash(unsigned long long start, unsigned long long end, uin
hash.begin(CRYS_HASH_SHA256_mode);
bool finish = false;
uint8_t size;
bool application = true;
int end_count = 0;
unsigned long length = 0;
while (start < end - 1 ) {
while (start < end ) {
const void* src = (const void*)start;
if (start + CHUNK_SIZE >= end) {
size = (end - 1) - start;
size = end - start;
}
else {
size = CHUNK_SIZE;
@ -169,74 +174,9 @@ void calculate_region_hash(unsigned long long start, unsigned long long end, uin
memcpy(chunk, src, CHUNK_SIZE);
// check if we've reached the end of the program
// if we're checking the application region
if (application) {
for (int i = 0; i < CHUNK_SIZE; i++) {
if (chunk[i] == 0xFF) {
bool matched = true;
end_count = 1;
// check if rest of chunk is FFs as well, only if FF is not
// at the end of chunk
if (i < CHUNK_SIZE - 1) {
for (int x = 0; x < CHUNK_SIZE - i; x++) {
if (chunk[i+x] != 0xFF) {
matched = false;
break;
}
end_count++;
}
}
if (matched) {
while (end_count < END_SECTION_SIZE) {
// check if bytes in next chunk up to total
// required are also FFs
for (int x = 1; x <= ceil(END_SECTION_SIZE / CHUNK_SIZE); x++) {
const void* src_next = (const void*)start + CHUNK_SIZE*x;
if ((END_SECTION_SIZE - end_count) > CHUNK_SIZE) {
size = CHUNK_SIZE;
} else {
size = END_SECTION_SIZE - end_count;
}
memcpy(chunk_next, src_next, size);
for (int y = 0; y < size; y++) {
if (chunk_next[y] != 0xFF) {
matched = false;
break;
}
end_count++;
}
if (!matched) {
break;
}
}
if (!matched) {
break;
}
}
if (matched) {
finish = true;
size = i;
break;
}
}
}
}
}
if (finish) {
hash.update(chunk, size);
length += size;
break;
} else {
hash.update(chunk, size);
}
hash.update(chunk, size);
start += CHUNK_SIZE;
length += CHUNK_SIZE;
}
hash.end(return_hash);
}
@ -257,7 +197,7 @@ void device_validate_partitions() {
esp_partition_get_sha256(esp_ota_get_running_partition(), dev_firmware_hash);
#elif MCU_VARIANT == MCU_NRF52
// todo, add bootloader, partition table, or softdevice?
calculate_region_hash(APPLICATION_START, USER_DATA_START, dev_firmware_hash);
calculate_region_hash(APPLICATION_START, APPLICATION_START+retrieve_application_size(), dev_firmware_hash);
#endif
#if VALIDATE_FIRMWARE
for (uint8_t i = 0; i < DEV_HASH_LEN; i++) {

433
Display.h
View File

@ -16,18 +16,33 @@
#include "Graphics.h"
#include <Adafruit_GFX.h>
#if BOARD_MODEL == BOARD_TDECK
#include <Adafruit_ST7789.h>
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
#include <Adafruit_SH110X.h>
#if BOARD_MODEL != BOARD_TECHO
#if BOARD_MODEL == BOARD_TDECK
#include <Adafruit_ST7789.h>
#elif BOARD_MODEL == BOARD_HELTEC_T114
#include "ST7789.h"
#define COLOR565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3))
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
#include <Adafruit_SH110X.h>
#else
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#endif
#else
#include <Wire.h>
#include <Adafruit_SSD1306.h>
void (*display_callback)();
void display_add_callback(void (*callback)()) { display_callback = callback; }
void busyCallback(const void* p) { display_callback(); }
#define SSD1306_BLACK GxEPD_BLACK
#define SSD1306_WHITE GxEPD_WHITE
#include <GxEPD2_BW.h>
#include <SPI.h>
#endif
#include "Fonts/Org_01.h"
#define DISP_W 128
#define DISP_H 64
#if BOARD_MODEL == BOARD_RNODE_NG_20 || BOARD_MODEL == BOARD_LORA32_V2_0
#define DISP_RST -1
#define DISP_ADDR 0x3C
@ -54,11 +69,16 @@
#elif BOARD_MODEL == BOARD_RNODE_NG_21
#define DISP_RST -1
#define DISP_ADDR 0x3C
#elif BOARD_MODEL == BOARD_RNODE_NG_22
#elif BOARD_MODEL == BOARD_T3S3
#define DISP_RST 21
#define DISP_ADDR 0x3C
#define SCL_OLED 17
#define SDA_OLED 18
#elif BOARD_MODEL == BOARD_TECHO
SPIClass displaySPI = SPIClass(NRF_SPIM0, pin_disp_miso, pin_disp_sck, pin_disp_mosi);
#define DISP_W 128
#define DISP_H 64
#define DISP_ADDR -1
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
#define DISP_RST -1
#define DISP_ADDR 0x3C
@ -77,14 +97,26 @@
Adafruit_ST7789 display = Adafruit_ST7789(DISPLAY_CS, DISPLAY_DC, -1);
#define SSD1306_WHITE ST77XX_WHITE
#define SSD1306_BLACK ST77XX_BLACK
#elif BOARD_MODEL == BOARD_HELTEC_T114
ST7789Spi display(&SPI1, DISPLAY_RST, DISPLAY_DC, DISPLAY_CS);
#define SSD1306_WHITE ST77XX_WHITE
#define SSD1306_BLACK ST77XX_BLACK
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);
#define SSD1306_WHITE SH110X_WHITE
#define SSD1306_BLACK SH110X_BLACK
#elif BOARD_MODEL == BOARD_TECHO
GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(pin_disp_cs, pin_disp_dc, pin_disp_reset, pin_disp_busy));
uint32_t last_epd_refresh = 0;
uint32_t last_epd_full_refresh = 0;
#define REFRESH_PERIOD 300000
#else
Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST);
#endif
float disp_target_fps = 7;
float epd_update_fps = 0.5;
#define DISP_MODE_UNKNOWN 0x00
#define DISP_MODE_LANDSCAPE 0x01
#define DISP_MODE_PORTRAIT 0x02
@ -99,8 +131,9 @@ uint32_t display_blanking_timeout = DISPLAY_BLANKING_TIMEOUT;
uint8_t display_unblank_intensity = display_intensity;
bool display_blanked = false;
bool display_tx = false;
uint8_t disp_target_fps = 7;
bool recondition_display = false;
int disp_update_interval = 1000/disp_target_fps;
int epd_update_interval = 1000/disp_target_fps;
uint32_t last_page_flip = 0;
int page_interval = 4000;
bool device_signatures_ok();
@ -118,24 +151,59 @@ int p_as_y = 0;
GFXcanvas1 stat_area(64, 64);
GFXcanvas1 disp_area(64, 64);
void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour);
void update_area_positions() {
if (disp_mode == DISP_MODE_PORTRAIT) {
p_ad_x = 0;
p_ad_y = 0;
p_as_x = 0;
p_as_y = 64;
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
p_ad_x = 0;
p_ad_y = 0;
p_as_x = 64;
p_as_y = 0;
}
#if BOARD_MODEL == BOARD_HELTEC_T114
if (disp_mode == DISP_MODE_PORTRAIT) {
p_ad_x = 16;
p_ad_y = 64;
p_as_x = 16;
p_as_y = p_ad_y+126;
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
p_ad_x = 0;
p_ad_y = 96;
p_as_x = 126;
p_as_y = p_ad_y;
}
#elif BOARD_MODEL == BOARD_TECHO
if (disp_mode == DISP_MODE_PORTRAIT) {
p_ad_x = 61;
p_ad_y = 36;
p_as_x = 64;
p_as_y = 64+36;
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
p_ad_x = 0;
p_ad_y = 0;
p_as_x = 64;
p_as_y = 0;
}
#else
if (disp_mode == DISP_MODE_PORTRAIT) {
p_ad_x = 0 * DISPLAY_SCALE;
p_ad_y = 0 * DISPLAY_SCALE;
p_as_x = 0 * DISPLAY_SCALE;
p_as_y = 64 * DISPLAY_SCALE;
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
p_ad_x = 0 * DISPLAY_SCALE;
p_ad_y = 0 * DISPLAY_SCALE;
p_as_x = 64 * DISPLAY_SCALE;
p_as_y = 0 * DISPLAY_SCALE;
}
#endif
}
uint8_t display_contrast = 0x00;
#if BOARD_MODEL == BOARD_TBEAM_S_V1
void set_contrast(Adafruit_SH1106G *display, uint8_t value) {
}
#elif BOARD_MODEL == BOARD_HELTEC_T114
void set_contrast(ST7789Spi *display, uint8_t value) { }
#elif BOARD_MODEL == BOARD_TECHO
void set_contrast(void *display, uint8_t value) {
if (value == 0) { analogWrite(pin_backlight, 0); }
else { analogWrite(pin_backlight, value); }
}
#elif BOARD_MODEL == BOARD_TDECK
void set_contrast(Adafruit_ST7789 *display, uint8_t value) {
static uint8_t level = 0;
@ -175,7 +243,7 @@ bool display_init() {
digitalWrite(pin_display_en, LOW);
delay(50);
digitalWrite(pin_display_en, HIGH);
#elif BOARD_MODEL == BOARD_RNODE_NG_22
#elif BOARD_MODEL == BOARD_T3S3
Wire.begin(SDA_OLED, SCL_OLED);
#elif BOARD_MODEL == BOARD_HELTEC32_V2
Wire.begin(SDA_OLED, SCL_OLED);
@ -197,15 +265,33 @@ bool display_init() {
delay(50);
digitalWrite(pin_display_en, HIGH);
Wire.begin(SDA_OLED, SCL_OLED);
#elif BOARD_MODEL == BOARD_HELTEC_T114
pinMode(PIN_T114_TFT_EN, OUTPUT);
digitalWrite(PIN_T114_TFT_EN, LOW);
#elif BOARD_MODEL == BOARD_TECHO
display.init(0, true, 10, false, displaySPI, SPISettings(4000000, MSBFIRST, SPI_MODE0));
display.setPartialWindow(0, 0, DISP_W, DISP_H);
display.epd2.setBusyCallback(busyCallback);
#if HAS_BACKLIGHT
pinMode(pin_backlight, OUTPUT);
analogWrite(pin_backlight, 0);
#endif
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
Wire.begin(SDA_OLED, SCL_OLED);
#endif
#if HAS_EEPROM
uint8_t display_rotation = EEPROM.read(eeprom_addr(ADDR_CONF_DROT));
#elif MCU_VARIANT == MCU_NRF52
uint8_t display_rotation = eeprom_read(eeprom_addr(ADDR_CONF_DROT));
#endif
if (display_rotation < 0 or display_rotation > 3) display_rotation = 0xFF;
#if DISP_CUSTOM_ADDR == true
#if HAS_EEPROM
uint8_t display_address = EEPROM.read(eeprom_addr(ADDR_CONF_DADR));
uint8_t display_address = EEPROM.read(eeprom_addr(ADDR_CONF_DADR));
#elif MCU_VARIANT == MCU_NRF52
uint8_t display_address = eeprom_read(eeprom_addr(ADDR_CONF_DADR));
uint8_t display_address = eeprom_read(eeprom_addr(ADDR_CONF_DADR));
#endif
if (display_address == 0xFF) display_address = DISP_ADDR;
#else
@ -222,11 +308,28 @@ bool display_init() {
display_blanking_timeout = db_timeout*1000;
}
}
#elif MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_CONF_BSET)) == CONF_OK_BYTE) {
uint8_t db_timeout = eeprom_read(eeprom_addr(ADDR_CONF_DBLK));
if (db_timeout == 0x00) {
display_blanking_enabled = false;
} else {
display_blanking_enabled = true;
display_blanking_timeout = db_timeout*1000;
}
}
#endif
#if BOARD_MODEL == BOARD_TDECK
#if BOARD_MODEL == BOARD_TECHO
// Don't check if display is actually connected
if(false) {
#elif BOARD_MODEL == BOARD_TDECK
display.init(240, 320);
display.setSPISpeed(80e6);
#elif BOARD_MODEL == BOARD_HELTEC_T114
display.init();
// set white as default pixel colour for Heltec T114
display.setRGB(COLOR565(0xFF, 0xFF, 0xFF));
if (false) {
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
if (!display.begin(display_address, true)) {
@ -236,60 +339,83 @@ bool display_init() {
return false;
} else {
set_contrast(&display, display_contrast);
#if BOARD_MODEL == BOARD_RNODE_NG_20
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_RNODE_NG_21
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V1_0
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V2_0
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V2_1
disp_mode = DISP_MODE_LANDSCAPE;
display.setRotation(0);
#elif BOARD_MODEL == BOARD_TBEAM
disp_mode = DISP_MODE_LANDSCAPE;
display.setRotation(0);
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC32_V2
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC32_V3
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#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);
#endif
if (display_rotation != 0xFF) {
if (display_rotation == 0 || display_rotation == 2) {
disp_mode = DISP_MODE_LANDSCAPE;
} else {
disp_mode = DISP_MODE_PORTRAIT;
}
display.setRotation(display_rotation);
} else {
#if BOARD_MODEL == BOARD_RNODE_NG_20
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_RNODE_NG_21
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V1_0
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V2_0
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#elif BOARD_MODEL == BOARD_LORA32_V2_1
disp_mode = DISP_MODE_LANDSCAPE;
display.setRotation(0);
#elif BOARD_MODEL == BOARD_TBEAM
disp_mode = DISP_MODE_LANDSCAPE;
display.setRotation(0);
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC32_V2
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC32_V3
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#elif BOARD_MODEL == BOARD_HELTEC_T114
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(1);
#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);
#elif BOARD_MODEL == BOARD_TECHO
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#else
disp_mode = DISP_MODE_PORTRAIT;
display.setRotation(3);
#endif
}
update_area_positions();
for (int i = 0; i < WATERFALL_SIZE; i++) {
waterfall[i] = 0;
}
for (int i = 0; i < WATERFALL_SIZE; i++) { waterfall[i] = 0; }
last_page_flip = millis();
stat_area.cp437(true);
disp_area.cp437(true);
#if BOARD_MODEL != BOARD_HELTEC_T114
display.cp437(true);
#endif
#if HAS_EEPROM
#if MCU_VARIANT != MCU_NRF52
display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT));
#else
display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT));
display_intensity = EEPROM.read(eeprom_addr(ADDR_CONF_DINT));
#elif MCU_VARIANT == MCU_NRF52
display_intensity = eeprom_read(eeprom_addr(ADDR_CONF_DINT));
#endif
display_unblank_intensity = display_intensity;
#if BOARD_MODEL == BOARD_TECHO
#if HAS_BACKLIGHT
if (display_intensity == 0) { analogWrite(pin_backlight, 0); }
else { analogWrite(pin_backlight, display_intensity); }
#endif
#endif
@ -297,6 +423,14 @@ bool display_init() {
display.fillScreen(SSD1306_BLACK);
#endif
#if BOARD_MODEL == BOARD_HELTEC_T114
// Enable backlight led (display is always black without this)
fillRect(p_ad_x, p_ad_y, 128, 128, SSD1306_BLACK);
fillRect(p_as_x, p_as_y, 128, 128, SSD1306_BLACK);
pinMode(PIN_T114_TFT_BLGT, OUTPUT);
digitalWrite(PIN_T114_TFT_BLGT, LOW);
#endif
return true;
}
#else
@ -304,6 +438,60 @@ bool display_init() {
#endif
}
// Draws a line on the screen
void drawLine(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) {
#if BOARD_MODEL == BOARD_HELTEC_T114
if(colour == SSD1306_WHITE){
display.setColor(WHITE);
} else if(colour == SSD1306_BLACK) {
display.setColor(BLACK);
}
display.drawLine(x, y, width, height);
#else
display.drawLine(x, y, width, height, colour);
#endif
}
// Draws a filled rectangle on the screen
void fillRect(int16_t x, int16_t y, int16_t width, int16_t height, uint16_t colour) {
#if BOARD_MODEL == BOARD_HELTEC_T114
if(colour == SSD1306_WHITE){
display.setColor(WHITE);
} else if(colour == SSD1306_BLACK) {
display.setColor(BLACK);
}
display.fillRect(x, y, width, height);
#else
display.fillRect(x, y, width, height, colour);
#endif
}
// Draws a bitmap to the display and auto scales it based on the boards configured DISPLAY_SCALE
void drawBitmap(int16_t startX, int16_t startY, const uint8_t* bitmap, int16_t bitmapWidth, int16_t bitmapHeight, uint16_t foregroundColour, uint16_t backgroundColour) {
#if DISPLAY_SCALE == 1
display.drawBitmap(startX, startY, bitmap, bitmapWidth, bitmapHeight, foregroundColour, backgroundColour);
#else
for(int16_t row = 0; row < bitmapHeight; row++){
for(int16_t col = 0; col < bitmapWidth; col++){
// determine index and bitmask
int16_t index = row * ((bitmapWidth + 7) / 8) + (col / 8);
uint8_t bitmask = 1 << (7 - (col % 8));
// check if the current pixel is set in the bitmap
if(bitmap[index] & bitmask){
// draw a scaled rectangle for the foreground pixel
fillRect(startX + col * DISPLAY_SCALE, startY + row * DISPLAY_SCALE, DISPLAY_SCALE, DISPLAY_SCALE, foregroundColour);
} else {
// draw a scaled rectangle for the background pixel
fillRect(startX + col * DISPLAY_SCALE, startY + row * DISPLAY_SCALE, DISPLAY_SCALE, DISPLAY_SCALE, backgroundColour);
}
}
}
#endif
}
void draw_cable_icon(int px, int py) {
if (cable_state == CABLE_STATE_DISCONNECTED) {
stat_area.drawBitmap(px, py, bm_cable+0*32, 16, 16, SSD1306_WHITE, SSD1306_BLACK);
@ -421,8 +609,13 @@ void draw_quality_bars(int px, int py) {
}
}
#define S_RSSI_MIN -135.0
#define S_RSSI_MAX -75.0
#if MODE == SX1280
#define S_RSSI_MIN -105.0
#define S_RSSI_MAX -65.0
#else
#define S_RSSI_MIN -135.0
#define S_RSSI_MAX -75.0
#endif
#define S_RSSI_SPAN (S_RSSI_MAX-S_RSSI_MIN)
void draw_signal_bars(int px, int py) {
stat_area.fillRect(px, py, 13, 7, SSD1306_BLACK);
@ -447,8 +640,11 @@ void draw_signal_bars(int px, int py) {
}
}
#define WF_TX_SIZE 5
#define WF_TX_WIDTH 5
#if MODEM == SX1280
#define WF_TX_SIZE 5
#else
#define WF_TX_SIZE 5
#endif
#define WF_RSSI_MAX -60
#define WF_RSSI_MIN -135
#define WF_RSSI_SPAN (WF_RSSI_MAX-WF_RSSI_MIN)
@ -510,19 +706,19 @@ void update_stat_area() {
draw_stat_area();
if (disp_mode == DISP_MODE_PORTRAIT) {
display.drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
display.drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (device_init_done && !disp_ext_fb) display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
drawBitmap(p_as_x+2, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (device_init_done && !disp_ext_fb) drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
}
} else {
if (firmware_update_mode) {
display.drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
drawBitmap(p_as_x, p_as_y, bm_updating, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
} else if (console_active && device_init_done) {
display.drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
drawBitmap(p_as_x, p_as_y, bm_console, stat_area.width(), stat_area.height(), SSD1306_BLACK, SSD1306_WHITE);
if (disp_mode == DISP_MODE_LANDSCAPE) {
display.drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
drawLine(p_as_x, 0, p_as_x, 64, SSD1306_WHITE);
}
}
}
@ -619,7 +815,7 @@ void draw_disp_area() {
if (!modem_installed) {
disp_area.drawBitmap(0, 37, bm_no_radio, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK);
} else {
disp_area.drawBitmap(0, 37, bm_hwfail, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK);
disp_area.drawBitmap(0, 37, bm_conf_missing, disp_area.width(), 27, SSD1306_WHITE, SSD1306_BLACK);
}
}
} else if (bt_state == BT_STATE_PAIRING and bt_ssp_pin != 0) {
@ -683,15 +879,48 @@ void draw_disp_area() {
void update_disp_area() {
draw_disp_area();
display.drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (disp_mode == DISP_MODE_LANDSCAPE) {
if (device_init_done && !firmware_update_mode && !disp_ext_fb) {
display.drawLine(0, 0, 0, 63, SSD1306_WHITE);
drawLine(0, 0, 0, 63, SSD1306_WHITE);
}
}
}
void display_recondition() {
#if PLATFORM == PLATFORM_ESP32
for (uint8_t iy = 0; iy < disp_area.height(); iy++) {
unsigned char rand_seg [] = {random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF),random(0xFF)};
stat_area.drawBitmap(0, iy, rand_seg, 64, 1, SSD1306_WHITE, SSD1306_BLACK);
disp_area.drawBitmap(0, iy, rand_seg, 64, 1, SSD1306_WHITE, SSD1306_BLACK);
}
drawBitmap(p_ad_x, p_ad_y, disp_area.getBuffer(), disp_area.width(), disp_area.height(), SSD1306_WHITE, SSD1306_BLACK);
if (disp_mode == DISP_MODE_PORTRAIT) {
drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
} else if (disp_mode == DISP_MODE_LANDSCAPE) {
drawBitmap(p_as_x, p_as_y, stat_area.getBuffer(), stat_area.width(), stat_area.height(), SSD1306_WHITE, SSD1306_BLACK);
}
#endif
}
bool epd_blanked = false;
#if BOARD_MODEL == BOARD_TECHO
void epd_blank(bool full_update = true) {
display.setFullWindow();
display.fillScreen(SSD1306_WHITE);
display.display(full_update);
}
void epd_black(bool full_update = true) {
display.setFullWindow();
display.fillScreen(SSD1306_BLACK);
display.display(full_update);
}
#endif
void update_display(bool blank = false) {
display_updating = true;
if (blank == true) {
last_disp_update = millis()-disp_update_interval-1;
} else {
@ -718,7 +947,17 @@ void update_display(bool blank = false) {
set_contrast(&display, display_contrast);
}
#if BOARD_MODEL != BOARD_TDECK
#if BOARD_MODEL == BOARD_TECHO
if (!epd_blanked) {
epd_blank();
epd_blanked = true;
}
#endif
#if BOARD_MODEL == BOARD_HELTEC_T114
display.clear();
display.display();
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
display.clearDisplay();
display.display();
#else
@ -727,26 +966,50 @@ void update_display(bool blank = false) {
last_disp_update = millis();
}
} else {
if (millis()-last_disp_update >= disp_update_interval) {
uint32_t current = millis();
if (display_contrast != display_intensity) {
display_contrast = display_intensity;
set_contrast(&display, display_contrast);
}
#if BOARD_MODEL != BOARD_TDECK
#if BOARD_MODEL == BOARD_HELTEC_T114
display.clear();
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
display.clearDisplay();
#endif
update_stat_area();
update_disp_area();
if (recondition_display) {
disp_target_fps = 30;
disp_update_interval = 1000/disp_target_fps;
display_recondition();
} else {
#if BOARD_MODEL == BOARD_TECHO
display.setFullWindow();
display.fillScreen(SSD1306_WHITE);
#endif
#if BOARD_MODEL != BOARD_TDECK
update_stat_area();
update_disp_area();
}
#if BOARD_MODEL == BOARD_TECHO
if (current-last_epd_refresh >= epd_update_interval) {
if (current-last_epd_full_refresh >= REFRESH_PERIOD) { display.display(false); last_epd_full_refresh = millis(); }
else { display.display(true); }
last_epd_refresh = millis();
epd_blanked = false;
}
#elif BOARD_MODEL != BOARD_TDECK
display.display();
#endif
last_disp_update = millis();
}
}
display_updating = false;
}
void display_unblank() {

View File

@ -45,6 +45,7 @@
#define CMD_STAT_CHTM 0x25
#define CMD_STAT_PHYPRM 0x26
#define CMD_STAT_BAT 0x27
#define CMD_STAT_CSMA 0x28
#define CMD_BLINK 0x30
#define CMD_RANDOM 0x40
@ -52,12 +53,16 @@
#define CMD_FB_READ 0x42
#define CMD_FB_WRITE 0x43
#define CMD_FB_READL 0x44
#define CMD_DISP_READ 0x66
#define CMD_DISP_INT 0x45
#define CMD_DISP_ADDR 0x63
#define CMD_DISP_BLNK 0x64
#define CMD_DISP_ROT 0x67
#define CMD_DISP_RCND 0x68
#define CMD_NP_INT 0x65
#define CMD_BT_CTRL 0x46
#define CMD_BT_PIN 0x62
#define CMD_DIS_IA 0x69
#define CMD_BOARD 0x47
#define CMD_PLATFORM 0x48

View File

@ -311,6 +311,23 @@ const unsigned char bm_hwfail [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const unsigned char bm_conf_missing [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0x33, 0x87, 0x0c, 0xcc, 0xe1, 0xff, 0xff,
0xe2, 0x33, 0x3e, 0x7c, 0xc4, 0xcf, 0xff, 0xff, 0xe0, 0x33, 0x8f, 0x1c, 0xc0, 0xc9, 0xff, 0xff,
0xe5, 0x33, 0xe7, 0xcc, 0xc8, 0xc9, 0xff, 0xff, 0xe7, 0x33, 0x0e, 0x1c, 0xcc, 0xe3, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xf1, 0xe3, 0x99, 0x86, 0x70, 0xff, 0xf6, 0xff,
0xe4, 0xc9, 0x89, 0x9e, 0x67, 0xff, 0xf6, 0xff, 0xe7, 0xc9, 0x81, 0x86, 0x64, 0xff, 0xef, 0x7f,
0xe4, 0xc9, 0x91, 0x9e, 0x64, 0xff, 0xe9, 0x7f, 0xf1, 0xe3, 0x99, 0x9e, 0x71, 0xff, 0xd9, 0xbf,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd9, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xef,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
const unsigned char bm_no_radio [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0xc7, 0x0e, 0x71, 0xfc, 0xce, 0x38, 0x7f,

View File

@ -46,6 +46,11 @@ prep-samd:
prep-nrf:
arduino-cli core update-index --config-file arduino-cli.yaml
arduino-cli core install rakwireless:nrf52 --config-file arduino-cli.yaml
arduino-cli core install Heltec_nRF52:Heltec_nRF52 --config-file arduino-cli.yaml
arduino-cli core install adafruit:nrf52 --config-file arduino-cli.yaml
arduino-cli lib install "GxEPD2"
arduino-cli config set library.enable_unsafe_install true
arduino-cli lib install --git-url https://github.com/liamcottle/esp8266-oled-ssd1306#e16cee124fe26490cb14880c679321ad8ac89c95
pip install adafruit-nrfutil --upgrade
console-site:
@ -81,6 +86,9 @@ firmware-t3s3:
firmware-t3s3_sx127x:
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x01\""
firmware-t3s3_sx1280_pa:
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x04\""
firmware-tdeck:
arduino-cli compile --log --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3B\""
@ -129,6 +137,12 @@ firmware-genericesp32: check_bt_buffers
firmware-rak4631:
arduino-cli compile --log --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
firmware-heltec_t114:
arduino-cli compile --log --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\""
firmware-techo:
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
upload:
arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode
@ -146,8 +160,8 @@ upload-tbeam_sx1262:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:t-beam
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
#@sleep 3
#python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-lora32_v10:
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:ttgo-lora32
@ -178,11 +192,11 @@ upload-heltec32_v2:
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyUSB1 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-heltec32_v3:
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:heltec_wifi_lora_32_V3
arduino-cli upload -p /dev/ttyUSB1 --fqbn esp32:esp32:heltec_wifi_lora_32_V3
@sleep 1
rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin)
rnodeconf /dev/ttyUSB1 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.heltec_wifi_lora_32_V3/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
python ./Release/esptool/esptool.py --chip esp32-s3 --port /dev/ttyUSB1 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
upload-tdeck:
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32s3
@ -228,12 +242,22 @@ upload-featheresp32:
upload-rak4631:
arduino-cli upload -p /dev/ttyACM0 --fqbn rakwireless:nrf52:WisCoreRAK4631Board
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
upload-heltec_t114:
arduino-cli upload -p /dev/ttyACM0 --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262
@sleep 1
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
upload-techo:
arduino-cli upload -p /dev/ttyACM0 --fqbn adafruit:nrf52:pca10056
@sleep 6
rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes from_device /dev/ttyACM0)
release: release-all
release-all: console-site spiffs-image release-rnode 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-t3s3_sx127x release-tdeck release-tbeam_supreme release-rak4631 release-hashes
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-heltec_t114 release-techo release-rnode_ng_20 release-rnode_ng_21 release-t3s3 release-t3s3_sx127x release-t3s3_sx1280_pa release-tdeck release-tbeam_supreme release-rak4631 release-hashes
release-hashes:
python ./release_hashes.py > ./Release/release.json
@ -378,6 +402,15 @@ release-t3s3:
zip --junk-paths ./Release/rnode_firmware_t3s3.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3.boot_app0 build/rnode_firmware_t3s3.bin build/rnode_firmware_t3s3.bootloader build/rnode_firmware_t3s3.partitions
rm -r build
release-t3s3_sx1280_pa:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x04\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bin build/rnode_firmware_t3s3_sx1280_pa.bin
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader
cp build/esp32.esp32.esp32s3/RNode_Firmware.ino.partitions.bin build/rnode_firmware_t3s3_sx1280_pa.partitions
zip --junk-paths ./Release/rnode_firmware_t3s3_sx1280_pa.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_t3s3_sx1280_pa.boot_app0 build/rnode_firmware_t3s3_sx1280_pa.bin build/rnode_firmware_t3s3_sx1280_pa.bootloader build/rnode_firmware_t3s3_sx1280_pa.partitions
rm -r build
release-t3s3_sx127x:
arduino-cli compile --fqbn "esp32:esp32:esp32s3:CDCOnBoot=cdc" -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x42\" \"-DMODEM=0x01\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_t3s3_sx127x.boot_app0
@ -432,3 +465,13 @@ release-rak4631:
arduino-cli compile --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
cp build/rakwireless.nrf52.WisCoreRAK4631Board/RNode_Firmware.ino.hex build/rnode_firmware_rak4631.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_rak4631.hex Release/rnode_firmware_rak4631.zip
release-heltec_t114:
arduino-cli compile --fqbn Heltec_nRF52:Heltec_nRF52:HT-n5262 -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x3C\""
cp build/Heltec_nRF52.Heltec_nRF52.HT-n5262/RNode_Firmware.ino.hex build/rnode_firmware_heltec_t114.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_heltec_t114.hex Release/rnode_firmware_heltec_t114.zip
release-techo:
arduino-cli compile --log --fqbn adafruit:nrf52:pca10056 -e --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x44\""
cp build/adafruit.nrf52.pca10056/RNode_Firmware.ino.hex build/rnode_firmware_techo.hex
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application build/rnode_firmware_techo.hex Release/rnode_firmware_techo.zip

76
Power.h
View File

@ -62,6 +62,22 @@
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_T3S3
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.217
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 5
const uint8_t pin_vbat = 1;
float bat_p_samples[BAT_SAMPLES];
float bat_v_samples[BAT_SAMPLES];
uint8_t bat_samples_count = 0;
int bat_discharging_samples = 0;
int bat_charging_samples = 0;
int bat_charged_samples = 0;
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_TDECK
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.3
@ -95,6 +111,39 @@
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_HELTEC_T114
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.165
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 7
const uint8_t pin_vbat = 4;
const uint8_t pin_ctrl = 6;
float bat_p_samples[BAT_SAMPLES];
float bat_v_samples[BAT_SAMPLES];
uint8_t bat_samples_count = 0;
int bat_discharging_samples = 0;
int bat_charging_samples = 0;
int bat_charged_samples = 0;
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#elif BOARD_MODEL == BOARD_TECHO
#define BAT_V_MIN 3.15
#define BAT_V_MAX 4.16
#define BAT_V_CHG 4.48
#define BAT_V_FLOAT 4.33
#define BAT_SAMPLES 7
const uint8_t pin_vbat = 4;
float bat_p_samples[BAT_SAMPLES];
float bat_v_samples[BAT_SAMPLES];
uint8_t bat_samples_count = 0;
int bat_discharging_samples = 0;
int bat_charging_samples = 0;
int bat_charged_samples = 0;
bool bat_voltage_dropping = false;
float bat_delay_v = 0;
float bat_state_change_v = 0;
#endif
uint32_t last_pmu_update = 0;
@ -105,14 +154,20 @@ uint8_t pmu_rc = 0;
void kiss_indicate_battery();
void measure_battery() {
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_HELTEC32_V3 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_HELTEC_T114 || BOARD_MODEL == BOARD_TECHO
battery_installed = true;
battery_indeterminate = true;
#if BOARD_MODEL == BOARD_HELTEC32_V3
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.0041;
#elif BOARD_MODEL == BOARD_T3S3
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*6.7828;
#elif BOARD_MODEL == BOARD_HELTEC_T114
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.017165;
#elif BOARD_MODEL == BOARD_TECHO
float battery_measurement = (float)(analogRead(pin_vbat)) * 0.007067;
#else
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*2.0*3.3*1.1;
float battery_measurement = (float)(analogRead(pin_vbat)) / 4095.0*7.26;
#endif
bat_v_samples[bat_samples_count%BAT_SAMPLES] = battery_measurement;
@ -177,13 +232,14 @@ void measure_battery() {
}
}
#if MCU_VARIANT == MCU_NRF52
if (bt_state != BT_STATE_OFF) { blebas.write(battery_percent); }
#endif
// if (bt_state == BT_STATE_CONNECTED) {
// SerialBT.printf("Bus voltage %.3fv. Unfiltered %.3fv.", battery_voltage, bat_v_samples[BAT_SAMPLES-1]);
// if (bat_voltage_dropping) {
// SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent);
// } else {
// SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent);
// }
// if (bat_voltage_dropping) { SerialBT.printf(" Voltage is dropping. Percentage %.1f%%.", battery_percent); }
// else { SerialBT.printf(" Voltage is not dropping. Percentage %.1f%%.", battery_percent); }
// if (battery_state == BATTERY_STATE_DISCHARGING) { SerialBT.printf(" Battery discharging. delay_v %.3fv", bat_delay_v); }
// if (battery_state == BATTERY_STATE_CHARGING) { SerialBT.printf(" Battery charging. delay_v %.3fv", bat_delay_v); }
// if (battery_state == BATTERY_STATE_CHARGED) { SerialBT.print(" Battery is charged."); }
@ -288,13 +344,17 @@ void update_pmu() {
}
bool init_pmu() {
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK
#if BOARD_MODEL == BOARD_RNODE_NG_21 || BOARD_MODEL == BOARD_LORA32_V2_1 || BOARD_MODEL == BOARD_TDECK || BOARD_MODEL == BOARD_T3S3 || BOARD_MODEL == BOARD_TECHO
pinMode(pin_vbat, INPUT);
return true;
#elif BOARD_MODEL == BOARD_HELTEC32_V3
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, LOW);
return true;
#elif BOARD_MODEL == BOARD_HELTEC_T114
pinMode(pin_ctrl,OUTPUT);
digitalWrite(pin_ctrl, HIGH);
return true;
#elif BOARD_MODEL == BOARD_TBEAM
Wire.begin(I2C_SDA, I2C_SCL);

View File

@ -1,4 +1,4 @@
***Important!** This repository is currently functioning as a stable reference for the default RNode Firmware, and only receives bugfix and security updates. Further development, new features and expanded board support is now happening at the [RNode Firmware Community Edition](https://github.com/liberatedsystems/RNode_Firmware_CE) repository, and is maintained by [Liberated Systems](https://github.com/liberatedsystems). Thanks for all contributions so far!*
***Important!** This repository is currently functioning as a stable reference for the default RNode Firmware, and only receives bugfix and security updates. Further development, new features and expanded board support is now happening at the [RNode Firmware Community Edition](https://github.com/liberatedsystems/RNode_Firmware_CE) repository, and is maintained by [Liberated Embedded Systems](https://github.com/liberatedsystems). Thanks for all contributions so far!*
# RNode Firmware
@ -16,16 +16,7 @@ The RNode system is primarily software, which *transforms* different kinds of av
## Latest Release
The latest release, installable through `rnodeconf`, is version `1.78`. This release brings the following changes:
- Improves BLE on RAK4631
- Adds graceful BLE disconnect on device sleep
- Fixes intermittent packet corruption on RAK4631
- Fixes incorrect preamble calculation on SX1280
- Improves CSMA parameters and P-curve
- Updated console image to include latest packages
You must have at least version `2.2.0` of `rnodeconf` installed to update the RNode Firmware to version `1.78`. Get it by updating the `rns` package to at least version `0.8.4`.
The latest release, installable through `rnodeconf`, is version `1.81`. You must have at least version `2.4.0` of `rnodeconf` installed to update the RNode Firmware to version `1.81`. Get it by updating the `rns` package to at least version `0.9.0`.
## A Self-Replicating System
@ -80,8 +71,11 @@ The RNode Firmware supports the following boards:
- LilyGO LoRa32 v2.1 devices (with and without TCXO)
- LilyGO T3S3 devices with SX1276/8 LoRa chips
- LilyGO T3S3 devices with SX1262/8 LoRa chips
- LilyGO T3S3 devices with SX1280 LoRa chips
- LilyGO T-Echo devices
- Heltec LoRa32 v2 devices
- Heltec LoRa32 v3 devices
- Heltec T114 devices
- RAK4631 devices
- Homebrew RNodes based on ATmega1284p boards
- Homebrew RNodes based on ATmega2560 boards
@ -89,9 +83,7 @@ The RNode Firmware supports the following boards:
- Homebrew RNodes based on generic ESP32 boards
## Supported Transceiver Modules
The RNode Firmware supports all transceiver modules based on **Semtech SX1276** or **Semtech SX1278** chips, that have an **SPI interface** and expose the **DIO_0** interrupt pin from the chip.
Support for **SX1262**, **SX1268** and **SX1280** is being implemented. Please support the project with donations if you want this faster!
The RNode Firmware supports all transceiver modules based on Semtech **SX1276**, **SX1278**, **SX1262**, **SX1268** and **SX1280** chips, that have an **SPI interface** and expose the relevant **DIO** interrupt pins from the chip.
## Getting Started Fast
You can download and flash the firmware to all the supported boards using the [RNode Config Utility](https://github.com/markqvist/rnodeconfigutil). All firmware releases are now handled and installed directly through the `rnodeconf` utility, which is included in the `rns` package. It can be installed via `pip`:
@ -104,6 +96,8 @@ pip install rns --upgrade
rnodeconf --autoinstall
```
For most of the supported device types, it is also possible to use [Liam Cottle's Web-based RNode Flasher](https://liamcottle.github.io/rnode-flasher/). This option may be easier if you're not familiar with using a command line interface.
For more detailed instruction and in-depth guides, you can have a look at some of these resources:
- Create a [basic RNode from readily available development boards](https://unsigned.io/guides/2022_01_25_installing-rnode-firmware-on-supported-devices.html)

View File

@ -78,9 +78,19 @@ void setup() {
#endif
#if MCU_VARIANT == MCU_NRF52
if (!eeprom_begin()) {
Serial.write("EEPROM initialisation failed.\r\n");
}
#if BOARD_MODEL == BOARD_TECHO
delay(200);
pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_VEXT_EN, HIGH);
pinMode(pin_btn_usr1, INPUT_PULLUP);
pinMode(pin_btn_touch, INPUT_PULLUP);
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_GREEN, OUTPUT);
pinMode(PIN_LED_BLUE, OUTPUT);
delay(200);
#endif
if (!eeprom_begin()) { Serial.write("EEPROM initialisation failed.\r\n"); }
#endif
// Seed the PRNG for CSMA R-value selection
@ -105,11 +115,11 @@ void setup() {
led_init();
#endif
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_RNODE_NG_22 && BOARD_MODEL != BOARD_TBEAM_S_V1
// Some boards need to wait until the hardware UART is set up before booting
// the full firmware. In the case of the RAK4631, the line below will wait
// until a serial connection is actually established with a master. Thus, it
// is disabled on this platform.
#if BOARD_MODEL != BOARD_RAK4631 && BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_TECHO && BOARD_MODEL != BOARD_T3S3 && BOARD_MODEL != BOARD_TBEAM_S_V1
// Some boards need to wait until the hardware UART is set up before booting
// the full firmware. In the case of the RAK4631 and Heltec T114, the line below will wait
// until a serial connection is actually established with a master. Thus, it
// is disabled on this platform.
while (!Serial);
#endif
@ -161,6 +171,14 @@ void setup() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
init_channel_stats();
#if BOARD_MODEL == BOARD_T3S3
#if MODEM == SX1280
delay(300);
LoRa->reset();
delay(100);
#endif
#endif
// Check installed transceiver chip and
// probe boot parameters.
if (LoRa->preInit()) {
@ -201,8 +219,16 @@ void setup() {
if (eeprom_read(eeprom_addr(ADDR_CONF_DSET)) != CONF_OK_BYTE) {
#endif
eeprom_update(eeprom_addr(ADDR_CONF_DSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF);
#if BOARD_MODEL == BOARD_TECHO
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0x03);
#else
eeprom_update(eeprom_addr(ADDR_CONF_DINT), 0xFF);
#endif
}
#if BOARD_MODEL == BOARD_TECHO
display_add_callback(work_while_waiting);
#endif
display_unblank();
disp_ready = display_init();
update_display();
@ -229,6 +255,22 @@ void setup() {
}
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#if MODEM == SX1280
avoid_interference = false;
#else
#if HAS_EEPROM
uint8_t ia_conf = EEPROM.read(eeprom_addr(ADDR_CONF_DIA));
if (ia_conf == 0x00) { avoid_interference = true; }
else { avoid_interference = false; }
#elif MCU_VARIANT == MCU_NRF52
uint8_t ia_conf = eeprom_read(eeprom_addr(ADDR_CONF_DIA));
if (ia_conf == 0x00) { avoid_interference = true; }
else { avoid_interference = false; }
#endif
#endif
#endif
// Validate board health, EEPROM and config
validate_status();
@ -501,17 +543,13 @@ void update_radio_lock() {
}
}
bool queueFull() {
return (queue_height >= CONFIG_QUEUE_MAX_LENGTH || queued_bytes >= CONFIG_QUEUE_SIZE);
}
bool queue_full() { return (queue_height >= CONFIG_QUEUE_MAX_LENGTH || queued_bytes >= CONFIG_QUEUE_SIZE); }
volatile bool queue_flushing = false;
void flushQueue(void) {
void flush_queue(void) {
if (!queue_flushing) {
queue_flushing = true;
led_tx_on();
uint16_t processed = 0;
led_tx_on(); uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
while (!fifo16_isempty(&packet_starts)) {
@ -528,39 +566,102 @@ void flushQueue(void) {
tbuf[i] = packet_queue[pos];
}
transmit(length);
processed++;
transmit(length); processed++;
}
}
lora_receive();
led_tx_off();
post_tx_yield_timeout = millis()+(lora_post_tx_yield_slots*csma_slot_ms);
lora_receive(); led_tx_off();
}
queue_height = 0;
queued_bytes = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
update_airtime();
#endif
queue_flushing = false;
#if HAS_DISPLAY
display_tx = true;
#endif
}
void pop_queue() {
if (!queue_flushing) {
queue_flushing = true;
led_tx_on(); uint16_t processed = 0;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!fifo16_isempty(&packet_starts)) {
#else
if (!fifo16_isempty_locked(&packet_starts)) {
#endif
uint16_t start = fifo16_pop(&packet_starts);
uint16_t length = fifo16_pop(&packet_lengths);
if (length >= MIN_L && length <= MTU) {
for (uint16_t i = 0; i < length; i++) {
uint16_t pos = (start+i)%CONFIG_QUEUE_SIZE;
tbuf[i] = packet_queue[pos];
}
transmit(length); processed++;
}
queue_height -= processed;
queued_bytes -= length;
}
lora_receive(); led_tx_off();
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
update_airtime();
#endif
queue_flushing = false;
#if HAS_DISPLAY
display_tx = true;
#endif
}
#define PHY_HEADER_LORA_SYMBOLS 8
void add_airtime(uint16_t written) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
float lora_symbols = 0;
float packet_cost_ms = 0.0;
float payload_cost_ms = ((float)written * lora_us_per_byte)/1000.0;
packet_cost_ms += payload_cost_ms;
packet_cost_ms += (lora_preamble_symbols+4.25)*lora_symbol_time_ms;
packet_cost_ms += PHY_HEADER_LORA_SYMBOLS * lora_symbol_time_ms;
int ldr_opt = 0; if (lora_low_datarate) ldr_opt = 1;
#if MODEM == SX1276 || MODEM == SX1278
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*(lora_sf-2*ldr_opt);
lora_symbols *= lora_cr;
lora_symbols += lora_preamble_symbols + 0.25 + 8;
packet_cost_ms += lora_symbols * lora_symbol_time_ms;
#elif MODEM == SX1262 || MODEM == SX1280
if (lora_sf < 7) {
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*lora_sf;
lora_symbols *= lora_cr;
lora_symbols += lora_preamble_symbols + 2.25 + 8;
packet_cost_ms += lora_symbols * lora_symbol_time_ms;
} else {
lora_symbols += (8*written + PHY_CRC_LORA_BITS - 4*lora_sf + 8 + PHY_HEADER_LORA_SYMBOLS);
lora_symbols /= 4*(lora_sf-2*ldr_opt);
lora_symbols *= lora_cr;
lora_symbols += lora_preamble_symbols + 0.25 + 8;
packet_cost_ms += lora_symbols * lora_symbol_time_ms;
}
#endif
uint16_t cb = current_airtime_bin();
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
airtime_bins[cb] += packet_cost_ms;
airtime_bins[nb] = 0;
#endif
}
@ -569,24 +670,20 @@ void update_airtime() {
uint16_t cb = current_airtime_bin();
uint16_t pb = cb-1; if (cb-1 < 0) { pb = AIRTIME_BINS-1; }
uint16_t nb = cb+1; if (nb == AIRTIME_BINS) { nb = 0; }
airtime_bins[nb] = 0;
airtime = (float)(airtime_bins[cb]+airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
airtime_bins[nb] = 0; airtime = (float)(airtime_bins[cb]+airtime_bins[pb])/(2.0*AIRTIME_BINLEN_MS);
uint32_t longterm_airtime_sum = 0;
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
longterm_airtime_sum += airtime_bins[bin];
}
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) { longterm_airtime_sum += airtime_bins[bin]; }
longterm_airtime = (float)longterm_airtime_sum/(float)AIRTIME_LONGTERM_MS;
float longterm_channel_util_sum = 0.0;
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) {
longterm_channel_util_sum += longterm_bins[bin];
}
for (uint16_t bin = 0; bin < AIRTIME_BINS; bin++) { longterm_channel_util_sum += longterm_bins[bin]; }
longterm_channel_util = (float)longterm_channel_util_sum/(float)AIRTIME_BINS;
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
update_csma_p();
update_csma_parameters();
#endif
kiss_indicate_channel_stats();
#endif
}
@ -596,21 +693,23 @@ void transmit(uint16_t size) {
if (!promisc) {
uint16_t written = 0;
uint8_t header = random(256) & 0xF0;
if (size > SINGLE_MTU - HEADER_L) {
header = header | FLAG_SPLIT;
}
if (size > SINGLE_MTU - HEADER_L) { header = header | FLAG_SPLIT; }
LoRa->beginPacket();
LoRa->write(header); written++;
for (uint16_t i=0; i < size; i++) {
LoRa->write(tbuf[i]);
LoRa->write(tbuf[i]); written++;
written++;
if (written == 255 && isSplitPacket(header)) {
if (!LoRa->endPacket()) {
kiss_indicate_error(ERROR_MODEM_TIMEOUT);
kiss_indicate_error(ERROR_TXFAILED);
led_indicate_error(5);
hard_reset();
}
if (written == 255) {
LoRa->endPacket(); add_airtime(written);
add_airtime(written);
LoRa->beginPacket();
LoRa->write(header);
written = 1;
@ -623,42 +722,22 @@ void transmit(uint16_t size) {
led_indicate_error(5);
hard_reset();
}
add_airtime(written);
} else {
// In promiscuous mode, we only send out
// plain raw LoRa packets with a maximum
// payload of 255 bytes
led_tx_on();
uint16_t written = 0;
// Cap packets at 255 bytes
if (size > SINGLE_MTU) {
size = SINGLE_MTU;
}
// If implicit header mode has been set,
// set packet length to payload data length
if (!implicit) {
LoRa->beginPacket();
} else {
LoRa->beginPacket(size);
}
for (uint16_t i=0; i < size; i++) {
LoRa->write(tbuf[i]);
written++;
}
led_tx_on(); uint16_t written = 0;
if (size > SINGLE_MTU) { size = SINGLE_MTU; }
if (!implicit) { LoRa->beginPacket(); }
else { LoRa->beginPacket(size); }
for (uint16_t i=0; i < size; i++) { LoRa->write(tbuf[i]); written++; }
LoRa->endPacket(); add_airtime(written);
}
} else {
kiss_indicate_error(ERROR_TXFAILED);
led_indicate_error(5);
}
} else { kiss_indicate_error(ERROR_TXFAILED); led_indicate_error(5); }
}
void serialCallback(uint8_t sbyte) {
void serial_callback(uint8_t sbyte) {
if (IN_FRAME && sbyte == FEND && command == CMD_DATA) {
IN_FRAME = false;
@ -667,21 +746,15 @@ void serialCallback(uint8_t sbyte) {
int16_t e = queue_cursor-1; if (e == -1) e = CONFIG_QUEUE_SIZE-1;
uint16_t l;
if (s != e) {
l = (s < e) ? e - s + 1 : CONFIG_QUEUE_SIZE - s + e + 1;
} else {
l = 1;
}
if (s != e) { l = (s < e) ? e - s + 1 : CONFIG_QUEUE_SIZE - s + e + 1; }
else { l = 1; }
if (l >= MIN_L) {
queue_height++;
fifo16_push(&packet_starts, s);
fifo16_push(&packet_lengths, l);
current_packet_start = queue_cursor;
}
}
} else if (sbyte == FEND) {
@ -763,6 +836,12 @@ void serialCallback(uint8_t sbyte) {
int txp = sbyte;
#if MODEM == SX1262
if (txp > 22) txp = 22;
#elif MODEM == SX1280
#if HAS_PA
if (txp > 20) txp = 20;
#else
if (txp > 13) txp = 13;
#endif
#else
if (txp > 17) txp = 17;
#endif
@ -893,7 +972,7 @@ void serialCallback(uint8_t sbyte) {
}
kiss_indicate_promisc();
} else if (command == CMD_READY) {
if (!queueFull()) {
if (!queue_full()) {
kiss_indicate_ready();
} else {
kiss_indicate_not_ready();
@ -967,9 +1046,9 @@ void serialCallback(uint8_t sbyte) {
}
#endif
} else if (command == CMD_FB_READ) {
if (sbyte != 0x00) {
kiss_indicate_fb();
}
if (sbyte != 0x00) { kiss_indicate_fb(); }
} else if (command == CMD_DISP_READ) {
if (sbyte != 0x00) { kiss_indicate_disp(); }
} else if (command == CMD_DEV_HASH) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (sbyte != 0x00) {
@ -1062,7 +1141,6 @@ void serialCallback(uint8_t sbyte) {
di_conf_save(display_intensity);
display_unblank();
}
#endif
} else if (command == CMD_DISP_ADDR) {
#if HAS_DISPLAY
@ -1092,7 +1170,44 @@ void serialCallback(uint8_t sbyte) {
db_conf_save(sbyte);
display_unblank();
}
#endif
} else if (command == CMD_DISP_ROT) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
drot_conf_save(sbyte);
display_unblank();
}
#endif
} else if (command == CMD_DIS_IA) {
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
dia_conf_save(sbyte);
}
} else if (command == CMD_DISP_RCND) {
#if HAS_DISPLAY
if (sbyte == FESC) {
ESCAPE = true;
} else {
if (ESCAPE) {
if (sbyte == TFEND) sbyte = FEND;
if (sbyte == TFESC) sbyte = FESC;
ESCAPE = false;
}
if (sbyte > 0x00) recondition_display = true;
}
#endif
} else if (command == CMD_NP_INT) {
#if HAS_NP
@ -1118,14 +1233,46 @@ void serialCallback(uint8_t sbyte) {
portMUX_TYPE update_lock = portMUX_INITIALIZER_UNLOCKED;
#endif
void updateModemStatus() {
bool medium_free() {
update_modem_status();
if (avoid_interference && interference_detected) { return false; }
return !dcd;
}
bool noise_floor_sampled = false;
int noise_floor_sample = 0;
int noise_floor_buffer[NOISE_FLOOR_SAMPLES] = {0};
void update_noise_floor() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (!dcd) {
if (!noise_floor_sampled || current_rssi < noise_floor + CSMA_INFR_THRESHOLD_DB) {
noise_floor_buffer[noise_floor_sample] = current_rssi;
noise_floor_sample = noise_floor_sample+1;
if (noise_floor_sample >= NOISE_FLOOR_SAMPLES) {
noise_floor_sample %= NOISE_FLOOR_SAMPLES;
noise_floor_sampled = true;
}
if (noise_floor_sampled) {
noise_floor = 0;
for (int ni = 0; ni < NOISE_FLOOR_SAMPLES; ni++) { noise_floor += noise_floor_buffer[ni]; }
noise_floor /= NOISE_FLOOR_SAMPLES;
}
}
}
#endif
}
#define LED_ID_TRIG 16
uint8_t led_id_filter = 0;
void update_modem_status() {
#if MCU_VARIANT == MCU_ESP32
portENTER_CRITICAL(&update_lock);
#elif MCU_VARIANT == MCU_NRF52
portENTER_CRITICAL();
#endif
uint8_t status = LoRa->modemStatus();
bool carrier_detected = LoRa->dcd();
current_rssi = LoRa->currentRssi();
last_status_update = millis();
@ -1135,52 +1282,28 @@ void updateModemStatus() {
portEXIT_CRITICAL();
#endif
if ((status & SIG_DETECT) == SIG_DETECT) { stat_signal_detected = true; } else { stat_signal_detected = false; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { stat_signal_synced = true; } else { stat_signal_synced = false; }
if ((status & RX_ONGOING) == RX_ONGOING) { stat_rx_ongoing = true; } else { stat_rx_ongoing = false; }
interference_detected = !carrier_detected && (current_rssi > (noise_floor+CSMA_INFR_THRESHOLD_DB));
if (interference_detected) { if (led_id_filter < LED_ID_TRIG) { led_id_filter += 1; } }
else { if (led_id_filter > 0) {led_id_filter -= 1; } }
// if (stat_signal_detected || stat_signal_synced || stat_rx_ongoing) {
if (stat_signal_detected || stat_signal_synced) {
if (stat_rx_ongoing) {
if (dcd_count < dcd_threshold) {
dcd_count++;
} else {
last_dcd = last_status_update;
dcd_led = true;
dcd = true;
}
}
} else {
#define DCD_LED_STEP_D 3
if (dcd_count == 0) {
dcd_led = false;
} else if (dcd_count > DCD_LED_STEP_D) {
dcd_count -= DCD_LED_STEP_D;
if (carrier_detected) { dcd = true; } else { dcd = false; }
dcd_led = dcd;
if (dcd_led) { led_rx_on(); }
else {
if (interference_detected) {
if (led_id_filter >= LED_ID_TRIG && noise_floor_sampled) { led_id_on(); }
} else {
dcd_count = 0;
}
if (last_status_update > last_dcd+csma_slot_ms) {
dcd = false;
dcd_led = false;
dcd_count = 0;
}
}
if (dcd_led) {
led_rx_on();
} else {
if (airtime_lock) {
led_indicate_airtime_lock();
} else {
led_rx_off();
if (airtime_lock) { led_indicate_airtime_lock(); }
else { led_rx_off(); led_id_off(); }
}
}
}
void checkModemStatus() {
void check_modem_status() {
if (millis()-last_status_update >= status_interval_ms) {
updateModemStatus();
update_modem_status();
update_noise_floor();
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
util_samples[dcd_sample] = dcd;
@ -1335,14 +1458,58 @@ void validate_status() {
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#define _e 2.71828183
#define _S 12.5
float csma_slope(float u) { return (pow(_e,_S*u-_S/2.0))/(pow(_e,_S*u-_S/2.0)+1.0); }
void update_csma_p() {
csma_p = (uint8_t)((1.0-(csma_p_min+(csma_p_max-csma_p_min)*csma_slope(airtime+csma_b_speed)))*255.0);
void update_csma_parameters() {
int airtime_pct = (int)(airtime*100);
int new_cw_band = cw_band;
if (airtime_pct <= CSMA_BAND_1_MAX_AIRTIME) { new_cw_band = 1; }
else {
int at = airtime_pct + CSMA_BAND_1_MAX_AIRTIME;
new_cw_band = map(at, CSMA_BAND_1_MAX_AIRTIME, CSMA_BAND_N_MIN_AIRTIME, 2, CSMA_CW_BANDS);
}
if (new_cw_band > CSMA_CW_BANDS) { new_cw_band = CSMA_CW_BANDS; }
if (new_cw_band != cw_band) {
cw_band = (uint8_t)(new_cw_band);
cw_min = (cw_band-1) * CSMA_CW_PER_BAND_WINDOWS;
cw_max = (cw_band) * CSMA_CW_PER_BAND_WINDOWS - 1;
kiss_indicate_csma_stats();
}
}
#endif
void tx_queue_handler() {
if (!airtime_lock && queue_height > 0) {
if (csma_cw == -1) {
csma_cw = random(cw_min, cw_max);
cw_wait_target = csma_cw * csma_slot_ms;
}
if (difs_wait_start == -1) { // DIFS wait not yet started
if (medium_free()) { difs_wait_start = millis(); return; } // Set DIFS wait start time
else { return; } } // Medium not yet free, continue waiting
else { // We are waiting for DIFS or CW to pass
if (!medium_free()) { difs_wait_start = -1; cw_wait_start = -1; return; } // Medium became occupied while in DIFS wait, restart waiting when free again
else { // Medium is free, so continue waiting
if (millis() < difs_wait_start+difs_ms) { return; } // DIFS has not yet passed, continue waiting
else { // DIFS has passed, and we are now in CW wait
if (cw_wait_start == -1) { cw_wait_start = millis(); return; } // If we haven't started counting CW wait time, do it from now
else { // If we are already counting CW wait time, add it to the counter
cw_wait_passed += millis()-cw_wait_start; cw_wait_start = millis();
if (cw_wait_passed < cw_wait_target) { return; } // Contention window wait time has not yet passed, continue waiting
else { // Wait time has passed, flush the queue
if (!lora_limit_rate) { flush_queue(); } else { pop_queue(); }
cw_wait_passed = 0; csma_cw = -1; difs_wait_start = -1; }
}
}
}
}
}
}
void work_while_waiting() { loop(); }
void loop() {
if (radio_online) {
#if MCU_VARIANT == MCU_ESP32
@ -1387,49 +1554,8 @@ void loop() {
#endif
checkModemStatus();
if (!airtime_lock) {
if (queue_height > 0) {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
long check_time = millis();
if (check_time > post_tx_yield_timeout) {
if (dcd_waiting && (check_time >= dcd_wait_until)) { dcd_waiting = false; }
if (!dcd_waiting) {
for (uint8_t dcd_i = 0; dcd_i < dcd_threshold*2; dcd_i++) {
delay(STATUS_INTERVAL_MS); updateModemStatus();
}
if (!dcd) {
uint8_t csma_r = (uint8_t)random(256);
if (csma_p >= csma_r) {
flushQueue();
} else {
dcd_waiting = true;
dcd_wait_until = millis()+csma_slot_ms;
}
}
}
}
#else
if (!dcd_waiting) updateModemStatus();
if (!dcd && !dcd_led) {
if (dcd_waiting) delay(lora_rx_turnaround_ms);
updateModemStatus();
if (!dcd) {
dcd_waiting = false;
flushQueue();
}
} else {
dcd_waiting = true;
}
#endif
}
}
tx_queue_handler();
check_modem_status();
} else {
if (hw_ready) {
@ -1455,7 +1581,7 @@ void loop() {
#endif
#if HAS_DISPLAY
if (disp_ready) update_display();
if (disp_ready && !display_updating) update_display();
#endif
#if HAS_PMU
@ -1485,22 +1611,40 @@ void loop() {
void sleep_now() {
#if HAS_SLEEP == true
#if BOARD_MODEL == BOARD_RNODE_NG_22
display_intensity = 0;
update_display(true);
#endif
#if PIN_DISP_SLEEP >= 0
pinMode(PIN_DISP_SLEEP, OUTPUT);
digitalWrite(PIN_DISP_SLEEP, DISP_SLEEP_LEVEL);
#endif
#if HAS_BLUETOOTH
if (bt_state == BT_STATE_CONNECTED) {
bt_stop();
#if PLATFORM == PLATFORM_ESP32
#if BOARD_MODEL == BOARD_T3S3
display_intensity = 0;
update_display(true);
#endif
#if PIN_DISP_SLEEP >= 0
pinMode(PIN_DISP_SLEEP, OUTPUT);
digitalWrite(PIN_DISP_SLEEP, DISP_SLEEP_LEVEL);
#endif
#if HAS_BLUETOOTH
if (bt_state == BT_STATE_CONNECTED) {
bt_stop();
delay(100);
}
#endif
esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL);
esp_deep_sleep_start();
#elif PLATFORM == PLATFORM_NRF52
#if BOARD_MODEL == BOARD_HELTEC_T114
npset(0,0,0);
digitalWrite(PIN_VEXT_EN, LOW);
digitalWrite(PIN_T114_TFT_BLGT, HIGH);
digitalWrite(PIN_T114_TFT_EN, HIGH);
#elif BOARD_MODEL == BOARD_TECHO
for (uint8_t i = display_intensity; i > 0; i--) { analogWrite(pin_backlight, i-1); delay(1); }
epd_black(true); delay(300); epd_black(true); delay(300); epd_black(false);
delay(2000);
analogWrite(PIN_VEXT_EN, 0);
delay(100);
}
#endif
sd_power_gpregret_set(0, 0x6d);
nrf_gpio_cfg_sense_input(pin_btn_usr1, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
NRF_POWER->SYSTEMOFF = 1;
#endif
esp_sleep_enable_ext0_wakeup(PIN_WAKEUP, WAKEUP_LEVEL);
esp_deep_sleep_start();
#endif
}
@ -1552,7 +1696,7 @@ void serial_poll() {
while (!fifo_isempty(&serialFIFO)) {
#endif
char sbyte = fifo_pop(&serialFIFO);
serialCallback(sbyte);
serial_callback(sbyte);
}
serial_polling = false;
@ -1614,7 +1758,6 @@ void serial_interrupt_init() {
// Buffer incoming frames every 1ms
ICR3 = 16000;
TIMSK3 = _BV(ICIE3);
#elif MCU_VARIANT == MCU_2560
@ -1628,7 +1771,6 @@ void serial_interrupt_init() {
// Buffer incoming frames every 1ms
ICR3 = 16000;
TIMSK3 = _BV(ICIE3);
#elif MCU_VARIANT == MCU_ESP32
@ -1638,7 +1780,5 @@ void serial_interrupt_init() {
}
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
ISR(TIMER3_CAPT_vect) {
buffer_serial();
}
ISR(TIMER3_CAPT_vect) { buffer_serial(); }
#endif

4
ROM.h
View File

@ -23,7 +23,7 @@
#define ADDR_HW_REV 0x02
#define ADDR_SERIAL 0x03
#define ADDR_MADE 0x07
#define ADDR_CHKSUM 0x0B
#define ADDR_CHKSUM 0x0B
#define ADDR_SIGNATURE 0x1B
#define ADDR_INFO_LOCK 0x9B
@ -39,9 +39,11 @@
#define ADDR_CONF_DINT 0xB2
#define ADDR_CONF_DADR 0xB3
#define ADDR_CONF_DBLK 0xB4
#define ADDR_CONF_DROT 0xB8
#define ADDR_CONF_PSET 0xB5
#define ADDR_CONF_PINT 0xB6
#define ADDR_CONF_BSET 0xB7
#define ADDR_CONF_DIA 0xB9
#define INFO_LOCK_BYTE 0x73
#define CONF_OK_BYTE 0x73

Binary file not shown.

440
ST7789.h Normal file
View File

@ -0,0 +1,440 @@
/**
* The MIT License (MIT)
*
* Copyright (c) 2018 by ThingPulse, Daniel Eichhorn
* Copyright (c) 2018 by Fabrice Weinberg
* Copyright (c) 2024 by Heltec AutoMation
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* ThingPulse invests considerable time and money to develop these open source libraries.
* Please support us by buying our products (and not the clones) from
* https://thingpulse.com
*
*/
#ifndef ST7789Spi_h
#define ST7789Spi_h
#include "OLEDDisplay.h"
#include <SPI.h>
#define ST_CMD_DELAY 0x80 // special signifier for command lists
#define ST77XX_NOP 0x00
#define ST77XX_SWRESET 0x01
#define ST77XX_RDDID 0x04
#define ST77XX_RDDST 0x09
#define ST77XX_SLPIN 0x10
#define ST77XX_SLPOUT 0x11
#define ST77XX_PTLON 0x12
#define ST77XX_NORON 0x13
#define ST77XX_INVOFF 0x20
#define ST77XX_INVON 0x21
#define ST77XX_DISPOFF 0x28
#define ST77XX_DISPON 0x29
#define ST77XX_CASET 0x2A
#define ST77XX_RASET 0x2B
#define ST77XX_RAMWR 0x2C
#define ST77XX_RAMRD 0x2E
#define ST77XX_PTLAR 0x30
#define ST77XX_TEOFF 0x34
#define ST77XX_TEON 0x35
#define ST77XX_MADCTL 0x36
#define ST77XX_COLMOD 0x3A
#define ST77XX_MADCTL_MY 0x80
#define ST77XX_MADCTL_MX 0x40
#define ST77XX_MADCTL_MV 0x20
#define ST77XX_MADCTL_ML 0x10
#define ST77XX_MADCTL_RGB 0x00
#define ST77XX_RDID1 0xDA
#define ST77XX_RDID2 0xDB
#define ST77XX_RDID3 0xDC
#define ST77XX_RDID4 0xDD
// Some ready-made 16-bit ('565') color settings:
#define ST77XX_BLACK 0x0000
#define ST77XX_WHITE 0xFFFF
#define ST77XX_RED 0xF800
#define ST77XX_GREEN 0x07E0
#define ST77XX_BLUE 0x001F
#define ST77XX_CYAN 0x07FF
#define ST77XX_MAGENTA 0xF81F
#define ST77XX_YELLOW 0xFFE0
#define ST77XX_ORANGE 0xFC00
#define LED_A_ON LOW
#ifdef ESP_PLATFORM
#undef LED_A_ON
#define LED_A_ON HIGH
#define rtos_free free
#define rtos_malloc malloc
//SPIClass SPI1(HSPI);
#endif
class ST7789Spi : public OLEDDisplay {
private:
uint8_t _rst;
uint8_t _dc;
uint8_t _cs;
uint8_t _ledA;
int _miso;
int _mosi;
int _clk;
SPIClass * _spi;
SPISettings _spiSettings;
uint16_t _RGB=0xFFFF;
uint8_t _buffheight;
public:
/* pass _cs as -1 to indicate "do not use CS pin", for cases where it is hard wired low */
ST7789Spi(SPIClass *spiClass,uint8_t _rst, uint8_t _dc, uint8_t _cs, OLEDDISPLAY_GEOMETRY g = GEOMETRY_RAWMODE,uint16_t width=240,uint16_t height=320,int mosi=-1,int miso=-1,int clk=-1) {
this->_spi = spiClass;
this->_rst = _rst;
this->_dc = _dc;
this->_cs = _cs;
this->_mosi=mosi;
this->_miso=miso;
this->_clk=clk;
//this->_ledA = _ledA;
_spiSettings = SPISettings(40000000, MSBFIRST, SPI_MODE0);
setGeometry(g,width,height);
}
bool connect(){
this->_buffheight=displayHeight / 8;
this->_buffheight+=displayHeight % 8 ? 1:0;
pinMode(_cs, OUTPUT);
pinMode(_dc, OUTPUT);
//pinMode(_ledA, OUTPUT);
if (_cs != (uint8_t) -1) {
pinMode(_cs, OUTPUT);
}
pinMode(_rst, OUTPUT);
#ifdef ESP_PLATFORM
_spi->begin(_clk,_miso,_mosi,-1);
#else
_spi->begin();
#endif
_spi->setClockDivider (SPI_CLOCK_DIV2);
// Pulse Reset low for 10ms
digitalWrite(_rst, HIGH);
delay(1);
digitalWrite(_rst, LOW);
delay(10);
digitalWrite(_rst, HIGH);
_spi->begin ();
//digitalWrite(_ledA, LED_A_ON);
return true;
}
void display(void) {
#ifdef OLEDDISPLAY_DOUBLE_BUFFER
uint16_t minBoundY = UINT16_MAX;
uint16_t maxBoundY = 0;
uint16_t minBoundX = UINT16_MAX;
uint16_t maxBoundX = 0;
uint16_t x, y;
// Calculate the Y bounding box of changes
// and copy buffer[pos] to buffer_back[pos];
for (y = 0; y < _buffheight; y++) {
for (x = 0; x < displayWidth; x++) {
//Serial.printf("x %d y %d\r\n",x,y);
uint16_t pos = x + y * displayWidth;
if (buffer[pos] != buffer_back[pos]) {
minBoundY = min(minBoundY, y);
maxBoundY = max(maxBoundY, y);
minBoundX = min(minBoundX, x);
maxBoundX = max(maxBoundX, x);
}
buffer_back[pos] = buffer[pos];
}
yield();
}
// If the minBoundY wasn't updated
// we can savely assume that buffer_back[pos] == buffer[pos]
// holdes true for all values of pos
if (minBoundY == UINT16_MAX) return;
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
for (y = minBoundY; y <= maxBoundY; y++)
{
for(int temp = 0; temp<8;temp++)
{
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
//setAddrWindow(y*8+temp,minBoundX,1,maxBoundX-minBoundX+1);
uint32_t const pixbufcount = maxBoundX-minBoundX+1;
uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
for (x = minBoundX; x <= maxBoundX; x++)
{
pixbuf[x-minBoundX] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
}
#ifdef ESP_PLATFORM
_spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
#else
_spi->transfer(pixbuf, NULL, 2 * pixbufcount);
#endif
rtos_free(pixbuf);
}
}
_spi->endTransaction();
set_CS(HIGH);
#else
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
uint8_t x, y;
for (y = 0; y < _buffheight; y++)
{
for(int temp = 0; temp<8;temp++)
{
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
//setAddrWindow(minBoundX,y*8+temp,maxBoundX-minBoundX+1,1);
setAddrWindow(y*8+temp,0,1,displayWidth);
uint32_t const pixbufcount = displayWidth;
uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount);
for (x = 0; x < displayWidth; x++)
{
pixbuf[x] = ((buffer[x + y * displayWidth]>>temp)&0x01)==1?_RGB:0;
}
#ifdef ESP_PLATFORM
_spi->transferBytes((uint8_t *)pixbuf, NULL, 2 * pixbufcount);
#else
_spi->transfer(pixbuf, NULL, 2 * pixbufcount);
#endif
rtos_free(pixbuf);
}
}
_spi->endTransaction();
set_CS(HIGH);
#endif
}
virtual void resetOrientation() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void flipScreenVertically() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void mirrorScreen() {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX|ST77XX_MADCTL_MY;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
virtual void setRotation(uint8_t r) {
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
if (r == 1) { madctl = 0xC0; }
if (r == 2) { madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MY; }
if (r == 3) { madctl = 0x00; }
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
}
void setRGB(uint16_t c)
{
this->_RGB=0x00|c>>8|c<<8&0xFF00;
}
void displayOn(void) {
//sendCommand(DISPLAYON);
}
void displayOff(void) {
//sendCommand(DISPLAYOFF);
}
//#define ST77XX_MADCTL_MY 0x80
//#define ST77XX_MADCTL_MX 0x40
//#define ST77XX_MADCTL_MV 0x20
//#define ST77XX_MADCTL_ML 0x10
protected:
// Send all the init commands
virtual void sendInitCommands()
{
sendCommand(ST77XX_SWRESET); // 1: Software reset, no args, w/delay
delay(150);
sendCommand(ST77XX_SLPOUT); // 2: Out of sleep mode, no args, w/delay
delay(10);
sendCommand(ST77XX_COLMOD); // 3: Set color mode, 16-bit color
WriteData(0x55);
delay(10);
sendCommand(ST77XX_MADCTL); // 4: Mem access ctrl (directions), Row/col addr, bottom-top refresh
WriteData(0x08);
sendCommand(ST77XX_CASET); // 5: Column addr set,
WriteData(0x00);
WriteData(0x00); // XSTART = 0
WriteData(0x00);
WriteData(240); // XEND = 240
sendCommand(ST77XX_RASET); // 6: Row addr set,
WriteData(0x00);
WriteData(0x00); // YSTART = 0
WriteData(320>>8);
WriteData(320&0xFF); // YSTART = 320
sendCommand(ST77XX_SLPOUT); // 7: hack
delay(10);
sendCommand(ST77XX_NORON); // 8: Normal display on, no args, w/delay
delay(10);
sendCommand(ST77XX_DISPON); // 9: Main screen turn on, no args, delay
delay(10);
sendCommand(ST77XX_INVON); // 10: invert
delay(10);
//uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MX;
uint8_t madctl = ST77XX_MADCTL_RGB|ST77XX_MADCTL_MV|ST77XX_MADCTL_MX;
sendCommand(ST77XX_MADCTL);
WriteData(madctl);
delay(10);
setRGB(ST77XX_GREEN);
}
private:
void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
x += (320-displayWidth)/2;
y += (240-displayHeight)/2;
uint32_t xa = ((uint32_t)x << 16) | (x + w - 1);
uint32_t ya = ((uint32_t)y << 16) | (y + h - 1);
writeCommand(ST77XX_CASET); // Column addr set
SPI_WRITE32(xa);
writeCommand(ST77XX_RASET); // Row addr set
SPI_WRITE32(ya);
writeCommand(ST77XX_RAMWR); // write to RAM
}
int getBufferOffset(void) {
return 0;
}
inline void set_CS(bool level) {
if (_cs != (uint8_t) -1) {
digitalWrite(_cs, level);
}
};
inline void sendCommand(uint8_t com) __attribute__((always_inline)){
set_CS(HIGH);
digitalWrite(_dc, LOW);
set_CS(LOW);
_spi->beginTransaction(_spiSettings);
_spi->transfer(com);
_spi->endTransaction();
set_CS(HIGH);
digitalWrite(_dc, HIGH);
}
inline void WriteData(uint8_t data) __attribute__((always_inline)){
digitalWrite(_cs, LOW);
_spi->beginTransaction(_spiSettings);
_spi->transfer(data);
_spi->endTransaction();
digitalWrite(_cs, HIGH);
}
void SPI_WRITE32(uint32_t l)
{
_spi->transfer(l >> 24);
_spi->transfer(l >> 16);
_spi->transfer(l >> 8);
_spi->transfer(l);
}
void writeCommand(uint8_t cmd) {
digitalWrite(_dc, LOW);
_spi->transfer(cmd);
digitalWrite(_dc, HIGH);
}
// Private functions
void setGeometry(OLEDDISPLAY_GEOMETRY g, uint16_t width, uint16_t height) {
this->geometry = g;
switch (g) {
case GEOMETRY_128_128:
this->displayWidth = 128;
this->displayHeight = 128;
break;
case GEOMETRY_128_64:
this->displayWidth = 128;
this->displayHeight = 64;
break;
case GEOMETRY_128_32:
this->displayWidth = 128;
this->displayHeight = 32;
break;
case GEOMETRY_64_48:
this->displayWidth = 64;
this->displayHeight = 48;
break;
case GEOMETRY_64_32:
this->displayWidth = 64;
this->displayHeight = 32;
break;
case GEOMETRY_RAWMODE:
this->displayWidth = width > 0 ? width : 128;
this->displayHeight = height > 0 ? height : 64;
break;
}
uint8_t tmp=displayHeight % 8;
uint8_t _buffheight=displayHeight / 8;
if(tmp!=0)
_buffheight++;
this->displayBufferSize = displayWidth * _buffheight ;
}
};
#endif

View File

@ -15,7 +15,7 @@
#include "Config.h"
#if HAS_EEPROM
#if HAS_EEPROM
#include <EEPROM.h>
#elif PLATFORM == PLATFORM_NRF52
#include <Adafruit_LittleFS.h>
@ -74,7 +74,7 @@ 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_RNODE_NG_22
#elif BOARD_MODEL == BOARD_T3S3
#include "hal/wdt_hal.h"
#else
#include "hal/wdt_hal.h"
@ -106,7 +106,6 @@ uint8_t boot_vector = 0x00;
#if HAS_NP == true
#include <Adafruit_NeoPixel.h>
#define NUMPIXELS 1
#define NP_M 0.15
Adafruit_NeoPixel pixels(NUMPIXELS, pin_np, NEO_GRB + NEO_KHZ800);
uint8_t npr = 0;
@ -120,10 +119,23 @@ uint8_t boot_vector = 0x00;
}
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);
}
#if BOARD_MODEL == BOARD_HELTEC_T114
// Enable vext power supply to neopixel
pinMode(PIN_VEXT_EN, OUTPUT);
digitalWrite(PIN_VEXT_EN, HIGH);
#endif
#if MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) {
uint8_t int_val = eeprom_read(eeprom_addr(ADDR_CONF_PINT));
led_set_intensity(int_val);
}
#else
if (EEPROM.read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) {
uint8_t int_val = EEPROM.read(eeprom_addr(ADDR_CONF_PINT));
led_set_intensity(int_val);
}
#endif
}
void npset(uint8_t r, uint8_t g, uint8_t b) {
@ -159,53 +171,73 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif MCU_VARIANT == MCU_ESP32
#if HAS_NP == true
void led_rx_on() { npset(0, 0, 0xFF); }
void led_rx_off() { npset(0, 0, 0); }
void led_tx_on() { npset(0xFF, 0x50, 0x00); }
void led_tx_off() { npset(0, 0, 0); }
void led_id_on() { npset(0x90, 0, 0x70); }
void led_id_off() { npset(0, 0, 0); }
#elif BOARD_MODEL == BOARD_RNODE_NG_20
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_RNODE_NG_21
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#elif BOARD_MODEL == BOARD_RNODE_NG_22
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_T3S3
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TBEAM
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TDECK
void led_rx_on() { }
void led_rx_off() { }
void led_tx_on() { }
void led_tx_off() { }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
void led_rx_on() { }
void led_rx_off() { }
void led_tx_on() { }
void led_tx_off() { }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_LORA32_V1_0
#if defined(EXTERNAL_LEDS)
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#else
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#endif
#elif BOARD_MODEL == BOARD_LORA32_V2_0
#if defined(EXTERNAL_LEDS)
@ -213,11 +245,15 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#else
void led_rx_on() { digitalWrite(pin_led_rx, LOW); }
void led_rx_off() { digitalWrite(pin_led_rx, HIGH); }
void led_tx_on() { digitalWrite(pin_led_tx, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#endif
#elif BOARD_MODEL == BOARD_HELTEC32_V2
#if defined(EXTERNAL_LEDS)
@ -225,40 +261,76 @@ uint8_t boot_vector = 0x00;
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#else
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#endif
#elif BOARD_MODEL == BOARD_HELTEC32_V3
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_LORA32_V2_1
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_HUZZAH32
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
void led_id_on() { }
void led_id_off() { }
#endif
#elif MCU_VARIANT == MCU_NRF52
#if BOARD_MODEL == BOARD_RAK4631
#if HAS_NP == true
void led_rx_on() { npset(0, 0, 0xFF); }
void led_rx_off() { npset(0, 0, 0); }
void led_tx_on() { npset(0xFF, 0x50, 0x00); }
void led_tx_off() { npset(0, 0, 0); }
void led_id_on() { npset(0x90, 0, 0x70); }
void led_id_off() { npset(0, 0, 0); }
#elif BOARD_MODEL == BOARD_RAK4631
void led_rx_on() { digitalWrite(pin_led_rx, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
void led_tx_on() { digitalWrite(pin_led_tx, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#endif
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_HELTEC_T114
// Heltec T114 pulls pins LOW to turn on
void led_rx_on() { digitalWrite(pin_led_rx, LOW); }
void led_rx_off() { digitalWrite(pin_led_rx, HIGH); }
void led_tx_on() { digitalWrite(pin_led_tx, LOW); }
void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
void led_id_on() { }
void led_id_off() { }
#elif BOARD_MODEL == BOARD_TECHO
void led_rx_on() { digitalWrite(pin_led_rx, LED_ON); }
void led_rx_off() { digitalWrite(pin_led_rx, LED_OFF); }
void led_tx_on() { digitalWrite(pin_led_tx, LED_ON); }
void led_tx_off() { digitalWrite(pin_led_tx, LED_OFF); }
void led_id_on() { }
void led_id_off() { }
#endif
#endif
void hard_reset(void) {
@ -411,6 +483,19 @@ void led_indicate_warning(int cycles) {
}
led_rx_off();
}
#elif BOARD_MODEL == BOARD_TECHO
void led_indicate_info(int cycles) {
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
led_rx_off();
delay(100);
led_rx_on();
delay(100);
if (!forever) cycles--;
}
led_rx_off();
}
#else
void led_indicate_info(int cycles) {
bool forever = (cycles == 0) ? true : false;
@ -463,6 +548,8 @@ unsigned long led_standby_ticks = 0;
#endif
#elif MCU_VARIANT == MCU_NRF52
int led_standby_lng = 200;
int led_standby_cut = 100;
uint8_t led_standby_min = 200;
uint8_t led_standby_max = 255;
uint8_t led_notready_min = 0;
@ -562,9 +649,17 @@ int8_t led_standby_direction = 0;
}
led_standby_value += led_standby_direction;
if (led_standby_value > 253) {
led_tx_on();
#if BOARD_MODEL == BOARD_TECHO
led_rx_on();
#else
led_tx_on();
#endif
} else {
led_tx_off();
#if BOARD_MODEL == BOARD_TECHO
led_rx_off();
#else
led_tx_off();
#endif
}
#if BOARD_MODEL == BOARD_LORA32_V2_1
#if defined(EXTERNAL_LEDS)
@ -671,13 +766,8 @@ void serial_write(uint8_t 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;
}
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
@ -733,7 +823,7 @@ void kiss_indicate_stat_tx() {
}
void kiss_indicate_stat_rssi() {
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
serial_write(FEND);
serial_write(CMD_STAT_RSSI);
escaped_serial_write(packet_rssi_val);
@ -821,11 +911,14 @@ void kiss_indicate_lt_alock() {
}
void kiss_indicate_channel_stats() {
#if MCU_VARIANT == MCU_ESP32
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
uint16_t ats = (uint16_t)(airtime*100*100);
uint16_t atl = (uint16_t)(longterm_airtime*100*100);
uint16_t cls = (uint16_t)(total_channel_util*100*100);
uint16_t cll = (uint16_t)(longterm_channel_util*100*100);
uint8_t crs = (uint8_t)(current_rssi+rssi_offset);
uint8_t nfl = (uint8_t)(noise_floor+rssi_offset);
uint8_t ntf = 0xFF; if (interference_detected) { ntf = (uint8_t)(current_rssi+rssi_offset); }
serial_write(FEND);
serial_write(CMD_STAT_CHTM);
escaped_serial_write(ats>>8);
@ -836,35 +929,46 @@ void kiss_indicate_channel_stats() {
escaped_serial_write(cls);
escaped_serial_write(cll>>8);
escaped_serial_write(cll);
escaped_serial_write(crs);
escaped_serial_write(nfl);
escaped_serial_write(ntf);
serial_write(FEND);
#endif
}
void kiss_indicate_csma_stats() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
serial_write(FEND);
serial_write(CMD_STAT_CSMA);
escaped_serial_write(cw_band);
escaped_serial_write(cw_min);
escaped_serial_write(cw_max);
serial_write(FEND);
#endif
}
void kiss_indicate_phy_stats() {
#if MCU_VARIANT == MCU_ESP32
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000);
uint16_t lsr = (uint16_t)(lora_symbol_rate);
uint16_t prs = (uint16_t)(lora_preamble_symbols+4);
uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms);
uint16_t prs = (uint16_t)(lora_preamble_symbols);
uint16_t prt = (uint16_t)(lora_preamble_time_ms);
uint16_t cst = (uint16_t)(csma_slot_ms);
uint16_t dft = (uint16_t)(difs_ms);
serial_write(FEND);
serial_write(CMD_STAT_PHYPRM);
escaped_serial_write(lst>>8);
escaped_serial_write(lst);
escaped_serial_write(lsr>>8);
escaped_serial_write(lsr);
escaped_serial_write(prs>>8);
escaped_serial_write(prs);
escaped_serial_write(prt>>8);
escaped_serial_write(prt);
escaped_serial_write(cst>>8);
escaped_serial_write(cst);
escaped_serial_write(lst>>8); escaped_serial_write(lst);
escaped_serial_write(lsr>>8); escaped_serial_write(lsr);
escaped_serial_write(prs>>8); escaped_serial_write(prs);
escaped_serial_write(prt>>8); escaped_serial_write(prt);
escaped_serial_write(cst>>8); escaped_serial_write(cst);
escaped_serial_write(dft>>8); escaped_serial_write(dft);
serial_write(FEND);
#endif
}
void kiss_indicate_battery() {
#if MCU_VARIANT == MCU_ESP32
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
serial_write(FEND);
serial_write(CMD_STAT_BAT);
escaped_serial_write(battery_state);
@ -977,6 +1081,20 @@ void kiss_indicate_fb() {
serial_write(FEND);
}
void kiss_indicate_disp() {
serial_write(FEND);
serial_write(CMD_DISP_READ);
#if HAS_DISPLAY
uint8_t *da = disp_area.getBuffer();
uint8_t *sa = stat_area.getBuffer();
for (int i = 0; i < 512; i++) { escaped_serial_write(da[i]); }
for (int i = 0; i < 512; i++) { escaped_serial_write(sa[i]); }
#else
serial_write(0xFF);
#endif
serial_write(FEND);
}
void kiss_indicate_ready() {
serial_write(FEND);
serial_write(CMD_READY);
@ -1053,24 +1171,33 @@ void setPreamble() {
void updateBitrate() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (radio_online) {
if (!radio_online) { lora_bitrate = 0; }
else {
lora_symbol_rate = (float)lora_bw/(float)(pow(2, lora_sf));
lora_symbol_time_ms = (1.0/lora_symbol_rate)*1000.0;
lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0);
lora_us_per_byte = 1000000.0/((float)lora_bitrate/8.0);
csma_slot_ms = lora_symbol_time_ms*12;
bool fast_rate = lora_bitrate > LORA_FAST_THRESHOLD_BPS;
lora_limit_rate = lora_bitrate > LORA_LIMIT_THRESHOLD_BPS;
int csma_slot_min_ms = CSMA_SLOT_MIN_MS;
float lora_preamble_target_ms = LORA_PREAMBLE_TARGET_MS;
if (fast_rate) { csma_slot_min_ms -= CSMA_SLOT_MIN_FAST_DELTA;
lora_preamble_target_ms -= LORA_PREAMBLE_FAST_DELTA; }
csma_slot_ms = lora_symbol_time_ms*CSMA_SLOT_SYMBOLS;
if (csma_slot_ms > CSMA_SLOT_MAX_MS) { csma_slot_ms = CSMA_SLOT_MAX_MS; }
if (csma_slot_ms < CSMA_SLOT_MIN_MS) { csma_slot_ms = CSMA_SLOT_MIN_MS; }
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
lora_preamble_symbols = (long)target_preamble_symbols;
setPreamble();
} else {
lora_bitrate = 0;
if (csma_slot_ms < CSMA_SLOT_MIN_MS) { csma_slot_ms = csma_slot_min_ms; }
difs_ms = CSMA_SIFS_MS + 2*csma_slot_ms;
float target_preamble_symbols = lora_preamble_target_ms/lora_symbol_time_ms;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) { target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN; }
else { target_preamble_symbols = (ceil)(target_preamble_symbols); }
lora_preamble_symbols = (long)target_preamble_symbols; setPreamble();
lora_preamble_time_ms = (ceil)(lora_preamble_symbols * lora_symbol_time_ms);
lora_header_time_ms = (ceil)(PHY_HEADER_LORA_SYMBOLS * lora_symbol_time_ms);
}
#endif
}
@ -1104,6 +1231,9 @@ void setTXPower() {
if (model == MODEL_11) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_12) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C6) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_C7) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
@ -1114,7 +1244,10 @@ void setTXPower() {
if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_AC) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_BB) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
@ -1122,6 +1255,8 @@ void setTXPower() {
if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C5) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_CA) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_D9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
@ -1167,13 +1302,7 @@ void setFrequency() {
}
}
uint8_t getRandom() {
if (radio_online) {
return LoRa->random();
} else {
return 0x00;
}
}
uint8_t getRandom() { return random(0xFF); }
void promisc_enable() {
promisc = true;
@ -1184,35 +1313,32 @@ void promisc_disable() {
}
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
bool eeprom_begin() {
InternalFS.begin();
bool eeprom_begin() {
InternalFS.begin();
file.open(EEPROM_FILE, FILE_O_READ);
// if file doesn't exist
if (!file) {
if (file.open(EEPROM_FILE, FILE_O_WRITE)) {
// initialise the file with empty content
uint8_t empty_content[EEPROM_SIZE] = {0};
file.write(empty_content, EEPROM_SIZE);
return true;
} else {
return false;
}
} else {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
return true;
}
file.open(EEPROM_FILE, FILE_O_READ);
if (!file) {
if (file.open(EEPROM_FILE, FILE_O_WRITE)) {
for (uint32_t mapped_addr = 0; mapped_addr < EEPROM_SIZE; mapped_addr++) { file.seek(mapped_addr); file.write(0xFF); }
eeprom_flush();
return true;
} else {
return false;
}
} else {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
return true;
}
}
uint8_t eeprom_read(uint32_t mapped_addr) {
uint8_t byte;
void* byte_ptr = &byte;
file.seek(mapped_addr);
file.read(byte_ptr, 1);
return byte;
}
uint8_t eeprom_read(uint32_t mapped_addr) {
uint8_t byte;
void* byte_ptr = &byte;
file.seek(mapped_addr);
file.read(byte_ptr, 1);
return byte;
}
#endif
bool eeprom_info_locked() {
@ -1270,7 +1396,6 @@ void kiss_dump_eeprom() {
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
void eeprom_flush() {
// sync file contents to flash
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
@ -1297,19 +1422,7 @@ void eeprom_update(int mapped_addr, uint8_t byte) {
file.write(byte);
}
written_bytes++;
if ((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) {
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// have to do a flush because we're only writing 1 byte and it syncs after 4
eeprom_flush();
#endif
}
if (written_bytes >= 4) {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
}
eeprom_flush();
#endif
}
@ -1322,9 +1435,13 @@ void eeprom_write(uint8_t addr, uint8_t byte) {
}
void eeprom_erase() {
for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
eeprom_update(eeprom_addr(addr), 0xFF);
}
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
InternalFS.format();
#else
for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
eeprom_update(eeprom_addr(addr), 0xFF);
}
#endif
hard_reset();
}
@ -1352,7 +1469,7 @@ bool eeprom_product_valid() {
#elif PLATFORM == PLATFORM_ESP32
if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3 || rval == PRODUCT_TDECK_V1 || rval == PRODUCT_TBEAM_S_V1) {
#elif PLATFORM == PLATFORM_NRF52
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) {
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HELTEC_T114 || rval == PRODUCT_TECHO || rval == PRODUCT_HMBRW) {
#else
if (false) {
#endif
@ -1374,14 +1491,16 @@ 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_A6 || model == MODEL_A5 || model == MODEL_AA || model == MODEL_AC) {
#elif BOARD_MODEL == BOARD_HMBRW
if (model == MODEL_FF || model == MODEL_FE) {
#elif BOARD_MODEL == BOARD_TBEAM
if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) {
#elif BOARD_MODEL == BOARD_TDECK
if (model == MODEL_D4 || model == MODEL_D9) {
#elif BOARD_MODEL == BOARD_TECHO
if (model == MODEL_16 || model == MODEL_17) {
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
if (model == MODEL_DB || model == MODEL_DC) {
#elif BOARD_MODEL == BOARD_LORA32_V1_0
@ -1394,6 +1513,8 @@ bool eeprom_model_valid() {
if (model == MODEL_C4 || model == MODEL_C9) {
#elif BOARD_MODEL == BOARD_HELTEC32_V3
if (model == MODEL_C5 || model == MODEL_CA) {
#elif BOARD_MODEL == BOARD_HELTEC_T114
if (model == MODEL_C6 || model == MODEL_C7) {
#elif BOARD_MODEL == BOARD_RAK4631
if (model == MODEL_11 || model == MODEL_12) {
#elif BOARD_MODEL == BOARD_HUZZAH32
@ -1489,6 +1610,21 @@ void db_conf_save(uint8_t val) {
#endif
}
void drot_conf_save(uint8_t val) {
#if HAS_DISPLAY
if (val >= 0x00 and val <= 0x03) {
eeprom_update(eeprom_addr(ADDR_CONF_DROT), val);
hard_reset();
}
#endif
}
void dia_conf_save(uint8_t val) {
if (val > 0x00) { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x01); }
else { eeprom_update(eeprom_addr(ADDR_CONF_DIA), 0x00); }
hard_reset();
}
void np_int_conf_save(uint8_t p_int) {
eeprom_update(eeprom_addr(ADDR_CONF_PSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_PINT), p_int);

View File

@ -2,4 +2,6 @@ board_manager:
additional_urls:
- https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- https://raw.githubusercontent.com/RAKwireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless_index.json
- https://github.com/HelTecAutomation/Heltec_nRF52/releases/download/1.7.0/package_heltec_nrf_index.json
- https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
- http://unsigned.io/arduino/package_unsignedio_UnsignedBoards_index.json

View File

@ -20,6 +20,7 @@ import sys
import RNS
import json
import hashlib
import subprocess
major_version = None
minor_version = None
@ -27,9 +28,23 @@ target_version = None
target_file = os.path.join(sys.argv[1])
firmware_data = open(target_file, "rb").read()
calc_hash = hashlib.sha256(firmware_data[0:-32]).digest()
part_hash = firmware_data[-32:]
if sys.argv[1] == "from_device":
from_device = True
else:
from_device = False
if calc_hash == part_hash:
print(RNS.hexrep(part_hash, delimit=False))
if not from_device:
firmware_data = open(target_file, "rb").read()
calc_hash = hashlib.sha256(firmware_data[0:-32]).digest()
part_hash = firmware_data[-32:]
if calc_hash == part_hash:
print(RNS.hexrep(part_hash, delimit=False))
else:
try:
cmdresult = subprocess.run(["rnodeconf", sys.argv[2], "-L"], stdout=subprocess.PIPE).stdout.decode('utf-8')
part_hash = cmdresult.split("The actual firmware hash is: ")[1].replace("\n", "")
print(part_hash)
except Exception as e:
print("Could not get partition hash from device: "+str(e))

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved.
// Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX126X_H
#define SX126X_H
@ -69,9 +66,9 @@ public:
long getSignalBandwidth();
void setSignalBandwidth(long sbw);
void setCodingRate4(int denominator);
void setPreambleLength(long length);
void setPreambleLength(long preamble_symbols);
void setSyncWord(uint16_t sw);
uint8_t modemStatus();
bool dcd();
void enableCrc();
void disableCrc();
void enableTCXO();
@ -84,7 +81,7 @@ public:
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
void writeBuffer(const uint8_t* buffer, size_t size);
void readBuffer(uint8_t* buffer, size_t size);
void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
void setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved.
// Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#include "Boards.h"
#if MODEM == SX1276
@ -81,10 +78,7 @@ extern SPIClass SPI;
sx127x::sx127x() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
_frequency(0),
_packetIndex(0),
_preinit_done(false),
_onReceive(NULL) { setTimeout(0); }
_frequency(0), _packetIndex(0), _preinit_done(false), _onReceive(NULL) { setTimeout(0); }
void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); }
void sx127x::setPins(int ss, int reset, int dio0, int busy) { _ss = ss; _reset = reset; _dio0 = dio0; _busy = busy; }
@ -92,7 +86,6 @@ uint8_t ISR_VECT sx127x::readRegister(uint8_t address) { return singleTransfer(a
void sx127x::writeRegister(uint8_t address, uint8_t value) { singleTransfer(address | 0x80, value); }
void sx127x::standby() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_STDBY_7X); }
void sx127x::sleep() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_SLEEP_7X); }
uint8_t sx127x::modemStatus() { return readRegister(REG_MODEM_STAT_7X); }
void sx127x::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD_7X, sw); }
void sx127x::enableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) | 0x04); }
void sx127x::disableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) & 0xfb); }
@ -107,7 +100,7 @@ bool sx127x::preInit() {
pinMode(_ss, OUTPUT);
digitalWrite(_ss, HIGH);
#if BOARD_MODEL == BOARD_RNODE_NG_22
#if BOARD_MODEL == BOARD_T3S3
SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs);
#else
SPI.begin();
@ -123,7 +116,6 @@ bool sx127x::preInit() {
}
if (version != 0x12) { return false; }
_preinit_done = true;
return true;
}
@ -144,8 +136,6 @@ uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) {
int sx127x::begin(long frequency) {
if (_reset != -1) {
pinMode(_reset, OUTPUT);
// Perform reset
digitalWrite(_reset, LOW);
delay(10);
digitalWrite(_reset, HIGH);
@ -153,19 +143,16 @@ int sx127x::begin(long frequency) {
}
if (_busy != -1) { pinMode(_busy, INPUT); }
if (!_preinit_done) {
if (!preInit()) { return false; }
}
if (!_preinit_done) { if (!preInit()) { return false; } }
sleep();
setFrequency(frequency);
// set base addresses
// Set base addresses
writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0);
writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0);
// set LNA boost and auto AGC
// Set LNA boost and auto AGC
writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03);
writeRegister(REG_MODEM_CONFIG_3_7X, 0x04);
@ -178,20 +165,13 @@ int sx127x::begin(long frequency) {
return 1;
}
void sx127x::end() {
sleep();
SPI.end();
_preinit_done = false;
}
void sx127x::end() { sleep(); SPI.end(); _preinit_done = false; }
int sx127x::beginPacket(int implicitHeader) {
standby();
if (implicitHeader) {
implicitHeaderMode();
} else {
explicitHeaderMode();
}
if (implicitHeader) { implicitHeaderMode(); }
else { explicitHeaderMode(); }
// Reset FIFO address and payload length
writeRegister(REG_FIFO_ADDR_PTR_7X, 0);
@ -214,6 +194,14 @@ int sx127x::endPacket() {
return 1;
}
bool sx127x::dcd() {
bool carrier_detected = false;
uint8_t status = readRegister(REG_MODEM_STAT_7X);
if ((status & SIG_DETECT) == SIG_DETECT) { carrier_detected = true; }
if ((status & SIG_SYNCED) == SIG_SYNCED) { carrier_detected = true; }
return carrier_detected;
}
uint8_t sx127x::currentRssiRaw() {
uint8_t rssi = readRegister(REG_RSSI_VALUE_7X);
return rssi;
@ -248,29 +236,24 @@ int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) {
}
int ISR_VECT sx127x::packetRssi() {
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET;
int pkt_snr = packetSnr();
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET;
int pkt_snr = packetSnr();
if (_frequency < 820E6) pkt_rssi -= 7;
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;
if (pkt_snr < 0) { pkt_rssi += pkt_snr; }
else {
// Slope correction is (16/15)*pkt_rssi,
// this estimation looses one floating point
// operation, and should be precise enough.
pkt_rssi = (int)(1.066 * pkt_rssi);
}
return pkt_rssi;
}
uint8_t ISR_VECT sx127x::packetSnrRaw() {
return readRegister(REG_PKT_SNR_VALUE_7X);
}
uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); }
float ISR_VECT sx127x::packetSnr() {
return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25;
}
float ISR_VECT sx127x::packetSnr() { return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; }
long sx127x::packetFrequencyError() {
int32_t freqError = 0;
@ -293,17 +276,13 @@ long sx127x::packetFrequencyError() {
size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); }
size_t sx127x::write(const uint8_t *buffer, size_t size) {
int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X);
if ((currentLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - currentLength;
}
int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X);
if ((currentLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; }
for (size_t i = 0; i < size; i++) {
writeRegister(REG_FIFO_7X, buffer[i]);
}
for (size_t i = 0; i < size; i++) { writeRegister(REG_FIFO_7X, buffer[i]); }
writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size);
writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size);
return size;
return size;
}
int ISR_VECT sx127x::available() { return (readRegister(REG_RX_NB_BYTES_7X) - _packetIndex); }
@ -468,19 +447,23 @@ void sx127x::setCodingRate4(int denominator) {
writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0xf1) | (cr << 1));
}
void sx127x::setPreambleLength(long length) {
void sx127x::setPreambleLength(long preamble_symbols) {
long length = preamble_symbols - 4;
writeRegister(REG_PREAMBLE_MSB_7X, (uint8_t)(length >> 8));
writeRegister(REG_PREAMBLE_LSB_7X, (uint8_t)(length >> 0));
}
extern bool lora_low_datarate;
void sx127x::handleLowDataRate() {
int sf = (readRegister(REG_MODEM_CONFIG_2_7X) >> 4);
if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) {
// Set auto AGC and LowDataRateOptimize
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2));
lora_low_datarate = true;
} else {
// Only set auto AGC
writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2));
lora_low_datarate = false;
}
}

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved.
// Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX1276_H
#define SX1276_H
@ -21,6 +18,11 @@
#define RSSI_OFFSET 157
// Modem status flags
#define SIG_DETECT 0x01
#define SIG_SYNCED 0x02
#define RX_ONGOING 0x04
class sx127x : public Stream {
public:
sx127x();
@ -66,9 +68,9 @@ public:
long getSignalBandwidth();
void setSignalBandwidth(long sbw);
void setCodingRate4(int denominator);
void setPreambleLength(long length);
void setPreambleLength(long preamble_symbols);
void setSyncWord(uint8_t sw);
uint8_t modemStatus();
bool dcd();
void enableCrc();
void disableCrc();
void enableTCXO();

1051
sx128x.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,6 @@
// Copyright (c) Sandeep Mistry. All rights reserved.
// Copyright Sandeep Mistry, Mark Qvist and Jacob Eva.
// Licensed under the MIT license.
// Modifications and additions copyright 2024 by Mark Qvist
// Obviously still under the MIT license.
#ifndef SX128X_H
#define SX128X_H
@ -11,17 +8,16 @@
#include <SPI.h>
#include "Modem.h"
#define LORA_DEFAULT_SS_PIN 10
#define LORA_DEFAULT_RESET_PIN 9
#define LORA_DEFAULT_DIO0_PIN 2
#define LORA_DEFAULT_SS_PIN 10
#define LORA_DEFAULT_RESET_PIN 9
#define LORA_DEFAULT_DIO0_PIN 2
#define LORA_DEFAULT_RXEN_PIN -1
#define LORA_DEFAULT_TXEN_PIN -1
#define LORA_DEFAULT_BUSY_PIN -1
#define PA_OUTPUT_RFO_PIN 0
#define PA_OUTPUT_PA_BOOST_PIN 1
#define RSSI_OFFSET 157
#define LORA_MODEM_TIMEOUT_MS 15E3
#define PA_OUTPUT_RFO_PIN 0
#define PA_OUTPUT_PA_BOOST_PIN 1
#define RSSI_OFFSET 157
class sx128x : public Stream {
public:
@ -29,6 +25,7 @@ public:
int begin(unsigned long frequency);
void end();
void reset();
int beginPacket(int implicitHeader = false);
int endPacket();
@ -56,21 +53,24 @@ public:
void onReceive(void(*callback)(int));
void receive(int size = 0);
void idle();
void standby();
void sleep();
bool preInit();
uint8_t getTxPower();
void setTxPower(int level, int outputPin = PA_OUTPUT_PA_BOOST_PIN);
uint32_t getFrequency();
void setFrequency(unsigned long frequency);
void setFrequency(uint32_t frequency);
void setSpreadingFactor(int sf);
long getSignalBandwidth();
void setSignalBandwidth(long sbw);
uint8_t getSpreadingFactor();
uint32_t getSignalBandwidth();
void setSignalBandwidth(uint32_t sbw);
void setCodingRate4(int denominator);
void setPreambleLength(long length);
uint8_t getCodingRate4();
void setPreambleLength(long preamble_symbols);
void setSyncWord(int sw);
uint8_t modemStatus();
bool dcd();
void clearIRQStatus();
void enableCrc();
void disableCrc();
void enableTCXO();
@ -84,15 +84,12 @@ public:
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
void writeBuffer(const uint8_t* buffer, size_t size);
void readBuffer(uint8_t* buffer, size_t size);
void setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t length, uint8_t crc);
void setPacketParams(uint32_t target_preamble_symbols, uint8_t headermode, uint8_t payload_length, uint8_t crc);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr);
// deprecated
void crc() { enableCrc(); }
void noCrc() { disableCrc(); }
byte random();
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN, int txen = LORA_DEFAULT_TXEN_PIN);
void setSPIFrequency(uint32_t frequency);
@ -102,6 +99,7 @@ private:
void explicitHeaderMode();
void implicitHeaderMode();
bool getPacketValidity();
void handleDio0Rise();
uint8_t readRegister(uint16_t address);
@ -136,8 +134,11 @@ private:
int _fifo_rx_addr_ptr;
uint8_t _packet[256];
bool _preinit_done;
bool _tcxo;
bool _radio_online;
int _rxPacketLength;
void (*_onReceive)(int);
uint32_t _bitrate;
void (*_receive_callback)(int);
};
extern sx128x sx128x_modem;