Merge branch 'develop' into clear-rangetest-results
This commit is contained in:
@@ -146,7 +146,7 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess
|
||||
{
|
||||
int result;
|
||||
#ifdef ARCH_PORTDUINO
|
||||
bool utf = !settingsMap[ascii_logs];
|
||||
bool utf = !portduino_config.ascii_logs;
|
||||
#else
|
||||
bool utf = true;
|
||||
#endif
|
||||
|
||||
@@ -38,4 +38,46 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
|
||||
return useShortName ? "Custom" : "Invalid";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *DisplayFormatters::getDeviceRole(meshtastic_Config_DeviceConfig_Role role)
|
||||
{
|
||||
switch (role) {
|
||||
case meshtastic_Config_DeviceConfig_Role_CLIENT:
|
||||
return "Client";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE:
|
||||
return "Client Mute";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN:
|
||||
return "Client Hidden";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND:
|
||||
return "Lost and Found";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_TRACKER:
|
||||
return "Tracker";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_SENSOR:
|
||||
return "Sensor";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_TAK:
|
||||
return "TAK";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_TAK_TRACKER:
|
||||
return "TAK Tracker";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_ROUTER:
|
||||
return "Router";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_ROUTER_LATE:
|
||||
return "Router Late";
|
||||
break;
|
||||
case meshtastic_Config_DeviceConfig_Role_REPEATER:
|
||||
return "Repeater";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6,4 +6,7 @@ class DisplayFormatters
|
||||
public:
|
||||
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
|
||||
bool usePreset);
|
||||
|
||||
public:
|
||||
static const char *getDeviceRole(meshtastic_Config_DeviceConfig_Role role);
|
||||
};
|
||||
|
||||
@@ -22,6 +22,9 @@ class GPSStatus : public Status
|
||||
|
||||
meshtastic_Position p = meshtastic_Position_init_default;
|
||||
|
||||
/// Time of last valid GPS fix (millis since boot)
|
||||
uint32_t lastFixMillis = 0;
|
||||
|
||||
public:
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
@@ -83,6 +86,9 @@ class GPSStatus : public Status
|
||||
|
||||
uint32_t getNumSatellites() const { return p.sats_in_view; }
|
||||
|
||||
/// Return millis() when the last GPS fix occurred (0 = never)
|
||||
uint32_t getLastFixMillis() const { return lastFixMillis; }
|
||||
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
#ifdef GPS_DEBUG
|
||||
@@ -114,6 +120,9 @@ class GPSStatus : public Status
|
||||
|
||||
if (isDirty) {
|
||||
if (hasLock) {
|
||||
// Record time of last valid GPS fix
|
||||
lastFixMillis = millis();
|
||||
|
||||
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
||||
LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d", p.timestamp,
|
||||
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
||||
|
||||
+24
-11
@@ -833,16 +833,25 @@ void Power::readPowerStatus()
|
||||
newStatus.notifyObservers(&powerStatus2);
|
||||
#ifdef DEBUG_HEAP
|
||||
if (lastheap != memGet.getFreeHeap()) {
|
||||
std::string threadlist = "Threads running:";
|
||||
// Use stack-allocated buffer to avoid heap allocations in monitoring code
|
||||
char threadlist[256] = "Threads running:";
|
||||
int threadlistLen = strlen(threadlist);
|
||||
int running = 0;
|
||||
for (int i = 0; i < MAX_THREADS; i++) {
|
||||
auto thread = concurrency::mainController.get(i);
|
||||
if ((thread != nullptr) && (thread->enabled)) {
|
||||
threadlist += vformat(" %s", thread->ThreadName.c_str());
|
||||
// Use snprintf to safely append to stack buffer without heap allocation
|
||||
int remaining = sizeof(threadlist) - threadlistLen - 1;
|
||||
if (remaining > 0) {
|
||||
int written = snprintf(threadlist + threadlistLen, remaining, " %s", thread->ThreadName.c_str());
|
||||
if (written > 0 && written < remaining) {
|
||||
threadlistLen += written;
|
||||
}
|
||||
}
|
||||
running++;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(threadlist.c_str());
|
||||
LOG_DEBUG(threadlist);
|
||||
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
|
||||
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
|
||||
lastheap = memGet.getFreeHeap();
|
||||
@@ -856,15 +865,19 @@ void Power::readPowerStatus()
|
||||
sprintf(mac, "!%02x%02x%02x%02x", dmac[2], dmac[3], dmac[4], dmac[5]);
|
||||
|
||||
auto newHeap = memGet.getFreeHeap();
|
||||
std::string heapTopic =
|
||||
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/heap/") + std::string(mac);
|
||||
std::string heapString = std::to_string(newHeap);
|
||||
mqtt->pubSub.publish(heapTopic.c_str(), heapString.c_str(), false);
|
||||
// Use stack-allocated buffers to avoid heap allocations in monitoring code
|
||||
char heapTopic[128];
|
||||
snprintf(heapTopic, sizeof(heapTopic), "%s/2/heap/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
||||
char heapString[16];
|
||||
snprintf(heapString, sizeof(heapString), "%u", newHeap);
|
||||
mqtt->pubSub.publish(heapTopic, heapString, false);
|
||||
|
||||
auto wifiRSSI = WiFi.RSSI();
|
||||
std::string wifiTopic =
|
||||
(*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh") + std::string("/2/wifi/") + std::string(mac);
|
||||
std::string wifiString = std::to_string(wifiRSSI);
|
||||
mqtt->pubSub.publish(wifiTopic.c_str(), wifiString.c_str(), false);
|
||||
char wifiTopic[128];
|
||||
snprintf(wifiTopic, sizeof(wifiTopic), "%s/2/wifi/%s", (*moduleConfig.mqtt.root ? moduleConfig.mqtt.root : "msh"), mac);
|
||||
char wifiString[16];
|
||||
snprintf(wifiString, sizeof(wifiString), "%d", wifiRSSI);
|
||||
mqtt->pubSub.publish(wifiTopic, wifiString, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
bool color = !settingsMap[ascii_logs];
|
||||
bool color = !portduino_config.ascii_logs;
|
||||
#else
|
||||
bool color = true;
|
||||
#endif
|
||||
@@ -99,7 +99,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format,
|
||||
size_t r = 0;
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
bool color = !settingsMap[ascii_logs];
|
||||
bool color = !portduino_config.ascii_logs;
|
||||
#else
|
||||
bool color = true;
|
||||
#endif
|
||||
@@ -288,7 +288,7 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
#if ARCH_PORTDUINO
|
||||
// level trace is special, two possible ways to handle it.
|
||||
if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
||||
if (settingsStrings[traceFilename] != "") {
|
||||
if (portduino_config.traceFilename != "") {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
try {
|
||||
@@ -297,18 +297,18 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...)
|
||||
}
|
||||
va_end(arg);
|
||||
}
|
||||
if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
||||
if (portduino_config.logoutputlevel < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) {
|
||||
delete[] newFormat;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
|
||||
if (portduino_config.logoutputlevel < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
|
||||
delete[] newFormat;
|
||||
return;
|
||||
} else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
|
||||
} else if (portduino_config.logoutputlevel < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) {
|
||||
delete[] newFormat;
|
||||
return;
|
||||
} else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
|
||||
} else if (portduino_config.logoutputlevel < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) {
|
||||
delete[] newFormat;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -431,6 +431,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MESHTASTIC_EXCLUDE_SERIAL 1
|
||||
#define MESHTASTIC_EXCLUDE_POWERSTRESS 1
|
||||
#define MESHTASTIC_EXCLUDE_ADMIN 1
|
||||
#define MESHTASTIC_EXCLUDE_AMBIENTLIGHTING 1
|
||||
#endif
|
||||
|
||||
// // Turn off wifi even if HW supports wifi (webserver relies on wifi and is also disabled)
|
||||
|
||||
@@ -80,6 +80,7 @@ class ScanI2C
|
||||
LTR553ALS,
|
||||
BHI260AP,
|
||||
BMM150,
|
||||
TSL2561,
|
||||
DRV2605
|
||||
} DeviceType;
|
||||
|
||||
|
||||
@@ -461,7 +461,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
|
||||
SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address);
|
||||
case TSL25911_ADDR:
|
||||
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
|
||||
if (registerValue == 0x50) {
|
||||
type = TSL2591;
|
||||
logFoundDevice("TSL25911", (uint8_t)addr.address);
|
||||
} else {
|
||||
type = TSL2561;
|
||||
logFoundDevice("TSL2561", (uint8_t)addr.address);
|
||||
}
|
||||
break;
|
||||
|
||||
SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address);
|
||||
SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address);
|
||||
|
||||
+19
-6
@@ -808,6 +808,14 @@ bool GPS::setup()
|
||||
} else {
|
||||
LOG_INFO("GNSS module configuration saved!");
|
||||
}
|
||||
} else if (gnssModel == GNSS_MODEL_CM121) {
|
||||
// only ask for RMC and GGA
|
||||
// enable GGA
|
||||
_serial_gps->write("$CFGMSG,0,0,1,1*1B\r\n");
|
||||
delay(250);
|
||||
// enable RMC
|
||||
_serial_gps->write("$CFGMSG,0,4,1,1*1F\r\n");
|
||||
delay(250);
|
||||
}
|
||||
didSerialInit = true;
|
||||
}
|
||||
@@ -1240,9 +1248,15 @@ GnssModel_t GPS::probe(int serialSpeed)
|
||||
_serial_gps->write("$PUBX,40,GSV,0,0,0,0,0,0*59\r\n");
|
||||
_serial_gps->write("$PUBX,40,VTG,0,0,0,0,0,0*5E\r\n");
|
||||
delay(20);
|
||||
// Close NMEA sequences on CM121
|
||||
_serial_gps->write("$CFGMSG,0,1,0,1*1B\r\n");
|
||||
_serial_gps->write("$CFGMSG,0,2,0,1*18\r\n");
|
||||
_serial_gps->write("$CFGMSG,0,3,0,1*19\r\n");
|
||||
delay(20);
|
||||
|
||||
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A
|
||||
std::vector<ChipInfo> unicore = {{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}};
|
||||
// Unicore UFirebirdII Series: UC6580, UM620, UM621, UM670A, UM680A, or UM681A,or CM121
|
||||
std::vector<ChipInfo> unicore = {
|
||||
{"UC6580", "UC6580", GNSS_MODEL_UC6580}, {"UM600", "UM600", GNSS_MODEL_UC6580}, {"CM121", "CM121", GNSS_MODEL_CM121}};
|
||||
PROBE_FAMILY("Unicore Family", "$PDTINFO", unicore, 500);
|
||||
|
||||
std::vector<ChipInfo> atgm = {
|
||||
@@ -1422,7 +1436,7 @@ GPS *GPS::createGps()
|
||||
_en_gpio = PIN_GPS_EN;
|
||||
#endif
|
||||
#ifdef ARCH_PORTDUINO
|
||||
if (!settingsMap[has_gps])
|
||||
if (!portduino_config.has_gps)
|
||||
return nullptr;
|
||||
#endif
|
||||
if (!_rx_gpio || !_serial_gps) // Configured to have no GPS at all
|
||||
@@ -1532,10 +1546,9 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
||||
t.tm_year = d.year() - 1900;
|
||||
t.tm_isdst = false;
|
||||
if (t.tm_mon > -1) {
|
||||
LOG_DEBUG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min,
|
||||
t.tm_sec, ti.age());
|
||||
if (perhapsSetRTC(RTCQualityGPS, t) == RTCSetResultSuccess) {
|
||||
LOG_DEBUG("Time set.");
|
||||
LOG_DEBUG("NMEA GPS time set %02d-%02d-%02d %02d:%02d:%02d age %d", d.year(), d.month(), t.tm_mday, t.tm_hour,
|
||||
t.tm_min, t.tm_sec, ti.age());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
+2
-1
@@ -31,7 +31,8 @@ typedef enum {
|
||||
GNSS_MODEL_MTK_PA1616S,
|
||||
GNSS_MODEL_AG3335,
|
||||
GNSS_MODEL_AG3352,
|
||||
GNSS_MODEL_LS20031
|
||||
GNSS_MODEL_LS20031,
|
||||
GNSS_MODEL_CM121
|
||||
} GnssModel_t;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -130,11 +130,15 @@ RTCSetResult perhapsSetRTC(RTCQuality q, const struct timeval *tv, bool forceUpd
|
||||
uint32_t printableEpoch = tv->tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv->tv_sec < BUILD_EPOCH) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
#endif
|
||||
return RTCSetResultInvalidTime;
|
||||
} else if (tv->tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
|
||||
BUILD_EPOCH + FORTY_YEARS);
|
||||
#endif
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
@@ -252,11 +256,15 @@ RTCSetResult perhapsSetRTC(RTCQuality q, struct tm &t)
|
||||
uint32_t printableEpoch = tv.tv_sec; // Print lib only supports 32 bit but time_t can be 64 bit on some platforms
|
||||
#ifdef BUILD_EPOCH
|
||||
if (tv.tv_sec < BUILD_EPOCH) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_WARN("Ignore time (%ld) before build epoch (%ld)!", printableEpoch, BUILD_EPOCH);
|
||||
#endif
|
||||
return RTCSetResultInvalidTime;
|
||||
} else if (tv.tv_sec > (BUILD_EPOCH + FORTY_YEARS)) {
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_WARN("Ignore time (%ld) too far in the future (build epoch: %ld, max allowed: %ld)!", printableEpoch, BUILD_EPOCH,
|
||||
BUILD_EPOCH + FORTY_YEARS);
|
||||
#endif
|
||||
return RTCSetResultInvalidTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
+12
-2
@@ -370,7 +370,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
#elif ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
if (portduino_config.displayPanel != no_screen) {
|
||||
LOG_DEBUG("Make TFTDisplay!");
|
||||
dispdev = new TFTDisplay(address.address, -1, -1, geometry,
|
||||
(address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE);
|
||||
@@ -618,7 +618,7 @@ void Screen::setup()
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
if (portduino_config.touchscreenModule) {
|
||||
touchScreenImpl1 =
|
||||
new TouchScreenImpl1(dispdev->getWidth(), dispdev->getHeight(), static_cast<TFTDisplay *>(dispdev)->getTouch);
|
||||
touchScreenImpl1->init();
|
||||
@@ -1018,6 +1018,11 @@ void Screen::setFrames(FrameFocus focus)
|
||||
indicatorIcons.push_back(digital_icon_clock);
|
||||
}
|
||||
#endif
|
||||
if (!hiddenFrames.chirpy) {
|
||||
fsi.positions.chirpy = numframes;
|
||||
normalFrames[numframes++] = graphics::DebugRenderer::drawChirpy;
|
||||
indicatorIcons.push_back(small_chirpy);
|
||||
}
|
||||
|
||||
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||||
if (!hiddenFrames.wifi && isWifiAvailable()) {
|
||||
@@ -1186,6 +1191,9 @@ void Screen::toggleFrameVisibility(const std::string &frameName)
|
||||
if (frameName == "show_favorites") {
|
||||
hiddenFrames.show_favorites = !hiddenFrames.show_favorites;
|
||||
}
|
||||
if (frameName == "chirpy") {
|
||||
hiddenFrames.chirpy = !hiddenFrames.chirpy;
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen::isFrameHidden(const std::string &frameName) const
|
||||
@@ -1214,6 +1222,8 @@ bool Screen::isFrameHidden(const std::string &frameName) const
|
||||
return hiddenFrames.clock;
|
||||
if (frameName == "show_favorites")
|
||||
return hiddenFrames.show_favorites;
|
||||
if (frameName == "chirpy")
|
||||
return hiddenFrames.chirpy;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -669,6 +669,7 @@ class Screen : public concurrency::OSThread
|
||||
uint8_t nodelist_distance = 255;
|
||||
uint8_t nodelist_bearings = 255;
|
||||
uint8_t clock = 255;
|
||||
uint8_t chirpy = 255;
|
||||
uint8_t firstFavorite = 255;
|
||||
uint8_t lastFavorite = 255;
|
||||
uint8_t lora = 255;
|
||||
@@ -698,6 +699,7 @@ class Screen : public concurrency::OSThread
|
||||
#endif
|
||||
bool lora = false;
|
||||
bool show_favorites = false;
|
||||
bool chirpy = true;
|
||||
} hiddenFrames;
|
||||
|
||||
/// Try to start drawing ASAP
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "RTC.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/draw/UIRenderer.h"
|
||||
#include "main.h"
|
||||
#include "meshtastic/config.pb.h"
|
||||
#include "power.h"
|
||||
@@ -16,6 +17,10 @@ void determineResolution(int16_t screenheight, int16_t screenwidth)
|
||||
isHighResolution = true;
|
||||
}
|
||||
|
||||
if (screenwidth > 128 && screenheight <= 64) {
|
||||
isHighResolution = false;
|
||||
}
|
||||
|
||||
// Special case for Heltec Wireless Tracker v1.1
|
||||
if (screenwidth == 160 && screenheight == 80) {
|
||||
isHighResolution = false;
|
||||
@@ -53,7 +58,7 @@ void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w,
|
||||
// *************************
|
||||
// * Common Header Drawing *
|
||||
// *************************
|
||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only)
|
||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool force_no_invert, bool show_date)
|
||||
{
|
||||
constexpr int HEADER_OFFSET_Y = 1;
|
||||
y += HEADER_OFFSET_Y;
|
||||
@@ -69,7 +74,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
const int screenW = display->getWidth();
|
||||
const int screenH = display->getHeight();
|
||||
|
||||
if (!battery_only) {
|
||||
if (!force_no_invert) {
|
||||
// === Inverted Header Background ===
|
||||
if (isInverted) {
|
||||
display->setColor(BLACK);
|
||||
@@ -187,13 +192,28 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
int timeStrWidth = display->getStringWidth("12:34"); // Default alignment
|
||||
int timeX = screenW - xOffset - timeStrWidth + 4;
|
||||
|
||||
if (rtc_sec > 0 && !battery_only) {
|
||||
if (rtc_sec > 0) {
|
||||
// === Build Time String ===
|
||||
long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY;
|
||||
int hour = hms / SEC_PER_HOUR;
|
||||
int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||||
snprintf(timeStr, sizeof(timeStr), "%d:%02d", hour, minute);
|
||||
|
||||
// === Build Date String ===
|
||||
char datetimeStr[25];
|
||||
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, false);
|
||||
char dateLine[40];
|
||||
|
||||
if (isHighResolution) {
|
||||
snprintf(dateLine, sizeof(dateLine), "%s", datetimeStr);
|
||||
} else {
|
||||
if (hasUnreadMessage) {
|
||||
snprintf(dateLine, sizeof(dateLine), "%s", &datetimeStr[5]);
|
||||
} else {
|
||||
snprintf(dateLine, sizeof(dateLine), "%s", &datetimeStr[2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.display.use_12h_clock) {
|
||||
bool isPM = hour >= 12;
|
||||
hour %= 12;
|
||||
@@ -202,7 +222,11 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
snprintf(timeStr, sizeof(timeStr), "%d:%02d%s", hour, minute, isPM ? "p" : "a");
|
||||
}
|
||||
|
||||
timeStrWidth = display->getStringWidth(timeStr);
|
||||
if (show_date) {
|
||||
timeStrWidth = display->getStringWidth(dateLine);
|
||||
} else {
|
||||
timeStrWidth = display->getStringWidth(timeStr);
|
||||
}
|
||||
timeX = screenW - xOffset - timeStrWidth + 3;
|
||||
|
||||
// === Show Mail or Mute Icon to the Left of Time ===
|
||||
@@ -229,7 +253,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
int iconW = 16, iconH = 12;
|
||||
int iconX = iconRightEdge - iconW;
|
||||
int iconY = textY + (FONT_HEIGHT_SMALL - iconH) / 2 - 1;
|
||||
if (isInverted) {
|
||||
if (isInverted && !force_no_invert) {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(iconX - 1, iconY - 1, iconW + 3, iconH + 2);
|
||||
display->setColor(BLACK);
|
||||
@@ -244,7 +268,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
} else {
|
||||
int iconX = iconRightEdge - (mail_width - 2);
|
||||
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
|
||||
if (isInverted) {
|
||||
if (isInverted && !force_no_invert) {
|
||||
display->setColor(WHITE);
|
||||
display->fillRect(iconX - 1, iconY - 1, mail_width + 2, mail_height + 2);
|
||||
display->setColor(BLACK);
|
||||
@@ -287,10 +311,17 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
|
||||
}
|
||||
}
|
||||
|
||||
// === Draw Time ===
|
||||
display->drawString(timeX, textY, timeStr);
|
||||
if (isBold)
|
||||
display->drawString(timeX - 1, textY, timeStr);
|
||||
if (show_date) {
|
||||
// === Draw Date ===
|
||||
display->drawString(timeX, textY, dateLine);
|
||||
if (isBold)
|
||||
display->drawString(timeX - 1, textY, dateLine);
|
||||
} else {
|
||||
// === Draw Time ===
|
||||
display->drawString(timeX, textY, timeStr);
|
||||
if (isBold)
|
||||
display->drawString(timeX - 1, textY, timeStr);
|
||||
}
|
||||
|
||||
} else {
|
||||
// === No Time Available: Mail/Mute Icon Moves to Far Right ===
|
||||
|
||||
@@ -49,7 +49,8 @@ void determineResolution(int16_t screenheight, int16_t screenwidth);
|
||||
void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r);
|
||||
|
||||
// Shared battery/time/mail header
|
||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool battery_only = false);
|
||||
void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool force_no_invert = false,
|
||||
bool show_date = false);
|
||||
|
||||
const int *getTextPositions(OLEDDisplay *display);
|
||||
|
||||
|
||||
+53
-44
@@ -767,24 +767,24 @@ class LGFX : public lgfx::LGFX_Device
|
||||
|
||||
LGFX(void)
|
||||
{
|
||||
if (settingsMap[displayPanel] == st7789)
|
||||
if (portduino_config.displayPanel == st7789)
|
||||
_panel_instance = new lgfx::Panel_ST7789;
|
||||
else if (settingsMap[displayPanel] == st7735)
|
||||
else if (portduino_config.displayPanel == st7735)
|
||||
_panel_instance = new lgfx::Panel_ST7735;
|
||||
else if (settingsMap[displayPanel] == st7735s)
|
||||
else if (portduino_config.displayPanel == st7735s)
|
||||
_panel_instance = new lgfx::Panel_ST7735S;
|
||||
else if (settingsMap[displayPanel] == st7796)
|
||||
else if (portduino_config.displayPanel == st7796)
|
||||
_panel_instance = new lgfx::Panel_ST7796;
|
||||
else if (settingsMap[displayPanel] == ili9341)
|
||||
else if (portduino_config.displayPanel == ili9341)
|
||||
_panel_instance = new lgfx::Panel_ILI9341;
|
||||
else if (settingsMap[displayPanel] == ili9342)
|
||||
else if (portduino_config.displayPanel == ili9342)
|
||||
_panel_instance = new lgfx::Panel_ILI9342;
|
||||
else if (settingsMap[displayPanel] == ili9488)
|
||||
else if (portduino_config.displayPanel == ili9488)
|
||||
_panel_instance = new lgfx::Panel_ILI9488;
|
||||
else if (settingsMap[displayPanel] == hx8357d)
|
||||
else if (portduino_config.displayPanel == hx8357d)
|
||||
_panel_instance = new lgfx::Panel_HX8357D;
|
||||
#if defined(LGFX_SDL)
|
||||
else if (settingsMap[displayPanel] == x11) {
|
||||
else if (portduino_config.displayPanel == x11) {
|
||||
_panel_instance = new lgfx::Panel_sdl;
|
||||
}
|
||||
#endif
|
||||
@@ -795,61 +795,61 @@ class LGFX : public lgfx::LGFX_Device
|
||||
|
||||
auto buscfg = _bus_instance.config();
|
||||
buscfg.spi_mode = 0;
|
||||
buscfg.spi_host = settingsMap[displayspidev];
|
||||
buscfg.spi_host = portduino_config.display_spi_dev_int;
|
||||
|
||||
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||
buscfg.pin_dc = portduino_config.displayDC.pin; // Set SPI DC pin number (-1 = disable)
|
||||
|
||||
_bus_instance.config(buscfg); // applies the set value to the bus.
|
||||
_panel_instance->setBus(&_bus_instance); // set the bus on the panel.
|
||||
|
||||
auto cfg = _panel_instance->config(); // Gets a structure for display panel settings.
|
||||
LOG_DEBUG("Width: %d, Height: %d", settingsMap[displayWidth], settingsMap[displayHeight]);
|
||||
cfg.pin_cs = settingsMap[displayCS]; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = settingsMap[displayReset];
|
||||
if (settingsMap[displayRotate]) {
|
||||
cfg.panel_width = settingsMap[displayHeight]; // actual displayable width
|
||||
cfg.panel_height = settingsMap[displayWidth]; // actual displayable height
|
||||
LOG_DEBUG("Width: %d, Height: %d", portduino_config.displayWidth, portduino_config.displayHeight);
|
||||
cfg.pin_cs = portduino_config.displayCS.pin; // Pin number where CS is connected (-1 = disable)
|
||||
cfg.pin_rst = portduino_config.displayReset.pin;
|
||||
if (portduino_config.displayRotate) {
|
||||
cfg.panel_width = portduino_config.displayHeight; // actual displayable width
|
||||
cfg.panel_height = portduino_config.displayWidth; // actual displayable height
|
||||
} else {
|
||||
cfg.panel_width = settingsMap[displayWidth]; // actual displayable width
|
||||
cfg.panel_height = settingsMap[displayHeight]; // actual displayable height
|
||||
cfg.panel_width = portduino_config.displayWidth; // actual displayable width
|
||||
cfg.panel_height = portduino_config.displayHeight; // actual displayable height
|
||||
}
|
||||
cfg.offset_x = settingsMap[displayOffsetX]; // Panel offset amount in X direction
|
||||
cfg.offset_y = settingsMap[displayOffsetY]; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = settingsMap[displayOffsetRotate]; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.invert = settingsMap[displayInvert]; // Set to true if the light/darkness of the panel is reversed
|
||||
cfg.offset_x = portduino_config.displayOffsetX; // Panel offset amount in X direction
|
||||
cfg.offset_y = portduino_config.displayOffsetY; // Panel offset amount in Y direction
|
||||
cfg.offset_rotation = portduino_config.displayOffsetRotate; // Rotation direction value offset 0~7 (4~7 is mirrored)
|
||||
cfg.invert = portduino_config.displayInvert; // Set to true if the light/darkness of the panel is reversed
|
||||
|
||||
_panel_instance->config(cfg);
|
||||
|
||||
// Configure settings for touch control.
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
if (settingsMap[touchscreenModule] == xpt2046) {
|
||||
if (portduino_config.touchscreenModule) {
|
||||
if (portduino_config.touchscreenModule == xpt2046) {
|
||||
_touch_instance = new lgfx::Touch_XPT2046;
|
||||
} else if (settingsMap[touchscreenModule] == stmpe610) {
|
||||
} else if (portduino_config.touchscreenModule == stmpe610) {
|
||||
_touch_instance = new lgfx::Touch_STMPE610;
|
||||
} else if (settingsMap[touchscreenModule] == ft5x06) {
|
||||
} else if (portduino_config.touchscreenModule == ft5x06) {
|
||||
_touch_instance = new lgfx::Touch_FT5x06;
|
||||
}
|
||||
auto touch_cfg = _touch_instance->config();
|
||||
|
||||
touch_cfg.pin_cs = settingsMap[touchscreenCS];
|
||||
touch_cfg.pin_cs = portduino_config.touchscreenCS.pin;
|
||||
touch_cfg.x_min = 0;
|
||||
touch_cfg.x_max = settingsMap[displayHeight] - 1;
|
||||
touch_cfg.x_max = portduino_config.displayHeight - 1;
|
||||
touch_cfg.y_min = 0;
|
||||
touch_cfg.y_max = settingsMap[displayWidth] - 1;
|
||||
touch_cfg.pin_int = settingsMap[touchscreenIRQ];
|
||||
touch_cfg.y_max = portduino_config.displayWidth - 1;
|
||||
touch_cfg.pin_int = portduino_config.touchscreenIRQ.pin;
|
||||
touch_cfg.bus_shared = true;
|
||||
touch_cfg.offset_rotation = settingsMap[touchscreenRotate];
|
||||
if (settingsMap[touchscreenI2CAddr] != -1) {
|
||||
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
|
||||
touch_cfg.offset_rotation = portduino_config.touchscreenRotate;
|
||||
if (portduino_config.touchscreenI2CAddr != -1) {
|
||||
touch_cfg.i2c_addr = portduino_config.touchscreenI2CAddr;
|
||||
} else {
|
||||
touch_cfg.spi_host = settingsMap[touchscreenspidev];
|
||||
touch_cfg.spi_host = portduino_config.touchscreen_spi_dev_int;
|
||||
}
|
||||
|
||||
_touch_instance->config(touch_cfg);
|
||||
_panel_instance->setTouch(_touch_instance);
|
||||
}
|
||||
#if defined(LGFX_SDL)
|
||||
if (settingsMap[displayPanel] == x11) {
|
||||
if (portduino_config.displayPanel == x11) {
|
||||
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)_panel_instance;
|
||||
sdl_panel_->setup();
|
||||
sdl_panel_->addKeyCodeMapping(SDLK_RETURN, SDL_SCANCODE_KP_ENTER);
|
||||
@@ -1115,10 +1115,10 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
||||
backlightEnable = p;
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[displayRotate]) {
|
||||
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayWidth], settingsMap[configNames::displayHeight]);
|
||||
if (portduino_config.displayRotate) {
|
||||
setGeometry(GEOMETRY_RAWMODE, portduino_config.displayWidth, portduino_config.displayWidth);
|
||||
} else {
|
||||
setGeometry(GEOMETRY_RAWMODE, settingsMap[configNames::displayHeight], settingsMap[configNames::displayWidth]);
|
||||
setGeometry(GEOMETRY_RAWMODE, portduino_config.displayHeight, portduino_config.displayHeight);
|
||||
}
|
||||
|
||||
#elif defined(SCREEN_ROTATE)
|
||||
@@ -1128,6 +1128,15 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY g
|
||||
#endif
|
||||
}
|
||||
|
||||
TFTDisplay::~TFTDisplay()
|
||||
{
|
||||
// Clean up allocated line pixel buffer to prevent memory leak
|
||||
if (linePixelBuffer != nullptr) {
|
||||
free(linePixelBuffer);
|
||||
linePixelBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the buffer to the display memory
|
||||
void TFTDisplay::display(bool fromBlank)
|
||||
{
|
||||
@@ -1231,7 +1240,7 @@ void TFTDisplay::sdlLoop()
|
||||
#if defined(LGFX_SDL)
|
||||
static int lastPressed = 0;
|
||||
static int shuttingDown = false;
|
||||
if (settingsMap[displayPanel] == x11) {
|
||||
if (portduino_config.displayPanel == x11) {
|
||||
lgfx::Panel_sdl *sdl_panel_ = (lgfx::Panel_sdl *)tft->_panel_instance;
|
||||
if (sdl_panel_->loop() && !shuttingDown) {
|
||||
LOG_WARN("Window Closed!");
|
||||
@@ -1279,8 +1288,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
backlightEnable->set(true);
|
||||
#if ARCH_PORTDUINO
|
||||
display(true);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], TFT_BACKLIGHT_ON);
|
||||
if (portduino_config.displayBacklight.pin > 0)
|
||||
digitalWrite(portduino_config.displayBacklight.pin, TFT_BACKLIGHT_ON);
|
||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||
tft->wakeup();
|
||||
tft->powerSaveOff();
|
||||
@@ -1303,8 +1312,8 @@ void TFTDisplay::sendCommand(uint8_t com)
|
||||
backlightEnable->set(false);
|
||||
#if ARCH_PORTDUINO
|
||||
tft->clear();
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
digitalWrite(settingsMap[displayBacklight], !TFT_BACKLIGHT_ON);
|
||||
if (portduino_config.displayBacklight.pin > 0)
|
||||
digitalWrite(portduino_config.displayBacklight.pin, !TFT_BACKLIGHT_ON);
|
||||
#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE)
|
||||
tft->sleep();
|
||||
tft->powerSaveOn();
|
||||
|
||||
@@ -20,6 +20,9 @@ class TFTDisplay : public OLEDDisplay
|
||||
*/
|
||||
TFTDisplay(uint8_t, int, int, OLEDDISPLAY_GEOMETRY, HW_I2C);
|
||||
|
||||
// Destructor to clean up allocated memory
|
||||
~TFTDisplay();
|
||||
|
||||
// Write the buffer to the display memory
|
||||
virtual void display() override { display(false); };
|
||||
virtual void display(bool fromBlank);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#if HAS_SCREEN
|
||||
#include "ClockRenderer.h"
|
||||
#include "NodeDB.h"
|
||||
#include "UIRenderer.h"
|
||||
#include "configuration.h"
|
||||
#include "gps/GeoCoord.h"
|
||||
#include "gps/RTC.h"
|
||||
@@ -190,7 +189,7 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
// === Set Title, Blank for Clock
|
||||
const char *titleStr = "";
|
||||
// === Header ===
|
||||
graphics::drawCommonHeader(display, x, y, titleStr, true);
|
||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
||||
@@ -294,6 +293,7 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
display->drawString(startingHourMinuteTextX + xOffset, (display->getHeight() - hourMinuteTextY) - yOffset - 2,
|
||||
isPM ? "pm" : "am");
|
||||
}
|
||||
|
||||
#ifndef USE_EINK
|
||||
xOffset = (isHighResolution) ? 18 : 10;
|
||||
display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset,
|
||||
@@ -313,7 +313,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// === Set Title, Blank for Clock
|
||||
const char *titleStr = "";
|
||||
// === Header ===
|
||||
graphics::drawCommonHeader(display, x, y, titleStr, true);
|
||||
graphics::drawCommonHeader(display, x, y, titleStr, true, true);
|
||||
|
||||
#ifdef T_WATCH_S3
|
||||
if (nimbleBluetooth && nimbleBluetooth->isConnected()) {
|
||||
|
||||
@@ -391,18 +391,27 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
int nameX = (SCREEN_WIDTH - textWidth);
|
||||
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
|
||||
|
||||
// === Second Row: Radio Preset ===
|
||||
// === Second Row: Role ===
|
||||
auto role = DisplayFormatters::getDeviceRole(config.device.role);
|
||||
char device_role[25];
|
||||
snprintf(device_role, sizeof(device_role), "Role: %s", role);
|
||||
textWidth = display->getStringWidth(device_role);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], device_role);
|
||||
|
||||
// === Third Row: Radio Preset ===
|
||||
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
|
||||
|
||||
char regionradiopreset[25];
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
if (region != nullptr) {
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
|
||||
snprintf(regionradiopreset, sizeof(regionradiopreset), "Reg: %s/%s", region, mode);
|
||||
}
|
||||
textWidth = display->getStringWidth(regionradiopreset);
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], regionradiopreset);
|
||||
|
||||
// === Third Row: Frequency / ChanNum ===
|
||||
// === Fourth Row: Frequency / ChanNum ===
|
||||
char frequencyslot[35];
|
||||
char freqStr[16];
|
||||
float freq = RadioLibInterface::instance->getFreq();
|
||||
@@ -420,7 +429,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
nameX = (SCREEN_WIDTH - textWidth) / 2;
|
||||
display->drawString(nameX, getTextPositions(display)[line++], frequencyslot);
|
||||
|
||||
// === Fourth Row: Channel Utilization ===
|
||||
// === Fifth Row: Channel Utilization ===
|
||||
const char *chUtil = "ChUtil:";
|
||||
char chUtilPercentage[10];
|
||||
snprintf(chUtilPercentage, sizeof(chUtilPercentage), "%2.0f%%", airTime->channelUtilizationPercent());
|
||||
@@ -437,7 +446,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
int total_line_content_width = (chUtil_x + chutil_bar_width + display->getStringWidth(chUtilPercentage) + extraoffset) / 2;
|
||||
int starting_position = centerofscreen - total_line_content_width;
|
||||
|
||||
display->drawString(starting_position, getTextPositions(display)[line++], chUtil);
|
||||
display->drawString(starting_position, getTextPositions(display)[line], chUtil);
|
||||
|
||||
// Force 56% or higher to show a full 100% bar, text would still show related percent.
|
||||
if (chutil_percent >= 61) {
|
||||
@@ -474,7 +483,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
display->fillRect(starting_position + chUtil_x, chUtil_y, fillRight, chutil_bar_height);
|
||||
}
|
||||
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[4],
|
||||
display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[line++],
|
||||
chUtilPercentage);
|
||||
}
|
||||
|
||||
@@ -625,6 +634,33 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
display->drawString(nameX, getTextPositions(display)[line], uptimeStr);
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************
|
||||
// * Chirpy Screen *
|
||||
// ****************************
|
||||
void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
int line = 1;
|
||||
int iconX = SCREEN_WIDTH - chirpy_width - (chirpy_width / 3);
|
||||
int iconY = (SCREEN_HEIGHT - chirpy_height) / 2;
|
||||
int textX_offset = 10;
|
||||
if (isHighResolution) {
|
||||
iconX = SCREEN_WIDTH - chirpy_width_hirez - (chirpy_width_hirez / 3);
|
||||
iconY = (SCREEN_HEIGHT - chirpy_height_hirez) / 2;
|
||||
textX_offset = textX_offset * 4;
|
||||
display->drawXbm(iconX, iconY, chirpy_width_hirez, chirpy_height_hirez, chirpy_hirez);
|
||||
} else {
|
||||
display->drawXbm(iconX, iconY, chirpy_width, chirpy_height, chirpy);
|
||||
}
|
||||
|
||||
int textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("Hello") / 2);
|
||||
display->drawString(textX, getTextPositions(display)[line++], "Hello");
|
||||
textX = (display->getWidth() / 2) - textX_offset - (display->getStringWidth("World!") / 2);
|
||||
display->drawString(textX, getTextPositions(display)[line++], "World!");
|
||||
}
|
||||
} // namespace DebugRenderer
|
||||
} // namespace graphics
|
||||
#endif
|
||||
@@ -33,6 +33,9 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
|
||||
|
||||
// System screen display
|
||||
void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
|
||||
// Chirpy screen display
|
||||
void drawChirpy(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
} // namespace DebugRenderer
|
||||
|
||||
} // namespace graphics
|
||||
|
||||
@@ -31,17 +31,19 @@ uint8_t test_count = 0;
|
||||
|
||||
void menuHandler::loraMenu()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Region Picker"};
|
||||
enum optionsNumbers { Back = 0, lora_picker = 1 };
|
||||
static const char *optionsArray[] = {"Back", "Region Picker", "Device Role"};
|
||||
enum optionsNumbers { Back = 0, lora_picker = 1, device_role_picker = 2 };
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "LoRa Actions";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.optionsCount = 3;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Back) {
|
||||
// No action
|
||||
} else if (selected == lora_picker) {
|
||||
menuHandler::menuQueue = menuHandler::lora_picker;
|
||||
} else if (selected == device_role_picker) {
|
||||
menuHandler::menuQueue = menuHandler::device_role_picker;
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
@@ -140,6 +142,40 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::DeviceRolePicker()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "Client", "Client Mute", "Lost and Found", "Tracker"};
|
||||
enum optionsNumbers {
|
||||
Back = 0,
|
||||
devicerole_client = 1,
|
||||
devicerole_clientmute = 2,
|
||||
devicerole_lostandfound = 3,
|
||||
devicerole_tracker = 4
|
||||
};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Device Role";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 5;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Back) {
|
||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
||||
screen->runNow();
|
||||
return;
|
||||
} else if (selected == devicerole_client) {
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||
} else if (selected == devicerole_clientmute) {
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT_MUTE;
|
||||
} else if (selected == devicerole_lostandfound) {
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_LOST_AND_FOUND;
|
||||
} else if (selected == devicerole_tracker) {
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_TRACKER;
|
||||
}
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
}
|
||||
|
||||
void menuHandler::TwelveHourPicker()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "12-hour", "24-hour"};
|
||||
@@ -968,16 +1004,33 @@ void menuHandler::traceRouteMenu()
|
||||
void menuHandler::testMenu()
|
||||
{
|
||||
|
||||
static const char *optionsArray[] = {"Back", "Number Picker"};
|
||||
enum optionsNumbers { Back, NumberPicker, ShowChirpy };
|
||||
static const char *optionsArray[4] = {"Back"};
|
||||
static int optionsEnumArray[4] = {Back};
|
||||
int options = 1;
|
||||
|
||||
optionsArray[options] = "Number Picker";
|
||||
optionsEnumArray[options++] = NumberPicker;
|
||||
|
||||
optionsArray[options] = screen->isFrameHidden("chirpy") ? "Show Chirpy" : "Hide Chirpy";
|
||||
optionsEnumArray[options++] = ShowChirpy;
|
||||
|
||||
BannerOverlayOptions bannerOptions;
|
||||
std::string message = "Test to Run?\n";
|
||||
bannerOptions.message = message.c_str();
|
||||
bannerOptions.message = "Hidden Test Menu";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 2;
|
||||
bannerOptions.optionsCount = options;
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == 1) {
|
||||
if (selected == NumberPicker) {
|
||||
menuQueue = number_test;
|
||||
screen->runNow();
|
||||
} else if (selected == ShowChirpy) {
|
||||
screen->toggleFrameVisibility("chirpy");
|
||||
screen->setFrames(Screen::FOCUS_SYSTEM);
|
||||
|
||||
} else {
|
||||
menuQueue = system_base_menu;
|
||||
screen->runNow();
|
||||
}
|
||||
};
|
||||
screen->showOverlayBanner(bannerOptions);
|
||||
@@ -1232,7 +1285,7 @@ void menuHandler::FrameToggles_menu()
|
||||
bannerOptions.optionsEnumPtr = optionsEnumArray;
|
||||
bannerOptions.InitialSelected = lastSelectedIndex; // Use index, not enum value
|
||||
|
||||
bannerOptions.bannerCallback = [optionsEnumArray, options](int selected) mutable -> void {
|
||||
bannerOptions.bannerCallback = [options](int selected) mutable -> void {
|
||||
// Find the index of selected in optionsEnumArray
|
||||
int idx = 0;
|
||||
for (; idx < options; ++idx) {
|
||||
@@ -1291,9 +1344,15 @@ void menuHandler::handleMenuSwitch(OLEDDisplay *display)
|
||||
switch (menuQueue) {
|
||||
case menu_none:
|
||||
break;
|
||||
case lora_Menu:
|
||||
loraMenu();
|
||||
break;
|
||||
case lora_picker:
|
||||
LoraRegionPicker();
|
||||
break;
|
||||
case device_role_picker:
|
||||
DeviceRolePicker();
|
||||
break;
|
||||
case no_timeout_lora_picker:
|
||||
LoraRegionPicker(0);
|
||||
break;
|
||||
|
||||
@@ -9,7 +9,9 @@ class menuHandler
|
||||
public:
|
||||
enum screenMenus {
|
||||
menu_none,
|
||||
lora_Menu,
|
||||
lora_picker,
|
||||
device_role_picker,
|
||||
no_timeout_lora_picker,
|
||||
TZ_picker,
|
||||
twelve_hour_picker,
|
||||
@@ -46,6 +48,7 @@ class menuHandler
|
||||
static void OnboardMessage();
|
||||
static void LoraRegionPicker(uint32_t duration = 30000);
|
||||
static void loraMenu();
|
||||
static void DeviceRolePicker();
|
||||
static void handleMenuSwitch(OLEDDisplay *display);
|
||||
static void showConfirmationBanner(const char *message, std::function<void()> onConfirm);
|
||||
static void clockMenu();
|
||||
|
||||
@@ -879,7 +879,26 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
config.display.heading_bold = false;
|
||||
|
||||
const char *displayLine = ""; // Initialize to empty string by default
|
||||
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum());
|
||||
|
||||
bool usePhoneGPS = (ourNode && nodeDB->hasValidPosition(ourNode) &&
|
||||
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED);
|
||||
|
||||
if (usePhoneGPS) {
|
||||
// Phone-provided GPS is active
|
||||
displayLine = "Phone GPS";
|
||||
int yOffset = (isHighResolution) ? 3 : 1;
|
||||
if (isHighResolution) {
|
||||
NodeListRenderer::drawScaledXBitmap16x16(x, getTextPositions(display)[line] + yOffset - 5, imgSatellite_width,
|
||||
imgSatellite_height, imgSatellite, display);
|
||||
} else {
|
||||
display->drawXbm(x + 1, getTextPositions(display)[line] + yOffset, imgSatellite_width, imgSatellite_height,
|
||||
imgSatellite);
|
||||
}
|
||||
int xOffset = (isHighResolution) ? 6 : 0;
|
||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
||||
} else if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
// GPS disabled / not present
|
||||
if (config.position.fixed_position) {
|
||||
displayLine = "Fixed GPS";
|
||||
} else {
|
||||
@@ -896,6 +915,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
int xOffset = (isHighResolution) ? 6 : 0;
|
||||
display->drawString(x + 11 + xOffset, getTextPositions(display)[line++], displayLine);
|
||||
} else {
|
||||
// Onboard GPS
|
||||
UIRenderer::drawGps(display, 0, getTextPositions(display)[line++], gpsStatus);
|
||||
}
|
||||
|
||||
@@ -922,32 +942,61 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU
|
||||
|
||||
// If GPS is off, no need to display these parts
|
||||
if (strcmp(displayLine, "GPS off") != 0 && strcmp(displayLine, "No GPS") != 0) {
|
||||
// === Second Row: Last GPS Fix ===
|
||||
if (gpsStatus->getLastFixMillis() > 0) {
|
||||
uint32_t delta = (millis() - gpsStatus->getLastFixMillis()) / 1000; // seconds since last fix
|
||||
uint32_t days = delta / 86400;
|
||||
uint32_t hours = (delta % 86400) / 3600;
|
||||
uint32_t mins = (delta % 3600) / 60;
|
||||
uint32_t secs = delta % 60;
|
||||
|
||||
// === Second Row: Date ===
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
char datetimeStr[25];
|
||||
bool showTime = false; // set to true for full datetime
|
||||
UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||
char fullLine[40];
|
||||
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
|
||||
display->drawString(0, getTextPositions(display)[line++], fullLine);
|
||||
char buf[32];
|
||||
#if defined(USE_EINK)
|
||||
// E-Ink: skip seconds, show only days/hours/mins
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), " Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), " Last: %uh %um", hours, mins);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), " Last: %um", mins);
|
||||
}
|
||||
#else
|
||||
// Non E-Ink: include seconds where useful
|
||||
if (days > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %ud %uh", days, hours);
|
||||
} else if (hours > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %uh %um", hours, mins);
|
||||
} else if (mins > 0) {
|
||||
snprintf(buf, sizeof(buf), "Last: %um %us", mins, secs);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Last: %us", secs);
|
||||
}
|
||||
#endif
|
||||
|
||||
display->drawString(0, getTextPositions(display)[line++], buf);
|
||||
} else {
|
||||
display->drawString(0, getTextPositions(display)[line++], "Last: ?");
|
||||
}
|
||||
|
||||
// === Third Row: Latitude ===
|
||||
char latStr[32];
|
||||
snprintf(latStr, sizeof(latStr), " Lat: %.5f", geoCoord.getLatitude() * 1e-7);
|
||||
snprintf(latStr, sizeof(latStr), "Lat: %.5f", geoCoord.getLatitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++], latStr);
|
||||
|
||||
// === Fourth Row: Longitude ===
|
||||
char lonStr[32];
|
||||
snprintf(lonStr, sizeof(lonStr), " Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||
snprintf(lonStr, sizeof(lonStr), "Lon: %.5f", geoCoord.getLongitude() * 1e-7);
|
||||
display->drawString(x, getTextPositions(display)[line++], lonStr);
|
||||
|
||||
// === Fifth Row: Altitude ===
|
||||
char DisplayLineTwo[32] = {0};
|
||||
int32_t alt = (strcmp(displayLine, "Phone GPS") == 0 && ourNode && nodeDB->hasValidPosition(ourNode))
|
||||
? ourNode->position.altitude
|
||||
: geoCoord.getAltitude();
|
||||
if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) {
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0fft", geoCoord.getAltitude() * METERS_TO_FEET);
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), "Alt: %.0fft", geoCoord.getAltitude() * METERS_TO_FEET);
|
||||
} else {
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), " Alt: %.0im", geoCoord.getAltitude());
|
||||
snprintf(DisplayLineTwo, sizeof(DisplayLineTwo), "Alt: %.0im", geoCoord.getAltitude());
|
||||
}
|
||||
display->drawString(x, getTextPositions(display)[line++], DisplayLineTwo);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "NodeDB.h"
|
||||
#include "graphics/Screen.h"
|
||||
#include "graphics/emotes.h"
|
||||
#include <OLEDDisplay.h>
|
||||
|
||||
@@ -288,5 +288,77 @@ const uint8_t digital_icon_clock[] PROGMEM = {0b00111100, 0b01000010, 0b10000101
|
||||
const uint8_t analog_icon_clock[] PROGMEM = {0b11111111, 0b01000010, 0b00100100, 0b00011000,
|
||||
0b00100100, 0b01000010, 0b01000010, 0b11111111};
|
||||
|
||||
#define chirpy_width 38
|
||||
#define chirpy_height 50
|
||||
static unsigned char chirpy[] = {
|
||||
0xfe, 0xff, 0xff, 0xff, 0xdf, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x80, 0xe3, 0x01,
|
||||
0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0xc0, 0xe7, 0x01, 0x00, 0x00, 0x80, 0xe3, 0x01, 0x00,
|
||||
0x00, 0x00, 0xe0, 0x81, 0xff, 0xff, 0x7f, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xcf, 0x7f,
|
||||
0xfe, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc,
|
||||
0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0,
|
||||
0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0x87, 0x3f, 0xfc, 0xe0, 0xc1,
|
||||
0x87, 0x3f, 0xfc, 0xe0, 0xc1, 0xcf, 0x7f, 0xfe, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0x81, 0xff,
|
||||
0xff, 0x7f, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0xc3, 0x00, 0xe0, 0x01, 0x00, 0xc3,
|
||||
0x00, 0xe0, 0x01, 0x80, 0xe1, 0x01, 0xe0, 0x01, 0x80, 0xe1, 0x01, 0xe0, 0x01, 0xc0, 0x30, 0x03, 0xe0, 0x01, 0xc0, 0x30, 0x03,
|
||||
0xe0, 0x01, 0x60, 0x18, 0x06, 0xe0, 0x01, 0x60, 0x18, 0x06, 0xe0, 0x01, 0x30, 0x0c, 0x0c, 0xe0, 0x01, 0x30, 0x0c, 0x0c, 0xe0,
|
||||
0x01, 0x18, 0x06, 0x18, 0xe0, 0x01, 0x18, 0x06, 0x18, 0xe0, 0x01, 0x0c, 0x03, 0x30, 0xe0, 0x01, 0x0c, 0x03, 0x30, 0xe0, 0x01,
|
||||
0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xdf};
|
||||
|
||||
#define chirpy_width_hirez 76
|
||||
#define chirpy_height_hirez 100
|
||||
static unsigned char chirpy_hirez[] = {
|
||||
0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00,
|
||||
0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc,
|
||||
0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03,
|
||||
0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0,
|
||||
0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f,
|
||||
0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0,
|
||||
0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff,
|
||||
0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f,
|
||||
0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0,
|
||||
0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff,
|
||||
0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00,
|
||||
0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc,
|
||||
0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03,
|
||||
0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0,
|
||||
0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f,
|
||||
0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0,
|
||||
0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0x3f, 0xc0, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff,
|
||||
0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xf0, 0xff, 0x3f, 0xfc, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0xfc, 0x03, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x00, 0xfc, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
|
||||
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03,
|
||||
0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00,
|
||||
0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
|
||||
0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0, 0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xc0,
|
||||
0x03, 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00,
|
||||
0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0xf0, 0x00, 0x0f,
|
||||
0x0f, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c,
|
||||
0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x3c, 0xc0, 0x03, 0x3c, 0x00,
|
||||
0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00,
|
||||
0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0xf0, 0x00, 0x00, 0xfc,
|
||||
0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03,
|
||||
0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0x03, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xfc, 0x03, 0x00,
|
||||
0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0,
|
||||
0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0x00, 0x0f, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf3, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3};
|
||||
|
||||
#define chirpy_small_image_width 8
|
||||
#define chirpy_small_image_height 8
|
||||
static unsigned char small_chirpy[] = {0x7f, 0x41, 0x55, 0x55, 0x55, 0x55, 0x41, 0x7f};
|
||||
|
||||
#include "img/icon.xbm"
|
||||
static_assert(sizeof(icon_bits) >= 0, "Silence unused variable warning");
|
||||
+48
-48
@@ -41,78 +41,78 @@ void tftSetup(void)
|
||||
PacketAPI::create(PacketServer::init());
|
||||
deviceScreen->init(new PacketClient);
|
||||
#else
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
if (portduino_config.displayPanel != no_screen) {
|
||||
DisplayDriverConfig displayConfig;
|
||||
static char *panels[] = {"NOSCREEN", "X11", "FB", "ST7789", "ST7735", "ST7735S",
|
||||
"ST7796", "ILI9341", "ILI9342", "ILI9486", "ILI9488", "HX8357D"};
|
||||
static char *touch[] = {"NOTOUCH", "XPT2046", "STMPE610", "GT911", "FT5x06"};
|
||||
#if defined(USE_X11)
|
||||
if (settingsMap[displayPanel] == x11) {
|
||||
if (settingsMap[displayWidth] && settingsMap[displayHeight])
|
||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)settingsMap[displayWidth],
|
||||
(uint16_t)settingsMap[displayHeight]);
|
||||
if (portduino_config.displayPanel == x11) {
|
||||
if (portduino_config.displayWidth && portduino_config.displayHeight)
|
||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::X11, (uint16_t)portduino_config.displayWidth,
|
||||
(uint16_t)portduino_config.displayHeight);
|
||||
else
|
||||
displayConfig.device(DisplayDriverConfig::device_t::X11);
|
||||
} else
|
||||
#elif defined(USE_FRAMEBUFFER)
|
||||
if (settingsMap[displayPanel] == fb) {
|
||||
if (settingsMap[displayWidth] && settingsMap[displayHeight])
|
||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)settingsMap[displayWidth],
|
||||
(uint16_t)settingsMap[displayHeight]);
|
||||
if (portduino_config.displayPanel == fb) {
|
||||
if (portduino_config.displayWidth && portduino_config.displayHeight)
|
||||
displayConfig = DisplayDriverConfig(DisplayDriverConfig::device_t::FB, (uint16_t)portduino_config.displayWidth,
|
||||
(uint16_t)portduino_config.displayHeight);
|
||||
else
|
||||
displayConfig.device(DisplayDriverConfig::device_t::FB);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
displayConfig.device(DisplayDriverConfig::device_t::CUSTOM_TFT)
|
||||
.panel(DisplayDriverConfig::panel_config_t{.type = panels[settingsMap[displayPanel]],
|
||||
.panel_width = (uint16_t)settingsMap[displayWidth],
|
||||
.panel_height = (uint16_t)settingsMap[displayHeight],
|
||||
.rotation = (bool)settingsMap[displayRotate],
|
||||
.pin_cs = (int16_t)settingsMap[displayCS],
|
||||
.pin_rst = (int16_t)settingsMap[displayReset],
|
||||
.offset_x = (uint16_t)settingsMap[displayOffsetX],
|
||||
.offset_y = (uint16_t)settingsMap[displayOffsetY],
|
||||
.offset_rotation = (uint8_t)settingsMap[displayOffsetRotate],
|
||||
.invert = settingsMap[displayInvert] ? true : false,
|
||||
.rgb_order = (bool)settingsMap[displayRGBOrder],
|
||||
.dlen_16bit = settingsMap[displayPanel] == ili9486 ||
|
||||
settingsMap[displayPanel] == ili9488})
|
||||
.bus(DisplayDriverConfig::bus_config_t{.freq_write = (uint32_t)settingsMap[displayBusFrequency],
|
||||
.panel(DisplayDriverConfig::panel_config_t{.type = panels[portduino_config.displayPanel],
|
||||
.panel_width = (uint16_t)portduino_config.displayWidth,
|
||||
.panel_height = (uint16_t)portduino_config.displayHeight,
|
||||
.rotation = (bool)portduino_config.displayRotate,
|
||||
.pin_cs = (int16_t)portduino_config.displayCS.pin,
|
||||
.pin_rst = (int16_t)portduino_config.displayReset.pin,
|
||||
.offset_x = (uint16_t)portduino_config.displayOffsetX,
|
||||
.offset_y = (uint16_t)portduino_config.displayOffsetY,
|
||||
.offset_rotation = (uint8_t)portduino_config.displayOffsetRotate,
|
||||
.invert = portduino_config.displayInvert ? true : false,
|
||||
.rgb_order = (bool)portduino_config.displayRGBOrder,
|
||||
.dlen_16bit = portduino_config.displayPanel == ili9486 ||
|
||||
portduino_config.displayPanel == ili9488})
|
||||
.bus(DisplayDriverConfig::bus_config_t{.freq_write = (uint32_t)portduino_config.displayBusFrequency,
|
||||
.freq_read = 16000000,
|
||||
.spi{.pin_dc = (int8_t)settingsMap[displayDC],
|
||||
.spi{.pin_dc = (int8_t)portduino_config.displayDC.pin,
|
||||
.use_lock = true,
|
||||
.spi_host = (uint16_t)settingsMap[displayspidev]}})
|
||||
.input(DisplayDriverConfig::input_config_t{.keyboardDevice = settingsStrings[keyboardDevice],
|
||||
.pointerDevice = settingsStrings[pointerDevice]})
|
||||
.light(DisplayDriverConfig::light_config_t{.pin_bl = (int16_t)settingsMap[displayBacklight],
|
||||
.pwm_channel = (int8_t)settingsMap[displayBacklightPWMChannel],
|
||||
.invert = (bool)settingsMap[displayBacklightInvert]});
|
||||
if (settingsMap[touchscreenI2CAddr] == -1) {
|
||||
.spi_host = (uint16_t)portduino_config.display_spi_dev_int}})
|
||||
.input(DisplayDriverConfig::input_config_t{.keyboardDevice = portduino_config.keyboardDevice,
|
||||
.pointerDevice = portduino_config.pointerDevice})
|
||||
.light(DisplayDriverConfig::light_config_t{.pin_bl = (int16_t)portduino_config.displayBacklight.pin,
|
||||
.pwm_channel = (int8_t)portduino_config.displayBacklightPWMChannel.pin,
|
||||
.invert = (bool)portduino_config.displayBacklightInvert});
|
||||
if (portduino_config.touchscreenI2CAddr == -1) {
|
||||
displayConfig.touch(
|
||||
DisplayDriverConfig::touch_config_t{.type = touch[settingsMap[touchscreenModule]],
|
||||
.freq = (uint32_t)settingsMap[touchscreenBusFrequency],
|
||||
.pin_int = (int16_t)settingsMap[touchscreenIRQ],
|
||||
.offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
|
||||
DisplayDriverConfig::touch_config_t{.type = touch[portduino_config.touchscreenModule],
|
||||
.freq = (uint32_t)portduino_config.touchscreenBusFrequency,
|
||||
.pin_int = (int16_t)portduino_config.touchscreenIRQ.pin,
|
||||
.offset_rotation = (uint8_t)portduino_config.touchscreenRotate,
|
||||
.spi{
|
||||
.spi_host = (int8_t)settingsMap[touchscreenspidev],
|
||||
.spi_host = (int8_t)portduino_config.touchscreen_spi_dev_int,
|
||||
},
|
||||
.pin_cs = (int16_t)settingsMap[touchscreenCS]});
|
||||
.pin_cs = (int16_t)portduino_config.touchscreenCS.pin});
|
||||
} else {
|
||||
displayConfig.touch(DisplayDriverConfig::touch_config_t{
|
||||
.type = touch[settingsMap[touchscreenModule]],
|
||||
.freq = (uint32_t)settingsMap[touchscreenBusFrequency],
|
||||
.type = touch[portduino_config.touchscreenModule],
|
||||
.freq = (uint32_t)portduino_config.touchscreenBusFrequency,
|
||||
.x_min = 0,
|
||||
.x_max =
|
||||
(int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayWidth] : settingsMap[displayHeight]) -
|
||||
1),
|
||||
.x_max = (int16_t)((portduino_config.touchscreenRotate & 1 ? portduino_config.displayWidth
|
||||
: portduino_config.displayHeight) -
|
||||
1),
|
||||
.y_min = 0,
|
||||
.y_max =
|
||||
(int16_t)((settingsMap[touchscreenRotate] & 1 ? settingsMap[displayHeight] : settingsMap[displayWidth]) -
|
||||
1),
|
||||
.pin_int = (int16_t)settingsMap[touchscreenIRQ],
|
||||
.offset_rotation = (uint8_t)settingsMap[touchscreenRotate],
|
||||
.i2c{.i2c_addr = (uint8_t)settingsMap[touchscreenI2CAddr]}});
|
||||
.y_max = (int16_t)((portduino_config.touchscreenRotate & 1 ? portduino_config.displayHeight
|
||||
: portduino_config.displayWidth) -
|
||||
1),
|
||||
.pin_int = (int16_t)portduino_config.touchscreenIRQ.pin,
|
||||
.offset_rotation = (uint8_t)portduino_config.touchscreenRotate,
|
||||
.i2c{.i2c_addr = (uint8_t)portduino_config.touchscreenI2CAddr}});
|
||||
}
|
||||
}
|
||||
deviceScreen = &DeviceScreen::create(&displayConfig);
|
||||
|
||||
@@ -33,9 +33,9 @@ int32_t LinuxInput::runOnce()
|
||||
{
|
||||
|
||||
if (firstTime) {
|
||||
if (settingsStrings[keyboardDevice] == "")
|
||||
if (portduino_config.keyboardDevice == "")
|
||||
return disable();
|
||||
fd = open(settingsStrings[keyboardDevice].c_str(), O_RDWR);
|
||||
fd = open(portduino_config.keyboardDevice.c_str(), O_RDWR);
|
||||
if (fd < 0)
|
||||
return disable();
|
||||
ret = ioctl(fd, EVIOCGRAB, (void *)1);
|
||||
|
||||
@@ -40,10 +40,7 @@ bool RotaryEncoderImpl::init()
|
||||
|
||||
int32_t RotaryEncoderImpl::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = INPUT_BROKER_NONE;
|
||||
e.source = this->originName;
|
||||
|
||||
InputEvent e{originName, INPUT_BROKER_NONE, 0, 0, 0};
|
||||
static uint32_t lastPressed = millis();
|
||||
if (rotary->readButton() == RotaryEncoder::ButtonState::BUTTON_PRESSED) {
|
||||
if (lastPressed + 200 < millis()) {
|
||||
@@ -70,7 +67,7 @@ int32_t RotaryEncoderImpl::runOnce()
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
return 20;
|
||||
return 10;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -18,7 +18,7 @@ TouchScreenImpl1::TouchScreenImpl1(uint16_t width, uint16_t height, bool (*getTo
|
||||
void TouchScreenImpl1::init()
|
||||
{
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[touchscreenModule]) {
|
||||
if (portduino_config.touchscreenModule) {
|
||||
TouchScreenBase::init(true);
|
||||
inputBroker->registerSource(this);
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef TB_DIRECTION
|
||||
#if ARCH_PORTDUINO
|
||||
#include "PortduinoGlue.h"
|
||||
#define TB_DIRECTION (PinStatus) settingsMap[tbDirection]
|
||||
#define TB_DIRECTION (PinStatus) portduino_config.lora_usb_vid
|
||||
#else
|
||||
#define TB_DIRECTION RISING
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,11 @@ void CardKbI2cImpl::init()
|
||||
if (cardkb_found.address == 0x00) {
|
||||
LOG_DEBUG("Rescan for I2C keyboard");
|
||||
uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR, MPR121_KB_ADDR, TCA8418_KB_ADDR};
|
||||
#if defined(T_LORA_PAGER)
|
||||
uint8_t i2caddr_asize = sizeof(i2caddr_scan) / sizeof(i2caddr_scan[0]);
|
||||
#else
|
||||
uint8_t i2caddr_asize = 5;
|
||||
#endif
|
||||
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
|
||||
|
||||
#if WIRE_INTERFACES_COUNT == 2
|
||||
|
||||
+54
-55
@@ -390,7 +390,7 @@ void setup()
|
||||
|
||||
concurrency::hasBeenSetup = true;
|
||||
#if ARCH_PORTDUINO
|
||||
SPISettings spiSettings(settingsMap[spiSpeed], MSBFIRST, SPI_MODE0);
|
||||
SPISettings spiSettings(portduino_config.spiSpeed, MSBFIRST, SPI_MODE0);
|
||||
#else
|
||||
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
|
||||
#endif
|
||||
@@ -535,9 +535,9 @@ void setup()
|
||||
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
|
||||
Wire.begin(I2C_SDA, I2C_SCL);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if (settingsStrings[i2cdev] != "") {
|
||||
LOG_INFO("Use %s as I2C device", settingsStrings[i2cdev].c_str());
|
||||
Wire.begin(settingsStrings[i2cdev].c_str());
|
||||
if (portduino_config.i2cdev != "") {
|
||||
LOG_INFO("Use %s as I2C device", portduino_config.i2cdev.c_str());
|
||||
Wire.begin(portduino_config.i2cdev.c_str());
|
||||
} else {
|
||||
LOG_INFO("No I2C device configured, Skip");
|
||||
}
|
||||
@@ -583,7 +583,7 @@ void setup()
|
||||
#if defined(I2C_SDA)
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if (settingsStrings[i2cdev] != "") {
|
||||
if (portduino_config.i2cdev != "") {
|
||||
LOG_INFO("Scan for i2c devices");
|
||||
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
|
||||
}
|
||||
@@ -743,6 +743,7 @@ void setup()
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PCT2075, meshtastic_TelemetrySensorType_PCT2075);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SCD4X, meshtastic_TelemetrySensorType_SCD4X);
|
||||
scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2561, meshtastic_TelemetrySensorType_TSL2561);
|
||||
|
||||
i2cScanner.reset();
|
||||
#endif
|
||||
@@ -855,7 +856,7 @@ void setup()
|
||||
SPI.begin(false);
|
||||
#endif // HW_SPI1_DEVICE
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsStrings[spidev] != "ch341") {
|
||||
if (portduino_config.lora_spi_dev != "ch341") {
|
||||
SPI.begin();
|
||||
}
|
||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||
@@ -881,7 +882,7 @@ void setup()
|
||||
defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(ST7796_CS)
|
||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || portduino_config.displayPanel) &&
|
||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
screen = new graphics::Screen(screen_found, screen_model, screen_geometry);
|
||||
}
|
||||
@@ -982,13 +983,13 @@ void setup()
|
||||
#endif
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
|
||||
if (settingsMap.count(userButtonPin) != 0 && settingsMap[userButtonPin] != RADIOLIB_NC) {
|
||||
if (portduino_config.userButtonPin.enabled) {
|
||||
|
||||
LOG_DEBUG("Use GPIO%02d for button", settingsMap[userButtonPin]);
|
||||
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
|
||||
UserButtonThread = new ButtonThread("UserButton");
|
||||
if (screen) {
|
||||
ButtonConfig config;
|
||||
config.pinNumber = (uint8_t)settingsMap[userButtonPin];
|
||||
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
|
||||
config.activeLow = true;
|
||||
config.activePullup = true;
|
||||
config.pullupSense = INPUT_PULLUP;
|
||||
@@ -1145,7 +1146,7 @@ void setup()
|
||||
if (screen)
|
||||
screen->setup();
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) &&
|
||||
if ((screen_found.port != ScanI2C::I2CPort::NO_I2C || portduino_config.displayPanel) &&
|
||||
config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
screen->setup();
|
||||
}
|
||||
@@ -1161,15 +1162,10 @@ void setup()
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
const struct {
|
||||
configNames cfgName;
|
||||
std::string strName;
|
||||
} loraModules[] = {{use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"}, {use_sx1280, "sx1280"},
|
||||
{use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
// as one can't use a function pointer to the class constructor:
|
||||
auto loraModuleInterface = [](configNames cfgName, LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy) {
|
||||
switch (cfgName) {
|
||||
auto loraModuleInterface = [](LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
|
||||
RADIOLIB_PIN_TYPE busy) {
|
||||
switch (portduino_config.lora_module) {
|
||||
case use_rf95:
|
||||
return (RadioInterface *)new RF95Interface(hal, cs, irq, rst, busy);
|
||||
case use_sx1262:
|
||||
@@ -1186,31 +1182,34 @@ void setup()
|
||||
return (RadioInterface *)new LR1121Interface(hal, cs, irq, rst, busy);
|
||||
case use_llcc68:
|
||||
return (RadioInterface *)new LLCC68Interface(hal, cs, irq, rst, busy);
|
||||
case use_simradio:
|
||||
return (RadioInterface *)new SimRadio;
|
||||
default:
|
||||
assert(0); // shouldn't happen
|
||||
return (RadioInterface *)nullptr;
|
||||
}
|
||||
};
|
||||
for (auto &loraModule : loraModules) {
|
||||
if (settingsMap[loraModule.cfgName] && !rIf) {
|
||||
LOG_DEBUG("Activate %s radio on SPI port %s", loraModule.strName.c_str(), settingsStrings[spidev].c_str());
|
||||
if (settingsStrings[spidev] == "ch341") {
|
||||
RadioLibHAL = ch341Hal;
|
||||
} else {
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
}
|
||||
rIf = loraModuleInterface(loraModule.cfgName, (LockingArduinoHal *)RadioLibHAL, settingsMap[cs_pin],
|
||||
settingsMap[irq_pin], settingsMap[reset_pin], settingsMap[busy_pin]);
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No %s radio", loraModule.strName.c_str());
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("%s init success", loraModule.strName.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("Activate %s radio on SPI port %s", portduino_config.loraModules[portduino_config.lora_module].c_str(),
|
||||
portduino_config.lora_spi_dev.c_str());
|
||||
if (portduino_config.lora_spi_dev == "ch341") {
|
||||
RadioLibHAL = ch341Hal;
|
||||
} else {
|
||||
RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
||||
}
|
||||
rIf =
|
||||
loraModuleInterface((LockingArduinoHal *)RadioLibHAL, portduino_config.lora_cs_pin.pin, portduino_config.lora_irq_pin.pin,
|
||||
portduino_config.lora_reset_pin.pin, portduino_config.lora_busy_pin.pin);
|
||||
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No %s radio", portduino_config.loraModules[portduino_config.lora_module].c_str());
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
LOG_INFO("%s init success", portduino_config.loraModules[portduino_config.lora_module].c_str());
|
||||
}
|
||||
|
||||
#elif defined(HW_SPI1_DEVICE)
|
||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI1, spiSettings);
|
||||
#else // HW_SPI1_DEVICE
|
||||
@@ -1232,20 +1231,6 @@ void setup()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_PORTDUINO)
|
||||
if (!rIf) {
|
||||
rIf = new SimRadio;
|
||||
if (!rIf->init()) {
|
||||
LOG_WARN("No simulated radio");
|
||||
delete rIf;
|
||||
rIf = NULL;
|
||||
} else {
|
||||
LOG_INFO("Use SIMULATED radio!");
|
||||
radioType = SIM_RADIO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(RF95_IRQ) && RADIOLIB_EXCLUDE_SX127X != 1
|
||||
if ((!rIf) && (config.lora.region != meshtastic_Config_LoRaConfig_RegionCode_LORA_24)) {
|
||||
rIf = new RF95Interface(RadioLibHAL, LORA_CS, RF95_IRQ, RF95_RESET, RF95_DIO1);
|
||||
@@ -1460,7 +1445,7 @@ void setup()
|
||||
|
||||
#ifdef ARCH_PORTDUINO
|
||||
#if __has_include(<ulfius.h>)
|
||||
if (settingsMap[webserverport] != -1) {
|
||||
if (portduino_config.webserverport != -1) {
|
||||
piwebServerThread = new PiWebServerThread();
|
||||
std::atexit([] { delete piwebServerThread; });
|
||||
}
|
||||
@@ -1521,6 +1506,9 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
||||
deviceMetadata.hw_model = HW_VENDOR;
|
||||
deviceMetadata.hasRemoteHardware = moduleConfig.remote_hardware.enabled;
|
||||
deviceMetadata.excluded_modules = meshtastic_ExcludedModules_EXCLUDED_NONE;
|
||||
#if MESHTASTIC_EXCLUDE_MQTT
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_MQTT_CONFIG;
|
||||
#endif
|
||||
#if MESHTASTIC_EXCLUDE_REMOTEHARDWARE
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_REMOTEHARDWARE_CONFIG;
|
||||
#endif
|
||||
@@ -1543,10 +1531,21 @@ extern meshtastic_DeviceMetadata getDeviceMetadata()
|
||||
#if NO_EXT_GPIO && NO_GPS || MESHTASTIC_EXCLUDE_SERIAL
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_SERIAL_CONFIG;
|
||||
#endif
|
||||
#ifndef ARCH_ESP32
|
||||
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
// PAXCOUNTER is only supported on ESP32 due to memory constraints
|
||||
#else
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_PAXCOUNTER_CONFIG;
|
||||
#endif
|
||||
#if !defined(HAS_RGB_LED) && !RAK_4631
|
||||
#if MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_STOREFORWARD_CONFIG;
|
||||
#endif
|
||||
#if MESHTASTIC_EXCLUDE_RANGETEST
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_RANGETEST_CONFIG;
|
||||
#endif
|
||||
#if MESHTASTIC_EXCLUDE_NEIGHBORINFO
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_NEIGHBORINFO_CONFIG;
|
||||
#endif
|
||||
#if (!defined(HAS_RGB_LED) && !defined(RAK_4631)) || defined(MESHTASTIC_EXCLUDE_AMBIENTLIGHTING)
|
||||
deviceMetadata.excluded_modules |= meshtastic_ExcludedModules_AMBIENTLIGHTING_CONFIG;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
|
||||
// specified (may be dangerous if using external PA and LR11x0 power config forgotten)
|
||||
#if ARCH_PORTDUINO
|
||||
#define LR1110_MAX_POWER settingsMap[lr1110_max_power]
|
||||
#define LR1110_MAX_POWER portduino_config.lr1110_max_power
|
||||
#endif
|
||||
#ifndef LR1110_MAX_POWER
|
||||
#define LR1110_MAX_POWER 22
|
||||
@@ -30,7 +30,7 @@ static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||
// the 2.4G part maxes at 13dBm
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#define LR1120_MAX_POWER settingsMap[lr1120_max_power]
|
||||
#define LR1120_MAX_POWER portduino_config.lr1120_max_power
|
||||
#endif
|
||||
#ifndef LR1120_MAX_POWER
|
||||
#define LR1120_MAX_POWER 13
|
||||
@@ -55,7 +55,7 @@ template <typename T> bool LR11x0Interface<T>::init()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000;
|
||||
float tcxoVoltage = (float)portduino_config.dio3_tcxo_voltage / 1000;
|
||||
// FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE
|
||||
#elif !defined(LR11X0_DIO3_TCXO_VOLTAGE)
|
||||
float tcxoVoltage =
|
||||
|
||||
@@ -34,8 +34,11 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
bool weWereNextHop = false;
|
||||
if (wasSeenRecently(p, true, &wasFallback, &weWereNextHop)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignore dupe incoming msg", p);
|
||||
rxDupe++;
|
||||
stopRetransmission(p->from, p->id);
|
||||
|
||||
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
rxDupe++;
|
||||
stopRetransmission(p->from, p->id);
|
||||
}
|
||||
|
||||
// If it was a fallback to flooding, try to relay again
|
||||
if (wasFallback) {
|
||||
@@ -71,10 +74,11 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast
|
||||
if (p->from != 0) {
|
||||
meshtastic_NodeInfoLite *origTx = nodeDB->getMeshNode(p->from);
|
||||
if (origTx) {
|
||||
// Either relayer of ACK was also a relayer of the packet, or we were the relayer and the ACK came directly from
|
||||
// the destination
|
||||
// Either relayer of ACK was also a relayer of the packet, or we were the *only* relayer and the ACK came directly
|
||||
// from the destination
|
||||
if (wasRelayer(p->relay_node, p->decoded.request_id, p->to) ||
|
||||
(wasRelayer(ourRelayID, p->decoded.request_id, p->to) && p->hop_start != 0 && p->hop_start == p->hop_limit)) {
|
||||
(p->hop_start != 0 && p->hop_start == p->hop_limit &&
|
||||
wasSoleRelayer(ourRelayID, p->decoded.request_id, p->to))) {
|
||||
if (origTx->next_hop != p->relay_node) { // Not already set
|
||||
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply", p->from, p->relay_node);
|
||||
origTx->next_hop = p->relay_node;
|
||||
|
||||
+23
-3
@@ -673,7 +673,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
#endif
|
||||
#elif ARCH_PORTDUINO
|
||||
bool hasScreen = false;
|
||||
if (settingsMap[displayPanel])
|
||||
if (portduino_config.displayPanel)
|
||||
hasScreen = true;
|
||||
else
|
||||
hasScreen = screen_found.port != ScanI2C::I2CPort::NO_I2C;
|
||||
@@ -775,7 +775,9 @@ void NodeDB::installDefaultModuleConfig()
|
||||
|
||||
moduleConfig.version = DEVICESTATE_CUR_VER;
|
||||
moduleConfig.has_mqtt = true;
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST
|
||||
moduleConfig.has_range_test = true;
|
||||
#endif
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
@@ -841,6 +843,12 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.canned_message.inputbroker_event_press = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT;
|
||||
#endif
|
||||
moduleConfig.has_canned_message = true;
|
||||
#if !MESHTASTIC_EXCLUDE_AUDIO
|
||||
moduleConfig.has_audio = true;
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
moduleConfig.has_paxcounter = true;
|
||||
#endif
|
||||
#if USERPREFS_MQTT_ENABLED && !MESHTASTIC_EXCLUDE_MQTT
|
||||
moduleConfig.mqtt.enabled = true;
|
||||
#endif
|
||||
@@ -883,12 +891,14 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.detection_sensor.detection_trigger_type = meshtastic_ModuleConfig_DetectionSensorConfig_TriggerType_LOGIC_HIGH;
|
||||
moduleConfig.detection_sensor.minimum_broadcast_secs = 45;
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_AMBIENTLIGHTING
|
||||
moduleConfig.has_ambient_lighting = true;
|
||||
moduleConfig.ambient_lighting.current = 10;
|
||||
// Default to a color based on our node number
|
||||
moduleConfig.ambient_lighting.red = (myNodeInfo.my_node_num & 0xFF0000) >> 16;
|
||||
moduleConfig.ambient_lighting.green = (myNodeInfo.my_node_num & 0x00FF00) >> 8;
|
||||
moduleConfig.ambient_lighting.blue = myNodeInfo.my_node_num & 0x0000FF;
|
||||
#endif
|
||||
|
||||
initModuleConfigIntervals();
|
||||
}
|
||||
@@ -1334,8 +1344,8 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
#if ARCH_PORTDUINO
|
||||
// set any config overrides
|
||||
if (settingsMap[has_configDisplayMode]) {
|
||||
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)settingsMap[configDisplayMode];
|
||||
if (portduino_config.has_configDisplayMode) {
|
||||
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)portduino_config.configDisplayMode;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1428,15 +1438,25 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
||||
moduleConfig.has_canned_message = true;
|
||||
moduleConfig.has_external_notification = true;
|
||||
moduleConfig.has_mqtt = true;
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST
|
||||
moduleConfig.has_range_test = true;
|
||||
#endif
|
||||
moduleConfig.has_serial = true;
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
moduleConfig.has_store_forward = true;
|
||||
#endif
|
||||
moduleConfig.has_telemetry = true;
|
||||
moduleConfig.has_neighbor_info = true;
|
||||
moduleConfig.has_detection_sensor = true;
|
||||
#if !MESHTASTIC_EXCLUDE_AMBIENTLIGHTING
|
||||
moduleConfig.has_ambient_lighting = true;
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_AUDIO
|
||||
moduleConfig.has_audio = true;
|
||||
#endif
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
moduleConfig.has_paxcounter = true;
|
||||
#endif
|
||||
|
||||
success &=
|
||||
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
|
||||
|
||||
+25
-10
@@ -294,7 +294,7 @@ void PacketHistory::insert(const PacketRecord &r)
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole)
|
||||
{
|
||||
if (!initOk()) {
|
||||
LOG_ERROR("PacketHistory - wasRelayer: NOT INITIALIZED!");
|
||||
@@ -322,27 +322,42 @@ bool PacketHistory::wasRelayer(const uint8_t relayer, const uint32_t id, const N
|
||||
found->sender, found->id, found->next_hop, millis() - found->rxTimeMsec, found->relayed_by[0], found->relayed_by[1],
|
||||
found->relayed_by[2], relayer);
|
||||
#endif
|
||||
return wasRelayer(relayer, *found);
|
||||
return wasRelayer(relayer, *found, wasSole);
|
||||
}
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r)
|
||||
bool PacketHistory::wasRelayer(const uint8_t relayer, const PacketRecord &r, bool *wasSole)
|
||||
{
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; i++) {
|
||||
bool found = false;
|
||||
bool other_present = false;
|
||||
|
||||
for (uint8_t i = 0; i < NUM_RELAYERS; ++i) {
|
||||
if (r.relayed_by[i] == relayer) {
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? YES", r.sender, r.id,
|
||||
r.relayed_by[0], r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
return true;
|
||||
found = true;
|
||||
} else if (r.relayed_by[i] != 0) {
|
||||
other_present = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (wasSole) {
|
||||
*wasSole = (found && !other_present);
|
||||
}
|
||||
|
||||
#if VERBOSE_PACKET_HISTORY
|
||||
LOG_DEBUG("Packet History - was rel.PR.: s=%08x id=%08x rls=%02x %02x %02x / rl=%02x? NO", r.sender, r.id, r.relayed_by[0],
|
||||
r.relayed_by[1], r.relayed_by[2], relayer);
|
||||
#endif
|
||||
return false;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Check if a certain node was the *only* relayer of a packet in the history given an ID and sender
|
||||
bool PacketHistory::wasSoleRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender)
|
||||
{
|
||||
bool wasSole = false;
|
||||
wasRelayer(relayer, id, sender, &wasSole);
|
||||
return wasSole;
|
||||
}
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
|
||||
@@ -34,8 +34,9 @@ class PacketHistory
|
||||
void insert(const PacketRecord &r); // Insert or replace a packet record in the history
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given iterator
|
||||
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const PacketRecord &r);
|
||||
bool wasRelayer(const uint8_t relayer, const PacketRecord &r, bool *wasSole = nullptr);
|
||||
|
||||
PacketHistory(const PacketHistory &); // non construction-copyable
|
||||
PacketHistory &operator=(const PacketHistory &); // non copyable
|
||||
@@ -54,8 +55,12 @@ class PacketHistory
|
||||
bool *weWereNextHop = nullptr);
|
||||
|
||||
/* Check if a certain node was a relayer of a packet in the history given an ID and sender
|
||||
* If wasSole is not nullptr, it will be set to true if the relayer was the only relayer of that packet
|
||||
* @return true if node was indeed a relayer, false if not */
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
bool wasRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender, bool *wasSole = nullptr);
|
||||
|
||||
// Check if a certain node was the *only* relayer of a packet in the history given an ID and sender
|
||||
bool wasSoleRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
// Remove a relayer from the list of relayers of a packet in the history given an ID and sender
|
||||
void removeRelayer(const uint8_t relayer, const uint32_t id, const NodeNum sender);
|
||||
|
||||
@@ -34,6 +34,21 @@
|
||||
// Flag to indicate a heartbeat was received and we should send queue status
|
||||
bool heartbeatReceived = false;
|
||||
|
||||
// Helper function to skip excluded module configs and advance state
|
||||
size_t PhoneAPI::skipExcludedModuleConfig(uint8_t *buf)
|
||||
{
|
||||
config_state++;
|
||||
if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) {
|
||||
if (config_nonce == SPECIAL_NONCE_ONLY_CONFIG) {
|
||||
state = STATE_SEND_FILEMANIFEST;
|
||||
} else {
|
||||
state = STATE_SEND_OTHER_NODEINFOS;
|
||||
}
|
||||
config_state = 0;
|
||||
}
|
||||
return getFromRadio(buf);
|
||||
}
|
||||
|
||||
PhoneAPI::PhoneAPI()
|
||||
{
|
||||
lastContactMsec = millis();
|
||||
@@ -354,20 +369,35 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.payload_variant.serial = moduleConfig.serial;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_external_notification_tag:
|
||||
#if !(NO_EXT_GPIO || MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION)
|
||||
LOG_DEBUG("Send module config: ext notification");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_external_notification_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.external_notification = moduleConfig.external_notification;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("External Notification module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
case meshtastic_ModuleConfig_store_forward_tag:
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
LOG_DEBUG("Send module config: store forward");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_store_forward_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.store_forward = moduleConfig.store_forward;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("Store & Forward module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
case meshtastic_ModuleConfig_range_test_tag:
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST
|
||||
LOG_DEBUG("Send module config: range test");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_range_test_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.range_test = moduleConfig.range_test;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("Range Test module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
case meshtastic_ModuleConfig_telemetry_tag:
|
||||
LOG_DEBUG("Send module config: telemetry");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_telemetry_tag;
|
||||
@@ -379,10 +409,15 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.payload_variant.canned_message = moduleConfig.canned_message;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_audio_tag:
|
||||
#if !MESHTASTIC_EXCLUDE_AUDIO
|
||||
LOG_DEBUG("Send module config: audio");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_audio_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.audio = moduleConfig.audio;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("Audio module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
case meshtastic_ModuleConfig_remote_hardware_tag:
|
||||
LOG_DEBUG("Send module config: remote hardware");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_remote_hardware_tag;
|
||||
@@ -399,15 +434,25 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
fromRadioScratch.moduleConfig.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
break;
|
||||
case meshtastic_ModuleConfig_ambient_lighting_tag:
|
||||
#if !MESHTASTIC_EXCLUDE_AMBIENTLIGHTING
|
||||
LOG_DEBUG("Send module config: ambient lighting");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("Ambient Lighting module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
case meshtastic_ModuleConfig_paxcounter_tag:
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
LOG_DEBUG("Send module config: paxcounter");
|
||||
fromRadioScratch.moduleConfig.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
|
||||
fromRadioScratch.moduleConfig.payload_variant.paxcounter = moduleConfig.paxcounter;
|
||||
break;
|
||||
#else
|
||||
LOG_DEBUG("Paxcounter module excluded from build, skipping");
|
||||
return skipExcludedModuleConfig(buf);
|
||||
#endif
|
||||
default:
|
||||
LOG_ERROR("Unknown module config type %d", config_state);
|
||||
}
|
||||
|
||||
@@ -172,4 +172,7 @@ class PhoneAPI
|
||||
|
||||
/// If the mesh service tells us fromNum has changed, tell the phone
|
||||
virtual int onNotify(uint32_t newValue) override;
|
||||
|
||||
/// Helper function to skip excluded module configs and advance state
|
||||
size_t skipExcludedModuleConfig(uint8_t *buf);
|
||||
};
|
||||
|
||||
+11
-11
@@ -10,7 +10,7 @@
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
#define RF95_MAX_POWER settingsMap[rf95_max_power]
|
||||
#define RF95_MAX_POWER portduino_config.rf95_max_power
|
||||
#endif
|
||||
#ifndef RF95_MAX_POWER
|
||||
#define RF95_MAX_POWER 20
|
||||
@@ -94,16 +94,16 @@ void RF95Interface::setTransmitEnable(bool txon)
|
||||
#ifdef RF95_TXEN
|
||||
digitalWrite(RF95_TXEN, txon ? 1 : 0);
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], txon ? 1 : 0);
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, txon ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef RF95_RXEN
|
||||
digitalWrite(RF95_RXEN, txon ? 0 : 1);
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], txon ? 0 : 1);
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, txon ? 0 : 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -164,13 +164,13 @@ bool RF95Interface::init()
|
||||
digitalWrite(RF95_RXEN, 1);
|
||||
#endif
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[txen_pin], 0);
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
pinMode(portduino_config.lora_txen_pin.pin, OUTPUT);
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, 0);
|
||||
}
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen_pin], 0);
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
pinMode(portduino_config.lora_rxen_pin.pin, OUTPUT);
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, 0);
|
||||
}
|
||||
#endif
|
||||
setTransmitEnable(false);
|
||||
|
||||
@@ -417,7 +417,7 @@ void RadioLibInterface::handleReceiveInterrupt()
|
||||
|
||||
int state = iface->readData((uint8_t *)&radioBuffer, length);
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[logoutputlevel] == level_trace) {
|
||||
if (portduino_config.logoutputlevel == level_trace) {
|
||||
printBytes("Raw incoming packet: ", (uint8_t *)&radioBuffer, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -58,7 +58,10 @@ bool ReliableRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
|
||||
// marked as wantAck
|
||||
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, old->packet->channel);
|
||||
|
||||
stopRetransmission(key);
|
||||
// Only stop retransmissions if the rebroadcast came via LoRa
|
||||
if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA) {
|
||||
stopRetransmission(key);
|
||||
}
|
||||
} else {
|
||||
LOG_DEBUG("Didn't find pending packet");
|
||||
}
|
||||
|
||||
+2
-2
@@ -446,7 +446,7 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p)
|
||||
#if ENABLE_JSON_LOGGING
|
||||
LOG_TRACE("%s", MeshPacketSerializer::JsonSerialize(p, false).c_str());
|
||||
#elif ARCH_PORTDUINO
|
||||
if (settingsStrings[traceFilename] != "" || settingsMap[logoutputlevel] == level_trace) {
|
||||
if (portduino_config.traceFilename != "" || portduino_config.logoutputlevel == level_trace) {
|
||||
LOG_TRACE("%s", MeshPacketSerializer::JsonSerialize(p, false).c_str());
|
||||
}
|
||||
#endif
|
||||
@@ -685,7 +685,7 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||
LOG_TRACE("%s", MeshPacketSerializer::JsonSerializeEncrypted(p).c_str());
|
||||
#elif ARCH_PORTDUINO
|
||||
// Even ignored packets get logged in the trace
|
||||
if (settingsStrings[traceFilename] != "" || settingsMap[logoutputlevel] == level_trace) {
|
||||
if (portduino_config.traceFilename != "" || portduino_config.logoutputlevel == level_trace) {
|
||||
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
|
||||
LOG_TRACE("%s", MeshPacketSerializer::JsonSerializeEncrypted(p).c_str());
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#include "STM32WLE5JCInterface.h"
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
#include "STM32WLE5JCInterface.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifndef STM32WLx_MAX_POWER
|
||||
#define STM32WLx_MAX_POWER 22
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
|
||||
STM32WLE5JCInterface::STM32WLE5JCInterface(LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq,
|
||||
RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy)
|
||||
: SX126xInterface(hal, cs, irq, rst, busy)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "SX126xInterface.h"
|
||||
|
||||
#ifdef ARCH_STM32WL
|
||||
#include "SX126xInterface.h"
|
||||
#include "rfswitch.h"
|
||||
|
||||
/**
|
||||
* Our adapter for STM32WLE5JC radios
|
||||
@@ -16,13 +16,4 @@ class STM32WLE5JCInterface : public SX126xInterface<STM32WLx>
|
||||
virtual bool init() override;
|
||||
};
|
||||
|
||||
/* https://wiki.seeedstudio.com/LoRa-E5_STM32WLE5JC_Module/
|
||||
* Wio-E5 module ONLY transmits through RFO_HP
|
||||
* Receive: PA4=1, PA5=0
|
||||
* Transmit(high output power, SMPS mode): PA4=0, PA5=1 */
|
||||
static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PA4, PA5, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
|
||||
static const Module::RfSwitchMode_t rfswitch_table[4] = {
|
||||
{STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE};
|
||||
|
||||
#endif // ARCH_STM32WL
|
||||
@@ -12,7 +12,7 @@
|
||||
// Particular boards might define a different max power based on what their hardware can do, default to max power output if not
|
||||
// specified (may be dangerous if using external PA and SX126x power config forgotten)
|
||||
#if ARCH_PORTDUINO
|
||||
#define SX126X_MAX_POWER settingsMap[sx126x_max_power]
|
||||
#define SX126X_MAX_POWER portduino_config.sx126x_max_power
|
||||
#endif
|
||||
#ifndef SX126X_MAX_POWER
|
||||
#define SX126X_MAX_POWER 22
|
||||
@@ -53,10 +53,10 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000;
|
||||
if (settingsMap[sx126x_ant_sw_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[sx126x_ant_sw_pin], HIGH);
|
||||
pinMode(settingsMap[sx126x_ant_sw_pin], OUTPUT);
|
||||
tcxoVoltage = (float)portduino_config.dio3_tcxo_voltage / 1000;
|
||||
if (portduino_config.lora_sx126x_ant_sw_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_sx126x_ant_sw_pin.pin, HIGH);
|
||||
pinMode(portduino_config.lora_sx126x_ant_sw_pin.pin, OUTPUT);
|
||||
}
|
||||
#endif
|
||||
if (tcxoVoltage == 0.0)
|
||||
@@ -98,7 +98,7 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
bool dio2AsRfSwitch = true;
|
||||
#elif defined(ARCH_PORTDUINO)
|
||||
bool dio2AsRfSwitch = false;
|
||||
if (settingsMap[dio2_as_rf_switch]) {
|
||||
if (portduino_config.dio2_as_rf_switch) {
|
||||
dio2AsRfSwitch = true;
|
||||
}
|
||||
#else
|
||||
@@ -112,9 +112,9 @@ template <typename T> bool SX126xInterface<T>::init()
|
||||
// no effect
|
||||
#if ARCH_PORTDUINO
|
||||
if (res == RADIOLIB_ERR_NONE) {
|
||||
LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", settingsMap[rxen_pin],
|
||||
settingsMap[txen_pin]);
|
||||
lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]);
|
||||
LOG_DEBUG("Use MCU pin %i as RXEN and pin %i as TXEN to control RF switching", portduino_config.lora_rxen_pin.pin,
|
||||
portduino_config.lora_txen_pin.pin);
|
||||
lora.setRfSwitchPins(portduino_config.lora_rxen_pin.pin, portduino_config.lora_txen_pin.pin);
|
||||
}
|
||||
#else
|
||||
#ifndef SX126X_RXEN
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
#if ARCH_PORTDUINO
|
||||
#define SX128X_MAX_POWER settingsMap[sx128x_max_power]
|
||||
#define SX128X_MAX_POWER portduino_config.sx128x_max_power
|
||||
#endif
|
||||
#ifndef SX128X_MAX_POWER
|
||||
#define SX128X_MAX_POWER 13
|
||||
@@ -41,13 +41,13 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[rxen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[rxen_pin], LOW); // Set low before becoming an output
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
pinMode(portduino_config.lora_rxen_pin.pin, OUTPUT);
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, LOW); // Set low before becoming an output
|
||||
}
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
pinMode(settingsMap[txen_pin], OUTPUT);
|
||||
digitalWrite(settingsMap[txen_pin], LOW); // Set low before becoming an output
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
pinMode(portduino_config.lora_txen_pin.pin, OUTPUT);
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, LOW); // Set low before becoming an output
|
||||
}
|
||||
#else
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // set not rx or tx mode
|
||||
@@ -93,8 +93,9 @@ template <typename T> bool SX128xInterface<T>::init()
|
||||
lora.setRfSwitchPins(SX128X_RXEN, SX128X_TXEN);
|
||||
}
|
||||
#elif ARCH_PORTDUINO
|
||||
if (res == RADIOLIB_ERR_NONE && settingsMap[rxen_pin] != RADIOLIB_NC && settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
lora.setRfSwitchPins(settingsMap[rxen_pin], settingsMap[txen_pin]);
|
||||
if (res == RADIOLIB_ERR_NONE && portduino_config.lora_rxen_pin.pin != RADIOLIB_NC &&
|
||||
portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
lora.setRfSwitchPins(portduino_config.lora_rxen_pin.pin, portduino_config.lora_txen_pin.pin);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -174,11 +175,11 @@ template <typename T> void SX128xInterface<T>::setStandby()
|
||||
LOG_ERROR("SX128x standby %s%d", radioLibErr, err);
|
||||
assert(err == RADIOLIB_ERR_NONE);
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], LOW);
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, LOW);
|
||||
}
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], LOW);
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, LOW);
|
||||
}
|
||||
#else
|
||||
#if defined(SX128X_RXEN) && (SX128X_RXEN != RADIOLIB_NC) // we have RXEN/TXEN control - turn off RX and TX power
|
||||
@@ -210,11 +211,11 @@ template <typename T> void SX128xInterface<T>::addReceiveMetadata(meshtastic_Mes
|
||||
template <typename T> void SX128xInterface<T>::configHardwareForSend()
|
||||
{
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], HIGH);
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, HIGH);
|
||||
}
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], LOW);
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, LOW);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -241,11 +242,11 @@ template <typename T> void SX128xInterface<T>::startReceive()
|
||||
setStandby();
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[rxen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[rxen_pin], HIGH);
|
||||
if (portduino_config.lora_rxen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_rxen_pin.pin, HIGH);
|
||||
}
|
||||
if (settingsMap[txen_pin] != RADIOLIB_NC) {
|
||||
digitalWrite(settingsMap[txen_pin], LOW);
|
||||
if (portduino_config.lora_txen_pin.pin != RADIOLIB_NC) {
|
||||
digitalWrite(portduino_config.lora_txen_pin.pin, LOW);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -64,7 +64,12 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
|
||||
in areas not already covered by other routers, or to bridge around problematic terrain,
|
||||
but should not be given priority over other routers in order to avoid unnecessaraily
|
||||
consuming hops. */
|
||||
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11
|
||||
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11,
|
||||
/* Description: Treats packets from or to favorited nodes as ROUTER, and all other packets as CLIENT.
|
||||
Technical Details: Used for stronger attic/roof nodes to distribute messages more widely
|
||||
from weaker, indoor, or less-well-positioned nodes. Recommended for users with multiple nodes
|
||||
where one CLIENT_BASE acts as a more powerful base station, such as an attic/roof node. */
|
||||
meshtastic_Config_DeviceConfig_Role_CLIENT_BASE = 12
|
||||
} meshtastic_Config_DeviceConfig_Role;
|
||||
|
||||
/* Defines the device's behavior for how messages are rebroadcast */
|
||||
@@ -646,8 +651,8 @@ extern "C" {
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_ROUTER_LATE
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_ROUTER_LATE+1))
|
||||
#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_CLIENT_BASE
|
||||
#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_CLIENT_BASE+1))
|
||||
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
|
||||
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY
|
||||
|
||||
@@ -270,6 +270,10 @@ typedef enum _meshtastic_HardwareModel {
|
||||
/* MeshSolar is an integrated power management and communication solution designed for outdoor low-power devices.
|
||||
https://heltec.org/project/meshsolar/ */
|
||||
meshtastic_HardwareModel_HELTEC_MESH_SOLAR = 108,
|
||||
/* Lilygo T-Echo Lite */
|
||||
meshtastic_HardwareModel_T_ECHO_LITE = 109,
|
||||
/* New Heltec LoRA32 with ESP32-S3 CPU */
|
||||
meshtastic_HardwareModel_HELTEC_V4 = 110,
|
||||
/* ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
||||
@@ -342,6 +342,11 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
res->print(value->Stringify().c_str());
|
||||
|
||||
delete value;
|
||||
|
||||
// Clean up the fileList to prevent memory leak
|
||||
for (auto *val : fileList) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
|
||||
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||
@@ -610,33 +615,38 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||
res->println("<pre>");
|
||||
}
|
||||
|
||||
// Helper lambda to create JSON array and clean up memory properly
|
||||
auto createJSONArrayFromLog = [](uint32_t *logArray, int count) -> JSONValue * {
|
||||
JSONArray tempArray;
|
||||
for (int i = 0; i < count; i++) {
|
||||
tempArray.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
JSONValue *result = new JSONValue(tempArray);
|
||||
// Clean up original array to prevent memory leak
|
||||
for (auto *val : tempArray) {
|
||||
delete val;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// data->airtime->tx_log
|
||||
JSONArray txLogValues;
|
||||
uint32_t *logArray;
|
||||
logArray = airTime->airtimeReport(TX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
txLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
JSONValue *txLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
|
||||
// data->airtime->rx_log
|
||||
JSONArray rxLogValues;
|
||||
logArray = airTime->airtimeReport(RX_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
rxLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
JSONValue *rxLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
|
||||
// data->airtime->rx_all_log
|
||||
JSONArray rxAllLogValues;
|
||||
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||
rxAllLogValues.push_back(new JSONValue((int)logArray[i]));
|
||||
}
|
||||
JSONValue *rxAllLogJsonValue = createJSONArrayFromLog(logArray, airTime->getPeriodsToLog());
|
||||
|
||||
// data->airtime
|
||||
JSONObject jsonObjAirtime;
|
||||
jsonObjAirtime["tx_log"] = new JSONValue(txLogValues);
|
||||
jsonObjAirtime["rx_log"] = new JSONValue(rxLogValues);
|
||||
jsonObjAirtime["rx_all_log"] = new JSONValue(rxAllLogValues);
|
||||
jsonObjAirtime["tx_log"] = txLogJsonValue;
|
||||
jsonObjAirtime["rx_log"] = rxLogJsonValue;
|
||||
jsonObjAirtime["rx_all_log"] = rxAllLogJsonValue;
|
||||
jsonObjAirtime["channel_utilization"] = new JSONValue(airTime->channelUtilizationPercent());
|
||||
jsonObjAirtime["utilization_tx"] = new JSONValue(airTime->utilizationTXPercent());
|
||||
jsonObjAirtime["seconds_since_boot"] = new JSONValue(int(airTime->getSecondsSinceBoot()));
|
||||
@@ -765,6 +775,11 @@ void handleNodes(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
|
||||
// Clean up the nodesArray to prevent memory leak
|
||||
for (auto *val : nodesArray) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -955,5 +970,10 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||
JSONValue *value = new JSONValue(jsonObjOuter);
|
||||
res->print(value->Stringify().c_str());
|
||||
delete value;
|
||||
|
||||
// Clean up the networkObjs to prevent memory leak
|
||||
for (auto *val : networkObjs) {
|
||||
delete val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -65,8 +65,8 @@ mail: marchammermann@googlemail.com
|
||||
#define DEFAULT_REALM "default_realm"
|
||||
#define PREFIX ""
|
||||
|
||||
#define KEY_PATH settingsStrings[websslkeypath].c_str()
|
||||
#define CERT_PATH settingsStrings[websslcertpath].c_str()
|
||||
#define KEY_PATH portduino_config.webserver_ssl_key_path.c_str()
|
||||
#define CERT_PATH portduino_config.webserver_ssl_cert_path.c_str()
|
||||
|
||||
struct _file_config configWeb;
|
||||
|
||||
@@ -458,8 +458,8 @@ PiWebServerThread::PiWebServerThread()
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsMap[webserverport] != 0) {
|
||||
webservport = settingsMap[webserverport];
|
||||
if (portduino_config.webserverport != 0) {
|
||||
webservport = portduino_config.webserverport;
|
||||
LOG_INFO("Use webserver port from yaml config %i ", webservport);
|
||||
} else {
|
||||
LOG_INFO("Webserver port in yaml config set to 0, defaulting to port 9443");
|
||||
@@ -490,7 +490,7 @@ PiWebServerThread::PiWebServerThread()
|
||||
u_map_put(&configWeb.mime_types, ".ico", "image/x-icon");
|
||||
u_map_put(&configWeb.mime_types, ".svg", "image/svg+xml");
|
||||
|
||||
webrootpath = settingsStrings[webserverrootpath];
|
||||
webrootpath = portduino_config.webserver_root_path;
|
||||
|
||||
configWeb.files_path = (char *)webrootpath.c_str();
|
||||
configWeb.url_prefix = "";
|
||||
|
||||
@@ -1040,19 +1040,32 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
res.get_module_config_response.payload_variant.serial = moduleConfig.serial;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_EXTNOTIF_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
|
||||
LOG_INFO("Get module config: External Notification");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_external_notification_tag;
|
||||
res.get_module_config_response.payload_variant.external_notification = moduleConfig.external_notification;
|
||||
#else
|
||||
LOG_DEBUG("External Notification module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_STOREFORWARD_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
|
||||
LOG_INFO("Get module config: Store & Forward");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_store_forward_tag;
|
||||
res.get_module_config_response.payload_variant.store_forward = moduleConfig.store_forward;
|
||||
#else
|
||||
LOG_DEBUG("Store & Forward module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_RANGETEST_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_RANGETEST
|
||||
LOG_INFO("Get module config: Range Test");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_range_test_tag;
|
||||
res.get_module_config_response.payload_variant.range_test = moduleConfig.range_test;
|
||||
#else
|
||||
LOG_DEBUG("Range Test module excluded from build, skipping config");
|
||||
// Don't set payload variant - will result in empty response
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_TELEMETRY_CONFIG:
|
||||
LOG_INFO("Get module config: Telemetry");
|
||||
@@ -1065,9 +1078,13 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
res.get_module_config_response.payload_variant.canned_message = moduleConfig.canned_message;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_AUDIO_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_AUDIO
|
||||
LOG_INFO("Get module config: Audio");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_audio_tag;
|
||||
res.get_module_config_response.payload_variant.audio = moduleConfig.audio;
|
||||
#else
|
||||
LOG_DEBUG("Audio module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_REMOTEHARDWARE_CONFIG:
|
||||
LOG_INFO("Get module config: Remote Hardware");
|
||||
@@ -1080,19 +1097,31 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
|
||||
res.get_module_config_response.payload_variant.neighbor_info = moduleConfig.neighbor_info;
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG:
|
||||
#if !(NO_EXT_GPIO || MESHTASTIC_EXCLUDE_DETECTIONSENSOR)
|
||||
LOG_INFO("Get module config: Detection Sensor");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_detection_sensor_tag;
|
||||
res.get_module_config_response.payload_variant.detection_sensor = moduleConfig.detection_sensor;
|
||||
#else
|
||||
LOG_DEBUG("Detection Sensor module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_AMBIENTLIGHTING_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_AMBIENTLIGHTING
|
||||
LOG_INFO("Get module config: Ambient Lighting");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_ambient_lighting_tag;
|
||||
res.get_module_config_response.payload_variant.ambient_lighting = moduleConfig.ambient_lighting;
|
||||
#else
|
||||
LOG_DEBUG("Ambient Lighting module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
case meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG:
|
||||
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
|
||||
LOG_INFO("Get module config: Paxcounter");
|
||||
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
|
||||
res.get_module_config_response.payload_variant.paxcounter = moduleConfig.paxcounter;
|
||||
#else
|
||||
LOG_DEBUG("Paxcounter module excluded from build, skipping config");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
|
||||
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool force_no_invert,
|
||||
bool show_date);
|
||||
}
|
||||
#if __has_include(<Adafruit_AHTX0.h>)
|
||||
#include "Sensor/AHT10.h"
|
||||
@@ -198,6 +199,13 @@ T1000xSensor t1000xSensor;
|
||||
IndicatorSensor indicatorSensor;
|
||||
#endif
|
||||
|
||||
#if __has_include(<Adafruit_TSL2561_U.h>)
|
||||
#include "Sensor/TSL2561Sensor.h"
|
||||
TSL2561Sensor tsl2561Sensor;
|
||||
#else
|
||||
NullSensor tsl2561Sensor;
|
||||
#endif
|
||||
|
||||
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
|
||||
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
|
||||
|
||||
@@ -296,6 +304,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
|
||||
result = max17048Sensor.runOnce();
|
||||
if (cgRadSens.hasSensor())
|
||||
result = cgRadSens.runOnce();
|
||||
if (tsl2561Sensor.hasSensor())
|
||||
result = tsl2561Sensor.runOnce();
|
||||
if (pct2075Sensor.hasSensor())
|
||||
result = pct2075Sensor.runOnce();
|
||||
// this only works on the wismesh hub with the solar option. This is not an I2C sensor, so we don't need the
|
||||
@@ -642,6 +652,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
|
||||
valid = valid && nau7802Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (tsl2561Sensor.hasSensor()) {
|
||||
valid = valid && tsl2561Sensor.getMetrics(m);
|
||||
hasSensor = true;
|
||||
}
|
||||
if (aht10Sensor.hasSensor()) {
|
||||
if (!bmp280Sensor.hasSensor() && !bmp3xxSensor.hasSensor()) {
|
||||
valid = valid && aht10Sensor.getMetrics(m);
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
int32_t HostMetricsModule::runOnce()
|
||||
{
|
||||
#if ARCH_PORTDUINO
|
||||
if (settingsMap[hostMetrics_interval] == 0) {
|
||||
if (portduino_config.hostMetrics_interval == 0) {
|
||||
return disable();
|
||||
} else {
|
||||
sendMetrics();
|
||||
return 60 * 1000 * settingsMap[hostMetrics_interval];
|
||||
return 60 * 1000 * portduino_config.hostMetrics_interval;
|
||||
}
|
||||
#else
|
||||
return disable();
|
||||
@@ -110,8 +110,8 @@ meshtastic_Telemetry HostMetricsModule::getHostMetrics()
|
||||
proc_loadavg.close();
|
||||
}
|
||||
}
|
||||
if (settingsStrings[hostMetrics_user_command] != "") {
|
||||
std::string userCommandResult = exec(settingsStrings[hostMetrics_user_command].c_str());
|
||||
if (portduino_config.hostMetrics_user_command != "") {
|
||||
std::string userCommandResult = exec(portduino_config.hostMetrics_user_command.c_str());
|
||||
if (userCommandResult.length() > 1) {
|
||||
strncpy(t.variant.host_metrics.user_string, userCommandResult.c_str(), sizeof(t.variant.host_metrics.user_string));
|
||||
t.variant.host_metrics.user_string[sizeof(t.variant.host_metrics.user_string) - 1] = '\0';
|
||||
@@ -135,7 +135,7 @@ bool HostMetricsModule::sendMetrics()
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
|
||||
p->channel = settingsMap[hostMetrics_channel];
|
||||
p->channel = portduino_config.hostMetrics_channel;
|
||||
LOG_INFO("Send packet to mesh");
|
||||
service->sendToMesh(p, RX_SRC_LOCAL, true);
|
||||
return true;
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
|
||||
namespace graphics
|
||||
{
|
||||
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool battery_only);
|
||||
extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr, bool force_no_invert,
|
||||
bool show_date);
|
||||
}
|
||||
|
||||
int32_t PowerTelemetryModule::runOnce()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_TSL2561_U.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TSL2561Sensor.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_TSL2561_U.h>
|
||||
|
||||
TSL2561Sensor::TSL2561Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_TSL2561, "TSL2561") {}
|
||||
|
||||
int32_t TSL2561Sensor::runOnce()
|
||||
{
|
||||
LOG_INFO("Init sensor: %s", sensorName);
|
||||
if (!hasSensor()) {
|
||||
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
|
||||
}
|
||||
|
||||
status = tsl.begin(nodeTelemetrySensorsMap[sensorType].second);
|
||||
|
||||
return initI2CSensor();
|
||||
}
|
||||
|
||||
void TSL2561Sensor::setup()
|
||||
{
|
||||
tsl.setGain(TSL2561_GAIN_1X);
|
||||
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS);
|
||||
}
|
||||
|
||||
bool TSL2561Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||
{
|
||||
measurement->variant.environment_metrics.has_lux = true;
|
||||
sensors_event_t event;
|
||||
tsl.getEvent(&event);
|
||||
measurement->variant.environment_metrics.lux = event.light;
|
||||
LOG_INFO("Lux: %f", measurement->variant.environment_metrics.lux);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "configuration.h"
|
||||
|
||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_TSL2561_U.h>)
|
||||
|
||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||
#include "TelemetrySensor.h"
|
||||
#include <Adafruit_TSL2561_U.h>
|
||||
|
||||
class TSL2561Sensor : public TelemetrySensor
|
||||
{
|
||||
private:
|
||||
// The magic number is a sensor id, the actual value doesn't matter
|
||||
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_LOW, 12345);
|
||||
|
||||
protected:
|
||||
virtual void setup() override;
|
||||
|
||||
public:
|
||||
TSL2561Sensor();
|
||||
virtual int32_t runOnce() override;
|
||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||
};
|
||||
#endif
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C
|
||||
|
||||
#if defined(RAK_4631) && !defined(RAK2560) && __has_include(<Rak_BMX160.h>)
|
||||
#if !defined(RAK2560) && __has_include(<Rak_BMX160.h>)
|
||||
|
||||
#include "Fusion/Fusion.h"
|
||||
#include <Rak_BMX160.h>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "api/ServerAPI.h"
|
||||
#include "linux/gpio/LinuxGPIOPin.h"
|
||||
#include "meshUtils.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include <ErriezCRC32.h>
|
||||
#include <Utility.h>
|
||||
#include <assert.h>
|
||||
@@ -28,14 +27,13 @@
|
||||
|
||||
#include "platform/portduino/USBHal.h"
|
||||
|
||||
std::map<configNames, int> settingsMap;
|
||||
std::map<configNames, std::string> settingsStrings;
|
||||
portduino_config_struct portduino_config;
|
||||
std::ofstream traceFile;
|
||||
Ch341Hal *ch341Hal = nullptr;
|
||||
char *configPath = nullptr;
|
||||
char *optionMac = nullptr;
|
||||
bool verboseEnabled = false;
|
||||
bool yamlOnly = false;
|
||||
|
||||
const char *argp_program_version = optstr(APP_VERSION);
|
||||
|
||||
@@ -75,6 +73,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
case 'v':
|
||||
verboseEnabled = true;
|
||||
break;
|
||||
case 'y':
|
||||
yamlOnly = true;
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
return 0;
|
||||
default:
|
||||
@@ -90,6 +91,7 @@ void portduinoCustomInit()
|
||||
{"hwid", 'h', "HWID", 0, "The mac address to assign to this virtual machine"},
|
||||
{"sim", 's', 0, 0, "Run in Simulated radio mode"},
|
||||
{"verbose", 'v', 0, 0, "Set log level to full debug"},
|
||||
{"output-yaml", 'y', 0, 0, "Output config yaml and exit"},
|
||||
{0}};
|
||||
static void *childArguments;
|
||||
static char doc[] = "Meshtastic native build.";
|
||||
@@ -115,8 +117,8 @@ void getMacAddr(uint8_t *dmac)
|
||||
dmac[4] = hwId >> 8;
|
||||
dmac[5] = hwId & 0xff;
|
||||
}
|
||||
} else if (settingsStrings[mac_address].length() > 11) {
|
||||
MAC_from_string(settingsStrings[mac_address], dmac);
|
||||
} else if (portduino_config.mac_address.length() > 11) {
|
||||
MAC_from_string(portduino_config.mac_address, dmac);
|
||||
exit;
|
||||
} else {
|
||||
|
||||
@@ -148,89 +150,46 @@ void getMacAddr(uint8_t *dmac)
|
||||
*/
|
||||
void portduinoSetup()
|
||||
{
|
||||
printf("Set up Meshtastic on Portduino...\n");
|
||||
int max_GPIO = 0;
|
||||
const configNames GPIO_lines[] = {cs_pin,
|
||||
irq_pin,
|
||||
busy_pin,
|
||||
reset_pin,
|
||||
sx126x_ant_sw_pin,
|
||||
txen_pin,
|
||||
rxen_pin,
|
||||
displayDC,
|
||||
displayCS,
|
||||
displayBacklight,
|
||||
displayBacklightPWMChannel,
|
||||
displayReset,
|
||||
touchscreenCS,
|
||||
touchscreenIRQ,
|
||||
userButtonPin,
|
||||
tbUpPin,
|
||||
tbDownPin,
|
||||
tbLeftPin,
|
||||
tbRightPin,
|
||||
tbPressPin};
|
||||
|
||||
std::string gpioChipName = "gpiochip";
|
||||
settingsStrings[i2cdev] = "";
|
||||
settingsStrings[keyboardDevice] = "";
|
||||
settingsStrings[pointerDevice] = "";
|
||||
settingsStrings[webserverrootpath] = "";
|
||||
settingsStrings[spidev] = "";
|
||||
settingsStrings[displayspidev] = "";
|
||||
settingsMap[spiSpeed] = 2000000;
|
||||
settingsMap[ascii_logs] = !isatty(1);
|
||||
settingsMap[displayPanel] = no_screen;
|
||||
settingsMap[touchscreenModule] = no_touchscreen;
|
||||
settingsMap[tbUpPin] = RADIOLIB_NC;
|
||||
settingsMap[tbDownPin] = RADIOLIB_NC;
|
||||
settingsMap[tbLeftPin] = RADIOLIB_NC;
|
||||
settingsMap[tbRightPin] = RADIOLIB_NC;
|
||||
settingsMap[tbPressPin] = RADIOLIB_NC;
|
||||
|
||||
YAML::Node yamlConfig;
|
||||
portduino_config.displayPanel = no_screen;
|
||||
|
||||
if (portduino_config.force_simradio == true) {
|
||||
settingsMap[use_simradio] = true;
|
||||
portduino_config.lora_module = use_simradio;
|
||||
} else if (configPath != nullptr) {
|
||||
if (loadConfig(configPath)) {
|
||||
std::cout << "Using " << configPath << " as config file" << std::endl;
|
||||
if (!yamlOnly)
|
||||
std::cout << "Using " << configPath << " as config file" << std::endl;
|
||||
} else {
|
||||
std::cout << "Unable to use " << configPath << " as config file" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (access("config.yaml", R_OK) == 0) {
|
||||
if (loadConfig("config.yaml")) {
|
||||
std::cout << "Using local config.yaml as config file" << std::endl;
|
||||
if (!yamlOnly)
|
||||
std::cout << "Using local config.yaml as config file" << std::endl;
|
||||
} else {
|
||||
std::cout << "Unable to use local config.yaml as config file" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0) {
|
||||
if (loadConfig("/etc/meshtasticd/config.yaml")) {
|
||||
std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl;
|
||||
if (!yamlOnly)
|
||||
std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl;
|
||||
} else {
|
||||
std::cout << "Unable to use /etc/meshtasticd/config.yaml as config file" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
std::cout << "No 'config.yaml' found..." << std::endl;
|
||||
settingsMap[use_simradio] = true;
|
||||
if (!yamlOnly)
|
||||
std::cout << "No 'config.yaml' found..." << std::endl;
|
||||
portduino_config.lora_module = use_simradio;
|
||||
}
|
||||
|
||||
if (settingsMap[use_simradio] == true) {
|
||||
std::cout << "Running in simulated mode." << std::endl;
|
||||
settingsMap[maxnodes] = 200; // Default to 200 nodes
|
||||
settingsMap[logoutputlevel] = level_debug; // Default to debug
|
||||
// Set the random seed equal to TCPPort to have a different seed per instance
|
||||
randomSeed(TCPPort);
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingsStrings[config_directory] != "") {
|
||||
if (portduino_config.config_directory != "") {
|
||||
std::string filetype = ".yaml";
|
||||
for (const std::filesystem::directory_entry &entry :
|
||||
std::filesystem::directory_iterator{settingsStrings[config_directory]}) {
|
||||
std::filesystem::directory_iterator{portduino_config.config_directory}) {
|
||||
if (ends_with(entry.path().string(), ".yaml")) {
|
||||
std::cout << "Also using " << entry << " as additional config file" << std::endl;
|
||||
loadConfig(entry.path().c_str());
|
||||
@@ -238,15 +197,28 @@ void portduinoSetup()
|
||||
}
|
||||
}
|
||||
|
||||
if (yamlOnly) {
|
||||
std::cout << portduino_config.emit_yaml() << std::endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (portduino_config.lora_module == use_simradio) {
|
||||
std::cout << "Running in simulated mode." << std::endl;
|
||||
portduino_config.MaxNodes = 200; // Default to 200 nodes
|
||||
// Set the random seed equal to TCPPort to have a different seed per instance
|
||||
randomSeed(TCPPort);
|
||||
return;
|
||||
}
|
||||
|
||||
// If LoRa `Module: auto` (default in config.yaml),
|
||||
// attempt to auto config based on Product Strings
|
||||
if (settingsMap[use_autoconf] == true) {
|
||||
if (portduino_config.lora_module == use_autoconf) {
|
||||
char autoconf_product[96] = {0};
|
||||
// Try CH341
|
||||
try {
|
||||
std::cout << "autoconf: Looking for CH341 device..." << std::endl;
|
||||
ch341Hal =
|
||||
new Ch341Hal(0, settingsStrings[lora_usb_serial_num], settingsMap[lora_usb_vid], settingsMap[lora_usb_pid]);
|
||||
ch341Hal = new Ch341Hal(0, portduino_config.lora_usb_serial_num, portduino_config.lora_usb_vid,
|
||||
portduino_config.lora_usb_pid);
|
||||
ch341Hal->getProductString(autoconf_product, 95);
|
||||
delete ch341Hal;
|
||||
std::cout << "autoconf: Found CH341 device " << autoconf_product << std::endl;
|
||||
@@ -323,7 +295,7 @@ void portduinoSetup()
|
||||
if (mac_start != nullptr) {
|
||||
std::cout << "autoconf: Found mac data " << mac_start << std::endl;
|
||||
if (strlen(mac_start) == 12)
|
||||
settingsStrings[mac_address] = std::string(mac_start);
|
||||
portduino_config.mac_address = std::string(mac_start);
|
||||
}
|
||||
if (devID_start != nullptr) {
|
||||
std::cout << "autoconf: Found deviceid data " << devID_start << std::endl;
|
||||
@@ -354,7 +326,7 @@ void portduinoSetup()
|
||||
std::cerr << "autoconf: Unable to find config for " << autoconf_product << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (loadConfig((settingsStrings[available_directory] + product_config).c_str())) {
|
||||
if (loadConfig((portduino_config.available_directory + product_config).c_str())) {
|
||||
std::cout << "autoconf: Using " << product_config << " as config file for " << autoconf_product << std::endl;
|
||||
} else {
|
||||
std::cerr << "autoconf: Unable to use " << product_config << " as config file for " << autoconf_product
|
||||
@@ -363,15 +335,16 @@ void portduinoSetup()
|
||||
}
|
||||
} else {
|
||||
std::cerr << "autoconf: Could not locate any devices" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// if we're using a usermode driver, we need to initialize it here, to get a serial number back for mac address
|
||||
uint8_t dmac[6] = {0};
|
||||
if (settingsStrings[spidev] == "ch341") {
|
||||
if (portduino_config.lora_spi_dev == "ch341") {
|
||||
try {
|
||||
ch341Hal =
|
||||
new Ch341Hal(0, settingsStrings[lora_usb_serial_num], settingsMap[lora_usb_vid], settingsMap[lora_usb_pid]);
|
||||
ch341Hal = new Ch341Hal(0, portduino_config.lora_usb_serial_num, portduino_config.lora_usb_vid,
|
||||
portduino_config.lora_usb_pid);
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
std::cerr << "Could not initialize CH341 device!" << std::endl;
|
||||
@@ -383,7 +356,7 @@ void portduinoSetup()
|
||||
char product_string[96] = {0};
|
||||
ch341Hal->getProductString(product_string, 95);
|
||||
std::cout << "CH341 Product " << product_string << std::endl;
|
||||
if (strlen(serial) == 8 && settingsStrings[mac_address].length() < 12) {
|
||||
if (strlen(serial) == 8 && portduino_config.mac_address.length() < 12) {
|
||||
uint8_t hash[32] = {0};
|
||||
memcpy(hash, serial, 8);
|
||||
crypto->hash(hash, 8);
|
||||
@@ -395,7 +368,7 @@ void portduinoSetup()
|
||||
dmac[5] = hash[5];
|
||||
char macBuf[13] = {0};
|
||||
sprintf(macBuf, "%02X%02X%02X%02X%02X%02X", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
|
||||
settingsStrings[mac_address] = macBuf;
|
||||
portduino_config.mac_address = macBuf;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,100 +382,38 @@ void portduinoSetup()
|
||||
// Rather important to set this, if not running simulated.
|
||||
randomSeed(time(NULL));
|
||||
|
||||
std::string defaultGpioChipName = gpioChipName + std::to_string(settingsMap[default_gpiochip]);
|
||||
|
||||
for (configNames i : GPIO_lines) {
|
||||
if (settingsMap.count(i) && settingsMap[i] > max_GPIO)
|
||||
max_GPIO = settingsMap[i];
|
||||
std::string defaultGpioChipName = gpioChipName + std::to_string(portduino_config.lora_default_gpiochip);
|
||||
for (auto i : portduino_config.all_pins) {
|
||||
if (i->enabled && i->pin > max_GPIO)
|
||||
max_GPIO = i->pin;
|
||||
}
|
||||
|
||||
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
|
||||
|
||||
// Need to bind all the configured GPIO pins so they're not simulated
|
||||
// TODO: If one of these fails, we should log and terminate
|
||||
if (settingsMap.count(userButtonPin) > 0 && settingsMap[userButtonPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[userButtonPin], defaultGpioChipName, settingsMap[userButtonPin]) != ERRNO_OK) {
|
||||
settingsMap[userButtonPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(tbUpPin) > 0 && settingsMap[tbUpPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[tbUpPin], defaultGpioChipName, settingsMap[tbUpPin]) != ERRNO_OK) {
|
||||
settingsMap[tbUpPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(tbDownPin) > 0 && settingsMap[tbDownPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[tbDownPin], defaultGpioChipName, settingsMap[tbDownPin]) != ERRNO_OK) {
|
||||
settingsMap[tbDownPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(tbLeftPin) > 0 && settingsMap[tbLeftPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[tbLeftPin], defaultGpioChipName, settingsMap[tbLeftPin]) != ERRNO_OK) {
|
||||
settingsMap[tbLeftPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(tbRightPin) > 0 && settingsMap[tbRightPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[tbRightPin], defaultGpioChipName, settingsMap[tbRightPin]) != ERRNO_OK) {
|
||||
settingsMap[tbRightPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap.count(tbPressPin) > 0 && settingsMap[tbPressPin] != RADIOLIB_NC) {
|
||||
if (initGPIOPin(settingsMap[tbPressPin], defaultGpioChipName, settingsMap[tbPressPin]) != ERRNO_OK) {
|
||||
settingsMap[tbPressPin] = RADIOLIB_NC;
|
||||
}
|
||||
}
|
||||
if (settingsMap[displayPanel] != no_screen) {
|
||||
if (settingsMap[displayCS] > 0)
|
||||
initGPIOPin(settingsMap[displayCS], defaultGpioChipName, settingsMap[displayCS]);
|
||||
if (settingsMap[displayDC] > 0)
|
||||
initGPIOPin(settingsMap[displayDC], defaultGpioChipName, settingsMap[displayDC]);
|
||||
if (settingsMap[displayBacklight] > 0)
|
||||
initGPIOPin(settingsMap[displayBacklight], defaultGpioChipName, settingsMap[displayBacklight]);
|
||||
if (settingsMap[displayReset] > 0)
|
||||
initGPIOPin(settingsMap[displayReset], defaultGpioChipName, settingsMap[displayReset]);
|
||||
}
|
||||
if (settingsMap[touchscreenModule] != no_touchscreen) {
|
||||
if (settingsMap[touchscreenCS] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenCS], defaultGpioChipName, settingsMap[touchscreenCS]);
|
||||
if (settingsMap[touchscreenIRQ] > 0)
|
||||
initGPIOPin(settingsMap[touchscreenIRQ], defaultGpioChipName, settingsMap[touchscreenIRQ]);
|
||||
for (auto i : portduino_config.all_pins) {
|
||||
if (i->enabled)
|
||||
if (initGPIOPin(i->pin, gpioChipName + std::to_string(i->gpiochip), i->line) != ERRNO_OK) {
|
||||
printf("Error setting pin number %d. It may not exist, or may already be in use.\n", i->line);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// Only initialize the radio pins when dealing with real, kernel controlled SPI hardware
|
||||
if (settingsStrings[spidev] != "" && settingsStrings[spidev] != "ch341") {
|
||||
const struct {
|
||||
configNames pin;
|
||||
configNames gpiochip;
|
||||
configNames line;
|
||||
} pinMappings[] = {{cs_pin, cs_gpiochip, cs_line},
|
||||
{irq_pin, irq_gpiochip, irq_line},
|
||||
{busy_pin, busy_gpiochip, busy_line},
|
||||
{reset_pin, reset_gpiochip, reset_line},
|
||||
{rxen_pin, rxen_gpiochip, rxen_line},
|
||||
{txen_pin, txen_gpiochip, txen_line},
|
||||
{sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line}};
|
||||
for (auto &pinMap : pinMappings) {
|
||||
auto setMapIter = settingsMap.find(pinMap.pin);
|
||||
if (setMapIter != settingsMap.end() && setMapIter->second != RADIOLIB_NC) {
|
||||
if (initGPIOPin(setMapIter->second, gpioChipName + std::to_string(settingsMap[pinMap.gpiochip]),
|
||||
settingsMap[pinMap.line]) != ERRNO_OK) {
|
||||
printf("Error setting pin number %d. It may not exist, or may already be in use.\n",
|
||||
settingsMap[pinMap.line]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
SPI.begin(settingsStrings[spidev].c_str());
|
||||
if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") {
|
||||
SPI.begin(portduino_config.lora_spi_dev.c_str());
|
||||
}
|
||||
if (settingsStrings[traceFilename] != "") {
|
||||
if (portduino_config.traceFilename != "") {
|
||||
try {
|
||||
traceFile.open(settingsStrings[traceFilename], std::ios::out | std::ios::app);
|
||||
traceFile.open(portduino_config.traceFilename, std::ios::out | std::ios::app);
|
||||
} catch (std::ofstream::failure &e) {
|
||||
std::cout << "*** traceFile Exception " << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (verboseEnabled && settingsMap[logoutputlevel] != level_trace) {
|
||||
settingsMap[logoutputlevel] = level_debug;
|
||||
if (verboseEnabled && portduino_config.logoutputlevel != level_trace) {
|
||||
portduino_config.logoutputlevel = level_debug;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -537,99 +448,78 @@ bool loadConfig(const char *configPath)
|
||||
yamlConfig = YAML::LoadFile(configPath);
|
||||
if (yamlConfig["Logging"]) {
|
||||
if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "trace") {
|
||||
settingsMap[logoutputlevel] = level_trace;
|
||||
portduino_config.logoutputlevel = level_trace;
|
||||
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "debug") {
|
||||
settingsMap[logoutputlevel] = level_debug;
|
||||
portduino_config.logoutputlevel = level_debug;
|
||||
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "info") {
|
||||
settingsMap[logoutputlevel] = level_info;
|
||||
portduino_config.logoutputlevel = level_info;
|
||||
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "warn") {
|
||||
settingsMap[logoutputlevel] = level_warn;
|
||||
portduino_config.logoutputlevel = level_warn;
|
||||
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "error") {
|
||||
settingsMap[logoutputlevel] = level_error;
|
||||
portduino_config.logoutputlevel = level_error;
|
||||
}
|
||||
settingsStrings[traceFilename] = yamlConfig["Logging"]["TraceFile"].as<std::string>("");
|
||||
portduino_config.traceFilename = yamlConfig["Logging"]["TraceFile"].as<std::string>("");
|
||||
if (yamlConfig["Logging"]["AsciiLogs"]) {
|
||||
// Default is !isatty(1) but can be set explicitly in config.yaml
|
||||
settingsMap[ascii_logs] = yamlConfig["Logging"]["AsciiLogs"].as<bool>();
|
||||
portduino_config.ascii_logs = yamlConfig["Logging"]["AsciiLogs"].as<bool>();
|
||||
portduino_config.ascii_logs_explicit = true;
|
||||
}
|
||||
}
|
||||
if (yamlConfig["Lora"]) {
|
||||
const struct {
|
||||
configNames cfgName;
|
||||
std::string strName;
|
||||
} loraModules[] = {{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"},
|
||||
{use_sx1268, "sx1268"}, {use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"},
|
||||
{use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
for (auto &loraModule : loraModules) {
|
||||
settingsMap[loraModule.cfgName] = false;
|
||||
}
|
||||
|
||||
if (yamlConfig["Lora"]["Module"]) {
|
||||
for (auto &loraModule : loraModules) {
|
||||
if (yamlConfig["Lora"]["Module"].as<std::string>("") == loraModule.strName) {
|
||||
settingsMap[loraModule.cfgName] = true;
|
||||
for (auto &loraModule : portduino_config.loraModules) {
|
||||
if (yamlConfig["Lora"]["Module"].as<std::string>("") == loraModule.second) {
|
||||
portduino_config.lora_module = loraModule.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlConfig["Lora"]["SX126X_MAX_POWER"])
|
||||
portduino_config.sx126x_max_power = yamlConfig["Lora"]["SX126X_MAX_POWER"].as<int>(22);
|
||||
if (yamlConfig["Lora"]["SX128X_MAX_POWER"])
|
||||
portduino_config.sx128x_max_power = yamlConfig["Lora"]["SX128X_MAX_POWER"].as<int>(13);
|
||||
if (yamlConfig["Lora"]["LR1110_MAX_POWER"])
|
||||
portduino_config.lr1110_max_power = yamlConfig["Lora"]["LR1110_MAX_POWER"].as<int>(22);
|
||||
if (yamlConfig["Lora"]["LR1120_MAX_POWER"])
|
||||
portduino_config.lr1120_max_power = yamlConfig["Lora"]["LR1120_MAX_POWER"].as<int>(13);
|
||||
if (yamlConfig["Lora"]["RF95_MAX_POWER"])
|
||||
portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
|
||||
|
||||
settingsMap[sx126x_max_power] = yamlConfig["Lora"]["SX126X_MAX_POWER"].as<int>(22);
|
||||
settingsMap[sx128x_max_power] = yamlConfig["Lora"]["SX128X_MAX_POWER"].as<int>(13);
|
||||
settingsMap[lr1110_max_power] = yamlConfig["Lora"]["LR1110_MAX_POWER"].as<int>(22);
|
||||
settingsMap[lr1120_max_power] = yamlConfig["Lora"]["LR1120_MAX_POWER"].as<int>(13);
|
||||
settingsMap[rf95_max_power] = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
|
||||
if (portduino_config.lora_module != use_autoconf && portduino_config.lora_module != use_simradio &&
|
||||
!portduino_config.force_simradio) {
|
||||
portduino_config.dio2_as_rf_switch = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
|
||||
portduino_config.dio3_tcxo_voltage = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<float>(0) * 1000;
|
||||
if (portduino_config.dio3_tcxo_voltage == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false)) {
|
||||
portduino_config.dio3_tcxo_voltage = 1800; // default millivolts for "true"
|
||||
}
|
||||
|
||||
settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
|
||||
settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<float>(0) * 1000;
|
||||
if (settingsMap[dio3_tcxo_voltage] == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as<bool>(false)) {
|
||||
settingsMap[dio3_tcxo_voltage] = 1800; // default millivolts for "true"
|
||||
}
|
||||
|
||||
// backwards API compatibility and to globally set gpiochip once
|
||||
int defaultGpioChip = settingsMap[default_gpiochip] = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||
|
||||
const struct {
|
||||
configNames pin;
|
||||
configNames gpiochip;
|
||||
configNames line;
|
||||
std::string strName;
|
||||
} pinMappings[] = {
|
||||
{cs_pin, cs_gpiochip, cs_line, "CS"},
|
||||
{irq_pin, irq_gpiochip, irq_line, "IRQ"},
|
||||
{busy_pin, busy_gpiochip, busy_line, "Busy"},
|
||||
{reset_pin, reset_gpiochip, reset_line, "Reset"},
|
||||
{txen_pin, txen_gpiochip, txen_line, "TXen"},
|
||||
{rxen_pin, rxen_gpiochip, rxen_line, "RXen"},
|
||||
{sx126x_ant_sw_pin, sx126x_ant_sw_gpiochip, sx126x_ant_sw_line, "SX126X_ANT_SW"},
|
||||
};
|
||||
for (auto &pinMap : pinMappings) {
|
||||
if (yamlConfig["Lora"][pinMap.strName].IsMap()) {
|
||||
settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName]["pin"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[pinMap.line] = yamlConfig["Lora"][pinMap.strName]["line"].as<int>(settingsMap[pinMap.pin]);
|
||||
settingsMap[pinMap.gpiochip] = yamlConfig["Lora"][pinMap.strName]["gpiochip"].as<int>(defaultGpioChip);
|
||||
} else { // backwards API compatibility
|
||||
settingsMap[pinMap.pin] = yamlConfig["Lora"][pinMap.strName].as<int>(RADIOLIB_NC);
|
||||
settingsMap[pinMap.line] = settingsMap[pinMap.pin];
|
||||
settingsMap[pinMap.gpiochip] = defaultGpioChip;
|
||||
// backwards API compatibility and to globally set gpiochip once
|
||||
portduino_config.lora_default_gpiochip = yamlConfig["Lora"]["gpiochip"].as<int>(0);
|
||||
for (auto this_pin : portduino_config.all_pins) {
|
||||
if (this_pin->config_section == "Lora") {
|
||||
readGPIOFromYaml(yamlConfig["Lora"][this_pin->config_name], *this_pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
settingsMap[spiSpeed] = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
||||
settingsStrings[lora_usb_serial_num] = yamlConfig["Lora"]["USB_Serialnum"].as<std::string>("");
|
||||
settingsMap[lora_usb_pid] = yamlConfig["Lora"]["USB_PID"].as<int>(0x5512);
|
||||
settingsMap[lora_usb_vid] = yamlConfig["Lora"]["USB_VID"].as<int>(0x1A86);
|
||||
portduino_config.spiSpeed = yamlConfig["Lora"]["spiSpeed"].as<int>(2000000);
|
||||
portduino_config.lora_usb_serial_num = yamlConfig["Lora"]["USB_Serialnum"].as<std::string>("");
|
||||
portduino_config.lora_usb_pid = yamlConfig["Lora"]["USB_PID"].as<int>(0x5512);
|
||||
portduino_config.lora_usb_vid = yamlConfig["Lora"]["USB_VID"].as<int>(0x1A86);
|
||||
|
||||
settingsStrings[spidev] = yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
|
||||
if (settingsStrings[spidev] != "ch341") {
|
||||
settingsStrings[spidev] = "/dev/" + settingsStrings[spidev];
|
||||
if (settingsStrings[spidev].length() == 14) {
|
||||
int x = settingsStrings[spidev].at(11) - '0';
|
||||
int y = settingsStrings[spidev].at(13) - '0';
|
||||
portduino_config.lora_spi_dev = yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
|
||||
if (portduino_config.lora_spi_dev != "ch341") {
|
||||
portduino_config.lora_spi_dev = "/dev/" + portduino_config.lora_spi_dev;
|
||||
if (portduino_config.lora_spi_dev.length() == 14) {
|
||||
int x = portduino_config.lora_spi_dev.at(11) - '0';
|
||||
int y = portduino_config.lora_spi_dev.at(13) - '0';
|
||||
// Pretty sure this is always true
|
||||
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
|
||||
// I believe this bit of weirdness is specifically for the new GUI
|
||||
settingsMap[spidev] = x + y << 4;
|
||||
settingsMap[displayspidev] = settingsMap[spidev];
|
||||
settingsMap[touchscreenspidev] = settingsMap[spidev];
|
||||
portduino_config.lora_spi_dev_int = x + y << 4;
|
||||
portduino_config.display_spi_dev_int = portduino_config.lora_spi_dev_int;
|
||||
portduino_config.touchscreen_spi_dev_int = portduino_config.lora_spi_dev_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,163 +566,152 @@ bool loadConfig(const char *configPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlConfig["GPIO"]) {
|
||||
settingsMap[userButtonPin] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
|
||||
}
|
||||
readGPIOFromYaml(yamlConfig["GPIO"]["User"], portduino_config.userButtonPin);
|
||||
if (yamlConfig["GPS"]) {
|
||||
std::string serialPath = yamlConfig["GPS"]["SerialPath"].as<std::string>("");
|
||||
if (serialPath != "") {
|
||||
Serial1.setPath(serialPath);
|
||||
settingsMap[has_gps] = 1;
|
||||
portduino_config.has_gps = 1;
|
||||
}
|
||||
}
|
||||
if (yamlConfig["I2C"]) {
|
||||
settingsStrings[i2cdev] = yamlConfig["I2C"]["I2CDevice"].as<std::string>("");
|
||||
portduino_config.i2cdev = yamlConfig["I2C"]["I2CDevice"].as<std::string>("");
|
||||
}
|
||||
if (yamlConfig["Display"]) {
|
||||
if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7789")
|
||||
settingsMap[displayPanel] = st7789;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7735")
|
||||
settingsMap[displayPanel] = st7735;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7735S")
|
||||
settingsMap[displayPanel] = st7735s;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7796")
|
||||
settingsMap[displayPanel] = st7796;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9341")
|
||||
settingsMap[displayPanel] = ili9341;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9342")
|
||||
settingsMap[displayPanel] = ili9342;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9486")
|
||||
settingsMap[displayPanel] = ili9486;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ILI9488")
|
||||
settingsMap[displayPanel] = ili9488;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "HX8357D")
|
||||
settingsMap[displayPanel] = hx8357d;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "X11")
|
||||
settingsMap[displayPanel] = x11;
|
||||
else if (yamlConfig["Display"]["Panel"].as<std::string>("") == "FB")
|
||||
settingsMap[displayPanel] = fb;
|
||||
settingsMap[displayHeight] = yamlConfig["Display"]["Height"].as<int>(0);
|
||||
settingsMap[displayWidth] = yamlConfig["Display"]["Width"].as<int>(0);
|
||||
settingsMap[displayDC] = yamlConfig["Display"]["DC"].as<int>(-1);
|
||||
settingsMap[displayCS] = yamlConfig["Display"]["CS"].as<int>(-1);
|
||||
settingsMap[displayRGBOrder] = yamlConfig["Display"]["RGBOrder"].as<bool>(false);
|
||||
settingsMap[displayBacklight] = yamlConfig["Display"]["Backlight"].as<int>(-1);
|
||||
settingsMap[displayBacklightInvert] = yamlConfig["Display"]["BacklightInvert"].as<bool>(false);
|
||||
settingsMap[displayBacklightPWMChannel] = yamlConfig["Display"]["BacklightPWMChannel"].as<int>(-1);
|
||||
settingsMap[displayReset] = yamlConfig["Display"]["Reset"].as<int>(-1);
|
||||
settingsMap[displayOffsetX] = yamlConfig["Display"]["OffsetX"].as<int>(0);
|
||||
settingsMap[displayOffsetY] = yamlConfig["Display"]["OffsetY"].as<int>(0);
|
||||
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
||||
settingsMap[displayOffsetRotate] = yamlConfig["Display"]["OffsetRotate"].as<int>(1);
|
||||
settingsMap[displayInvert] = yamlConfig["Display"]["Invert"].as<bool>(false);
|
||||
settingsMap[displayBusFrequency] = yamlConfig["Display"]["BusFrequency"].as<int>(40000000);
|
||||
|
||||
for (auto &screen_name : portduino_config.screen_names) {
|
||||
if (yamlConfig["Display"]["Panel"].as<std::string>("") == screen_name.second)
|
||||
portduino_config.displayPanel = screen_name.first;
|
||||
}
|
||||
portduino_config.displayHeight = yamlConfig["Display"]["Height"].as<int>(0);
|
||||
portduino_config.displayWidth = yamlConfig["Display"]["Width"].as<int>(0);
|
||||
|
||||
readGPIOFromYaml(yamlConfig["Display"]["DC"], portduino_config.displayDC, -1);
|
||||
readGPIOFromYaml(yamlConfig["Display"]["CS"], portduino_config.displayCS, -1);
|
||||
readGPIOFromYaml(yamlConfig["Display"]["Backlight"], portduino_config.displayBacklight, -1);
|
||||
readGPIOFromYaml(yamlConfig["Display"]["BacklightPWMChannel"], portduino_config.displayBacklightPWMChannel, -1);
|
||||
readGPIOFromYaml(yamlConfig["Display"]["Reset"], portduino_config.displayReset, -1);
|
||||
|
||||
portduino_config.displayBacklightInvert = yamlConfig["Display"]["BacklightInvert"].as<bool>(false);
|
||||
portduino_config.displayRGBOrder = yamlConfig["Display"]["RGBOrder"].as<bool>(false);
|
||||
portduino_config.displayOffsetX = yamlConfig["Display"]["OffsetX"].as<int>(0);
|
||||
portduino_config.displayOffsetY = yamlConfig["Display"]["OffsetY"].as<int>(0);
|
||||
portduino_config.displayRotate = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
||||
portduino_config.displayOffsetRotate = yamlConfig["Display"]["OffsetRotate"].as<int>(1);
|
||||
portduino_config.displayInvert = yamlConfig["Display"]["Invert"].as<bool>(false);
|
||||
portduino_config.displayBusFrequency = yamlConfig["Display"]["BusFrequency"].as<int>(40000000);
|
||||
if (yamlConfig["Display"]["spidev"]) {
|
||||
settingsStrings[displayspidev] = "/dev/" + yamlConfig["Display"]["spidev"].as<std::string>("spidev0.1");
|
||||
if (settingsStrings[displayspidev].length() == 14) {
|
||||
int x = settingsStrings[displayspidev].at(11) - '0';
|
||||
int y = settingsStrings[displayspidev].at(13) - '0';
|
||||
portduino_config.display_spi_dev = "/dev/" + yamlConfig["Display"]["spidev"].as<std::string>("spidev0.1");
|
||||
if (portduino_config.display_spi_dev.length() == 14) {
|
||||
int x = portduino_config.display_spi_dev.at(11) - '0';
|
||||
int y = portduino_config.display_spi_dev.at(13) - '0';
|
||||
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
|
||||
settingsMap[displayspidev] = x + y << 4;
|
||||
settingsMap[touchscreenspidev] = settingsMap[displayspidev];
|
||||
portduino_config.display_spi_dev_int = x + y << 4;
|
||||
portduino_config.touchscreen_spi_dev_int = portduino_config.display_spi_dev_int;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlConfig["Touchscreen"]) {
|
||||
if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "XPT2046")
|
||||
settingsMap[touchscreenModule] = xpt2046;
|
||||
portduino_config.touchscreenModule = xpt2046;
|
||||
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "STMPE610")
|
||||
settingsMap[touchscreenModule] = stmpe610;
|
||||
portduino_config.touchscreenModule = stmpe610;
|
||||
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "GT911")
|
||||
settingsMap[touchscreenModule] = gt911;
|
||||
portduino_config.touchscreenModule = gt911;
|
||||
else if (yamlConfig["Touchscreen"]["Module"].as<std::string>("") == "FT5x06")
|
||||
settingsMap[touchscreenModule] = ft5x06;
|
||||
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
|
||||
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
|
||||
settingsMap[touchscreenBusFrequency] = yamlConfig["Touchscreen"]["BusFrequency"].as<int>(1000000);
|
||||
settingsMap[touchscreenRotate] = yamlConfig["Touchscreen"]["Rotate"].as<int>(-1);
|
||||
settingsMap[touchscreenI2CAddr] = yamlConfig["Touchscreen"]["I2CAddr"].as<int>(-1);
|
||||
portduino_config.touchscreenModule = ft5x06;
|
||||
|
||||
readGPIOFromYaml(yamlConfig["Touchscreen"]["CS"], portduino_config.touchscreenCS, -1);
|
||||
readGPIOFromYaml(yamlConfig["Touchscreen"]["IRQ"], portduino_config.touchscreenIRQ, -1);
|
||||
|
||||
portduino_config.touchscreenBusFrequency = yamlConfig["Touchscreen"]["BusFrequency"].as<int>(1000000);
|
||||
portduino_config.touchscreenRotate = yamlConfig["Touchscreen"]["Rotate"].as<int>(-1);
|
||||
portduino_config.touchscreenI2CAddr = yamlConfig["Touchscreen"]["I2CAddr"].as<int>(-1);
|
||||
if (yamlConfig["Touchscreen"]["spidev"]) {
|
||||
settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
|
||||
if (settingsStrings[touchscreenspidev].length() == 14) {
|
||||
int x = settingsStrings[touchscreenspidev].at(11) - '0';
|
||||
int y = settingsStrings[touchscreenspidev].at(13) - '0';
|
||||
portduino_config.touchscreen_spi_dev = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
|
||||
if (portduino_config.touchscreen_spi_dev.length() == 14) {
|
||||
int x = portduino_config.touchscreen_spi_dev.at(11) - '0';
|
||||
int y = portduino_config.touchscreen_spi_dev.at(13) - '0';
|
||||
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
|
||||
settingsMap[touchscreenspidev] = x + y << 4;
|
||||
portduino_config.touchscreen_spi_dev_int = x + y << 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yamlConfig["Input"]) {
|
||||
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
||||
settingsStrings[pointerDevice] = (yamlConfig["Input"]["PointerDevice"]).as<std::string>("");
|
||||
settingsMap[userButtonPin] = yamlConfig["Input"]["User"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[tbUpPin] = yamlConfig["Input"]["TrackballUp"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[tbDownPin] = yamlConfig["Input"]["TrackballDown"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[tbLeftPin] = yamlConfig["Input"]["TrackballLeft"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[tbRightPin] = yamlConfig["Input"]["TrackballRight"].as<int>(RADIOLIB_NC);
|
||||
settingsMap[tbPressPin] = yamlConfig["Input"]["TrackballPress"].as<int>(RADIOLIB_NC);
|
||||
portduino_config.keyboardDevice = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
||||
portduino_config.pointerDevice = (yamlConfig["Input"]["PointerDevice"]).as<std::string>("");
|
||||
|
||||
readGPIOFromYaml(yamlConfig["Input"]["User"], portduino_config.userButtonPin);
|
||||
readGPIOFromYaml(yamlConfig["Input"]["TrackballUp"], portduino_config.tbUpPin);
|
||||
readGPIOFromYaml(yamlConfig["Input"]["TrackballDown"], portduino_config.tbDownPin);
|
||||
readGPIOFromYaml(yamlConfig["Input"]["TrackballLeft"], portduino_config.tbLeftPin);
|
||||
readGPIOFromYaml(yamlConfig["Input"]["TrackballRight"], portduino_config.tbRightPin);
|
||||
readGPIOFromYaml(yamlConfig["Input"]["TrackballPress"], portduino_config.tbPressPin);
|
||||
|
||||
if (yamlConfig["Input"]["TrackballDirection"].as<std::string>("RISING") == "RISING") {
|
||||
settingsMap[tbDirection] = 4;
|
||||
portduino_config.tbDirection = 4;
|
||||
} else if (yamlConfig["Input"]["TrackballDirection"].as<std::string>("RISING") == "FALLING") {
|
||||
settingsMap[tbDirection] = 3;
|
||||
portduino_config.tbDirection = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (yamlConfig["Webserver"]) {
|
||||
settingsMap[webserverport] = (yamlConfig["Webserver"]["Port"]).as<int>(-1);
|
||||
settingsStrings[webserverrootpath] =
|
||||
portduino_config.webserverport = (yamlConfig["Webserver"]["Port"]).as<int>(-1);
|
||||
portduino_config.webserver_root_path =
|
||||
(yamlConfig["Webserver"]["RootPath"]).as<std::string>("/usr/share/meshtasticd/web");
|
||||
settingsStrings[websslkeypath] =
|
||||
portduino_config.webserver_ssl_key_path =
|
||||
(yamlConfig["Webserver"]["SSLKey"]).as<std::string>("/etc/meshtasticd/ssl/private_key.pem");
|
||||
settingsStrings[websslcertpath] =
|
||||
portduino_config.webserver_ssl_cert_path =
|
||||
(yamlConfig["Webserver"]["SSLCert"]).as<std::string>("/etc/meshtasticd/ssl/certificate.pem");
|
||||
}
|
||||
|
||||
if (yamlConfig["HostMetrics"]) {
|
||||
settingsMap[hostMetrics_channel] = (yamlConfig["HostMetrics"]["Channel"]).as<int>(0);
|
||||
settingsMap[hostMetrics_interval] = (yamlConfig["HostMetrics"]["ReportInterval"]).as<int>(0);
|
||||
settingsStrings[hostMetrics_user_command] = (yamlConfig["HostMetrics"]["UserStringCommand"]).as<std::string>("");
|
||||
portduino_config.hostMetrics_channel = (yamlConfig["HostMetrics"]["Channel"]).as<int>(0);
|
||||
portduino_config.hostMetrics_interval = (yamlConfig["HostMetrics"]["ReportInterval"]).as<int>(0);
|
||||
portduino_config.hostMetrics_user_command = (yamlConfig["HostMetrics"]["UserStringCommand"]).as<std::string>("");
|
||||
}
|
||||
|
||||
if (yamlConfig["Config"]) {
|
||||
if (yamlConfig["Config"]["DisplayMode"]) {
|
||||
settingsMap[has_configDisplayMode] = true;
|
||||
portduino_config.has_configDisplayMode = true;
|
||||
if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "TWOCOLOR") {
|
||||
settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR;
|
||||
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR;
|
||||
} else if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "INVERTED") {
|
||||
settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_INVERTED;
|
||||
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_INVERTED;
|
||||
} else if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "COLOR") {
|
||||
settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_COLOR;
|
||||
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_COLOR;
|
||||
} else {
|
||||
settingsMap[configDisplayMode] = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
||||
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (yamlConfig["General"]) {
|
||||
settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as<int>(200);
|
||||
settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as<int>(100);
|
||||
settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as<std::string>("");
|
||||
settingsStrings[available_directory] =
|
||||
portduino_config.MaxNodes = (yamlConfig["General"]["MaxNodes"]).as<int>(200);
|
||||
portduino_config.maxtophone = (yamlConfig["General"]["MaxMessageQueue"]).as<int>(100);
|
||||
portduino_config.config_directory = (yamlConfig["General"]["ConfigDirectory"]).as<std::string>("");
|
||||
portduino_config.available_directory =
|
||||
(yamlConfig["General"]["AvailableDirectory"]).as<std::string>("/etc/meshtasticd/available.d/");
|
||||
if ((yamlConfig["General"]["MACAddress"]).as<std::string>("") != "" &&
|
||||
(yamlConfig["General"]["MACAddressSource"]).as<std::string>("") != "") {
|
||||
std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
settingsStrings[mac_address] = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
||||
if ((yamlConfig["General"]["MACAddressSource"]).as<std::string>("") != "") {
|
||||
std::ifstream infile("/sys/class/net/" + (yamlConfig["General"]["MACAddressSource"]).as<std::string>("") +
|
||||
"/address");
|
||||
std::getline(infile, settingsStrings[mac_address]);
|
||||
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
||||
if (portduino_config.mac_address != "") {
|
||||
portduino_config.mac_address_explicit = true;
|
||||
} else if ((yamlConfig["General"]["MACAddressSource"]).as<std::string>("") != "") {
|
||||
portduino_config.mac_address_source = (yamlConfig["General"]["MACAddressSource"]).as<std::string>("");
|
||||
std::ifstream infile("/sys/class/net/" + portduino_config.mac_address_source + "/address");
|
||||
std::getline(infile, portduino_config.mac_address);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/20326454
|
||||
settingsStrings[mac_address].erase(
|
||||
std::remove(settingsStrings[mac_address].begin(), settingsStrings[mac_address].end(), ':'),
|
||||
settingsStrings[mac_address].end());
|
||||
portduino_config.mac_address.erase(
|
||||
std::remove(portduino_config.mac_address.begin(), portduino_config.mac_address.end(), ':'),
|
||||
portduino_config.mac_address.end());
|
||||
}
|
||||
} catch (YAML::Exception &e) {
|
||||
std::cout << "*** Exception " << e.what() << std::endl;
|
||||
@@ -851,12 +730,12 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac)
|
||||
{
|
||||
mac_str.erase(std::remove(mac_str.begin(), mac_str.end(), ':'), mac_str.end());
|
||||
if (mac_str.length() == 12) {
|
||||
dmac[0] = std::stoi(settingsStrings[mac_address].substr(0, 2), nullptr, 16);
|
||||
dmac[1] = std::stoi(settingsStrings[mac_address].substr(2, 2), nullptr, 16);
|
||||
dmac[2] = std::stoi(settingsStrings[mac_address].substr(4, 2), nullptr, 16);
|
||||
dmac[3] = std::stoi(settingsStrings[mac_address].substr(6, 2), nullptr, 16);
|
||||
dmac[4] = std::stoi(settingsStrings[mac_address].substr(8, 2), nullptr, 16);
|
||||
dmac[5] = std::stoi(settingsStrings[mac_address].substr(10, 2), nullptr, 16);
|
||||
dmac[0] = std::stoi(portduino_config.mac_address.substr(0, 2), nullptr, 16);
|
||||
dmac[1] = std::stoi(portduino_config.mac_address.substr(2, 2), nullptr, 16);
|
||||
dmac[2] = std::stoi(portduino_config.mac_address.substr(4, 2), nullptr, 16);
|
||||
dmac[3] = std::stoi(portduino_config.mac_address.substr(6, 2), nullptr, 16);
|
||||
dmac[4] = std::stoi(portduino_config.mac_address.substr(8, 2), nullptr, 16);
|
||||
dmac[5] = std::stoi(portduino_config.mac_address.substr(10, 2), nullptr, 16);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -875,4 +754,19 @@ std::string exec(const char *cmd)
|
||||
result += buffer.data();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault)
|
||||
{
|
||||
if (sourceNode.IsMap()) {
|
||||
destPin.enabled = true;
|
||||
destPin.pin = sourceNode["pin"].as<int>(pinDefault);
|
||||
destPin.line = sourceNode["line"].as<int>(destPin.pin);
|
||||
destPin.gpiochip = sourceNode["gpiochip"].as<int>(portduino_config.lora_default_gpiochip);
|
||||
} else if (sourceNode) { // backwards API compatibility
|
||||
destPin.enabled = true;
|
||||
destPin.pin = sourceNode.as<int>(pinDefault);
|
||||
destPin.line = destPin.pin;
|
||||
destPin.gpiochip = portduino_config.lora_default_gpiochip;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "LR11x0Interface.h"
|
||||
#include "Module.h"
|
||||
#include "platform/portduino/USBHal.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
// Product strings for auto-configuration
|
||||
// {"PRODUCT_STRING", "CONFIG.YAML"}
|
||||
@@ -19,36 +20,10 @@ inline const std::unordered_map<std::string, std::string> configProducts = {
|
||||
{"RAK6421-13300-S1", "lora-RAK6421-13300-slot1.yaml"},
|
||||
{"RAK6421-13300-S2", "lora-RAK6421-13300-slot2.yaml"}};
|
||||
|
||||
enum configNames {
|
||||
default_gpiochip,
|
||||
cs_pin,
|
||||
cs_line,
|
||||
cs_gpiochip,
|
||||
irq_pin,
|
||||
irq_line,
|
||||
irq_gpiochip,
|
||||
busy_pin,
|
||||
busy_line,
|
||||
busy_gpiochip,
|
||||
reset_pin,
|
||||
reset_line,
|
||||
reset_gpiochip,
|
||||
txen_pin,
|
||||
txen_line,
|
||||
txen_gpiochip,
|
||||
rxen_pin,
|
||||
rxen_line,
|
||||
rxen_gpiochip,
|
||||
sx126x_ant_sw_pin,
|
||||
sx126x_ant_sw_line,
|
||||
sx126x_ant_sw_gpiochip,
|
||||
sx126x_max_power,
|
||||
sx128x_max_power,
|
||||
lr1110_max_power,
|
||||
lr1120_max_power,
|
||||
rf95_max_power,
|
||||
dio2_as_rf_switch,
|
||||
dio3_tcxo_voltage,
|
||||
enum screen_modules { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
|
||||
enum touchscreen_modules { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
|
||||
enum portduino_log_level { level_error, level_warn, level_info, level_debug, level_trace };
|
||||
enum lora_module_enum {
|
||||
use_simradio,
|
||||
use_autoconf,
|
||||
use_rf95,
|
||||
@@ -58,72 +33,18 @@ enum configNames {
|
||||
use_lr1110,
|
||||
use_lr1120,
|
||||
use_lr1121,
|
||||
use_llcc68,
|
||||
lora_usb_serial_num,
|
||||
lora_usb_pid,
|
||||
lora_usb_vid,
|
||||
userButtonPin,
|
||||
tbUpPin,
|
||||
tbDownPin,
|
||||
tbLeftPin,
|
||||
tbRightPin,
|
||||
tbPressPin,
|
||||
tbDirection,
|
||||
spidev,
|
||||
spiSpeed,
|
||||
i2cdev,
|
||||
has_gps,
|
||||
touchscreenModule,
|
||||
touchscreenCS,
|
||||
touchscreenIRQ,
|
||||
touchscreenI2CAddr,
|
||||
touchscreenBusFrequency,
|
||||
touchscreenRotate,
|
||||
touchscreenspidev,
|
||||
displayspidev,
|
||||
displayBusFrequency,
|
||||
displayPanel,
|
||||
displayWidth,
|
||||
displayHeight,
|
||||
displayCS,
|
||||
displayDC,
|
||||
displayRGBOrder,
|
||||
displayBacklight,
|
||||
displayBacklightPWMChannel,
|
||||
displayBacklightInvert,
|
||||
displayReset,
|
||||
displayRotate,
|
||||
displayOffsetRotate,
|
||||
displayOffsetX,
|
||||
displayOffsetY,
|
||||
displayInvert,
|
||||
keyboardDevice,
|
||||
pointerDevice,
|
||||
logoutputlevel,
|
||||
traceFilename,
|
||||
webserver,
|
||||
webserverport,
|
||||
webserverrootpath,
|
||||
websslkeypath,
|
||||
websslcertpath,
|
||||
maxtophone,
|
||||
maxnodes,
|
||||
ascii_logs,
|
||||
config_directory,
|
||||
available_directory,
|
||||
mac_address,
|
||||
hostMetrics_interval,
|
||||
hostMetrics_channel,
|
||||
hostMetrics_user_command,
|
||||
configDisplayMode,
|
||||
has_configDisplayMode
|
||||
use_llcc68
|
||||
};
|
||||
|
||||
struct pinMapping {
|
||||
std::string config_section;
|
||||
std::string config_name;
|
||||
int pin = RADIOLIB_NC;
|
||||
int gpiochip;
|
||||
int line;
|
||||
bool enabled = false;
|
||||
};
|
||||
enum { no_screen, x11, fb, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9486, ili9488, hx8357d };
|
||||
enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 };
|
||||
enum { level_error, level_warn, level_info, level_debug, level_trace };
|
||||
|
||||
extern std::map<configNames, int> settingsMap;
|
||||
extern std::map<configNames, std::string> settingsStrings;
|
||||
extern std::ofstream traceFile;
|
||||
extern Ch341Hal *ch341Hal;
|
||||
int initGPIOPin(int pinNum, std::string gpioChipname, int line);
|
||||
@@ -131,13 +52,422 @@ bool loadConfig(const char *configPath);
|
||||
static bool ends_with(std::string_view str, std::string_view suffix);
|
||||
void getMacAddr(uint8_t *dmac);
|
||||
bool MAC_from_string(std::string mac_str, uint8_t *dmac);
|
||||
void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault = RADIOLIB_NC);
|
||||
std::string exec(const char *cmd);
|
||||
|
||||
extern struct portduino_config_struct {
|
||||
// Lora
|
||||
std::map<lora_module_enum, std::string> loraModules = {
|
||||
{use_simradio, "sim"}, {use_autoconf, "auto"}, {use_rf95, "RF95"}, {use_sx1262, "sx1262"}, {use_sx1268, "sx1268"},
|
||||
{use_sx1280, "sx1280"}, {use_lr1110, "lr1110"}, {use_lr1120, "lr1120"}, {use_lr1121, "lr1121"}, {use_llcc68, "LLCC68"}};
|
||||
|
||||
std::map<screen_modules, std::string> screen_names = {{x11, "X11"}, {fb, "FB"}, {st7789, "ST7789"},
|
||||
{st7735, "ST7735"}, {st7735s, "ST7735S"}, {st7796, "ST7796"},
|
||||
{ili9341, "ILI9341"}, {ili9342, "ILI9342"}, {ili9486, "ILI9486"},
|
||||
{ili9488, "ILI9488"}, {hx8357d, "HX8357D"}};
|
||||
|
||||
lora_module_enum lora_module;
|
||||
bool has_rfswitch_table = false;
|
||||
uint32_t rfswitch_dio_pins[5] = {RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||
Module::RfSwitchMode_t rfswitch_table[8];
|
||||
bool force_simradio = false;
|
||||
bool has_device_id = false;
|
||||
uint8_t device_id[16] = {0};
|
||||
std::string lora_spi_dev = "";
|
||||
std::string lora_usb_serial_num = "";
|
||||
int lora_spi_dev_int = 0;
|
||||
int lora_default_gpiochip = 0;
|
||||
int sx126x_max_power = 22;
|
||||
int sx128x_max_power = 13;
|
||||
int lr1110_max_power = 22;
|
||||
int lr1120_max_power = 13;
|
||||
int rf95_max_power = 20;
|
||||
bool dio2_as_rf_switch = false;
|
||||
int dio3_tcxo_voltage = 0;
|
||||
int lora_usb_pid = 0x5512;
|
||||
int lora_usb_vid = 0x1A86;
|
||||
int spiSpeed = 2000000;
|
||||
pinMapping lora_cs_pin = {"Lora", "CS"};
|
||||
pinMapping lora_irq_pin = {"Lora", "IRQ"};
|
||||
pinMapping lora_busy_pin = {"Lora", "Busy"};
|
||||
pinMapping lora_reset_pin = {"Lora", "Reset"};
|
||||
pinMapping lora_txen_pin = {"Lora", "TXen"};
|
||||
pinMapping lora_rxen_pin = {"Lora", "RXen"};
|
||||
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
|
||||
|
||||
// GPS
|
||||
bool has_gps = false;
|
||||
|
||||
// I2C
|
||||
std::string i2cdev = "";
|
||||
|
||||
// Display
|
||||
std::string display_spi_dev = "";
|
||||
int display_spi_dev_int = 0;
|
||||
int displayBusFrequency = 40000000;
|
||||
screen_modules displayPanel = no_screen;
|
||||
int displayWidth = 0;
|
||||
int displayHeight = 0;
|
||||
bool displayRGBOrder = false;
|
||||
bool displayBacklightInvert = false;
|
||||
bool displayRotate = false;
|
||||
int displayOffsetRotate = 1;
|
||||
bool displayInvert = false;
|
||||
int displayOffsetX = 0;
|
||||
int displayOffsetY = 0;
|
||||
pinMapping displayDC = {"Display", "DC"};
|
||||
pinMapping displayCS = {"Display", "CS"};
|
||||
pinMapping displayBacklight = {"Display", "Backlight"};
|
||||
pinMapping displayBacklightPWMChannel = {"Display", "BacklightPWMChannel"};
|
||||
pinMapping displayReset = {"Display", "Reset"};
|
||||
|
||||
// Touchscreen
|
||||
std::string touchscreen_spi_dev = "";
|
||||
int touchscreen_spi_dev_int = 0;
|
||||
touchscreen_modules touchscreenModule = no_touchscreen;
|
||||
int touchscreenI2CAddr = -1;
|
||||
int touchscreenBusFrequency = 1000000;
|
||||
int touchscreenRotate = -1;
|
||||
pinMapping touchscreenCS = {"Touchscreen", "CS"};
|
||||
pinMapping touchscreenIRQ = {"Touchscreen", "IRQ"};
|
||||
|
||||
// Input
|
||||
std::string keyboardDevice = "";
|
||||
std::string pointerDevice = "";
|
||||
int tbDirection;
|
||||
pinMapping userButtonPin = {"Input", "User"};
|
||||
pinMapping tbUpPin = {"Input", "TrackballUp"};
|
||||
pinMapping tbDownPin = {"Input", "TrackballDown"};
|
||||
pinMapping tbLeftPin = {"Input", "TrackballLwft"};
|
||||
pinMapping tbRightPin = {"Input", "TrackballRight"};
|
||||
pinMapping tbPressPin = {"Input", "TrackballPress"};
|
||||
|
||||
// Logging
|
||||
portduino_log_level logoutputlevel = level_debug;
|
||||
std::string traceFilename;
|
||||
bool ascii_logs = !isatty(1);
|
||||
bool ascii_logs_explicit = false;
|
||||
|
||||
// Webserver
|
||||
std::string webserver_root_path = "";
|
||||
std::string webserver_ssl_key_path = "/etc/meshtasticd/ssl/private_key.pem";
|
||||
std::string webserver_ssl_cert_path = "/etc/meshtasticd/ssl/certificate.pem";
|
||||
int webserverport = -1;
|
||||
|
||||
// HostMetrics
|
||||
std::string hostMetrics_user_command = "";
|
||||
int hostMetrics_interval = 0;
|
||||
int hostMetrics_channel = 0;
|
||||
|
||||
// config
|
||||
int configDisplayMode = 0;
|
||||
bool has_configDisplayMode = false;
|
||||
|
||||
// General
|
||||
std::string mac_address = "";
|
||||
bool mac_address_explicit = false;
|
||||
std::string mac_address_source = "";
|
||||
std::string config_directory = "";
|
||||
std::string available_directory = "/etc/meshtasticd/available.d/";
|
||||
int maxtophone = 100;
|
||||
int MaxNodes = 200;
|
||||
|
||||
pinMapping *all_pins[20] = {&lora_cs_pin,
|
||||
&lora_irq_pin,
|
||||
&lora_busy_pin,
|
||||
&lora_reset_pin,
|
||||
&lora_txen_pin,
|
||||
&lora_rxen_pin,
|
||||
&lora_sx126x_ant_sw_pin,
|
||||
&displayDC,
|
||||
&displayCS,
|
||||
&displayBacklight,
|
||||
&displayBacklightPWMChannel,
|
||||
&displayReset,
|
||||
&touchscreenCS,
|
||||
&touchscreenIRQ,
|
||||
&userButtonPin,
|
||||
&tbUpPin,
|
||||
&tbDownPin,
|
||||
&tbLeftPin,
|
||||
&tbRightPin,
|
||||
&tbPressPin};
|
||||
|
||||
std::string emit_yaml()
|
||||
{
|
||||
YAML::Emitter out;
|
||||
out << YAML::BeginMap;
|
||||
|
||||
// Lora
|
||||
out << YAML::Key << "Lora" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "Module" << YAML::Value << loraModules[lora_module];
|
||||
|
||||
for (auto lora_pin : all_pins) {
|
||||
if (lora_pin->config_section == "Lora" && lora_pin->enabled) {
|
||||
out << YAML::Key << lora_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << lora_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << lora_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << lora_pin->gpiochip;
|
||||
out << YAML::EndMap; // User
|
||||
}
|
||||
}
|
||||
|
||||
if (sx126x_max_power != 22)
|
||||
out << YAML::Key << "SX126X_MAX_POWER" << YAML::Value << sx126x_max_power;
|
||||
if (sx128x_max_power != 13)
|
||||
out << YAML::Key << "SX128X_MAX_POWER" << YAML::Value << sx128x_max_power;
|
||||
if (lr1110_max_power != 22)
|
||||
out << YAML::Key << "LR1110_MAX_POWER" << YAML::Value << lr1110_max_power;
|
||||
if (lr1120_max_power != 13)
|
||||
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
|
||||
if (rf95_max_power != 20)
|
||||
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
|
||||
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
|
||||
if (dio3_tcxo_voltage != 0)
|
||||
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << dio3_tcxo_voltage;
|
||||
if (lora_usb_pid != 0x5512)
|
||||
out << YAML::Key << "USB_PID" << YAML::Value << YAML::Hex << lora_usb_pid;
|
||||
if (lora_usb_vid != 0x1A86)
|
||||
out << YAML::Key << "USB_VID" << YAML::Value << YAML::Hex << lora_usb_vid;
|
||||
if (lora_spi_dev != "")
|
||||
out << YAML::Key << "spidev" << YAML::Value << lora_spi_dev;
|
||||
if (lora_usb_serial_num != "")
|
||||
out << YAML::Key << "USB_Serialnum" << YAML::Value << lora_usb_serial_num;
|
||||
out << YAML::Key << "spiSpeed" << YAML::Value << spiSpeed;
|
||||
if (rfswitch_dio_pins[0] != RADIOLIB_NC) {
|
||||
out << YAML::Key << "rfswitch_table" << YAML::Value << YAML::BeginMap;
|
||||
|
||||
out << YAML::Key << "pins";
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// set up the pin array first
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO5)
|
||||
out << "DIO5";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO6)
|
||||
out << "DIO6";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO7)
|
||||
out << "DIO7";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO8)
|
||||
out << "DIO8";
|
||||
if (rfswitch_dio_pins[i] == RADIOLIB_LR11X0_DIO10)
|
||||
out << "DIO10";
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
out << YAML::Key << "MODE_STBY";
|
||||
break;
|
||||
case 1:
|
||||
out << YAML::Key << "MODE_RX";
|
||||
break;
|
||||
case 2:
|
||||
out << YAML::Key << "MODE_TX";
|
||||
break;
|
||||
case 3:
|
||||
out << YAML::Key << "MODE_TX_HP";
|
||||
break;
|
||||
case 4:
|
||||
out << YAML::Key << "MODE_TX_HF";
|
||||
break;
|
||||
case 5:
|
||||
out << YAML::Key << "MODE_GNSS";
|
||||
break;
|
||||
case 6:
|
||||
out << YAML::Key << "MODE_WIFI";
|
||||
break;
|
||||
}
|
||||
|
||||
out << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||
for (int j = 0; j < 5; j++) {
|
||||
if (rfswitch_table[i].values[j] == HIGH) {
|
||||
out << "HIGH";
|
||||
} else {
|
||||
out << "LOW";
|
||||
}
|
||||
}
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
out << YAML::EndMap; // rfswitch_table
|
||||
}
|
||||
out << YAML::EndMap; // Lora
|
||||
|
||||
if (i2cdev != "") {
|
||||
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;
|
||||
out << YAML::EndMap; // I2C
|
||||
}
|
||||
|
||||
// Display
|
||||
if (displayPanel != no_screen) {
|
||||
out << YAML::Key << "Display" << YAML::Value << YAML::BeginMap;
|
||||
for (auto &screen_name : screen_names) {
|
||||
if (displayPanel == screen_name.first)
|
||||
out << YAML::Key << "Module" << YAML::Value << screen_name.second;
|
||||
}
|
||||
for (auto display_pin : all_pins) {
|
||||
if (display_pin->config_section == "Display" && display_pin->enabled) {
|
||||
out << YAML::Key << display_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << display_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << display_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << display_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
out << YAML::Key << "spidev" << YAML::Value << display_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << displayBusFrequency;
|
||||
if (displayWidth)
|
||||
out << YAML::Key << "Width" << YAML::Value << displayWidth;
|
||||
if (displayHeight)
|
||||
out << YAML::Key << "Height" << YAML::Value << displayHeight;
|
||||
if (displayRGBOrder)
|
||||
out << YAML::Key << "RGBOrder" << YAML::Value << true;
|
||||
if (displayBacklightInvert)
|
||||
out << YAML::Key << "BacklightInvert" << YAML::Value << true;
|
||||
if (displayRotate)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << true;
|
||||
if (displayInvert)
|
||||
out << YAML::Key << "Invert" << YAML::Value << true;
|
||||
if (displayOffsetX)
|
||||
out << YAML::Key << "OffsetX" << YAML::Value << displayOffsetX;
|
||||
if (displayOffsetY)
|
||||
out << YAML::Key << "OffsetY" << YAML::Value << displayOffsetY;
|
||||
|
||||
out << YAML::Key << "OffsetRotate" << YAML::Value << displayOffsetRotate;
|
||||
|
||||
out << YAML::EndMap; // Display
|
||||
}
|
||||
|
||||
// Touchscreen
|
||||
if (touchscreen_spi_dev != "") {
|
||||
out << YAML::Key << "Touchscreen" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "spidev" << YAML::Value << touchscreen_spi_dev;
|
||||
out << YAML::Key << "BusFrequency" << YAML::Value << touchscreenBusFrequency;
|
||||
switch (touchscreenModule) {
|
||||
case xpt2046:
|
||||
out << YAML::Key << "Module" << YAML::Value << "XPT2046";
|
||||
case stmpe610:
|
||||
out << YAML::Key << "Module" << YAML::Value << "STMPE610";
|
||||
case gt911:
|
||||
out << YAML::Key << "Module" << YAML::Value << "GT911";
|
||||
case ft5x06:
|
||||
out << YAML::Key << "Module" << YAML::Value << "FT5x06";
|
||||
}
|
||||
for (auto touchscreen_pin : all_pins) {
|
||||
if (touchscreen_pin->config_section == "Touchscreen" && touchscreen_pin->enabled) {
|
||||
out << YAML::Key << touchscreen_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << touchscreen_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << touchscreen_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << touchscreen_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (touchscreenRotate != -1)
|
||||
out << YAML::Key << "Rotate" << YAML::Value << touchscreenRotate;
|
||||
if (touchscreenI2CAddr != -1)
|
||||
out << YAML::Key << "I2CAddr" << YAML::Value << touchscreenI2CAddr;
|
||||
out << YAML::EndMap; // Touchscreen
|
||||
}
|
||||
|
||||
// Input
|
||||
out << YAML::Key << "Input" << YAML::Value << YAML::BeginMap;
|
||||
if (keyboardDevice != "")
|
||||
out << YAML::Key << "KeyboardDevice" << YAML::Value << keyboardDevice;
|
||||
if (pointerDevice != "")
|
||||
out << YAML::Key << "PointerDevice" << YAML::Value << pointerDevice;
|
||||
|
||||
for (auto input_pin : all_pins) {
|
||||
if (input_pin->config_section == "Input" && input_pin->enabled) {
|
||||
out << YAML::Key << input_pin->config_name << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "pin" << YAML::Value << input_pin->pin;
|
||||
out << YAML::Key << "line" << YAML::Value << input_pin->line;
|
||||
out << YAML::Key << "gpiochip" << YAML::Value << input_pin->gpiochip;
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
}
|
||||
if (tbDirection == 3)
|
||||
out << YAML::Key << "TrackballDirection" << YAML::Value << "FALLING";
|
||||
|
||||
out << YAML::EndMap; // Input
|
||||
|
||||
out << YAML::Key << "Logging" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "LogLevel" << YAML::Value;
|
||||
switch (logoutputlevel) {
|
||||
case level_error:
|
||||
out << "error";
|
||||
break;
|
||||
case level_warn:
|
||||
out << "warn";
|
||||
break;
|
||||
case level_info:
|
||||
out << "info";
|
||||
break;
|
||||
case level_debug:
|
||||
out << "debug";
|
||||
break;
|
||||
case level_trace:
|
||||
out << "trace";
|
||||
break;
|
||||
}
|
||||
if (traceFilename != "")
|
||||
out << YAML::Key << "TraceFile" << YAML::Value << traceFilename;
|
||||
if (ascii_logs_explicit) {
|
||||
out << YAML::Key << "AsciiLogs" << YAML::Value << ascii_logs;
|
||||
}
|
||||
out << YAML::EndMap; // Logging
|
||||
|
||||
// Webserver
|
||||
if (webserver_root_path != "") {
|
||||
out << YAML::Key << "Webserver" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "RootPath" << YAML::Value << webserver_root_path;
|
||||
out << YAML::Key << "SSLKey" << YAML::Value << webserver_ssl_key_path;
|
||||
out << YAML::Key << "SSLCert" << YAML::Value << webserver_ssl_cert_path;
|
||||
out << YAML::Key << "Port" << YAML::Value << webserverport;
|
||||
out << YAML::EndMap; // Webserver
|
||||
}
|
||||
|
||||
// HostMetrics
|
||||
if (hostMetrics_user_command != "") {
|
||||
out << YAML::Key << "HostMetrics" << YAML::Value << YAML::BeginMap;
|
||||
out << YAML::Key << "UserStringCommand" << YAML::Value << hostMetrics_user_command;
|
||||
out << YAML::Key << "ReportInterval" << YAML::Value << hostMetrics_interval;
|
||||
out << YAML::Key << "Channel" << YAML::Value << hostMetrics_channel;
|
||||
|
||||
out << YAML::EndMap; // HostMetrics
|
||||
}
|
||||
|
||||
// config
|
||||
if (has_configDisplayMode) {
|
||||
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
|
||||
switch (configDisplayMode) {
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
|
||||
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
|
||||
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
|
||||
}
|
||||
|
||||
out << YAML::EndMap; // Config
|
||||
}
|
||||
|
||||
// General
|
||||
out << YAML::Key << "General" << YAML::Value << YAML::BeginMap;
|
||||
if (config_directory != "")
|
||||
out << YAML::Key << "ConfigDirectory" << YAML::Value << config_directory;
|
||||
if (mac_address_explicit)
|
||||
out << YAML::Key << "MACAddress" << YAML::Value << mac_address;
|
||||
if (mac_address_source != "")
|
||||
out << YAML::Key << "MACAddressSource" << YAML::Value << mac_address_source;
|
||||
if (available_directory != "")
|
||||
out << YAML::Key << "AvailableDirectory" << YAML::Value << available_directory;
|
||||
out << YAML::Key << "MaxMessageQueue" << YAML::Value << maxtophone;
|
||||
out << YAML::Key << "MaxNodes" << YAML::Value << MaxNodes;
|
||||
out << YAML::EndMap; // General
|
||||
return out.c_str();
|
||||
}
|
||||
} portduino_config;
|
||||
@@ -28,9 +28,9 @@
|
||||
#endif
|
||||
#ifndef HAS_TRACKBALL
|
||||
#define HAS_TRACKBALL 1
|
||||
#define TB_DOWN (uint8_t) settingsMap[tbDownPin]
|
||||
#define TB_UP (uint8_t) settingsMap[tbUpPin]
|
||||
#define TB_LEFT (uint8_t) settingsMap[tbLeftPin]
|
||||
#define TB_RIGHT (uint8_t) settingsMap[tbRightPin]
|
||||
#define TB_PRESS (uint8_t) settingsMap[tbPressPin]
|
||||
#define TB_DOWN (uint8_t) portduino_config.tbDownPin.pin
|
||||
#define TB_UP (uint8_t) portduino_config.tbUpPin.pin
|
||||
#define TB_LEFT (uint8_t) portduino_config.tbLeftPin.pin
|
||||
#define TB_RIGHT (uint8_t) portduino_config.tbRightPin.pin
|
||||
#define TB_PRESS (uint8_t) portduino_config.tbPressPin.pin
|
||||
#endif
|
||||
@@ -431,15 +431,6 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
gpio_wakeup_enable((gpio_num_t)PMU_IRQ, GPIO_INTR_LOW_LEVEL); // pmu irq
|
||||
#endif
|
||||
|
||||
#ifdef T_LORA_PAGER
|
||||
LOG_DEBUG("power down XL9555 io");
|
||||
io.digitalWrite(EXPANDS_DRV_EN, LOW);
|
||||
io.digitalWrite(EXPANDS_AMP_EN, LOW);
|
||||
io.digitalWrite(EXPANDS_KB_EN, LOW);
|
||||
io.digitalWrite(EXPANDS_SD_EN, LOW);
|
||||
io.digitalWrite(EXPANDS_GPIO_EN, LOW);
|
||||
#endif
|
||||
|
||||
auto res = esp_sleep_enable_gpio_wakeup();
|
||||
if (res != ESP_OK) {
|
||||
LOG_ERROR("esp_sleep_enable_gpio_wakeup result %d", res);
|
||||
@@ -480,14 +471,6 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
gpio_wakeup_disable((gpio_num_t)RF95_IRQ);
|
||||
}
|
||||
#endif
|
||||
#ifdef T_LORA_PAGER
|
||||
LOG_DEBUG("power up XL9555 io");
|
||||
io.digitalWrite(EXPANDS_DRV_EN, HIGH);
|
||||
io.digitalWrite(EXPANDS_AMP_EN, HIGH);
|
||||
io.digitalWrite(EXPANDS_KB_EN, HIGH);
|
||||
io.digitalWrite(EXPANDS_SD_EN, HIGH);
|
||||
io.digitalWrite(EXPANDS_GPIO_EN, HIGH);
|
||||
#endif
|
||||
|
||||
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
|
||||
notifyLightSleepEnd.notifyObservers(cause); // Button interrupts are reattached here
|
||||
|
||||
Reference in New Issue
Block a user