Merge branch 'develop' into pioarduino

This commit is contained in:
Manuel
2026-04-09 17:02:38 +02:00
committed by GitHub
80 changed files with 1423 additions and 311 deletions
+3 -3
View File
@@ -231,7 +231,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define BME_ADDR 0x76
#define BME_ADDR_ALTERNATE 0x77
#define MCP9808_ADDR 0x18
#define INA_ADDR 0x40
#define INA_ADDR 0x40 // same as SHT2X
#define INA_ADDR_ALTERNATE 0x41
#define INA_ADDR_WAVESHARE_UPS 0x43
#define INA3221_ADDR 0x42
@@ -244,8 +244,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define LPS22HB_ADDR 0x5C
#define LPS22HB_ADDR_ALT 0x5D
#define SFA30_ADDR 0x5D
#define SHT31_4x_ADDR 0x44
#define SHT31_4x_ADDR_ALT 0x45
#define SHTXX_ADDR 0x44
#define SHTXX_ADDR_ALT 0x45
#define PMSA003I_ADDR 0x12
#define QMA6100P_ADDR 0x12
#define AHT10_ADDR 0x38
+2 -4
View File
@@ -31,9 +31,6 @@ class ScanI2C
INA3221,
MAX17048,
MCP9808,
SHT31,
SHT4X,
SHTC3,
LPS22HB,
QMC6310U,
QMC6310N,
@@ -94,7 +91,8 @@ class ScanI2C
SFA30,
CW2015,
SCD30,
ADS1115
ADS1115,
SHTXX
} DeviceType;
// typedef uint8_t DeviceAddress;
+58 -12
View File
@@ -136,7 +136,9 @@ bool ScanI2CTwoWire::i2cCommandResponseLength(ScanI2C::DeviceAddress addr, uint1
return match;
}
/// for SEN5X detection
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
// FIXME Move to a separate file for detection of sensors that require more complex interactions?
// For SEN5X detection
// Note, this code needs to be called before setting the I2C bus speed
// for the screen at high speed. The speed needs to be at 100kHz, otherwise
// detection will not work
@@ -174,6 +176,46 @@ String readSEN5xProductName(TwoWire *i2cBus, uint8_t address)
return String(productName);
}
#endif
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
bool detectSHT21SerialNumber(TwoWire *i2cBus, uint8_t address)
{
i2cBus->beginTransmission(address);
i2cBus->write(0xFA);
i2cBus->write(0x0F);
if (i2cBus->endTransmission() != 0)
return false;
if (i2cBus->requestFrom(address, (uint8_t)8) != 8)
return false;
// Just flush the data
while (i2cBus->available() < 8) {
i2cBus->read();
}
i2cBus->beginTransmission(address);
i2cBus->write(0xFC);
i2cBus->write(0xC9);
if (i2cBus->endTransmission() != 0)
return false;
if (i2cBus->requestFrom(address, (uint8_t)6) != 6)
return false;
// Just flush the data
while (i2cBus->available() < 6) {
i2cBus->read();
}
// Assume we detect the SHT21 if something came back from the request
return true;
}
#endif
#define SCAN_SIMPLE_CASE(ADDR, T, ...) \
case ADDR: \
@@ -371,7 +413,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
#endif
#if !defined(M5STACK_UNITC6L)
case INA_ADDR:
case INA_ADDR: // Same as SHT2X
case INA_ADDR_ALTERNATE:
case INA_ADDR_WAVESHARE_UPS:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2);
@@ -387,7 +429,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
logFoundDevice("INA260", (uint8_t)addr.address);
type = INA260;
}
} else { // Assume INA219 if INA260 ID is not found
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
} else if (detectSHT21SerialNumber(i2cBus, (uint8_t)addr.address)) {
logFoundDevice("SHTXX (SHT2X)", (uint8_t)addr.address);
type = SHTXX;
#endif
} else { // Assume INA219 if none of the above ones are found
logFoundDevice("INA219", (uint8_t)addr.address);
type = INA219;
}
@@ -448,22 +495,19 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
}
case SHT31_4x_ADDR: // same as OPT3001_ADDR_ALT
case SHT31_4x_ADDR_ALT: // same as OPT3001_ADDR
case SHTXX_ADDR: // same as OPT3001_ADDR_ALT
case SHTXX_ADDR_ALT: // same as OPT3001_ADDR
if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) {
type = OPT3001;
logFoundDevice("OPT3001", (uint8_t)addr.address);
} else if (i2cCommandResponseLength(addr, 0x89, 6)) { // SHT4x serial number (6 bytes inc. CRC)
type = SHT4X;
logFoundDevice("SHT4X", (uint8_t)addr.address);
} else {
type = SHT31;
logFoundDevice("SHT31", (uint8_t)addr.address);
} else { // SHTXX
type = SHTXX;
logFoundDevice("SHTXX", (uint8_t)addr.address);
}
break;
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address)
SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTXX, "SHTXX", (uint8_t)addr.address)
case RCWL9620_ADDR:
// get MAX30102 PARTID
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1);
@@ -675,6 +719,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
logFoundDevice("BMX160", (uint8_t)addr.address);
break;
} else {
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR
String prod = "";
prod = readSEN5xProductName(i2cBus, addr.address);
if (prod.startsWith("SEN55")) {
@@ -690,6 +735,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
logFoundDevice("Sensirion SEN50", addr.address);
break;
}
#endif
if (addr.address == BMX160_ADDR) {
type = BMX160;
logFoundDevice("BMX160", (uint8_t)addr.address);
+15 -7
View File
@@ -1254,14 +1254,14 @@ void TFTDisplay::display(bool fromBlank)
// Did we find a pixel that needs updating on this row?
if (x_FirstPixelUpdate < displayWidth) {
// Align the first pixel for update to an even number so the total alignment of
// the data will be at 32-bit boundary, which is required by GDMA SPI transfers.
x_FirstPixelUpdate &= ~1;
// Quickly write out the first changed pixel (saves another array lookup)
linePixelBuffer[x_FirstPixelUpdate] = isset ? colorTftMesh : colorTftBlack;
x_LastPixelUpdate = x_FirstPixelUpdate;
// Step 3: copy all remaining pixels in this row into the pixel line buffer,
// while also recording the last pixel in the row that needs updating
for (x = x_FirstPixelUpdate + 1; x < displayWidth; x++) {
// Step 3a: copy rest of the pixels in this row into the pixel line buffer,
// while also recording the last pixel in the row that needs updating.
// Since the first changed pixel will be looked up, the x_LastPixelUpdate will be set.
for (x = x_FirstPixelUpdate; x < displayWidth; x++) {
isset = buffer[x + y_byteIndex] & y_byteMask;
linePixelBuffer[x] = isset ? colorTftMesh : colorTftBlack;
@@ -1274,6 +1274,14 @@ void TFTDisplay::display(bool fromBlank)
x_LastPixelUpdate = x;
}
}
// Step 3b: Round up the last pixel to odd number to maintain 32-bit alignment for SPIs.
// Most displays will have even number of pixels in a row -- this will be in bounds
// of the displayWidth. (Hopefully odd displays will just ignore that extra pixel.)
x_LastPixelUpdate |= 1;
// Ensure the last pixel index does not exceed the display width.
if (x_LastPixelUpdate >= displayWidth) {
x_LastPixelUpdate = displayWidth - 1;
}
#if defined(HACKADAY_COMMUNICATOR)
tft->draw16bitBeRGBBitmap(x_FirstPixelUpdate, y, &linePixelBuffer[x_FirstPixelUpdate],
(x_LastPixelUpdate - x_FirstPixelUpdate + 1), 1);
+11 -6
View File
@@ -299,6 +299,7 @@ void InputBroker::Init()
// Buttons. Moved here cause we need NodeDB to be initialized
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
UserButtonThread = new ButtonThread("UserButton");
#if !MESHTASTIC_EXCLUDE_SCREEN
if (screen) {
ButtonConfig userConfig;
userConfig.pinNumber = (uint8_t)_pinNum;
@@ -317,7 +318,9 @@ void InputBroker::Init()
userConfig.longPressTime = 500;
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
UserButtonThread->initButton(userConfig);
} else {
} else
#endif
{
ButtonConfig userConfigNoScreen;
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
@@ -379,11 +382,13 @@ void InputBroker::Init()
}
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
if (portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
+1 -1
View File
@@ -819,7 +819,7 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.has_store_forward = true;
moduleConfig.has_telemetry = true;
moduleConfig.has_external_notification = true;
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION)
#if defined(PIN_BUZZER) || defined(PIN_VIBRATION) || defined(LED_NOTIFICATION) || defined(PCA_LED_NOTIFICATION)
moduleConfig.external_notification.enabled = true;
#endif
#if defined(PIN_BUZZER)
+4 -2
View File
@@ -152,8 +152,10 @@ const RegionInfo regions[] = {
/*
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
https://standard.nbtc.go.th/getattachment/Standards/%E0%B8%A1%E0%B8%B2%E0%B8%95%E0%B8%A3%E0%B8%90%E0%B8%B2%E0%B8%99%E0%B8%97%E0%B8%B2%E0%B8%87%E0%B9%80%E0%B8%97%E0%B8%84%E0%B8%99%E0%B8%B4%E0%B8%84%E0%B8%82%E0%B8%AD%E0%B8%87%E0%B9%80%E0%B8%84%E0%B8%A3%E0%B8%B7%E0%B9%88%E0%B8%AD%E0%B8%87%E0%B9%82%E0%B8%97%E0%B8%A3%E0%B8%84%E0%B8%A1%E0%B8%99%E0%B8%B2%E0%B8%84%E0%B8%A1/1033-2565.pdf.aspx?lang=th-TH
Thailand 920–925 MHz set max TX power to 27 dBm and enforce 10% duty cycle, aligned with NBTC regulations.
*/
RDEF(TH, 920.0f, 925.0f, 100, 16, false, false, PROFILE_STD),
RDEF(TH, 920.0f, 925.0f, 10, 27, false, false, PROFILE_STD),
/*
433,05-434,7 Mhz 10 mW
@@ -961,7 +963,7 @@ void RadioInterface::applyModemConfig()
cr = loraConfig.coding_rate;
LOG_INFO("Using custom Coding Rate %u", cr);
} else {
cr = loraConfig.coding_rate;
cr = newcr;
}
} else { // if not using preset, then just use the custom settings
+12
View File
@@ -24,6 +24,18 @@ PB_BIND(meshtastic_Contact, meshtastic_Contact, AUTO)
PB_BIND(meshtastic_PLI, meshtastic_PLI, AUTO)
PB_BIND(meshtastic_AircraftTrack, meshtastic_AircraftTrack, AUTO)
PB_BIND(meshtastic_TAKPacketV2, meshtastic_TAKPacketV2, 2)
+393 -1
View File
@@ -65,6 +65,197 @@ typedef enum _meshtastic_MemberRole {
meshtastic_MemberRole_K9 = 8
} meshtastic_MemberRole;
/* CoT how field values.
Represents how the coordinates were generated. */
typedef enum _meshtastic_CotHow {
/* Unspecified */
meshtastic_CotHow_CotHow_Unspecified = 0,
/* Human entered */
meshtastic_CotHow_CotHow_h_e = 1,
/* Machine generated */
meshtastic_CotHow_CotHow_m_g = 2,
/* Human GPS/INS derived */
meshtastic_CotHow_CotHow_h_g_i_g_o = 3,
/* Machine relayed (imported from another system/gateway) */
meshtastic_CotHow_CotHow_m_r = 4,
/* Machine fused (corroborated from multiple sources) */
meshtastic_CotHow_CotHow_m_f = 5,
/* Machine predicted */
meshtastic_CotHow_CotHow_m_p = 6,
/* Machine simulated */
meshtastic_CotHow_CotHow_m_s = 7
} meshtastic_CotHow;
/* Well-known CoT event types.
When the type is known, use the enum value for efficient encoding.
For unknown types, set cot_type_id to CotType_Other and populate cot_type_str. */
typedef enum _meshtastic_CotType {
/* Unknown or unmapped type, use cot_type_str */
meshtastic_CotType_CotType_Other = 0,
/* a-f-G-U-C: Friendly ground unit combat */
meshtastic_CotType_CotType_a_f_G_U_C = 1,
/* a-f-G-U-C-I: Friendly ground unit combat infantry */
meshtastic_CotType_CotType_a_f_G_U_C_I = 2,
/* a-n-A-C-F: Neutral aircraft civilian fixed-wing */
meshtastic_CotType_CotType_a_n_A_C_F = 3,
/* a-n-A-C-H: Neutral aircraft civilian helicopter */
meshtastic_CotType_CotType_a_n_A_C_H = 4,
/* a-n-A-C: Neutral aircraft civilian */
meshtastic_CotType_CotType_a_n_A_C = 5,
/* a-f-A-M-H: Friendly aircraft military helicopter */
meshtastic_CotType_CotType_a_f_A_M_H = 6,
/* a-f-A-M: Friendly aircraft military */
meshtastic_CotType_CotType_a_f_A_M = 7,
/* a-f-A-M-F-F: Friendly aircraft military fixed-wing fighter */
meshtastic_CotType_CotType_a_f_A_M_F_F = 8,
/* a-f-A-M-H-A: Friendly aircraft military helicopter attack */
meshtastic_CotType_CotType_a_f_A_M_H_A = 9,
/* a-f-A-M-H-U-M: Friendly aircraft military helicopter utility medium */
meshtastic_CotType_CotType_a_f_A_M_H_U_M = 10,
/* a-h-A-M-F-F: Hostile aircraft military fixed-wing fighter */
meshtastic_CotType_CotType_a_h_A_M_F_F = 11,
/* a-h-A-M-H-A: Hostile aircraft military helicopter attack */
meshtastic_CotType_CotType_a_h_A_M_H_A = 12,
/* a-u-A-C: Unknown aircraft civilian */
meshtastic_CotType_CotType_a_u_A_C = 13,
/* t-x-d-d: Tasking delete/disconnect */
meshtastic_CotType_CotType_t_x_d_d = 14,
/* a-f-G-E-S-E: Friendly ground equipment sensor */
meshtastic_CotType_CotType_a_f_G_E_S_E = 15,
/* a-f-G-E-V-C: Friendly ground equipment vehicle */
meshtastic_CotType_CotType_a_f_G_E_V_C = 16,
/* a-f-S: Friendly sea */
meshtastic_CotType_CotType_a_f_S = 17,
/* a-f-A-M-F: Friendly aircraft military fixed-wing */
meshtastic_CotType_CotType_a_f_A_M_F = 18,
/* a-f-A-M-F-C-H: Friendly aircraft military fixed-wing cargo heavy */
meshtastic_CotType_CotType_a_f_A_M_F_C_H = 19,
/* a-f-A-M-F-U-L: Friendly aircraft military fixed-wing utility light */
meshtastic_CotType_CotType_a_f_A_M_F_U_L = 20,
/* a-f-A-M-F-L: Friendly aircraft military fixed-wing liaison */
meshtastic_CotType_CotType_a_f_A_M_F_L = 21,
/* a-f-A-M-F-P: Friendly aircraft military fixed-wing patrol */
meshtastic_CotType_CotType_a_f_A_M_F_P = 22,
/* a-f-A-C-H: Friendly aircraft civilian helicopter */
meshtastic_CotType_CotType_a_f_A_C_H = 23,
/* a-n-A-M-F-Q: Neutral aircraft military fixed-wing drone */
meshtastic_CotType_CotType_a_n_A_M_F_Q = 24,
/* b-t-f: GeoChat message */
meshtastic_CotType_CotType_b_t_f = 25,
/* b-r-f-h-c: CASEVAC/MEDEVAC report */
meshtastic_CotType_CotType_b_r_f_h_c = 26,
/* b-a-o-pan: Ring the bell / alert all */
meshtastic_CotType_CotType_b_a_o_pan = 27,
/* b-a-o-opn: Troops in contact */
meshtastic_CotType_CotType_b_a_o_opn = 28,
/* b-a-o-can: Cancel alert */
meshtastic_CotType_CotType_b_a_o_can = 29,
/* b-a-o-tbl: 911 alert */
meshtastic_CotType_CotType_b_a_o_tbl = 30,
/* b-a-g: Geofence breach alert */
meshtastic_CotType_CotType_b_a_g = 31,
/* a-f-G: Friendly ground (generic) */
meshtastic_CotType_CotType_a_f_G = 32,
/* a-f-G-U: Friendly ground unit (generic) */
meshtastic_CotType_CotType_a_f_G_U = 33,
/* a-h-G: Hostile ground (generic) */
meshtastic_CotType_CotType_a_h_G = 34,
/* a-u-G: Unknown ground (generic) */
meshtastic_CotType_CotType_a_u_G = 35,
/* a-n-G: Neutral ground (generic) */
meshtastic_CotType_CotType_a_n_G = 36,
/* b-m-r: Route */
meshtastic_CotType_CotType_b_m_r = 37,
/* b-m-p-w: Route waypoint */
meshtastic_CotType_CotType_b_m_p_w = 38,
/* b-m-p-s-p-i: Self-position marker */
meshtastic_CotType_CotType_b_m_p_s_p_i = 39,
/* u-d-f: Freeform shape (line/polygon) */
meshtastic_CotType_CotType_u_d_f = 40,
/* u-d-r: Rectangle */
meshtastic_CotType_CotType_u_d_r = 41,
/* u-d-c-c: Circle */
meshtastic_CotType_CotType_u_d_c_c = 42,
/* u-rb-a: Range/bearing line */
meshtastic_CotType_CotType_u_rb_a = 43,
/* a-h-A: Hostile aircraft (generic) */
meshtastic_CotType_CotType_a_h_A = 44,
/* a-u-A: Unknown aircraft (generic) */
meshtastic_CotType_CotType_a_u_A = 45,
/* a-f-A-M-H-Q: Friendly aircraft military helicopter observation */
meshtastic_CotType_CotType_a_f_A_M_H_Q = 46,
/* a-f-A-C-F: Friendly aircraft civilian fixed-wing */
meshtastic_CotType_CotType_a_f_A_C_F = 47,
/* a-f-A-C: Friendly aircraft civilian (generic) */
meshtastic_CotType_CotType_a_f_A_C = 48,
/* a-f-A-C-L: Friendly aircraft civilian lighter-than-air */
meshtastic_CotType_CotType_a_f_A_C_L = 49,
/* a-f-A: Friendly aircraft (generic) */
meshtastic_CotType_CotType_a_f_A = 50,
/* a-f-A-M-H-C: Friendly aircraft military helicopter cargo */
meshtastic_CotType_CotType_a_f_A_M_H_C = 51,
/* a-n-A-M-F-F: Neutral aircraft military fixed-wing fighter */
meshtastic_CotType_CotType_a_n_A_M_F_F = 52,
/* a-u-A-C-F: Unknown aircraft civilian fixed-wing */
meshtastic_CotType_CotType_a_u_A_C_F = 53,
/* a-f-G-U-C-F-T-A: Friendly ground unit combat forces theater aviation */
meshtastic_CotType_CotType_a_f_G_U_C_F_T_A = 54,
/* a-f-G-U-C-V-S: Friendly ground unit combat vehicle support */
meshtastic_CotType_CotType_a_f_G_U_C_V_S = 55,
/* a-f-G-U-C-R-X: Friendly ground unit combat reconnaissance exploitation */
meshtastic_CotType_CotType_a_f_G_U_C_R_X = 56,
/* a-f-G-U-C-I-Z: Friendly ground unit combat infantry mechanized */
meshtastic_CotType_CotType_a_f_G_U_C_I_Z = 57,
/* a-f-G-U-C-E-C-W: Friendly ground unit combat engineer construction wheeled */
meshtastic_CotType_CotType_a_f_G_U_C_E_C_W = 58,
/* a-f-G-U-C-I-L: Friendly ground unit combat infantry light */
meshtastic_CotType_CotType_a_f_G_U_C_I_L = 59,
/* a-f-G-U-C-R-O: Friendly ground unit combat reconnaissance other */
meshtastic_CotType_CotType_a_f_G_U_C_R_O = 60,
/* a-f-G-U-C-R-V: Friendly ground unit combat reconnaissance cavalry */
meshtastic_CotType_CotType_a_f_G_U_C_R_V = 61,
/* a-f-G-U-H: Friendly ground unit headquarters */
meshtastic_CotType_CotType_a_f_G_U_H = 62,
/* a-f-G-U-U-M-S-E: Friendly ground unit support medical surgical evacuation */
meshtastic_CotType_CotType_a_f_G_U_U_M_S_E = 63,
/* a-f-G-U-S-M-C: Friendly ground unit support maintenance collection */
meshtastic_CotType_CotType_a_f_G_U_S_M_C = 64,
/* a-f-G-E-S: Friendly ground equipment sensor (generic) */
meshtastic_CotType_CotType_a_f_G_E_S = 65,
/* a-f-G-E: Friendly ground equipment (generic) */
meshtastic_CotType_CotType_a_f_G_E = 66,
/* a-f-G-E-V-C-U: Friendly ground equipment vehicle utility */
meshtastic_CotType_CotType_a_f_G_E_V_C_U = 67,
/* a-f-G-E-V-C-ps: Friendly ground equipment vehicle public safety */
meshtastic_CotType_CotType_a_f_G_E_V_C_ps = 68,
/* a-u-G-E-V: Unknown ground equipment vehicle */
meshtastic_CotType_CotType_a_u_G_E_V = 69,
/* a-f-S-N-N-R: Friendly sea surface non-naval rescue */
meshtastic_CotType_CotType_a_f_S_N_N_R = 70,
/* a-f-F-B: Friendly force boundary */
meshtastic_CotType_CotType_a_f_F_B = 71,
/* b-m-p-s-p-loc: Self-position location marker */
meshtastic_CotType_CotType_b_m_p_s_p_loc = 72,
/* b-i-v: Imagery/video */
meshtastic_CotType_CotType_b_i_v = 73,
/* b-f-t-r: File transfer request */
meshtastic_CotType_CotType_b_f_t_r = 74,
/* b-f-t-a: File transfer acknowledgment */
meshtastic_CotType_CotType_b_f_t_a = 75
} meshtastic_CotType;
/* Geopoint and altitude source */
typedef enum _meshtastic_GeoPointSource {
/* Unspecified */
meshtastic_GeoPointSource_GeoPointSource_Unspecified = 0,
/* GPS derived */
meshtastic_GeoPointSource_GeoPointSource_GPS = 1,
/* User entered */
meshtastic_GeoPointSource_GeoPointSource_USER = 2,
/* Network/external */
meshtastic_GeoPointSource_GeoPointSource_NETWORK = 3
} meshtastic_GeoPointSource;
/* Struct definitions */
/* ATAK GeoChat message */
typedef struct _meshtastic_GeoChat {
@@ -146,6 +337,95 @@ typedef struct _meshtastic_TAKPacket {
} payload_variant;
} meshtastic_TAKPacket;
/* Aircraft track information from ADS-B or military air tracking.
Covers the majority of observed real-world CoT traffic. */
typedef struct _meshtastic_AircraftTrack {
/* ICAO hex identifier (e.g. "AD237C") */
char icao[8];
/* Aircraft registration (e.g. "N946AK") */
char registration[16];
/* Flight number/callsign (e.g. "ASA864") */
char flight[16];
/* ICAO aircraft type designator (e.g. "B39M") */
char aircraft_type[8];
/* Transponder squawk code (0-7777 octal) */
uint16_t squawk;
/* ADS-B emitter category (e.g. "A3") */
char category[4];
/* Received signal strength * 10 (e.g. -194 for -19.4 dBm) */
int32_t rssi_x10;
/* Whether receiver has GPS fix */
bool gps;
/* CoT host ID for source attribution */
char cot_host_id[64];
} meshtastic_AircraftTrack;
typedef PB_BYTES_ARRAY_T(220) meshtastic_TAKPacketV2_raw_detail_t;
/* ATAK v2 packet with expanded CoT field support and zstd dictionary compression.
Sent on ATAK_PLUGIN_V2 port. The wire payload is:
[1 byte flags][zstd-compressed TAKPacketV2 protobuf]
Flags byte: bits 0-5 = dictionary ID, bits 6-7 = reserved. */
typedef struct _meshtastic_TAKPacketV2 {
/* Well-known CoT event type enum.
Use CotType_Other with cot_type_str for unknown types. */
meshtastic_CotType cot_type_id;
/* How the coordinates were generated */
meshtastic_CotHow how;
/* Callsign */
char callsign[120];
/* Team color assignment */
meshtastic_Team team;
/* Role of the group member */
meshtastic_MemberRole role;
/* Latitude, multiply by 1e-7 to get degrees in floating point */
int32_t latitude_i;
/* Longitude, multiply by 1e-7 to get degrees in floating point */
int32_t longitude_i;
/* Altitude in meters (HAE) */
int32_t altitude;
/* Speed in cm/s */
uint32_t speed;
/* Course in degrees * 100 (0-36000) */
uint16_t course;
/* Battery level 0-100 */
uint8_t battery;
/* Geopoint source */
meshtastic_GeoPointSource geo_src;
/* Altitude source */
meshtastic_GeoPointSource alt_src;
/* Device UID (UUID string or device ID like "ANDROID-xxxx") */
char uid[48];
/* Device callsign */
char device_callsign[120];
/* Stale time as seconds offset from event time */
uint16_t stale_seconds;
/* TAK client version string */
char tak_version[64];
/* TAK device model */
char tak_device[32];
/* TAK platform (ATAK-CIV, WebTAK, etc.) */
char tak_platform[32];
/* TAK OS version */
char tak_os[16];
/* Connection endpoint */
char endpoint[32];
/* Phone number */
char phone[20];
/* CoT event type string, only populated when cot_type_id is CotType_Other */
char cot_type_str[32];
pb_size_t which_payload_variant;
union {
/* Position report (true = PLI, no extra fields beyond the common ones above) */
bool pli;
/* ATAK GeoChat message */
meshtastic_GeoChat chat;
/* Aircraft track data (ADS-B, military air) */
meshtastic_AircraftTrack aircraft;
/* Generic CoT detail XML for unmapped types */
meshtastic_TAKPacketV2_raw_detail_t raw_detail;
} payload_variant;
} meshtastic_TAKPacketV2;
#ifdef __cplusplus
extern "C" {
@@ -160,6 +440,18 @@ extern "C" {
#define _meshtastic_MemberRole_MAX meshtastic_MemberRole_K9
#define _meshtastic_MemberRole_ARRAYSIZE ((meshtastic_MemberRole)(meshtastic_MemberRole_K9+1))
#define _meshtastic_CotHow_MIN meshtastic_CotHow_CotHow_Unspecified
#define _meshtastic_CotHow_MAX meshtastic_CotHow_CotHow_m_s
#define _meshtastic_CotHow_ARRAYSIZE ((meshtastic_CotHow)(meshtastic_CotHow_CotHow_m_s+1))
#define _meshtastic_CotType_MIN meshtastic_CotType_CotType_Other
#define _meshtastic_CotType_MAX meshtastic_CotType_CotType_b_f_t_a
#define _meshtastic_CotType_ARRAYSIZE ((meshtastic_CotType)(meshtastic_CotType_CotType_b_f_t_a+1))
#define _meshtastic_GeoPointSource_MIN meshtastic_GeoPointSource_GeoPointSource_Unspecified
#define _meshtastic_GeoPointSource_MAX meshtastic_GeoPointSource_GeoPointSource_NETWORK
#define _meshtastic_GeoPointSource_ARRAYSIZE ((meshtastic_GeoPointSource)(meshtastic_GeoPointSource_GeoPointSource_NETWORK+1))
#define meshtastic_Group_role_ENUMTYPE meshtastic_MemberRole
@@ -169,6 +461,14 @@ extern "C" {
#define meshtastic_TAKPacketV2_cot_type_id_ENUMTYPE meshtastic_CotType
#define meshtastic_TAKPacketV2_how_ENUMTYPE meshtastic_CotHow
#define meshtastic_TAKPacketV2_team_ENUMTYPE meshtastic_Team
#define meshtastic_TAKPacketV2_role_ENUMTYPE meshtastic_MemberRole
#define meshtastic_TAKPacketV2_geo_src_ENUMTYPE meshtastic_GeoPointSource
#define meshtastic_TAKPacketV2_alt_src_ENUMTYPE meshtastic_GeoPointSource
/* Initializer values for message structs */
#define meshtastic_TAKPacket_init_default {0, false, meshtastic_Contact_init_default, false, meshtastic_Group_init_default, false, meshtastic_Status_init_default, 0, {meshtastic_PLI_init_default}}
#define meshtastic_GeoChat_init_default {"", false, "", false, ""}
@@ -176,12 +476,16 @@ extern "C" {
#define meshtastic_Status_init_default {0}
#define meshtastic_Contact_init_default {"", ""}
#define meshtastic_PLI_init_default {0, 0, 0, 0, 0}
#define meshtastic_AircraftTrack_init_default {"", "", "", "", 0, "", 0, 0, ""}
#define meshtastic_TAKPacketV2_init_default {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", 0, {0}}
#define meshtastic_TAKPacket_init_zero {0, false, meshtastic_Contact_init_zero, false, meshtastic_Group_init_zero, false, meshtastic_Status_init_zero, 0, {meshtastic_PLI_init_zero}}
#define meshtastic_GeoChat_init_zero {"", false, "", false, ""}
#define meshtastic_Group_init_zero {_meshtastic_MemberRole_MIN, _meshtastic_Team_MIN}
#define meshtastic_Status_init_zero {0}
#define meshtastic_Contact_init_zero {"", ""}
#define meshtastic_PLI_init_zero {0, 0, 0, 0, 0}
#define meshtastic_AircraftTrack_init_zero {"", "", "", "", 0, "", 0, 0, ""}
#define meshtastic_TAKPacketV2_init_zero {_meshtastic_CotType_MIN, _meshtastic_CotHow_MIN, "", _meshtastic_Team_MIN, _meshtastic_MemberRole_MIN, 0, 0, 0, 0, 0, 0, _meshtastic_GeoPointSource_MIN, _meshtastic_GeoPointSource_MIN, "", "", 0, "", "", "", "", "", "", "", 0, {0}}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_GeoChat_message_tag 1
@@ -204,6 +508,42 @@ extern "C" {
#define meshtastic_TAKPacket_pli_tag 5
#define meshtastic_TAKPacket_chat_tag 6
#define meshtastic_TAKPacket_detail_tag 7
#define meshtastic_AircraftTrack_icao_tag 1
#define meshtastic_AircraftTrack_registration_tag 2
#define meshtastic_AircraftTrack_flight_tag 3
#define meshtastic_AircraftTrack_aircraft_type_tag 4
#define meshtastic_AircraftTrack_squawk_tag 5
#define meshtastic_AircraftTrack_category_tag 6
#define meshtastic_AircraftTrack_rssi_x10_tag 7
#define meshtastic_AircraftTrack_gps_tag 8
#define meshtastic_AircraftTrack_cot_host_id_tag 9
#define meshtastic_TAKPacketV2_cot_type_id_tag 1
#define meshtastic_TAKPacketV2_how_tag 2
#define meshtastic_TAKPacketV2_callsign_tag 3
#define meshtastic_TAKPacketV2_team_tag 4
#define meshtastic_TAKPacketV2_role_tag 5
#define meshtastic_TAKPacketV2_latitude_i_tag 6
#define meshtastic_TAKPacketV2_longitude_i_tag 7
#define meshtastic_TAKPacketV2_altitude_tag 8
#define meshtastic_TAKPacketV2_speed_tag 9
#define meshtastic_TAKPacketV2_course_tag 10
#define meshtastic_TAKPacketV2_battery_tag 11
#define meshtastic_TAKPacketV2_geo_src_tag 12
#define meshtastic_TAKPacketV2_alt_src_tag 13
#define meshtastic_TAKPacketV2_uid_tag 14
#define meshtastic_TAKPacketV2_device_callsign_tag 15
#define meshtastic_TAKPacketV2_stale_seconds_tag 16
#define meshtastic_TAKPacketV2_tak_version_tag 17
#define meshtastic_TAKPacketV2_tak_device_tag 18
#define meshtastic_TAKPacketV2_tak_platform_tag 19
#define meshtastic_TAKPacketV2_tak_os_tag 20
#define meshtastic_TAKPacketV2_endpoint_tag 21
#define meshtastic_TAKPacketV2_phone_tag 22
#define meshtastic_TAKPacketV2_cot_type_str_tag 23
#define meshtastic_TAKPacketV2_pli_tag 30
#define meshtastic_TAKPacketV2_chat_tag 31
#define meshtastic_TAKPacketV2_aircraft_tag 32
#define meshtastic_TAKPacketV2_raw_detail_tag 33
/* Struct field encoding specification for nanopb */
#define meshtastic_TAKPacket_FIELDLIST(X, a) \
@@ -255,12 +595,60 @@ X(a, STATIC, SINGULAR, UINT32, course, 5)
#define meshtastic_PLI_CALLBACK NULL
#define meshtastic_PLI_DEFAULT NULL
#define meshtastic_AircraftTrack_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, icao, 1) \
X(a, STATIC, SINGULAR, STRING, registration, 2) \
X(a, STATIC, SINGULAR, STRING, flight, 3) \
X(a, STATIC, SINGULAR, STRING, aircraft_type, 4) \
X(a, STATIC, SINGULAR, UINT32, squawk, 5) \
X(a, STATIC, SINGULAR, STRING, category, 6) \
X(a, STATIC, SINGULAR, SINT32, rssi_x10, 7) \
X(a, STATIC, SINGULAR, BOOL, gps, 8) \
X(a, STATIC, SINGULAR, STRING, cot_host_id, 9)
#define meshtastic_AircraftTrack_CALLBACK NULL
#define meshtastic_AircraftTrack_DEFAULT NULL
#define meshtastic_TAKPacketV2_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, cot_type_id, 1) \
X(a, STATIC, SINGULAR, UENUM, how, 2) \
X(a, STATIC, SINGULAR, STRING, callsign, 3) \
X(a, STATIC, SINGULAR, UENUM, team, 4) \
X(a, STATIC, SINGULAR, UENUM, role, 5) \
X(a, STATIC, SINGULAR, SFIXED32, latitude_i, 6) \
X(a, STATIC, SINGULAR, SFIXED32, longitude_i, 7) \
X(a, STATIC, SINGULAR, SINT32, altitude, 8) \
X(a, STATIC, SINGULAR, UINT32, speed, 9) \
X(a, STATIC, SINGULAR, UINT32, course, 10) \
X(a, STATIC, SINGULAR, UINT32, battery, 11) \
X(a, STATIC, SINGULAR, UENUM, geo_src, 12) \
X(a, STATIC, SINGULAR, UENUM, alt_src, 13) \
X(a, STATIC, SINGULAR, STRING, uid, 14) \
X(a, STATIC, SINGULAR, STRING, device_callsign, 15) \
X(a, STATIC, SINGULAR, UINT32, stale_seconds, 16) \
X(a, STATIC, SINGULAR, STRING, tak_version, 17) \
X(a, STATIC, SINGULAR, STRING, tak_device, 18) \
X(a, STATIC, SINGULAR, STRING, tak_platform, 19) \
X(a, STATIC, SINGULAR, STRING, tak_os, 20) \
X(a, STATIC, SINGULAR, STRING, endpoint, 21) \
X(a, STATIC, SINGULAR, STRING, phone, 22) \
X(a, STATIC, SINGULAR, STRING, cot_type_str, 23) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,pli,payload_variant.pli), 30) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,chat,payload_variant.chat), 31) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,aircraft,payload_variant.aircraft), 32) \
X(a, STATIC, ONEOF, BYTES, (payload_variant,raw_detail,payload_variant.raw_detail), 33)
#define meshtastic_TAKPacketV2_CALLBACK NULL
#define meshtastic_TAKPacketV2_DEFAULT NULL
#define meshtastic_TAKPacketV2_payload_variant_chat_MSGTYPE meshtastic_GeoChat
#define meshtastic_TAKPacketV2_payload_variant_aircraft_MSGTYPE meshtastic_AircraftTrack
extern const pb_msgdesc_t meshtastic_TAKPacket_msg;
extern const pb_msgdesc_t meshtastic_GeoChat_msg;
extern const pb_msgdesc_t meshtastic_Group_msg;
extern const pb_msgdesc_t meshtastic_Status_msg;
extern const pb_msgdesc_t meshtastic_Contact_msg;
extern const pb_msgdesc_t meshtastic_PLI_msg;
extern const pb_msgdesc_t meshtastic_AircraftTrack_msg;
extern const pb_msgdesc_t meshtastic_TAKPacketV2_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_TAKPacket_fields &meshtastic_TAKPacket_msg
@@ -269,14 +657,18 @@ extern const pb_msgdesc_t meshtastic_PLI_msg;
#define meshtastic_Status_fields &meshtastic_Status_msg
#define meshtastic_Contact_fields &meshtastic_Contact_msg
#define meshtastic_PLI_fields &meshtastic_PLI_msg
#define meshtastic_AircraftTrack_fields &meshtastic_AircraftTrack_msg
#define meshtastic_TAKPacketV2_fields &meshtastic_TAKPacketV2_msg
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_TAKPacket_size
#define MESHTASTIC_MESHTASTIC_ATAK_PB_H_MAX_SIZE meshtastic_TAKPacketV2_size
#define meshtastic_AircraftTrack_size 134
#define meshtastic_Contact_size 242
#define meshtastic_GeoChat_size 444
#define meshtastic_Group_size 4
#define meshtastic_PLI_size 31
#define meshtastic_Status_size 3
#define meshtastic_TAKPacketV2_size 1027
#define meshtastic_TAKPacket_size 705
#ifdef __cplusplus
+2
View File
@@ -308,6 +308,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_TDISPLAY_S3_PRO = 126,
/* Heltec Mesh Node T096 board features an nRF52840 CPU and a TFT screen. */
meshtastic_HardwareModel_HELTEC_MESH_NODE_T096 = 127,
/* Seeed studio T1000-E Pro tracker card. NRF52840 w/ LR2021 radio, GPS, button, buzzer, and sensors. */
meshtastic_HardwareModel_TRACKER_T1000_E_PRO = 128,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -150,6 +150,10 @@ typedef enum _meshtastic_PortNum {
arbitrary telemetry over meshtastic that is not covered by telemetry.proto
ENCODING: CayenneLLP */
meshtastic_PortNum_CAYENNE_APP = 77,
/* ATAK Plugin V2
Portnum for payloads from the official Meshtastic ATAK plugin using
TAKPacketV2 with zstd dictionary compression. */
meshtastic_PortNum_ATAK_PLUGIN_V2 = 78,
/* GroupAlarm integration
Used for transporting GroupAlarm-related messages between Meshtastic nodes
and companion applications/services. */
@@ -203,6 +203,10 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
default:
if (output > 0)
digitalWrite(output, (moduleConfig.external_notification.active ? on : !on));
#ifdef PCA_LED_NOTIFICATION
io.digitalWrite(PCA_LED_NOTIFICATION, on);
#endif
break;
}
+1 -1
View File
@@ -651,7 +651,7 @@ void SerialModule::processWXSerial()
LOG_INFO("WS8X : %i %.1fg%.1f %.1fv %.1fv %.1fC rain: %.1f, %i sum", atoi(windDir), strtof(windVel, nullptr),
strtof(windGust, nullptr), batVoltageF, capVoltageF, temperatureF, rain, rainSum);
}
if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis)) {
if (gotwind && !Throttle::isWithinTimespanMs(lastAveraged, averageIntervalMillis) && velCount > 0 && dirCount > 0) {
// calculate averages and send to the mesh
float velAvg = 1.0 * velSum / velCount;
+15 -29
View File
@@ -66,18 +66,10 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
#include "Sensor/MCP9808Sensor.h"
#endif
#if __has_include(<Adafruit_SHT31.h>)
#include "Sensor/SHT31Sensor.h"
#endif
#if __has_include(<Adafruit_LPS2X.h>)
#include "Sensor/LPS22HBSensor.h"
#endif
#if __has_include(<Adafruit_SHTC3.h>)
#include "Sensor/SHTC3Sensor.h"
#endif
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
#include "Sensor/RAK12035Sensor.h"
#endif
@@ -94,8 +86,8 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
#include "Sensor/OPT3001Sensor.h"
#endif
#if __has_include(<Adafruit_SHT4x.h>)
#include "Sensor/SHT4XSensor.h"
#if __has_include(<SHTSensor.h>)
#include "Sensor/SHTXXSensor.h"
#endif
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
@@ -155,6 +147,15 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
}
LOG_INFO("Environment Telemetry adding I2C devices...");
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// moduleConfig.telemetry.environment_measurement_enabled = 1;
// moduleConfig.telemetry.environment_screen_enabled = 1;
// moduleConfig.telemetry.environment_update_interval = 15;
// order by priority of metrics/values (low top, high bottom)
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
@@ -202,15 +203,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
#if __has_include(<Adafruit_MCP9808.h>)
addSensor<MCP9808Sensor>(i2cScanner, ScanI2C::DeviceType::MCP9808);
#endif
#if __has_include(<Adafruit_SHT31.h>)
addSensor<SHT31Sensor>(i2cScanner, ScanI2C::DeviceType::SHT31);
#endif
#if __has_include(<Adafruit_LPS2X.h>)
addSensor<LPS22HBSensor>(i2cScanner, ScanI2C::DeviceType::LPS22HB);
#endif
#if __has_include(<Adafruit_SHTC3.h>)
addSensor<SHTC3Sensor>(i2cScanner, ScanI2C::DeviceType::SHTC3);
#endif
#if __has_include("RAK12035_SoilMoisture.h") && defined(RAK_4631) && RAK_4631 == 1
addSensor<RAK12035Sensor>(i2cScanner, ScanI2C::DeviceType::RAK12035);
#endif
@@ -223,13 +218,9 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
#if __has_include(<ClosedCube_OPT3001.h>)
addSensor<OPT3001Sensor>(i2cScanner, ScanI2C::DeviceType::OPT3001);
#endif
#if __has_include(<Adafruit_SHT4x.h>)
addSensor<SHT4XSensor>(i2cScanner, ScanI2C::DeviceType::SHT4X);
#endif
#if __has_include(<SparkFun_MLX90632_Arduino_Library.h>)
addSensor<MLX90632Sensor>(i2cScanner, ScanI2C::DeviceType::MLX90632);
#endif
#if __has_include(<Adafruit_BMP3XX.h>)
addSensor<BMP3XXSensor>(i2cScanner, ScanI2C::DeviceType::BMP_3XX);
#endif
@@ -245,7 +236,10 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
#if __has_include(<BH1750_WE.h>)
addSensor<BH1750Sensor>(i2cScanner, ScanI2C::DeviceType::BH1750);
#endif
#if __has_include(<SHTSensor.h>)
// TODO Can we scan for multiple sensors connected on the same bus?
addSensor<SHTXXSensor>(i2cScanner, ScanI2C::DeviceType::SHTXX);
#endif
#endif
}
@@ -260,14 +254,6 @@ int32_t EnvironmentTelemetryModule::runOnce()
}
uint32_t result = UINT32_MAX;
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
*/
// moduleConfig.telemetry.environment_measurement_enabled = 1;
// moduleConfig.telemetry.environment_screen_enabled = 1;
// moduleConfig.telemetry.environment_update_interval = 15;
if (!(moduleConfig.telemetry.environment_measurement_enabled || moduleConfig.telemetry.environment_screen_enabled ||
ENVIRONMENTAL_TELEMETRY_MODULE_ENABLE)) {
@@ -1,31 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT31.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "SHT31Sensor.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHT31.h>
SHT31Sensor::SHT31Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT31, "SHT31") {}
bool SHT31Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
LOG_INFO("Init sensor: %s", sensorName);
sht31 = Adafruit_SHT31(bus);
status = sht31.begin(dev->address.address);
initI2CSensor();
return status;
}
bool SHT31Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;
measurement->variant.environment_metrics.temperature = sht31.readTemperature();
measurement->variant.environment_metrics.relative_humidity = sht31.readHumidity();
return true;
}
#endif
@@ -1,20 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT31.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHT31.h>
class SHT31Sensor : public TelemetrySensor
{
private:
Adafruit_SHT31 sht31;
public:
SHT31Sensor();
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
};
#endif
@@ -1,48 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT4x.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "SHT4XSensor.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHT4x.h>
SHT4XSensor::SHT4XSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHT4X, "SHT4X") {}
bool SHT4XSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
LOG_INFO("Init sensor: %s", sensorName);
uint32_t serialNumber = 0;
status = sht4x.begin(bus);
if (!status) {
return status;
}
serialNumber = sht4x.readSerial();
if (serialNumber != 0) {
LOG_DEBUG("serialNumber : %x", serialNumber);
status = 1;
} else {
LOG_DEBUG("Error trying to execute readSerial(): ");
status = 0;
}
initI2CSensor();
return status;
}
bool SHT4XSensor::getMetrics(meshtastic_Telemetry *measurement)
{
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;
sensors_event_t humidity, temp;
sht4x.getEvent(&humidity, &temp);
measurement->variant.environment_metrics.temperature = temp.temperature;
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
return true;
}
#endif
@@ -1,20 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHT4x.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHT4x.h>
class SHT4XSensor : public TelemetrySensor
{
private:
Adafruit_SHT4x sht4x = Adafruit_SHT4x();
public:
SHT4XSensor();
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
};
#endif
@@ -1,35 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHTC3.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "SHTC3Sensor.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHTC3.h>
SHTC3Sensor::SHTC3Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTC3, "SHTC3") {}
bool SHTC3Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
LOG_INFO("Init sensor: %s", sensorName);
status = shtc3.begin(bus);
initI2CSensor();
return status;
}
bool SHTC3Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;
sensors_event_t humidity, temp;
shtc3.getEvent(&humidity, &temp);
measurement->variant.environment_metrics.temperature = temp.temperature;
measurement->variant.environment_metrics.relative_humidity = humidity.relative_humidity;
return true;
}
#endif
@@ -1,20 +0,0 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<Adafruit_SHTC3.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <Adafruit_SHTC3.h>
class SHTC3Sensor : public TelemetrySensor
{
private:
Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
public:
SHTC3Sensor();
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
};
#endif
@@ -0,0 +1,145 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SHTSensor.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "SHTXXSensor.h"
#include "TelemetrySensor.h"
#include <SHTSensor.h>
SHTXXSensor::SHTXXSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SHTXX, "SHTXX") {}
void SHTXXSensor::getSensorVariant(SHTSensor::SHTSensorType sensorType)
{
switch (sensorType) {
case SHTSensor::SHTSensorType::SHT2X:
sensorVariant = "SHT2x";
break;
case SHTSensor::SHTSensorType::SHT3X:
case SHTSensor::SHTSensorType::SHT85:
sensorVariant = "SHT3x/SHT85";
break;
case SHTSensor::SHTSensorType::SHT3X_ALT:
sensorVariant = "SHT3x";
break;
case SHTSensor::SHTSensorType::SHTW1:
case SHTSensor::SHTSensorType::SHTW2:
case SHTSensor::SHTSensorType::SHTC1:
case SHTSensor::SHTSensorType::SHTC3:
sensorVariant = "SHTC1/SHTC3/SHTW1/SHTW2";
break;
case SHTSensor::SHTSensorType::SHT4X:
sensorVariant = "SHT4x";
break;
default:
sensorVariant = "Unknown";
break;
}
}
bool SHTXXSensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
LOG_INFO("Init sensor: %s", sensorName);
_bus = bus;
_address = dev->address.address;
if (sht.init(*_bus)) {
LOG_INFO("%s: init(): success", sensorName);
getSensorVariant(sht.mSensorType);
LOG_INFO("%s Sensor detected: %s on 0x%x", sensorName, sensorVariant, _address);
status = 1;
} else {
LOG_ERROR("%s: init(): failed", sensorName);
}
initI2CSensor();
return status;
}
/**
* Accuracy setting of measurement.
* Not all sensors support changing the sampling accuracy (only SHT3X and SHT4X)
* SHTAccuracy:
* - SHT_ACCURACY_HIGH: Highest repeatability at the cost of slower measurement
* - SHT_ACCURACY_MEDIUM: Balanced repeatability and speed of measurement
* - SHT_ACCURACY_LOW: Fastest measurement but lowest repeatability
*/
bool SHTXXSensor::setAccuracy(SHTSensor::SHTAccuracy newAccuracy)
{
// Only SHT3X-family (including alternates) and SHT4X support changing accuracy
if (sht.mSensorType != SHTSensor::SHTSensorType::SHT3X && sht.mSensorType != SHTSensor::SHTSensorType::SHT3X_ALT &&
sht.mSensorType != SHTSensor::SHTSensorType::SHT85 && sht.mSensorType != SHTSensor::SHTSensorType::SHT4X) {
LOG_WARN("%s doesn't support accuracy setting", sensorVariant);
return false;
}
LOG_INFO("%s: setting new accuracy setting", sensorVariant);
accuracy = newAccuracy;
return sht.setAccuracy(accuracy);
}
bool SHTXXSensor::getMetrics(meshtastic_Telemetry *measurement)
{
if (sht.readSample()) {
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;
measurement->variant.environment_metrics.temperature = sht.getTemperature();
measurement->variant.environment_metrics.relative_humidity = sht.getHumidity();
LOG_INFO("%s (%s): Got: temp:%fdegC, hum:%f%%rh", sensorName, sensorVariant,
measurement->variant.environment_metrics.temperature,
measurement->variant.environment_metrics.relative_humidity);
return true;
} else {
LOG_ERROR("%s (%s): read sample failed", sensorName, sensorVariant);
return false;
}
}
AdminMessageHandleResult SHTXXSensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response)
{
AdminMessageHandleResult result;
result = AdminMessageHandleResult::NOT_HANDLED;
switch (request->which_payload_variant) {
case meshtastic_AdminMessage_sensor_config_tag:
if (!request->sensor_config.has_shtxx_config) {
result = AdminMessageHandleResult::NOT_HANDLED;
break;
}
// Check for sensor accuracy setting
if (request->sensor_config.shtxx_config.has_set_accuracy) {
SHTSensor::SHTAccuracy newAccuracy;
if (request->sensor_config.shtxx_config.set_accuracy == 0) {
newAccuracy = SHTSensor::SHT_ACCURACY_LOW;
} else if (request->sensor_config.shtxx_config.set_accuracy == 1) {
newAccuracy = SHTSensor::SHT_ACCURACY_MEDIUM;
} else if (request->sensor_config.shtxx_config.set_accuracy == 2) {
newAccuracy = SHTSensor::SHT_ACCURACY_HIGH;
} else {
LOG_ERROR("%s: incorrect accuracy setting", sensorName);
result = AdminMessageHandleResult::HANDLED;
break;
}
this->setAccuracy(newAccuracy);
}
result = AdminMessageHandleResult::HANDLED;
break;
default:
result = AdminMessageHandleResult::NOT_HANDLED;
}
return result;
}
#endif
@@ -0,0 +1,29 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<SHTSensor.h>)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#include <SHTSensor.h>
class SHTXXSensor : public TelemetrySensor
{
private:
SHTSensor sht;
TwoWire *_bus{};
uint8_t _address{};
SHTSensor::SHTAccuracy accuracy{};
bool setAccuracy(SHTSensor::SHTAccuracy newAccuracy);
public:
SHTXXSensor();
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
void getSensorVariant(SHTSensor::SHTSensorType);
const char *sensorVariant{};
AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request,
meshtastic_AdminMessage *response) override;
};
#endif
+2 -2
View File
@@ -321,8 +321,8 @@ bool connectPubSub(const PubSubConfig &config, PubSubClient &pubSub, Client &cli
pubSub.setClient(client);
pubSub.setServer(config.serverAddr.c_str(), config.serverPort);
LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: %s", config.serverAddr.c_str(),
config.serverPort, config.mqttUsername, config.mqttPassword);
LOG_INFO("Connecting directly to MQTT server %s, port: %d, username: %s, password: ***", config.serverAddr.c_str(),
config.serverPort, config.mqttUsername);
// Generate node ID from nodenum for client identification
std::string nodeId = nodeDB->getNodeId();
+3 -1
View File
@@ -232,7 +232,9 @@ void cpuDeepSleep(uint32_t msecToWake)
#if SOC_RTCIO_HOLD_SUPPORTED && SOC_PM_SUPPORT_EXT_WAKEUP
uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
#endif
#ifdef ALT_BUTTON_WAKE
gpioMask |= (1ULL << BUTTON_PIN_ALT);
#endif
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)BUTTON_PIN);
#endif
@@ -23,5 +23,6 @@ void lateInitVariant()
cfg.i2s.bits = BIT_LENGTH_16BITS;
cfg.i2s.rate = RATE_44K;
board.begin(cfg);
board.setVolume(75); // 75% volume
}
#endif
+11
View File
@@ -0,0 +1,11 @@
.globl HardFault_Handler
.syntax unified
.thumb
.type HardFault_Handler, %function
HardFault_Handler:
tst lr, #4
ite eq
mrseq r0, msp
mrsne r0, psp
b HardFault_Handler_C
+97 -1
View File
@@ -1,5 +1,6 @@
#include "RTC.h"
#include "configuration.h"
#include <stdarg.h>
#include <stm32wle5xx.h>
#include <stm32wlxx_hal.h>
@@ -53,4 +54,99 @@ extern "C" void __wrap__tzset_unlocked_r(struct _reent *reent_ptr)
{
return;
}
#endif
#endif
// Taken from https://interrupt.memfault.com/blog/cortex-m-hardfault-debug
typedef struct __attribute__((packed)) ContextStateFrame {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t return_address;
uint32_t xpsr;
} sContextStateFrame;
// NOTE: If you are using CMSIS, the registers can also be
// accessed through CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk
#define HALT_IF_DEBUGGING() \
do { \
if ((*(volatile uint32_t *)0xE000EDF0) & (1 << 0)) { \
__asm("bkpt 1"); \
} \
} while (0)
static char hardfault_message_buffer[256];
// printf directly using srcwrapper's debug UART function.
static void debug_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
int length = vsnprintf(hardfault_message_buffer, sizeof(hardfault_message_buffer), format, args);
va_end(args);
if (length < 0)
return;
uart_debug_write((uint8_t *)hardfault_message_buffer, min((unsigned int)length, sizeof(hardfault_message_buffer) - 1));
}
// N picked by guessing
#define DOT_TIME 1200000
static void dot()
{
digitalWrite(LED_POWER, LED_STATE_ON);
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
}
digitalWrite(LED_POWER, LED_STATE_OFF);
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
}
}
static void dash()
{
digitalWrite(LED_POWER, LED_STATE_ON);
for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */
}
digitalWrite(LED_POWER, LED_STATE_OFF);
for (volatile int i = 0; i < DOT_TIME; i++) { /* busy wait */
}
}
static void space()
{
for (volatile int i = 0; i < (DOT_TIME * 3); i++) { /* busy wait */
}
}
// Disable optimizations for this function so "frame" argument
// does not get optimized away
extern "C" __attribute__((optimize("O0"))) void HardFault_Handler_C(sContextStateFrame *frame)
{
debug_printf("HardFault!\r\n");
debug_printf("r0: %08x\r\n", frame->r0);
debug_printf("r1: %08x\r\n", frame->r1);
debug_printf("r2: %08x\r\n", frame->r2);
debug_printf("r3: %08x\r\n", frame->r3);
debug_printf("r12: %08x\r\n", frame->r12);
debug_printf("lr: %08x\r\n", frame->lr);
debug_printf("pc[return address]: %08x\r\n", frame->return_address);
debug_printf("xpsr: %08x\r\n", frame->xpsr);
HALT_IF_DEBUGGING();
// blink SOS forever
while (1) {
dot();
dot();
dot();
dash();
dash();
dash();
dot();
dot();
dot();
space();
}
}