mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-04 03:18:10 +10:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce0942e08a | ||
|
|
9c72767c01 | ||
|
|
1e32c94e81 | ||
|
|
96085b11bd | ||
|
|
c0425d7444 | ||
|
|
d7db0f5829 |
@@ -0,0 +1,51 @@
|
||||
name: Build MacOS Binary
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
macos_ver:
|
||||
required: false
|
||||
default: "26" # ARM64
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-MacOS:
|
||||
runs-on: macos-${{ inputs.macos_ver }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install deps
|
||||
shell: bash
|
||||
run: |
|
||||
brew update
|
||||
brew install platformio yaml-cpp libuv openssl@3 libusb argp-standalone pkg-config
|
||||
|
||||
- name: Get release version string
|
||||
run: |
|
||||
echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
|
||||
- name: Build for MacOS
|
||||
run: |
|
||||
platformio run -e native-macos
|
||||
env:
|
||||
PKG_VERSION: ${{ steps.version.outputs.long }}
|
||||
# Errors in this step should not fail the entire workflow while MacOS support is in development.
|
||||
continue-on-error: true
|
||||
|
||||
- name: List output files
|
||||
run: ls -lah .pio/build/native-macos/
|
||||
|
||||
- name: Store binaries as an artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: firmware-macos-${{ inputs.macos_ver }}-${{ steps.version.outputs.long }}
|
||||
overwrite: true
|
||||
path: |
|
||||
.pio/build/native-macos/meshtasticd
|
||||
@@ -116,6 +116,20 @@ jobs:
|
||||
build_location: local
|
||||
secrets: inherit
|
||||
|
||||
MacOS:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
macos_ver:
|
||||
- "26" # ARM64
|
||||
# - '26-intel' # x86_64
|
||||
- "15" # ARM64
|
||||
# - '15-intel' # x86_64
|
||||
uses: ./.github/workflows/build_macos_bin.yml
|
||||
with:
|
||||
macos_ver: ${{ matrix.macos_ver }}
|
||||
# secrets: inherit
|
||||
|
||||
package-pio-deps-native-tft:
|
||||
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/package_pio_deps.yml
|
||||
@@ -286,6 +300,7 @@ jobs:
|
||||
- gather-artifacts
|
||||
- build-debian-src
|
||||
- package-pio-deps-native-tft
|
||||
# - MacOS
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld",
|
||||
"partitions": "default_16MB.csv",
|
||||
"memory_type": "qio_opi"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DBOARD_HAS_PSRAM",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=1",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "qio",
|
||||
"psram_type": "opi",
|
||||
"hwids": [["0x303A", "0x1001"]],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "heltec_v4_r8"
|
||||
},
|
||||
"connectivity": ["wifi", "bluetooth", "lora"],
|
||||
"debug": {
|
||||
"default_tool": "esp-builtin",
|
||||
"onboard_tools": ["esp-builtin"],
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": ["arduino", "espidf"],
|
||||
"name": "heltec_wifi_lora_32 v4 r8 (16 MB FLASH, 8 MB PSRAM)",
|
||||
"upload": {
|
||||
"flash_size": "16MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 16777216,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "https://heltec.org/",
|
||||
"vendor": "heltec"
|
||||
}
|
||||
@@ -157,6 +157,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#elif defined(HELTEC_MESH_NODE_T096)
|
||||
#define NUM_PA_POINTS 22
|
||||
#define TX_GAIN_LORA 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 12, 11, 10, 9, 8, 7
|
||||
#elif defined(HELTEC_V4_R8)
|
||||
#define NUM_PA_POINTS 22
|
||||
#define TX_GAIN_LORA 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7
|
||||
#else
|
||||
// If a board enables USE_KCT8103L_PA but does not match a known variant and has
|
||||
// not already provided a PA curve, fail at compile time to avoid unsafe defaults.
|
||||
|
||||
@@ -428,7 +428,7 @@ static LGFX *tft = nullptr;
|
||||
|
||||
#elif defined(ST7789_CS)
|
||||
#include <LovyanGFX.hpp> // Graphics and font library for ST7735 driver chip
|
||||
#ifdef HELTEC_V4_TFT
|
||||
#if defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT)
|
||||
#include "chsc6x.h"
|
||||
#include "lgfx/v1/Touch.hpp"
|
||||
namespace lgfx
|
||||
@@ -450,7 +450,11 @@ class TOUCH_CHSC6X : public ITouch
|
||||
bool init(void) override
|
||||
{
|
||||
if (chsc6xTouch == nullptr) {
|
||||
#if (TOUCH_I2C_PORT == 1)
|
||||
chsc6xTouch = new chsc6x(&Wire1, TOUCH_SDA_PIN, TOUCH_SCL_PIN, TOUCH_INT_PIN, TOUCH_RST_PIN);
|
||||
#else
|
||||
chsc6xTouch = new chsc6x(&Wire, TOUCH_SDA_PIN, TOUCH_SCL_PIN, TOUCH_INT_PIN, TOUCH_RST_PIN);
|
||||
#endif
|
||||
}
|
||||
chsc6xTouch->chsc6x_init();
|
||||
return true;
|
||||
@@ -487,7 +491,7 @@ class LGFX : public lgfx::LGFX_Device
|
||||
#if HAS_TOUCHSCREEN
|
||||
#if defined(T_WATCH_S3) || defined(ELECROW)
|
||||
lgfx::Touch_FT5x06 _touch_instance;
|
||||
#elif defined(HELTEC_V4_TFT)
|
||||
#elif defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT)
|
||||
lgfx::TOUCH_CHSC6X _touch_instance;
|
||||
#else
|
||||
lgfx::Touch_GT911 _touch_instance;
|
||||
@@ -506,7 +510,11 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.freq_write = SPI_FREQUENCY; // SPI clock for transmission (up to 80MHz, rounded to the value obtained by dividing
|
||||
// 80MHz by an integer)
|
||||
cfg.freq_read = SPI_READ_FREQUENCY; // SPI clock when receiving
|
||||
cfg.spi_3wire = false;
|
||||
#ifdef SPI_3_WIRE
|
||||
cfg.spi_3wire = SPI_3_WIRE;
|
||||
#else
|
||||
cfg.spi_3wire = true; // Set to true if reception is done on the MOSI pin
|
||||
#endif
|
||||
cfg.use_lock = true; // Set to true to use transaction locking
|
||||
cfg.dma_channel = SPI_DMA_CH_AUTO; // SPI_DMA_CH_AUTO; // Set DMA channel to use (0=not use DMA / 1=1ch / 2=ch /
|
||||
// SPI_DMA_CH_AUTO=auto setting)
|
||||
@@ -556,8 +564,11 @@ class LGFX : public lgfx::LGFX_Device
|
||||
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
|
||||
cfg.dlen_16bit =
|
||||
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
|
||||
#if defined(HAS_SDCARD)
|
||||
cfg.bus_shared = true; // If the bus is shared with the SD card, set to true (bus control with drawJpgFile etc.)
|
||||
|
||||
#else
|
||||
cfg.bus_shared = false;
|
||||
#endif
|
||||
// Set the following only when the display is shifted with a driver with a variable number of pixels, such as the
|
||||
// ST7735 or ILI9163.
|
||||
// cfg.memory_width = TFT_WIDTH; // Maximum width supported by the driver IC
|
||||
|
||||
+18
-8
@@ -2,18 +2,21 @@
|
||||
|
||||
#include "meshUtils.h"
|
||||
|
||||
// Convert seconds to ms, clamping at INT32_MAX (~24.86 days)
|
||||
static inline uint32_t secondsToMsClamped(uint32_t secs)
|
||||
{
|
||||
constexpr uint32_t MAX_MS = static_cast<uint32_t>(INT32_MAX);
|
||||
return (secs > MAX_MS / 1000U) ? MAX_MS : secs * 1000U;
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return defaultInterval * 1000;
|
||||
return secondsToMsClamped(configuredInterval > 0 ? configuredInterval : defaultInterval);
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval)
|
||||
{
|
||||
if (configuredInterval > 0)
|
||||
return configuredInterval * 1000;
|
||||
return default_broadcast_interval_secs * 1000;
|
||||
return secondsToMsClamped(configuredInterval > 0 ? configuredInterval : default_broadcast_interval_secs);
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue)
|
||||
@@ -47,7 +50,14 @@ uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t d
|
||||
meshtastic_Config_DeviceConfig_Role_TAK_TRACKER))
|
||||
return getConfiguredOrDefaultMs(configured, defaultValue);
|
||||
|
||||
return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes);
|
||||
// Saturate at INT32_MAX to match secondsToMsClamped: float→uint32_t when
|
||||
// out of range is UB, and the result is consumed as an int32_t downstream.
|
||||
constexpr uint32_t MAX_MS = static_cast<uint32_t>(INT32_MAX);
|
||||
uint32_t base = getConfiguredOrDefaultMs(configured, defaultValue);
|
||||
float coef = congestionScalingCoefficient(numOnlineNodes);
|
||||
if (static_cast<double>(base) * static_cast<double>(coef) >= static_cast<double>(MAX_MS))
|
||||
return MAX_MS;
|
||||
return base * coef;
|
||||
}
|
||||
|
||||
uint32_t Default::getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue)
|
||||
@@ -66,4 +76,4 @@ uint8_t Default::getConfiguredOrDefaultHopLimit(uint8_t configured)
|
||||
#else
|
||||
return (configured >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -688,7 +688,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
|
||||
strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32);
|
||||
|
||||
#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3) || defined(SENSECAP_INDICATOR) || \
|
||||
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT)) && \
|
||||
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT)) && \
|
||||
HAS_TFT
|
||||
// switch BT off by default; use TFT programming mode or hotkey to enable
|
||||
config.bluetooth.enabled = false;
|
||||
|
||||
@@ -490,10 +490,17 @@ void portduinoSetup()
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
char serial[9] = {0};
|
||||
ch341Hal->getSerialString(serial, 8);
|
||||
// Pass the full buffer size (9 = 8 chars + null) to getSerialString,
|
||||
// not 8. The function treats `len` as buffer size and reserves one
|
||||
// slot for the null terminator, so passing 8 produced a 7-char serial
|
||||
// and broke the `strlen(serial) == 8` check below — masked on Linux
|
||||
// by the BlueZ HCI MAC fallback in getMacAddr(), but on macOS (where
|
||||
// the BlueZ path is __linux__-guarded) it left mac_address empty and
|
||||
// meshtasticd refused to start.
|
||||
ch341Hal->getSerialString(serial, sizeof(serial));
|
||||
std::cout << "CH341 Serial " << serial << std::endl;
|
||||
char product_string[96] = {0};
|
||||
ch341Hal->getProductString(product_string, 95);
|
||||
ch341Hal->getProductString(product_string, sizeof(product_string));
|
||||
std::cout << "CH341 Product " << product_string << std::endl;
|
||||
if (strlen(serial) == 8 && portduino_config.mac_address.length() < 12) {
|
||||
std::cout << "Deriving MAC address from Serial and Product String" << std::endl;
|
||||
|
||||
@@ -127,6 +127,60 @@ void test_client_uses_public_channel_minimums()
|
||||
TEST_ASSERT_EQUAL_UINT32(60 * 60, position);
|
||||
}
|
||||
|
||||
// --- Saturation/clamp tests for getConfiguredOrDefaultMs[Scaled] ---
|
||||
// These guard the INT32_MAX clamp added to avoid uint32 wrap of secs*1000 and
|
||||
// to keep results safe to cast to int32_t for OSThread runOnce returns.
|
||||
|
||||
void test_ms_below_threshold()
|
||||
{
|
||||
// Ordinary value passes through unchanged.
|
||||
TEST_ASSERT_EQUAL_UINT32(60000U, Default::getConfiguredOrDefaultMs(60, 0));
|
||||
}
|
||||
|
||||
void test_ms_at_threshold()
|
||||
{
|
||||
// INT32_MAX / 1000 = 2,147,483 — largest secs that does not clamp.
|
||||
TEST_ASSERT_EQUAL_UINT32(2147483000U, Default::getConfiguredOrDefaultMs(2147483U, 0));
|
||||
}
|
||||
|
||||
void test_ms_just_above_threshold()
|
||||
{
|
||||
// One second over the boundary must saturate, not wrap.
|
||||
TEST_ASSERT_EQUAL_UINT32(static_cast<uint32_t>(INT32_MAX), Default::getConfiguredOrDefaultMs(2147484U, 0));
|
||||
}
|
||||
|
||||
void test_ms_uint32_max()
|
||||
{
|
||||
// default_sds_secs == UINT32_MAX on non-routers must not wrap.
|
||||
TEST_ASSERT_EQUAL_UINT32(static_cast<uint32_t>(INT32_MAX), Default::getConfiguredOrDefaultMs(UINT32_MAX, 0));
|
||||
}
|
||||
|
||||
void test_ms_default_clamps()
|
||||
{
|
||||
// Clamp also applies when the default-arg path is taken (configured == 0).
|
||||
TEST_ASSERT_EQUAL_UINT32(static_cast<uint32_t>(INT32_MAX), Default::getConfiguredOrDefaultMs(0, UINT32_MAX));
|
||||
}
|
||||
|
||||
void test_ms_result_is_int32_safe()
|
||||
{
|
||||
// Regression guard for runOnce returns: cast to int32_t must not go negative.
|
||||
int32_t result = static_cast<int32_t>(Default::getConfiguredOrDefaultMs(UINT32_MAX, 0));
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT32(0, result);
|
||||
}
|
||||
|
||||
void test_scaled_overflow_saturates()
|
||||
{
|
||||
// long_fast (SF11/BW250) with a 24h base and heavy congestion overflows
|
||||
// the uint32 result without the double-precision guard. Must saturate.
|
||||
config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT;
|
||||
config.lora.use_preset = false;
|
||||
config.lora.spread_factor = 11;
|
||||
config.lora.bandwidth = 250;
|
||||
|
||||
uint32_t res = Default::getConfiguredOrDefaultMsScaled(0, ONE_DAY, 1000);
|
||||
TEST_ASSERT_EQUAL_UINT32(static_cast<uint32_t>(INT32_MAX), res);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Small delay to match other test mains
|
||||
@@ -140,6 +194,13 @@ void setup()
|
||||
RUN_TEST(test_router_uses_router_minimums);
|
||||
RUN_TEST(test_router_late_uses_router_minimums);
|
||||
RUN_TEST(test_client_uses_public_channel_minimums);
|
||||
RUN_TEST(test_ms_below_threshold);
|
||||
RUN_TEST(test_ms_at_threshold);
|
||||
RUN_TEST(test_ms_just_above_threshold);
|
||||
RUN_TEST(test_ms_uint32_max);
|
||||
RUN_TEST(test_ms_default_clamps);
|
||||
RUN_TEST(test_ms_result_is_int32_safe);
|
||||
RUN_TEST(test_scaled_overflow_saturates);
|
||||
exit(UNITY_END());
|
||||
}
|
||||
|
||||
|
||||
@@ -89,8 +89,10 @@ build_flags =
|
||||
-D VIEW_240x320
|
||||
-D DISPLAY_SET_RESOLUTION
|
||||
-D DISPLAY_SIZE=240x320 ; portrait mode
|
||||
-D LGFX_SPI_3WIRE=true
|
||||
-D LGFX_PIN_SCK=17
|
||||
-D LGFX_PIN_MOSI=33
|
||||
-D LGFX_PIN_MISO=-1
|
||||
-D LGFX_PIN_DC=16
|
||||
-D LGFX_PIN_CS=15
|
||||
-D LGFX_PIN_BL=21
|
||||
@@ -123,7 +125,7 @@ build_flags =
|
||||
-D SCREEN_TRANSITION_FRAMERATE=5
|
||||
-D BRIGHTNESS_DEFAULT=130 ; Medium Low Brightness
|
||||
-D HAS_TOUCHSCREEN=1
|
||||
-D TOUCH_I2C_PORT=0
|
||||
-D TOUCH_I2C_PORT=1
|
||||
-D TOUCH_SLAVE_ADDRESS=0x2E
|
||||
-D SCREEN_TOUCH_INT=TOUCH_INT_PIN
|
||||
-D SCREEN_TOUCH_RST=TOUCH_RST_PIN
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x1001
|
||||
|
||||
static const uint8_t TX = 43;
|
||||
static const uint8_t RX = 44;
|
||||
|
||||
static const uint8_t SDA = 17;
|
||||
static const uint8_t SCL = 18;
|
||||
|
||||
static const uint8_t SS = 8;
|
||||
static const uint8_t MOSI = 10;
|
||||
static const uint8_t MISO = 11;
|
||||
static const uint8_t SCK = 9;
|
||||
|
||||
static const uint8_t A0 = 1;
|
||||
static const uint8_t A1 = 2;
|
||||
static const uint8_t A2 = 3;
|
||||
static const uint8_t A3 = 4;
|
||||
static const uint8_t A4 = 5;
|
||||
static const uint8_t A5 = 6;
|
||||
static const uint8_t A6 = 7;
|
||||
static const uint8_t A7 = 8;
|
||||
static const uint8_t A8 = 9;
|
||||
static const uint8_t A9 = 10;
|
||||
static const uint8_t A10 = 11;
|
||||
static const uint8_t A11 = 12;
|
||||
static const uint8_t A12 = 13;
|
||||
static const uint8_t A13 = 14;
|
||||
static const uint8_t A14 = 15;
|
||||
static const uint8_t A15 = 16;
|
||||
static const uint8_t A16 = 17;
|
||||
static const uint8_t A17 = 18;
|
||||
static const uint8_t A18 = 19;
|
||||
static const uint8_t A19 = 20;
|
||||
|
||||
static const uint8_t T1 = 1;
|
||||
static const uint8_t T2 = 2;
|
||||
static const uint8_t T3 = 3;
|
||||
static const uint8_t T4 = 4;
|
||||
static const uint8_t T5 = 5;
|
||||
static const uint8_t T6 = 6;
|
||||
static const uint8_t T7 = 7;
|
||||
static const uint8_t T8 = 8;
|
||||
static const uint8_t T9 = 9;
|
||||
static const uint8_t T10 = 10;
|
||||
static const uint8_t T11 = 11;
|
||||
static const uint8_t T12 = 12;
|
||||
static const uint8_t T13 = 13;
|
||||
static const uint8_t T14 = 14;
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
@@ -0,0 +1,145 @@
|
||||
[heltec_v4_r8_base]
|
||||
extends = esp32s3_base
|
||||
board = heltec_v4_r8
|
||||
board_check = true
|
||||
board_build.partitions = default_16MB.csv
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags}
|
||||
-D HELTEC_V4_R8
|
||||
-D HAS_LORA_FEM=1
|
||||
-D BOARD_HAS_PSRAM
|
||||
-I variants/esp32s3/heltec_v4_r8
|
||||
-ULED_BUILTIN
|
||||
|
||||
[env:heltec-v4-r8-oled]
|
||||
custom_meshtastic_hw_model = 132
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V4_R8
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec V4 R8
|
||||
custom_meshtastic_images = heltec_v4_r8.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = heltec_v4_r8_base
|
||||
build_flags =
|
||||
${heltec_v4_r8_base.build_flags}
|
||||
-D HELTEC_V4_R8_OLED
|
||||
-D USE_SSD1306 ; Heltec_v4_R8 has an SSD1315 display (compatible with SSD1306 driver)
|
||||
-D LED_POWER=46
|
||||
-D RESET_OLED=21
|
||||
-D I2C_SDA=17
|
||||
-D I2C_SCL=18
|
||||
|
||||
[env:heltec-v4-r8-tft]
|
||||
custom_meshtastic_hw_model = 132
|
||||
custom_meshtastic_hw_model_slug = HELTEC_V4_R8
|
||||
custom_meshtastic_architecture = esp32-s3
|
||||
custom_meshtastic_actively_supported = true
|
||||
custom_meshtastic_support_level = 1
|
||||
custom_meshtastic_display_name = Heltec V4 R8 TFT
|
||||
custom_meshtastic_images = heltec_v4_r8_tft.svg
|
||||
custom_meshtastic_tags = Heltec
|
||||
custom_meshtastic_requires_dfu = true
|
||||
custom_meshtastic_partition_scheme = 16MB
|
||||
|
||||
extends = heltec_v4_r8_base
|
||||
build_flags =
|
||||
${heltec_v4_r8_base.build_flags} ;-Os
|
||||
-D HELTEC_V4_R8_TFT
|
||||
-D I2C_SDA=17
|
||||
-D I2C_SCL=18
|
||||
-D PIN_BUTTON2=46
|
||||
-D ALT_BUTTON_PIN=PIN_BUTTON2
|
||||
-D ALT_BUTTON_ACTIVE_LOW=false
|
||||
-D PIN_BUZZER=4
|
||||
-D USE_PIN_BUZZER=PIN_BUZZER
|
||||
-D CONFIG_ARDUHAL_LOG_COLORS
|
||||
-D RADIOLIB_DEBUG_SPI=0
|
||||
-D RADIOLIB_DEBUG_PROTOCOL=0
|
||||
-D RADIOLIB_DEBUG_BASIC=0
|
||||
-D RADIOLIB_VERBOSE_ASSERT=0
|
||||
-D RADIOLIB_SPI_PARANOID=0
|
||||
-D CONFIG_DISABLE_HAL_LOCKS=1
|
||||
-D INPUTDRIVER_BUTTON_TYPE=0
|
||||
-D HAS_SCREEN=1
|
||||
-D HAS_TFT=1
|
||||
-D RAM_SIZE=5120
|
||||
-D LV_LVGL_H_INCLUDE_SIMPLE
|
||||
-D LV_CONF_INCLUDE_SIMPLE
|
||||
-D LV_COMP_CONF_INCLUDE_SIMPLE
|
||||
-D LV_USE_SYSMON=0
|
||||
-D LV_USE_PROFILER=0
|
||||
-D LV_USE_PERF_MONITOR=0
|
||||
-D LV_USE_MEM_MONITOR=0
|
||||
-D LV_USE_LOG=0
|
||||
-D LV_BUILD_TEST=0
|
||||
-D USE_LOG_DEBUG
|
||||
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
|
||||
-D USE_PACKET_API
|
||||
-D LGFX_DRIVER=LGFX_HELTEC_V4_TFT
|
||||
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_HELTEC_V4_TFT.h\"
|
||||
-D VIEW_240x320
|
||||
-D DISPLAY_SET_RESOLUTION
|
||||
-D DISPLAY_SIZE=240x320 ; portrait mode
|
||||
-D LGFX_SPI_3WIRE=false
|
||||
-D LGFX_PIN_SCK=16
|
||||
-D LGFX_PIN_MOSI=15
|
||||
-D LGFX_PIN_MISO=45
|
||||
-D LGFX_PIN_DC=48
|
||||
-D LGFX_PIN_CS=47
|
||||
-D LGFX_PIN_BL=44
|
||||
-D LGFX_PIN_RST=21
|
||||
-D CUSTOM_TOUCH_DRIVER
|
||||
-D TOUCH_SDA_PIN=I2C_SDA
|
||||
-D TOUCH_SCL_PIN=I2C_SCL
|
||||
-D TOUCH_INT_PIN=-1
|
||||
-D TOUCH_RST_PIN=-1
|
||||
;base UI
|
||||
-D TFT_CS=LGFX_PIN_CS
|
||||
-D ST7789_CS=TFT_CS
|
||||
-D ST7789_RS=LGFX_PIN_DC
|
||||
-D ST7789_SDA=LGFX_PIN_MOSI
|
||||
-D ST7789_SCK=LGFX_PIN_SCK
|
||||
-D ST7789_RESET=LGFX_PIN_RST
|
||||
-D ST7789_MISO=LGFX_PIN_MISO
|
||||
-D ST7789_BUSY=-1
|
||||
-D ST7789_BL=LGFX_PIN_BL
|
||||
-D ST7789_SPI_HOST=SPI3_HOST
|
||||
-D TFT_BL=ST7789_BL
|
||||
-D SPI_FREQUENCY=75000000
|
||||
-D SPI_READ_FREQUENCY=SPI_FREQUENCY
|
||||
-D SPI_3_WIRE=false
|
||||
-D TFT_HEIGHT=320
|
||||
-D TFT_WIDTH=240
|
||||
-D TFT_OFFSET_X=0
|
||||
-D TFT_OFFSET_Y=0
|
||||
-D TFT_OFFSET_ROTATION=0
|
||||
-D SCREEN_ROTATE
|
||||
-D SCREEN_TRANSITION_FRAMERATE=5
|
||||
-D BRIGHTNESS_DEFAULT=130 ; Medium Low Brightness
|
||||
-D HAS_TOUCHSCREEN=1
|
||||
-D TOUCH_I2C_PORT=0
|
||||
-D TOUCH_SLAVE_ADDRESS=0x2E
|
||||
-D SCREEN_TOUCH_INT=TOUCH_INT_PIN
|
||||
-D SCREEN_TOUCH_RST=TOUCH_RST_PIN
|
||||
|
||||
; Have SPI interface SD card slot
|
||||
-D HAS_SDCARD
|
||||
-D SDCARD_USE_SPI1
|
||||
-D SDCARD_USER_SPI_BEGIN
|
||||
-D SPI_MOSI=LGFX_PIN_MOSI
|
||||
-D SPI_SCK=LGFX_PIN_SCK
|
||||
-D SPI_MISO=LGFX_PIN_MISO
|
||||
-D SPI_CS=3
|
||||
-D SDCARD_CS=SPI_CS
|
||||
-D SD_SPI_FREQUENCY=SPI_FREQUENCY
|
||||
|
||||
lib_deps = ${heltec_v4_r8_base.lib_deps}
|
||||
${device-ui_base.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
|
||||
lovyan03/LovyanGFX@1.2.19
|
||||
# renovate: datasource=git-refs depName=Quency-D_chsc6x packageName=https://github.com/Quency-D/chsc6x gitBranch=master
|
||||
https://github.com/Quency-D/chsc6x/archive/3b2b6cebf3177b3e2c33d06e07909b0b10159516.zip
|
||||
@@ -0,0 +1,72 @@
|
||||
#define VEXT_ENABLE 40 // active low, powers the oled display and the lora antenna boost
|
||||
#define VEXT_ON_VALUE LOW
|
||||
#define BUTTON_PIN 0
|
||||
|
||||
#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_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
|
||||
#define ADC_MULTIPLIER 4.9 * 1.035
|
||||
|
||||
#define USE_SX1262
|
||||
#define LORA_DIO0 -1 // a No connect on the SX1262 module
|
||||
#define LORA_RESET 12
|
||||
#define LORA_DIO1 14 // SX1262 IRQ
|
||||
#define LORA_DIO2 13 // SX1262 BUSY
|
||||
#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TCXO is enabled
|
||||
|
||||
#define LORA_SCK 9
|
||||
#define LORA_MISO 11
|
||||
#define LORA_MOSI 10
|
||||
#define LORA_CS 8
|
||||
|
||||
#define SX126X_CS LORA_CS
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY LORA_DIO2
|
||||
#define SX126X_RESET LORA_RESET
|
||||
|
||||
#define SX126X_DIO2_AS_RF_SWITCH
|
||||
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||
|
||||
// Enable Traffic Management Module for Heltec V4
|
||||
#ifndef HAS_TRAFFIC_MANAGEMENT
|
||||
#define HAS_TRAFFIC_MANAGEMENT 1
|
||||
#endif
|
||||
#ifndef TRAFFIC_MANAGEMENT_CACHE_SIZE
|
||||
#define TRAFFIC_MANAGEMENT_CACHE_SIZE 2048
|
||||
#endif
|
||||
|
||||
// ---- KCT8103L RF FRONT END CONFIGURATION ----
|
||||
// The Heltec V4.3 uses a KCT8103L FEM chip with integrated PA and LNA
|
||||
// RF path: SX1262 -> Pi attenuator -> KCT8103L PA -> Antenna
|
||||
// Control logic (from KCT8103L datasheet):
|
||||
// Transmit PA: CSD=1, CTX=1, CPS=1
|
||||
// Receive LNA: CSD=1, CTX=0, CPS=X (21dB gain, 1.9dB NF)
|
||||
// Receive bypass: CSD=1, CTX=1, CPS=0
|
||||
// Shutdown: CSD=0, CTX=X, CPS=X
|
||||
// Pin mapping:
|
||||
// CPS (pin 5) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH)
|
||||
// CSD (pin 4) -> GPIO2: Chip enable (HIGH=on, LOW=shutdown)
|
||||
// CTX (pin 6) -> GPIO5: Switch between Receive LNA Mode and Receive Bypass Mode. (HIGH=RX bypass, LOW=RX LNA)
|
||||
// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
|
||||
// KCT8103L FEM: TX/RX path switching is handled by DIO2 -> CPS pin (via SX126X_DIO2_AS_RF_SWITCH)
|
||||
|
||||
#define USE_KCT8103L_PA
|
||||
#define LORA_PA_POWER 7 // VFEM_Ctrl - KCT8103L LDO power enable
|
||||
#define LORA_KCT8103L_PA_CSD 2 // CSD - KCT8103L chip enable (HIGH=on)
|
||||
#define LORA_KCT8103L_PA_CTX 5 // CTX - Switch between Receive LNA Mode and Receive Bypass Mode. (HIGH=RX bypass, LOW=RX LNA)
|
||||
|
||||
#if HAS_TFT
|
||||
#define USE_TFTDISPLAY 1
|
||||
#endif
|
||||
/*
|
||||
* GPS pins
|
||||
*/
|
||||
#define GPS_L76K
|
||||
#define PIN_GPS_EN (42)
|
||||
#define GPS_EN_ACTIVE LOW
|
||||
#define PERIPHERAL_WARMUP_MS 1000 // Make sure I2C QuickLink has stable power before continuing
|
||||
#define PIN_GPS_PPS (41)
|
||||
// Seems to be missing on this new board
|
||||
#define GPS_TX_PIN (38) // This is for bits going TOWARDS the CPU
|
||||
#define GPS_RX_PIN (39) // This is for bits going TOWARDS the GPS
|
||||
#define GPS_THREAD_INTERVAL 50
|
||||
@@ -133,6 +133,39 @@ test_testing_command =
|
||||
; 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.
|
||||
;
|
||||
; Real LoRa hardware on macOS:
|
||||
; The same lib_dep `pine64/libch341-spi-userspace` used on Linux works on
|
||||
; macOS as-is — its `libusb_detach_kernel_driver()` call is `__linux__`-
|
||||
; guarded, but on macOS the kernel doesn't bind a driver to a CH341A SPI
|
||||
; bridge (PID 0x5512; bDeviceClass=0xff vendor-specific) by default, so
|
||||
; no detach is needed. Apple's bundled CH34x driver targets the CH340
|
||||
; *UART* variant (PID 0x7523) — different product. libusb opens the device
|
||||
; and claims interface 0 directly via IOUSBHostInterface.
|
||||
;
|
||||
; To use, point `meshtasticd` at any of the existing `bin/config.d/lora-*.yaml`
|
||||
; files that specify `spidev: ch341` — they're platform-agnostic. Example:
|
||||
; pio run -e native-macos
|
||||
; mkdir -p ~/.meshtasticd && cp bin/config-dist.yaml ~/.meshtasticd/config.yaml
|
||||
; # Edit ~/.meshtasticd/config.yaml: ConfigDirectory: ./config.d/
|
||||
; mkdir ~/.meshtasticd/config.d && cp bin/config.d/lora-meshstick-1262.yaml ~/.meshtasticd/config.d/
|
||||
; cd ~/.meshtasticd && /path/to/firmware/.pio/build/native-macos/meshtasticd
|
||||
;
|
||||
; The MAC address auto-derives from the CH341's USB serial + product string
|
||||
; (PortduinoGlue.cpp ~497-518); on Linux a BlueZ HCI socket is the fallback
|
||||
; when that path isn't taken, but BlueZ is `__linux__`-guarded so the
|
||||
; serial-derivation path is mandatory on macOS. Override with
|
||||
; `MACAddress: AA:BB:CC:DD:EE:FF` in config.yaml's `General:` section if
|
||||
; the device's serial isn't 8 hex chars.
|
||||
;
|
||||
; Diagnosing CH341 issues on macOS:
|
||||
; ioreg -p IOUSB -l -w 0 | grep -B2 -A30 0x5512
|
||||
; Children should be `IOUSBHostInterface`. If a vendor driver class
|
||||
; (e.g. `com.wch.CH34xVCPDriver` from a third-party WCH installer)
|
||||
; claims interface 0, libusb will fail with LIBUSB_ERROR_BUSY.
|
||||
; Workaround: `sudo kmutil unload -b <bundleID>`.
|
||||
; LIBUSB_DEBUG=4 .pio/build/native-macos/meshtasticd
|
||||
; Verbose libusb trace — useful when claim_interface fails.
|
||||
; ---------------------------------------------------------------------------
|
||||
[env:native-macos]
|
||||
extends = native_base
|
||||
|
||||
Reference in New Issue
Block a user