Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,71 @@ jobs:

- name: Pack component (same validation the registry runs on upload)
run: compote -W component pack --project-dir components/microlink --name microlink

examples:
name: "build ${{ matrix.example }} (${{ matrix.idf_version }})"
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
example:
- basic_connect
- cellular_connect
- cellular_heartbeat
- failover_connect
- rebind_test
idf_version: [ v6.0.1 ]
include:
# Early warning for the next ESP-IDF minor release -- allowed to
# fail without turning the whole workflow red.
- example: basic_connect
idf_version: release-v6.0
continue_on_error: true
steps:
- uses: actions/checkout@v7
with:
submodules: recursive

- uses: espressif/esp-idf-ci-action@v1
continue-on-error: ${{ matrix.continue_on_error == true }}
with:
esp_idf_version: ${{ matrix.idf_version }}
target: esp32s3
path: "examples/${{ matrix.example }}"
command: "idf.py build"

config-variants:
name: "build ${{ matrix.variant }}"
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
# Each variant overlays ci/sdkconfig.ci.<variant> on top of an
# existing example's own sdkconfig.defaults. SDKCONFIG_DEFAULTS
# replaces the implicit default entirely, so the base file has to
# be listed again alongside the overlay.
- variant: zerocopy
base_example: basic_connect
- variant: minimal
base_example: basic_connect
- variant: cellular-zerocopy
base_example: cellular_connect
steps:
- uses: actions/checkout@v7
with:
submodules: recursive

- name: Copy overlay into example dir
run: cp "ci/sdkconfig.ci.${{ matrix.variant }}" "examples/${{ matrix.base_example }}/sdkconfig.ci"

- uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: v6.0.1
target: esp32s3
path: "examples/${{ matrix.base_example }}"
# esp-idf-ci-action interpolates `command` inside a single-quoted
# bash -c '...' -- only double quotes are safe to use here.
command: "idf.py -DSDKCONFIG_DEFAULTS=\"sdkconfig.defaults;sdkconfig.ci\" build"
86 changes: 86 additions & 0 deletions .github/workflows/upstream-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Upstream drift

on:
schedule:
- cron: '17 6 * * 1' # Mondays 06:17 UTC
workflow_dispatch:

permissions:
contents: read
issues: write

concurrency:
group: upstream-drift
cancel-in-progress: false

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 10
env:
GH_TOKEN: ${{ github.token }}
UPSTREAM: CamM2325/microlink
TITLE: 'Upstream drift: CamM2325/microlink'
# PR numbers already accounted for in UPSTREAM_PRS.md (absorbed or
# deliberately skipped with a recorded reason) -- excluded so the
# tracking issue only ever shows genuinely new drift.
KNOWN_PRS: '20 21 22 23 24 25 14 3'
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }

- name: Collect drift
id: drift
run: |
set -euo pipefail
git fetch --no-tags --quiet origin main # this repo IS the fork; origin's parent is upstream
# This repo is a real GitHub fork of $UPSTREAM. We don't have a local
# remote pointed at it (no need to -- GitHub tracks the fork relationship
# directly), so fetch it by URL for the comparison.
git fetch --no-tags --quiet "https://github.com/$UPSTREAM.git" main:refs/remotes/upstream-check/main

# `git cherry <upstream> <head>` lists commits in <head> missing from
# <upstream> by patch-id, prefixing '-' when already present. Reversing
# the arguments gives upstream commits we lack.
COMMITS="$(git cherry -v HEAD upstream-check/main | sed -n 's/^+ //p' || true)"

PRS=""
while read -r n title; do
[ -n "$n" ] || continue
case " $KNOWN_PRS " in *" $n "*) continue ;; esac
PRS="${PRS}- [#${n}](https://github.com/${UPSTREAM}/pull/${n}) — ${title}"$'\n'
done < <(gh pr list --repo "$UPSTREAM" --state open --limit 100 \
--json number,title --jq '.[] | "\(.number) \(.title)"')

{
echo 'body<<DRIFT_EOF'
if [ -n "$COMMITS" ]; then
echo '### New upstream commits not in this fork'
echo '```'; echo "$COMMITS"; echo '```'
fi
if [ -n "$PRS" ]; then
echo '### Open upstream PRs not yet recorded in UPSTREAM_PRS.md'
echo "$PRS"
fi
echo
echo "_Checked $(date -u +%Y-%m-%dT%H:%MZ) against \`$UPSTREAM\` @ \`$(git rev-parse --short upstream-check/main)\`._"
echo 'DRIFT_EOF'
} >> "$GITHUB_OUTPUT"

if [ -n "$COMMITS$PRS" ]; then echo 'drifted=true' >> "$GITHUB_OUTPUT";
else echo 'drifted=false' >> "$GITHUB_OUTPUT"; fi

- name: Open / update / close the tracking issue
run: |
set -euo pipefail
NUM="$(gh issue list --state open --label upstream-drift --limit 1 --json number --jq '.[0].number // empty')"
if [ "${{ steps.drift.outputs.drifted }}" = 'true' ]; then
if [ -n "$NUM" ]; then
gh issue edit "$NUM" --body "${{ steps.drift.outputs.body }}"
else
gh issue create --title "$TITLE" --label upstream-drift \
--body "${{ steps.drift.outputs.body }}"
fi
elif [ -n "$NUM" ]; then
gh issue close "$NUM" --comment 'No upstream drift remaining.'
fi
6 changes: 6 additions & 0 deletions ci/sdkconfig.ci.cellular-zerocopy
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Config-variant overlay for CI: zero-copy WireGuard receive combined with
# cellular, on top of cellular_connect's own sdkconfig.defaults (which
# already has CONFIG_ML_ENABLE_CELLULAR=y). Catches interaction bugs between
# the two features that neither one alone would surface.
# See .github/workflows/ci.yml's config-variants job.
CONFIG_ML_ZERO_COPY_WG=y
8 changes: 8 additions & 0 deletions ci/sdkconfig.ci.minimal
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Config-variant overlay for CI: everything optional switched off, on top of
# basic_connect's own sdkconfig.defaults -- catches REQUIRES/ifdef mistakes
# that only show up when optional features are compiled OUT, not in.
# See .github/workflows/ci.yml's config-variants job.
CONFIG_ML_ENABLE_CONFIG_HTTPD=n
CONFIG_ML_ZERO_COPY_WG=n
CONFIG_ML_ENABLE_CELLULAR=n
CONFIG_ML_ENABLE_NET_SWITCH=n
4 changes: 4 additions & 0 deletions ci/sdkconfig.ci.zerocopy
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Config-variant overlay for CI: exercises the zero-copy WireGuard receive
# path (contributed by dj-oyu). Applied on top of basic_connect's own
# sdkconfig.defaults -- see .github/workflows/ci.yml's config-variants job.
CONFIG_ML_ZERO_COPY_WG=y
16 changes: 9 additions & 7 deletions components/microlink/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,19 @@ set(REQUIRES
driver
esp_driver_tsens
esp_http_server
)

if(CONFIG_ML_ENABLE_CELLULAR)
# ml_cellular.c / ml_at_socket.c include driver/uart.h and driver/gpio.h. On
# ESP-IDF 6.x those headers live in esp_driver_uart / esp_driver_gpio, not in
# the umbrella `driver` component above -- `driver` only PRIV_REQUIRES
# esp_driver_gpio (private, doesn't propagate) and doesn't require
# esp_driver_uart at all. Without these, any CONFIG_ML_ENABLE_CELLULAR=y
# build fails to find both headers.
list(APPEND REQUIRES esp_driver_uart esp_driver_gpio)
endif()
# esp_driver_uart at all. Unconditional, not gated on CONFIG_ML_ENABLE_CELLULAR:
# REQUIRES/PRIV_REQUIRES are resolved during ESP-IDF's component-requirements
# expansion pass, which runs before Kconfig is available -- REQUIRES can never
# be conditioned on a CONFIG_* value (only SRCS can, in the later registration
# pass). Confirmed empirically: a Kconfig-gated REQUIRES here silently no-ops
# in every environment tried (PlatformIO and real ESP-IDF Docker CI alike).
esp_driver_uart
esp_driver_gpio
)

idf_component_register(
SRCS ${SRCS}
Expand Down
6 changes: 5 additions & 1 deletion components/microlink/src/ml_config_httpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,11 @@ static void config_load_peers(ml_config_ctx_t *ctx) {
size_t rlen = stored_len;
err = nvs_get_blob(ctx->nvs, NVS_KEY_PEERS, tmp, &rlen);
if (err == ESP_OK) {
uint8_t old_count = tmp[0];
/* old_count is widened to uint16_t before the comparison: comparing the
* uint8_t directly against ML_CONFIG_MAX_ALLOWED_PEERS is tautological
* whenever that Kconfig value is >= 255 (true for the default of 512),
* which -Werror=type-limits correctly flags as always-true. */
uint16_t old_count = tmp[0];
uint16_t count = (old_count <= ML_CONFIG_MAX_ALLOWED_PEERS) ? old_count : 0;
memset(&ctx->peer_list, 0, sizeof(ctx->peer_list));
ctx->peer_list.count = count;
Expand Down
1 change: 1 addition & 0 deletions examples/failover_connect/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
idf_component_register(
SRCS "main.c"
INCLUDE_DIRS "."
REQUIRES microlink nvs_flash esp_netif esp_event driver
)
Loading