Compare commits

...

66 Commits

Author SHA1 Message Date
Scott Powell
97b6a1874a Merge branch 'dev' 2025-03-30 19:18:35 +11:00
ripplebiz
05fa1ba50e Merge pull request #145 from recrof/main
change new default freq to 869.525
2025-03-30 19:01:55 +11:00
Scott Powell
fc6aa0ed0f * ver bump to v1.4.2 2025-03-30 18:56:21 +11:00
Scott Powell
75eabd5c66 * minor refactor 2025-03-30 14:47:52 +11:00
ripplebiz
2e5b4eb910 Merge pull request #154 from recrof/dev
added new CommonCLI get commands: `get role` and `get public.key`
2025-03-30 14:40:49 +11:00
recrof
b77701ced0 added new CommonCLI get commands: get role and get public.key 2025-03-29 19:40:35 +01:00
Scott Powell
0d5c17f7ed * ESP-Now: long range mode 2025-03-29 13:27:17 +11:00
Scott Powell
022b43ef3d * isReceiving() now includes either preamble detect or header detect 2025-03-28 22:20:42 +11:00
Scott Powell
89bd6c3416 * Dispatcher: now impose a max time for CAD fail (ie. channel busy), defined by getCADFailMaxDuration(), default 4 seconds.
(an sx126x bug _might_ be making radio->isReceiving() return true indefinitely)
2025-03-28 20:50:42 +11:00
Scott Powell
ba93867037 * companion: temp fix: logRxRaw() is blowing the MAX_FRAME_SIZE 2025-03-28 14:14:59 +11:00
Scott Powell
c0cb57be5c * refactor: rtc_clock now defined by variants/*/target modules 2025-03-27 21:28:06 +11:00
Scott Powell
2224bddcb5 * new ESPNOWRadio driver
* refactored the examples/*/main.cpp modules, moving radio specifics to variants/*/target modules
* new Generic_ESPNOW_* target envs
2025-03-27 19:34:16 +11:00
Scott Powell
9c165add61 Merge branch 'dev' into esp-now 2025-03-27 17:24:56 +11:00
Scott Powell
d5cc28b0c5 * room server: now support "log start/stop..." 2025-03-27 13:00:40 +11:00
recrof
8a248bb47d change new default freq to 869.525 2025-03-26 18:06:20 +01:00
ripplebiz
32edc934fa Merge pull request #144 from adrian-immel/Fix-Typo
Fix build issue for FakeTec board
2025-03-26 16:22:01 +11:00
Adrian
7cab681697 Update FaketecBoard.cpp 2025-03-25 23:21:05 +01:00
Adrian
4d262e9e5d Rename faketecBoard.h to FaketecBoard.h 2025-03-25 23:16:08 +01:00
Adrian
ee230ab2ca Rename faketecBoard.cpp to FaketecBoard.cpp 2025-03-25 23:14:48 +01:00
Scott Powell
321a9425da * experiment: enabling forwarding in terminal chat 2025-03-26 03:57:36 +11:00
Scott Powell
88b88cbc90 * ver bump to 1.4.1 2025-03-25 22:02:37 +11:00
Scott Powell
753e6a69dc * flood_advert_interval" now defaults to 3 hours for upgrading nodes (not just fresh install)
* companion: "node_prefs" -> "new_prefs" migration
2025-03-25 20:20:03 +11:00
Scott Powell
d32e641225 * fix for double radio.begin(). RNG seed from pressing ENTER 2025-03-25 17:40:36 +11:00
Scott Powell
1220c69aa9 * wifi power max 2025-03-25 15:13:07 +11:00
Scott Powell
8355543366 * more experiments 2025-03-25 01:26:46 +11:00
Scott Powell
7bd7bfb14a * ESP-NOW experiment with terminal-chat 2025-03-24 21:16:00 +11:00
Scott Powell
f33e1b22b3 * build fixes 2025-03-24 13:11:08 +11:00
ripplebiz
16039eebfb Merge pull request #128 from Noki/xiao-s3-wio-room-server
xiao s3 wio: add room server
2025-03-24 11:59:05 +11:00
ripplebiz
0d9201b560 Merge pull request #127 from jameshall9327/main
Added screen and button support for the lilygo tbeam
2025-03-24 11:55:22 +11:00
ripplebiz
02edc645bb Merge pull request #135 from recrof/dev
LilyGo T-ECHO: report correct battery voltage
2025-03-24 11:48:52 +11:00
recrof
ac71bac4cf cleanup 2025-03-23 18:31:39 +01:00
Rastislav Vysoky
1677d4db65 Merge branch 'ripplebiz:dev' into dev 2025-03-23 18:27:02 +01:00
recrof
0d114ecfbd LilyGo T-ECHO: report correct battery voltage 2025-03-23 15:57:33 +01:00
Scott Powell
edb201ccbe * repeater & room server: "node_prefs" -> "com_prefs" migration 2025-03-24 00:50:28 +11:00
Scott Powell
d07abc39b6 * room server: new config "allow.read.only" 2025-03-24 00:25:36 +11:00
Scott Powell
39a4476194 * repeater & room server: new config "flood.advert.interval" 2025-03-23 23:23:02 +11:00
Scott Powell
7010123619 * companion: CMD_SEND_TXT_MSG fix for attempt number 2025-03-23 20:25:03 +11:00
Scott Powell
f861b68a09 * refactor: ESP32 OTA lib-deps now selectively added 2025-03-23 17:36:31 +11:00
Scott Powell
a4bb3782a4 * OTA update for ESP32 targets 2025-03-22 23:51:44 +11:00
Scott Powell
30c6a0bc76 * workaround for > 3 retry attempts 2025-03-22 22:21:54 +11:00
ripplebiz
2b8b6aacbb Merge pull request #131 from fdlamotte/t1000e_range_fix
Some fixes for range issue
2025-03-22 11:54:10 +11:00
Florent de Lamotte
1ff3033372 Some fixes for range issue 2025-03-21 15:08:13 +01:00
Scott Powell
0163c4034b * faketec/promicro fix 2025-03-21 21:53:53 +11:00
Scott Powell
965e40eb9e * fix for Faketec/Promicro 2025-03-21 21:53:23 +11:00
Scott Powell
bfb4b1c496 * BIG refactor: 'board' and 'radio' objects now defined in 'target.h/.cpp'
* mesh::RTCClock class moved to MeshCore.h
2025-03-21 18:57:12 +11:00
Tobias Schwarz
e1d8179f72 xiao s3 wio: add room server 2025-03-20 16:49:24 +00:00
James Hall
1299b6f813 added button support 2025-03-20 12:26:52 -04:00
James Hall
8b4662a40a removed repeater code not working properly 2025-03-20 11:48:35 -04:00
James Hall
ae08ecf8fd Screen support for tbeam 2025-03-20 11:44:12 -04:00
ripplebiz
0a5a115875 Merge pull request #124 from recrof/dev
added battery voltage support for Heltec T114
2025-03-20 22:22:33 +11:00
recrof
41e01a0e25 added battery voltage support for Heltec T114 2025-03-20 11:08:13 +01:00
ripplebiz
390e8407c0 Merge pull request #123 from oltaco/faketec-support
Faketec display and button support.
2025-03-20 15:27:25 +11:00
Scott Powell
182c6d479d * minor refactor, SNR from packet 2025-03-20 15:26:23 +11:00
taco
de67ee29eb Fix builds for repeater, room server and companion usb. 2025-03-20 12:50:35 +11:00
taco
1c14482bd4 Remove PIN_OLED_RESET from board header, will leave in build target for now. 2025-03-20 10:05:01 +11:00
taco
61f7f15dc1 Changed BLE pin back to 123456 now - dynamic display sensing happening. 2025-03-20 09:46:40 +11:00
taco
bd0ce731f1 Add faketec changes back after dev merge 2025-03-20 09:27:11 +11:00
taco
74ec702136 Merge branch 'dev' into faketec-support 2025-03-20 09:26:23 +11:00
Scott Powell
a9dde51a9b * build.sh: .uf2 step also for Faketec/ProMicro targets 2025-03-19 20:22:46 +11:00
taco
6a78cfd00d match changes to other nrf52 boards, add pin definitions to platformio.ini 2025-03-17 13:51:26 +11:00
taco
f671b753da revert variant.h pins 2025-03-17 13:50:05 +11:00
taco
88dfa42e47 Merge branch 'faketec-testing' into dev 2025-03-17 13:15:54 +11:00
taco
86ece04fe2 move DISPLAY_CLASS definition 2025-03-17 13:09:26 +11:00
taco
d59b1d235e define PIN_OLED_RESET -1 2025-03-17 13:09:02 +11:00
taco
a67bb8e1e3 tidy up 2025-03-17 12:17:36 +11:00
taco
8b2f783d04 OLED and button support, some refactoring. 2025-03-16 13:24:43 +11:00
84 changed files with 4185 additions and 729 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Ayush Sharma
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.

View File

@@ -0,0 +1,2 @@
AsyncElegantOTA KEYWORD1
begin KEYWORD2

View File

@@ -0,0 +1,9 @@
name=AsyncElegantOTA
version=2.2.8
author=Ayush Sharma
category=Communication
maintainer=Ayush Sharma <asrocks5@gmail.com>
sentence=Perform OTAs for ESP8266 & ESP32 Asynchronously.
paragraph=A User Interface Library which provides interactive elements for your Over the Air Updates on ESP8266/ESP32.
url=https://github.com/ayushsharma82/AsyncElegantOTA
architectures=esp8266,esp32

View File

@@ -0,0 +1,129 @@
#include <AsyncElegantOTA.h>
AsyncElegantOtaClass AsyncElegantOTA;
void AsyncElegantOtaClass::setID(const char* id){
_id = id;
}
void AsyncElegantOtaClass::begin(AsyncWebServer *server, const char* username, const char* password){
_server = server;
if(strlen(username) > 0){
_authRequired = true;
_username = username;
_password = password;
}else{
_authRequired = false;
_username = "";
_password = "";
}
_server->on("/update/identity", HTTP_GET, [&](AsyncWebServerRequest *request){
if(_authRequired){
if(!request->authenticate(_username.c_str(), _password.c_str())){
return request->requestAuthentication();
}
}
#if defined(ESP8266)
request->send(200, "application/json", "{\"id\": \""+_id+"\", \"hardware\": \"ESP8266\"}");
#elif defined(ESP32)
request->send(200, "application/json", "{\"id\": \""+_id+"\", \"hardware\": \"ESP32\"}");
#endif
});
_server->on("/update", HTTP_GET, [&](AsyncWebServerRequest *request){
if(_authRequired){
if(!request->authenticate(_username.c_str(), _password.c_str())){
return request->requestAuthentication();
}
}
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", ELEGANT_HTML, ELEGANT_HTML_SIZE);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
_server->on("/update", HTTP_POST, [&](AsyncWebServerRequest *request) {
if(_authRequired){
if(!request->authenticate(_username.c_str(), _password.c_str())){
return request->requestAuthentication();
}
}
// the request handler is triggered after the upload has finished...
// create the response, add header, and send response
AsyncWebServerResponse *response = request->beginResponse((Update.hasError())?500:200, "text/plain", (Update.hasError())?"FAIL":"OK");
response->addHeader("Connection", "close");
response->addHeader("Access-Control-Allow-Origin", "*");
request->send(response);
restart();
}, [&](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
//Upload handler chunks in data
if(_authRequired){
if(!request->authenticate(_username.c_str(), _password.c_str())){
return request->requestAuthentication();
}
}
if (!index) {
if(!request->hasParam("MD5", true)) {
return request->send(400, "text/plain", "MD5 parameter missing");
}
if(!Update.setMD5(request->getParam("MD5", true)->value().c_str())) {
return request->send(400, "text/plain", "MD5 parameter invalid");
}
#if defined(ESP8266)
int cmd = (filename == "filesystem") ? U_FS : U_FLASH;
Update.runAsync(true);
size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start);
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin((cmd == U_FS)?fsSize:maxSketchSpace, cmd)){ // Start with max available size
#elif defined(ESP32)
int cmd = (filename == "filesystem") ? U_SPIFFS : U_FLASH;
if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) { // Start with max available size
#endif
Update.printError(Serial);
return request->send(400, "text/plain", "OTA could not begin");
}
}
// Write chunked data to the free sketch space
if(len){
if (Update.write(data, len) != len) {
return request->send(400, "text/plain", "OTA could not begin");
}
}
if (final) { // if the final flag is set then this is the last frame of data
if (!Update.end(true)) { //true to set the size to the current progress
Update.printError(Serial);
return request->send(400, "text/plain", "Could not end OTA");
}
}else{
return;
}
});
}
// deprecated, keeping for backward compatibility
void AsyncElegantOtaClass::loop() {
}
void AsyncElegantOtaClass::restart() {
yield();
delay(1000);
yield();
ESP.restart();
}
String AsyncElegantOtaClass::getID(){
String id = "";
#if defined(ESP8266)
id = String(ESP.getChipId());
#elif defined(ESP32)
id = String((uint32_t)ESP.getEfuseMac(), HEX);
#endif
id.toUpperCase();
return id;
}

View File

@@ -0,0 +1,52 @@
#ifndef AsyncElegantOTA_h
#define AsyncElegantOTA_h
#warning AsyncElegantOTA library is deprecated, Please consider moving to newer ElegantOTA library which now comes with an Async Mode. Learn More: https://docs.elegantota.pro/async-mode/
#include "Arduino.h"
#include "stdlib_noniso.h"
#if defined(ESP8266)
#include "ESP8266WiFi.h"
#include "ESPAsyncTCP.h"
#include "flash_hal.h"
#include "FS.h"
#elif defined(ESP32)
#include "WiFi.h"
#include "AsyncTCP.h"
#include "Update.h"
#include "esp_int_wdt.h"
#include "esp_task_wdt.h"
#endif
#include "Hash.h"
#include "ESPAsyncWebServer.h"
#include "FS.h"
#include "elegantWebpage.h"
class AsyncElegantOtaClass{
public:
void
setID(const char* id),
begin(AsyncWebServer *server, const char* username = "", const char* password = ""),
loop(),
restart();
private:
AsyncWebServer *_server;
String getID();
String _id = getID();
String _username = "";
String _password = "";
bool _authRequired = false;
};
extern AsyncElegantOtaClass AsyncElegantOTA;
#endif

View File

@@ -0,0 +1,38 @@
/**
* @file Hash.h
* @date 20.05.2015
* @author Markus Sattler
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the esp8266 core for Arduino environment.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef HASH_H_
#define HASH_H_
//#define DEBUG_SHA1
void sha1(const uint8_t* data, uint32_t size, uint8_t hash[20]);
void sha1(const char* data, uint32_t size, uint8_t hash[20]);
void sha1(const String& data, uint8_t hash[20]);
String sha1(const uint8_t* data, uint32_t size);
String sha1(const char* data, uint32_t size);
String sha1(const String& data);
#endif /* HASH_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ build_firmware() {
fi
# build .uf2 for nrf52 boards
if [[ $1 == *"RAK_4631"* || $1 == *"t1000e"* || $1 == *"t114"* || $1 == *"T-Echo"* ]]; then
if [[ $1 == *"RAK_4631"* || $1 == *"t1000e"* || $1 == *"t114"* || $1 == *"T-Echo"* || $1 == *"Faketec"* || $1 == *"ProMicro"* ]]; then
python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840
fi

View File

@@ -7,15 +7,13 @@
#include <SPIFFS.h>
#endif
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleMeshTables.h>
#include <helpers/IdentityStore.h>
#include <helpers/BaseSerialInterface.h>
#include <RTClib.h>
#include <target.h>
/* ---------------------------------- CONFIGURATION ------------------------------------- */
@@ -59,59 +57,6 @@
#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg=="
#if defined(HELTEC_LORA_V3)
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static HeltecV3Board board;
#elif defined(HELTEC_LORA_V2)
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
static HeltecV2Board board;
#elif defined(ARDUINO_XIAO_ESP32C3)
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
static XiaoC3Board board;
#elif defined(SEEED_XIAO_S3) || defined(LILYGO_T3S3)
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
#elif defined(LILYGO_TLORA)
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static RAK4631Board board;
#elif defined(T1000_E)
#include <helpers/nrf52/T1000eBoard.h>
#include <helpers/CustomLR1110Wrapper.h>
static T1000eBoard board;
#elif defined(HELTEC_T114)
#include <helpers/nrf52/T114Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static T114Board board;
#elif defined(LILYGO_TECHO)
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(LILYGO_TBEAM)
#include <helpers/TBeamBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static TBeamBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
#ifdef DISPLAY_CLASS
#include "UITask.h"
#include <helpers/ui/SSD1306Display.h>
@@ -141,11 +86,11 @@ static uint32_t _atoi(const char* sp) {
#define FIRMWARE_VER_CODE 3
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#define FIRMWARE_BUILD_DATE "30 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.4.0"
#define FIRMWARE_VERSION "v1.4.2"
#endif
#define CMD_APP_START 1
@@ -249,7 +194,6 @@ struct NodePrefs { // persisted to file
class MyMesh : public BaseChatMesh {
FILESYSTEM* _fs;
RADIO_CLASS* _phy;
IdentityStore* _identity_store;
NodePrefs _prefs;
uint32_t pending_login;
@@ -281,9 +225,9 @@ class MyMesh : public BaseChatMesh {
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table
int next_ack_idx;
void loadMainIdentity(mesh::RNG& trng) {
void loadMainIdentity() {
if (!_identity_store->load("_main", self_id)) {
self_id = mesh::LocalIdentity(&trng); // create new random identity
self_id = radio_new_identity(); // create new random identity
saveMainIdentity(self_id);
}
}
@@ -540,7 +484,7 @@ protected:
}
void logRxRaw(float snr, float rssi, const uint8_t raw[], int len) override {
if (_serial->isConnected()) {
if (_serial->isConnected() && len+3 <= MAX_FRAME_SIZE) {
int i = 0;
out_frame[i++] = PUSH_CODE_LOG_RX_DATA;
out_frame[i++] = (int8_t)(snr * 4);
@@ -739,7 +683,7 @@ protected:
memcpy(&out_frame[i], &auth_code, 4); i += 4;
memcpy(&out_frame[i], path_hashes, path_len); i += path_len;
memcpy(&out_frame[i], path_snrs, path_len); i += path_len;
out_frame[i++] = (int8_t)(_radio->getLastSNR() * 4); // extra/final SNR (to this node)
out_frame[i++] = (int8_t)(packet->getSNR() * 4); // extra/final SNR (to this node)
if (_serial->isConnected()) {
_serial->writeFrame(out_frame, i);
@@ -761,8 +705,8 @@ protected:
public:
MyMesh(RADIO_CLASS& phy, RadioLibWrapper& rw, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
: BaseChatMesh(rw, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL), _phy(&phy)
MyMesh(mesh::Radio& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), _serial(NULL)
{
_iter_started = false;
offline_queue_len = 0;
@@ -784,7 +728,42 @@ public:
//_prefs.rx_delay_base = 10.0f; enable once new algo fixed
}
void begin(FILESYSTEM& fs, mesh::RNG& trng, bool has_display) {
void loadPrefsInt(const char* filename) {
File file = _fs->open(filename);
if (file) {
uint8_t pad[8];
file.read((uint8_t *) &_prefs.airtime_factor, sizeof(float)); // 0
file.read((uint8_t *) _prefs.node_name, sizeof(_prefs.node_name)); // 4
file.read(pad, 4); // 36
file.read((uint8_t *) &_prefs.node_lat, sizeof(_prefs.node_lat)); // 40
file.read((uint8_t *) &_prefs.node_lon, sizeof(_prefs.node_lon)); // 48
file.read((uint8_t *) &_prefs.freq, sizeof(_prefs.freq)); // 56
file.read((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60
file.read((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61
file.read((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
file.read((uint8_t *) &_prefs.reserved2, sizeof(_prefs.reserved2)); // 63
file.read((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64
file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
file.read((uint8_t *) _prefs.unused, sizeof(_prefs.unused)); // 69
file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
file.read(pad, 4); // 76
file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
// sanitise bad pref values
_prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f);
_prefs.airtime_factor = constrain(_prefs.airtime_factor, 0, 9.0f);
_prefs.freq = constrain(_prefs.freq, 400.0f, 2500.0f);
_prefs.bw = constrain(_prefs.bw, 62.5f, 500.0f);
_prefs.sf = constrain(_prefs.sf, 7, 12);
_prefs.cr = constrain(_prefs.cr, 5, 8);
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER);
file.close();
}
}
void begin(FILESYSTEM& fs, bool has_display) {
_fs = &fs;
BaseChatMesh::begin();
@@ -795,49 +774,23 @@ public:
_identity_store = new IdentityStore(fs, "/identity");
#endif
loadMainIdentity(trng);
loadMainIdentity();
// load persisted prefs
if (_fs->exists("/node_prefs")) {
File file = _fs->open("/node_prefs");
if (file) {
uint8_t pad[8];
file.read((uint8_t *) &_prefs.airtime_factor, sizeof(float)); // 0
file.read((uint8_t *) _prefs.node_name, sizeof(_prefs.node_name)); // 4
file.read(pad, 4); // 36
file.read((uint8_t *) &_prefs.node_lat, sizeof(_prefs.node_lat)); // 40
file.read((uint8_t *) &_prefs.node_lon, sizeof(_prefs.node_lon)); // 48
file.read((uint8_t *) &_prefs.freq, sizeof(_prefs.freq)); // 56
file.read((uint8_t *) &_prefs.sf, sizeof(_prefs.sf)); // 60
file.read((uint8_t *) &_prefs.cr, sizeof(_prefs.cr)); // 61
file.read((uint8_t *) &_prefs.reserved1, sizeof(_prefs.reserved1)); // 62
file.read((uint8_t *) &_prefs.reserved2, sizeof(_prefs.reserved2)); // 63
file.read((uint8_t *) &_prefs.bw, sizeof(_prefs.bw)); // 64
file.read((uint8_t *) &_prefs.tx_power_dbm, sizeof(_prefs.tx_power_dbm)); // 68
file.read((uint8_t *) _prefs.unused, sizeof(_prefs.unused)); // 69
file.read((uint8_t *) &_prefs.rx_delay_base, sizeof(_prefs.rx_delay_base)); // 72
file.read(pad, 4); // 76
file.read((uint8_t *) &_prefs.ble_pin, sizeof(_prefs.ble_pin)); // 80
// sanitise bad pref values
_prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f);
_prefs.airtime_factor = constrain(_prefs.airtime_factor, 0, 9.0f);
_prefs.freq = constrain(_prefs.freq, 400.0f, 2500.0f);
_prefs.bw = constrain(_prefs.bw, 62.5f, 500.0f);
_prefs.sf = constrain(_prefs.sf, 7, 12);
_prefs.cr = constrain(_prefs.cr, 5, 8);
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER);
file.close();
}
if (_fs->exists("/new_prefs")) {
loadPrefsInt("/new_prefs"); // new filename
} else if (_fs->exists("/node_prefs")) {
loadPrefsInt("/node_prefs");
savePrefs(); // save to new filename
_fs->remove("/node_prefs"); // remove old
}
#ifdef BLE_PIN_CODE
if (_prefs.ble_pin == 0) {
#ifdef HAS_UI
if (has_display) {
_active_ble_pin = trng.nextInt(100000, 999999); // random pin each session
StdRNG rng;
_active_ble_pin = rng.nextInt(100000, 999999); // random pin each session
} else {
_active_ble_pin = BLE_PIN_CODE; // otherwise static pin
}
@@ -858,11 +811,8 @@ public:
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
loadChannels();
_phy->setFrequency(_prefs.freq);
_phy->setSpreadingFactor(_prefs.sf);
_phy->setBandwidth(_prefs.bw);
_phy->setCodingRate(_prefs.cr);
_phy->setOutputPower(_prefs.tx_power_dbm);
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_set_tx_power(_prefs.tx_power_dbm);
}
const char* getNodeName() { return _prefs.node_name; }
@@ -875,10 +825,10 @@ public:
void savePrefs() {
#if defined(NRF52_PLATFORM)
File file = _fs->open("/node_prefs", FILE_O_WRITE);
File file = _fs->open("/new_prefs", FILE_O_WRITE);
if (file) { file.seek(0); file.truncate(); }
#else
File file = _fs->open("/node_prefs", "w", true);
File file = _fs->open("/new_prefs", "w", true);
#endif
if (file) {
uint8_t pad[8];
@@ -959,7 +909,7 @@ public:
memcpy(&msg_timestamp, &cmd_frame[i], 4); i += 4;
uint8_t* pub_key_prefix = &cmd_frame[i]; i += 6;
ContactInfo* recipient = lookupContactByPubKey(pub_key_prefix, 6);
if (recipient && attempt < 4 && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) {
if (recipient && (txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_CLI_DATA)) {
char *text = (char *) &cmd_frame[i];
int tlen = len - i;
uint32_t est_timeout;
@@ -1197,10 +1147,7 @@ public:
_prefs.bw = (float)bw / 1000.0;
savePrefs();
_phy->setFrequency(_prefs.freq);
_phy->setSpreadingFactor(_prefs.sf);
_phy->setBandwidth(_prefs.bw);
_phy->setCodingRate(_prefs.cr);
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
MESH_DEBUG_PRINTLN("OK: CMD_SET_RADIO_PARAMS: f=%d, bw=%d, sf=%d, cr=%d", freq, bw, (uint32_t)sf, (uint32_t)cr);
writeOKFrame();
@@ -1214,7 +1161,7 @@ public:
} else {
_prefs.tx_power_dbm = cmd_frame[1];
savePrefs();
_phy->setOutputPower(_prefs.tx_power_dbm);
radio_set_tx_power(_prefs.tx_power_dbm);
writeOKFrame();
}
} else if (cmd_frame[0] == CMD_SET_TUNING_PARAMS) {
@@ -1473,23 +1420,9 @@ public:
#error "need to define a serial interface"
#endif
#if defined(NRF52_PLATFORM)
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
#elif defined(LILYGO_TLORA)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(LILYGO_TBEAM)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(P_LORA_SCLK)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
MyMesh the_mesh(radio, *new WRAPPER_CLASS(radio, board), fast_rng, *new VolatileRTCClock(), tables);
MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp
void halt() {
while (1) ;
@@ -1499,47 +1432,10 @@ void setup() {
Serial.begin(115200);
board.begin();
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(NRF52_PLATFORM)
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
#elif defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
#if defined(FAKETEC)
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
halt();
}
if (!radio_init()) { halt(); }
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
fast_rng.begin(radio.random(0x7FFFFFFF));
RadioNoiseListener trng(radio);
fast_rng.begin(radio_get_rng_seed());
#ifdef HAS_UI
DisplayDriver* disp = NULL;
@@ -1552,7 +1448,7 @@ void setup() {
#if defined(NRF52_PLATFORM)
InternalFS.begin();
the_mesh.begin(InternalFS, trng,
the_mesh.begin(InternalFS,
#ifdef HAS_UI
disp != NULL
#else
@@ -1570,7 +1466,7 @@ void setup() {
the_mesh.startInterface(serial_interface);
#elif defined(ESP32)
SPIFFS.begin(true);
the_mesh.begin(SPIFFS, trng,
the_mesh.begin(SPIFFS,
#ifdef HAS_UI
disp != NULL
#else

View File

@@ -7,26 +7,24 @@
#include <SPIFFS.h>
#endif
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleMeshTables.h>
#include <helpers/IdentityStore.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/AdvertDataHelpers.h>
#include <helpers/TxtDataHelpers.h>
#include <helpers/CommonCLI.h>
#include <RTClib.h>
#include <target.h>
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#define FIRMWARE_BUILD_DATE "30 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.4.0"
#define FIRMWARE_VERSION "v1.4.2"
#endif
#ifndef LORA_FREQ
@@ -59,52 +57,6 @@
#define ADMIN_PASSWORD "password"
#endif
#if defined(HELTEC_LORA_V3)
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static HeltecV3Board board;
#elif defined(HELTEC_LORA_V2)
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
static HeltecV2Board board;
#elif defined(ARDUINO_XIAO_ESP32C3)
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
static XiaoC3Board board;
#elif defined(SEEED_XIAO_S3) || defined(LILYGO_T3S3)
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
#elif defined(LILYGO_TLORA)
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(STATION_G2)
#include <helpers/StationG2Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static StationG2Board board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static RAK4631Board board;
#elif defined(HELTEC_T114)
#include <helpers/nrf52/T114Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static T114Board board;
#elif defined(LILYGO_TECHO)
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
@@ -114,6 +66,8 @@
static UITask ui_task(display);
#endif
#define FIRMWARE_ROLE "repeater"
#define PACKET_LOG_FILE "/packet_log"
/* ------------------------------ Code -------------------------------- */
@@ -153,11 +107,8 @@ struct ClientInfo {
#define CLI_REPLY_DELAY_MILLIS 1500
class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
RadioLibWrapper* my_radio;
FILESYSTEM* _fs;
RADIO_CLASS* _phy;
mesh::MainBoard* _board;
unsigned long next_local_advert;
unsigned long next_local_advert, next_flood_advert;
bool _logging;
NodePrefs _prefs;
CommonCLI _cli;
@@ -192,9 +143,9 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
stats.batt_milli_volts = board.getBattMilliVolts();
stats.curr_tx_queue_len = _mgr->getOutboundCount();
stats.curr_free_queue_len = _mgr->getFreeCount();
stats.last_rssi = (int16_t) my_radio->getLastRSSI();
stats.n_packets_recv = my_radio->getPacketsRecv();
stats.n_packets_sent = my_radio->getPacketsSent();
stats.last_rssi = (int16_t) radio_driver.getLastRSSI();
stats.n_packets_recv = radio_driver.getPacketsRecv();
stats.n_packets_sent = radio_driver.getPacketsSent();
stats.total_air_time_secs = getTotalAirTime() / 1000;
stats.total_up_time_secs = _ms->getMillis() / 1000;
stats.n_sent_flood = getNumSentFlood();
@@ -202,7 +153,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
stats.n_recv_flood = getNumRecvFlood();
stats.n_recv_direct = getNumRecvDirect();
stats.n_full_events = getNumFullEvents();
stats.last_snr = (int16_t)(my_radio->getLastSNR() * 4);
stats.last_snr = (int16_t)(radio_driver.getLastSNR() * 4);
stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups();
stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups();
@@ -519,13 +470,12 @@ protected:
}
public:
MyMesh(RADIO_CLASS& phy, mesh::MainBoard& board, RadioLibWrapper& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_phy(&phy), _board(&board), _cli(board, this, &_prefs, this)
_cli(board, this, &_prefs, this)
{
my_radio = &radio;
memset(known_clients, 0, sizeof(known_clients));
next_local_advert = 0;
next_local_advert = next_flood_advert = 0;
_logging = false;
// defaults
@@ -543,6 +493,7 @@ public:
_prefs.cr = LORA_CR;
_prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_advert_interval = 3; // 3 hours
_prefs.flood_max = 64;
}
@@ -554,17 +505,16 @@ public:
// load persisted prefs
_cli.loadPrefs(_fs);
_phy->setFrequency(_prefs.freq);
_phy->setSpreadingFactor(_prefs.sf);
_phy->setBandwidth(_prefs.bw);
_phy->setCodingRate(_prefs.cr);
_phy->setOutputPower(_prefs.tx_power_dbm);
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_set_tx_power(_prefs.tx_power_dbm);
updateAdvertTimer();
updateFloodAdvertTimer();
}
const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
const char* getRole() override { return FIRMWARE_ROLE; }
const char* getNodeName() { return _prefs.node_name; }
void savePrefs() override {
@@ -593,11 +543,18 @@ public:
void updateAdvertTimer() override {
if (_prefs.advert_interval > 0) { // schedule local advert timer
next_local_advert = futureMillis((uint32_t)_prefs.advert_interval * 2 * 60 * 1000);
next_local_advert = futureMillis( ((uint32_t)_prefs.advert_interval) * 2 * 60 * 1000);
} else {
next_local_advert = 0; // stop the timer
}
}
void updateFloodAdvertTimer() override {
if (_prefs.flood_advert_interval > 0) { // schedule flood advert timer
next_flood_advert = futureMillis( ((uint32_t)_prefs.flood_advert_interval) * 60 * 60 * 1000);
} else {
next_flood_advert = 0; // stop the timer
}
}
void setLoggingOn(bool enable) override { _logging = enable; }
@@ -618,17 +575,21 @@ public:
}
void setTxPower(uint8_t power_dbm) override {
_phy->setOutputPower(power_dbm);
radio_set_tx_power(power_dbm);
}
void loop() {
mesh::Mesh::loop();
if (next_local_advert && millisHasNowPassed(next_local_advert)) {
if (next_flood_advert && millisHasNowPassed(next_flood_advert)) {
mesh::Packet* pkt = createSelfAdvert();
if (pkt) {
sendZeroHop(pkt);
}
if (pkt) sendFlood(pkt);
updateFloodAdvertTimer(); // schedule next flood advert
updateAdvertTimer(); // also schedule local advert (so they don't overlap)
} else if (next_local_advert && millisHasNowPassed(next_local_advert)) {
mesh::Packet* pkt = createSelfAdvert();
if (pkt) sendZeroHop(pkt);
updateAdvertTimer(); // schedule next local advert
}
@@ -638,28 +599,10 @@ public:
}
};
#if defined(NRF52_PLATFORM)
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
#elif defined(LILYGO_TLORA)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(P_LORA_SCLK)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
#ifdef ESP32
ESP32RTCClock fallback_clock;
#else
VolatileRTCClock fallback_clock;
#endif
AutoDiscoverRTCClock rtc_clock(fallback_clock);
MyMesh the_mesh(radio, board, *new WRAPPER_CLASS(radio, board), *new ArduinoMillis(), fast_rng, rtc_clock, tables);
MyMesh the_mesh(board, radio_driver, *new ArduinoMillis(), fast_rng, rtc_clock, tables);
void halt() {
while (1) ;
@@ -672,51 +615,10 @@ void setup() {
delay(1000);
board.begin();
#ifdef ESP32
fallback_clock.begin();
#endif
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
if (!radio_init()) { halt(); }
#if defined(NRF52_PLATFORM)
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
#elif defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
#if defined(FAKETEC)
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
delay(5000);
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
halt();
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
fast_rng.begin(radio.random(0x7FFFFFFF));
fast_rng.begin(radio_get_rng_seed());
FILESYSTEM* fs;
#if defined(NRF52_PLATFORM)
@@ -732,8 +634,7 @@ void setup() {
#endif
if (!store.load("_main", the_mesh.self_id)) {
MESH_DEBUG_PRINTLN("Generating new keypair");
RadioNoiseListener rng(radio);
the_mesh.self_id = mesh::LocalIdentity(&rng); // create new random identity
the_mesh.self_id = radio_new_identity(); // create new random identity
store.save("_main", the_mesh.self_id);
}
@@ -750,7 +651,7 @@ void setup() {
#endif
// send out initial Advertisement to the mesh
the_mesh.sendSelfAdvertisement(2000);
the_mesh.sendSelfAdvertisement(16000);
}
void loop() {

View File

@@ -7,26 +7,24 @@
#include <SPIFFS.h>
#endif
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleMeshTables.h>
#include <helpers/IdentityStore.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/AdvertDataHelpers.h>
#include <helpers/TxtDataHelpers.h>
#include <helpers/CommonCLI.h>
#include <RTClib.h>
#include <target.h>
/* ------------------------------ Config -------------------------------- */
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "19 Mar 2025"
#define FIRMWARE_BUILD_DATE "30 Mar 2025"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "v1.4.0"
#define FIRMWARE_VERSION "v1.4.2"
#endif
#ifndef LORA_FREQ
@@ -67,52 +65,6 @@
#define MAX_UNSYNCED_POSTS 16
#endif
#if defined(HELTEC_LORA_V3)
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static HeltecV3Board board;
#elif defined(HELTEC_LORA_V2)
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
static HeltecV2Board board;
#elif defined(ARDUINO_XIAO_ESP32C3)
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
static XiaoC3Board board;
#elif defined(SEEED_XIAO_S3) || defined(LILYGO_T3S3)
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
#elif defined(LILYGO_TLORA)
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(STATION_G2)
#include <helpers/StationG2Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static StationG2Board board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static RAK4631Board board;
#elif defined(HELTEC_T114)
#include <helpers/nrf52/T114Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static T114Board board;
#elif defined(LILYGO_TECHO)
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
static TechoBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
@@ -122,8 +74,18 @@
static UITask ui_task(display);
#endif
#define FIRMWARE_ROLE "room_server"
#define PACKET_LOG_FILE "/packet_log"
/* ------------------------------ Code -------------------------------- */
enum RoomPermission {
ADMIN,
GUEST,
READ_ONLY
};
struct ClientInfo {
mesh::Identity id;
uint32_t last_timestamp; // by THEIR clock
@@ -132,7 +94,7 @@ struct ClientInfo {
uint32_t pending_ack;
uint32_t push_post_timestamp;
unsigned long ack_timeout;
bool is_admin;
RoomPermission permission;
uint8_t push_failures;
uint8_t secret[PUB_KEY_SIZE];
int out_path_len;
@@ -180,11 +142,9 @@ struct ServerStats {
};
class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
RadioLibWrapper* my_radio;
FILESYSTEM* _fs;
RADIO_CLASS* _phy;
mesh::MainBoard* _board;
unsigned long next_local_advert;
unsigned long next_local_advert, next_flood_advert;
bool _logging;
NodePrefs _prefs;
CommonCLI _cli;
uint8_t reply_data[MAX_PACKET_PAYLOAD];
@@ -296,6 +256,14 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
return createAdvert(self_id, app_data, app_data_len);
}
File openAppend(const char* fname) {
#if defined(NRF52_PLATFORM)
return _fs->open(fname, FILE_O_WRITE);
#else
return _fs->open(fname, "a", true);
#endif
}
protected:
float getAirtimeBudgetFactor() const override {
return _prefs.airtime_factor;
@@ -310,6 +278,55 @@ protected:
#endif
}
void logRx(mesh::Packet* pkt, int len, float score) override {
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
f.print(getLogDateTime());
f.printf(": RX, len=%d (type=%d, route=%s, payload_len=%d) SNR=%d RSSI=%d score=%d",
len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len,
(int)_radio->getLastSNR(), (int)_radio->getLastRSSI(), (int)(score*1000));
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ
|| pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
f.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]);
} else {
f.printf("\n");
}
f.close();
}
}
}
void logTx(mesh::Packet* pkt, int len) override {
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
f.print(getLogDateTime());
f.printf(": TX, len=%d (type=%d, route=%s, payload_len=%d)",
len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
if (pkt->getPayloadType() == PAYLOAD_TYPE_PATH || pkt->getPayloadType() == PAYLOAD_TYPE_REQ
|| pkt->getPayloadType() == PAYLOAD_TYPE_RESPONSE || pkt->getPayloadType() == PAYLOAD_TYPE_TXT_MSG) {
f.printf(" [%02X -> %02X]\n", (uint32_t)pkt->payload[1], (uint32_t)pkt->payload[0]);
} else {
f.printf("\n");
}
f.close();
}
}
}
void logTxFail(mesh::Packet* pkt, int len) override {
if (_logging) {
File f = openAppend(PACKET_LOG_FILE);
if (f) {
f.print(getLogDateTime());
f.printf(": TX FAIL!, len=%d (type=%d, route=%s, payload_len=%d)\n",
len, pkt->getPayloadType(), pkt->isRouteDirect() ? "D" : "F", pkt->payload_len);
f.close();
}
}
}
int calcRxDelay(float score, uint32_t air_time) const override {
if (_prefs.rx_delay_base <= 0.0f) return 0;
return (int) ((pow(_prefs.rx_delay_base, 0.85f - score) - 1.0) * air_time);
@@ -344,13 +361,16 @@ protected:
memcpy(&sender_timestamp, data, 4);
memcpy(&sender_sync_since, &data[4], 4); // sender's "sync messags SINCE x" timestamp
bool is_admin;
RoomPermission perm;
data[len] = 0; // ensure null terminator
if (strcmp((char *) &data[8], _prefs.password) == 0) { // check for valid admin password
is_admin = true;
perm = RoomPermission::ADMIN;
} else {
is_admin = false;
if (strcmp((char *) &data[8], _prefs.guest_password) != 0) { // check the room/public password
if (strcmp((char *) &data[8], _prefs.guest_password) == 0) { // check the room/public password
perm = RoomPermission::GUEST;
} else if (_prefs.allow_read_only) {
perm = RoomPermission::READ_ONLY;
} else {
MESH_DEBUG_PRINTLN("Incorrect room password");
return; // no response. Client will timeout
}
@@ -363,7 +383,7 @@ protected:
}
MESH_DEBUG_PRINTLN("Login success!");
client->is_admin = is_admin;
client->permission = perm;
client->last_timestamp = sender_timestamp;
client->sync_since = sender_sync_since;
client->pending_ack = 0;
@@ -377,7 +397,7 @@ protected:
// TODO: maybe reply with count of messages waiting to be synced for THIS client?
reply_data[4] = RESP_SERVER_LOGIN_OK;
reply_data[5] = (CLIENT_KEEP_ALIVE_SECS >> 4); // NEW: recommended keep-alive interval (secs / 16)
reply_data[6] = is_admin ? 1 : 0;
reply_data[6] = (perm == RoomPermission::ADMIN ? 1 : (perm == RoomPermission::GUEST ? 0 : 2));
reply_data[7] = 0; // FUTURE: reserved
memcpy(&reply_data[8], "OK", 2); // REVISIT: not really needed
@@ -454,7 +474,7 @@ protected:
uint8_t temp[166];
bool send_ack;
if (flags == TXT_TYPE_CLI_DATA) {
if (client->is_admin) {
if (client->permission == RoomPermission::ADMIN) {
if (is_retry) {
temp[5] = 0; // no reply
} else {
@@ -467,11 +487,16 @@ protected:
send_ack = false; // and no ACK... user shoudn't be sending these
}
} else { // TXT_TYPE_PLAIN
if (!is_retry) {
addPost(client, (const char *) &data[5]);
if (client->permission == RoomPermission::READ_ONLY) {
temp[5] = 0; // no reply
send_ack = false; // no ACK
} else {
if (!is_retry) {
addPost(client, (const char *) &data[5]);
}
temp[5] = 0; // no reply (ACK is enough)
send_ack = true;
}
temp[5] = 0; // no reply (ACK is enough)
send_ack = true;
}
uint32_t delay_millis;
@@ -555,9 +580,9 @@ protected:
stats.batt_milli_volts = board.getBattMilliVolts();
stats.curr_tx_queue_len = _mgr->getOutboundCount();
stats.curr_free_queue_len = _mgr->getFreeCount();
stats.last_rssi = (int16_t) my_radio->getLastRSSI();
stats.n_packets_recv = my_radio->getPacketsRecv();
stats.n_packets_sent = my_radio->getPacketsSent();
stats.last_rssi = (int16_t) radio_driver.getLastRSSI();
stats.n_packets_recv = radio_driver.getPacketsRecv();
stats.n_packets_sent = radio_driver.getPacketsSent();
stats.total_air_time_secs = getTotalAirTime() / 1000;
stats.total_up_time_secs = _ms->getMillis() / 1000;
stats.n_sent_flood = getNumSentFlood();
@@ -565,7 +590,7 @@ protected:
stats.n_recv_flood = getNumRecvFlood();
stats.n_recv_direct = getNumRecvDirect();
stats.n_full_events = getNumFullEvents();
stats.last_snr = (int16_t)(my_radio->getLastSNR() * 4);
stats.last_snr = (int16_t)(radio_driver.getLastSNR() * 4);
stats.n_direct_dups = ((SimpleMeshTables *)getTables())->getNumDirectDups();
stats.n_flood_dups = ((SimpleMeshTables *)getTables())->getNumFloodDups();
stats.n_posted = _num_posted;
@@ -575,7 +600,7 @@ protected:
memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
memcpy(&reply_data[4], &stats, sizeof(stats));
uint8_t reply_len = 4 + sizeof(stats);
if (packet->isRouteFlood()) {
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the response
mesh::Packet* path = createPathReturn(client->id, secret, packet->path, packet->path_len,
@@ -624,12 +649,12 @@ protected:
}
public:
MyMesh(RADIO_CLASS& phy, mesh::MainBoard& board, RadioLibWrapper& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
MyMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::MillisecondClock& ms, mesh::RNG& rng, mesh::RTCClock& rtc, mesh::MeshTables& tables)
: mesh::Mesh(radio, ms, rng, rtc, *new StaticPoolPacketManager(32), tables),
_phy(&phy), _board(&board), _cli(board, this, &_prefs, this)
_cli(board, this, &_prefs, this)
{
my_radio = &radio;
next_local_advert = 0;
next_local_advert = next_flood_advert = 0;
_logging = false;
// defaults
memset(&_prefs, 0, sizeof(_prefs));
@@ -647,6 +672,7 @@ public:
_prefs.tx_power_dbm = LORA_TX_POWER;
_prefs.disable_fwd = 1;
_prefs.advert_interval = 1; // default to 2 minutes for NEW installs
_prefs.flood_advert_interval = 3; // 3 hours
_prefs.flood_max = 64;
#ifdef ROOM_PASSWORD
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
@@ -668,17 +694,16 @@ public:
// load persisted prefs
_cli.loadPrefs(_fs);
_phy->setFrequency(_prefs.freq);
_phy->setSpreadingFactor(_prefs.sf);
_phy->setBandwidth(_prefs.bw);
_phy->setCodingRate(_prefs.cr);
_phy->setOutputPower(_prefs.tx_power_dbm);
radio_set_params(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_set_tx_power(_prefs.tx_power_dbm);
updateAdvertTimer();
updateFloodAdvertTimer();
}
const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
const char* getRole() override { return FIRMWARE_ROLE; }
const char* getNodeName() { return _prefs.node_name; }
void savePrefs() override {
@@ -712,13 +737,34 @@ public:
next_local_advert = 0; // stop the timer
}
}
void updateFloodAdvertTimer() override {
if (_prefs.flood_advert_interval > 0) { // schedule flood advert timer
next_flood_advert = futureMillis( ((uint32_t)_prefs.flood_advert_interval) * 60 * 60 * 1000);
} else {
next_flood_advert = 0; // stop the timer
}
}
void setLoggingOn(bool enable) override { /* no-op */ }
void eraseLogFile() override { /* no-op */ }
void dumpLogFile() override { /* no-op */ }
void setLoggingOn(bool enable) override { _logging = enable; }
void eraseLogFile() override {
_fs->remove(PACKET_LOG_FILE);
}
void dumpLogFile() override {
File f = _fs->open(PACKET_LOG_FILE);
if (f) {
while (f.available()) {
int c = f.read();
if (c < 0) break;
Serial.print((char)c);
}
f.close();
}
}
void setTxPower(uint8_t power_dbm) override {
_phy->setOutputPower(power_dbm);
radio_set_tx_power(power_dbm);
}
void loop() {
@@ -756,11 +802,15 @@ public:
next_push = futureMillis(SYNC_PUSH_INTERVAL);
}
if (next_local_advert && millisHasNowPassed(next_local_advert)) {
if (next_flood_advert && millisHasNowPassed(next_flood_advert)) {
mesh::Packet* pkt = createSelfAdvert();
if (pkt) {
sendZeroHop(pkt);
}
if (pkt) sendFlood(pkt);
updateFloodAdvertTimer(); // schedule next flood advert
updateAdvertTimer(); // also schedule local advert (so they don't overlap)
} else if (next_local_advert && millisHasNowPassed(next_local_advert)) {
mesh::Packet* pkt = createSelfAdvert();
if (pkt) sendZeroHop(pkt);
updateAdvertTimer(); // schedule next local advert
}
@@ -773,28 +823,9 @@ public:
}
};
#if defined(NRF52_PLATFORM)
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
#elif defined(LILYGO_TLORA)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(P_LORA_SCLK)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
#ifdef ESP32
ESP32RTCClock fallback_clock;
#else
VolatileRTCClock fallback_clock;
#endif
AutoDiscoverRTCClock rtc_clock(fallback_clock);
MyMesh the_mesh(radio, board, *new WRAPPER_CLASS(radio, board), *new ArduinoMillis(), fast_rng, rtc_clock, tables);
MyMesh the_mesh(board, radio_driver, *new ArduinoMillis(), fast_rng, rtc_clock, tables);
void halt() {
while (1) ;
@@ -807,51 +838,10 @@ void setup() {
delay(1000);
board.begin();
#ifdef ESP32
fallback_clock.begin();
#endif
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
if (!radio_init()) { halt(); }
#if defined(NRF52_PLATFORM)
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
#elif defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
#if defined(FAKETEC)
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
}
#endif
if (status != RADIOLIB_ERR_NONE) {
delay(5000);
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
halt();
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
fast_rng.begin(radio.random(0x7FFFFFFF));
fast_rng.begin(radio_get_rng_seed());
FILESYSTEM* fs;
#if defined(NRF52_PLATFORM)
@@ -866,8 +856,7 @@ void setup() {
#error "need to define filesystem"
#endif
if (!store.load("_main", the_mesh.self_id)) {
RadioNoiseListener rng(radio);
the_mesh.self_id = mesh::LocalIdentity(&rng); // create new random identity
the_mesh.self_id = radio_new_identity(); // create new random identity
store.save("_main", the_mesh.self_id);
}
@@ -884,7 +873,7 @@ void setup() {
#endif
// send out initial Advertisement to the mesh
the_mesh.sendSelfAdvertisement(2000);
the_mesh.sendSelfAdvertisement(16000);
}
void loop() {

View File

@@ -7,14 +7,12 @@
#include <SPIFFS.h>
#endif
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/StaticPoolPacketManager.h>
#include <helpers/SimpleMeshTables.h>
#include <helpers/IdentityStore.h>
#include <RTClib.h>
#include <target.h>
/* ---------------------------------- CONFIGURATION ------------------------------------- */
@@ -49,44 +47,6 @@
#define PUBLIC_GROUP_PSK "izOH6cXN6mrJ5e26oRXNcg=="
#if defined(HELTEC_LORA_V3)
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static HeltecV3Board board;
#elif defined(HELTEC_LORA_V2)
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
static HeltecV2Board board;
#elif defined(ARDUINO_XIAO_ESP32C3)
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
static XiaoC3Board board;
#elif defined(SEEED_XIAO_S3) || defined(LILYGO_T3S3)
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static ESP32Board board;
#elif defined(LILYGO_TLORA)
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
static LilyGoTLoraBoard board;
#elif defined(RAK_4631)
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
static RAK4631Board board;
#elif defined(T1000_E)
#include <helpers/nrf52/T1000eBoard.h>
#include <helpers/CustomLR1110Wrapper.h>
static T1000eBoard board;
#elif defined(FAKETEC)
#include <helpers/nrf52/faketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
static faketecBoard board;
#else
#error "need to provide a 'board' object"
#endif
// Believe it or not, this std C function is busted on some platforms!
static uint32_t _atoi(const char* sp) {
uint32_t n = 0;
@@ -230,6 +190,10 @@ protected:
return 0; // disable rxdelay
}
bool allowPacketForward(const mesh::Packet* packet) override {
return true;
}
void onDiscoveredContact(ContactInfo& contact, bool is_new) override {
// TODO: if not in favs, prompt to add as fav(?)
@@ -299,8 +263,7 @@ protected:
}
public:
MyMesh(RadioLibWrapper& radio, mesh::RNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
MyMesh(mesh::Radio& radio, StdRNG& rng, mesh::RTCClock& rtc, SimpleMeshTables& tables)
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables)
{
// defaults
@@ -328,6 +291,14 @@ public:
IdentityStore store(fs, "/identity");
#endif
if (!store.load("_main", self_id, _prefs.node_name, sizeof(_prefs.node_name))) { // legacy: node_name was from identity file
// Need way to get some entropy to seed RNG
Serial.println("Press ENTER to generate key:");
char c = 0;
while (c != '\n') { // wait for ENTER to be pressed
if (Serial.available()) c = Serial.read();
}
((StdRNG *)getRNG())->begin(millis());
self_id = mesh::LocalIdentity(getRNG()); // create new random identity
store.save("_main", self_id);
}
@@ -362,6 +333,8 @@ public:
Serial.println("===== MeshCore Chat Terminal =====");
Serial.println();
Serial.printf("WELCOME %s\n", _prefs.node_name);
mesh::Utils::printHex(Serial, self_id.pub_key, PUB_KEY_SIZE);
Serial.println();
Serial.println(" (enter 'help' for basic commands)");
Serial.println();
}
@@ -548,20 +521,9 @@ public:
}
};
#if defined(NRF52_PLATFORM)
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
#elif defined(LILYGO_TLORA)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
#elif defined(P_LORA_SCLK)
SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
MyMesh the_mesh(*new WRAPPER_CLASS(radio, board), fast_rng, *new VolatileRTCClock(), tables);
MyMesh the_mesh(radio_driver, fast_rng, *new VolatileRTCClock(), tables); // TODO: test with 'rtc_clock' in target.cpp
void halt() {
while (1) ;
@@ -571,36 +533,10 @@ void setup() {
Serial.begin(115200);
board.begin();
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(NRF52_PLATFORM)
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
#elif defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
halt();
}
if (!radio_init()) { halt(); }
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
fast_rng.begin(radio.random(0x7FFFFFFF));
fast_rng.begin(radio_get_rng_seed());
#if defined(NRF52_PLATFORM)
InternalFS.begin();
@@ -612,12 +548,8 @@ void setup() {
#error "need to define filesystem"
#endif
if (LORA_FREQ != the_mesh.getFreqPref()) {
radio.setFrequency(the_mesh.getFreqPref());
}
if (LORA_TX_POWER != the_mesh.getTxPowerPref()) {
radio.setOutputPower(the_mesh.getTxPowerPref());
}
radio_set_params(the_mesh.getFreqPref(), LORA_BW, LORA_SF, LORA_CR);
radio_set_tx_power(the_mesh.getTxPowerPref());
the_mesh.showWelcome();

View File

@@ -23,7 +23,7 @@ lib_deps =
adafruit/RTClib @ ^2.1.3
melopero/Melopero RV3028 @ ^1.1.0
build_flags = -w -DNDEBUG -DRADIOLIB_STATIC_ONLY=1 -DRADIOLIB_GODMODE=1
-D LORA_FREQ=867.5
-D LORA_FREQ=869.525
-D LORA_BW=250
-D LORA_SF=10
build_src_filter =
@@ -41,6 +41,10 @@ build_flags = ${arduino_base.build_flags}
; -D ESP32_CPU_FREQ=80 ; change it to your need
build_src_filter = ${arduino_base.build_src_filter}
[esp32_ota]
lib_deps =
me-no-dev/ESPAsyncWebServer @ ^3.6.0
file://arch/esp32/AsyncElegantOTA
; ----------------- NRF52 ---------------------
[nrf52_base]

View File

@@ -29,6 +29,9 @@ int Dispatcher::calcRxDelay(float score, uint32_t air_time) const {
uint32_t Dispatcher::getCADFailRetryDelay() const {
return 200;
}
uint32_t Dispatcher::getCADFailMaxDuration() const {
return 4000; // 4 seconds
}
void Dispatcher::loop() {
if (outbound) { // waiting for outbound send to be completed
@@ -185,9 +188,20 @@ void Dispatcher::checkSend() {
if (_mgr->getOutboundCount() == 0) return; // nothing waiting to send
if (!millisHasNowPassed(next_tx_time)) return; // still in 'radio silence' phase (from airtime budget setting)
if (_radio->isReceiving()) { // LBT - check if radio is currently mid-receive, or if channel activity
next_tx_time = futureMillis(getCADFailRetryDelay());
return;
if (cad_busy_start == 0) {
cad_busy_start = _ms->getMillis(); // record when CAD busy state started
}
if (_ms->getMillis() - cad_busy_start > getCADFailMaxDuration()) {
MESH_DEBUG_PRINTLN("%s Dispatcher::checkSend(): CAD busy max duration reached!", getLogDateTime());
// channel activity has gone on too long... (Radio might be in a bad state)
// force the pending transmit below...
} else {
next_tx_time = futureMillis(getCADFailRetryDelay());
return;
}
}
cad_busy_start = 0; // reset busy state
outbound = _mgr->getNextOutbound(_ms->getMillis());
if (outbound) {

View File

@@ -98,6 +98,7 @@ class Dispatcher {
Packet* outbound; // current outbound packet
unsigned long outbound_expiry, outbound_start, total_air_time;
unsigned long next_tx_time;
unsigned long cad_busy_start;
uint32_t n_sent_flood, n_sent_direct;
uint32_t n_recv_flood, n_recv_direct;
uint32_t n_full_events;
@@ -113,6 +114,7 @@ protected:
: _radio(&radio), _ms(&ms), _mgr(&mgr)
{
outbound = NULL; total_air_time = 0; next_tx_time = 0;
cad_busy_start = 0;
}
virtual DispatcherAction onRecvPacket(Packet* pkt) = 0;
@@ -127,6 +129,7 @@ protected:
virtual float getAirtimeBudgetFactor() const;
virtual int calcRxDelay(float score, uint32_t air_time) const;
virtual uint32_t getCADFailRetryDelay() const;
virtual uint32_t getCADFailMaxDuration() const;
public:
void begin();

View File

@@ -4,34 +4,6 @@
namespace mesh {
/**
* An abstraction of the device's Realtime Clock.
*/
class RTCClock {
uint32_t last_unique;
protected:
RTCClock() { last_unique = 0; }
public:
/**
* \returns the current time. in UNIX epoch seconds.
*/
virtual uint32_t getCurrentTime() = 0;
/**
* \param time current time in UNIX epoch seconds.
*/
virtual void setCurrentTime(uint32_t time) = 0;
uint32_t getCurrentTimeUnique() {
uint32_t t = getCurrentTime();
if (t <= last_unique) {
return ++last_unique;
}
return last_unique = t;
}
};
class GroupChannel {
public:
uint8_t hash[PATH_HASH_SIZE];

View File

@@ -42,7 +42,35 @@ public:
virtual void reboot() = 0;
virtual void powerOff() { /* no op */ }
virtual uint8_t getStartupReason() const = 0;
virtual bool startOTAUpdate() { return false; } // not supported
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
};
/**
* An abstraction of the device's Realtime Clock.
*/
class RTCClock {
uint32_t last_unique;
protected:
RTCClock() { last_unique = 0; }
public:
/**
* \returns the current time. in UNIX epoch seconds.
*/
virtual uint32_t getCurrentTime() = 0;
/**
* \param time current time in UNIX epoch seconds.
*/
virtual void setCurrentTime(uint32_t time) = 0;
uint32_t getCurrentTimeUnique() {
uint32_t t = getCurrentTime();
if (t <= last_unique) {
return ++last_unique;
}
return last_unique = t;
}
};
}

View File

@@ -229,6 +229,7 @@ void BaseChatMesh::onGroupDataRecv(mesh::Packet* packet, uint8_t type, const mes
mesh::Packet* BaseChatMesh::composeMsgPacket(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char *text, uint32_t& expected_ack) {
int text_len = strlen(text);
if (text_len > MAX_TEXT_LEN) return NULL;
if (attempt > 3 && text_len > MAX_TEXT_LEN-2) return NULL;
uint8_t temp[5+MAX_TEXT_LEN+1];
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
@@ -238,7 +239,13 @@ mesh::Packet* BaseChatMesh::composeMsgPacket(const ContactInfo& recipient, uint3
// calc expected ACK reply
mesh::Utils::sha256((uint8_t *)&expected_ack, 4, temp, 5 + text_len, self_id.pub_key, PUB_KEY_SIZE);
return createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, 5 + text_len);
int len = 5 + text_len;
if (attempt > 3) {
temp[len++] = 0; // null terminator
temp[len++] = attempt; // hide attempt number at tail end of payload
}
return createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, len);
}
int BaseChatMesh::sendMessage(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char* text, uint32_t& expected_ack, uint32_t& est_timeout) {

View File

@@ -14,57 +14,66 @@ static uint32_t _atoi(const char* sp) {
}
void CommonCLI::loadPrefs(FILESYSTEM* fs) {
if (fs->exists("/node_prefs")) {
File file = fs->open("/node_prefs");
if (file) {
uint8_t pad[8];
if (fs->exists("/com_prefs")) {
loadPrefsInt(fs, "/com_prefs"); // new filename
} else if (fs->exists("/node_prefs")) {
loadPrefsInt(fs, "/node_prefs");
savePrefs(fs); // save to new filename
fs->remove("/node_prefs"); // remove old
}
}
file.read((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
file.read((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4
file.read(pad, 4); // 36
file.read((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
file.read((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
file.read((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56
file.read((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72
file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
file.read((uint8_t *) &_prefs->unused, sizeof(_prefs->unused)); // 79
file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
file.read((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
file.read(pad, 4); // 108
file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112
file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113
file.read((uint8_t *) &_prefs->reserved1, sizeof(_prefs->reserved1)); // 114
file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
file.read(pad, 4); // 120
file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
File file = fs->open(filename);
if (file) {
uint8_t pad[8];
// sanitise bad pref values
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
_prefs->tx_delay_factor = constrain(_prefs->tx_delay_factor, 0, 2.0f);
_prefs->direct_tx_delay_factor = constrain(_prefs->direct_tx_delay_factor, 0, 2.0f);
_prefs->airtime_factor = constrain(_prefs->airtime_factor, 0, 9.0f);
_prefs->freq = constrain(_prefs->freq, 400.0f, 2500.0f);
_prefs->bw = constrain(_prefs->bw, 62.5f, 500.0f);
_prefs->sf = constrain(_prefs->sf, 7, 12);
_prefs->cr = constrain(_prefs->cr, 5, 8);
_prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30);
file.read((uint8_t *) &_prefs->airtime_factor, sizeof(_prefs->airtime_factor)); // 0
file.read((uint8_t *) &_prefs->node_name, sizeof(_prefs->node_name)); // 4
file.read(pad, 4); // 36
file.read((uint8_t *) &_prefs->node_lat, sizeof(_prefs->node_lat)); // 40
file.read((uint8_t *) &_prefs->node_lon, sizeof(_prefs->node_lon)); // 48
file.read((uint8_t *) &_prefs->password[0], sizeof(_prefs->password)); // 56
file.read((uint8_t *) &_prefs->freq, sizeof(_prefs->freq)); // 72
file.read((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
file.read((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
file.read((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
file.read((uint8_t *) pad, 1); // 79 was 'unused'
file.read((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
file.read((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
file.read((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
file.read((uint8_t *) &_prefs->direct_tx_delay_factor, sizeof(_prefs->direct_tx_delay_factor)); // 104
file.read(pad, 4); // 108
file.read((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112
file.read((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113
file.read((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
file.read((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
file.read((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
file.read(pad, 4); // 120
file.read((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.read((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.close();
}
// sanitise bad pref values
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
_prefs->tx_delay_factor = constrain(_prefs->tx_delay_factor, 0, 2.0f);
_prefs->direct_tx_delay_factor = constrain(_prefs->direct_tx_delay_factor, 0, 2.0f);
_prefs->airtime_factor = constrain(_prefs->airtime_factor, 0, 9.0f);
_prefs->freq = constrain(_prefs->freq, 400.0f, 2500.0f);
_prefs->bw = constrain(_prefs->bw, 62.5f, 500.0f);
_prefs->sf = constrain(_prefs->sf, 7, 12);
_prefs->cr = constrain(_prefs->cr, 5, 8);
_prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30);
file.close();
}
}
void CommonCLI::savePrefs(FILESYSTEM* fs) {
#if defined(NRF52_PLATFORM)
File file = fs->open("/node_prefs", FILE_O_WRITE);
File file = fs->open("/com_prefs", FILE_O_WRITE);
if (file) { file.seek(0); file.truncate(); }
#else
File file = fs->open("/node_prefs", "w", true);
File file = fs->open("/com_prefs", "w", true);
#endif
if (file) {
uint8_t pad[8];
@@ -80,7 +89,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *) &_prefs->tx_power_dbm, sizeof(_prefs->tx_power_dbm)); // 76
file.write((uint8_t *) &_prefs->disable_fwd, sizeof(_prefs->disable_fwd)); // 77
file.write((uint8_t *) &_prefs->advert_interval, sizeof(_prefs->advert_interval)); // 78
file.write((uint8_t *) &_prefs->unused, sizeof(_prefs->unused)); // 79
file.write((uint8_t *) pad, 1); // 79 was 'unused'
file.write((uint8_t *) &_prefs->rx_delay_base, sizeof(_prefs->rx_delay_base)); // 80
file.write((uint8_t *) &_prefs->tx_delay_factor, sizeof(_prefs->tx_delay_factor)); // 84
file.write((uint8_t *) &_prefs->guest_password[0], sizeof(_prefs->guest_password)); // 88
@@ -88,11 +97,12 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write(pad, 4); // 108
file.write((uint8_t *) &_prefs->sf, sizeof(_prefs->sf)); // 112
file.write((uint8_t *) &_prefs->cr, sizeof(_prefs->cr)); // 113
file.write((uint8_t *) &_prefs->reserved1, sizeof(_prefs->reserved1)); // 114
file.write((uint8_t *) &_prefs->allow_read_only, sizeof(_prefs->allow_read_only)); // 114
file.write((uint8_t *) &_prefs->reserved2, sizeof(_prefs->reserved2)); // 115
file.write((uint8_t *) &_prefs->bw, sizeof(_prefs->bw)); // 116
file.write(pad, 4); // 120
file.write((uint8_t *) &_prefs->flood_max, sizeof(_prefs->flood_max)); // 124
file.write((uint8_t *) &_prefs->flood_advert_interval, sizeof(_prefs->flood_advert_interval)); // 125
file.close();
}
@@ -129,9 +139,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
strcpy(reply, "ERR: clock cannot go backwards");
}
} else if (memcmp(command, "start ota", 9) == 0) {
if (_board->startOTAUpdate()) {
strcpy(reply, "OK");
} else {
if (!_board->startOTAUpdate(_prefs->node_name, reply)) {
strcpy(reply, "Error");
}
} else if (memcmp(command, "clock", 5) == 0) {
@@ -157,6 +165,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
const char* config = &command[4];
if (memcmp(config, "af", 2) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->airtime_factor));
} else if (memcmp(config, "allow.read.only", 15) == 0) {
sprintf(reply, "> %s", _prefs->allow_read_only ? "on" : "off");
} else if (memcmp(config, "flood.advert.interval", 21) == 0) {
sprintf(reply, "> %d", ((uint32_t) _prefs->flood_advert_interval));
} else if (memcmp(config, "advert.interval", 15) == 0) {
sprintf(reply, "> %d", ((uint32_t) _prefs->advert_interval) * 2);
} else if (memcmp(config, "guest.password", 14) == 0) {
@@ -186,6 +198,11 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
sprintf(reply, "> %d", (uint32_t) _prefs->tx_power_dbm);
} else if (memcmp(config, "freq", 4) == 0) {
sprintf(reply, "> %s", StrHelper::ftoa(_prefs->freq));
} else if (memcmp(config, "public.key", 10) == 0) {
strcpy(reply, "> ");
mesh::Utils::toHex(&reply[2], _mesh->self_id.pub_key, PUB_KEY_SIZE);
} else if (memcmp(config, "role", 4) == 0) {
sprintf(reply, "> %s", _callbacks->getRole());
} else {
sprintf(reply, "??: %s", config);
}
@@ -195,6 +212,22 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
_prefs->airtime_factor = atof(&config[3]);
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "allow.read.only ", 16) == 0) {
_prefs->allow_read_only = memcmp(&config[16], "on", 2) == 0;
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "flood.advert.interval ", 22) == 0) {
int hours = _atoi(&config[22]);
if (hours > 0 && hours < 3) {
sprintf(reply, "Error: min is 3 hours");
} else if (hours > 48) {
strcpy(reply, "Error: max is 48 hours");
} else {
_prefs->flood_advert_interval = (uint8_t)(hours);
_callbacks->updateFloodAdvertTimer();
savePrefs();
strcpy(reply, "OK");
}
} else if (memcmp(config, "advert.interval ", 16) == 0) {
int mins = _atoi(&config[16]);
if (mins > 0 && mins < MIN_LOCAL_ADVERT_INTERVAL) {

View File

@@ -11,8 +11,8 @@ struct NodePrefs { // persisted to file
float freq;
uint8_t tx_power_dbm;
uint8_t disable_fwd;
uint8_t advert_interval; // minutes
uint8_t unused;
uint8_t advert_interval; // minutes / 2
uint8_t flood_advert_interval; // hours
float rx_delay_base;
float tx_delay_factor;
char guest_password[16];
@@ -20,7 +20,7 @@ struct NodePrefs { // persisted to file
uint32_t guard;
uint8_t sf;
uint8_t cr;
uint8_t reserved1;
uint8_t allow_read_only;
uint8_t reserved2;
float bw;
uint8_t flood_max;
@@ -31,9 +31,11 @@ public:
virtual void savePrefs() = 0;
virtual const char* getFirmwareVer() = 0;
virtual const char* getBuildDate() = 0;
virtual const char* getRole() = 0;
virtual bool formatFileSystem() = 0;
virtual void sendSelfAdvertisement(int delay_millis) = 0;
virtual void updateAdvertTimer() = 0;
virtual void updateFloodAdvertTimer() = 0;
virtual void setLoggingOn(bool enable) = 0;
virtual void eraseLogFile() = 0;
virtual void dumpLogFile() = 0;
@@ -52,8 +54,10 @@ class CommonCLI {
void checkAdvertInterval();
void loadPrefsInt(FILESYSTEM* _fs, const char* filename);
public:
CommonCLI(mesh::MainBoard& board, mesh::Mesh* mesh, NodePrefs* prefs, CommonCLICallbacks* callbacks)
CommonCLI(mesh::MainBoard& board, mesh::Mesh* mesh, NodePrefs* prefs, CommonCLICallbacks* callbacks)
: _board(&board), _mesh(mesh), _prefs(prefs), _callbacks(callbacks) { }
void loadPrefs(FILESYSTEM* _fs);

View File

@@ -3,6 +3,7 @@
#include <RadioLib.h>
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
#define SX126X_IRQ_PREAMBLE_DETECTED 0x04
class CustomLLCC68 : public LLCC68 {
public:
@@ -10,7 +11,7 @@ class CustomLLCC68 : public LLCC68 {
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
return detected;
}
};

View File

@@ -11,7 +11,7 @@ class CustomLR1110 : public LR1110 {
bool isReceiving() {
uint16_t irq = getIrqStatus();
bool hasPreamble = ((irq & LR1110_IRQ_HEADER_VALID) && (irq & LR1110_IRQ_HAS_PREAMBLE));
return hasPreamble;
bool detected = ((irq & LR1110_IRQ_HEADER_VALID) || (irq & LR1110_IRQ_HAS_PREAMBLE));
return detected;
}
};

View File

@@ -3,6 +3,7 @@
#include <RadioLib.h>
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
#define SX126X_IRQ_PREAMBLE_DETECTED 0x04
class CustomSX1262 : public SX1262 {
public:
@@ -10,7 +11,7 @@ class CustomSX1262 : public SX1262 {
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
return detected;
}
};

View File

@@ -3,6 +3,7 @@
#include <RadioLib.h>
#define SX126X_IRQ_HEADER_VALID 0b0000010000 // 4 4 valid LoRa header received
#define SX126X_IRQ_PREAMBLE_DETECTED 0x04
class CustomSX1268 : public SX1268 {
public:
@@ -10,7 +11,7 @@ class CustomSX1268 : public SX1268 {
bool isReceiving() {
uint16_t irq = getIrqFlags();
bool hasPreamble = (irq & SX126X_IRQ_HEADER_VALID);
return hasPreamble;
bool detected = (irq & SX126X_IRQ_HEADER_VALID) || (irq & SX126X_IRQ_PREAMBLE_DETECTED);
return detected;
}
};

View File

@@ -0,0 +1,41 @@
#ifdef ESP_PLATFORM
#include "ESP32Board.h"
#if defined(ADMIN_PASSWORD) // Repeater or Room Server only
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>
bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
WiFi.softAP("MeshCore-OTA", NULL);
sprintf(reply, "Started: http://%s/update", WiFi.softAPIP().toString().c_str());
MESH_DEBUG_PRINTLN("startOTAUpdate: %s", reply);
static char id_buf[60];
sprintf(id_buf, "%s (%s)", id, getManufacturerName());
static char home_buf[90];
sprintf(home_buf, "<H2>Hi! I am a MeshCore Repeater. ID: %s</H2>", id);
AsyncWebServer* server = new AsyncWebServer(80);
server->on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "text/html", home_buf);
});
AsyncElegantOTA.setID(id_buf);
AsyncElegantOTA.begin(server); // Start ElegantOTA
server->begin();
return true;
}
#else
bool ESP32Board::startOTAUpdate(const char* id, char reply[]) {
return false; // not supported
}
#endif
#endif

View File

@@ -7,6 +7,7 @@
#include <rom/rtc.h>
#include <sys/time.h>
#include <Wire.h>
class ESP32Board : public mesh::MainBoard {
protected:
@@ -33,7 +34,9 @@ public:
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
#if PIN_BOARD_SDA >= 0 && PIN_BOARD_SCL >= 0
Wire.begin(PIN_BOARD_SDA, PIN_BOARD_SCL);
#endif
#else
Wire.begin();
#endif
@@ -73,6 +76,8 @@ public:
void reboot() override {
esp_restart();
}
bool startOTAUpdate(const char* id, char reply[]) override;
};
class ESP32RTCClock : public mesh::RTCClock {

View File

@@ -37,6 +37,8 @@ public:
power.setALDO2Voltage(3300);
power.enableALDO2();
pinMode(38,INPUT_PULLUP);
esp_reset_reason_t reason = esp_reset_reason();
if (reason == ESP_RST_DEEPSLEEP) {
long wakeup_source = esp_sleep_get_ext1_wakeup_status();

View File

@@ -0,0 +1,103 @@
#include "ESPNOWRadio.h"
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>
static uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static esp_now_peer_info_t peerInfo;
static bool is_send_complete = false;
static esp_err_t last_send_result;
static uint8_t rx_buf[256];
static uint8_t last_rx_len = 0;
// callback when data is sent
static void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
is_send_complete = true;
ESPNOW_DEBUG_PRINTLN("Send Status: %d", (int)status);
}
static void OnDataRecv(const uint8_t *mac, const uint8_t *data, int len) {
ESPNOW_DEBUG_PRINTLN("Recv: len = %d", len);
memcpy(rx_buf, data, len);
last_rx_len = len;
}
void ESPNOWRadio::begin() {
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Long Range mode
esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR);
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
ESPNOW_DEBUG_PRINTLN("Error initializing ESP-NOW");
return;
}
esp_wifi_set_max_tx_power(80); // should be 20dBm
esp_now_register_send_cb(OnDataSent);
esp_now_register_recv_cb(OnDataRecv);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) == ESP_OK) {
ESPNOW_DEBUG_PRINTLN("init success");
} else {
// ESPNOW_DEBUG_PRINTLN("Failed to add peer");
}
}
void ESPNOWRadio::setTxPower(uint8_t dbm) {
esp_wifi_set_max_tx_power(dbm * 4);
}
uint32_t ESPNOWRadio::intID() {
uint8_t mac[8];
memset(mac, 0, sizeof(mac));
esp_efuse_mac_get_default(mac);
uint32_t n, m;
memcpy(&n, &mac[0], 4);
memcpy(&m, &mac[4], 4);
return n + m;
}
void ESPNOWRadio::startSendRaw(const uint8_t* bytes, int len) {
// Send message via ESP-NOW
is_send_complete = false;
esp_err_t result = esp_now_send(broadcastAddress, bytes, len);
if (result == ESP_OK) {
ESPNOW_DEBUG_PRINTLN("Send success");
} else {
last_send_result = result;
is_send_complete = true;
ESPNOW_DEBUG_PRINTLN("Send failed: %d", result);
}
}
bool ESPNOWRadio::isSendComplete() {
return is_send_complete;
}
void ESPNOWRadio::onSendFinished() {
}
float ESPNOWRadio::getLastRSSI() const { return 0; }
float ESPNOWRadio::getLastSNR() const { return 0; }
int ESPNOWRadio::recvRaw(uint8_t* bytes, int sz) {
int len = last_rx_len;
if (last_rx_len > 0) {
memcpy(bytes, rx_buf, last_rx_len);
last_rx_len = 0;
}
return len;
}
uint32_t ESPNOWRadio::getEstAirtimeFor(int len_bytes) {
return 4; // Fast AF
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <Mesh.h>
class ESPNOWRadio : public mesh::Radio {
protected:
uint32_t n_recv, n_sent;
public:
ESPNOWRadio() { n_recv = n_sent = 0; }
void begin() override;
int recvRaw(uint8_t* bytes, int sz) override;
uint32_t getEstAirtimeFor(int len_bytes) override;
void startSendRaw(const uint8_t* bytes, int len) override;
bool isSendComplete() override;
void onSendFinished() override;
uint32_t getPacketsRecv() const { return n_recv; }
uint32_t getPacketsSent() const { return n_sent; }
virtual float getLastRSSI() const override;
virtual float getLastSNR() const override;
float packetScore(float snr, int packet_len) override { return 0; }
uint32_t intID();
void setTxPower(uint8_t dbm);
};
#if ESPNOW_DEBUG_LOGGING && ARDUINO
#include <Arduino.h>
#define ESPNOW_DEBUG_PRINT(F, ...) Serial.printf("ESP-Now: " F, ##__VA_ARGS__)
#define ESPNOW_DEBUG_PRINTLN(F, ...) Serial.printf("ESP-Now: " F "\n", ##__VA_ARGS__)
#else
#define ESPNOW_DEBUG_PRINT(...) {}
#define ESPNOW_DEBUG_PRINTLN(...) {}
#endif

View File

@@ -1,24 +1,45 @@
#include <Arduino.h>
#include "faketecBoard.h"
#include "FaketecBoard.h"
#include <bluefruit.h>
#include <Wire.h>
static BLEDfu bledfu;
void FaketecBoard::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
btn_prev_state = HIGH;
pinMode(PIN_VBAT_READ, INPUT);
#ifdef BUTTON_PIN
pinMode(BUTTON_PIN, INPUT);
#endif
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}
static void connect_callback(uint16_t conn_handle) {
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
(void)conn_handle;
MESH_DEBUG_PRINTLN("BLE client connected");
}
static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
(void)conn_handle;
(void)reason;
MESH_DEBUG_PRINTLN("BLE client disconnected");
}
bool faketecBoard::startOTAUpdate() {
bool FaketecBoard::startOTAUpdate(const char* id, char reply[]) {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
@@ -57,5 +78,6 @@ bool faketecBoard::startOTAUpdate() {
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started");
return true;
}

View File

@@ -2,7 +2,6 @@
#include <MeshCore.h>
#include <Arduino.h>
#include <Wire.h>
#define P_LORA_NSS 13 //P1.13 45
#define P_LORA_DIO_1 11 //P0.10 10
@@ -20,27 +19,13 @@
#define PIN_VBAT_READ 17
#define ADC_MULTIPLIER (1.815f) // dependent on voltage divider resistors. TODO: more accurate battery tracking
class faketecBoard : public mesh::MainBoard {
class FaketecBoard : public mesh::MainBoard {
protected:
uint8_t startup_reason;
uint8_t btn_prev_state;
public:
void begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
pinMode(PIN_VBAT_READ, INPUT);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
Wire.begin();
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, HIGH);
delay(10); // give sx1262 some time to power up
}
void begin();
uint8_t getStartupReason() const override { return startup_reason; }
@@ -61,9 +46,20 @@ public:
return "Faketec DIY";
}
int buttonStateChanged() {
#ifdef BUTTON_PIN
uint8_t v = digitalRead(BUTTON_PIN);
if (v != btn_prev_state) {
btn_prev_state = v;
return (v == LOW) ? 1 : -1;
}
#endif
return 0;
}
void reboot() override {
NVIC_SystemReset();
}
bool startOTAUpdate() override;
bool startOTAUpdate(const char* id, char reply[]) override;
};

View File

@@ -37,7 +37,7 @@ void RAK4631Board::begin() {
delay(10); // give sx1262 some time to power up
}
bool RAK4631Board::startOTAUpdate() {
bool RAK4631Board::startOTAUpdate(const char* id, char reply[]) {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
@@ -76,5 +76,6 @@ bool RAK4631Board::startOTAUpdate() {
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started");
return true;
}

View File

@@ -50,5 +50,5 @@ public:
NVIC_SystemReset();
}
bool startOTAUpdate() override;
bool startOTAUpdate(const char* id, char reply[]) override;
};

View File

@@ -9,6 +9,8 @@ void T1000eBoard::begin() {
startup_reason = BD_STARTUP_NORMAL;
btn_prev_state = HIGH;
sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
#ifdef BUTTON_PIN
pinMode(BATTERY_PIN, INPUT);
pinMode(BUTTON_PIN, INPUT);
@@ -40,7 +42,7 @@ static void disconnect_callback(uint16_t conn_handle, uint8_t reason) {
}
bool TrackerT1000eBoard::startOTAUpdate() {
bool TrackerT1000eBoard::startOTAUpdate(const char* id, char reply[]) {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
@@ -79,6 +81,7 @@ bool TrackerT1000eBoard::startOTAUpdate() {
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started");
return true;
}
#endif

View File

@@ -90,5 +90,5 @@ public:
NVIC_SystemReset();
}
// bool startOTAUpdate() override;
// bool startOTAUpdate(const char* id, char reply[]) override;
};

View File

@@ -42,7 +42,7 @@ void T114Board::begin() {
delay(10); // give sx1262 some time to power up
}
bool T114Board::startOTAUpdate() {
bool T114Board::startOTAUpdate(const char* id, char reply[]) {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
@@ -81,5 +81,6 @@ bool T114Board::startOTAUpdate() {
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started");
return true;
}

View File

@@ -18,7 +18,8 @@
// built-ins
#define PIN_VBAT_READ 4
#define ADC_MULTIPLIER (3 * 1.73 * 1.187 * 1000)
#define PIN_BAT_CTL 6
#define MV_LSB (3000.0F / 4096.0F) // 12-bit ADC with 3.0V input range
class T114Board : public mesh::MainBoard {
protected:
@@ -37,17 +38,18 @@ public:
}
#endif
#define BATTERY_SAMPLES 8
uint16_t getBattMilliVolts() override {
int adcvalue = 0;
analogReadResolution(12);
uint32_t raw = 0;
for (int i = 0; i < BATTERY_SAMPLES; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / BATTERY_SAMPLES;
analogReference(AR_INTERNAL_3_0);
pinMode(PIN_BAT_CTL, OUTPUT); // battery adc can be read only ctrl pin 6 set to high
digitalWrite(PIN_BAT_CTL, 1);
return (ADC_MULTIPLIER * raw) / 4096;
delay(10);
adcvalue = analogRead(PIN_VBAT_READ);
digitalWrite(6, 0);
return (uint16_t)((float)adcvalue * MV_LSB * 4.9);
}
const char* getManufacturerName() const override {
@@ -58,5 +60,5 @@ public:
NVIC_SystemReset();
}
bool startOTAUpdate() override;
bool startOTAUpdate(const char* id, char reply[]) override;
};

View File

@@ -1,6 +1,8 @@
#include <Arduino.h>
#include "TechoBoard.h"
#ifdef LILYGO_TECHO
#include <bluefruit.h>
#include <Wire.h>
@@ -22,11 +24,18 @@ void TechoBoard::begin() {
// for future use, sub-classes SHOULD call this from their begin()
startup_reason = BD_STARTUP_NORMAL;
pinMode(PIN_VBAT_READ, INPUT);
delay(200);
pinMode(PIN_PWR_EN, OUTPUT);
digitalWrite(PIN_PWR_EN, HIGH);
pinMode(PIN_BUTTON1, INPUT_PULLUP);
pinMode(PIN_BUTTON2, INPUT_PULLUP);
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
delay(200);
#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL)
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL)
#endif
pinMode(PIN_TXCO, OUTPUT);
digitalWrite(PIN_TXCO, HIGH);
Wire.begin();
@@ -35,7 +44,21 @@ void TechoBoard::begin() {
delay(10); // give sx1262 some time to power up
}
bool TechoBoard::startOTAUpdate() {
uint16_t TechoBoard::getBattMilliVolts() {
int adcvalue = 0;
analogReference(AR_INTERNAL_3_0);
analogReadResolution(12);
delay(10);
// ADC range is 0..3000mV and resolution is 12-bit (0..4095)
adcvalue = analogRead(PIN_VBAT_READ);
// Convert the raw value to compensated mv, taking the resistor-
// divider into account (providing the actual LIPO voltage)
return (uint16_t)((float)adcvalue * REAL_VBAT_MV_PER_LSB);
}
bool TechoBoard::startOTAUpdate(const char* id, char reply[]) {
// Config the peripheral connection with maximum bandwidth
// more SRAM required by SoftDevice
// Note: All config***() function must be called before begin()
@@ -74,5 +97,7 @@ bool TechoBoard::startOTAUpdate() {
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
strcpy(reply, "OK - started");
return true;
}
#endif

View File

@@ -17,28 +17,26 @@
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// built-ins
#define PIN_VBAT_READ 4
#define ADC_MULTIPLIER (2.0)
#define VBAT_MV_PER_LSB (0.73242188F) // 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
#define VBAT_DIVIDER (0.5F) // 150K + 150K voltage divider on VBAT
#define VBAT_DIVIDER_COMP (2.0F) // Compensation factor for the VBAT divider
#define PIN_VBAT_READ (4)
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
class TechoBoard : public mesh::MainBoard {
protected:
uint8_t startup_reason;
public:
void begin();
uint8_t getStartupReason() const override { return startup_reason; }
uint16_t getBattMilliVolts() override;
bool startOTAUpdate(const char* id, char reply[]) override;
#define BATTERY_SAMPLES 8
uint16_t getBattMilliVolts() override {
analogReadResolution(12);
uint32_t raw = 0;
for (int i = 0; i < BATTERY_SAMPLES; i++) {
raw += analogRead(PIN_VBAT_READ);
}
raw = raw / BATTERY_SAMPLES;
return (ADC_MULTIPLIER * raw) / 4096;
uint8_t getStartupReason() const override {
return startup_reason;
}
const char* getManufacturerName() const override {
@@ -48,6 +46,4 @@ public:
void reboot() override {
NVIC_SystemReset();
}
bool startOTAUpdate() override;
};

View File

@@ -0,0 +1,83 @@
; ----------- Generic ESP32-C3 ------------
[Generic_ESPNOW]
extends = esp32_base
board = esp32-c3-devkitm-1
;board = esp32-s3-devkitm-1
build_flags =
${esp32_base.build_flags}
-I variants/generic_espnow
; -D ESP32_CPU_FREQ=80
-D PIN_BOARD_SDA=-1
-D PIN_BOARD_SCL=-1
; -D P_LORA_TX_LED=8
-D PIN_USER_BTN=0
; -D ARDUINO_USB_MODE=1
; -D ARDUINO_USB_CDC_ON_BOOT=1
; -D ESPNOW_DEBUG_LOGGING=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${esp32_base.build_src_filter}
+<helpers/esp32/ESPNowRadio.cpp>
+<../variants/generic_espnow>
[env:Generic_ESPNOW_terminal_chat]
extends = Generic_ESPNOW
build_flags =
${Generic_ESPNOW.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
build_src_filter = ${Generic_ESPNOW.build_src_filter}
+<../examples/simple_secure_chat/main.cpp>
lib_deps =
${Generic_ESPNOW.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Generic_ESPNOW_repeatr]
extends = Generic_ESPNOW
build_flags =
${Generic_ESPNOW.build_flags}
-D ADVERT_NAME='"ESPNOW Repeater"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
build_src_filter = ${Generic_ESPNOW.build_src_filter}
+<../examples/simple_repeater/main.cpp>
lib_deps =
${Generic_ESPNOW.lib_deps}
${esp32_ota.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Generic_ESPNOW_comp_radio_usb]
extends = Generic_ESPNOW
build_flags =
${Generic_ESPNOW.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D ENABLE_PRIVATE_KEY_IMPORT=1
; -D ENABLE_PRIVATE_KEY_EXPORT=1
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
; NOTE: DO NOT ENABLE --> -D ESPNOW_DEBUG_LOGGING=1
build_src_filter = ${Generic_ESPNOW.build_src_filter}
+<../examples/companion_radio/main.cpp>
lib_deps =
${Generic_ESPNOW.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:Generic_ESPNOW_room_svr]
extends = Generic_ESPNOW
build_flags =
${Generic_ESPNOW.build_flags}
-D ADVERT_NAME='"Heltec Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
build_src_filter = ${Generic_ESPNOW.build_src_filter}
+<../examples/simple_room_server/main.cpp>
lib_deps =
${Generic_ESPNOW.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,33 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
ESP32Board board;
ESPNOWRadio radio_driver;
ESP32RTCClock rtc_clock;
bool radio_init() {
rtc_clock.begin();
// NOTE: radio_driver.begin() is called by Dispatcher::begin(), so not needed here
return true; // success
}
uint32_t radio_get_rng_seed() {
return millis() + radio_driver.intID(); // TODO: where to get some entropy?
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
// no-op
}
void radio_set_tx_power(uint8_t dbm) {
radio_driver.setTxPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
StdRNG rng; // TODO: need stronger True-RNG here
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <helpers/ESP32Board.h>
#include <helpers/esp32/ESPNOWRadio.h>
extern ESP32Board board;
extern ESPNOWRadio radio_driver;
extern ESP32RTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -3,6 +3,7 @@ extends = esp32_base
board = heltec_wifi_lora_32_V2 ; heltec_wifi_lora_32_V2
build_flags =
${esp32_base.build_flags}
-I variants/heltec_v2
-D HELTEC_LORA_V2
-D PIN_BOARD_SDA=4
-D PIN_BOARD_SCL=15
@@ -13,6 +14,7 @@ build_flags =
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=25
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/heltec_v2>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
@@ -31,6 +33,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<../examples/simple_repeater>
+<helpers/ui/*.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_v2_room_server]
extends = Heltec_lora32_v2
@@ -47,6 +52,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_lora32_v2.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_v2_terminal_chat]
extends = Heltec_lora32_v2

View File

@@ -0,0 +1,59 @@
#include <Arduino.h>
#include "target.h"
HeltecV2Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/HeltecV2Board.h>
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern HeltecV2Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -3,6 +3,7 @@ extends = esp32_base
board = esp32-s3-devkitc-1
build_flags =
${esp32_base.build_flags}
-I variants/heltec_v3
-D HELTEC_LORA_V3
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
@@ -16,6 +17,7 @@ build_flags =
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/heltec_v3>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
@@ -34,6 +36,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_v3_room_server]
extends = Heltec_lora32_v3
@@ -50,6 +55,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_v3_terminal_chat]
extends = Heltec_lora32_v3
@@ -138,6 +146,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<../examples/simple_repeater>
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_WSL3_room_server]
extends = Heltec_lora32_v3
@@ -152,6 +163,9 @@ build_flags =
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
[env:Heltec_WSL3_companion_radio_ble]
extends = Heltec_lora32_v3

View File

@@ -0,0 +1,75 @@
#include <Arduino.h>
#include "target.h"
HeltecV3Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/HeltecV3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern HeltecV3Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -3,6 +3,7 @@ extends = esp32_base
board = t3_s3_v1_x
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_t3s3
-D LILYGO_T3S3
-D P_LORA_DIO_1=33
-D P_LORA_NSS=7
@@ -26,6 +27,7 @@ build_flags =
-D LORA_TX_POWER=22
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_t3s3>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
@@ -45,6 +47,9 @@ build_flags =
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_repeater>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
${esp32_ota.lib_deps}
[env:LilyGo_T3S3_sx1262_terminal_chat]
extends = LilyGo_T3S3_sx1262
@@ -75,6 +80,9 @@ build_flags =
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/*.cpp>
+<../examples/simple_room_server>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
${esp32_ota.lib_deps}
[env:LilyGo_T3S3_sx1262_companion_radio_usb]
extends = LilyGo_T3S3_sx1262

View File

@@ -0,0 +1,75 @@
#include <Arduino.h>
#include "target.h"
ESP32Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern ESP32Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -3,19 +3,29 @@ extends = esp32_base
board = ttgo-t-beam
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam
-D LILYGO_TBEAM
-D RADIO_CLASS=CustomSX1276
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
-D P_LORA_TX_LED=4
-D PIN_BOARD_SDA=21
-D PIN_BOARD_SCL=22
-D PIN_USER_BTN=38
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tbeam>
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
lib_deps =
${esp32_base.lib_deps}
lewisxhe/XPowersLib@^0.2.7
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:Tbeam_companion_radio_ble]
extends = LilyGo_TBeam
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=1
-D BLE_PIN_CODE=123456
@@ -29,8 +39,8 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio/main.cpp>
+<helpers/ui/*.cpp>
+<../examples/companion_radio>
lib_deps =
${LilyGo_TBeam.lib_deps}
densaugeo/base64 @ ~1.4.0
lewisxhe/XPowersLib@^0.2.7
densaugeo/base64 @ ~1.4.0

View File

@@ -0,0 +1,59 @@
#include <Arduino.h>
#include "target.h"
TBeamBoard board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/TBeamBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern TBeamBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -6,6 +6,7 @@ build_type = release ; Set build type to release
board_build.partitions = min_spiffs.csv ; get around 4mb flash limit
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tlora_v2_1
-Os -ffunction-sections -fdata-sections ; Optimize for size
-D LILYGO_TLORA ; LILYGO T-LoRa V2.1-1.6 ESP32 with SX1276
-D P_LORA_DIO_0=26 ; SX1276 DIO0 interrupt pin
@@ -23,6 +24,8 @@ build_flags =
-D DISPLAY_CLASS=SSD1306Display
-D WRAPPER_CLASS=CustomSX1276Wrapper
-D LORA_TX_POWER=20
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/lilygo_tlora_v2_1>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
@@ -42,6 +45,9 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
; -D CORE_DEBUG_LEVEL=3
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
${esp32_ota.lib_deps}
[env:LilyGo_TLora_V2_1_1_6_terminal_chat]
extends = LilyGo_TLora_V2_1_1_6
@@ -109,3 +115,6 @@ build_flags =
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,53 @@
#include <Arduino.h>
#include "target.h"
LilyGoTLoraBoard board;
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi);
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/LilyGoTLoraBoard.h>
#include <helpers/CustomSX1276Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern LilyGoTLoraBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -1,18 +1,29 @@
[faketec]
extends = nrf52840_base
board = promicro_nrf52840
build_src_filter = ${nrf52840_base.build_src_filter} +<helpers/nrf52/faketecBoard.cpp>
build_flags = ${nrf52840_base.build_flags}
-I variants/promicro
-D FAKETEC
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
-D DISPLAY_CLASS=SSD1306Display
-D PIN_BOARD_SCL=7
-D PIN_BOARD_SDA=8
-D PIN_OLED_RESET=-1
-D PIN_USER_BTN=6
build_src_filter = ${nrf52840_base.build_src_filter}
+<helpers/nrf52/FaketecBoard.cpp>
+<../variants/promicro>
lib_deps=
${nrf52840_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:Faketec_Repeater]
extends = faketec
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_repeater/main.cpp>
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_repeater> +<helpers/ui/*.cpp>
build_flags =
${faketec.build_flags}
-D ADVERT_NAME="\"Faketec Repeater\""
@@ -27,7 +38,7 @@ lib_deps =
[env:Faketec_room_server]
extends = faketec
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_room_server/main.cpp>
build_src_filter = ${faketec.build_src_filter} +<../examples/simple_room_server> +<helpers/ui/*.cpp>
build_flags =
${faketec.build_flags}
-D ADVERT_NAME="\"Test Room\""
@@ -63,7 +74,7 @@ build_flags =
-D MAX_GROUP_CHANNELS=8
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${faketec.build_src_filter} +<../examples/companion_radio/main.cpp>
build_src_filter = ${faketec.build_src_filter} +<../examples/companion_radio> +<../examples/companion_radio> +<helpers/ui/*.cpp>
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
@@ -81,7 +92,7 @@ build_flags =
-D ENABLE_PRIVATE_KEY_IMPORT=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${faketec.build_src_filter} +<helpers/nrf52/SerialBLEInterface.cpp> +<../examples/companion_radio/main.cpp>
build_src_filter = ${faketec.build_src_filter} +<helpers/nrf52/SerialBLEInterface.cpp> +<../examples/companion_radio> +<helpers/ui/*.cpp>
lib_deps =
${faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
@@ -90,14 +101,17 @@ lib_deps =
[ProMicroLLCC68]
extends = nrf52840_base
board = promicro_nrf52840
build_src_filter = ${nrf52840_base.build_src_filter} +<helpers/nrf52/faketecBoard.cpp>
build_flags = ${nrf52840_base.build_flags}
-I variants/promicro
-D FAKETEC
-D RADIO_CLASS=CustomLLCC68
-D WRAPPER_CLASS=CustomLLCC68Wrapper
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=130
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_base.build_src_filter}
+<helpers/nrf52/FaketecBoard.cpp>
+<../variants/promicro>
[env:ProMicroLLCC68_Repeater]
extends = ProMicroLLCC68

View File

@@ -0,0 +1,74 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
FaketecBoard board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
#define SX126X_DIO3_TCXO_VOLTAGE (0.0f);
tcxo = SX126X_DIO3_TCXO_VOLTAGE;
status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
}
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,19 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/FaketecBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomLLCC68Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern FaketecBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -4,6 +4,7 @@ platform = https://github.com/maxgerhardt/platform-nordicnrf52.git#rak
board = wiscore_rak4631
board_check = true
build_flags = ${nrf52840_base.build_flags}
-I variants/rak4631
-D RAK_4631
-D PIN_USER_BTN=9
-D RADIO_CLASS=CustomSX1262
@@ -13,6 +14,7 @@ build_flags = ${nrf52840_base.build_flags}
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${nrf52840_base.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../variants/rak4631>
lib_deps =
${nrf52840_base.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13

View File

@@ -0,0 +1,69 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
RAK4631Board board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

18
variants/rak4631/target.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/RAK4631Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern RAK4631Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -3,6 +3,7 @@ extends = esp32_base
board = station-g2
build_flags =
${esp32_base.build_flags}
-I variants/station_g2
-D STATION_G2
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
@@ -16,8 +17,8 @@ build_flags =
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
; -D SX126X_RX_BOOSTED_GAIN=1 - DO NOT ENABLE THIS!
; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/station_g2>
lib_deps =
${esp32_base.lib_deps}
@@ -33,6 +34,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Station_G2.build_src_filter}
+<../examples/simple_repeater>
lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}
[env:Station_G2_room_server]
extends = Station_G2
@@ -47,3 +51,6 @@ build_flags =
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,75 @@
#include <Arduino.h>
#include "target.h"
StationG2Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/StationG2Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern StationG2Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -19,14 +19,14 @@ extends = nrf52840_t1000e
board = tracker-t1000-e
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52840_t1000e.build_flags}
-Ivariants/t1000-e
-I variants/t1000-e
-D T1000_E
-D PIN_USER_BTN=6
-D USER_BTN_PRESSED=HIGH
-D PIN_STATUS_LED=24
-D RADIO_CLASS=CustomLR1110
-D WRAPPER_CLASS=CustomLR1110Wrapper
-D MAX_LORA_TX_POWER=22
-D LORA_TX_POWER=22
build_src_filter = ${nrf52840_t1000e.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/T1000eBoard.cpp>
@@ -43,6 +43,8 @@ build_flags = ${t1000-e.build_flags}
-D BLE_DEBUG_LOGGING=1
-D MESH_PACKET_LOGGING=1
-D MESH_DEBUG=1
-D RX_BOOSTED_GAIN=true
-D RF_SWITCH_TABLE
-D HAS_UI
build_src_filter = ${t1000-e.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>

View File

@@ -0,0 +1,88 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
T1000eBoard board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
#ifdef RF_SWITCH_TABLE
static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = {
RADIOLIB_LR11X0_DIO5,
RADIOLIB_LR11X0_DIO6,
RADIOLIB_LR11X0_DIO7,
RADIOLIB_LR11X0_DIO8,
RADIOLIB_NC
};
static const Module::RfSwitchMode_t rfswitch_table[] = {
// mode DIO5 DIO6 DIO7 DIO8
{ LR11x0::MODE_STBY, {LOW, LOW, LOW, LOW }},
{ LR11x0::MODE_RX, {HIGH, LOW, LOW, HIGH }},
{ LR11x0::MODE_TX, {HIGH, HIGH, LOW, HIGH }},
{ LR11x0::MODE_TX_HP, {LOW, HIGH, LOW, HIGH }},
{ LR11x0::MODE_TX_HF, {LOW, LOW, LOW, LOW }},
{ LR11x0::MODE_GNSS, {LOW, LOW, HIGH, LOW }},
{ LR11x0::MODE_WIFI, {LOW, LOW, LOW, LOW }},
END_OF_MODE_TABLE,
};
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef LR11X0_DIO3_TCXO_VOLTAGE
float tcxo = LR11X0_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef RF_SWITCH_TABLE
radio.setRfSwitchTable(rfswitch_dios, rfswitch_table);
#endif
#ifdef RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

18
variants/t1000-e/target.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/T1000eBoard.h>
#include <helpers/CustomLR1110Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern T1000eBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -14,7 +14,7 @@ extends = nrf52840_t114
board = heltec_t114
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_t114.build_flags}
-Ivariants/t114
-I variants/t114
-DHELTEC_T114
-D P_LORA_TX_LED=35
-D RADIO_CLASS=CustomSX1262

69
variants/t114/target.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
T114Board board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

18
variants/t114/target.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/T114Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern T114Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -14,7 +14,7 @@ extends = nrf52840_techo
board = t-echo
board_build.ldscript = boards/nrf52840_s140_v6.ld
build_flags = ${nrf52840_techo.build_flags}
-Ivariants/techo
-I variants/techo
-DLILYGO_TECHO
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper

69
variants/techo/target.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
TechoBoard board;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
WRAPPER_CLASS radio_driver(radio, board);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
SPI.begin();
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

18
variants/techo/target.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/nrf52/TechoBoard.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern TechoBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -14,12 +14,12 @@
#define USE_LFXO // 32.768 kHz crystal oscillator
#define VARIANT_MCK (64000000ul)
#define WIRE_INTERFACES_COUNT (1)
#define WIRE_INTERFACES_COUNT (1)
#define PIN_TXCO (21)
////////////////////////////////////////////////////////////////////////////////
// Power
#define PIN_PWR_EN (6)
#define PIN_PWR_EN (12)
#define BATTERY_PIN (4)
#define ADC_MULTIPLIER (4.90F)
@@ -62,11 +62,11 @@
////////////////////////////////////////////////////////////////////////////////
// Builtin LEDs
#define LED_RED (13)
#define LED_RED (34)
#define LED_GREEN (33)
#define LED_BLUE (14)
#define LED_GREEN (15)
#define LED_BUILTIN (15)
#define LED_BUILTIN LED_GREEN
#define PIN_LED LED_BUILTIN
#define LED_PIN LED_BUILTIN
#define LED_STATE_ON LOW
@@ -80,7 +80,7 @@
#define PIN_BUTTON1 (42)
#define BUTTON_PIN PIN_BUTTON1
#define PIN_BUTTON2 (18)
#define PIN_BUTTON2 (11)
#define BUTTON_PIN2 PIN_BUTTON2
#define EXTERNAL_FLASH_DEVICES MX25R1635F

View File

@@ -3,6 +3,7 @@ extends = esp32_base
board = seeed_xiao_esp32c3
build_flags =
${esp32_base.build_flags}
-I variants/xiao_c3
-D LORA_TX_BOOST_PIN=D3
-D P_LORA_TX_LED=D5
-D PIN_VBAT_READ=D0
@@ -15,6 +16,8 @@ build_flags =
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=130.0f ; for best TX power!
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/xiao_c3>
[env:Xiao_C3_Repeater_sx1262]
extends = Xiao_esp32_C3
@@ -32,6 +35,9 @@ build_flags =
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Xiao_esp32_C3.lib_deps}
${esp32_ota.lib_deps}
[env:Xiao_C3_Repeater_sx1268]
extends = Xiao_esp32_C3
@@ -48,3 +54,6 @@ build_flags =
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Xiao_esp32_C3.lib_deps}
${esp32_ota.lib_deps}

View File

@@ -0,0 +1,75 @@
#include <Arduino.h>
#include "target.h"
XiaoC3Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

19
variants/xiao_c3/target.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/XiaoC3Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/CustomSX1268Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern XiaoC3Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();

View File

@@ -4,6 +4,7 @@ board = seeed_xiao_esp32s3
board_check = true
board_build.mcu = esp32s3
build_flags = ${esp32_base.build_flags}
-I variants/xiao_s3_wio
-D SEEED_XIAO_S3
-D P_LORA_DIO_1=39
-D P_LORA_NSS=41
@@ -19,6 +20,8 @@ build_flags = ${esp32_base.build_flags}
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D SX126X_RX_BOOSTED_GAIN=1
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/xiao_s3_wio>
[env:Xiao_S3_WIO_Repeater]
extends = Xiao_S3_WIO
@@ -32,6 +35,26 @@ build_flags =
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Xiao_S3_WIO.lib_deps}
${esp32_ota.lib_deps}
[env:Xiao_S3_WIO_room_server]
extends = Xiao_S3_WIO
build_src_filter = ${Xiao_S3_WIO.build_src_filter}
+<../examples/simple_room_server>
build_flags =
${Xiao_S3_WIO.build_flags}
-D ADVERT_NAME='"XiaoS3 Room"'
-D ADVERT_LAT=-37.0
-D ADVERT_LON=145.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
lib_deps =
${Xiao_S3_WIO.lib_deps}
${esp32_ota.lib_deps}
[env:Xiao_S3_WIO_terminal_chat]
extends = Xiao_S3_WIO

View File

@@ -0,0 +1,75 @@
#include <Arduino.h>
#include "target.h"
ESP32Board board;
#if defined(P_LORA_SCLK)
static SPIClass spi;
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
#else
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
#endif
WRAPPER_CLASS radio_driver(radio, board);
ESP32RTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifndef LORA_CR
#define LORA_CR 5
#endif
bool radio_init() {
fallback_clock.begin();
rtc_clock.begin(Wire);
#ifdef SX126X_DIO3_TCXO_VOLTAGE
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
#else
float tcxo = 1.6f;
#endif
#if defined(P_LORA_SCLK)
spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI);
#endif
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
if (status != RADIOLIB_ERR_NONE) {
Serial.print("ERROR: radio init failed: ");
Serial.println(status);
return false; // fail
}
radio.setCRC(1);
#ifdef SX126X_CURRENT_LIMIT
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
#endif
#ifdef SX126X_DIO2_AS_RF_SWITCH
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
#endif
#ifdef SX126X_RX_BOOSTED_GAIN
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
#endif
return true; // success
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View File

@@ -0,0 +1,18 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/RadioLibWrappers.h>
#include <helpers/ESP32Board.h>
#include <helpers/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
extern ESP32Board board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(uint8_t dbm);
mesh::LocalIdentity radio_new_identity();