Merge pull request #2 from Quency-D/dev

Merging changes
This commit is contained in:
Quency-D 2025-08-28 15:36:59 +08:00 committed by GitHub
commit bb63f8165d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
112 changed files with 1873 additions and 271 deletions

View file

@ -3,6 +3,7 @@
# usage
# sh build.sh build-firmware RAK_4631_Repeater
# sh build.sh build-firmwares
# sh build.sh build-matching-firmwares RAK_4631
# sh build.sh build-companion-firmwares
# sh build.sh build-repeater-firmwares
# sh build.sh build-room-server-firmwares
@ -144,6 +145,16 @@ mkdir -p out
if [[ $1 == "build-firmware" ]]; then
if [ "$2" ]; then
build_firmware $2
else
echo "usage: $0 build-firmware <target>"
exit 1
fi
elif [[ $1 == "build-matching-firmwares" ]]; then
if [ "$2" ]; then
build_all_firmwares_matching $2
else
echo "usage: $0 build-matching-firmwares <build-match-spec>"
exit 1
fi
elif [[ $1 == "build-firmwares" ]]; then
build_firmwares

64
build_as_lib.py Normal file
View file

@ -0,0 +1,64 @@
from os.path import realpath
Import("env") # type: ignore
menv=env # type: ignore
src_filter = [
'+<*.cpp>',
'+<helpers/*.cpp>',
'+<helpers/sensors>',
'+<helpers/radiolib/*.cpp>',
'+<helpers/ui/MomentaryButton.cpp>',
'+<helpers/ui/buzzer.cpp>',
]
# add build and include dirs according to CPPDEFINES
for item in menv.get("CPPDEFINES", []):
# PLATFORM HANDLING
if item == "STM32_PLATFORM":
src_filter.append("+<helpers/stm32/*>")
elif item == "ESP32":
src_filter.append("+<helpers/esp32/*>")
elif item == "NRF52_PLATFORM":
src_filter.append("+<helpers/nrf52/*>")
elif item == "RP2040_PLATFORM":
src_filter.append("+<helpers/rp2040/*>")
# DISPLAY HANDLING
elif isinstance(item, tuple) and item[0] == "DISPLAY_CLASS":
display_class = item[1]
src_filter.append(f"+<helpers/ui/{display_class}.cpp>")
if (display_class == "ST7789Display") :
src_filter.append(f"+<helpers/ui/OLEDDisplay.cpp>")
src_filter.append(f"+<helpers/ui/OLEDDisplayFonts.cpp>")
# VARIANTS HANDLING
elif isinstance(item, tuple) and item[0] == "MC_VARIANT":
variant_name = item[1]
src_filter.append(f"+<../variants/{variant_name}>")
# INCLUDE EXAMPLE CODE IN BUILD (to provide your own support files without touching the tree)
elif isinstance(item, tuple) and item[0] == "BUILD_EXAMPLE":
example_name = item[1]
src_filter.append(f"+<../examples/{example_name}/*.cpp>")
# EXCLUDE A SOURCE FILE FROM AN EXAMPLE (must be placed after example name or boom)
elif isinstance(item, tuple) and item[0] == "EXCLUDE_FROM_EXAMPLE":
exclude_name = item[1]
if example_name is None:
print("***** PLEASE DEFINE EXAMPLE FIRST *****")
break
src_filter.append(f"-<../examples/{example_name}/{exclude_name}>")
# DEAL WITH UI VARIANT FOR AN EXAMPLE
elif isinstance(item, tuple) and item[0] == "MC_UI_FLAVOR":
ui_flavor = item[1]
if example_name is None:
print("***** PLEASE DEFINE EXAMPLE FIRST *****")
break
src_filter.append(f"+<../examples/{example_name}/{ui_flavor}/*.cpp>")
menv.Replace(SRC_FILTER=src_filter)
#print (menv.Dump())

View file

@ -0,0 +1,46 @@
#pragma once
#include <MeshCore.h>
#include <helpers/ui/DisplayDriver.h>
#include <helpers/ui/UIScreen.h>
#include <helpers/SensorManager.h>
#include <helpers/BaseSerialInterface.h>
#include <Arduino.h>
#ifdef PIN_BUZZER
#include <helpers/ui/buzzer.h>
#endif
#include "NodePrefs.h"
enum class UIEventType {
none,
contactMessage,
channelMessage,
roomMessage,
newContactMessage,
ack
};
class AbstractUITask {
protected:
mesh::MainBoard* _board;
BaseSerialInterface* _serial;
bool _connected;
AbstractUITask(mesh::MainBoard* board, BaseSerialInterface* serial) : _board(board), _serial(serial) {
_connected = false;
}
public:
void setHasConnection(bool connected) { _connected = connected; }
bool hasConnection() const { return _connected; }
uint16_t getBattMilliVolts() const { return _board->getBattMilliVolts(); }
bool isSerialEnabled() const { return _serial->isEnabled(); }
void enableSerial() { _serial->enable(); }
void disableSerial() { _serial->disable(); }
virtual void msgRead(int msgcount) = 0;
virtual void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) = 0;
virtual void soundBuzzer(UIEventType bet = UIEventType::none) = 0;
virtual void loop() = 0;
};

View file

@ -109,10 +109,6 @@
#define MAX_SIGN_DATA_LEN (8 * 1024) // 8K
#ifdef DISPLAY_CLASS
#include "UITask.h"
#endif
void MyMesh::writeOKFrame() {
uint8_t buf[1];
buf[0] = RESP_CODE_OK;
@ -247,7 +243,7 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
}
} else {
#ifdef DISPLAY_CLASS
ui_task.soundBuzzer(UIEventType::newContactMessage);
if (_ui) _ui->soundBuzzer(UIEventType::newContactMessage);
#endif
}
@ -267,6 +263,7 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
}
memcpy(p->pubkey_prefix, contact.id.pub_key, sizeof(p->pubkey_prefix));
strcpy(p->name, contact.name);
p->recv_timestamp = getRTCClock()->getCurrentTime();
p->path_len = path_len;
memcpy(p->path, path, p->path_len);
@ -275,6 +272,20 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path
dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY);
}
static int sort_by_recent(const void *a, const void *b) {
return ((AdvertPath *) b)->recv_timestamp - ((AdvertPath *) a)->recv_timestamp;
}
int MyMesh::getRecentlyHeard(AdvertPath dest[], int max_num) {
if (max_num > ADVERT_PATH_TABLE_SIZE) max_num = ADVERT_PATH_TABLE_SIZE;
qsort(advert_paths, ADVERT_PATH_TABLE_SIZE, sizeof(advert_paths[0]), sort_by_recent);
for (int i = 0; i < max_num; i++) {
dest[i] = advert_paths[i];
}
return max_num;
}
void MyMesh::onContactPathUpdated(const ContactInfo &contact) {
out_frame[0] = PUSH_CODE_PATH_UPDATED;
memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE);
@ -339,10 +350,10 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe
#ifdef DISPLAY_CLASS
// we only want to show text messages on display, not cli data
bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN;
if (should_display) {
ui_task.newMsg(path_len, from.name, text, offline_queue_len);
if (should_display && _ui) {
_ui->newMsg(path_len, from.name, text, offline_queue_len);
if (!_serial->isConnected()) {
ui_task.soundBuzzer(UIEventType::contactMessage);
_ui->soundBuzzer(UIEventType::contactMessage);
}
}
#endif
@ -401,7 +412,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
_serial->writeFrame(frame, 1);
} else {
#ifdef DISPLAY_CLASS
ui_task.soundBuzzer(UIEventType::channelMessage);
if (_ui) _ui->soundBuzzer(UIEventType::channelMessage);
#endif
}
#ifdef DISPLAY_CLASS
@ -411,7 +422,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe
if (getChannel(channel_idx, channel_details)) {
channel_name = channel_details.name;
}
ui_task.newMsg(path_len, channel_name, text, offline_queue_len);
if (_ui) _ui->newMsg(path_len, channel_name, text, offline_queue_len);
#endif
}
@ -620,9 +631,9 @@ uint32_t MyMesh::calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t
void MyMesh::onSendTimeout() {}
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store)
MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui)
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables),
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store) {
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui) {
_iter_started = false;
_cli_rescue = false;
offline_queue_len = 0;
@ -1026,7 +1037,7 @@ void MyMesh::handleCmdFrame(size_t len) {
if ((out_len = getFromOfflineQueue(out_frame)) > 0) {
_serial->writeFrame(out_frame, out_len);
#ifdef DISPLAY_CLASS
ui_task.msgRead(offline_queue_len);
if (_ui) _ui->msgRead(offline_queue_len);
#endif
} else {
out_frame[0] = RESP_CODE_NO_MORE_MESSAGES;
@ -1628,7 +1639,7 @@ void MyMesh::loop() {
}
#ifdef DISPLAY_CLASS
ui_task.setHasConnection(_serial->isConnected());
if (_ui) _ui->setHasConnection(_serial->isConnected());
#endif
}

View file

@ -2,9 +2,7 @@
#include <Arduino.h>
#include <Mesh.h>
#ifdef DISPLAY_CLASS
#include "UITask.h"
#endif
#include "AbstractUITask.h"
/*------------ Frame Protocol --------------*/
#define FIRMWARE_VER_CODE 7
@ -77,9 +75,17 @@
#define REQ_TYPE_KEEP_ALIVE 0x02
#define REQ_TYPE_GET_TELEMETRY_DATA 0x03
struct AdvertPath {
uint8_t pubkey_prefix[7];
uint8_t path_len;
char name[32];
uint32_t recv_timestamp;
uint8_t path[MAX_PATH_SIZE];
};
class MyMesh : public BaseChatMesh, public DataStoreHost {
public:
MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store);
MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui=NULL);
void begin(bool has_display);
void startInterface(BaseSerialInterface &serial);
@ -93,6 +99,8 @@ public:
bool advert();
void enterCLIRescue();
int getRecentlyHeard(AdvertPath dest[], int max_num);
protected:
float getAirtimeBudgetFactor() const override;
int getInterferenceThreshold() const override;
@ -169,6 +177,7 @@ private:
uint32_t pending_telemetry, pending_discovery; // pending _TELEMETRY_REQ
uint32_t pending_req; // pending _BINARY_REQ
BaseSerialInterface *_serial;
AbstractUITask* _ui;
ContactsIterator _iter;
uint32_t _iter_filter_since;
@ -201,17 +210,8 @@ private:
AckTableEntry expected_ack_table[EXPECTED_ACK_TABLE_SIZE]; // circular table
int next_ack_idx;
struct AdvertPath {
uint8_t pubkey_prefix[7];
uint8_t path_len;
uint32_t recv_timestamp;
uint8_t path[MAX_PATH_SIZE];
};
#define ADVERT_PATH_TABLE_SIZE 16
AdvertPath advert_paths[ADVERT_PATH_TABLE_SIZE]; // circular table
};
extern MyMesh the_mesh;
#ifdef DISPLAY_CLASS
extern UITask ui_task;
#endif

View file

@ -75,14 +75,19 @@ static uint32_t _atoi(const char* sp) {
#endif
/* GLOBAL OBJECTS */
StdRNG fast_rng;
SimpleMeshTables tables;
MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store);
#ifdef DISPLAY_CLASS
#include "UITask.h"
UITask ui_task(&board);
UITask ui_task(&board, &serial_interface);
#endif
StdRNG fast_rng;
SimpleMeshTables tables;
MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store
#ifdef DISPLAY_CLASS
, &ui_task
#endif
);
/* END GLOBAL OBJECTS */
void halt() {
@ -99,7 +104,10 @@ void setup() {
if (display.begin()) {
disp = &display;
disp->startFrame();
disp->print("Please wait...");
#ifdef ST7789
disp->setTextSize(2);
#endif
disp->drawTextCentered(disp->width() / 2, 28, "Loading...");
disp->endFrame();
}
#endif

View file

@ -0,0 +1,597 @@
#include "UITask.h"
#include <helpers/TxtDataHelpers.h>
#include "../MyMesh.h"
#include "target.h"
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds
#ifdef PIN_STATUS_LED
#define LED_ON_MILLIS 20
#define LED_ON_MSG_MILLIS 200
#define LED_CYCLE_MILLIS 4000
#endif
#define LONG_PRESS_MILLIS 1200
#ifndef UI_RECENT_LIST_SIZE
#define UI_RECENT_LIST_SIZE 4
#endif
#define PRESS_LABEL "long press"
#include "icons.h"
class SplashScreen : public UIScreen {
UITask* _task;
unsigned long dismiss_after;
char _version_info[12];
public:
SplashScreen(UITask* task) : _task(task) {
// strip off dash and commit hash by changing dash to null terminator
// e.g: v1.2.3-abcdef -> v1.2.3
const char *ver = FIRMWARE_VERSION;
const char *dash = strchr(ver, '-');
int len = dash ? dash - ver : strlen(ver);
if (len >= sizeof(_version_info)) len = sizeof(_version_info) - 1;
memcpy(_version_info, ver, len);
_version_info[len] = 0;
dismiss_after = millis() + BOOT_SCREEN_MILLIS;
}
int render(DisplayDriver& display) override {
// meshcore logo
display.setColor(DisplayDriver::BLUE);
int logoWidth = 128;
display.drawXbm((display.width() - logoWidth) / 2, 3, meshcore_logo, logoWidth, 13);
// version info
display.setColor(DisplayDriver::LIGHT);
display.setTextSize(2);
display.drawTextCentered(display.width()/2, 22, _version_info);
display.setTextSize(1);
display.drawTextCentered(display.width()/2, 42, FIRMWARE_BUILD_DATE);
return 1000;
}
void poll() override {
if (millis() >= dismiss_after) {
_task->gotoHomeScreen();
}
}
};
class HomeScreen : public UIScreen {
enum HomePage {
FIRST,
RECENT,
RADIO,
BLUETOOTH,
ADVERT,
SHUTDOWN,
Count // keep as last
};
UITask* _task;
mesh::RTCClock* _rtc;
SensorManager* _sensors;
NodePrefs* _node_prefs;
uint8_t _page;
bool _shutdown_init;
AdvertPath recent[UI_RECENT_LIST_SIZE];
void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) {
// Convert millivolts to percentage
const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V)
const int maxMilliVolts = 4200; // Maximum voltage (e.g., 4.2V)
int batteryPercentage = ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts);
if (batteryPercentage < 0) batteryPercentage = 0; // Clamp to 0%
if (batteryPercentage > 100) batteryPercentage = 100; // Clamp to 100%
// battery icon
int iconWidth = 24;
int iconHeight = 10;
int iconX = display.width() - iconWidth - 5; // Position the icon near the top-right corner
int iconY = 0;
display.setColor(DisplayDriver::GREEN);
// battery outline
display.drawRect(iconX, iconY, iconWidth, iconHeight);
// battery "cap"
display.fillRect(iconX + iconWidth, iconY + (iconHeight / 4), 3, iconHeight / 2);
// fill the battery based on the percentage
int fillWidth = (batteryPercentage * (iconWidth - 4)) / 100;
display.fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4);
}
public:
HomeScreen(UITask* task, mesh::RTCClock* rtc, SensorManager* sensors, NodePrefs* node_prefs)
: _task(task), _rtc(rtc), _sensors(sensors), _node_prefs(node_prefs), _page(0), _shutdown_init(false) { }
void poll() override {
if (_shutdown_init && !_task->isButtonPressed()) { // must wait for USR button to be released
_task->shutdown();
}
}
int render(DisplayDriver& display) override {
char tmp[80];
// node name
display.setCursor(0, 0);
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
display.print(_node_prefs->node_name);
// battery voltage
renderBatteryIndicator(display, _task->getBattMilliVolts());
// curr page indicator
int y = 14;
int x = display.width() / 2 - 25;
for (uint8_t i = 0; i < HomePage::Count; i++, x += 10) {
if (i == _page) {
display.fillRect(x-1, y-1, 3, 3);
} else {
display.fillRect(x, y, 1, 1);
}
}
if (_page == HomePage::FIRST) {
display.setColor(DisplayDriver::YELLOW);
display.setTextSize(2);
sprintf(tmp, "MSG: %d", _task->getMsgCount());
display.drawTextCentered(display.width() / 2, 20, tmp);
if (_task->hasConnection()) {
display.setColor(DisplayDriver::GREEN);
display.setTextSize(1);
display.drawTextCentered(display.width() / 2, 43, "< Connected >");
} else if (the_mesh.getBLEPin() != 0) { // BT pin
display.setColor(DisplayDriver::RED);
display.setTextSize(2);
sprintf(tmp, "Pin:%d", the_mesh.getBLEPin());
display.drawTextCentered(display.width() / 2, 43, tmp);
}
} else if (_page == HomePage::RECENT) {
the_mesh.getRecentlyHeard(recent, UI_RECENT_LIST_SIZE);
display.setColor(DisplayDriver::GREEN);
int y = 20;
for (int i = 0; i < UI_RECENT_LIST_SIZE; i++, y += 11) {
auto a = &recent[i];
if (a->name[0] == 0) continue; // empty slot
display.setCursor(0, y);
display.print(a->name);
int secs = _rtc->getCurrentTime() - a->recv_timestamp;
if (secs < 60) {
sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) {
sprintf(tmp, "%dm", secs / 60);
} else {
sprintf(tmp, "%dh", secs / (60*60));
}
display.setCursor(display.width() - display.getTextWidth(tmp) - 1, y);
display.print(tmp);
}
} else if (_page == HomePage::RADIO) {
display.setColor(DisplayDriver::YELLOW);
display.setTextSize(1);
// freq / sf
display.setCursor(0, 20);
sprintf(tmp, "FQ: %06.3f SF: %d", _node_prefs->freq, _node_prefs->sf);
display.print(tmp);
display.setCursor(0, 31);
sprintf(tmp, "BW: %03.2f CR: %d", _node_prefs->bw, _node_prefs->cr);
display.print(tmp);
// tx power, noise floor
display.setCursor(0, 42);
sprintf(tmp, "TX: %ddBm", _node_prefs->tx_power_dbm);
display.print(tmp);
display.setCursor(0, 53);
sprintf(tmp, "Noise floor: %d", radio_driver.getNoiseFloor());
display.print(tmp);
} else if (_page == HomePage::BLUETOOTH) {
display.setColor(DisplayDriver::GREEN);
display.drawXbm((display.width() - 32) / 2, 18,
_task->isSerialEnabled() ? bluetooth_on : bluetooth_off,
32, 32);
display.setTextSize(1);
display.drawTextCentered(display.width() / 2, 64 - 11, "toggle: " PRESS_LABEL);
} else if (_page == HomePage::ADVERT) {
display.setColor(DisplayDriver::GREEN);
display.drawXbm((display.width() - 32) / 2, 18, advert_icon, 32, 32);
display.drawTextCentered(display.width() / 2, 64 - 11, "advert: " PRESS_LABEL);
} else if (_page == HomePage::SHUTDOWN) {
display.setColor(DisplayDriver::GREEN);
display.setTextSize(1);
if (_shutdown_init) {
display.drawTextCentered(display.width() / 2, 34, "hibernating...");
} else {
display.drawXbm((display.width() - 32) / 2, 18, power_icon, 32, 32);
display.drawTextCentered(display.width() / 2, 64 - 11, "hibernate: " PRESS_LABEL);
}
}
return 5000; // next render after 5000 ms
}
bool handleInput(char c) override {
if (c == KEY_LEFT) {
_page = (_page + HomePage::Count - 1) % HomePage::Count;
return true;
}
if (c == KEY_RIGHT || c == KEY_SELECT) {
_page = (_page + 1) % HomePage::Count;
if (_page == HomePage::RECENT) {
_task->showAlert("Recent adverts", 800);
}
return true;
}
if (c == KEY_ENTER && _page == HomePage::BLUETOOTH) {
if (_task->isSerialEnabled()) { // toggle Bluetooth on/off
_task->disableSerial();
} else {
_task->enableSerial();
}
return true;
}
if (c == KEY_ENTER && _page == HomePage::ADVERT) {
#ifdef PIN_BUZZER
_task->soundBuzzer(UIEventType::ack);
#endif
if (the_mesh.advert()) {
_task->showAlert("Advert sent!", 1000);
} else {
_task->showAlert("Advert failed..", 1000);
}
return true;
}
if (c == KEY_ENTER && _page == HomePage::SHUTDOWN) {
_shutdown_init = true; // need to wait for button to be released
return true;
}
return false;
}
};
class MsgPreviewScreen : public UIScreen {
UITask* _task;
mesh::RTCClock* _rtc;
struct MsgEntry {
uint32_t timestamp;
char origin[62];
char msg[78];
};
#define MAX_UNREAD_MSGS 32
int num_unread;
MsgEntry unread[MAX_UNREAD_MSGS];
public:
MsgPreviewScreen(UITask* task, mesh::RTCClock* rtc) : _task(task), _rtc(rtc) { num_unread = 0; }
void addPreview(uint8_t path_len, const char* from_name, const char* msg) {
if (num_unread >= MAX_UNREAD_MSGS) return; // full
auto p = &unread[num_unread++];
p->timestamp = _rtc->getCurrentTime();
if (path_len == 0xFF) {
sprintf(p->origin, "(D) %s:", from_name);
} else {
sprintf(p->origin, "(%d) %s:", (uint32_t) path_len, from_name);
}
StrHelper::strncpy(p->msg, msg, sizeof(p->msg));
}
int render(DisplayDriver& display) override {
char tmp[16];
display.setCursor(0, 0);
display.setTextSize(1);
display.setColor(DisplayDriver::GREEN);
sprintf(tmp, "Unread: %d", num_unread);
display.print(tmp);
auto p = &unread[0];
int secs = _rtc->getCurrentTime() - p->timestamp;
if (secs < 60) {
sprintf(tmp, "%ds", secs);
} else if (secs < 60*60) {
sprintf(tmp, "%dm", secs / 60);
} else {
sprintf(tmp, "%dh", secs / (60*60));
}
display.setCursor(display.width() - display.getTextWidth(tmp) - 2, 0);
display.print(tmp);
display.drawRect(0, 11, display.width(), 1); // horiz line
display.setCursor(0, 14);
display.setColor(DisplayDriver::YELLOW);
display.print(p->origin);
display.setCursor(0, 25);
display.setColor(DisplayDriver::LIGHT);
display.printWordWrap(p->msg, display.width());
return 1000; // next render after 1000 ms
}
bool handleInput(char c) override {
if (c == KEY_SELECT || c == KEY_RIGHT) {
num_unread--;
if (num_unread == 0) {
_task->gotoHomeScreen();
} else {
// delete first/curr item from unread queue
for (int i = 0; i < num_unread; i++) {
unread[i] = unread[i + 1];
}
}
return true;
}
if (c == KEY_ENTER) {
num_unread = 0; // clear unread queue
_task->gotoHomeScreen();
return true;
}
return false;
}
};
void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs) {
_display = display;
_sensors = sensors;
_auto_off = millis() + AUTO_OFF_MILLIS;
#if defined(PIN_USER_BTN)
user_btn.begin();
#endif
_node_prefs = node_prefs;
if (_display != NULL) {
_display->turnOn();
}
#ifdef PIN_BUZZER
buzzer.begin();
#endif
ui_started_at = millis();
_alert_expiry = 0;
splash = new SplashScreen(this);
home = new HomeScreen(this, &rtc_clock, sensors, node_prefs);
msg_preview = new MsgPreviewScreen(this, &rtc_clock);
setCurrScreen(splash);
}
void UITask::showAlert(const char* text, int duration_millis) {
strcpy(_alert, text);
_alert_expiry = millis() + duration_millis;
}
void UITask::soundBuzzer(UIEventType bet) {
#if defined(PIN_BUZZER)
switch(bet){
case UIEventType::contactMessage:
// gemini's pick
buzzer.play("MsgRcv3:d=4,o=6,b=200:32e,32g,32b,16c7");
break;
case UIEventType::channelMessage:
buzzer.play("kerplop:d=16,o=6,b=120:32g#,32c#");
break;
case UIEventType::ack:
buzzer.play("ack:d=32,o=8,b=120:c");
break;
case UIEventType::roomMessage:
case UIEventType::newContactMessage:
case UIEventType::none:
default:
break;
}
#endif
}
void UITask::msgRead(int msgcount) {
_msgcount = msgcount;
if (msgcount == 0) {
gotoHomeScreen();
}
}
void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) {
_msgcount = msgcount;
((MsgPreviewScreen *) msg_preview)->addPreview(path_len, from_name, text);
setCurrScreen(msg_preview);
if (_display != NULL) {
if (!_display->isOn()) _display->turnOn();
_auto_off = millis() + AUTO_OFF_MILLIS; // extend the auto-off timer
_next_refresh = 0; // trigger refresh
}
}
void UITask::userLedHandler() {
#ifdef PIN_STATUS_LED
static int state = 0;
static int next_change = 0;
static int last_increment = 0;
int cur_time = millis();
if (cur_time > next_change) {
if (state == 0) {
state = 1;
if (_msgcount > 0) {
last_increment = LED_ON_MSG_MILLIS;
} else {
last_increment = LED_ON_MILLIS;
}
next_change = cur_time + last_increment;
} else {
state = 0;
next_change = cur_time + LED_CYCLE_MILLIS - last_increment;
}
digitalWrite(PIN_STATUS_LED, state);
}
#endif
}
void UITask::setCurrScreen(UIScreen* c) {
curr = c;
_next_refresh = 0;
}
/*
hardware-agnostic pre-shutdown activity should be done here
*/
void UITask::shutdown(bool restart){
#ifdef PIN_BUZZER
/* note: we have a choice here -
we can do a blocking buzzer.loop() with non-deterministic consequences
or we can set a flag and delay the shutdown for a couple of seconds
while a non-blocking buzzer.loop() plays out in UITask::loop()
*/
buzzer.shutdown();
uint32_t buzzer_timer = millis(); // fail-safe shutdown
while (buzzer.isPlaying() && (millis() - 2500) < buzzer_timer)
buzzer.loop();
#endif // PIN_BUZZER
if (restart) {
_board->reboot();
} else {
_display->turnOff();
_board->powerOff();
}
}
bool UITask::isButtonPressed() const {
#ifdef PIN_USER_BTN
return user_btn.isPressed();
#else
return false;
#endif
}
void UITask::loop() {
char c = 0;
#if defined(PIN_USER_BTN)
int ev = user_btn.check();
if (ev == BUTTON_EVENT_CLICK) {
c = checkDisplayOn(KEY_SELECT);
} else if (ev == BUTTON_EVENT_LONG_PRESS) {
c = handleLongPress(KEY_ENTER);
}
#endif
#if defined(WIO_TRACKER_L1)
ev = joystick_left.check();
if (ev == BUTTON_EVENT_CLICK) {
c = checkDisplayOn(KEY_LEFT);
} else if (ev == BUTTON_EVENT_LONG_PRESS) {
c = handleLongPress(KEY_LEFT);
}
ev = joystick_right.check();
if (ev == BUTTON_EVENT_CLICK) {
c = checkDisplayOn(KEY_RIGHT);
} else if (ev == BUTTON_EVENT_LONG_PRESS) {
c = handleLongPress(KEY_RIGHT);
}
#endif
if (c != 0 && curr) {
curr->handleInput(c);
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
_next_refresh = 0; // trigger refresh
}
userLedHandler();
#ifdef PIN_BUZZER
if (buzzer.isPlaying()) buzzer.loop();
#endif
if (curr) curr->poll();
if (_display != NULL && _display->isOn()) {
if (millis() >= _next_refresh && curr) {
_display->startFrame();
int delay_millis = curr->render(*_display);
if (millis() < _alert_expiry) { // render alert popup
_display->setTextSize(1);
int y = _display->height() / 3;
int p = _display->height() / 32;
_display->setColor(DisplayDriver::DARK);
_display->fillRect(p, y, _display->width() - p*2, y);
_display->setColor(DisplayDriver::LIGHT); // draw box border
_display->drawRect(p, y, _display->width() - p*2, y);
_display->drawTextCentered(_display->width() / 2, y + p*3, _alert);
_next_refresh = _alert_expiry; // will need refresh when alert is dismissed
} else {
_next_refresh = millis() + delay_millis;
}
_display->endFrame();
}
if (millis() > _auto_off) {
_display->turnOff();
}
}
#ifdef AUTO_SHUTDOWN_MILLIVOLTS
if (millis() > next_batt_chck) {
uint16_t milliVolts = getBattMilliVolts();
if (milliVolts > 0 && milliVolts < AUTO_SHUTDOWN_MILLIVOLTS) {
shutdown();
}
next_batt_chck = millis() + 8000;
}
#endif
}
char UITask::checkDisplayOn(char c) {
if (_display != NULL) {
if (!_display->isOn()) {
_display->turnOn(); // turn display on and consume event
c = 0;
}
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
_next_refresh = 0; // trigger refresh
}
return c;
}
char UITask::handleLongPress(char c) {
if (millis() - ui_started_at < 8000) { // long press in first 8 seconds since startup -> CLI/rescue
the_mesh.enterCLIRescue();
c = 0; // consume event
}
return c;
}
/*
void UITask::handleButtonTriplePress() {
MESH_DEBUG_PRINTLN("UITask: triple press triggered");
// Toggle buzzer quiet mode
#ifdef PIN_BUZZER
if (buzzer.isQuiet()) {
buzzer.quiet(false);
soundBuzzer(UIEventType::ack);
showAlert("Buzzer: ON", 600);
} else {
buzzer.quiet(true);
showAlert("Buzzer: OFF", 600);
}
_next_refresh = 0; // trigger refresh
#endif
}
*/

View file

@ -0,0 +1,65 @@
#pragma once
#include <MeshCore.h>
#include <helpers/ui/DisplayDriver.h>
#include <helpers/ui/UIScreen.h>
#include <helpers/SensorManager.h>
#include <helpers/BaseSerialInterface.h>
#include <Arduino.h>
#ifdef PIN_BUZZER
#include <helpers/ui/buzzer.h>
#endif
#include "../AbstractUITask.h"
#include "../NodePrefs.h"
class UITask : public AbstractUITask {
DisplayDriver* _display;
SensorManager* _sensors;
#ifdef PIN_BUZZER
genericBuzzer buzzer;
#endif
unsigned long _next_refresh, _auto_off;
NodePrefs* _node_prefs;
char _alert[80];
unsigned long _alert_expiry;
int _msgcount;
unsigned long ui_started_at, next_batt_chck;
UIScreen* splash;
UIScreen* home;
UIScreen* msg_preview;
UIScreen* curr;
void userLedHandler();
// Button action handlers
char checkDisplayOn(char c);
char handleLongPress(char c);
void setCurrScreen(UIScreen* c);
public:
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
next_batt_chck = _next_refresh = 0;
ui_started_at = 0;
curr = NULL;
}
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
void gotoHomeScreen() { setCurrScreen(home); }
void showAlert(const char* text, int duration_millis);
int getMsgCount() const { return _msgcount; }
bool hasDisplay() const { return _display != NULL; }
bool isButtonPressed() const;
// from AbstractUITask
void msgRead(int msgcount) override;
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
void soundBuzzer(UIEventType bet = UIEventType::none) override;
void loop() override;
void shutdown(bool restart = false);
};

View file

@ -0,0 +1,118 @@
#pragma once
#include <stdint.h>
// 'meshcore', 128x13px
static const uint8_t meshcore_logo [] = {
0x3c, 0x01, 0xe3, 0xff, 0xc7, 0xff, 0x8f, 0x03, 0x87, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe,
0x3c, 0x03, 0xe3, 0xff, 0xc7, 0xff, 0x8e, 0x03, 0x8f, 0xfe, 0x3f, 0xfe, 0x1f, 0xff, 0x1f, 0xfe,
0x3e, 0x03, 0xc3, 0xff, 0x8f, 0xff, 0x0e, 0x07, 0x8f, 0xfe, 0x7f, 0xfe, 0x1f, 0xff, 0x1f, 0xfc,
0x3e, 0x07, 0xc7, 0x80, 0x0e, 0x00, 0x0e, 0x07, 0x9e, 0x00, 0x78, 0x0e, 0x3c, 0x0f, 0x1c, 0x00,
0x3e, 0x0f, 0xc7, 0x80, 0x1e, 0x00, 0x0e, 0x07, 0x1e, 0x00, 0x70, 0x0e, 0x38, 0x0f, 0x3c, 0x00,
0x7f, 0x0f, 0xc7, 0xfe, 0x1f, 0xfc, 0x1f, 0xff, 0x1c, 0x00, 0x70, 0x0e, 0x38, 0x0e, 0x3f, 0xf8,
0x7f, 0x1f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x0e, 0x38, 0x0e, 0x3f, 0xf8,
0x7f, 0x3f, 0xc7, 0xfe, 0x0f, 0xff, 0x1f, 0xff, 0x1c, 0x00, 0xf0, 0x1e, 0x3f, 0xfe, 0x3f, 0xf0,
0x77, 0x3b, 0x87, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xfc, 0x38, 0x00,
0x77, 0xfb, 0x8f, 0x00, 0x00, 0x07, 0x1c, 0x0f, 0x3c, 0x00, 0xe0, 0x1c, 0x7f, 0xf8, 0x38, 0x00,
0x73, 0xf3, 0x8f, 0xff, 0x0f, 0xff, 0x1c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x78, 0x7f, 0xf8,
0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfe, 0x3c, 0x0e, 0x3f, 0xf8, 0xff, 0xfc, 0x70, 0x3c, 0x7f, 0xf8,
0xe3, 0xe3, 0x8f, 0xff, 0x1f, 0xfc, 0x3c, 0x0e, 0x1f, 0xf8, 0xff, 0xf8, 0x70, 0x3c, 0x7f, 0xf8,
};
static const uint8_t bluetooth_on[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00,
0x00, 0x3C, 0x00, 0x00,
0x00, 0x3E, 0x00, 0x00,
0x00, 0x3F, 0x80, 0x00,
0x00, 0x3F, 0xC0, 0x00,
0x00, 0x3B, 0xE0, 0x00,
0x30, 0x38, 0xF8, 0x00,
0x3C, 0x38, 0x7C, 0x00,
0x3E, 0x38, 0x7C, 0x00,
0x1F, 0xB8, 0xF8, 0x70,
0x07, 0xF9, 0xF0, 0x78,
0x03, 0xFF, 0xC0, 0x78,
0x00, 0xFF, 0x80, 0x3C,
0x00, 0x7F, 0x07, 0x1C,
0x00, 0x7E, 0x07, 0x1C,
0x03, 0xFF, 0x82, 0x1C,
0x03, 0xFF, 0xC0, 0x78,
0x07, 0xFB, 0xE0, 0x78,
0x0F, 0xB8, 0xF8, 0x70,
0x3E, 0x38, 0x7C, 0x00,
0x3C, 0x38, 0x7C, 0x00,
0x38, 0x38, 0xF8, 0x00,
0x00, 0x39, 0xF0, 0x00,
0x00, 0x3F, 0xC0, 0x00,
0x00, 0x3F, 0x80, 0x00,
0x00, 0x3E, 0x00, 0x00,
0x00, 0x3C, 0x00, 0x00,
0x00, 0x38, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static const uint8_t bluetooth_off[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x80, 0x00,
0x00, 0x03, 0xC0, 0x00,
0x00, 0x03, 0xE0, 0x00,
0x38, 0x03, 0xF8, 0x00,
0x3C, 0x03, 0xFC, 0x00,
0x3E, 0x03, 0xBF, 0x00,
0x0F, 0x83, 0x8F, 0x80,
0x07, 0xC3, 0x87, 0xC0,
0x03, 0xF0, 0x03, 0xC0,
0x00, 0xF8, 0x0F, 0x80,
0x00, 0x7C, 0x0F, 0x00,
0x00, 0x1F, 0x0E, 0x00,
0x00, 0x0F, 0x80, 0x00,
0x00, 0x07, 0xE0, 0x00,
0x00, 0x07, 0xF0, 0x00,
0x00, 0x0F, 0xF8, 0x00,
0x00, 0x3F, 0xBE, 0x00,
0x00, 0x7F, 0x9F, 0x00,
0x00, 0xFB, 0x8F, 0xC0,
0x03, 0xE3, 0x83, 0xE0,
0x03, 0xC3, 0x87, 0xF0,
0x03, 0x83, 0x8F, 0xFC,
0x00, 0x03, 0xBF, 0x3C,
0x00, 0x03, 0xFC, 0x1C,
0x00, 0x03, 0xF8, 0x00,
0x00, 0x03, 0xE0, 0x00,
0x00, 0x03, 0xC0, 0x00,
0x00, 0x03, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static const uint8_t power_icon[] = {
0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00,
0x00, 0x33, 0xCC, 0x00, 0x00, 0xF3, 0xCF, 0x00, 0x01, 0xF3, 0xCF, 0x80,
0x03, 0xF3, 0xCF, 0xC0, 0x07, 0xF3, 0xCF, 0xE0, 0x0F, 0xE3, 0xC7, 0xF0,
0x1F, 0xC3, 0xC3, 0xF8, 0x1F, 0x83, 0xC1, 0xF8, 0x3F, 0x03, 0xC0, 0xFC,
0x3E, 0x03, 0xC0, 0x7C, 0x3E, 0x03, 0xC0, 0x7C, 0x7E, 0x01, 0x80, 0x7E,
0x7C, 0x00, 0x00, 0x3E, 0x7C, 0x00, 0x00, 0x3E, 0x7C, 0x00, 0x00, 0x3E,
0x7C, 0x00, 0x00, 0x3E, 0x7C, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x7C,
0x3E, 0x00, 0x00, 0x7C, 0x3F, 0x00, 0x00, 0xFC, 0x1F, 0x80, 0x01, 0xF8,
0x1F, 0xC0, 0x03, 0xF8, 0x0F, 0xE0, 0x07, 0xF0, 0x0F, 0xF8, 0x1F, 0xF0,
0x07, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x00,
0x00, 0x3F, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00,
};
static const uint8_t advert_icon[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30,
0x1C, 0x00, 0x00, 0x38, 0x18, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0C,
0x30, 0x60, 0x06, 0x0C, 0x60, 0xE0, 0x07, 0x06, 0x61, 0xC0, 0x03, 0x86,
0xE1, 0x81, 0x81, 0x87, 0xC3, 0x07, 0xE0, 0xC3, 0xC3, 0x0F, 0xF0, 0xC3,
0xC3, 0x0F, 0xF0, 0xC3, 0xC3, 0x0F, 0xF0, 0xC3, 0xC3, 0x0F, 0xF0, 0xC3,
0xC3, 0x07, 0xE0, 0xC3, 0xC1, 0x83, 0xC1, 0x83, 0x61, 0x80, 0x01, 0x86,
0x60, 0xC0, 0x03, 0x06, 0x70, 0xE0, 0x07, 0x0E, 0x30, 0x40, 0x02, 0x0C,
0x38, 0x00, 0x00, 0x1C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x30,
0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

View file

@ -1,8 +1,7 @@
#include "UITask.h"
#include <Arduino.h>
#include <helpers/TxtDataHelpers.h>
#include "NodePrefs.h"
#include "MyMesh.h"
#include "../MyMesh.h"
#define AUTO_OFF_MILLIS 15000 // 15 seconds
#define BOOT_SCREEN_MILLIS 3000 // 3 seconds

View file

@ -9,28 +9,18 @@
#include <helpers/ui/buzzer.h>
#endif
#include "NodePrefs.h"
#include "../AbstractUITask.h"
#include "../NodePrefs.h"
#include "Button.h"
enum class UIEventType
{
none,
contactMessage,
channelMessage,
roomMessage,
newContactMessage,
ack
};
class UITask {
class UITask : public AbstractUITask {
DisplayDriver* _display;
mesh::MainBoard* _board;
SensorManager* _sensors;
#ifdef PIN_BUZZER
genericBuzzer buzzer;
#endif
unsigned long _next_refresh, _auto_off;
bool _connected;
NodePrefs* _node_prefs;
char _version_info[32];
char _origin[62];
@ -64,19 +54,20 @@ class UITask {
public:
UITask(mesh::MainBoard* board) : _board(board), _display(NULL), _sensors(NULL) {
UITask(mesh::MainBoard* board, BaseSerialInterface* serial) : AbstractUITask(board, serial), _display(NULL), _sensors(NULL) {
_next_refresh = 0;
ui_started_at = 0;
_connected = false;
}
void begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* node_prefs);
void setHasConnection(bool connected) { _connected = connected; }
bool hasDisplay() const { return _display != NULL; }
void clearMsgPreview();
void msgRead(int msgcount);
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount);
void soundBuzzer(UIEventType bet = UIEventType::none);
// from AbstractUITask
void msgRead(int msgcount) override;
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;
void soundBuzzer(UIEventType bet = UIEventType::none) override;
void loop() override;
void shutdown(bool restart = false);
void loop();
};

View file

@ -159,7 +159,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
}
void putNeighbour(const mesh::Identity& id, uint32_t timestamp, float snr) {
#if MAX_NEIGHBOURS // check if neighbours enabled
#if MAX_NEIGHBOURS // check if neighbours enabled
// find existing neighbour, else use least recently updated
uint32_t oldest_timestamp = 0xFFFFFFFF;
NeighbourInfo* neighbour = &neighbours[0];
@ -589,7 +589,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_advert_interval = 12; // 12 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled
}
@ -611,8 +611,8 @@ public:
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
const char* getRole() override { return FIRMWARE_ROLE; }
const char* getNodeName() { return _prefs.node_name; }
NodePrefs* getNodePrefs() {
return &_prefs;
NodePrefs* getNodePrefs() {
return &_prefs;
}
void savePrefs() override {

View file

@ -298,7 +298,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks {
// uint32_t now = getRTCClock()->getCurrentTimeUnique();
// memcpy(reply_data, &now, 4); // response packets always prefixed with timestamp
memcpy(reply_data, &sender_timestamp, 4); // reflect sender_timestamp back in response packet (kind of like a 'tag')
switch (payload[0]) {
case REQ_TYPE_GET_STATUS: {
ServerStats stats;
@ -746,9 +746,9 @@ 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_advert_interval = 12; // 12 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled
_prefs.interference_threshold = 0; // disabled
#ifdef ROOM_PASSWORD
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
#endif
@ -778,8 +778,8 @@ public:
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
const char* getRole() override { return FIRMWARE_ROLE; }
const char* getNodeName() { return _prefs.node_name; }
NodePrefs* getNodePrefs() {
return &_prefs;
NodePrefs* getNodePrefs() {
return &_prefs;
}
void savePrefs() override {

View file

@ -613,6 +613,23 @@ void SensorMesh::getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) {
}
}
void SensorMesh::sendAckTo(const ContactInfo& dest, uint32_t ack_hash) {
if (dest.out_path_len < 0) {
mesh::Packet* ack = createAck(ack_hash);
if (ack) sendFlood(ack, TXT_ACK_DELAY);
} else {
uint32_t d = TXT_ACK_DELAY;
if (getExtraAckTransmitCount() > 0) {
mesh::Packet* a1 = createMultiAck(ack_hash, 1);
if (a1) sendDirect(a1, dest.out_path, dest.out_path_len, d);
d += 300;
}
mesh::Packet* a2 = createAck(ack_hash);
if (a2) sendDirect(a2, dest.out_path, dest.out_path_len, d);
}
}
void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) {
int i = matching_peer_indexes[sender_idx];
if (i < 0 || i >= num_contacts) {
@ -656,38 +673,55 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong)
uint flags = (data[4] >> 2); // message attempt number, and other flags
if (!(flags == TXT_TYPE_CLI_DATA)) {
MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags);
} else if (sender_timestamp > from.last_timestamp) { // prevent replay attacks
from.last_timestamp = sender_timestamp;
from.last_activity = getRTCClock()->getCurrentTime();
if (sender_timestamp > from.last_timestamp) { // prevent replay attacks
if (flags == TXT_TYPE_PLAIN) {
bool handled = handleIncomingMsg(from, sender_timestamp, &data[5], flags, len - 5);
if (handled) { // if msg was handled then send an ack
uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it
mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), from.id.pub_key, PUB_KEY_SIZE);
// len can be > original length, but 'text' will be padded with zeroes
data[len] = 0; // need to make a C string again, with null terminator
uint8_t temp[166];
char *command = (char *) &data[5];
char *reply = (char *) &temp[5];
handleCommand(sender_timestamp, command, reply);
int text_len = strlen(reply);
if (text_len > 0) {
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
if (timestamp == sender_timestamp) {
// WORKAROUND: the two timestamps need to be different, in the CLI view
timestamp++;
}
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
temp[4] = (TXT_TYPE_CLI_DATA << 2);
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len);
if (reply) {
if (from.out_path_len < 0) {
sendFlood(reply, CLI_REPLY_DELAY_MILLIS);
if (packet->isRouteFlood()) {
// let this sender know path TO here, so they can use sendDirect(), and ALSO encode the ACK
mesh::Packet* path = createPathReturn(from.id, secret, packet->path, packet->path_len,
PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4);
if (path) sendFlood(path, TXT_ACK_DELAY);
} else {
sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS);
sendAckTo(from, ack_hash);
}
}
} else if (flags == TXT_TYPE_CLI_DATA) {
from.last_timestamp = sender_timestamp;
from.last_activity = getRTCClock()->getCurrentTime();
// len can be > original length, but 'text' will be padded with zeroes
data[len] = 0; // need to make a C string again, with null terminator
uint8_t temp[166];
char *command = (char *) &data[5];
char *reply = (char *) &temp[5];
handleCommand(sender_timestamp, command, reply);
int text_len = strlen(reply);
if (text_len > 0) {
uint32_t timestamp = getRTCClock()->getCurrentTimeUnique();
if (timestamp == sender_timestamp) {
// WORKAROUND: the two timestamps need to be different, in the CLI view
timestamp++;
}
memcpy(temp, &timestamp, 4); // mostly an extra blob to help make packet_hash unique
temp[4] = (TXT_TYPE_CLI_DATA << 2);
auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, from.id, secret, temp, 5 + text_len);
if (reply) {
if (from.out_path_len < 0) {
sendFlood(reply, CLI_REPLY_DELAY_MILLIS);
} else {
sendDirect(reply, from.out_path, from.out_path_len, CLI_REPLY_DELAY_MILLIS);
}
}
}
} else {
MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags);
}
} else {
MESH_DEBUG_PRINTLN("onPeerDataRecv: possible replay attack detected");
@ -695,6 +729,15 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
}
}
bool SensorMesh::handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len) {
MESH_DEBUG_PRINT("handleIncomingMsg: unhandled msg from ");
#ifdef MESH_DEBUG
mesh::Utils::printHex(Serial, from.id.pub_key, PUB_KEY_SIZE);
Serial.printf(": %s\n", data);
#endif
return false;
}
bool SensorMesh::onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) {
int i = matching_peer_indexes[sender_idx];
if (i < 0 || i >= num_contacts) {

View file

@ -140,7 +140,8 @@ protected:
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t* secret, uint8_t* data, size_t len) override;
bool onPeerPathRecv(mesh::Packet* packet, int sender_idx, const uint8_t* secret, uint8_t* path, uint8_t path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len) override;
void onAckRecv(mesh::Packet* packet, uint32_t ack_crc) override;
virtual bool handleIncomingMsg(ContactInfo& from, uint32_t timestamp, uint8_t* data, uint flags, size_t len);
void sendAckTo(const ContactInfo& dest, uint32_t ack_hash);
private:
FILESYSTEM* _fs;
unsigned long next_local_advert, next_flood_advert;

16
library.json Normal file
View file

@ -0,0 +1,16 @@
{
"name": "MeshCore",
"version" : "1.7.4",
"dependencies": {
"SPI": "*",
"Wire": "*",
"jgromes/RadioLib": "^7.1.2",
"rweather/Crypto": "^0.4.0",
"adafruit/RTClib": "^2.1.3",
"melopero/Melopero RV3028": "^1.1.0",
"electroniccats/CayenneLPP": "1.4.0"
},
"build": {
"extraScript": "build_as_lib.py"
}
}

View file

@ -47,6 +47,7 @@ build_src_filter =
+<*.cpp>
+<helpers/*.cpp>
+<helpers/radiolib/*.cpp>
+<helpers/ui/MomentaryButton.cpp>
; ----------------- ESP32 ---------------------
@ -114,12 +115,14 @@ build_flags =
-D ENV_INCLUDE_LPS22HB=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
-D ENV_INCLUDE_INA226=1
-D ENV_INCLUDE_INA260=1
-D ENV_INCLUDE_MLX90614=1
-D ENV_INCLUDE_VL53L0X=1
lib_deps =
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
robtillaart/INA226 @ ^0.6.4
adafruit/Adafruit INA260 Library @ ^1.5.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0

View file

@ -83,6 +83,7 @@ void SerialBLEInterface::onConnect(BLEServer* pServer) {
void SerialBLEInterface::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) {
BLE_DEBUG_PRINTLN("onConnect(), conn_id=%d, mtu=%d", param->connect.conn_id, pServer->getPeerMTU(param->connect.conn_id));
last_conn_id = param->connect.conn_id;
}
void SerialBLEInterface::onMtuChanged(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) {
@ -143,6 +144,7 @@ void SerialBLEInterface::disable() {
BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
pServer->getAdvertising()->stop();
pServer->disconnect(last_conn_id);
pService->stop();
oldDeviceConnected = deviceConnected = false;
adv_restart_time = 0;

View file

@ -13,6 +13,7 @@ class SerialBLEInterface : public BaseSerialInterface, BLESecurityCallbacks, BLE
bool deviceConnected;
bool oldDeviceConnected;
bool _isEnabled;
uint16_t last_conn_id;
uint32_t _pin_code;
unsigned long _last_write;
unsigned long adv_restart_time;
@ -56,6 +57,7 @@ public:
adv_restart_time = 0;
_isEnabled = false;
_last_write = 0;
last_conn_id = 0;
send_queue_len = recv_queue_len = 0;
}

View file

@ -115,6 +115,20 @@ void SerialBLEInterface::enable() {
void SerialBLEInterface::disable() {
_isEnabled = false;
BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
#ifdef RAK_BOARD
Bluefruit.disconnect(Bluefruit.connHandle());
#else
uint16_t conn_id;
if (Bluefruit.getConnectedHandles(&conn_id, 1) > 0) {
Bluefruit.disconnect(conn_id);
}
#endif
Bluefruit.Advertising.restartOnDisconnect(false);
Bluefruit.Advertising.stop();
Bluefruit.Advertising.clearData();
stopAdv();
}

View file

@ -60,5 +60,9 @@ public:
NVIC_SystemReset();
}
void powerOff() override {
sd_power_system_off();
}
bool startOTAUpdate(const char* id, char reply[]) override;
};

View file

@ -43,6 +43,25 @@ public:
return "LilyGo T-Echo";
}
void powerOff() override {
#ifdef LED_RED
digitalWrite(LED_RED, LOW);
#endif
#ifdef LED_GREEN
digitalWrite(LED_GREEN, LOW);
#endif
#ifdef LED_BLUE
digitalWrite(LED_BLUE, LOW);
#endif
#ifdef DISP_BACKLIGHT
digitalWrite(DISP_BACKLIGHT, LOW);
#endif
#ifdef PIN_PWR_EN
digitalWrite(PIN_PWR_EN, LOW);
#endif
sd_power_system_off();
}
void reboot() override {
NVIC_SystemReset();
}

View file

@ -55,4 +55,8 @@ public:
void reboot() override {
NVIC_SystemReset();
}
void powerOff() override {
sd_power_system_off();
}
};

View file

@ -65,6 +65,14 @@ static Adafruit_INA219 INA219(TELEM_INA219_ADDRESS);
static Adafruit_INA260 INA260;
#endif
#if ENV_INCLUDE_INA226
#define TELEM_INA226_ADDRESS 0x44
#define TELEM_INA226_SHUNT_VALUE 0.100
#define TELEM_INA226_MAX_AMP 0.8
#include <INA226.h>
static INA226 INA226(TELEM_INA226_ADDRESS);
#endif
#if ENV_INCLUDE_MLX90614
#define TELEM_MLX90614_ADDRESS 0x5A // MLX90614 IR temperature sensor I2C address
#include <Adafruit_MLX90614.h>
@ -202,6 +210,17 @@ bool EnvironmentSensorManager::begin() {
}
#endif
#if ENV_INCLUDE_INA226
if (INA226.begin()) {
MESH_DEBUG_PRINTLN("Found INA226 at address: %02X", TELEM_INA226_ADDRESS);
INA226.setMaxCurrentShunt(TELEM_INA226_MAX_AMP, TELEM_INA226_SHUNT_VALUE);
INA226_initialized = true;
} else {
INA226_initialized = false;
MESH_DEBUG_PRINTLN("INA226 was not found at I2C address %02X", TELEM_INA226_ADDRESS);
}
#endif
#if ENV_INCLUDE_MLX90614
if (MLX90614.begin(TELEM_MLX90614_ADDRESS, TELEM_WIRE)) {
MESH_DEBUG_PRINTLN("Found MLX90614 at address: %02X", TELEM_MLX90614_ADDRESS);
@ -323,6 +342,15 @@ bool EnvironmentSensorManager::querySensors(uint8_t requester_permissions, Cayen
}
#endif
#if ENV_INCLUDE_INA226
if (INA226_initialized) {
telemetry.addVoltage(next_available_channel, INA226.getBusVoltage());
telemetry.addCurrent(next_available_channel, INA226.getCurrent_mA() / 1000.0);
telemetry.addPower(next_available_channel, INA226.getPower_mW() / 1000.0);
next_available_channel++;
}
#endif
#if ENV_INCLUDE_MLX90614
if (MLX90614_initialized) {
telemetry.addTemperature(TELEM_CHANNEL_SELF, MLX90614.readObjectTempC());

View file

@ -14,6 +14,7 @@ protected:
bool INA3221_initialized = false;
bool INA219_initialized = false;
bool INA260_initialized = false;
bool INA226_initialized = false;
bool SHTC3_initialized = false;
bool LPS22HB_initialized = false;
bool MLX90614_initialized = false;

View file

@ -21,9 +21,15 @@ public:
virtual void setColor(Color c) = 0;
virtual void setCursor(int x, int y) = 0;
virtual void print(const char* str) = 0;
virtual void printWordWrap(const char* str, int max_width) { print(str); } // fallback to basic print() if no override
virtual void fillRect(int x, int y, int w, int h) = 0;
virtual void drawRect(int x, int y, int w, int h) = 0;
virtual void drawXbm(int x, int y, const uint8_t* bits, int w, int h) = 0;
virtual uint16_t getTextWidth(const char* str) = 0;
virtual void drawTextCentered(int mid_x, int y, const char* str) { // helper method (override to optimise)
int w = getTextWidth(str);
setCursor(mid_x - w/2, y);
print(str);
}
virtual void endFrame() = 0;
};

View file

@ -29,8 +29,8 @@ void GxEPDDisplay::turnOn() {
if (!_init) begin();
#if DISP_BACKLIGHT
digitalWrite(DISP_BACKLIGHT, HIGH);
_isOn = true;
#endif
_isOn = true;
}
void GxEPDDisplay::turnOff() {
@ -47,6 +47,7 @@ void GxEPDDisplay::clear() {
void GxEPDDisplay::startFrame(Color bkg) {
display.fillScreen(GxEPD_WHITE);
display.setTextColor(_curr_color = GxEPD_BLACK);
}
void GxEPDDisplay::setTextSize(int sz) {
@ -67,7 +68,12 @@ void GxEPDDisplay::setTextSize(int sz) {
}
void GxEPDDisplay::setColor(Color c) {
display.setTextColor(GxEPD_BLACK);
// colours need to be inverted for epaper displays
if (c == DARK) {
display.setTextColor(_curr_color = GxEPD_WHITE);
} else {
display.setTextColor(_curr_color = GxEPD_BLACK);
}
}
void GxEPDDisplay::setCursor(int x, int y) {
@ -79,11 +85,11 @@ void GxEPDDisplay::print(const char* str) {
}
void GxEPDDisplay::fillRect(int x, int y, int w, int h) {
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, GxEPD_BLACK);
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
}
void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, GxEPD_BLACK);
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
}
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
@ -116,7 +122,7 @@ void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
// If the bit is set, draw a block of pixels
if (bitSet) {
// Draw the block as a filled rectangle
display.fillRect(x1, y1, block_w, block_h, GxEPD_BLACK);
display.fillRect(x1, y1, block_w, block_h, _curr_color);
}
}
}
@ -126,7 +132,7 @@ uint16_t GxEPDDisplay::getTextWidth(const char* str) {
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
return w / SCALE_X;
return ceil((w + 1) / SCALE_X);
}
void GxEPDDisplay::endFrame() {

View file

@ -28,6 +28,7 @@ class GxEPDDisplay : public DisplayDriver {
GxEPD2_BW<GxEPD2_150_BN, 200> display;
bool _init = false;
bool _isOn = false;
uint16_t _curr_color;
public:
// there is a margin in y...

View file

@ -0,0 +1,75 @@
#include "MomentaryButton.h"
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) {
_pin = pin;
_reverse = reverse;
_pull = pulldownup;
down_at = 0;
prev = _reverse ? HIGH : LOW;
cancel = 0;
_long_millis = long_press_millis;
}
void MomentaryButton::begin() {
if (_pin >= 0) {
pinMode(_pin, _pull ? (_reverse ? INPUT_PULLUP : INPUT_PULLDOWN) : INPUT);
}
}
bool MomentaryButton::isPressed() const {
return isPressed(digitalRead(_pin));
}
void MomentaryButton::cancelClick() {
cancel = 1;
}
bool MomentaryButton::isPressed(int level) const {
if (_reverse) {
return level == LOW;
} else {
return level != LOW;
}
}
int MomentaryButton::check(bool repeat_click) {
if (_pin < 0) return BUTTON_EVENT_NONE;
int event = BUTTON_EVENT_NONE;
int btn = digitalRead(_pin);
if (btn != prev) {
if (isPressed(btn)) {
down_at = millis();
} else {
// button UP
if (_long_millis > 0) {
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
event = BUTTON_EVENT_CLICK;
}
} else {
event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature
}
if (event == BUTTON_EVENT_CLICK && cancel) {
event = BUTTON_EVENT_NONE;
}
down_at = 0;
}
prev = btn;
}
if (!isPressed(btn) && cancel) { // always clear the pending 'cancel' once button is back in UP state
cancel = 0;
}
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
event = BUTTON_EVENT_LONG_PRESS;
down_at = 0;
}
if (down_at > 0 && repeat_click) {
unsigned long diff = (unsigned long)(millis() - down_at);
if (diff >= 700) {
event = BUTTON_EVENT_CLICK; // wait 700 millis before repeating the click events
}
}
return event;
}

View file

@ -0,0 +1,25 @@
#pragma once
#include <Arduino.h>
#define BUTTON_EVENT_NONE 0
#define BUTTON_EVENT_CLICK 1
#define BUTTON_EVENT_LONG_PRESS 2
class MomentaryButton {
int8_t _pin;
int8_t prev, cancel;
bool _reverse, _pull;
int _long_millis;
unsigned long down_at;
bool isPressed(int level) const;
public:
MomentaryButton(int8_t pin, int long_press_mills=0, bool reverse=false, bool pulldownup=false);
void begin();
int check(bool repeat_click=false); // returns one of BUTTON_EVENT_*
void cancelClick(); // suppress next BUTTON_EVENT_CLICK (if already in DOWN state)
uint8_t getPin() { return _pin; }
bool isPressed() const;
};

View file

@ -73,6 +73,9 @@ void ST7789Display::clear() {
void ST7789Display::startFrame(Color bkg) {
display.clear();
_color = ST77XX_WHITE;
display.setRGB(_color);
display.setFont(ArialMT_Plain_16);
}
void ST7789Display::setTextSize(int sz) {
@ -92,7 +95,9 @@ void ST7789Display::setColor(Color c) {
switch (c) {
case DisplayDriver::DARK :
_color = ST77XX_BLACK;
display.setColor(OLEDDISPLAY_COLOR::BLACK);
break;
#if 0
case DisplayDriver::LIGHT :
_color = ST77XX_WHITE;
break;
@ -111,8 +116,10 @@ void ST7789Display::setColor(Color c) {
case DisplayDriver::ORANGE :
_color = ST77XX_ORANGE;
break;
#endif
default:
_color = ST77XX_WHITE;
display.setColor(OLEDDISPLAY_COLOR::WHITE);
break;
}
display.setRGB(_color);
@ -127,6 +134,10 @@ void ST7789Display::print(const char* str) {
display.drawString(_x, _y, str);
}
void ST7789Display::printWordWrap(const char* str, int max_width) {
display.drawStringMaxWidth(_x, _y, max_width*SCALE_X, str);
}
void ST7789Display::fillRect(int x, int y, int w, int h) {
display.fillRect(x*SCALE_X + X_OFFSET, y*SCALE_Y + Y_OFFSET, w*SCALE_X, h*SCALE_Y);
}

View file

@ -4,7 +4,7 @@
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <ST7789Spi.h>
#include "ST7789Spi.h"
class ST7789Display : public DisplayDriver {
ST7789Spi display;
@ -30,6 +30,7 @@ public:
void setColor(Color c) override;
void setCursor(int x, int y) override;
void print(const char* str) override;
void printWordWrap(const char* str, int max_width) override;
void fillRect(int x, int y, int w, int h) override;
void drawRect(int x, int y, int w, int h) override;
void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override;

21
src/helpers/ui/UIScreen.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#include "DisplayDriver.h"
#define KEY_LEFT 0xB4
#define KEY_UP 0xB5
#define KEY_DOWN 0xB6
#define KEY_RIGHT 0xB7
#define KEY_SELECT 10
#define KEY_ENTER 13
#define KEY_BACK 27 // Esc
class UIScreen {
protected:
UIScreen() { }
public:
virtual int render(DisplayDriver& display) =0; // return value is number of millis until next render
virtual bool handleInput(char c) { return false; }
virtual void poll() { }
};

View file

@ -60,7 +60,7 @@ build_flags =
; 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>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Generic_ESPNOW.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -61,7 +61,7 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_ct62.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Heltec_ct62.lib_deps}
${esp32_ota.lib_deps}
@ -80,7 +80,7 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_ct62.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<helpers/esp32/SerialBLEInterface.cpp>
lib_deps =
${Heltec_ct62.lib_deps}

View file

@ -68,7 +68,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Heltec_mesh_solar.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -85,7 +85,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_mesh_solar.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Heltec_mesh_solar.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -39,6 +39,7 @@ extends = Heltec_tracker_base
build_flags =
${Heltec_tracker_base.build_flags}
-I src/helpers/ui
-I examples/companion_radio/ui-new
-D ARDUINO_USB_CDC_ON_BOOT=1 ; need for Serial
-D DISPLAY_ROTATION=1
-D DISPLAY_CLASS=ST7735Display
@ -51,7 +52,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_tracker_base.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
+<helpers/ui/ST7735Display.cpp>
lib_deps =
${Heltec_tracker_base.lib_deps}

View file

@ -21,6 +21,7 @@ HWTSensorManager sensors = HWTSensorManager(nmea);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display(&board.periph_power); // peripheral power pin is shared
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/LocationProvider.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/ST7735Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
class HWTSensorManager : public SensorManager {
@ -36,6 +37,7 @@ extern HWTSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -35,6 +35,7 @@ build_flags =
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<../examples/simple_repeater>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
${esp32_ota.lib_deps}
@ -53,6 +54,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/simple_room_server>
lib_deps =
${Heltec_lora32_v2.lib_deps}
@ -76,6 +78,7 @@ lib_deps =
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -84,7 +87,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -93,6 +98,7 @@ lib_deps =
extends = Heltec_lora32_v2
build_flags =
${Heltec_lora32_v2.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -104,7 +110,9 @@ build_flags =
build_src_filter = ${Heltec_lora32_v2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_lora32_v2.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -18,6 +18,7 @@ SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -9,6 +9,7 @@
#include <helpers/SensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern HeltecV2Board board;
@ -18,6 +19,7 @@ extern SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -6,6 +6,7 @@ build_flags =
${sensor_base.build_flags}
-I variants/heltec_v3
-D HELTEC_LORA_V3
-D ESP32_CPU_FREQ=80
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
@ -16,7 +17,7 @@ build_flags =
-D PIN_VEXT_EN=36
-D SX126X_DIO2_AS_RF_SWITCH=true
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_CURRENT_LIMIT=160
-D SX126X_RX_BOOSTED_GAIN=1
-D PIN_GPS_RX=47
-D PIN_GPS_TX=48
@ -46,6 +47,7 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter}
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
bakercp/CRC32 @ ^2.0.0
[env:Heltec_v3_room_server]
extends = Heltec_lora32_v3
@ -84,6 +86,7 @@ lib_deps =
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
@ -91,7 +94,9 @@ build_flags =
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -100,18 +105,22 @@ lib_deps =
extends = Heltec_lora32_v3
build_flags =
${Heltec_lora32_v3.build_flags}
-D MAX_CONTACTS=100
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=160
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
-D BLE_PIN_CODE=123456 ; dynamic, random PIN
-D AUTO_SHUTDOWN_MILLIVOLTS=3400
-D BLE_DEBUG_LOGGING=1
-D OFFLINE_QUEUE_SIZE=256
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -130,6 +139,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
lib_deps =
@ -172,6 +182,7 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter}
lib_deps =
${Heltec_lora32_v3.lib_deps}
${esp32_ota.lib_deps}
bakercp/CRC32 @ ^2.0.0
[env:Heltec_WSL3_room_server]
extends = Heltec_lora32_v3
@ -203,7 +214,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -217,7 +228,7 @@ build_flags =
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${Heltec_lora32_v3.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${Heltec_lora32_v3.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -25,6 +25,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern HeltecV3Board board;
@ -19,6 +20,7 @@ extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -5,20 +5,6 @@
#ifdef XIAO_NRF52
// redefine lora pins if using the S3 variant of SX1262 board
#ifdef SX1262_XIAO_S3_VARIANT
#undef P_LORA_DIO_1
#undef P_LORA_BUSY
#undef P_LORA_RESET
#undef P_LORA_NSS
#undef SX126X_RXEN
#define P_LORA_DIO_1 D0
#define P_LORA_BUSY D1
#define P_LORA_RESET D2
#define P_LORA_NSS D3
#define SX126X_RXEN D4
#endif
class ikoka_stick_nrf_board : public mesh::MainBoard {
protected:
uint8_t startup_reason;

View file

@ -19,11 +19,10 @@ lib_deps =
adafruit/Adafruit INA3221 Library @ ^1.0.1
adafruit/Adafruit INA219 @ ^1.2.3
adafruit/Adafruit AHTX0 @ ^2.0.5
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit BME280 Library @ ^2.3.0
adafruit/Adafruit SSD1306 @ ^2.5.13
[ikoka_stick_nrf]
[ikoka_stick_nrf_baseboard]
extends = nrf52840_xiao
;board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52840_xiao.build_flags}
@ -34,7 +33,6 @@ build_flags = ${nrf52840_xiao.build_flags}
-D DISPLAY_ROTATION=2
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=9
-D P_LORA_DIO_1=D1
-D P_LORA_RESET=D2
-D P_LORA_BUSY=D3
@ -52,57 +50,96 @@ build_flags = ${nrf52840_xiao.build_flags}
-D ENV_INCLUDE_BME280=1
-D ENV_INCLUDE_INA3221=1
-D ENV_INCLUDE_INA219=1
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/ui/SSD1306Display.cpp>
+<../variants/ikoka_stick_nrf>
debug_tool = jlink
upload_protocol = nrfutil
[env:ikoka_stick_nrf_companion_radio_ble]
extends = ikoka_stick_nrf
;;; abstracted hardware variants
[ikoka_stick_nrf_e22_22dbm]
extends = ikoka_stick_nrf_baseboard
; No PA in this model, full 22dBm
build_flags =
${ikoka_stick_nrf.build_flags}
${ikoka_stick_nrf_baseboard.build_flags}
-D LORA_TX_POWER=22
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../variants/ikoka_stick_nrf>
[ikoka_stick_nrf_e22_30dbm]
extends = ikoka_stick_nrf_baseboard
; limit txpower to 20dBm on E22-900M30S. Anything higher will
; cause distortion in the PA output. 20dBm in -> 30dBm out
build_flags =
${ikoka_stick_nrf_baseboard.build_flags}
-D LORA_TX_POWER=20
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../variants/ikoka_stick_nrf>
[ikoka_stick_nrf_e22_33dbm]
extends = ikoka_stick_nrf_baseboard
; limit txpower to 9dBm on E22-900M33S to avoid hardware damage
; to the rf amplifier frontend. 9dBm in -> 33dBm out
build_flags =
${ikoka_stick_nrf_baseboard.build_flags}
-D LORA_TX_POWER=9
build_src_filter = ${nrf52840_xiao.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../variants/ikoka_stick_nrf>
;;; abstracted firmware roles
[ikoka_stick_nrf_companion_radio_ble]
extends = ikoka_stick_nrf_baseboard
build_flags =
${ikoka_stick_nrf_baseboard.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D OFFLINE_QUEUE_SIZE=256
-I examples/companion_radio/ui-new
; -D BLE_DEBUG_LOGGING=1
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${ikoka_stick_nrf.lib_deps}
${ikoka_stick_nrf_baseboard.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:ikoka_stick_nrf_companion_radio_usb]
extends = ikoka_stick_nrf
[ikoka_stick_nrf_companion_radio_usb]
extends = ikoka_stick_nrf_baseboard
build_flags =
${ikoka_stick_nrf.build_flags}
${ikoka_stick_nrf_baseboard.build_flags}
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-I examples/companion_radio/ui-new
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${ikoka_stick_nrf.lib_deps}
${ikoka_stick_nrf_baseboard.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:ikoka_stick_nrf_alt_pinout_companion_radio_ble]
extends = env:ikoka_stick_nrf_companion_radio_ble
[ikoka_stick_nrf_repeater]
extends = ikoka_stick_nrf_baseboard
build_flags =
${env:ikoka_stick_nrf_companion_radio_ble.build_flags}
-D SX1262_XIAO_S3_VARIANT
[env:ikoka_stick_nrf_repeater]
extends = ikoka_stick_nrf
build_flags =
${ikoka_stick_nrf.build_flags}
${ikoka_stick_nrf_baseboard.build_flags}
-D ADVERT_NAME='"Ikoka Stick Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
@ -110,24 +147,161 @@ build_flags =
-D MAX_NEIGHBOURS=8
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
+<../examples/simple_repeater/main.cpp>
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_repeater/*.cpp>
[env:ikoka_stick_nrf_alt_pinout_repeater]
extends = env:ikoka_stick_nrf_repeater
[ikoka_stick_nrf_room_server]
extends = ikoka_stick_nrf_baseboard
build_flags =
${env:ikoka_stick_nrf_repeater.build_flags}
-D SX1262_XIAO_S3_VARIANT
[env:ikoka_stick_nrf_room_server]
extends = ikoka_stick_nrf
build_flags =
${ikoka_stick_nrf.build_flags}
${ikoka_stick_nrf_baseboard.build_flags}
-D ADVERT_NAME='"Ikoka Stick Room"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
+<../examples/simple_room_server/main.cpp>
build_src_filter = ${ikoka_stick_nrf_baseboard.build_src_filter}
+<../examples/simple_room_server/*.cpp>
;;; hardware + firmware variants
;;; 22dBm EBYTE E22-900M22 variants
[env:ikoka_stick_nrf_22dbm_companion_radio_usb]
extends =
ikoka_stick_nrf_e22_22dbm
ikoka_stick_nrf_companion_radio_usb
build_flags =
${ikoka_stick_nrf_companion_radio_usb.build_flags}
${ikoka_stick_nrf_e22_22dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_usb.build_src_filter}
${ikoka_stick_nrf_e22_22dbm.build_src_filter}
[env:ikoka_stick_nrf_22dbm_companion_radio_ble]
extends =
ikoka_stick_nrf_e22_22dbm
ikoka_stick_nrf_companion_radio_ble
build_flags =
${ikoka_stick_nrf_companion_radio_ble.build_flags}
${ikoka_stick_nrf_e22_22dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_ble.build_src_filter}
${ikoka_stick_nrf_e22_22dbm.build_src_filter}
[env:ikoka_stick_nrf_22dbm_repeater]
extends =
ikoka_stick_nrf_e22_22dbm
ikoka_stick_nrf_repeater
build_flags =
${ikoka_stick_nrf_repeater.build_flags}
${ikoka_stick_nrf_e22_22dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_repeater.build_src_filter}
${ikoka_stick_nrf_e22_22dbm.build_src_filter}
[env:ikoka_stick_nrf_22dbm_room_server]
extends =
ikoka_stick_nrf_e22_22dbm
ikoka_stick_nrf_room_server
build_flags =
${ikoka_stick_nrf_room_server.build_flags}
${ikoka_stick_nrf_e22_22dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_room_server.build_src_filter}
${ikoka_stick_nrf_e22_22dbm.build_src_filter}
;;; 30dBm EBYTE E22-900M30 variants
[env:ikoka_stick_nrf_30dbm_companion_radio_usb]
extends =
ikoka_stick_nrf_e22_30dbm
ikoka_stick_nrf_companion_radio_usb
build_flags =
${ikoka_stick_nrf_companion_radio_usb.build_flags}
${ikoka_stick_nrf_e22_30dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_usb.build_src_filter}
${ikoka_stick_nrf_e22_30dbm.build_src_filter}
[env:ikoka_stick_nrf_30dbm_companion_radio_ble]
extends =
ikoka_stick_nrf_e22_30dbm
ikoka_stick_nrf_companion_radio_ble
build_flags =
${ikoka_stick_nrf_companion_radio_ble.build_flags}
${ikoka_stick_nrf_e22_30dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_ble.build_src_filter}
${ikoka_stick_nrf_e22_30dbm.build_src_filter}
[env:ikoka_stick_nrf_30dbm_repeater]
extends =
ikoka_stick_nrf_e22_30dbm
ikoka_stick_nrf_repeater
build_flags =
${ikoka_stick_nrf_repeater.build_flags}
${ikoka_stick_nrf_e22_30dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_repeater.build_src_filter}
${ikoka_stick_nrf_e22_30dbm.build_src_filter}
[env:ikoka_stick_nrf_30dbm_room_server]
extends =
ikoka_stick_nrf_e22_30dbm
ikoka_stick_nrf_room_server
build_flags =
${ikoka_stick_nrf_room_server.build_flags}
${ikoka_stick_nrf_e22_30dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_room_server.build_src_filter}
${ikoka_stick_nrf_e22_30dbm.build_src_filter}
;;; 33dBm EBYTE E22-900M33 variants
[env:ikoka_stick_nrf_33dbm_companion_radio_usb]
extends =
ikoka_stick_nrf_e22_33dbm
ikoka_stick_nrf_companion_radio_usb
build_flags =
${ikoka_stick_nrf_companion_radio_usb.build_flags}
${ikoka_stick_nrf_e22_33dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_usb.build_src_filter}
${ikoka_stick_nrf_e22_33dbm.build_src_filter}
[env:ikoka_stick_nrf_33dbm_companion_radio_ble]
extends =
ikoka_stick_nrf_e22_33dbm
ikoka_stick_nrf_companion_radio_ble
build_flags =
${ikoka_stick_nrf_companion_radio_ble.build_flags}
${ikoka_stick_nrf_e22_33dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_companion_radio_ble.build_src_filter}
${ikoka_stick_nrf_e22_33dbm.build_src_filter}
[env:ikoka_stick_nrf_33dbm_repeater]
extends =
ikoka_stick_nrf_e22_33dbm
ikoka_stick_nrf_repeater
build_flags =
${ikoka_stick_nrf_repeater.build_flags}
${ikoka_stick_nrf_e22_33dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_repeater.build_src_filter}
${ikoka_stick_nrf_e22_33dbm.build_src_filter}
[env:ikoka_stick_nrf_33dbm_room_server]
extends =
ikoka_stick_nrf_e22_33dbm
ikoka_stick_nrf_room_server
build_flags =
${ikoka_stick_nrf_room_server.build_flags}
${ikoka_stick_nrf_e22_33dbm.build_flags}
build_src_filter =
${ikoka_stick_nrf_room_server.build_src_filter}
${ikoka_stick_nrf_e22_33dbm.build_src_filter}

View file

@ -6,6 +6,7 @@ ikoka_stick_nrf_board board;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);

View file

@ -11,7 +11,9 @@
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
extern ikoka_stick_nrf_board board;

View file

@ -89,6 +89,7 @@ lib_deps =
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -96,7 +97,9 @@ build_flags =
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -105,6 +108,7 @@ lib_deps =
extends = LilyGo_T3S3_sx1262
build_flags =
${LilyGo_T3S3_sx1262.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -116,7 +120,9 @@ build_flags =
build_src_filter = ${LilyGo_T3S3_sx1262.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_T3S3_sx1262.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -13,6 +13,7 @@ SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
#ifndef LORA_CR

View file

@ -9,6 +9,7 @@
#include <helpers/SensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern ESP32Board board;
@ -18,6 +19,7 @@ extern SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -88,6 +88,7 @@ extends = LilyGo_T3S3_sx1276
upload_speed = 115200
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -95,7 +96,9 @@ build_flags =
-D MESH_DEBUG=1
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -104,6 +107,7 @@ lib_deps =
extends = LilyGo_T3S3_sx1276
build_flags =
${LilyGo_T3S3_sx1276.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SSD1306Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -115,7 +119,9 @@ build_flags =
build_src_filter = ${LilyGo_T3S3_sx1276.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_T3S3_sx1276.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -18,6 +18,7 @@ SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -9,6 +9,7 @@
#include <helpers/SensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern ESP32Board board;
@ -18,6 +19,7 @@ extern SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -37,6 +37,7 @@ extends = LilyGo_TBeam_SX1262
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam_SX1262.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -49,7 +50,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam_SX1262.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_TBeam_SX1262.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -25,6 +25,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -9,6 +9,7 @@
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern TBeamBoard board;
@ -18,6 +19,7 @@ extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -36,6 +36,7 @@ extends = LilyGo_TBeam_SX1276
board_build.upload.maximum_ram_size=2000000
build_flags =
${LilyGo_TBeam_SX1276.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -46,7 +47,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_TBeam_SX1276.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_TBeam_SX1276.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -25,6 +25,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -9,6 +9,7 @@
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern TBeamBoard board;
@ -18,6 +19,7 @@ extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -73,6 +73,7 @@ lib_deps =
extends = T_Beam_S3_Supreme_SX1262
build_flags =
${T_Beam_S3_Supreme_SX1262.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -82,7 +83,9 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter}
+<helpers/esp32/*.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${T_Beam_S3_Supreme_SX1262.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -5,6 +5,7 @@ TBeamBoard board;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
static SPIClass spi;

View file

@ -11,6 +11,8 @@
#ifdef DISPLAY_CLASS
#include <helpers/ui/SH1106Display.h>
extern DISPLAY_CLASS display;
#include <helpers/ui/MomentaryButton.h>
extern MomentaryButton user_btn;
#endif
extern TBeamBoard board;

View file

@ -79,7 +79,7 @@ build_flags = ${tlora_c6.build_flags}
build_src_filter = ${tlora_c6.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/ESPNOWRadio.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${tlora_c6.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -83,13 +83,16 @@ lib_deps =
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-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 = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -98,6 +101,7 @@ lib_deps =
extends = LilyGo_TLora_V2_1_1_6
build_flags =
${LilyGo_TLora_V2_1_1_6.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -108,7 +112,9 @@ build_flags =
build_src_filter = ${LilyGo_TLora_V2_1_1_6.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_TLora_V2_1_1_6.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -14,6 +14,7 @@ EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern LilyGoTLoraBoard board;
@ -19,6 +20,7 @@ extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -78,7 +78,7 @@ lib_deps =
[env:Meshadventurer_sx1262_companion_radio_usb]
extends = Meshadventurer
build_src_filter = ${Meshadventurer.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
build_flags =
${Meshadventurer.build_flags}
@ -96,7 +96,7 @@ lib_deps =
[env:Meshadventurer_sx1262_companion_radio_ble]
extends = Meshadventurer
build_src_filter = ${Meshadventurer.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
build_flags =
@ -157,7 +157,7 @@ lib_deps =
[env:Meshadventurer_sx1268_companion_radio_usb]
extends = Meshadventurer
build_src_filter = ${Meshadventurer.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
build_flags =
${Meshadventurer.build_flags}
@ -175,7 +175,7 @@ lib_deps =
[env:Meshadventurer_sx1268_companion_radio_ble]
extends = Meshadventurer
build_src_filter = ${Meshadventurer.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<helpers/esp32/*.cpp>
+<helpers/ui/SSD1306Display.cpp>
build_flags =

View file

@ -51,6 +51,7 @@ lib_deps = ${nrf52840_me25ls01.lib_deps}
[env:Minewsemi_me25ls01_companion_radio_ble]
extends = me25ls01
build_flags = ${me25ls01.build_flags}
-I examples/companion_radio/ui-orig
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -66,6 +67,7 @@ build_flags = ${me25ls01.build_flags}
build_src_filter = ${me25ls01.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps = ${me25ls01.lib_deps}
adafruit/RTClib @ ^2.1.3
@ -146,6 +148,7 @@ lib_deps = ${me25ls01.lib_deps}
[env:Minewsemi_me25ls01_companion_radio_usb]
extends = me25ls01
build_flags = ${me25ls01.build_flags}
-I examples/companion_radio/ui-orig
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
;-D BLE_PIN_CODE=123456
@ -158,7 +161,8 @@ build_flags = ${me25ls01.build_flags}
-D DISPLAY_CLASS=NullDisplayDriver
build_src_filter = ${me25ls01.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps = ${me25ls01.lib_deps}
adafruit/RTClib @ ^2.1.3

View file

@ -34,6 +34,7 @@ extends = Nano_G2_Ultra
build_flags =
${Nano_G2_Ultra.build_flags}
-I src/helpers/ui
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -47,7 +48,9 @@ build_src_filter = ${Nano_G2_Ultra.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<helpers/ui/SH1106Display.cpp>
+<helpers/ui/buzzer.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Nano_G2_Ultra.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -61,6 +64,7 @@ extends = Nano_G2_Ultra
build_flags =
${Nano_G2_Ultra.build_flags}
-I src/helpers/ui
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D OFFLINE_QUEUE_SIZE=256
@ -71,7 +75,9 @@ build_flags =
build_src_filter = ${Nano_G2_Ultra.build_src_filter}
+<helpers/ui/SH1106Display.cpp>
+<helpers/ui/buzzer.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Nano_G2_Ultra.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -1,5 +1,6 @@
#include <Arduino.h>
#include "target.h"
#include <Arduino.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/sensors/MicroNMEALocationProvider.h>
@ -16,29 +17,26 @@ NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init()
{
bool radio_init() {
rtc_clock.begin(Wire);
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed()
{
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr)
{
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)
{
void radio_set_tx_power(uint8_t dbm) {
radio.setOutputPower(dbm);
}
@ -64,8 +62,7 @@ void NanoG2UltraSensorManager::stop_gps() {
_location->stop();
}
bool NanoG2UltraSensorManager::begin()
{
bool NanoG2UltraSensorManager::begin() {
digitalWrite(PIN_GPS_STANDBY, HIGH); // Wake GPS from standby
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
Serial1.begin(9600);
@ -83,29 +80,26 @@ bool NanoG2UltraSensorManager::begin()
return true;
}
bool NanoG2UltraSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry)
{
if (requester_permissions & TELEM_PERM_LOCATION)
{ // does requester have permission?
bool NanoG2UltraSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) {
if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission?
telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude);
}
return true;
}
void NanoG2UltraSensorManager::loop()
{
void NanoG2UltraSensorManager::loop() {
static long next_gps_update = 0;
if (!gps_active) {
return; // GPS is not active, skip further processing
return; // GPS is not active, skip further processing
}
_location->loop();
if (millis() > next_gps_update) {
if (_location->isValid()) {
node_lat = ((double)_location->getLatitude())/1000000.;
node_lon = ((double)_location->getLongitude())/1000000.;
node_lat = ((double)_location->getLatitude()) / 1000000.;
node_lon = ((double)_location->getLongitude()) / 1000000.;
node_altitude = ((double)_location->getAltitude()) / 1000.0;
MESH_DEBUG_PRINTLN("VALID location: lat %f lon %f", node_lat, node_lon);
} else {
@ -116,24 +110,22 @@ void NanoG2UltraSensorManager::loop()
}
}
int NanoG2UltraSensorManager::getNumSettings() const { return 1; } // just one supported: "gps" (power switch)
int NanoG2UltraSensorManager::getNumSettings() const {
return 1;
} // just one supported: "gps" (power switch)
const char *NanoG2UltraSensorManager::getSettingName(int i) const
{
const char *NanoG2UltraSensorManager::getSettingName(int i) const {
return i == 0 ? "gps" : NULL;
}
const char *NanoG2UltraSensorManager::getSettingValue(int i) const
{
if (i == 0)
{
const char *NanoG2UltraSensorManager::getSettingValue(int i) const {
if (i == 0) {
return gps_active ? "1" : "0";
}
return NULL;
}
bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *value)
{
bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *value) {
if (strcmp(name, "gps") == 0) {
if (strcmp(value, "0") == 0) {
stop_gps();
@ -145,8 +137,7 @@ bool NanoG2UltraSensorManager::setSettingValue(const char *name, const char *val
return false; // not supported
}
mesh::LocalIdentity radio_new_identity()
{
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}

View file

@ -1,13 +1,15 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include "nano-g2.h"
#include <helpers/radiolib/RadioLibWrappers.h>
#include <helpers/radiolib/CustomSX1262Wrapper.h>
#include <RadioLib.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/SensorManager.h>
#include <helpers/radiolib/CustomSX1262Wrapper.h>
#include <helpers/radiolib/RadioLibWrappers.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/MomentaryButton.h>
#include <helpers/ui/SH1106Display.h>
#endif
#include <helpers/sensors/LocationProvider.h>
@ -37,6 +39,7 @@ extern NanoG2UltraSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -52,7 +52,7 @@ build_flags = ${picow.build_flags}
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${picow.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps = ${picow.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -66,7 +66,7 @@ lib_deps = ${picow.lib_deps}
; ; -D MESH_PACKET_LOGGING=1
; ; -D MESH_DEBUG=1
; build_src_filter = ${picow.build_src_filter}
; +<../examples/companion_radio>
; +<../examples/companion_radio/*.cpp>
; lib_deps = ${picow.lib_deps}
; densaugeo/base64 @ ~1.4.0
@ -81,7 +81,7 @@ lib_deps = ${picow.lib_deps}
; ; -D MESH_PACKET_LOGGING=1
; ; -D MESH_DEBUG=1
; build_src_filter = ${picow.build_src_filter}
; +<../examples/companion_radio>
; +<../examples/companion_radio/*.cpp>
; lib_deps = ${picow.lib_deps}
; densaugeo/base64 @ ~1.4.0

View file

@ -39,6 +39,7 @@ extends = Faketec
build_src_filter = ${Faketec.build_src_filter}
+<../examples/simple_repeater>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
build_flags =
${Faketec.build_flags}
-D ADVERT_NAME='"Faketec Repeater"'
@ -57,6 +58,7 @@ extends = Faketec
build_src_filter = ${Faketec.build_src_filter}
+<../examples/simple_room_server>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
build_flags = ${Faketec.build_flags}
-D ADVERT_NAME='"Faketec Room"'
-D ADVERT_LAT=0.0
@ -85,14 +87,17 @@ lib_deps = ${Faketec.lib_deps}
[env:Faketec_companion_radio_usb]
extends = Faketec
build_flags = ${Faketec.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D DISPLAY_CLASS=SSD1306Display
; 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>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps = ${Faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0
@ -100,6 +105,7 @@ lib_deps = ${Faketec.lib_deps}
[env:Faketec_companion_radio_ble]
extends = Faketec
build_flags = ${Faketec.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -110,8 +116,10 @@ build_flags = ${Faketec.build_flags}
-D MESH_DEBUG=1
build_src_filter = ${Faketec.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps = ${Faketec.lib_deps}
adafruit/RTClib @ ^2.1.3
densaugeo/base64 @ ~1.4.0
@ -129,6 +137,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Faketec.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/simple_sensor>
lib_deps =
${Faketec.lib_deps}

View file

@ -20,6 +20,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true);
#endif
bool radio_init() {

View file

@ -8,6 +8,7 @@
#include <helpers/AutoDiscoverRTCClock.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
#include <helpers/sensors/EnvironmentSensorManager.h>
@ -19,6 +20,7 @@ extern EnvironmentSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -22,6 +22,8 @@ build_flags = ${nrf52_base.build_flags}
build_src_filter = ${nrf52_base.build_src_filter}
+<../variants/rak4631>
+<helpers/sensors>
+<helpers/ui/SSD1306Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
lib_deps =
${nrf52_base.lib_deps}
${sensor_base.lib_deps}
@ -64,6 +66,7 @@ build_src_filter = ${rak4631.build_src_filter}
extends = rak4631
build_flags =
${rak4631.build_flags}
-I examples/companion_radio/ui-new
-D PIN_USER_BTN=9
-D PIN_USER_BTN_ANA=31
-D DISPLAY_CLASS=SSD1306Display
@ -72,8 +75,8 @@ build_flags =
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -82,6 +85,7 @@ lib_deps =
extends = rak4631
build_flags =
${rak4631.build_flags}
-I examples/companion_radio/ui-new
-D PIN_USER_BTN=9
-D PIN_USER_BTN_ANA=31
-D DISPLAY_CLASS=SSD1306Display
@ -93,9 +97,9 @@ build_flags =
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${rak4631.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -4,8 +4,13 @@
RAK4631Board board;
#ifndef PIN_USER_BTN
#define PIN_USER_BTN (-1)
#endif
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);

View file

@ -11,6 +11,8 @@
#ifdef DISPLAY_CLASS
#include <helpers/ui/SSD1306Display.h>
extern DISPLAY_CLASS display;
#include <helpers/ui/MomentaryButton.h>
extern MomentaryButton user_btn;
#endif
extern RAK4631Board board;

View file

@ -85,7 +85,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${SenseCap_Solar.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${SenseCap_Solar.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -100,7 +100,7 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${SenseCap_Solar.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps =
${SenseCap_Solar.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -22,6 +22,7 @@ build_flags =
build_src_filter = ${esp32_base.build_src_filter}
+<../variants/station_g2>
+<helpers/ui/SH1106Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
lib_deps =
${esp32_base.lib_deps}
adafruit/Adafruit SH110X @ ~2.1.13
@ -44,6 +45,25 @@ lib_deps =
${Station_G2.lib_deps}
${esp32_ota.lib_deps}
[env:Station_G2_logging_repeater]
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-D ADVERT_NAME='"Station G2 Logging Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=8
-D MESH_PACKET_LOGGING=1
-D SX126X_RX_BOOSTED_GAIN=1
; https://wiki.uniteng.com/en/meshtastic/station-g2#impact-of-lora-node-dense-areashigh-noise-environments-on-rf-performance
; -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
build_src_filter = ${Station_G2.build_src_filter}
@ -65,14 +85,16 @@ lib_deps =
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SH1106Display
-D MAX_CONTACTS=100
-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 = ${Station_G2.build_src_filter}
+<helpers/ui/SH1106Display.cpp>
+<../examples/companion_radio>
+<helpers/esp32/*.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Station_G2.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -81,6 +103,7 @@ lib_deps =
extends = Station_G2
build_flags =
${Station_G2.build_flags}
-I examples/companion_radio/ui-new
-D DISPLAY_CLASS=SH1106Display
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
@ -91,8 +114,8 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Station_G2.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/SH1106Display.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Station_G2.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -18,10 +18,7 @@ SensorManager sensors;
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
#ifndef LORA_CR
#define LORA_CR 5
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#ifdef DISPLAY_CLASS
#include <helpers/ui/SH1106Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
extern StationG2Board board;
@ -19,6 +20,7 @@ extern SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -84,12 +84,21 @@ public:
digitalWrite(PIN_3V3_EN, LOW);
#endif
// set led on and wait for button release before poweroff
#ifdef LED_PIN
digitalWrite(LED_PIN, HIGH);
#endif
#ifdef BUTTON_PIN
while(digitalRead(BUTTON_PIN));
#endif
#ifdef LED_PIN
digitalWrite(LED_PIN, LOW);
#endif
#ifdef BUTTON_PIN
nrf_gpio_cfg_sense_input(digitalPinToInterrupt(BUTTON_PIN), NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH);
#endif
sd_power_system_off();
}

View file

@ -37,6 +37,7 @@ upload_protocol = nrfutil
[env:t1000e_companion_radio_ble]
extends = t1000-e
build_flags = ${t1000-e.build_flags}
-I examples/companion_radio/ui-orig
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -53,6 +54,7 @@ build_src_filter = ${t1000-e.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<helpers/ui/buzzer.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps = ${t1000-e.lib_deps}
densaugeo/base64 @ ~1.4.0
stevemarple/MicroNMEA @ ^2.0.6

View file

@ -30,6 +30,7 @@ build_src_filter = ${nrf52840_t114.build_src_filter}
+<helpers/nrf52/T114Board.cpp>
+<../variants/t114>
+<helpers/ui/ST7789Display.cpp>
+<helpers/ui/MomentaryButton.cpp>
+<helpers/ui/OLEDDisplay.cpp>
+<helpers/ui/OLEDDisplayFonts.cpp>
lib_deps =
@ -72,6 +73,7 @@ build_flags =
extends = Heltec_t114
build_flags =
${Heltec_t114.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -81,7 +83,8 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_t114.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_t114.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -90,6 +93,7 @@ lib_deps =
extends = Heltec_t114
build_flags =
${Heltec_t114.build_flags}
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
; -D BLE_PIN_CODE=123456
@ -98,7 +102,8 @@ build_flags =
; -D MESH_DEBUG=1
build_src_filter = ${Heltec_t114.build_src_filter}
+<helpers/nrf52/*.cpp>
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${Heltec_t114.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -16,6 +16,7 @@ T114SensorManager sensors = T114SensorManager(nmea);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/LocationProvider.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/ST7789Display.h>
#include <helpers/ui/MomentaryButton.h>
#endif
class T114SensorManager : public SensorManager {
@ -37,6 +38,7 @@ extern T114SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -21,6 +21,7 @@ build_flags = ${nrf52840_techo.build_flags}
-D LORA_TX_POWER=22
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D P_LORA_TX_LED=LED_GREEN
build_src_filter = ${nrf52840_techo.build_src_filter}
+<helpers/*.cpp>
+<helpers/nrf52/TechoBoard.cpp>
@ -61,19 +62,23 @@ extends = LilyGo_Techo
build_flags =
${LilyGo_Techo.build_flags}
-I src/helpers/ui
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
-D BLE_DEBUG_LOGGING=1
-D DISPLAY_CLASS=GxEPDDisplay
-D OFFLINE_QUEUE_SIZE=256
-D UI_RECENT_LIST_SIZE=9
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${LilyGo_Techo.build_src_filter}
+<helpers/nrf52/TechoBoard.cpp>
+<helpers/nrf52/SerialBLEInterface.cpp>
+<helpers/ui/GxEPDDisplay.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${LilyGo_Techo.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -16,6 +16,7 @@ TechoSensorManager sensors = TechoSensorManager(nmea);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/LocationProvider.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/GxEPDDisplay.h>
#include <helpers/ui/MomentaryButton.h>
#endif
class TechoSensorManager : public SensorManager {
@ -36,6 +37,7 @@ extern TechoSensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -24,6 +24,8 @@ void initVariant() {
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_BLUE, HIGH);
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_RED, HIGH);
pinMode(PIN_TXCO, OUTPUT);
digitalWrite(PIN_TXCO, HIGH);

View file

@ -61,19 +61,15 @@
////////////////////////////////////////////////////////////////////////////////
// Builtin LEDs
#define LED_RED (34)
#define LED_GREEN (33)
#define LED_RED (13)
#define LED_BLUE (14)
#define LED_GREEN (15)
#define PIN_STATUS_LED LED_GREEN
#define LED_BUILTIN LED_GREEN
#define PIN_LED LED_BUILTIN
//#define PIN_STATUS_LED LED_BLUE
#define LED_BUILTIN (-1)
#define LED_PIN LED_BUILTIN
#define LED_STATE_ON LOW
#define PIN_NEOPIXEL (14)
#define NEOPIXEL_NUM (2)
////////////////////////////////////////////////////////////////////////////////
// Builtin buttons

View file

@ -68,6 +68,7 @@ extends = ThinkNode_M1
build_flags =
${ThinkNode_M1.build_flags}
-I src/helpers/ui
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=100
-D MAX_GROUP_CHANNELS=8
-D BLE_PIN_CODE=123456
@ -83,7 +84,9 @@ build_src_filter = ${ThinkNode_M1.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<helpers/ui/GxEPDDisplay.cpp>
+<helpers/ui/buzzer.cpp>
+<../examples/companion_radio>
+<helpers/ui/MomentaryButton.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-new/*.cpp>
lib_deps =
${ThinkNode_M1.lib_deps}
densaugeo/base64 @ ~1.4.0

View file

@ -16,6 +16,7 @@ ThinkNodeM1SensorManager sensors = ThinkNodeM1SensorManager(nmea);
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
#endif
bool radio_init() {

View file

@ -10,6 +10,7 @@
#include <helpers/sensors/LocationProvider.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/GxEPDDisplay.h>
#include <helpers/ui/MomentaryButton.h>
#endif
class ThinkNodeM1SensorManager : public SensorManager {
@ -37,6 +38,7 @@ extern ThinkNodeM1SensorManager sensors;
#ifdef DISPLAY_CLASS
extern DISPLAY_CLASS display;
extern MomentaryButton user_btn;
#endif
bool radio_init();

View file

@ -61,7 +61,7 @@ build_flags = ${waveshare_rp2040_lora.build_flags}
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1
build_src_filter = ${waveshare_rp2040_lora.build_src_filter}
+<../examples/companion_radio>
+<../examples/companion_radio/*.cpp>
lib_deps = ${waveshare_rp2040_lora.lib_deps}
densaugeo/base64 @ ~1.4.0
@ -75,7 +75,7 @@ lib_deps = ${waveshare_rp2040_lora.lib_deps}
; ; -D MESH_PACKET_LOGGING=1
; ; -D MESH_DEBUG=1
; build_src_filter = ${waveshare_rp2040_lora.build_src_filter}
; +<../examples/companion_radio>
; +<../examples/companion_radio/*.cpp>
; lib_deps = ${waveshare_rp2040_lora.lib_deps}
; densaugeo/base64 @ ~1.4.0
@ -90,7 +90,7 @@ lib_deps = ${waveshare_rp2040_lora.lib_deps}
; ; -D MESH_PACKET_LOGGING=1
; ; -D MESH_DEBUG=1
; build_src_filter = ${waveshare_rp2040_lora.build_src_filter}
; +<../examples/companion_radio>
; +<../examples/companion_radio/*.cpp>
; lib_deps = ${waveshare_rp2040_lora.lib_deps}
; densaugeo/base64 @ ~1.4.0

Some files were not shown because too many files have changed in this diff Show more