Native MacOS hello world (#10309)

* Native MacOS hello world

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update variants/native/portduino/platformio.ini

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: ensure null-termination in getSerialString() and handle len==0

Agent-Logs-Url: https://github.com/meshtastic/firmware/sessions/e5647919-2255-48ad-bcaa-7a2c2fdbf212

Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Ben Meadors
2026-04-27 07:07:49 -05:00
co-authored by Jonathan Bennett Copilot copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
parent 47a6c4c6a0
commit 126861fd16
15 changed files with 151 additions and 26 deletions
+2
View File
@@ -755,8 +755,10 @@ void Power::reboot()
rp2040.reboot();
#elif defined(ARCH_PORTDUINO)
deInitApiServer();
#ifdef __linux__
if (aLinuxInputImpl)
aLinuxInputImpl->deInit();
#endif
SPI.end();
Wire.end();
Serial1.end();
+1 -1
View File
@@ -1,8 +1,8 @@
#pragma once
#include "../freertosinc.h"
#include "Print.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
#include <Print.h>
#include <stdarg.h>
#include <string>
+3
View File
@@ -390,8 +390,11 @@ void InputBroker::Init()
seesawRotary = nullptr;
}
}
#ifdef __linux__
// Linux evdev keyboard input only — macOS has no <linux/input.h>.
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
#endif
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
+4 -1
View File
@@ -1,5 +1,8 @@
#pragma once
#if ARCH_PORTDUINO
// Linux evdev keyboard input. Only compiled on Linux portduino targets;
// macOS / non-Linux builds have no <linux/input.h> or epoll, and the
// headless build doesn't need real keyboards anyway.
#if ARCH_PORTDUINO && defined(__linux__)
#include "InputBroker.h"
#include "concurrency/OSThread.h"
#include <assert.h>
+2 -1
View File
@@ -1,4 +1,5 @@
#ifdef ARCH_PORTDUINO
// Linux evdev impl. Same Linux-only gating as LinuxInput.h.
#if defined(ARCH_PORTDUINO) && defined(__linux__)
#pragma once
#include "LinuxInput.h"
#include "main.h"
+11 -1
View File
@@ -19,8 +19,12 @@ extern Adafruit_nRFCrypto nRFCrypto;
#include <Arduino.h>
#elif defined(ARCH_PORTDUINO)
#include <random>
#include <sys/random.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/random.h> // getrandom()
#else
#include <stdlib.h> // arc4random_buf() on Darwin/BSD
#endif
#endif
namespace HardwareRNG
@@ -119,10 +123,16 @@ bool fill(uint8_t *buffer, size_t length, bool useRadioEntropy)
filled = true;
#elif defined(ARCH_PORTDUINO)
// Prefer the host OS RNG first when running under Portduino.
#ifdef __linux__
ssize_t generated = ::getrandom(buffer, length, 0);
if (generated == static_cast<ssize_t>(length)) {
filled = true;
}
#else
// arc4random_buf is available on Darwin/BSD and cannot fail.
::arc4random_buf(buffer, length);
filled = true;
#endif
if (!filled) {
fillWithRandomDevice(buffer, length);
+27
View File
@@ -6,6 +6,33 @@
#include "configuration.h"
#include "detect/LoRaRadioType.h"
// Sentinel marking the end of a modem preset array. Declared `const` rather
// than `constexpr` because the cast from 0xFF to the enum is out-of-range and
// therefore not a valid constant expression on Clang 16+ (Apple Clang on
// macOS). The value is only ever compared at runtime, so static-init is fine.
static const meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END =
static_cast<meshtastic_Config_LoRaConfig_ModemPreset>(0xFF);
// Region profile: bundles the preset list with regulatory parameters shared across regions
struct RegionProfile {
const meshtastic_Config_LoRaConfig_ModemPreset *presets; // sentinel-terminated; first entry is the default
float spacing; // gaps between radio channels
float padding; // padding at each side of the "operating channel"
bool audioPermitted;
bool licensedOnly; // a region profile for licensed operators only
int8_t textThrottle; // throttle for text - future expansion
int8_t positionThrottle; // throttle for location data - future expansion
int8_t telemetryThrottle; // throttle for telemetry - future expansion
uint8_t overrideSlot; // a per-region override slot for if we need to fix it in place
};
extern const RegionProfile PROFILE_STD;
extern const RegionProfile PROFILE_EU868;
extern const RegionProfile PROFILE_UNDEF;
// extern const RegionProfile PROFILE_LITE;
// extern const RegionProfile PROFILE_NARROW;
// extern const RegionProfile PROFILE_HAM;
// Map from old region names to new region enums
struct RegionInfo {
meshtastic_Config_LoRaConfig_RegionCode code;
+1 -1
View File
@@ -109,7 +109,7 @@ bool RadioLibInterface::canSendImmediately()
return true;
}
bool RadioLibInterface::receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag)
bool RadioLibInterface::receiveDetected(uint16_t irq, unsigned long syncWordHeaderValidFlag, unsigned long preambleDetectedFlag)
{
bool detected = (irq & (syncWordHeaderValidFlag | preambleDetectedFlag));
// Handle false detections
+1 -1
View File
@@ -213,7 +213,7 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified
protected:
uint32_t activeReceiveStart = 0;
bool receiveDetected(uint16_t irq, ulong syncWordHeaderValidFlag, ulong preambleDetectedFlag);
bool receiveDetected(uint16_t irq, unsigned long syncWordHeaderValidFlag, unsigned long preambleDetectedFlag);
/** Do any hardware setup needed on entry into send configuration for the radio.
* Subclasses can customize, but must also call this base method */
+1 -1
View File
@@ -32,7 +32,7 @@
#include <assert.h>
#include <utility>
#include <IPAddress.h>
#include "IPAddress.h"
#if defined(ARCH_PORTDUINO)
#include <netinet/in.h>
#elif !defined(ntohl)
+13 -5
View File
@@ -9,13 +9,10 @@
#include "PortduinoGlue.h"
#include "SHA256.h"
#include "api/ServerAPI.h"
#include "linux/gpio/LinuxGPIOPin.h"
#include "meshUtils.h"
#include <ErriezCRC32.h>
#include <Utility.h>
#include <assert.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <filesystem>
#include <fstream>
#include <iostream>
@@ -25,6 +22,12 @@
#include <sys/ioctl.h>
#include <unistd.h>
#ifdef PORTDUINO_LINUX_HARDWARE
#include "linux/gpio/LinuxGPIOPin.h"
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#endif
#ifdef PORTDUINO_LINUX_HARDWARE
#include <cxxabi.h>
#endif
@@ -130,9 +133,9 @@ void getMacAddr(uint8_t *dmac)
}
} else if (portduino_config.mac_address.length() > 11) {
MAC_from_string(portduino_config.mac_address, dmac);
exit;
return;
} else {
#ifdef PORTDUINO_LINUX_HARDWARE
struct hci_dev_info di = {0};
di.dev_id = 0;
bdaddr_t bdaddr;
@@ -152,6 +155,11 @@ void getMacAddr(uint8_t *dmac)
dmac[3] = di.bdaddr.b[2];
dmac[4] = di.bdaddr.b[1];
dmac[5] = di.bdaddr.b[0];
#else
// No BlueZ on non-Linux hosts (e.g. macOS). Leave dmac at its default;
// the caller can override via the --hwid CLI flag or the YAML config.
(void)dmac;
#endif
}
}
+7 -3
View File
@@ -5,6 +5,7 @@
#include "platform/portduino/PortduinoGlue.h"
#include <RadioLib.h>
#include <csignal>
#include <cstring>
#include <iostream>
#include <libpinedio-usb.h>
#include <unistd.h>
@@ -34,7 +35,7 @@ class Ch341Hal : public RadioLibHal
: RadioLibHal(PI_INPUT, PI_OUTPUT, PI_LOW, PI_HIGH, PI_RISING, PI_FALLING)
{
if (serial != "") {
strncpy(pinedio.serial_number, serial.c_str(), 8);
std::strncpy(pinedio.serial_number, serial.c_str(), 8);
pinedio_set_option(&pinedio, PINEDIO_OPTION_SEARCH_SERIAL, 1);
}
// LOG_INFO("USB Serial: %s", pinedio.serial_number);
@@ -59,8 +60,11 @@ class Ch341Hal : public RadioLibHal
void getSerialString(char *_serial, size_t len)
{
len = len > 8 ? 8 : len;
strncpy(_serial, pinedio.serial_number, len);
if (len == 0)
return;
size_t bytesCopied = (len - 1) < 8 ? (len - 1) : 8;
std::strncpy(_serial, pinedio.serial_number, bytesCopied);
_serial[bytesCopied] = '\0';
}
void getProductString(char *_product_string, size_t len)