mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-14 23:02:53 +00:00
Compare commits
14 Commits
kill-led-b
...
Thinknode-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b2a1547de | ||
|
|
6f725a1996 | ||
|
|
cc4c41167c | ||
|
|
fff2bbf4a0 | ||
|
|
fba92229a6 | ||
|
|
ff0a4ea320 | ||
|
|
83b603827c | ||
|
|
2032ff1c32 | ||
|
|
5910cc2e26 | ||
|
|
ee80ec7b68 | ||
|
|
ec0dfb7337 | ||
|
|
817f3b9ec8 | ||
|
|
0726bb4b56 | ||
|
|
6b11991be0 |
2
.github/workflows/release_channels.yml
vendored
2
.github/workflows/release_channels.yml
vendored
@@ -102,7 +102,7 @@ jobs:
|
|||||||
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||||
|
|
||||||
- name: Create Bumps pull request
|
- name: Create Bumps pull request
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
base: ${{ github.event.repository.default_branch }}
|
base: ${{ github.event.repository.default_branch }}
|
||||||
branch: create-pull-request/bump-version
|
branch: create-pull-request/bump-version
|
||||||
|
|||||||
2
.github/workflows/update_protobufs.yml
vendored
2
.github/workflows/update_protobufs.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
|||||||
./bin/regen-protos.sh
|
./bin/regen-protos.sh
|
||||||
|
|
||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
branch: create-pull-request/update-protobufs
|
branch: create-pull-request/update-protobufs
|
||||||
labels: submodules
|
labels: submodules
|
||||||
|
|||||||
@@ -9,24 +9,24 @@ plugins:
|
|||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.495
|
- checkov@3.2.495
|
||||||
- renovate@42.30.4
|
- renovate@42.44.0
|
||||||
- prettier@3.7.4
|
- prettier@3.7.4
|
||||||
- trufflehog@3.91.2
|
- trufflehog@3.92.2
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.9.2
|
- bandit@1.9.2
|
||||||
- trivy@0.67.2
|
- trivy@0.68.1
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.14.7
|
- ruff@0.14.8
|
||||||
- isort@7.0.0
|
- isort@7.0.0
|
||||||
- markdownlint@0.46.0
|
- markdownlint@0.47.0
|
||||||
- oxipng@9.1.5
|
- oxipng@10.0.0
|
||||||
- svgo@4.0.0
|
- svgo@4.0.0
|
||||||
- actionlint@1.7.9
|
- actionlint@1.7.9
|
||||||
- flake8@7.3.0
|
- flake8@7.3.0
|
||||||
- hadolint@2.14.0
|
- hadolint@2.14.0
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.11.0
|
- shellcheck@0.11.0
|
||||||
- black@25.11.0
|
- black@25.12.0
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.30.0
|
- gitleaks@8.30.0
|
||||||
- clang-format@16.0.3
|
- clang-format@16.0.3
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ Import("env")
|
|||||||
platform = env.PioPlatform()
|
platform = env.PioPlatform()
|
||||||
|
|
||||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||||
|
# IntelHex workaround, remove after fixed upstream
|
||||||
|
# https://github.com/platformio/platform-espressif32/issues/1632
|
||||||
|
try:
|
||||||
|
import intelhex
|
||||||
|
except ImportError:
|
||||||
|
env.Execute("$PYTHONEXE -m pip install intelhex")
|
||||||
import esptool
|
import esptool
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -532,8 +532,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
const int labelX = x;
|
const int labelX = x;
|
||||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||||
#ifdef USE_EINK
|
#ifdef USE_EINK
|
||||||
|
#ifndef T_DECK_PRO
|
||||||
barsOffset -= 12;
|
barsOffset -= 12;
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
#if defined(M5STACK_UNITC6L)
|
#if defined(M5STACK_UNITC6L)
|
||||||
const int barX = x + 45 + barsOffset;
|
const int barX = x + 45 + barsOffset;
|
||||||
#else
|
#else
|
||||||
@@ -574,7 +576,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
|||||||
#endif
|
#endif
|
||||||
// Value string
|
// Value string
|
||||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr);
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Memory values ===
|
// === Memory values ===
|
||||||
|
|||||||
@@ -1041,12 +1041,13 @@ void menuHandler::switchToMUIMenu()
|
|||||||
|
|
||||||
void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
||||||
{
|
{
|
||||||
static const char *optionsArray[] = {"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Teal",
|
static const char *optionsArray[] = {
|
||||||
"Pink", "White"};
|
"Back", "Default", "Meshtastic Green", "Yellow", "Red", "Orange", "Purple", "Blue", "Teal", "Cyan", "Ice", "Pink",
|
||||||
|
"White", "Gray"};
|
||||||
BannerOverlayOptions bannerOptions;
|
BannerOverlayOptions bannerOptions;
|
||||||
bannerOptions.message = "Select Screen Color";
|
bannerOptions.message = "Select Screen Color";
|
||||||
bannerOptions.optionsArrayPtr = optionsArray;
|
bannerOptions.optionsArrayPtr = optionsArray;
|
||||||
bannerOptions.optionsCount = 10;
|
bannerOptions.optionsCount = 14;
|
||||||
bannerOptions.bannerCallback = [display](int selected) -> void {
|
bannerOptions.bannerCallback = [display](int selected) -> void {
|
||||||
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || \
|
#if defined(HELTEC_MESH_NODE_T114) || defined(HELTEC_VISION_MASTER_T190) || defined(T_DECK) || defined(T_LORA_PAGER) || \
|
||||||
HAS_TFT || defined(HACKADAY_COMMUNICATOR)
|
HAS_TFT || defined(HACKADAY_COMMUNICATOR)
|
||||||
@@ -1082,20 +1083,40 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
|
|||||||
TFT_MESH_g = 153;
|
TFT_MESH_g = 153;
|
||||||
TFT_MESH_b = 255;
|
TFT_MESH_b = 255;
|
||||||
} else if (selected == 7) {
|
} else if (selected == 7) {
|
||||||
LOG_INFO("Setting color to Teal");
|
LOG_INFO("Setting color to Blue");
|
||||||
TFT_MESH_r = 64;
|
TFT_MESH_r = 0;
|
||||||
TFT_MESH_g = 224;
|
TFT_MESH_g = 0;
|
||||||
TFT_MESH_b = 208;
|
TFT_MESH_b = 255;
|
||||||
} else if (selected == 8) {
|
} else if (selected == 8) {
|
||||||
|
LOG_INFO("Setting color to Teal");
|
||||||
|
TFT_MESH_r = 16;
|
||||||
|
TFT_MESH_g = 102;
|
||||||
|
TFT_MESH_b = 102;
|
||||||
|
} else if (selected == 9) {
|
||||||
|
LOG_INFO("Setting color to Cyan");
|
||||||
|
TFT_MESH_r = 0;
|
||||||
|
TFT_MESH_g = 255;
|
||||||
|
TFT_MESH_b = 255;
|
||||||
|
} else if (selected == 10) {
|
||||||
|
LOG_INFO("Setting color to Ice");
|
||||||
|
TFT_MESH_r = 173;
|
||||||
|
TFT_MESH_g = 216;
|
||||||
|
TFT_MESH_b = 230;
|
||||||
|
} else if (selected == 11) {
|
||||||
LOG_INFO("Setting color to Pink");
|
LOG_INFO("Setting color to Pink");
|
||||||
TFT_MESH_r = 255;
|
TFT_MESH_r = 255;
|
||||||
TFT_MESH_g = 105;
|
TFT_MESH_g = 105;
|
||||||
TFT_MESH_b = 180;
|
TFT_MESH_b = 180;
|
||||||
} else if (selected == 9) {
|
} else if (selected == 12) {
|
||||||
LOG_INFO("Setting color to White");
|
LOG_INFO("Setting color to White");
|
||||||
TFT_MESH_r = 255;
|
TFT_MESH_r = 255;
|
||||||
TFT_MESH_g = 255;
|
TFT_MESH_g = 255;
|
||||||
TFT_MESH_b = 255;
|
TFT_MESH_b = 255;
|
||||||
|
} else if (selected == 13) {
|
||||||
|
LOG_INFO("Setting color to Gray");
|
||||||
|
TFT_MESH_r = 128;
|
||||||
|
TFT_MESH_g = 128;
|
||||||
|
TFT_MESH_b = 128;
|
||||||
} else {
|
} else {
|
||||||
menuQueue = system_base_menu;
|
menuQueue = system_base_menu;
|
||||||
screen->runNow();
|
screen->runNow();
|
||||||
|
|||||||
@@ -439,6 +439,11 @@ void setup()
|
|||||||
|
|
||||||
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
|
LOG_INFO("\n\n//\\ E S H T /\\ S T / C\n");
|
||||||
|
|
||||||
|
#if defined(ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||||
|
// use PSRAM for malloc calls > 256 bytes
|
||||||
|
heap_caps_malloc_extmem_enable(256);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(DEBUG_MUTE) && defined(DEBUG_PORT)
|
#if defined(DEBUG_MUTE) && defined(DEBUG_PORT)
|
||||||
DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n");
|
DEBUG_PORT.printf("\r\n\r\n//\\ E S H T /\\ S T / C\r\n");
|
||||||
DEBUG_PORT.printf("Version %s for %s from %s\r\n", optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
DEBUG_PORT.printf("Version %s for %s from %s\r\n", optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
||||||
|
|||||||
@@ -805,11 +805,15 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.external_notification.output_ms = 500;
|
moduleConfig.external_notification.output_ms = 500;
|
||||||
moduleConfig.external_notification.nag_timeout = 2;
|
moduleConfig.external_notification.nag_timeout = 2;
|
||||||
#endif
|
#endif
|
||||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312)
|
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE)
|
||||||
// Default to RAK led pin 2 (blue)
|
// Default to RAK led pin 2 (blue)
|
||||||
moduleConfig.external_notification.enabled = true;
|
moduleConfig.external_notification.enabled = true;
|
||||||
moduleConfig.external_notification.output = PIN_LED2;
|
moduleConfig.external_notification.output = PIN_LED2;
|
||||||
|
#if defined(MUZI_BASE)
|
||||||
|
moduleConfig.external_notification.active = false;
|
||||||
|
#else
|
||||||
moduleConfig.external_notification.active = true;
|
moduleConfig.external_notification.active = true;
|
||||||
|
#endif
|
||||||
moduleConfig.external_notification.alert_message = true;
|
moduleConfig.external_notification.alert_message = true;
|
||||||
moduleConfig.external_notification.output_ms = 1000;
|
moduleConfig.external_notification.output_ms = 1000;
|
||||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||||
|
|||||||
@@ -37,8 +37,8 @@
|
|||||||
|
|
||||||
static MemoryDynamic<meshtastic_MeshPacket> dynamicPool;
|
static MemoryDynamic<meshtastic_MeshPacket> dynamicPool;
|
||||||
Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
||||||
#elif defined(ARCH_STM32WL)
|
#elif defined(ARCH_STM32WL) || defined(BOARD_HAS_PSRAM)
|
||||||
// On STM32 there isn't enough heap left over for the rest of the firmware if we allocate this statically.
|
// On STM32 and boards with PSRAM, there isn't enough heap left over for the rest of the firmware if we allocate this statically.
|
||||||
// For now, make it dynamic again.
|
// For now, make it dynamic again.
|
||||||
#define MAX_PACKETS \
|
#define MAX_PACKETS \
|
||||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ void setupModules()
|
|||||||
}
|
}
|
||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
#if ARCH_PORTDUINO
|
#if ARCH_PORTDUINO
|
||||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
|
||||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||||
if (!seesawRotary->init()) {
|
if (!seesawRotary->init()) {
|
||||||
delete seesawRotary;
|
delete seesawRotary;
|
||||||
|
|||||||
@@ -45,8 +45,12 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
|||||||
{
|
{
|
||||||
auto p = *pptr;
|
auto p = *pptr;
|
||||||
|
|
||||||
// If inbound message is a replay (or spoof!) of our own messages, we shouldn't process
|
const auto transport = mp.transport_mechanism;
|
||||||
// (why use second-hand sources for our own data?)
|
if (isFromUs(&mp) && !IS_ONE_OF(transport, meshtastic_MeshPacket_TransportMechanism_TRANSPORT_INTERNAL,
|
||||||
|
meshtastic_MeshPacket_TransportMechanism_TRANSPORT_API)) {
|
||||||
|
LOG_WARN("Ignoring packet supposedly from us over external transport");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
|
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
|
||||||
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
|
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
|
||||||
@@ -472,19 +476,53 @@ void PositionModule::sendLostAndFoundText()
|
|||||||
delete[] message;
|
delete[] message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper: return imprecise (truncated + centered) lat/lon as int32 using current precision
|
||||||
|
static inline void computeImpreciseLatLon(int32_t inLat, int32_t inLon, uint8_t precisionBits, int32_t &outLat, int32_t &outLon)
|
||||||
|
{
|
||||||
|
if (precisionBits > 0 && precisionBits < 32) {
|
||||||
|
// Build mask for top 'precisionBits' bits of a 32-bit unsigned field
|
||||||
|
const uint32_t mask = (precisionBits == 32) ? UINT32_MAX : (UINT32_MAX << (32 - precisionBits));
|
||||||
|
// Note: latitude_i/longitude_i are stored as signed 32-bit in meshtastic code but
|
||||||
|
// the bitmask logic used previously operated as unsigned—preserve that behavior by
|
||||||
|
// casting to uint32_t for masking, then back to int32_t.
|
||||||
|
uint32_t lat_u = static_cast<uint32_t>(inLat) & mask;
|
||||||
|
uint32_t lon_u = static_cast<uint32_t>(inLon) & mask;
|
||||||
|
|
||||||
|
// Add the "center of cell" offset used elsewhere:
|
||||||
|
// The code previously added (1 << (31 - precision)) to produce the middle of the possible location.
|
||||||
|
uint32_t center_offset = (1u << (31 - precisionBits));
|
||||||
|
lat_u += center_offset;
|
||||||
|
lon_u += center_offset;
|
||||||
|
|
||||||
|
outLat = static_cast<int32_t>(lat_u);
|
||||||
|
outLon = static_cast<int32_t>(lon_u);
|
||||||
|
} else {
|
||||||
|
// full precision: return input unchanged
|
||||||
|
outLat = inLat;
|
||||||
|
outLon = inLon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
|
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
|
||||||
{
|
{
|
||||||
// The minimum distance to travel before we are able to send a new position packet.
|
|
||||||
const uint32_t distanceTravelThreshold =
|
const uint32_t distanceTravelThreshold =
|
||||||
Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
|
Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
|
||||||
|
|
||||||
// Determine the distance in meters between two points on the globe
|
int32_t lastLatImprecise, lastLonImprecise;
|
||||||
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
|
int32_t currentLatImprecise, currentLonImprecise;
|
||||||
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
|
|
||||||
|
|
||||||
return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
|
computeImpreciseLatLon(lastGpsLatitude, lastGpsLongitude, precision, lastLatImprecise, lastLonImprecise);
|
||||||
|
computeImpreciseLatLon(currentPosition.latitude_i, currentPosition.longitude_i, precision, currentLatImprecise,
|
||||||
|
currentLonImprecise);
|
||||||
|
|
||||||
|
float distMeters = GeoCoord::latLongToMeter(lastLatImprecise * 1e-7, lastLonImprecise * 1e-7, currentLatImprecise * 1e-7,
|
||||||
|
currentLonImprecise * 1e-7);
|
||||||
|
|
||||||
|
float distanceTraveled = fabsf(distMeters);
|
||||||
|
|
||||||
|
return SmartPosition{.distanceTraveled = distanceTraveled,
|
||||||
.distanceThreshold = distanceTravelThreshold,
|
.distanceThreshold = distanceTravelThreshold,
|
||||||
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
|
.hasTraveledOverThreshold = distanceTraveled >= distanceTravelThreshold};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PositionModule::handleNewPosition()
|
void PositionModule::handleNewPosition()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
[env:meshtastic-dr-dev]
|
[env:meshtastic-dr-dev]
|
||||||
extends = esp32_base
|
extends = esp32_base
|
||||||
board = esp32doit-devkit-v1
|
board = esp32doit-devkit-v1
|
||||||
|
board_level = extra
|
||||||
board_upload.maximum_size = 4194304
|
board_upload.maximum_size = 4194304
|
||||||
board_upload.maximum_ram_size = 532480
|
board_upload.maximum_ram_size = 532480
|
||||||
build_flags =
|
build_flags =
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
|
|||||||
custom_mtjson_part =
|
custom_mtjson_part =
|
||||||
platform =
|
platform =
|
||||||
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
|
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
|
||||||
platformio/espressif32@6.11.0
|
platformio/espressif32@6.12.0
|
||||||
|
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
${env.extra_scripts}
|
${env.extra_scripts}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
[env:tbeam]
|
[env:tbeam]
|
||||||
extends = esp32_base
|
extends = esp32_base
|
||||||
board = ttgo-t-beam
|
board = ttgo-t-beam
|
||||||
board_level = pr
|
board_level = extra
|
||||||
board_check = true
|
board_check = true
|
||||||
lib_deps = ${esp32_base.lib_deps}
|
lib_deps = ${esp32_base.lib_deps}
|
||||||
build_flags = ${esp32_base.build_flags}
|
build_flags = ${esp32_base.build_flags}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[env:link32-s3-v1]
|
[env:link32-s3-v1]
|
||||||
extends = esp32s3_base
|
extends = esp32s3_base
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
|
board_level = extra
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_base.build_flags}
|
${esp32_base.build_flags}
|
||||||
-D LINK_32
|
-D LINK_32
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[env:feather_rp2040_rfm95]
|
[env:feather_rp2040_rfm95]
|
||||||
extends = rp2040_base
|
extends = rp2040_base
|
||||||
board = adafruit_feather
|
board = adafruit_feather
|
||||||
|
board_level = extra
|
||||||
upload_protocol = picotool
|
upload_protocol = picotool
|
||||||
# add our variants files to the include and src paths
|
# add our variants files to the include and src paths
|
||||||
build_flags =
|
build_flags =
|
||||||
|
|||||||
Reference in New Issue
Block a user