summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMumtahin Farabi <[email protected]>2026-05-12 00:23:26 -0400
committerMumtahin Farabi <[email protected]>2026-05-12 00:23:26 -0400
commitcdf1db1c4197f76cf2dd876e3c8a27c807acb7fd (patch)
treedb479c9577f96f84de4c4e10449b22370d0f19fc
parent28bf8cb5076f419abcfe912d4ec2e0c5f31819a0 (diff)
feat(firmware): scaffold setup
Signed-off-by: Mumtahin Farabi <[email protected]>
-rw-r--r--.gitignore1
-rw-r--r--.west/config21
-rw-r--r--firmware/CMakeLists.txt1
-rw-r--r--firmware/Kconfig1
-rw-r--r--firmware/boards/walter_esp32s3_procpu.conf15
-rw-r--r--firmware/boards/walter_esp32s3_procpu.overlay19
-rw-r--r--firmware/prj.conf10
-rw-r--r--firmware/src/main.c21
-rw-r--r--firmware/tests/CMakeLists.txt12
-rw-r--r--firmware/tests/kernel.c42
-rw-r--r--firmware/tests/prj.conf10
-rw-r--r--firmware/tests/shell.c71
-rw-r--r--firmware/tests/testcase.yaml19
-rw-r--r--firmware/west.yml21
-rw-r--r--hardware-map.yaml8
15 files changed, 272 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index edc65c0..c1b99a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@
**/target/
**/dist
**/node_modules
+twister-out*
#====================================================
# CACHES/LOGS
diff --git a/.west/config b/.west/config
new file mode 100644
index 0000000..a89ff9e
--- /dev/null
+++ b/.west/config
@@ -0,0 +1,21 @@
+[manifest]
+path = .
+file = firmware/west.yml
+
+[zephyr]
+base = firmware/zephyr
+
+[build]
+pristine = always
+board = walter/esp32s3/procpu
+sysbuild = true
+
+[flash]
+rebuild = true
+
+[alias]
+test = twister --device-testing --hardware-map hardware-map.yaml --clobber-output --force-color -vv -T firmware/tests
+test-debug = twister --device-testing --hardware-map hardware-map.yaml --clobber-output --force-color --inline-logs -vv -ll DEBUG -T firmware/tests
+menuconfig = build --pristine=never --target menuconfig
+guiconfig = build --pristine=never --target guiconfig
+
diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt
new file mode 100644
index 0000000..88c4c02
--- /dev/null
+++ b/firmware/CMakeLists.txt
@@ -0,0 +1 @@
+target_sources(app PRIVATE src/main.c)
diff --git a/firmware/Kconfig b/firmware/Kconfig
new file mode 100644
index 0000000..161325b
--- /dev/null
+++ b/firmware/Kconfig
@@ -0,0 +1 @@
+source "$(ZEPHYR_BASE)/Kconfig"
diff --git a/firmware/boards/walter_esp32s3_procpu.conf b/firmware/boards/walter_esp32s3_procpu.conf
new file mode 100644
index 0000000..2208466
--- /dev/null
+++ b/firmware/boards/walter_esp32s3_procpu.conf
@@ -0,0 +1,15 @@
+# Walter-specific Kconfig overrides — only applied when building for
+# walter/esp32s3/procpu (auto-discovered by Zephyr's build system).
+
+# Required for the v3_3_regulator node in walter_esp32s3_procpu.overlay.
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
+
+# Cellular networking and TLS go here as we add them. Examples:
+# CONFIG_NETWORKING=y
+# CONFIG_NET_NATIVE=y
+# CONFIG_NET_L2_PPP=y
+# CONFIG_MODEM=y
+# CONFIG_MODEM_CELLULAR=y
+# CONFIG_MBEDTLS_ENABLE_HEAP=y
+# CONFIG_MBEDTLS_HEAP_SIZE=10240
diff --git a/firmware/boards/walter_esp32s3_procpu.overlay b/firmware/boards/walter_esp32s3_procpu.overlay
new file mode 100644
index 0000000..e500c05
--- /dev/null
+++ b/firmware/boards/walter_esp32s3_procpu.overlay
@@ -0,0 +1,19 @@
+/*
+ * Walter-specific application-level DT additions.
+ *
+ * Walter has a MOSFET on GPIO0 (active-low) that gates the on-board 3.3V
+ * output rail. The rail is OFF at reset; any external sensor wired to V3.3
+ * is unpowered until something asserts this GPIO. Modeled as a regulator-fixed
+ * with regulator-boot-on so Zephyr's regulator framework enables it during
+ * kernel init, before driver init runs.
+ */
+
+/ {
+ v3_3_regulator: v3_3-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "walter-3v3-output";
+ enable-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+};
diff --git a/firmware/prj.conf b/firmware/prj.conf
new file mode 100644
index 0000000..85d70de
--- /dev/null
+++ b/firmware/prj.conf
@@ -0,0 +1,10 @@
+CONFIG_LOG=y
+CONFIG_LOG_CMDS=y
+
+CONFIG_SHELL=y
+CONFIG_SHELL_BACKEND_SERIAL=y
+CONFIG_KERNEL_SHELL=y
+CONFIG_DEVICE_SHELL=y
+CONFIG_HWINFO=y
+CONFIG_HWINFO_SHELL=y
+CONFIG_GPIO_SHELL=y
diff --git a/firmware/src/main.c b/firmware/src/main.c
new file mode 100644
index 0000000..3566e33
--- /dev/null
+++ b/firmware/src/main.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2026 Apidae Systems
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
+
+int main(void)
+{
+ LOG_INF("Walter is alive");
+
+ while (1) {
+ k_sleep(K_SECONDS(1));
+ }
+
+ return 0;
+}
diff --git a/firmware/tests/CMakeLists.txt b/firmware/tests/CMakeLists.txt
new file mode 100644
index 0000000..474f3b1
--- /dev/null
+++ b/firmware/tests/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.20.0)
+
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(tests)
+
+if(TEST_SUITE_KERNEL)
+ target_sources(app PRIVATE kernel.c)
+endif()
+
+if(TEST_SUITE_SHELL)
+ target_sources(app PRIVATE shell.c)
+endif()
diff --git a/firmware/tests/kernel.c b/firmware/tests/kernel.c
new file mode 100644
index 0000000..c9f84b6
--- /dev/null
+++ b/firmware/tests/kernel.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2026 Apidae Systems
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+#include <zephyr/ztest.h>
+
+LOG_MODULE_REGISTER(kernel, LOG_LEVEL_INF);
+
+ZTEST_SUITE(kernel, NULL, NULL, NULL, NULL, NULL);
+
+ZTEST(kernel, test_uptime_advances)
+{
+ int64_t t0 = k_uptime_get();
+
+ k_sleep(K_MSEC(50));
+
+ int64_t t1 = k_uptime_get();
+
+ zassert_true(t1 > t0,
+ "uptime did not advance: t0=%lld t1=%lld", t0, t1);
+ zassert_true((t1 - t0) >= 40,
+ "delta %lld ms is implausibly short", (t1 - t0));
+}
+
+ZTEST(kernel, test_log_subsystem_alive)
+{
+ LOG_INF("kernel test ran at uptime=%lld ms", k_uptime_get());
+}
+
+ZTEST(kernel, test_constants_make_sense)
+{
+ zassert_true(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC > 0,
+ "SYS_CLOCK_HW_CYCLES_PER_SEC=%d",
+ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC);
+ zassert_true(CONFIG_SYS_CLOCK_TICKS_PER_SEC > 0,
+ "SYS_CLOCK_TICKS_PER_SEC=%d",
+ CONFIG_SYS_CLOCK_TICKS_PER_SEC);
+}
diff --git a/firmware/tests/prj.conf b/firmware/tests/prj.conf
new file mode 100644
index 0000000..9d81903
--- /dev/null
+++ b/firmware/tests/prj.conf
@@ -0,0 +1,10 @@
+CONFIG_ZTEST=y
+CONFIG_TEST=y
+CONFIG_LOG=y
+CONFIG_LOG_MODE_IMMEDIATE=y
+CONFIG_MAIN_STACK_SIZE=4096
+
+CONFIG_SHELL=y
+CONFIG_SHELL_BACKEND_DUMMY=y
+CONFIG_SHELL_BACKEND_SERIAL=n
+CONFIG_KERNEL_SHELL=y
diff --git a/firmware/tests/shell.c b/firmware/tests/shell.c
new file mode 100644
index 0000000..5b52a53
--- /dev/null
+++ b/firmware/tests/shell.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2026 Apidae Systems
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr/kernel.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/sys/atomic.h>
+#include <zephyr/ztest.h>
+
+static atomic_t hello_invocations = ATOMIC_INIT(0);
+
+static int cmd_hello(const struct shell *sh, size_t argc, char **argv)
+{
+ atomic_inc(&hello_invocations);
+ shell_print(sh, "hello from %s", argc > 1 ? argv[1] : "test");
+ return 0;
+}
+
+SHELL_CMD_REGISTER(hello, NULL, "test-only command — increments a counter", cmd_hello);
+
+ZTEST_SUITE(shell, NULL, NULL, NULL, NULL, NULL);
+
+ZTEST(shell, test_dummy_backend_is_ready)
+{
+ const struct shell *sh = shell_backend_dummy_get_ptr();
+
+ zassert_not_null(sh, "dummy shell backend pointer is NULL");
+}
+
+ZTEST(shell, test_executes_builtin_help)
+{
+ const struct shell *sh = shell_backend_dummy_get_ptr();
+ int rc = shell_execute_cmd(sh, "help");
+
+ zassert_ok(rc, "shell_execute_cmd(\"help\") failed: %d", rc);
+}
+
+ZTEST(shell, test_executes_kernel_uptime)
+{
+ const struct shell *sh = shell_backend_dummy_get_ptr();
+ int rc = shell_execute_cmd(sh, "kernel uptime");
+
+ zassert_ok(rc, "shell_execute_cmd(\"kernel uptime\") failed: %d", rc);
+}
+
+ZTEST(shell, test_executes_custom_command_with_side_effect)
+{
+ const struct shell *sh = shell_backend_dummy_get_ptr();
+ atomic_val_t before = atomic_get(&hello_invocations);
+
+ int rc = shell_execute_cmd(sh, "hello world");
+
+ zassert_ok(rc, "shell_execute_cmd(\"hello world\") failed: %d", rc);
+
+ atomic_val_t after = atomic_get(&hello_invocations);
+ zassert_equal(after, before + 1,
+ "custom command did not run: before=%ld after=%ld",
+ (long)before, (long)after);
+}
+
+ZTEST(shell, test_unknown_command_does_not_crash)
+{
+ const struct shell *sh = shell_backend_dummy_get_ptr();
+ int rc = shell_execute_cmd(sh, "definitely_not_a_real_command_xyz");
+
+ zassert_not_equal(rc, 0,
+ "unknown command should return non-zero, got %d", rc);
+}
diff --git a/firmware/tests/testcase.yaml b/firmware/tests/testcase.yaml
new file mode 100644
index 0000000..8ba79d0
--- /dev/null
+++ b/firmware/tests/testcase.yaml
@@ -0,0 +1,19 @@
+common:
+ harness: ztest
+ integration_platforms:
+ - walter/esp32s3/procpu
+ platform_allow:
+ - walter/esp32s3/procpu
+ timeout: 30
+ tags:
+ - boot
+
+tests:
+ boot.kernel:
+ extra_args: TEST_SUITE_KERNEL=y
+ tags:
+ - kernel
+ boot.shell:
+ extra_args: TEST_SUITE_SHELL=y
+ tags:
+ - shell
diff --git a/firmware/west.yml b/firmware/west.yml
new file mode 100644
index 0000000..f174236
--- /dev/null
+++ b/firmware/west.yml
@@ -0,0 +1,21 @@
+manifest:
+ self:
+ path: firmware
+
+ remotes:
+ - name: zephyrproject
+ url-base: https://github.com/zephyrproject-rtos
+
+ projects:
+ - name: zephyr
+ remote: zephyrproject
+ revision: f1ff557f96f74a6d82d8b290bc4488ee5f93c483 # main~2: before HAL CS timing regression
+ import:
+ path-prefix: firmware
+ name-allowlist:
+ - hal_espressif
+ - hal_xtensa
+ - cmsis
+ - picolibc
+ - mcuboot
+ - mbedtls
diff --git a/hardware-map.yaml b/hardware-map.yaml
new file mode 100644
index 0000000..bc4d9ce
--- /dev/null
+++ b/hardware-map.yaml
@@ -0,0 +1,8 @@
+- id: /dev/cu.usbmodem2101
+ baud: 115200
+ runner: esp32
+ connected: true
+ flash_before: true
+ serial: /dev/cu.usbmodem2101
+ product: DPTechnics Walter
+ platform: walter/esp32s3/procpu