mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-08 10:57:51 +00:00
Compare commits
19 Commits
v2.3.5.2f9
...
v2.3.6.7a3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a3570aecf | ||
|
|
64edfb76e0 | ||
|
|
e4b5f2ce14 | ||
|
|
4c0b7ea409 | ||
|
|
425a715995 | ||
|
|
747c713ba9 | ||
|
|
2e14234b77 | ||
|
|
d47e9bed19 | ||
|
|
bc085ab840 | ||
|
|
2450031b1b | ||
|
|
c34956e9d8 | ||
|
|
55c9c3b298 | ||
|
|
9599549477 | ||
|
|
e813703bf5 | ||
|
|
699ea74672 | ||
|
|
a01069a549 | ||
|
|
3413b9da41 | ||
|
|
7d3175dc83 | ||
|
|
441638c2eb |
@@ -1,6 +1,6 @@
|
|||||||
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
|
||||||
[portduino_base]
|
[portduino_base]
|
||||||
platform = https://github.com/meshtastic/platform-native.git#c95616208ffff4c8a36d48df810a3f072cce3521
|
platform = https://github.com/meshtastic/platform-native.git#6fb39b6f94ece9c042141edb4afb91aca94dcaab
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
|
|||||||
@@ -101,18 +101,20 @@ Display:
|
|||||||
# Height: 240
|
# Height: 240
|
||||||
|
|
||||||
Touchscreen:
|
Touchscreen:
|
||||||
|
### Note, at least for now, the touchscreen must have a CS pin defined, even if you let Linux manage the CS switching.
|
||||||
|
|
||||||
# Module: STMPE610
|
# Module: STMPE610
|
||||||
# CS: 7
|
# CS: 7
|
||||||
# IRQ: 24
|
# IRQ: 24
|
||||||
|
|
||||||
# Module: XPT2046
|
# Module: XPT2046 # Waveshare 2.8inch
|
||||||
# CS: 7
|
# CS: 7
|
||||||
# IRQ: 17
|
# IRQ: 17
|
||||||
|
|
||||||
### Configure device for direct keyboard input
|
### Configure device for direct keyboard input
|
||||||
|
|
||||||
Input:
|
Input:
|
||||||
# KeyboardDevice: /dev/input/event0
|
# KeyboardDevice: /dev/input/by-id/usb-_Raspberry_Pi_Internal_Keyboard-event-kbd
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
|||||||
38
boards/CDEBYTE_EoRa-S3.json
Normal file
38
boards/CDEBYTE_EoRa-S3.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
"extra_flags": [
|
"extra_flags": [
|
||||||
"-DBOARD_HAS_PSRAM",
|
"-DBOARD_HAS_PSRAM",
|
||||||
"-DLILYGO_TBEAM_S3_CORE",
|
"-DLILYGO_TBEAM_S3_CORE",
|
||||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
|
||||||
"-DARDUINO_USB_MODE=1",
|
"-DARDUINO_USB_MODE=1",
|
||||||
"-DARDUINO_RUNNING_CORE=1",
|
"-DARDUINO_RUNNING_CORE=1",
|
||||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||||
|
|||||||
Submodule protobufs updated: f92900c5f8...0d08acd9c5
@@ -185,10 +185,12 @@ static void powerEnter()
|
|||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
setBluetoothEnable(true);
|
setBluetoothEnable(true);
|
||||||
// within enter() the function getState() returns the state we came from
|
// 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) {
|
strcmp(powerFSM.getState()->name, "DARK") != 0) {
|
||||||
screen->print("Powered...\n");
|
screen->print("Powered...\n");
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,8 +207,10 @@ static void powerExit()
|
|||||||
{
|
{
|
||||||
screen->setOn(true);
|
screen->setOn(true);
|
||||||
setBluetoothEnable(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()
|
static void onEnter()
|
||||||
|
|||||||
@@ -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)
|
void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len)
|
||||||
{
|
{
|
||||||
const char alphabet[17] = "0123456789abcdef";
|
const char alphabet[17] = "0123456789abcdef";
|
||||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
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, " |.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) {
|
for (uint16_t i = 0; i < len; i += 16) {
|
||||||
if (i % 128 == 0)
|
if (i % 128 == 0)
|
||||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||||
char s[] = "| | | |\n";
|
char s[] = "| | | |\n";
|
||||||
uint8_t ix = 1, iy = 52;
|
uint8_t ix = 1, iy = 52;
|
||||||
for (uint8_t j = 0; j < 16; j++) {
|
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, ".");
|
||||||
log(logLevel, s);
|
log(logLevel, s);
|
||||||
}
|
}
|
||||||
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
log(logLevel, " +------------------------------------------------+ +----------------+\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
|
std::string RedirectablePrint::mt_sprintf(const std::string fmt_str, ...)
|
||||||
|
|||||||
@@ -74,6 +74,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define RTC_DATA_ATTR
|
#define RTC_DATA_ATTR
|
||||||
#endif
|
#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
|
// Feature toggles
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
163
src/gps/GPS.cpp
163
src/gps/GPS.cpp
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "main.h" // pmu_found
|
#include "main.h" // pmu_found
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
|
||||||
|
#include "cas.h"
|
||||||
#include "ubx.h"
|
#include "ubx.h"
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
@@ -51,6 +53,28 @@ void GPS::UBXChecksum(uint8_t *message, size_t length)
|
|||||||
message[length - 1] = CK_B;
|
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
|
// 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)
|
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);
|
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)
|
GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
||||||
{
|
{
|
||||||
uint8_t buffer[768] = {0};
|
uint8_t buffer[768] = {0};
|
||||||
@@ -81,6 +140,7 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
while (millis() < startTimeout) {
|
while (millis() < startTimeout) {
|
||||||
if (_serial_gps->available()) {
|
if (_serial_gps->available()) {
|
||||||
b = _serial_gps->read();
|
b = _serial_gps->read();
|
||||||
|
|
||||||
#ifdef GPS_DEBUG
|
#ifdef GPS_DEBUG
|
||||||
LOG_DEBUG("%02X", (char *)buffer);
|
LOG_DEBUG("%02X", (char *)buffer);
|
||||||
#endif
|
#endif
|
||||||
@@ -104,6 +164,67 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
|
|||||||
return GNSS_RESPONSE_NONE;
|
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)
|
GPS_RESPONSE GPS::getACK(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis)
|
||||||
{
|
{
|
||||||
uint8_t b;
|
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)
|
// Switch to Fitness Mode, for running and walking purpose with low speed (<5 m/s)
|
||||||
_serial_gps->write("$PMTK886,1*29\r\n");
|
_serial_gps->write("$PMTK886,1*29\r\n");
|
||||||
delay(250);
|
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) {
|
} else if (gnssModel == GNSS_MODEL_UC6580) {
|
||||||
// The Unicore UC6580 can use a lot of sat systems, enable it to
|
// 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
|
// 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};
|
uint8_t buffer[768] = {0};
|
||||||
delay(100);
|
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");
|
_serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
delay(20);
|
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
|
// Get version information
|
||||||
clearBuffer();
|
clearBuffer();
|
||||||
_serial_gps->write("$PCAS06,0*1B\r\n");
|
_serial_gps->write("$PCAS06,0*1B\r\n");
|
||||||
@@ -1216,6 +1372,11 @@ bool GPS::factoryReset()
|
|||||||
LOG_INFO("GNSS Factory Reset via PCAS10,3\n");
|
LOG_INFO("GNSS Factory Reset via PCAS10,3\n");
|
||||||
_serial_gps->write("$PCAS10,3*1F\r\n");
|
_serial_gps->write("$PCAS10,3*1F\r\n");
|
||||||
delay(100);
|
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 {
|
} else {
|
||||||
// fire this for good measure, if we have an L76B - won't harm other devices.
|
// fire this for good measure, if we have an L76B - won't harm other devices.
|
||||||
_serial_gps->write("$PMTK104*37\r\n");
|
_serial_gps->write("$PMTK104*37\r\n");
|
||||||
|
|||||||
@@ -22,7 +22,14 @@ struct uBloxGnssModelInfo {
|
|||||||
char extension[10][30];
|
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 {
|
typedef enum {
|
||||||
GNSS_RESPONSE_NONE,
|
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_RAM[];
|
||||||
static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[];
|
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;
|
meshtastic_Position p = meshtastic_Position_init_default;
|
||||||
|
|
||||||
GPS() : concurrency::OSThread("GPS") {}
|
GPS() : concurrency::OSThread("GPS") {}
|
||||||
@@ -174,6 +186,7 @@ class GPS : private concurrency::OSThread
|
|||||||
|
|
||||||
// Create a ublox packet for editing in memory
|
// 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 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
|
// scratch space for creating ublox packets
|
||||||
uint8_t UBXscratch[250] = {0};
|
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(uint8_t c, uint8_t i, uint32_t waitMillis);
|
||||||
GPS_RESPONSE getACK(const char *message, 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
|
* 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
|
// Calculate checksum
|
||||||
void UBXChecksum(uint8_t *message, size_t length);
|
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
|
/** Get how long we should stay looking for each aquisition
|
||||||
*/
|
*/
|
||||||
|
|||||||
63
src/gps/cas.h
Normal file
63
src/gps/cas.h
Normal file
@@ -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
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
|
#include "mesh_bus_spi.h"
|
||||||
#include "platform/portduino/PortduinoGlue.h"
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -339,7 +340,7 @@ static TFT_eSPI *tft = nullptr; // Invoke library, pins defined in User_Setup.h
|
|||||||
class LGFX : public lgfx::LGFX_Device
|
class LGFX : public lgfx::LGFX_Device
|
||||||
{
|
{
|
||||||
lgfx::Panel_LCD *_panel_instance;
|
lgfx::Panel_LCD *_panel_instance;
|
||||||
lgfx::Bus_SPI _bus_instance;
|
lgfx::Mesh_Bus_SPI _bus_instance;
|
||||||
|
|
||||||
lgfx::ITouch *_touch_instance;
|
lgfx::ITouch *_touch_instance;
|
||||||
|
|
||||||
@@ -356,6 +357,7 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
_panel_instance = new lgfx::Panel_ILI9341;
|
_panel_instance = new lgfx::Panel_ILI9341;
|
||||||
auto buscfg = _bus_instance.config();
|
auto buscfg = _bus_instance.config();
|
||||||
buscfg.spi_mode = 0;
|
buscfg.spi_mode = 0;
|
||||||
|
_bus_instance.spi_device(DisplaySPI, settingsStrings[displayspidev]);
|
||||||
|
|
||||||
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
|
||||||
|
|
||||||
@@ -411,8 +413,7 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
lgfx::Panel_HX8357D _panel_instance;
|
lgfx::Panel_HX8357D _panel_instance;
|
||||||
lgfx::Bus_SPI _bus_instance;
|
lgfx::Bus_SPI _bus_instance;
|
||||||
#if defined(USE_XPT2046)
|
#if defined(USE_XPT2046)
|
||||||
lgfx::ITouch *_touch_instance;
|
lgfx::Touch_XPT2046 _touch_instance;
|
||||||
// lgfx::Touch_XPT2046 _touch_instance;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -466,8 +467,7 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
#if defined(USE_XPT2046)
|
#if defined(USE_XPT2046)
|
||||||
{
|
{
|
||||||
// Configure settings for touch control.
|
// Configure settings for touch control.
|
||||||
_touch_instance = new lgfx::Touch_XPT2046;
|
auto touch_cfg = _touch_instance.config();
|
||||||
auto touch_cfg = _touch_instance->config();
|
|
||||||
|
|
||||||
touch_cfg.pin_cs = TOUCH_CS;
|
touch_cfg.pin_cs = TOUCH_CS;
|
||||||
touch_cfg.x_min = 0;
|
touch_cfg.x_min = 0;
|
||||||
@@ -478,8 +478,8 @@ class LGFX : public lgfx::LGFX_Device
|
|||||||
touch_cfg.bus_shared = true;
|
touch_cfg.bus_shared = true;
|
||||||
touch_cfg.offset_rotation = 1;
|
touch_cfg.offset_rotation = 1;
|
||||||
|
|
||||||
_touch_instance->config(touch_cfg);
|
_touch_instance.config(touch_cfg);
|
||||||
//_panel_instance->setTouch(_touch_instance);
|
_panel_instance.setTouch(&_touch_instance);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
setPanel(&_panel_instance);
|
setPanel(&_panel_instance);
|
||||||
@@ -496,6 +496,11 @@ static LGFX *tft = nullptr;
|
|||||||
#include "TFTDisplay.h"
|
#include "TFTDisplay.h"
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#ifdef UNPHONE
|
||||||
|
#include "unPhone.h"
|
||||||
|
extern unPhone unphone;
|
||||||
|
#endif
|
||||||
|
|
||||||
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl, OLEDDISPLAY_GEOMETRY geometry, HW_I2C i2cBus)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("TFTDisplay!\n");
|
LOG_DEBUG("TFTDisplay!\n");
|
||||||
@@ -576,11 +581,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
digitalWrite(VTFT_CTRL, LOW);
|
digitalWrite(VTFT_CTRL, LOW);
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNPHONE
|
#ifdef UNPHONE
|
||||||
Wire.beginTransmission(0x26);
|
unphone.backlight(true); // using unPhone library
|
||||||
Wire.write(0x02);
|
|
||||||
Wire.write(0x04); // Backlight on
|
|
||||||
Wire.write(0x22); // G&B LEDs off
|
|
||||||
Wire.endTransmission();
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
@@ -612,11 +613,7 @@ void TFTDisplay::sendCommand(uint8_t com)
|
|||||||
digitalWrite(VTFT_CTRL, HIGH);
|
digitalWrite(VTFT_CTRL, HIGH);
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNPHONE
|
#ifdef UNPHONE
|
||||||
Wire.beginTransmission(0x26);
|
unphone.backlight(false); // using unPhone library
|
||||||
Wire.write(0x02);
|
|
||||||
Wire.write(0x00); // Backlight off
|
|
||||||
Wire.write(0x22); // G&B LEDs off
|
|
||||||
Wire.endTransmission();
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef RAK14014
|
#ifdef RAK14014
|
||||||
#elif !defined(M5STACK)
|
#elif !defined(M5STACK)
|
||||||
@@ -690,11 +687,7 @@ bool TFTDisplay::connect()
|
|||||||
digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
|
digitalWrite(ST7735_BL_V05, TFT_BACKLIGHT_ON);
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNPHONE
|
#ifdef UNPHONE
|
||||||
Wire.beginTransmission(0x26);
|
unphone.backlight(true); // using unPhone library
|
||||||
Wire.write(0x02);
|
|
||||||
Wire.write(0x04); // Backlight on
|
|
||||||
Wire.write(0x22); // G&B LEDs off
|
|
||||||
Wire.endTransmission();
|
|
||||||
LOG_INFO("Power to TFT Backlight\n");
|
LOG_INFO("Power to TFT Backlight\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
188
src/graphics/mesh_bus_spi.cpp
Normal file
188
src/graphics/mesh_bus_spi.cpp
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
// This code has been copied from LovyanGFX to make the SPI device selectable for touchscreens.
|
||||||
|
// Ideally this could eventually be an inherited class from BUS_SPI,
|
||||||
|
// but currently too many internal objects are set private.
|
||||||
|
|
||||||
|
#include "configuration.h"
|
||||||
|
#if ARCH_PORTDUINO
|
||||||
|
#include "lgfx/v1/misc/pixelcopy.hpp"
|
||||||
|
#include "main.h"
|
||||||
|
#include "mesh_bus_spi.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
namespace lgfx
|
||||||
|
{
|
||||||
|
inline namespace v1
|
||||||
|
{
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::config(const config_t &config)
|
||||||
|
{
|
||||||
|
_cfg = config;
|
||||||
|
|
||||||
|
if (_cfg.pin_dc >= 0) {
|
||||||
|
pinMode(_cfg.pin_dc, pin_mode_t::output);
|
||||||
|
gpio_hi(_cfg.pin_dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh_Bus_SPI::init(void)
|
||||||
|
{
|
||||||
|
dc_h();
|
||||||
|
pinMode(_cfg.pin_dc, pin_mode_t::output);
|
||||||
|
if (SPIName != "")
|
||||||
|
PrivateSPI->begin(SPIName.c_str());
|
||||||
|
else
|
||||||
|
PrivateSPI->begin();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::release(void)
|
||||||
|
{
|
||||||
|
PrivateSPI->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::spi_device(HardwareSPI *newSPI, std::string newSPIName)
|
||||||
|
{
|
||||||
|
PrivateSPI = newSPI;
|
||||||
|
SPIName = newSPIName;
|
||||||
|
}
|
||||||
|
void Mesh_Bus_SPI::beginTransaction(void)
|
||||||
|
{
|
||||||
|
dc_h();
|
||||||
|
SPISettings setting(_cfg.freq_write, MSBFIRST, _cfg.spi_mode);
|
||||||
|
PrivateSPI->beginTransaction(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::endTransaction(void)
|
||||||
|
{
|
||||||
|
PrivateSPI->endTransaction();
|
||||||
|
dc_h();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::beginRead(void)
|
||||||
|
{
|
||||||
|
PrivateSPI->endTransaction();
|
||||||
|
// SPISettings setting(_cfg.freq_read, BitOrder::MSBFIRST, _cfg.spi_mode, false);
|
||||||
|
SPISettings setting(_cfg.freq_read, MSBFIRST, _cfg.spi_mode);
|
||||||
|
PrivateSPI->beginTransaction(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::endRead(void)
|
||||||
|
{
|
||||||
|
PrivateSPI->endTransaction();
|
||||||
|
beginTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::wait(void) {}
|
||||||
|
|
||||||
|
bool Mesh_Bus_SPI::busy(void) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh_Bus_SPI::writeCommand(uint32_t data, uint_fast8_t bit_length)
|
||||||
|
{
|
||||||
|
dc_l();
|
||||||
|
PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3);
|
||||||
|
dc_h();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::writeData(uint32_t data, uint_fast8_t bit_length)
|
||||||
|
{
|
||||||
|
PrivateSPI->transfer((uint8_t *)&data, bit_length >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t length)
|
||||||
|
{
|
||||||
|
const uint8_t dst_bytes = bit_length >> 3;
|
||||||
|
uint32_t limit = (dst_bytes == 3) ? 12 : 16;
|
||||||
|
auto buf = _flip_buffer.getBuffer(512);
|
||||||
|
size_t fillpos = 0;
|
||||||
|
reinterpret_cast<uint32_t *>(buf)[0] = data;
|
||||||
|
fillpos += dst_bytes;
|
||||||
|
uint32_t len;
|
||||||
|
do {
|
||||||
|
len = ((length - 1) % limit) + 1;
|
||||||
|
if (limit <= 64)
|
||||||
|
limit <<= 1;
|
||||||
|
|
||||||
|
while (fillpos < len * dst_bytes) {
|
||||||
|
memcpy(&buf[fillpos], buf, fillpos);
|
||||||
|
fillpos += fillpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrivateSPI->transfer(buf, len * dst_bytes);
|
||||||
|
} while (length -= len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::writePixels(pixelcopy_t *param, uint32_t length)
|
||||||
|
{
|
||||||
|
const uint8_t dst_bytes = param->dst_bits >> 3;
|
||||||
|
uint32_t limit = (dst_bytes == 3) ? 12 : 16;
|
||||||
|
uint32_t len;
|
||||||
|
do {
|
||||||
|
len = ((length - 1) % limit) + 1;
|
||||||
|
if (limit <= 32)
|
||||||
|
limit <<= 1;
|
||||||
|
auto buf = _flip_buffer.getBuffer(len * dst_bytes);
|
||||||
|
param->fp_copy(buf, 0, len, param);
|
||||||
|
PrivateSPI->transfer(buf, len * dst_bytes);
|
||||||
|
} while (length -= len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma)
|
||||||
|
{
|
||||||
|
if (dc)
|
||||||
|
dc_h();
|
||||||
|
else
|
||||||
|
dc_l();
|
||||||
|
PrivateSPI->transfer(const_cast<uint8_t *>(data), length);
|
||||||
|
if (!dc)
|
||||||
|
dc_h();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Mesh_Bus_SPI::readData(uint_fast8_t bit_length)
|
||||||
|
{
|
||||||
|
uint32_t res = 0;
|
||||||
|
bit_length >>= 3;
|
||||||
|
if (!bit_length)
|
||||||
|
return res;
|
||||||
|
int idx = 0;
|
||||||
|
do {
|
||||||
|
res |= PrivateSPI->transfer(0) << idx;
|
||||||
|
idx += 8;
|
||||||
|
} while (--bit_length);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mesh_Bus_SPI::readBytes(uint8_t *dst, uint32_t length, bool use_dma)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
dst[0] = PrivateSPI->transfer(0);
|
||||||
|
++dst;
|
||||||
|
} while (--length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh_Bus_SPI::readPixels(void *dst, pixelcopy_t *param, uint32_t length)
|
||||||
|
{
|
||||||
|
uint32_t bytes = param->src_bits >> 3;
|
||||||
|
uint32_t dstindex = 0;
|
||||||
|
uint32_t len = 4;
|
||||||
|
uint8_t buf[24];
|
||||||
|
param->src_data = buf;
|
||||||
|
do {
|
||||||
|
if (len > length)
|
||||||
|
len = length;
|
||||||
|
readBytes((uint8_t *)buf, len * bytes, true);
|
||||||
|
param->src_x = 0;
|
||||||
|
dstindex = param->fp_copy(dst, dstindex, dstindex + len, param);
|
||||||
|
length -= len;
|
||||||
|
} while (length);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace v1
|
||||||
|
} // namespace lgfx
|
||||||
|
#endif
|
||||||
100
src/graphics/mesh_bus_spi.h
Normal file
100
src/graphics/mesh_bus_spi.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#if ARCH_PORTDUINO
|
||||||
|
/*----------------------------------------------------------------------------/
|
||||||
|
Lovyan GFX - Graphics library for embedded devices.
|
||||||
|
|
||||||
|
Original Source:
|
||||||
|
https://github.com/lovyan03/LovyanGFX/
|
||||||
|
|
||||||
|
Licence:
|
||||||
|
[FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt)
|
||||||
|
|
||||||
|
Author:
|
||||||
|
[lovyan03](https://twitter.com/lovyan03)
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
[ciniml](https://github.com/ciniml)
|
||||||
|
[mongonta0716](https://github.com/mongonta0716)
|
||||||
|
[tobozo](https://github.com/tobozo)
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "lgfx/v1/Bus.hpp"
|
||||||
|
#include "lgfx/v1/platforms/common.hpp"
|
||||||
|
|
||||||
|
namespace lgfx
|
||||||
|
{
|
||||||
|
inline namespace v1
|
||||||
|
{
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class Mesh_Bus_SPI : public IBus
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct config_t {
|
||||||
|
uint32_t freq_write = 16000000;
|
||||||
|
uint32_t freq_read = 8000000;
|
||||||
|
// bool spi_3wire = true;
|
||||||
|
// bool use_lock = true;
|
||||||
|
int16_t pin_sclk = -1;
|
||||||
|
int16_t pin_miso = -1;
|
||||||
|
int16_t pin_mosi = -1;
|
||||||
|
int16_t pin_dc = -1;
|
||||||
|
uint8_t spi_mode = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const config_t &config(void) const { return _cfg; }
|
||||||
|
|
||||||
|
void config(const config_t &config);
|
||||||
|
|
||||||
|
bus_type_t busType(void) const override { return bus_type_t::bus_spi; }
|
||||||
|
|
||||||
|
bool init(void) override;
|
||||||
|
void release(void) override;
|
||||||
|
void spi_device(HardwareSPI *newSPI, std::string newSPIName);
|
||||||
|
|
||||||
|
void beginTransaction(void) override;
|
||||||
|
void endTransaction(void) override;
|
||||||
|
void wait(void) override;
|
||||||
|
bool busy(void) const override;
|
||||||
|
|
||||||
|
bool writeCommand(uint32_t data, uint_fast8_t bit_length) override;
|
||||||
|
void writeData(uint32_t data, uint_fast8_t bit_length) override;
|
||||||
|
void writeDataRepeat(uint32_t data, uint_fast8_t bit_length, uint32_t count) override;
|
||||||
|
void writePixels(pixelcopy_t *param, uint32_t length) override;
|
||||||
|
void writeBytes(const uint8_t *data, uint32_t length, bool dc, bool use_dma) override;
|
||||||
|
|
||||||
|
void initDMA(void) {}
|
||||||
|
void flush(void) {}
|
||||||
|
void addDMAQueue(const uint8_t *data, uint32_t length) override { writeBytes(data, length, true, true); }
|
||||||
|
void execDMAQueue(void) {}
|
||||||
|
uint8_t *getDMABuffer(uint32_t length) override { return _flip_buffer.getBuffer(length); }
|
||||||
|
|
||||||
|
void beginRead(void) override;
|
||||||
|
void endRead(void) override;
|
||||||
|
uint32_t readData(uint_fast8_t bit_length) override;
|
||||||
|
bool readBytes(uint8_t *dst, uint32_t length, bool use_dma) override;
|
||||||
|
void readPixels(void *dst, pixelcopy_t *param, uint32_t length) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HardwareSPI *PrivateSPI;
|
||||||
|
std::string SPIName;
|
||||||
|
__attribute__((always_inline)) inline void dc_h(void) { gpio_hi(_cfg.pin_dc); }
|
||||||
|
__attribute__((always_inline)) inline void dc_l(void) { gpio_lo(_cfg.pin_dc); }
|
||||||
|
|
||||||
|
config_t _cfg;
|
||||||
|
FlipBuffer _flip_buffer;
|
||||||
|
bool _need_wait;
|
||||||
|
uint32_t _mask_reg_dc;
|
||||||
|
uint32_t _last_apb_freq = -1;
|
||||||
|
uint32_t _clkdiv_write;
|
||||||
|
uint32_t _clkdiv_read;
|
||||||
|
volatile uint32_t *_gpio_reg_dc_h;
|
||||||
|
volatile uint32_t *_gpio_reg_dc_l;
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
} // namespace v1
|
||||||
|
} // namespace lgfx
|
||||||
|
#endif
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "modules/ExternalNotificationModule.h"
|
#include "modules/ExternalNotificationModule.h"
|
||||||
|
|
||||||
#ifdef ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
#include "platform/portduino/PortduinoGlue.h"
|
#include "platform/portduino/PortduinoGlue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
28
src/main.cpp
28
src/main.cpp
@@ -590,20 +590,6 @@ void setup()
|
|||||||
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
|
if (config.display.oled != meshtastic_Config_DisplayConfig_OledType_OLED_AUTO)
|
||||||
screen_model = config.display.oled;
|
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)
|
#if defined(USE_SH1107)
|
||||||
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
|
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // set dimension of 128x128
|
||||||
display_geometry = GEOMETRY_128_128;
|
display_geometry = GEOMETRY_128_128;
|
||||||
@@ -644,14 +630,12 @@ void setup()
|
|||||||
pinMode(LORA_CS, OUTPUT);
|
pinMode(LORA_CS, OUTPUT);
|
||||||
digitalWrite(LORA_CS, HIGH);
|
digitalWrite(LORA_CS, HIGH);
|
||||||
SPI1.begin(false);
|
SPI1.begin(false);
|
||||||
#else // HW_SPI1_DEVICE
|
#else // HW_SPI1_DEVICE
|
||||||
SPI.setSCK(LORA_SCK);
|
SPI.setSCK(LORA_SCK);
|
||||||
SPI.setTX(LORA_MOSI);
|
SPI.setTX(LORA_MOSI);
|
||||||
SPI.setRX(LORA_MISO);
|
SPI.setRX(LORA_MISO);
|
||||||
SPI.begin(false);
|
SPI.begin(false);
|
||||||
#endif // HW_SPI1_DEVICE
|
#endif // HW_SPI1_DEVICE
|
||||||
#elif ARCH_PORTDUINO
|
|
||||||
SPI.begin(settingsStrings[spidev].c_str());
|
|
||||||
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
#elif !defined(ARCH_ESP32) // ARCH_RP2040
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
#else
|
#else
|
||||||
@@ -738,7 +722,7 @@ void setup()
|
|||||||
if (settingsMap[use_sx1262]) {
|
if (settingsMap[use_sx1262]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
|
||||||
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@@ -752,7 +736,7 @@ void setup()
|
|||||||
} else if (settingsMap[use_rf95]) {
|
} else if (settingsMap[use_rf95]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
|
||||||
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@@ -767,7 +751,7 @@ void setup()
|
|||||||
} else if (settingsMap[use_sx1280]) {
|
} else if (settingsMap[use_sx1280]) {
|
||||||
if (!rIf) {
|
if (!rIf) {
|
||||||
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s\n", settingsStrings[spidev].c_str());
|
||||||
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
|
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
|
||||||
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
|
||||||
settingsMap[busy]);
|
settingsMap[busy]);
|
||||||
if (!rIf->init()) {
|
if (!rIf->init()) {
|
||||||
@@ -1017,4 +1001,4 @@ void loop()
|
|||||||
mainDelay.delay(delayMsec);
|
mainDelay.delay(delayMsec);
|
||||||
}
|
}
|
||||||
// if (didWake) LOG_DEBUG("wake!\n");
|
// if (didWake) LOG_DEBUG("wake!\n");
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,11 @@ extern NimbleBluetooth *nimbleBluetooth;
|
|||||||
extern NRF52Bluetooth *nrf52Bluetooth;
|
extern NRF52Bluetooth *nrf52Bluetooth;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ARCH_PORTDUINO
|
||||||
|
extern HardwareSPI *DisplaySPI;
|
||||||
|
extern HardwareSPI *LoraSPI;
|
||||||
|
|
||||||
|
#endif
|
||||||
extern ScanI2C::DeviceAddress screen_found;
|
extern ScanI2C::DeviceAddress screen_found;
|
||||||
extern ScanI2C::DeviceAddress cardkb_found;
|
extern ScanI2C::DeviceAddress cardkb_found;
|
||||||
extern uint8_t kb_model;
|
extern uint8_t kb_model;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <NodeDB.h>
|
#include <NodeDB.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#define ONE_DAY 24 * 60 * 60
|
#define ONE_DAY 24 * 60 * 60
|
||||||
|
#define ONE_MINUTE_MS 60 * 1000
|
||||||
|
|
||||||
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
|
||||||
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
|
||||||
@@ -27,4 +28,4 @@ class Default
|
|||||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval);
|
||||||
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval);
|
||||||
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue);
|
||||||
};
|
};
|
||||||
@@ -12,7 +12,7 @@ const meshtastic_MeshPacket *MeshModule::currentRequest;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
|
* If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow
|
||||||
* the RoutingPlugin to avoid sending redundant acks
|
* the RoutingModule to avoid sending redundant acks
|
||||||
*/
|
*/
|
||||||
meshtastic_MeshPacket *MeshModule::currentReply;
|
meshtastic_MeshPacket *MeshModule::currentReply;
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
|||||||
c.error_reason = err;
|
c.error_reason = err;
|
||||||
c.which_variant = meshtastic_Routing_error_reason_tag;
|
c.which_variant = meshtastic_Routing_error_reason_tag;
|
||||||
|
|
||||||
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingPlugin
|
// Now that we have moded sendAckNak up one level into the class hierarchy we can no longer assume we are a RoutingModule
|
||||||
// So we manually call pb_encode_to_bytes and specify routing port number
|
// So we manually call pb_encode_to_bytes and specify routing port number
|
||||||
// auto p = allocDataProtobuf(c);
|
// auto p = allocDataProtobuf(c);
|
||||||
meshtastic_MeshPacket *p = router->allocForSending();
|
meshtastic_MeshPacket *p = router->allocForSending();
|
||||||
@@ -54,7 +54,8 @@ meshtastic_MeshPacket *MeshModule::allocAckNak(meshtastic_Routing_Error err, Nod
|
|||||||
p->to = to;
|
p->to = to;
|
||||||
p->decoded.request_id = idFrom;
|
p->decoded.request_id = idFrom;
|
||||||
p->channel = chIndex;
|
p->channel = chIndex;
|
||||||
LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
if (err != meshtastic_Routing_Error_NONE)
|
||||||
|
LOG_ERROR("Alloc an err=%d,to=0x%x,idFrom=0x%x,id=0x%x\n", err, to, idFrom, p->id);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -68,7 +69,7 @@ meshtastic_MeshPacket *MeshModule::allocErrorResponse(meshtastic_Routing_Error e
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshModule::callPlugins(meshtastic_MeshPacket &mp, RxSource src)
|
void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
|
||||||
{
|
{
|
||||||
// LOG_DEBUG("In call modules\n");
|
// LOG_DEBUG("In call modules\n");
|
||||||
bool moduleFound = false;
|
bool moduleFound = false;
|
||||||
@@ -258,7 +259,7 @@ void MeshModule::observeUIEvents(Observer<const UIFrameEvent *> *observer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AdminMessageHandleResult MeshModule::handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
|
AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp,
|
||||||
meshtastic_AdminMessage *request,
|
meshtastic_AdminMessage *request,
|
||||||
meshtastic_AdminMessage *response)
|
meshtastic_AdminMessage *response)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,11 +64,11 @@ class MeshModule
|
|||||||
|
|
||||||
/** For use only by MeshService
|
/** For use only by MeshService
|
||||||
*/
|
*/
|
||||||
static void callPlugins(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
static void callModules(meshtastic_MeshPacket &mp, RxSource src = RX_SRC_RADIO);
|
||||||
|
|
||||||
static std::vector<MeshModule *> GetMeshModulesWithUIFrames();
|
static std::vector<MeshModule *> GetMeshModulesWithUIFrames();
|
||||||
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
|
static void observeUIEvents(Observer<const UIFrameEvent *> *observer);
|
||||||
static AdminMessageHandleResult handleAdminMessageForAllPlugins(const meshtastic_MeshPacket &mp,
|
static AdminMessageHandleResult handleAdminMessageForAllModules(const meshtastic_MeshPacket &mp,
|
||||||
meshtastic_AdminMessage *request,
|
meshtastic_AdminMessage *request,
|
||||||
meshtastic_AdminMessage *response);
|
meshtastic_AdminMessage *response);
|
||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
@@ -195,4 +195,4 @@ class MeshModule
|
|||||||
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||||
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||||
*/
|
*/
|
||||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||||
@@ -527,8 +527,8 @@ void NodeDB::installDefaultDeviceState()
|
|||||||
void NodeDB::pickNewNodeNum()
|
void NodeDB::pickNewNodeNum()
|
||||||
{
|
{
|
||||||
NodeNum nodeNum = myNodeInfo.my_node_num;
|
NodeNum nodeNum = myNodeInfo.my_node_num;
|
||||||
|
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
||||||
if (nodeNum == 0) {
|
if (nodeNum == 0) {
|
||||||
getMacAddr(ourMacAddr); // Make sure ourMacAddr is set
|
|
||||||
// Pick an initial nodenum based on the macaddr
|
// Pick an initial nodenum based on the macaddr
|
||||||
nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
nodeNum = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||||
}
|
}
|
||||||
@@ -813,6 +813,7 @@ size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#include "MeshModule.h"
|
#include "MeshModule.h"
|
||||||
|
#include "Throttle.h"
|
||||||
|
|
||||||
/** Update position info for this node based on received position data
|
/** Update position info for this node based on received position data
|
||||||
*/
|
*/
|
||||||
@@ -907,8 +908,10 @@ bool NodeDB::updateUser(uint32_t nodeId, const meshtastic_User &p, uint8_t chann
|
|||||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||||
|
|
||||||
// We just changed something important about the user, store our DB
|
// We just changed something about the user, store our DB
|
||||||
saveToDisk(SEGMENT_DEVICESTATE);
|
Throttle::execute(
|
||||||
|
&lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); },
|
||||||
|
[]() { LOG_DEBUG("Deferring NodeDB saveToDisk for now, since we saved less than a minute ago\n"); });
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ class NodeDB
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint32_t lastNodeDbSave = 0; // when we last saved our db to flash
|
||||||
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
/// Find a node in our DB, create an empty NodeInfoLite if missing
|
||||||
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
|
||||||
|
|
||||||
@@ -229,4 +230,4 @@ extern uint32_t error_address;
|
|||||||
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
|
ModuleConfig_RangeTestConfig_size + ModuleConfig_SerialConfig_size + ModuleConfig_StoreForwardConfig_size + \
|
||||||
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
ModuleConfig_TelemetryConfig_size + ModuleConfig_size)
|
||||||
|
|
||||||
// Please do not remove this comment, it makes trunk and compiler happy at the same time.
|
// Please do not remove this comment, it makes trunk and compiler happy at the same time.
|
||||||
@@ -215,7 +215,7 @@ bool RF95Interface::isChannelActive()
|
|||||||
// LOG_DEBUG("Channel is busy!\n");
|
// LOG_DEBUG("Channel is busy!\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (result != RADIOLIB_ERR_WRONG_MODEM)
|
if (result != RADIOLIB_CHANNEL_FREE)
|
||||||
LOG_ERROR("Radiolib error %d when attempting RF95 isChannelActive!\n", result);
|
LOG_ERROR("Radiolib error %d when attempting RF95 isChannelActive!\n", result);
|
||||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||||
|
|
||||||
|
|||||||
@@ -151,10 +151,16 @@ static uint8_t bytes[MAX_RHPACKETLEN];
|
|||||||
void initRegion()
|
void initRegion()
|
||||||
{
|
{
|
||||||
const RegionInfo *r = regions;
|
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++)
|
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);
|
LOG_INFO("Wanted region %d, using %s\n", config.lora.region, r->name);
|
||||||
|
#endif
|
||||||
|
myRegion = r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -465,21 +465,22 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
|
|||||||
cancelSending(p->from, p->id);
|
cancelSending(p->from, p->id);
|
||||||
skipHandle = true;
|
skipHandle = true;
|
||||||
}
|
}
|
||||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
|
||||||
// Publish received message to MQTT if we're not the original transmitter of the packet
|
|
||||||
if (!skipHandle && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
|
|
||||||
mqtt->onSend(*p_encrypted, *p, p->channel);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
printPacket("packet decoding failed or skipped (no PSK?)", p);
|
printPacket("packet decoding failed or skipped (no PSK?)", p);
|
||||||
}
|
}
|
||||||
|
|
||||||
packetPool.release(p_encrypted); // Release the encrypted packet
|
|
||||||
|
|
||||||
// call modules here
|
// call modules here
|
||||||
if (!skipHandle)
|
if (!skipHandle) {
|
||||||
MeshModule::callPlugins(*p, src);
|
MeshModule::callModules(*p, src);
|
||||||
|
|
||||||
|
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||||
|
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
|
||||||
|
if (decoded && moduleConfig.mqtt.enabled && getFrom(p) != nodeDB->getNodeNum() && mqtt)
|
||||||
|
mqtt->onSend(*p_encrypted, *p, p->channel);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
packetPool.release(p_encrypted); // Release the encrypted packet
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
||||||
@@ -499,4 +500,4 @@ void Router::perhapsHandleReceived(meshtastic_MeshPacket *p)
|
|||||||
handleReceived(p);
|
handleReceived(p);
|
||||||
|
|
||||||
packetPool.release(p);
|
packetPool.release(p);
|
||||||
}
|
}
|
||||||
@@ -280,7 +280,7 @@ template <typename T> bool SX128xInterface<T>::isChannelActive()
|
|||||||
result = lora.scanChannel();
|
result = lora.scanChannel();
|
||||||
if (result == RADIOLIB_LORA_DETECTED)
|
if (result == RADIOLIB_LORA_DETECTED)
|
||||||
return true;
|
return true;
|
||||||
if (result != RADIOLIB_ERR_WRONG_MODEM)
|
if (result != RADIOLIB_CHANNEL_FREE)
|
||||||
LOG_ERROR("Radiolib error %d when attempting SX128X scanChannel!\n", result);
|
LOG_ERROR("Radiolib error %d when attempting SX128X scanChannel!\n", result);
|
||||||
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
assert(result != RADIOLIB_ERR_WRONG_MODEM);
|
||||||
|
|
||||||
|
|||||||
27
src/mesh/Throttle.cpp
Normal file
27
src/mesh/Throttle.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "Throttle.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/// @brief Execute a function throttled to a minimum interval
|
||||||
|
/// @param lastExecutionMs Pointer to the last execution time in milliseconds
|
||||||
|
/// @param minumumIntervalMs Minimum execution interval in milliseconds
|
||||||
|
/// @param throttleFunc Function to execute if the execution is not deferred
|
||||||
|
/// @param onDefer Default to NULL, execute the function if the execution is deferred
|
||||||
|
/// @return true if the function was executed, false if it was deferred
|
||||||
|
bool Throttle::execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, void (*throttleFunc)(void), void (*onDefer)(void))
|
||||||
|
{
|
||||||
|
if (*lastExecutionMs == 0) {
|
||||||
|
*lastExecutionMs = millis();
|
||||||
|
throttleFunc();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint32_t now = millis();
|
||||||
|
|
||||||
|
if ((now - *lastExecutionMs) >= minumumIntervalMs) {
|
||||||
|
throttleFunc();
|
||||||
|
*lastExecutionMs = now;
|
||||||
|
return true;
|
||||||
|
} else if (onDefer != NULL) {
|
||||||
|
onDefer();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
9
src/mesh/Throttle.h
Normal file
9
src/mesh/Throttle.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class Throttle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool execute(uint32_t *lastExecutionMs, uint32_t minumumIntervalMs, void (*func)(void), void (*onDefer)(void) = NULL);
|
||||||
|
};
|
||||||
@@ -324,35 +324,30 @@ typedef struct _meshtastic_Config_PositionConfig {
|
|||||||
/* Power Config\
|
/* Power Config\
|
||||||
See [Power Config](/docs/settings/config/power) for additional power config details. */
|
See [Power Config](/docs/settings/config/power) for additional power config details. */
|
||||||
typedef struct _meshtastic_Config_PowerConfig {
|
typedef struct _meshtastic_Config_PowerConfig {
|
||||||
/* If set, we are powered from a low-current source (i.e. solar), so even if it looks like we have power flowing in
|
/* Description: Will sleep everything as much as possible, for the tracker and sensor role this will also include the lora radio.
|
||||||
we should try to minimize power consumption as much as possible.
|
Don't use this setting if you want to use your device with the phone apps or are using a device without a user button.
|
||||||
YOU DO NOT NEED TO SET THIS IF YOU'VE set is_router (it is implied in that case).
|
Technical Details: Works for ESP32 devices and NRF52 devices in the Sensor or Tracker roles */
|
||||||
Advanced Option */
|
|
||||||
bool is_power_saving;
|
bool is_power_saving;
|
||||||
/* If non-zero, the device will fully power off this many seconds after external power is removed. */
|
/* Description: If non-zero, the device will fully power off this many seconds after external power is removed. */
|
||||||
uint32_t on_battery_shutdown_after_secs;
|
uint32_t on_battery_shutdown_after_secs;
|
||||||
/* Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k)
|
/* Ratio of voltage divider for battery pin eg. 3.20 (R1=100k, R2=220k)
|
||||||
Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation.
|
Overrides the ADC_MULTIPLIER defined in variant for battery voltage calculation.
|
||||||
Should be set to floating point value between 2 and 4
|
https://meshtastic.org/docs/configuration/radio/power/#adc-multiplier-override
|
||||||
Fixes issues on Heltec v2 */
|
Should be set to floating point value between 2 and 6 */
|
||||||
float adc_multiplier_override;
|
float adc_multiplier_override;
|
||||||
/* Wait Bluetooth Seconds
|
/* Description: The number of seconds for to wait before turning off BLE in No Bluetooth states
|
||||||
The number of seconds for to wait before turning off BLE in No Bluetooth states
|
Technical Details: ESP32 Only 0 for default of 1 minute */
|
||||||
0 for default of 1 minute */
|
|
||||||
uint32_t wait_bluetooth_secs;
|
uint32_t wait_bluetooth_secs;
|
||||||
/* Super Deep Sleep Seconds
|
/* Super Deep Sleep Seconds
|
||||||
While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep
|
While in Light Sleep if mesh_sds_timeout_secs is exceeded we will lower into super deep sleep
|
||||||
for this value (default 1 year) or a button press
|
for this value (default 1 year) or a button press
|
||||||
0 for default of one year */
|
0 for default of one year */
|
||||||
uint32_t sds_secs;
|
uint32_t sds_secs;
|
||||||
/* Light Sleep Seconds
|
/* Description: In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on
|
||||||
In light sleep the CPU is suspended, LoRa radio is on, BLE is off an GPS is on
|
Technical Details: ESP32 Only 0 for default of 300 */
|
||||||
ESP32 Only
|
|
||||||
0 for default of 300 */
|
|
||||||
uint32_t ls_secs;
|
uint32_t ls_secs;
|
||||||
/* Minimum Wake Seconds
|
/* Description: While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value
|
||||||
While in light sleep when we receive packets on the LoRa radio we will wake and handle them and stay awake in no BLE mode for this value
|
Technical Details: ESP32 Only 0 for default of 10 seconds */
|
||||||
0 for default of 10 seconds */
|
|
||||||
uint32_t min_wake_secs;
|
uint32_t min_wake_secs;
|
||||||
/* I2C address of INA_2XX to use for reading device battery voltage */
|
/* I2C address of INA_2XX to use for reading device battery voltage */
|
||||||
uint8_t device_battery_ina_address;
|
uint8_t device_battery_ina_address;
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ typedef enum _meshtastic_HardwareModel {
|
|||||||
/* Teledatics TD-LORAC NRF52840 based M.2 LoRA module
|
/* Teledatics TD-LORAC NRF52840 based M.2 LoRA module
|
||||||
Compatible with the TD-WRLS development board */
|
Compatible with the TD-WRLS development board */
|
||||||
meshtastic_HardwareModel_TD_LORAC = 60,
|
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.
|
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.
|
||||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
meshtastic_AdminMessage res = meshtastic_AdminMessage_init_default;
|
meshtastic_AdminMessage res = meshtastic_AdminMessage_init_default;
|
||||||
AdminMessageHandleResult handleResult = MeshModule::handleAdminMessageForAllPlugins(mp, r, &res);
|
AdminMessageHandleResult handleResult = MeshModule::handleAdminMessageForAllModules(mp, r, &res);
|
||||||
|
|
||||||
if (handleResult == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
|
if (handleResult == AdminMessageHandleResult::HANDLED_WITH_RESPONSE) {
|
||||||
myReply = allocDataProtobuf(res);
|
myReply = allocDataProtobuf(res);
|
||||||
|
|||||||
@@ -4,11 +4,8 @@
|
|||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
|
|
||||||
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
|
||||||
NeighborInfoModule *neighborInfoModule;
|
NeighborInfoModule *neighborInfoModule;
|
||||||
|
|
||||||
static const char *neighborInfoConfigFile = "/prefs/neighbors.proto";
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Prints a single neighbor info packet and associated neighbors
|
Prints a single neighbor info packet and associated neighbors
|
||||||
Uses LOG_DEBUG, which equates to Console.log
|
Uses LOG_DEBUG, which equates to Console.log
|
||||||
@@ -30,26 +27,23 @@ NOTE: for debugging only
|
|||||||
*/
|
*/
|
||||||
void NeighborInfoModule::printNodeDBNeighbors()
|
void NeighborInfoModule::printNodeDBNeighbors()
|
||||||
{
|
{
|
||||||
int num_neighbors = getNumNeighbors();
|
LOG_DEBUG("Our NodeDB contains %d neighbors\n", neighbors.size());
|
||||||
LOG_DEBUG("Our NodeDB contains %d neighbors\n", num_neighbors);
|
for (size_t i = 0; i < neighbors.size(); i++) {
|
||||||
for (int i = 0; i < num_neighbors; i++) {
|
LOG_DEBUG("Node %d: node_id=0x%x, snr=%.2f\n", i, neighbors[i].node_id, neighbors[i].snr);
|
||||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
|
||||||
LOG_DEBUG(" Node %d: node_id=0x%x, snr=%.2f\n", i, dbEntry->node_id, dbEntry->snr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
/* Send our initial owner announcement 35 seconds after we start (to give network time to setup) */
|
||||||
NeighborInfoModule::NeighborInfoModule()
|
NeighborInfoModule::NeighborInfoModule()
|
||||||
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
: ProtobufModule("neighborinfo", meshtastic_PortNum_NEIGHBORINFO_APP, &meshtastic_NeighborInfo_msg),
|
||||||
concurrency::OSThread("NeighborInfoModule"), neighbors(neighborState.neighbors),
|
concurrency::OSThread("NeighborInfoModule")
|
||||||
numNeighbors(&neighborState.neighbors_count)
|
|
||||||
{
|
{
|
||||||
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
|
ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP;
|
||||||
|
|
||||||
if (moduleConfig.neighbor_info.enabled) {
|
if (moduleConfig.neighbor_info.enabled) {
|
||||||
isPromiscuous = true; // Update neighbors from all packets
|
isPromiscuous = true; // Update neighbors from all packets
|
||||||
this->loadProtoForModule();
|
setIntervalFromNow(
|
||||||
setIntervalFromNow(35 * 1000);
|
Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs));
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG("NeighborInfoModule is disabled\n");
|
LOG_DEBUG("NeighborInfoModule is disabled\n");
|
||||||
disable();
|
disable();
|
||||||
@@ -63,18 +57,17 @@ Assumes that the neighborInfo packet has been allocated
|
|||||||
*/
|
*/
|
||||||
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo)
|
||||||
{
|
{
|
||||||
uint my_node_id = nodeDB->getNodeNum();
|
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||||
neighborInfo->node_id = my_node_id;
|
neighborInfo->node_id = my_node_id;
|
||||||
neighborInfo->last_sent_by_id = my_node_id;
|
neighborInfo->last_sent_by_id = my_node_id;
|
||||||
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
neighborInfo->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||||
|
|
||||||
int num_neighbors = cleanUpNeighbors();
|
cleanUpNeighbors();
|
||||||
|
|
||||||
for (int i = 0; i < num_neighbors; i++) {
|
for (auto nbr : neighbors) {
|
||||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (nbr.node_id != my_node_id)) {
|
||||||
if ((neighborInfo->neighbors_count < MAX_NUM_NEIGHBORS) && (dbEntry->node_id != my_node_id)) {
|
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = nbr.node_id;
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].node_id = dbEntry->node_id;
|
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = nbr.snr;
|
||||||
neighborInfo->neighbors[neighborInfo->neighbors_count].snr = dbEntry->snr;
|
|
||||||
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
// Note: we don't set the last_rx_time and node_broadcast_intervals_secs here, because we don't want to send this over
|
||||||
// the mesh
|
// the mesh
|
||||||
neighborInfo->neighbors_count++;
|
neighborInfo->neighbors_count++;
|
||||||
@@ -85,41 +78,22 @@ uint32_t NeighborInfoModule::collectNeighborInfo(meshtastic_NeighborInfo *neighb
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Remove neighbors from the database that we haven't heard from in a while
|
Remove neighbors from the database that we haven't heard from in a while
|
||||||
@returns new number of neighbors
|
|
||||||
*/
|
*/
|
||||||
size_t NeighborInfoModule::cleanUpNeighbors()
|
void NeighborInfoModule::cleanUpNeighbors()
|
||||||
{
|
{
|
||||||
uint32_t now = getTime();
|
uint32_t now = getTime();
|
||||||
int num_neighbors = getNumNeighbors();
|
|
||||||
NodeNum my_node_id = nodeDB->getNodeNum();
|
NodeNum my_node_id = nodeDB->getNodeNum();
|
||||||
|
for (auto it = neighbors.rbegin(); it != neighbors.rend();) {
|
||||||
// Find neighbors to remove
|
|
||||||
std::vector<int> indices_to_remove;
|
|
||||||
for (int i = 0; i < num_neighbors; i++) {
|
|
||||||
const meshtastic_Neighbor *dbEntry = getNeighborByIndex(i);
|
|
||||||
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
// We will remove a neighbor if we haven't heard from them in twice the broadcast interval
|
||||||
if ((now - dbEntry->last_rx_time > dbEntry->node_broadcast_interval_secs * 2) && (dbEntry->node_id != my_node_id)) {
|
if ((now - it->last_rx_time > it->node_broadcast_interval_secs * 2) && (it->node_id != my_node_id)) {
|
||||||
indices_to_remove.push_back(i);
|
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", it->node_id);
|
||||||
|
it = std::vector<meshtastic_Neighbor>::reverse_iterator(
|
||||||
|
neighbors.erase(std::next(it).base())); // Erase the element and update the iterator
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the neighbor list
|
|
||||||
for (uint i = 0; i < indices_to_remove.size(); i++) {
|
|
||||||
int index = indices_to_remove[i];
|
|
||||||
LOG_DEBUG("Removing neighbor with node ID 0x%x\n", neighbors[index].node_id);
|
|
||||||
for (int j = index; j < num_neighbors - 1; j++) {
|
|
||||||
neighbors[j] = neighbors[j + 1];
|
|
||||||
}
|
|
||||||
(*numNeighbors)--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the neighbor list if we removed any neighbors or neighbors were already updated upon receiving a packet
|
|
||||||
if (indices_to_remove.size() > 0 || shouldSave) {
|
|
||||||
saveProtoForModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
return *numNeighbors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send neighbor info to the mesh */
|
/* Send neighbor info to the mesh */
|
||||||
@@ -143,7 +117,9 @@ Will be used for broadcast.
|
|||||||
int32_t NeighborInfoModule::runOnce()
|
int32_t NeighborInfoModule::runOnce()
|
||||||
{
|
{
|
||||||
bool requestReplies = false;
|
bool requestReplies = false;
|
||||||
sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
|
if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) {
|
||||||
|
sendNeighborInfo(NODENUM_BROADCAST, requestReplies);
|
||||||
|
}
|
||||||
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
|
return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,10 +154,7 @@ void NeighborInfoModule::alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtas
|
|||||||
|
|
||||||
void NeighborInfoModule::resetNeighbors()
|
void NeighborInfoModule::resetNeighbors()
|
||||||
{
|
{
|
||||||
*numNeighbors = 0;
|
neighbors.clear();
|
||||||
neighborState.neighbors_count = 0;
|
|
||||||
memset(neighborState.neighbors, 0, sizeof(neighborState.neighbors));
|
|
||||||
saveProtoForModule();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
void NeighborInfoModule::updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np)
|
||||||
@@ -201,61 +174,36 @@ meshtastic_Neighbor *NeighborInfoModule::getOrCreateNeighbor(NodeNum originalSen
|
|||||||
n = nodeDB->getNodeNum();
|
n = nodeDB->getNodeNum();
|
||||||
}
|
}
|
||||||
// look for one in the existing list
|
// look for one in the existing list
|
||||||
for (int i = 0; i < (*numNeighbors); i++) {
|
for (size_t i = 0; i < neighbors.size(); i++) {
|
||||||
meshtastic_Neighbor *nbr = &neighbors[i];
|
if (neighbors[i].node_id == n) {
|
||||||
if (nbr->node_id == n) {
|
|
||||||
// if found, update it
|
// if found, update it
|
||||||
nbr->snr = snr;
|
neighbors[i].snr = snr;
|
||||||
nbr->last_rx_time = getTime();
|
neighbors[i].last_rx_time = getTime();
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
neighbors[i].node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
return nbr;
|
return &neighbors[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// otherwise, allocate one and assign data to it
|
// otherwise, allocate one and assign data to it
|
||||||
// TODO: max memory for the database should take neighbors into account, but currently doesn't
|
|
||||||
if (*numNeighbors < MAX_NUM_NEIGHBORS) {
|
meshtastic_Neighbor new_nbr = meshtastic_Neighbor_init_zero;
|
||||||
(*numNeighbors)++;
|
new_nbr.node_id = n;
|
||||||
}
|
new_nbr.snr = snr;
|
||||||
meshtastic_Neighbor *new_nbr = &neighbors[((*numNeighbors) - 1)];
|
new_nbr.last_rx_time = getTime();
|
||||||
new_nbr->node_id = n;
|
|
||||||
new_nbr->snr = snr;
|
|
||||||
new_nbr->last_rx_time = getTime();
|
|
||||||
// Only if this is the original sender, the broadcast interval corresponds to it
|
// Only if this is the original sender, the broadcast interval corresponds to it
|
||||||
if (originalSender == n && node_broadcast_interval_secs != 0)
|
if (originalSender == n && node_broadcast_interval_secs != 0)
|
||||||
new_nbr->node_broadcast_interval_secs = node_broadcast_interval_secs;
|
new_nbr.node_broadcast_interval_secs = node_broadcast_interval_secs;
|
||||||
else // Assume the same broadcast interval as us for the neighbor if we don't know it
|
else // Assume the same broadcast interval as us for the neighbor if we don't know it
|
||||||
new_nbr->node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
new_nbr.node_broadcast_interval_secs = moduleConfig.neighbor_info.update_interval;
|
||||||
shouldSave = true; // Save the new neighbor upon next cleanup
|
|
||||||
return new_nbr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NeighborInfoModule::loadProtoForModule()
|
if (neighbors.size() < MAX_NUM_NEIGHBORS) {
|
||||||
{
|
neighbors.push_back(new_nbr);
|
||||||
if (nodeDB->loadProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, sizeof(meshtastic_NeighborInfo),
|
} else {
|
||||||
&meshtastic_NeighborInfo_msg, &neighborState) != LoadFileResult::SUCCESS) {
|
// If we have too many neighbors, replace the oldest one
|
||||||
neighborState = meshtastic_NeighborInfo_init_zero;
|
LOG_WARN("Neighbor DB is full, replacing oldest neighbor\n");
|
||||||
|
neighbors.erase(neighbors.begin());
|
||||||
|
neighbors.push_back(new_nbr);
|
||||||
}
|
}
|
||||||
}
|
return &neighbors.back();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Save the module config to file.
|
|
||||||
*
|
|
||||||
* @return true On success.
|
|
||||||
* @return false On error.
|
|
||||||
*/
|
|
||||||
bool NeighborInfoModule::saveProtoForModule()
|
|
||||||
{
|
|
||||||
bool okay = true;
|
|
||||||
|
|
||||||
#ifdef FS
|
|
||||||
FS.mkdir("/prefs");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
okay &= nodeDB->saveProto(neighborInfoConfigFile, meshtastic_NeighborInfo_size, &meshtastic_NeighborInfo_msg, &neighborState);
|
|
||||||
if (okay)
|
|
||||||
shouldSave = false;
|
|
||||||
|
|
||||||
return okay;
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
|
#define MAX_NUM_NEIGHBORS 10 // also defined in NeighborInfo protobuf options
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
|
* Neighborinfo module for sending info on each node's 0-hop neighbors to the mesh
|
||||||
*/
|
*/
|
||||||
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
|
class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, private concurrency::OSThread
|
||||||
{
|
{
|
||||||
meshtastic_Neighbor *neighbors;
|
std::vector<meshtastic_Neighbor> neighbors;
|
||||||
pb_size_t *numNeighbors;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
@@ -18,15 +18,7 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
/* Reset neighbor info after clearing nodeDB*/
|
/* Reset neighbor info after clearing nodeDB*/
|
||||||
void resetNeighbors();
|
void resetNeighbors();
|
||||||
|
|
||||||
bool saveProtoForModule();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool shouldSave = false; // Whether we should save the neighbor info to flash
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Note: this holds our local info.
|
|
||||||
meshtastic_NeighborInfo neighborState;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called to handle a particular incoming message
|
* Called to handle a particular incoming message
|
||||||
* @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
* @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||||
@@ -40,10 +32,9 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
|
uint32_t collectNeighborInfo(meshtastic_NeighborInfo *neighborInfo);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Remove neighbors from the database that we haven't heard from in a while
|
Remove neighbors from the database that we haven't heard from in a while
|
||||||
@returns new number of neighbors
|
|
||||||
*/
|
*/
|
||||||
size_t cleanUpNeighbors();
|
void cleanUpNeighbors();
|
||||||
|
|
||||||
/* Allocate a new NeighborInfo packet */
|
/* Allocate a new NeighborInfo packet */
|
||||||
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
|
meshtastic_NeighborInfo *allocateNeighborInfoPacket();
|
||||||
@@ -56,22 +47,12 @@ class NeighborInfoModule : public ProtobufModule<meshtastic_NeighborInfo>, priva
|
|||||||
*/
|
*/
|
||||||
void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
void sendNeighborInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
size_t getNumNeighbors() { return *numNeighbors; }
|
|
||||||
|
|
||||||
meshtastic_Neighbor *getNeighborByIndex(size_t x)
|
|
||||||
{
|
|
||||||
assert(x < *numNeighbors);
|
|
||||||
return &neighbors[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update neighbors with subpacket sniffed from network */
|
/* update neighbors with subpacket sniffed from network */
|
||||||
void updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np);
|
void updateNeighbors(const meshtastic_MeshPacket &mp, const meshtastic_NeighborInfo *np);
|
||||||
|
|
||||||
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
|
/* update a NeighborInfo packet with our NodeNum as last_sent_by_id */
|
||||||
void alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n) override;
|
void alterReceivedProtobuf(meshtastic_MeshPacket &p, meshtastic_NeighborInfo *n) override;
|
||||||
|
|
||||||
void loadProtoForModule();
|
|
||||||
|
|
||||||
/* Does our periodic broadcast */
|
/* Does our periodic broadcast */
|
||||||
int32_t runOnce() override;
|
int32_t runOnce() override;
|
||||||
|
|
||||||
|
|||||||
@@ -506,7 +506,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0); // unexpected state
|
break; // no need to do anything
|
||||||
}
|
}
|
||||||
return true; // There's no need for others to look at this message.
|
return true; // There's no need for others to look at this message.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -656,6 +656,7 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
|
|||||||
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
|
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
|
||||||
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
|
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
|
||||||
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
|
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
|
||||||
|
msgPayload["uptime_seconds"] = new JSONValue((uint)decoded->variant.device_metrics.uptime_seconds);
|
||||||
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
|
||||||
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
|
||||||
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
|
||||||
|
|||||||
@@ -106,20 +106,26 @@ static NimbleBluetoothFromRadioCallback *fromRadioCallbacks;
|
|||||||
|
|
||||||
void NimbleBluetooth::shutdown()
|
void NimbleBluetooth::shutdown()
|
||||||
{
|
{
|
||||||
|
// No measurable power saving for ESP32 during light-sleep(?)
|
||||||
|
#ifndef ARCH_ESP32
|
||||||
// Shutdown bluetooth for minimum power draw
|
// Shutdown bluetooth for minimum power draw
|
||||||
LOG_INFO("Disable bluetooth\n");
|
LOG_INFO("Disable bluetooth\n");
|
||||||
// Bluefruit.Advertising.stop();
|
|
||||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||||
pAdvertising->reset();
|
pAdvertising->reset();
|
||||||
pAdvertising->stop();
|
pAdvertising->stop();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extra power-saving on some devices
|
// Proper shutdown for ESP32. Needs reboot to reverse.
|
||||||
void NimbleBluetooth::deinit()
|
void NimbleBluetooth::deinit()
|
||||||
{
|
{
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
LOG_INFO("Disable bluetooth until reboot\n");
|
||||||
NimBLEDevice::deinit();
|
NimBLEDevice::deinit();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Has initial setup been completed
|
||||||
bool NimbleBluetooth::isActive()
|
bool NimbleBluetooth::isActive()
|
||||||
{
|
{
|
||||||
return bleServer;
|
return bleServer;
|
||||||
|
|||||||
@@ -117,6 +117,8 @@
|
|||||||
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER
|
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_WIRELESS_PAPER
|
||||||
#elif defined(TLORA_T3S3_V1)
|
#elif defined(TLORA_T3S3_V1)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_TLORA_T3_S3
|
#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)
|
#elif defined(BETAFPV_2400_TX)
|
||||||
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_2400_TX
|
#define HW_VENDOR meshtastic_HardwareModel_BETAFPV_2400_TX
|
||||||
#elif defined(NANO_G1_EXPLORER)
|
#elif defined(NANO_G1_EXPLORER)
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ void setBluetoothEnable(bool enable)
|
|||||||
}
|
}
|
||||||
if (enable && !nimbleBluetooth->isActive()) {
|
if (enable && !nimbleBluetooth->isActive()) {
|
||||||
nimbleBluetooth->setup();
|
nimbleBluetooth->setup();
|
||||||
} else if (!enable) {
|
|
||||||
nimbleBluetooth->shutdown();
|
|
||||||
}
|
}
|
||||||
|
// For ESP32, no way to recover from bluetooth shutdown without reboot
|
||||||
|
// BLE advertising automatically stops when MCU enters light-sleep(?)
|
||||||
|
// For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
HardwareSPI *DisplaySPI;
|
||||||
|
HardwareSPI *LoraSPI;
|
||||||
std::map<configNames, int> settingsMap;
|
std::map<configNames, int> settingsMap;
|
||||||
std::map<configNames, std::string> settingsStrings;
|
std::map<configNames, std::string> settingsStrings;
|
||||||
char *configPath = nullptr;
|
char *configPath = nullptr;
|
||||||
@@ -81,6 +83,7 @@ void portduinoSetup()
|
|||||||
settingsStrings[keyboardDevice] = "";
|
settingsStrings[keyboardDevice] = "";
|
||||||
settingsStrings[webserverrootpath] = "";
|
settingsStrings[webserverrootpath] = "";
|
||||||
settingsStrings[spidev] = "";
|
settingsStrings[spidev] = "";
|
||||||
|
settingsStrings[displayspidev] = "";
|
||||||
|
|
||||||
YAML::Node yamlConfig;
|
YAML::Node yamlConfig;
|
||||||
|
|
||||||
@@ -187,6 +190,9 @@ void portduinoSetup()
|
|||||||
settingsMap[displayOffsetY] = yamlConfig["Display"]["OffsetY"].as<int>(0);
|
settingsMap[displayOffsetY] = yamlConfig["Display"]["OffsetY"].as<int>(0);
|
||||||
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
settingsMap[displayRotate] = yamlConfig["Display"]["Rotate"].as<bool>(false);
|
||||||
settingsMap[displayInvert] = yamlConfig["Display"]["Invert"].as<bool>(false);
|
settingsMap[displayInvert] = yamlConfig["Display"]["Invert"].as<bool>(false);
|
||||||
|
if (yamlConfig["Display"]["spidev"]) {
|
||||||
|
settingsStrings[displayspidev] = "/dev/" + yamlConfig["Display"]["spidev"].as<std::string>("spidev0.1");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
settingsMap[touchscreenModule] = no_touchscreen;
|
settingsMap[touchscreenModule] = no_touchscreen;
|
||||||
if (yamlConfig["Touchscreen"]) {
|
if (yamlConfig["Touchscreen"]) {
|
||||||
@@ -196,6 +202,9 @@ void portduinoSetup()
|
|||||||
settingsMap[touchscreenModule] = stmpe610;
|
settingsMap[touchscreenModule] = stmpe610;
|
||||||
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
|
settingsMap[touchscreenCS] = yamlConfig["Touchscreen"]["CS"].as<int>(-1);
|
||||||
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
|
settingsMap[touchscreenIRQ] = yamlConfig["Touchscreen"]["IRQ"].as<int>(-1);
|
||||||
|
if (yamlConfig["Touchscreen"]["spidev"]) {
|
||||||
|
settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (yamlConfig["Input"]) {
|
if (yamlConfig["Input"]) {
|
||||||
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
settingsStrings[keyboardDevice] = (yamlConfig["Input"]["KeyboardDevice"]).as<std::string>("");
|
||||||
@@ -267,6 +276,26 @@ void portduinoSetup()
|
|||||||
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we specify a touchscreen dev, that is SPI.
|
||||||
|
// else if we specify a screen dev, that is SPI
|
||||||
|
// else if we specify a LoRa dev, that is SPI.
|
||||||
|
if (settingsStrings[touchscreenspidev] != "") {
|
||||||
|
SPI.begin(settingsStrings[touchscreenspidev].c_str());
|
||||||
|
DisplaySPI = new HardwareSPI;
|
||||||
|
DisplaySPI->begin(settingsStrings[displayspidev].c_str());
|
||||||
|
LoraSPI = new HardwareSPI;
|
||||||
|
LoraSPI->begin(settingsStrings[spidev].c_str());
|
||||||
|
} else if (settingsStrings[displayspidev] != "") {
|
||||||
|
SPI.begin(settingsStrings[displayspidev].c_str());
|
||||||
|
DisplaySPI = &SPI;
|
||||||
|
LoraSPI = new HardwareSPI;
|
||||||
|
LoraSPI->begin(settingsStrings[spidev].c_str());
|
||||||
|
} else {
|
||||||
|
SPI.begin(settingsStrings[spidev].c_str());
|
||||||
|
LoraSPI = &SPI;
|
||||||
|
DisplaySPI = &SPI;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ enum configNames {
|
|||||||
touchscreenModule,
|
touchscreenModule,
|
||||||
touchscreenCS,
|
touchscreenCS,
|
||||||
touchscreenIRQ,
|
touchscreenIRQ,
|
||||||
|
touchscreenspidev,
|
||||||
|
displayspidev,
|
||||||
displayPanel,
|
displayPanel,
|
||||||
displayWidth,
|
displayWidth,
|
||||||
displayHeight,
|
displayHeight,
|
||||||
@@ -45,4 +47,6 @@ enum { level_error, level_warn, level_info, level_debug };
|
|||||||
|
|
||||||
extern std::map<configNames, int> settingsMap;
|
extern std::map<configNames, int> settingsMap;
|
||||||
extern std::map<configNames, std::string> settingsStrings;
|
extern std::map<configNames, std::string> settingsStrings;
|
||||||
int initGPIOPin(int pinNum, std::string gpioChipname);
|
int initGPIOPin(int pinNum, std::string gpioChipname);
|
||||||
|
extern HardwareSPI *DisplaySPI;
|
||||||
|
extern HardwareSPI *LoraSPI;
|
||||||
@@ -207,8 +207,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
|
|||||||
// esp_wifi_stop();
|
// esp_wifi_stop();
|
||||||
waitEnterSleep(skipPreflight);
|
waitEnterSleep(skipPreflight);
|
||||||
|
|
||||||
#ifdef NIMBLE_DEINIT_FOR_DEEPSLEEP
|
#ifdef ARCH_ESP32
|
||||||
// Extra power saving on some devices
|
// Full shutdown of bluetooth hardware
|
||||||
nimbleBluetooth->deinit();
|
nimbleBluetooth->deinit();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
37
variants/CDEBYTE_EoRa-S3/pins_arduino.h
Normal file
37
variants/CDEBYTE_EoRa-S3/pins_arduino.h
Normal file
@@ -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 <stdint.h>
|
||||||
|
#include <variant.h>
|
||||||
|
|
||||||
|
#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 */
|
||||||
8
variants/CDEBYTE_EoRa-S3/platformio.ini
Normal file
8
variants/CDEBYTE_EoRa-S3/platformio.ini
Normal file
@@ -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
|
||||||
63
variants/CDEBYTE_EoRa-S3/variant.h
Normal file
63
variants/CDEBYTE_EoRa-S3/variant.h
Normal file
@@ -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
|
||||||
@@ -55,6 +55,3 @@
|
|||||||
|
|
||||||
#define SX126X_DIO2_AS_RF_SWITCH
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
// Power management
|
|
||||||
#define NIMBLE_DEINIT_FOR_DEEPSLEEP // Required to reach manufacturers claim of 18uA
|
|
||||||
|
|||||||
@@ -55,6 +55,3 @@
|
|||||||
|
|
||||||
#define SX126X_DIO2_AS_RF_SWITCH
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
|
||||||
// Power management
|
|
||||||
#define NIMBLE_DEINIT_FOR_DEEPSLEEP // Required to reach manufacturers claim of 18uA
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
; platformio.ini for unphone meshtastic
|
||||||
|
|
||||||
[env:unphone]
|
[env:unphone]
|
||||||
;build_type = debug ; to make it possible to step through our jtag debugger
|
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board_level = extra
|
board_level = extra
|
||||||
board = unphone9
|
board = unphone9
|
||||||
@@ -14,6 +16,15 @@ build_flags = ${esp32_base.build_flags}
|
|||||||
-D UNPHONE
|
-D UNPHONE
|
||||||
-I variants/unphone
|
-I variants/unphone
|
||||||
-D ARDUINO_USB_MODE=0
|
-D ARDUINO_USB_MODE=0
|
||||||
|
-D UNPHONE_ACCEL=0
|
||||||
|
-D UNPHONE_TOUCHS=0
|
||||||
|
-D UNPHONE_SDCARD=0
|
||||||
|
-D UNPHONE_UI0=0
|
||||||
|
-D UNPHONE_LORA=0
|
||||||
|
-D UNPHONE_FACTORY_MODE=0
|
||||||
|
|
||||||
|
build_src_filter = ${esp32_base.build_src_filter} +<../variants/unphone>
|
||||||
|
|
||||||
lib_deps = ${esp32s3_base.lib_deps}
|
lib_deps = ${esp32s3_base.lib_deps}
|
||||||
lovyan03/LovyanGFX@^1.1.8
|
lovyan03/LovyanGFX @ ^1.1.8
|
||||||
|
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic @ ^9.0.0
|
||||||
20
variants/unphone/variant.cpp
Normal file
20
variants/unphone/variant.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// meshtastic/firmware/variants/unphone/variant.cpp
|
||||||
|
|
||||||
|
#include "unPhone.h"
|
||||||
|
unPhone unphone = unPhone("meshtastic_unphone");
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
unphone.begin(); // initialise hardware etc.
|
||||||
|
unphone.store(unphone.buildTime);
|
||||||
|
unphone.printWakeupReason(); // what woke us up? (stored, not printed :|)
|
||||||
|
unphone.checkPowerSwitch(); // if power switch is off, shutdown
|
||||||
|
unphone.backlight(false); // setup backlight and make sure its off
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) { // buzz a bit
|
||||||
|
unphone.vibe(true);
|
||||||
|
delay(150);
|
||||||
|
unphone.vibe(false);
|
||||||
|
delay(150);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
// meshtastic/firmware/variants/unphone/variant.h
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#define SPI_SCK 39
|
#define SPI_SCK 39
|
||||||
#define SPI_MOSI 40
|
#define SPI_MOSI 40
|
||||||
#define SPI_MISO 41
|
#define SPI_MISO 41
|
||||||
@@ -28,7 +32,7 @@
|
|||||||
#define TFT_WIDTH 320
|
#define TFT_WIDTH 320
|
||||||
#define TFT_OFFSET_X 0
|
#define TFT_OFFSET_X 0
|
||||||
#define TFT_OFFSET_Y 0
|
#define TFT_OFFSET_Y 0
|
||||||
#define TFT_OFFSET_ROTATION 6 // the unPhone's screen is wired unusually, 0 is typical value here
|
#define TFT_OFFSET_ROTATION 6 // unPhone's screen wired unusually, 0 typical
|
||||||
#define TFT_INVERT false
|
#define TFT_INVERT false
|
||||||
#define SCREEN_ROTATE true
|
#define SCREEN_ROTATE true
|
||||||
#define SCREEN_TRANSITION_FRAMERATE 5
|
#define SCREEN_TRANSITION_FRAMERATE 5
|
||||||
@@ -37,7 +41,10 @@
|
|||||||
#define USE_XPT2046 1
|
#define USE_XPT2046 1
|
||||||
#define TOUCH_CS 38
|
#define TOUCH_CS 38
|
||||||
|
|
||||||
#define HAS_GPS 0 // the unphone doesn't have a gps module
|
#define HAS_GPS \
|
||||||
|
0 // the unphone doesn't have a gps module by default (though
|
||||||
|
// GPS featherwing -- https://www.adafruit.com/product/3133
|
||||||
|
// -- can be added)
|
||||||
#undef GPS_RX_PIN
|
#undef GPS_RX_PIN
|
||||||
#undef GPS_TX_PIN
|
#undef GPS_TX_PIN
|
||||||
|
|
||||||
@@ -49,6 +56,7 @@
|
|||||||
|
|
||||||
#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode
|
#define BUTTON_PIN 21 // Button 3 - square - top button in landscape mode
|
||||||
#define BUTTON_NEED_PULLUP // we do need a helping hand up
|
#define BUTTON_NEED_PULLUP // we do need a helping hand up
|
||||||
|
#define BUTTON_PIN_ALT 45 // Button 1 - triangle - bottom button in landscape mode
|
||||||
|
|
||||||
#define I2C_SDA 3 // I2C pins for this board
|
#define I2C_SDA 3 // I2C pins for this board
|
||||||
#define I2C_SCL 4
|
#define I2C_SCL 4
|
||||||
@@ -58,6 +66,6 @@
|
|||||||
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
|
// ratio of voltage divider = 3.20 (R1=100k, R2=220k)
|
||||||
// #define ADC_MULTIPLIER 3.2
|
// #define ADC_MULTIPLIER 3.2
|
||||||
|
|
||||||
// #define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
// #define BATTERY_PIN 13 // battery V measurement pin; vbat divider is here
|
||||||
// #define ADC_CHANNEL ADC2_GPIO13_CHANNEL
|
// #define ADC_CHANNEL ADC2_GPIO13_CHANNEL
|
||||||
// #define BAT_MEASURE_ADC_UNIT 2
|
// #define BAT_MEASURE_ADC_UNIT 2
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 3
|
minor = 3
|
||||||
build = 5
|
build = 6
|
||||||
|
|||||||
Reference in New Issue
Block a user