diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml
index 5a8e658cb..d8cb5a9dd 100644
--- a/bin/config-dist.yaml
+++ b/bin/config-dist.yaml
@@ -112,7 +112,7 @@ Touchscreen:
### Configure device for direct keyboard input
Input:
-# KeyboardDevice: /dev/input/event0
+# KeyboardDevice: /dev/input/by-id/usb-_Raspberry_Pi_Internal_Keyboard-event-kbd
###
diff --git a/boards/CDEBYTE_EoRa-S3.json b/boards/CDEBYTE_EoRa-S3.json
new file mode 100644
index 000000000..9ecee3c9f
--- /dev/null
+++ b/boards/CDEBYTE_EoRa-S3.json
@@ -0,0 +1,38 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "esp32s3_out.ld"
+ },
+ "core": "esp32",
+ "extra_flags": [
+ "-D CDEBYTE_EORA_S3",
+ "-D ARDUINO_USB_CDC_ON_BOOT=1",
+ "-D ARDUINO_USB_MODE=0",
+ "-D ARDUINO_RUNNING_CORE=1",
+ "-D ARDUINO_EVENT_RUNNING_CORE=1",
+ "-D BOARD_HAS_PSRAM"
+ ],
+ "f_cpu": "240000000L",
+ "f_flash": "80000000L",
+ "flash_mode": "dio",
+ "hwids": [["0x303A", "0x1001"]],
+ "mcu": "esp32s3",
+ "variant": "CDEBYTE_EoRa-S3"
+ },
+ "connectivity": ["wifi"],
+ "debug": {
+ "openocd_target": "esp32s3.cfg"
+ },
+ "frameworks": ["arduino", "espidf"],
+ "name": "CDEBYTE EoRa-S3",
+ "upload": {
+ "flash_size": "4MB",
+ "maximum_ram_size": 327680,
+ "maximum_size": 4194304,
+ "wait_for_upload_port": true,
+ "require_upload_port": true,
+ "speed": 921600
+ },
+ "url": "https://www.cdebyte.com/Module-Testkits-EoRaPI",
+ "vendor": "CDEBYTE"
+}
diff --git a/protobufs b/protobufs
index f92900c5f..ecf105f66 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit f92900c5f884b04388fb7abf61d4df66783015e4
+Subproject commit ecf105f66d182531423b73f4408c53701313c4eb
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index ac48e664c..4f42b36b5 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -185,10 +185,12 @@ static void powerEnter()
screen->setOn(true);
setBluetoothEnable(true);
// within enter() the function getState() returns the state we came from
- if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
+
+ // Mothballed: print change of power-state to device screen
+ /* if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
strcmp(powerFSM.getState()->name, "DARK") != 0) {
screen->print("Powered...\n");
- }
+ }*/
}
}
@@ -205,8 +207,10 @@ static void powerExit()
{
screen->setOn(true);
setBluetoothEnable(true);
- if (!isPowered())
- screen->print("Unpowered...\n");
+
+ // Mothballed: print change of power-state to device screen
+ /*if (!isPowered())
+ screen->print("Unpowered...\n");*/
}
static void onEnter()
diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp
index 16906e2e0..e09e5fe30 100644
--- a/src/RedirectablePrint.cpp
+++ b/src/RedirectablePrint.cpp
@@ -182,11 +182,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len)
{
const char alphabet[17] = "0123456789abcdef";
- log(logLevel, " +------------------------------------------------+ +----------------+\n");
- log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
+ log(logLevel, " +------------------------------------------------+ +----------------+\n");
+ log(logLevel, " |.0 .1 .2 .3 .4 .5 .6 .7 .8 .9 .a .b .c .d .e .f | | ASCII |\n");
for (uint16_t i = 0; i < len; i += 16) {
if (i % 128 == 0)
- log(logLevel, " +------------------------------------------------+ +----------------+\n");
+ log(logLevel, " +------------------------------------------------+ +----------------+\n");
char s[] = "| | | |\n";
uint8_t ix = 1, iy = 52;
for (uint8_t j = 0; j < 16; j++) {
@@ -208,7 +208,7 @@ void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16
log(logLevel, ".");
log(logLevel, s);
}
- log(logLevel, " +------------------------------------------------+ +----------------+\n");
+ log(logLevel, " +------------------------------------------------+ +----------------+\n");
}
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
diff --git a/src/configuration.h b/src/configuration.h
index 37b67f666..701e07a32 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -74,6 +74,13 @@ along with this program. If not, see .
#define RTC_DATA_ATTR
#endif
+// -----------------------------------------------------------------------------
+// Regulatory overrides for producing regional builds
+// -----------------------------------------------------------------------------
+
+// Define if region should override user saved region
+// #define LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923
+
// -----------------------------------------------------------------------------
// Feature toggles
// -----------------------------------------------------------------------------
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 6a0e3e44a..0d0bfd9a2 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -7,6 +7,8 @@
#include "main.h" // pmu_found
#include "sleep.h"
+
+#include "cas.h"
#include "ubx.h"
#ifdef ARCH_PORTDUINO
@@ -51,6 +53,28 @@ void GPS::UBXChecksum(uint8_t *message, size_t length)
message[length - 1] = CK_B;
}
+// Calculate the checksum for a CAS packet
+void GPS::CASChecksum(uint8_t *message, size_t length)
+{
+ uint32_t cksum = ((uint32_t)message[5] << 24); // Message ID
+ cksum += ((uint32_t)message[4]) << 16; // Class
+ cksum += message[2]; // Payload Len
+
+ // Iterate over the payload as a series of uint32_t's and
+ // accumulate the cksum
+ uint32_t *payload = (uint32_t *)(message + 6);
+ for (size_t i = 0; i < (length - 10) / 4; i++) {
+ uint32_t p = payload[i];
+ cksum += p;
+ }
+
+ // Place the checksum values in the message
+ message[length - 4] = (cksum & 0xFF);
+ message[length - 3] = (cksum & (0xFF << 8)) >> 8;
+ message[length - 2] = (cksum & (0xFF << 16)) >> 16;
+ message[length - 1] = (cksum & (0xFF << 24)) >> 24;
+}
+
// Function to create a ublox packet for editing in memory
uint8_t GPS::makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg)
{
@@ -72,6 +96,41 @@ uint8_t GPS::makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_siz
return (payload_size + 8);
}
+// Function to create a CAS packet for editing in memory
+uint8_t GPS::makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg)
+{
+ // General CAS structure
+ // | H1 | H2 | payload_len | cls | msg | Payload ... | Checksum |
+ // Size: | 1 | 1 | 2 | 1 | 1 | payload_len | 4 |
+ // Pos: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 ... | 6 + payload_len ... |
+ // |------|------|-------------|------|------|------|--------------|---------------------------|
+ // | 0xBA | 0xCE | 0xXX | 0xXX | 0xXX | 0xXX | 0xXX | 0xXX ... | 0xXX | 0xXX | 0xXX | 0xXX |
+
+ // Construct the CAS packet
+ UBXscratch[0] = 0xBA; // header 1 (0xBA)
+ UBXscratch[1] = 0xCE; // header 2 (0xCE)
+ UBXscratch[2] = payload_size; // length 1
+ UBXscratch[3] = 0; // length 2
+ UBXscratch[4] = class_id; // class
+ UBXscratch[5] = msg_id; // id
+
+ UBXscratch[6 + payload_size] = 0x00; // Checksum
+ UBXscratch[7 + payload_size] = 0x00;
+ UBXscratch[8 + payload_size] = 0x00;
+ UBXscratch[9 + payload_size] = 0x00;
+
+ for (int i = 0; i < payload_size; i++) {
+ UBXscratch[6 + i] = pgm_read_byte(&msg[i]);
+ }
+ CASChecksum(UBXscratch, (payload_size + 10));
+
+#if defined(GPS_DEBUG) && defined(DEBUG_PORT)
+ LOG_DEBUG("Constructed CAS packet: \n");
+ DEBUG_PORT.hexDump(MESHTASTIC_LOG_LEVEL_DEBUG, UBXscratch, payload_size + 10);
+#endif
+ return (payload_size + 10);
+}
+
GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
{
uint8_t buffer[768] = {0};
@@ -81,6 +140,7 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
while (millis() < startTimeout) {
if (_serial_gps->available()) {
b = _serial_gps->read();
+
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", (char *)buffer);
#endif
@@ -104,6 +164,67 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
return GNSS_RESPONSE_NONE;
}
+GPS_RESPONSE GPS::getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
+{
+ uint32_t startTime = millis();
+ uint8_t buffer[CAS_ACK_NACK_MSG_SIZE] = {0};
+ uint8_t bufferPos = 0;
+
+ // CAS-ACK-(N)ACK structure
+ // | H1 | H2 | Payload Len | cls | msg | Payload | Checksum (4) |
+ // | | | | | | Cls | Msg | Reserved | |
+ // |------|------|-------------|------|------|------|------|-------------|---------------------------|
+ // ACK-NACK| 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x00 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
+ // ACK-ACK | 0xBA | 0xCE | 0x04 | 0x00 | 0x05 | 0x01 | 0xXX | 0xXX | 0x00 | 0x00 | 0xXX | 0xXX | 0xXX | 0xXX |
+
+ while (millis() - startTime < waitMillis) {
+ if (_serial_gps->available()) {
+ buffer[bufferPos++] = _serial_gps->read();
+
+ // keep looking at the first two bytes of buffer until
+ // we have found the CAS frame header (0xBA, 0xCE), if not
+ // keep reading bytes until we find a frame header or we run
+ // out of time.
+ if ((bufferPos == 2) && !(buffer[0] == 0xBA && buffer[1] == 0xCE)) {
+ buffer[0] = buffer[1];
+ buffer[1] = 0;
+ bufferPos = 1;
+ }
+ }
+
+ // we have read all the bytes required for the Ack/Nack (14-bytes)
+ // and we must have found a frame to get this far
+ if (bufferPos == sizeof(buffer) - 1) {
+ uint8_t msg_cls = buffer[4]; // message class should be 0x05
+ uint8_t msg_msg_id = buffer[5]; // message id should be 0x00 or 0x01
+ uint8_t payload_cls = buffer[6]; // payload class id
+ uint8_t payload_msg = buffer[7]; // payload message id
+
+ // Check for an ACK-ACK for the specified class and message id
+ if ((msg_cls == 0x05) && (msg_msg_id == 0x01) && payload_cls == class_id && payload_msg == msg_id) {
+#ifdef GPS_DEBUG
+ LOG_INFO("Got ACK for class %02X message %02X in %d millis.\n", class_id, msg_id, millis() - startTime);
+#endif
+ return GNSS_RESPONSE_OK;
+ }
+
+ // Check for an ACK-NACK for the specified class and message id
+ if ((msg_cls == 0x05) && (msg_msg_id == 0x00) && payload_cls == class_id && payload_msg == msg_id) {
+#ifdef GPS_DEBUG
+ LOG_WARN("Got NACK for class %02X message %02X in %d millis.\n", class_id, msg_id, millis() - startTime);
+#endif
+ return GNSS_RESPONSE_NAK;
+ }
+
+ // This isn't the frame we are looking for, clear the buffer
+ // and try again until we run out of time.
+ memset(buffer, 0x0, sizeof(buffer));
+ bufferPos = 0;
+ }
+ }
+ return GNSS_RESPONSE_NONE;
+}
+
GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
{
uint8_t b;
@@ -313,6 +434,33 @@ bool GPS::setup()
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
_serial_gps->write("$PMTK886,1*29\r\n");
delay(250);
+ } else if (gnssModel == GNSS_MODEL_ATGM336H) {
+ // Set the intial configuration of the device - these _should_ work for most AT6558 devices
+ msglen = makeCASPacket(0x06, 0x07, sizeof(_message_CAS_CFG_NAVX_CONF), _message_CAS_CFG_NAVX_CONF);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACKCas(0x06, 0x07, 250) != GNSS_RESPONSE_OK) {
+ LOG_WARN("ATGM336H - Could not set Configuration");
+ }
+
+ // Set the update frequence to 1Hz
+ msglen = makeCASPacket(0x06, 0x04, sizeof(_message_CAS_CFG_RATE_1HZ), _message_CAS_CFG_RATE_1HZ);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACKCas(0x06, 0x04, 250) != GNSS_RESPONSE_OK) {
+ LOG_WARN("ATGM336H - Could not set Update Frequency");
+ }
+
+ // Set the NEMA output messages
+ // Ask for only RMC and GGA
+ uint8_t fields[] = {CAS_NEMA_RMC, CAS_NEMA_GGA};
+ for (int i = 0; i < sizeof(fields); i++) {
+ // Construct a CAS-CFG-MSG packet
+ uint8_t cas_cfg_msg_packet[] = {0x4e, fields[i], 0x01, 0x00};
+ msglen = makeCASPacket(0x06, 0x01, sizeof(cas_cfg_msg_packet), cas_cfg_msg_packet);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACKCas(0x06, 0x01, 250) != GNSS_RESPONSE_OK) {
+ LOG_WARN("ATGM336H - Could not enable NMEA MSG: %d\n", fields[i]);
+ }
+ }
} else if (gnssModel == GNSS_MODEL_UC6580) {
// The Unicore UC6580 can use a lot of sat systems, enable it to
// use GPS L1 & L5 + BDS B1I & B2a + GLONASS L1 + GALILEO E1 & E5a + SBAS
@@ -948,10 +1096,18 @@ GnssModel_t GPS::probe(int serialSpeed)
uint8_t buffer[768] = {0};
delay(100);
- // Close all NMEA sentences , Only valid for L76K MTK platform
+ // Close all NMEA sentences, valid for L76K, ATGM336H (and likely other AT6558 devices)
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
delay(20);
+ // Get version information
+ clearBuffer();
+ _serial_gps->write("$PCAS06,1*1A\r\n");
+ if (getACK("$GPTXT,01,01,02,HW=ATGM336H", 500) == GNSS_RESPONSE_OK) {
+ LOG_INFO("ATGM336H GNSS init succeeded, using ATGM336H Module\n");
+ return GNSS_MODEL_ATGM336H;
+ }
+
// Get version information
clearBuffer();
_serial_gps->write("$PCAS06,0*1B\r\n");
@@ -1216,6 +1372,11 @@ bool GPS::factoryReset()
LOG_INFO("GNSS Factory Reset via PCAS10,3\n");
_serial_gps->write("$PCAS10,3*1F\r\n");
delay(100);
+ } else if (gnssModel == GNSS_MODEL_ATGM336H) {
+ LOG_INFO("Factory Reset via CAS-CFG-RST\n");
+ uint8_t msglen = makeCASPacket(0x06, 0x02, sizeof(_message_CAS_CFG_RST_FACTORY), _message_CAS_CFG_RST_FACTORY);
+ _serial_gps->write(UBXscratch, msglen);
+ delay(100);
} else {
// fire this for good measure, if we have an L76B - won't harm other devices.
_serial_gps->write("$PMTK104*37\r\n");
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 49f27e29f..77c6c0269 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -22,7 +22,14 @@ struct uBloxGnssModelInfo {
char extension[10][30];
};
-typedef enum { GNSS_MODEL_MTK, GNSS_MODEL_UBLOX, GNSS_MODEL_UC6580, GNSS_MODEL_UNKNOWN, GNSS_MODEL_MTK_L76B } GnssModel_t;
+typedef enum {
+ GNSS_MODEL_ATGM336H,
+ GNSS_MODEL_MTK,
+ GNSS_MODEL_UBLOX,
+ GNSS_MODEL_UC6580,
+ GNSS_MODEL_UNKNOWN,
+ GNSS_MODEL_MTK_L76B
+} GnssModel_t;
typedef enum {
GNSS_RESPONSE_NONE,
@@ -133,6 +140,11 @@ class GPS : private concurrency::OSThread
static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[];
static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[];
+ // CASIC commands for ATGM336H
+ static const uint8_t _message_CAS_CFG_RST_FACTORY[];
+ static const uint8_t _message_CAS_CFG_NAVX_CONF[];
+ static const uint8_t _message_CAS_CFG_RATE_1HZ[];
+
meshtastic_Position p = meshtastic_Position_init_default;
GPS() : concurrency::OSThread("GPS") {}
@@ -174,6 +186,7 @@ class GPS : private concurrency::OSThread
// Create a ublox packet for editing in memory
uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
+ uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg);
// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
@@ -184,6 +197,8 @@ class GPS : private concurrency::OSThread
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
+ GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis);
+
/**
* Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode
*
@@ -243,6 +258,7 @@ class GPS : private concurrency::OSThread
// Calculate checksum
void UBXChecksum(uint8_t *message, size_t length);
+ void CASChecksum(uint8_t *message, size_t length);
/** Get how long we should stay looking for each aquisition
*/
diff --git a/src/gps/cas.h b/src/gps/cas.h
new file mode 100644
index 000000000..53d75cda9
--- /dev/null
+++ b/src/gps/cas.h
@@ -0,0 +1,63 @@
+#pragma once
+
+// CASIC binary message definitions
+// Reference: https://www.icofchina.com/d/file/xiazai/2020-09-22/20f1b42b3a11ac52089caf3603b43fb5.pdf
+// ATGM33H-5N: https://www.icofchina.com/pro/mokuai/2016-08-01/4.html
+// (https://www.icofchina.com/d/file/xiazai/2016-12-05/b5c57074f4b1fcc62ba8c7868548d18a.pdf)
+
+// NEMA (Class ID - 0x4e) message IDs
+#define CAS_NEMA_GGA 0x00
+#define CAS_NEMA_GLL 0x01
+#define CAS_NEMA_GSA 0x02
+#define CAS_NEMA_GSV 0x03
+#define CAS_NEMA_RMC 0x04
+#define CAS_NEMA_VTG 0x05
+#define CAS_NEMA_GST 0x07
+#define CAS_NEMA_ZDA 0x08
+#define CAS_NEMA_DHV 0x0D
+
+// Size of a CAS-ACK-(N)ACK message (14 bytes)
+#define CAS_ACK_NACK_MSG_SIZE 0x0E
+
+// CFG-RST (0x06, 0x02)
+// Factory reset
+const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = {
+ 0xFF, 0x03, // Fields to clear
+ 0x01, // Reset Mode: Controlled Software reset
+ 0x03 // Startup Mode: Factory
+};
+
+// CFG_RATE (0x06, 0x01)
+// 1HZ update rate, this should always be the case after
+// factory reset but update it regardless
+const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = {
+ 0xE8, 0x03, // Update Rate: 0x03E8 = 1000ms
+ 0x00, 0x00 // Reserved
+};
+
+// CFG-NAVX (0x06, 0x07)
+// Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system
+// Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable
+// and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used.
+const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = {
+ 0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings
+ 0x03, // Dynamic Mode: Automotive
+ 0x03, // Fix Mode: Auto 2D/3D
+ 0x00, // Min SV
+ 0x00, // Max SVs
+ 0x00, // Min CNO
+ 0x00, // Reserved1
+ 0x00, // Init 3D fix
+ 0x00, // Min Elevation
+ 0x00, // Dr Limit
+ 0x07, // Nav System: 2^0 = GPS, 2^1 = BDS 2^2 = GLONASS: 2^3
+ // 3=GPS+BDS, 7=GPS+BDS+GLONASS
+ 0x00, 0x00, // Rollover Week
+ 0x00, 0x00, 0x00, 0x00, // Fix Altitude
+ 0x00, 0x00, 0x00, 0x00, // Fix Height Error
+ 0x00, 0x00, 0x00, 0x00, // PDOP Maximum
+ 0x00, 0x00, 0x00, 0x00, // TDOP Maximum
+ 0x00, 0x00, 0x00, 0x00, // Position Accuracy Max
+ 0x00, 0x00, 0x00, 0x00, // Time Accuracy Max
+ 0x00, 0x00, 0x00, 0x00 // Static Hold Threshold
+};
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 4b3212f5f..917799626 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -594,20 +594,6 @@ void setup()
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
screen_model = config.display.oled;
-#ifdef UNPHONE
- // initialise IO expander with pinmodes
- Wire.beginTransmission(0x26);
- Wire.write(0x06);
- Wire.write(0x7A);
- Wire.write(0xDD);
- Wire.endTransmission();
- Wire.beginTransmission(0x26);
- Wire.write(0x02);
- Wire.write(0x04); // Backlight on
- Wire.write(0x22); // G&B LEDs off
- Wire.endTransmission();
-#endif
-
#if defined(USE_SH1107)
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
display_geometry = GEOMETRY_128_128;
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index dce7e47af..73aa29bbf 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -688,9 +688,13 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
static uint8_t failedCounter = 0;
failedCounter++;
if (failedCounter >= 2) {
- FSCom.format();
- // After formatting, the device needs to be restarted
- nodeDB->resetRadioConfig(true);
+ LOG_ERROR("Failed to save file twice. Rebooting...\n");
+ delay(100);
+ NVIC_SystemReset();
+ // We used to blow away the filesystem here, but that's a bit extreme
+ // FSCom.format();
+ // // After formatting, the device needs to be restarted
+ // nodeDB->resetRadioConfig(true);
}
#endif
}
@@ -734,6 +738,7 @@ void NodeDB::saveToDisk(int saveWhat)
config.has_power = true;
config.has_network = true;
config.has_bluetooth = true;
+
saveProto(configFileName, meshtastic_LocalConfig_size, &meshtastic_LocalConfig_msg, &config);
}
@@ -745,6 +750,12 @@ void NodeDB::saveToDisk(int saveWhat)
moduleConfig.has_serial = true;
moduleConfig.has_store_forward = true;
moduleConfig.has_telemetry = true;
+ moduleConfig.has_neighbor_info = true;
+ moduleConfig.has_detection_sensor = true;
+ moduleConfig.has_ambient_lighting = true;
+ moduleConfig.has_audio = true;
+ moduleConfig.has_paxcounter = true;
+
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);
}
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index efbcc9558..2a69d6d56 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -430,6 +430,7 @@ bool PhoneAPI::available()
auto nextNode = nodeDB->readNextMeshNode(readIndex);
if (nextNode) {
nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode);
+ nodeInfoForPhone.hops_away = nodeInfoForPhone.num == nodeDB->getNodeNum() ? 0 : nodeInfoForPhone.hops_away;
nodeInfoForPhone.is_favorite =
nodeInfoForPhone.is_favorite || nodeInfoForPhone.num == nodeDB->getNodeNum(); // Our node is always a favorite
}
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 3aac9dfce..63912a03e 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -151,10 +151,16 @@ static uint8_t bytes[MAX_RHPACKETLEN];
void initRegion()
{
const RegionInfo *r = regions;
+#ifdef LORA_REGIONCODE
+ for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != LORA_REGIONCODE; r++)
+ ;
+ LOG_INFO("Wanted region %d, regulatory override to %s\n", config.lora.region, r->name);
+#else
for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != config.lora.region; r++)
;
- myRegion = r;
LOG_INFO("Wanted region %d, using %s\n", config.lora.region, r->name);
+#endif
+ myRegion = r;
}
/**
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index e674e28bb..67b2edd15 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -146,6 +146,8 @@ typedef enum _meshtastic_HardwareModel {
/* Teledatics TD-LORAC NRF52840 based M.2 LoRA module
Compatible with the TD-WRLS development board */
meshtastic_HardwareModel_TD_LORAC = 60,
+ /* CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3 */
+ meshtastic_HardwareModel_CDEBYTE_EORA_S3 = 61,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------------------------------------------------------------ */
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index 6855265ac..15e437bb5 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -117,6 +117,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER
#elif defined(TLORA_T3S3_V1)
#define HW_VENDOR meshtastic_HardwareModel_TLORA_T3_S3
+#elif defined(CDEBYTE_ELORA_S3)
+#define HW_VENDOR meshtastic_HardwareModel_CDEBYTE_ELORA_S3
#elif defined(BETAFPV_2400_TX)
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_2400_TX
#elif defined(NANO_G1_EXPLORER)
diff --git a/variants/CDEBYTE_EoRa-S3/pins_arduino.h b/variants/CDEBYTE_EoRa-S3/pins_arduino.h
new file mode 100644
index 000000000..38a9103f0
--- /dev/null
+++ b/variants/CDEBYTE_EoRa-S3/pins_arduino.h
@@ -0,0 +1,37 @@
+// Need this file for ESP32-S3
+// No need to modify this file, changes to pins imported from variant.h
+// Most is similar to https://github.com/espressif/arduino-esp32/blob/master/variants/esp32s3/pins_arduino.h
+
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include
+#include
+
+#define USB_VID 0x303a
+#define USB_PID 0x1001
+
+#define EXTERNAL_NUM_INTERRUPTS 46
+#define NUM_DIGITAL_PINS 48
+#define NUM_ANALOG_INPUTS 20
+
+#define analogInputToDigitalPin(p) (((p) < 20) ? (analogChannelToDigitalPin(p)) : -1)
+#define digitalPinToInterrupt(p) \
+ (((p) < 48) ? (p) : -1) // Maybe it should be <= 48 but this is from a trustworthy source so it is likely correct
+#define digitalPinHasPWM(p) (p < 46)
+
+// Serial
+static const uint8_t TX = UART_TX;
+static const uint8_t RX = UART_RX;
+
+// Default SPI will be mapped to Radio
+static const uint8_t SS = LORA_CS;
+static const uint8_t SCK = LORA_SCK;
+static const uint8_t MOSI = LORA_MOSI;
+static const uint8_t MISO = LORA_MISO;
+
+// The default Wire will be mapped to PMU and RTC
+static const uint8_t SCL = I2C_SCL;
+static const uint8_t SDA = I2C_SDA;
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/CDEBYTE_EoRa-S3/platformio.ini b/variants/CDEBYTE_EoRa-S3/platformio.ini
new file mode 100644
index 000000000..1ff54de88
--- /dev/null
+++ b/variants/CDEBYTE_EoRa-S3/platformio.ini
@@ -0,0 +1,8 @@
+[env:CDEBYTE_EoRa-S3]
+extends = esp32s3_base
+board = CDEBYTE_EoRa-S3
+build_flags =
+ ${esp32s3_base.build_flags}
+ -D CDEBYTE_EORA_S3
+ -I variants/CDEBYTE_EoRa-S3
+ -D GPS_POWER_TOGGLE
diff --git a/variants/CDEBYTE_EoRa-S3/variant.h b/variants/CDEBYTE_EoRa-S3/variant.h
new file mode 100644
index 000000000..5da99667b
--- /dev/null
+++ b/variants/CDEBYTE_EoRa-S3/variant.h
@@ -0,0 +1,63 @@
+// LED - status indication
+#define LED_PIN 37
+
+// Button - user interface
+#define BUTTON_PIN 0 // This is the BOOT button, and it has its own pull-up resistor
+
+// SD card - TODO: test, currently untested, copied from T3S3 variant
+#define HAS_SDCARD
+#define SDCARD_USE_SPI1
+// TODO: rename this to make this SD-card specific
+#define SPI_CS 13
+#define SPI_SCK 14
+#define SPI_MOSI 11
+#define SPI_MISO 2
+// FIXME: there are two other SPI pins that are not defined here
+// Compatibility
+#define SDCARD_CS SPI_CS
+
+// Battery voltage monitoring - TODO: test, currently untested, copied from T3S3 variant
+#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
+#define ADC_MULTIPLIER \
+ 2.11 // ratio of voltage divider = 2.0 (R10=1M, R13=1M), plus some undervoltage correction - TODO: this was carried over from
+ // the T3S3, test to see if the undervoltage correction is needed.
+
+// Display - OLED connected via I2C by the default hardware configuration
+#define HAS_SCREEN 1
+#define USE_SSD1306
+#define I2C_SCL 17
+#define I2C_SDA 18
+
+// UART - The 1mm JST SH connector closest to the USB-C port
+#define UART_TX 43
+#define UART_RX 44
+
+// Peripheral I2C - The 1mm JST SH connector furthest from the USB-C port which follows Adafruit connection standard. There are no
+// pull-up resistors on these lines, the downstream device needs to include them. TODO: test, currently untested
+#define I2C_SCL1 21
+#define I2C_SDA1 10
+
+// Radio
+#define USE_SX1262 // CDEBYTE EoRa-S3-900TB <- CDEBYTE E22-900MM22S <- Semtech SX1262
+#define USE_SX1268 // CDEBYTE EoRa-S3-400TB <- CDEBYTE E22-400MM22S <- Semtech SX1268
+
+#define SX126X_CS 7
+#define LORA_SCK 5
+#define LORA_MOSI 6
+#define LORA_MISO 3
+#define SX126X_RESET 8
+#define SX126X_BUSY 34
+#define SX126X_DIO1 33
+
+#define SX126X_DIO2_AS_RF_SWITCH // All switching is performed with DIO2, it is automatically inverted using circuitry.
+// CDEBYTE EoRa-S3 uses an XTAL, thus we do not need DIO3 as TCXO voltage reference. Don't define SX126X_DIO3_TCXO_VOLTAGE for
+// simplicity rather than defining it as 0.
+#define SX126X_MAX_POWER \
+ 22 // E22-900MM22S and E22-400MM22S have a raw SX1262 or SX1268 respsectively, they are rated to output up and including 22
+ // dBm out of their SX126x IC.
+
+// Compatibility with old variant.h file structure - FIXME: this should be done in the respective radio interface modules to clean
+// up all variants.
+#define LORA_CS SX126X_CS
+#define LORA_DIO1 SX126X_DIO1
\ No newline at end of file
diff --git a/version.properties b/version.properties
index 6aedf1e72..f5ad818a2 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
-build = 5
+build = 6