Merge remote-tracking branch 'origin/master' into meshtastic-ota

This commit is contained in:
Ben Meadors
2026-01-14 16:11:53 -06:00
368 changed files with 12974 additions and 3213 deletions

View File

@@ -195,6 +195,8 @@
#define HW_VENDOR meshtastic_HardwareModel_LINK_32
#elif defined(T_DECK_PRO)
#define HW_VENDOR meshtastic_HardwareModel_T_DECK_PRO
#elif defined(T_BEAM_1W)
#define HW_VENDOR meshtastic_HardwareModel_TBEAM_1_WATT
#elif defined(T_LORA_PAGER)
#define HW_VENDOR meshtastic_HardwareModel_T_LORA_PAGER
#elif defined(HELTEC_V4)

View File

@@ -66,6 +66,8 @@
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
#elif defined(T_ECHO_LITE)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE
#elif defined(TTGO_T_ECHO_PLUS)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS
#elif defined(ELECROW_ThinkNode_M1)
#define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1
#elif defined(ELECROW_ThinkNode_M3)

View File

@@ -6,6 +6,7 @@
#include "target_specific.h"
#include "PortduinoGlue.h"
#include "SHA256.h"
#include "api/ServerAPI.h"
#include "linux/gpio/LinuxGPIOPin.h"
#include "meshUtils.h"
@@ -270,7 +271,39 @@ void portduinoSetup()
}
std::cout << "autoconf: Found Pi HAT+ " << hat_vendor << " " << autoconf_product << " at /proc/device-tree/hat"
<< std::endl;
found_hat = true;
// potential TODO: Validate that this is a real UUID
std::ifstream hatUUID("/proc/device-tree/hat/uuid");
char uuid[38] = {0};
if (hatUUID.is_open()) {
hatUUID.read(uuid, 37);
hatUUID.close();
std::cout << "autoconf: UUID " << uuid << std::endl;
SHA256 uuid_hash;
uint8_t uuid_hash_bytes[32] = {0};
uuid_hash.reset();
uuid_hash.update(uuid, 37);
uuid_hash.finalize(uuid_hash_bytes, 32);
for (int j = 0; j < 16; j++) {
portduino_config.device_id[j] = uuid_hash_bytes[j];
}
portduino_config.has_device_id = true;
uint8_t dmac[6] = {0};
dmac[0] = (uuid_hash_bytes[17] << 4) | 2;
dmac[1] = uuid_hash_bytes[18];
dmac[2] = uuid_hash_bytes[19];
dmac[3] = uuid_hash_bytes[20];
dmac[4] = uuid_hash_bytes[21];
dmac[5] = uuid_hash_bytes[22];
char macBuf[13] = {0};
snprintf(macBuf, sizeof(macBuf), "%02X%02X%02X%02X%02X%02X", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
dmac[5]);
portduino_config.mac_address = macBuf;
found_hat = true;
}
} else {
std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat" << std::endl;
}
@@ -279,7 +312,7 @@ void portduinoSetup()
// RAK6421-13300-S1:aabbcc123456:5ba85807d92138b7519cfb60460573af:3061e8d8
// <model string>:mac address :<16 random unique bytes in hexidecimal> : crc32
// crc32 is calculated on the eeprom string up to but not including the final colon
if (strlen(autoconf_product) < 6) {
if (strlen(autoconf_product) < 6 && portduino_config.i2cdev != "") {
try {
char *mac_start = nullptr;
char *devID_start = nullptr;
@@ -366,6 +399,14 @@ void portduinoSetup()
cleanupNameForAutoconf("lora-hat-" + std::string(hat_vendor) + "-" + autoconf_product + ".yaml");
} else if (found_ch341) {
product_config = cleanupNameForAutoconf("lora-usb-" + std::string(autoconf_product) + ".yaml");
// look for more data after the null terminator
size_t len = strlen(autoconf_product);
if (len < 74) {
memcpy(portduino_config.device_id, autoconf_product + len + 1, 16);
if (!memfll(portduino_config.device_id, '\0', 16) && !memfll(portduino_config.device_id, 0xff, 16)) {
portduino_config.has_device_id = true;
}
}
}
// Don't try to automatically find config for a device with RAK eeprom.
@@ -411,9 +452,11 @@ void portduinoSetup()
ch341Hal->getProductString(product_string, 95);
std::cout << "CH341 Product " << product_string << std::endl;
if (strlen(serial) == 8 && portduino_config.mac_address.length() < 12) {
uint8_t hash[32] = {0};
std::cout << "Deriving MAC address from Serial and Product String" << std::endl;
uint8_t hash[104] = {0};
memcpy(hash, serial, 8);
crypto->hash(hash, 8);
memcpy(hash + 8, product_string, strlen(product_string));
crypto->hash(hash, 8 + strlen(product_string));
dmac[0] = (hash[0] << 4) | 2;
dmac[1] = hash[1];
dmac[2] = hash[2];
@@ -427,11 +470,13 @@ void portduinoSetup()
}
getMacAddr(dmac);
#ifndef UNIT_TEST
if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) {
std::cout << "*** Blank MAC Address not allowed!" << std::endl;
std::cout << "Please set a MAC Address in config.yaml using either MACAddress or MACAddressSource." << std::endl;
exit(EXIT_FAILURE);
}
#endif
printf("MAC ADDRESS: %02X:%02X:%02X:%02X:%02X:%02X\n", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);
// Rather important to set this, if not running simulated.
randomSeed(time(NULL));
@@ -442,6 +487,11 @@ void portduinoSetup()
max_GPIO = i->pin;
}
for (auto i : portduino_config.extra_pins) {
if (i.enabled && i.pin > max_GPIO)
max_GPIO = i.pin;
}
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
// Need to bind all the configured GPIO pins so they're not simulated
@@ -459,6 +509,19 @@ void portduinoSetup()
}
}
}
for (auto i : portduino_config.extra_pins) {
// In the case of a ch341 Lora device, we don't want to touch the system GPIO lines for Lora
// Those GPIO are handled in our usermode driver instead.
if (i.config_section == "Lora" && portduino_config.lora_spi_dev == "ch341") {
continue;
}
if (i.enabled) {
if (initGPIOPin(i.pin, gpioChipName + std::to_string(i.gpiochip), i.line) != ERRNO_OK) {
printf("Error setting pin number %d. It may not exist, or may already be in use.\n", i.line);
exit(EXIT_FAILURE);
}
}
}
// Only initialize the radio pins when dealing with real, kernel controlled SPI hardware
if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") {
@@ -672,6 +735,16 @@ bool loadConfig(const char *configPath)
portduino_config.has_gps = 1;
}
}
if (yamlConfig["GPIO"]["ExtraPins"]) {
for (auto extra_pin : yamlConfig["GPIO"]["ExtraPins"]) {
portduino_config.extra_pins.push_back(pinMapping());
portduino_config.extra_pins.back().config_section = "GPIO";
portduino_config.extra_pins.back().config_name = "ExtraPins";
portduino_config.extra_pins.back().enabled = true;
readGPIOFromYaml(extra_pin, portduino_config.extra_pins.back());
}
}
if (yamlConfig["I2C"]) {
portduino_config.i2cdev = yamlConfig["I2C"]["I2CDevice"].as<std::string>("");
}
@@ -867,4 +940,4 @@ void readGPIOFromYaml(YAML::Node sourceNode, pinMapping &destPin, int pinDefault
destPin.line = destPin.pin;
destPin.gpiochip = portduino_config.lora_default_gpiochip;
}
}
}

View File

@@ -2,6 +2,7 @@
#include <fstream>
#include <map>
#include <unordered_map>
#include <vector>
#include "LR11x0Interface.h"
#include "Module.h"
@@ -97,6 +98,7 @@ extern struct portduino_config_struct {
pinMapping lora_txen_pin = {"Lora", "TXen"};
pinMapping lora_rxen_pin = {"Lora", "RXen"};
pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"};
std::vector<pinMapping> extra_pins = {};
// GPS
bool has_gps = false;
@@ -300,6 +302,20 @@ extern struct portduino_config_struct {
}
out << YAML::EndMap; // Lora
if (!extra_pins.empty()) {
out << YAML::Key << "GPIO" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "ExtraPins" << YAML::Value << YAML::BeginSeq;
for (auto extra : extra_pins) {
out << YAML::BeginMap;
out << YAML::Key << "pin" << YAML::Value << extra.pin;
out << YAML::Key << "line" << YAML::Value << extra.line;
out << YAML::Key << "gpiochip" << YAML::Value << extra.gpiochip;
out << YAML::EndMap;
}
out << YAML::EndSeq;
out << YAML::EndMap; // GPIO
}
if (i2cdev != "") {
out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap;
out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev;

View File

@@ -64,7 +64,7 @@ class Ch341Hal : public RadioLibHal
void getProductString(char *_product_string, size_t len)
{
len = len > 95 ? 95 : len;
strncpy(_product_string, pinedio.product_string, len);
memcpy(_product_string, pinedio.product_string, len);
}
void init() override {}