mirror of
https://github.com/meshtastic/firmware.git
synced 2026-05-19 14:25:28 -04:00
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:
@@ -31,5 +31,6 @@ basename=meshtasticd-$1-$VERSION
|
||||
pio pkg install --environment "$PIO_ENV" || platformioFailed
|
||||
pio run --environment "$PIO_ENV" || platformioFailed
|
||||
|
||||
cp "$BUILDDIR/meshtasticd" "$OUTDIR/meshtasticd_linux_$(uname -m)"
|
||||
os_name=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
cp "$BUILDDIR/meshtasticd" "$OUTDIR/meshtasticd_${os_name}_$(uname -m)"
|
||||
cp bin/native-install.* $OUTDIR/
|
||||
|
||||
@@ -781,8 +781,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,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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
#include "configuration.h"
|
||||
#include "detect/LoRaRadioType.h"
|
||||
|
||||
// Sentinel marking the end of a modem preset array
|
||||
static constexpr meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END =
|
||||
// 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
|
||||
|
||||
@@ -119,7 +119,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
|
||||
|
||||
@@ -220,7 +220,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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[portduino_base]
|
||||
platform =
|
||||
# renovate: datasource=git-refs depName=platform-native packageName=https://github.com/meshtastic/platform-native gitBranch=develop
|
||||
https://github.com/meshtastic/platform-native/archive/135b91e953db0b5f44d278f8ebd5b8d985fc03d8.zip
|
||||
https://github.com/meshtastic/platform-native/archive/4ea5e09ac7d51a593e12ec7c1ebb6cd06745ce53.zip
|
||||
framework = arduino
|
||||
|
||||
build_src_filter =
|
||||
@@ -37,25 +37,35 @@ lib_deps =
|
||||
# renovate: datasource=github-tags depName=Adafruit_BME680 packageName=adafruit/Adafruit_BME680
|
||||
https://github.com/adafruit/Adafruit_BME680/archive/refs/tags/2.0.6.zip
|
||||
|
||||
build_flags =
|
||||
; Cross-platform build flags shared between native (Linux) and native-macos builds.
|
||||
; Anything Linux-only (libbluetooth, libgpiod, libi2c, /sys/class/gpio,
|
||||
; PORTDUINO_LINUX_HARDWARE, glibc-style _FORTIFY_SOURCE) goes in `build_flags`
|
||||
; instead. UDP multicast also lives there because the firmware's
|
||||
; UdpMulticastHandler.h unconditionally `#include <WiFi.h>` on non-NRF52
|
||||
; targets, which requires the framework's bundled WiFi shim that we
|
||||
; lib_ignore on macOS.
|
||||
build_flags_common =
|
||||
${arduino_base.build_flags}
|
||||
-D ARCH_PORTDUINO
|
||||
-fPIC
|
||||
-D_FORTIFY_SOURCE=2
|
||||
-fstack-protector-all -Wstack-protector --param ssp-buffer-size=4
|
||||
-Isrc/platform/portduino
|
||||
-DRADIOLIB_EEPROM_UNSUPPORTED
|
||||
-DPORTDUINO_LINUX_HARDWARE
|
||||
-DHAS_UDP_MULTICAST=1
|
||||
-lpthread
|
||||
-lstdc++fs
|
||||
-lbluetooth
|
||||
-lgpiod
|
||||
-lyaml-cpp
|
||||
-li2c
|
||||
-luv
|
||||
-std=gnu17
|
||||
-std=gnu++17
|
||||
|
||||
build_flags =
|
||||
${portduino_base.build_flags_common}
|
||||
-DHAS_UDP_MULTICAST=1
|
||||
-D_FORTIFY_SOURCE=2
|
||||
-fstack-protector-all -Wstack-protector --param ssp-buffer-size=4
|
||||
-DPORTDUINO_LINUX_HARDWARE
|
||||
-lstdc++fs
|
||||
-lbluetooth
|
||||
-lgpiod
|
||||
-li2c
|
||||
lib_ignore =
|
||||
Adafruit NeoPixel
|
||||
Adafruit ST7735 and ST7789 Library
|
||||
|
||||
@@ -117,3 +117,59 @@ build_flags = -lgcov --coverage -fprofile-abs-path -fsanitize=address ${env:nati
|
||||
test_testing_command =
|
||||
${platformio.build_dir}/${this.__env__}/meshtasticd
|
||||
-s
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
; Native build for macOS (Darwin / arm64 + x86_64). Headless meshtasticd that
|
||||
; runs in SimRadio mode (`-s`) or against real LoRa hardware via a CH341
|
||||
; USB-SPI bridge. No BlueZ, libgpiod, or Linux I2C — those require Linux.
|
||||
;
|
||||
; Prerequisites (Homebrew):
|
||||
; brew install platformio yaml-cpp libuv openssl@3 libusb argp-standalone pkg-config
|
||||
;
|
||||
; The macOS-side patches now live upstream:
|
||||
; * meshtastic/platform-native — `String.h`-shadow shim, `-Wno-enum-constexpr-conversion`,
|
||||
; empty-variant-dir guard. Pulled via `portduino_base.platform` zip pin.
|
||||
; * meshtastic/framework-portduino — LinuxHardwareI2C macOS stubs, AsyncUDP
|
||||
; SOCK_NONBLOCK fallback, Common.h __APPLE__ guard, WiFiServer.cpp extern-C
|
||||
; fix, package.json URL refresh. Pulled by platform-native at its pinned commit.
|
||||
; This env therefore only carries the firmware-side build flags and src filter.
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:native-macos]
|
||||
extends = native_base
|
||||
; Apple's ld doesn't accept GNU ld's `-Wl,-Map,<file>` syntax (inherited from
|
||||
; the top-level platformio.ini). Strip it; the linker map isn't useful for
|
||||
; the macOS dev loop anyway, and Apple ld's equivalent (`-Wl,-map,<file>`)
|
||||
; uses different argument shape.
|
||||
build_unflags = -Wl,-Map,"${platformio.build_dir}"/output.map
|
||||
build_flags = ${portduino_base.build_flags_common}
|
||||
-I variants/native/portduino
|
||||
-I/opt/homebrew/include
|
||||
-I/opt/homebrew/opt/argp-standalone/include
|
||||
-I/opt/homebrew/opt/yaml-cpp/include
|
||||
-L/opt/homebrew/lib
|
||||
-L/opt/homebrew/opt/argp-standalone/lib
|
||||
-L/opt/homebrew/opt/yaml-cpp/lib
|
||||
-largp
|
||||
-DPORTDUINO_DARWIN
|
||||
; Headless build — variants/native/portduino/variant.h would otherwise
|
||||
; default HAS_SCREEN to 1 and pull in screen-renderer source that uses
|
||||
; VLA-with-initializer (a GNU/GCC extension Apple Clang rejects).
|
||||
; MESHTASTIC_EXCLUDE_SCREEN gates the optional `screen->setHeading(...)`-
|
||||
; style screen-driver hooks scattered through sensor sources.
|
||||
-DHAS_SCREEN=0
|
||||
-DMESHTASTIC_EXCLUDE_SCREEN=1
|
||||
!pkg-config --libs openssl --silence-errors || :
|
||||
; src/input/Linux*.{cpp,h} drive evdev (`<linux/input.h>`) which doesn't exist
|
||||
; on macOS. graphics/Panel_sdl.* and graphics/TFTDisplay.cpp pull LovyanGFX
|
||||
; (which we lib_ignore on macOS for the <malloc.h> issue). Neither is needed
|
||||
; for the headless build.
|
||||
build_src_filter = ${native_base.build_src_filter}
|
||||
-<input/LinuxInput.cpp>
|
||||
-<input/LinuxInputImpl.cpp>
|
||||
-<graphics/Panel_sdl.cpp>
|
||||
-<graphics/TFTDisplay.cpp>
|
||||
; LovyanGFX includes <malloc.h> (Linux-only) and is only needed by TFT
|
||||
; variants — not relevant for the headless macOS build.
|
||||
lib_ignore =
|
||||
${portduino_base.lib_ignore}
|
||||
LovyanGFX
|
||||
|
||||
Reference in New Issue
Block a user