diff --git a/README.md b/README.md index 9f75c55..eb1c2f9 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,28 @@ The README is used to introduce the tool and provide instructions on how to install the tool, any machine dependencies it may have and any other information that should be provided before the tool is installed. -[![minihil C++ Checker](https://github.com/electux/minihil/actions/workflows/minihil_cc_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihil_cc_checker.yml) [![minihil Build Checker (SIL)](https://github.com/electux/minihil/actions/workflows/minihil_build_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihil_build_checker.yml) [![GitHub issues open](https://img.shields.io/github/issues/electux/minihil.svg)](https://github.com/electux/minihil/issues) [![GitHub contributors](https://img.shields.io/github/contributors/electux/minihil.svg)](https://github.com/electux/minihil/graphs/contributors) +[![minihil C++ Checker](https://github.com/electux/minihil/actions/workflows/minihil_cc_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihil_cc_checker.yml) [![minihil Build Checker (SIL)](https://github.com/electux/minihil/actions/workflows/minihil_build_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihil_build_checker.yml) [![minihil TOC](https://github.com/electux/minihil/actions/workflows/minihil_toc.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihil_toc.yml) +[![minihildesk C++ Checker](https://github.com/electux/minihil/actions/workflows/minihildesk_cc_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihildesk_cc_checker.yml) [![minihildesk Build Checker (SIL)](https://github.com/electux/minihil/actions/workflows/minihildesk_build_checker.yml/badge.svg)](https://github.com/electux/minihil/actions/workflows/minihildesk_build_checker.yml) +[![GitHub issues open](https://img.shields.io/github/issues/electux/minihil.svg)](https://github.com/electux/minihil/issues) [![GitHub contributors](https://img.shields.io/github/contributors/electux/minihil.svg)](https://github.com/electux/minihil/graphs/contributors) **Table of Contents** -- [Installation](#installation) -- [Dependencies](#dependencies) +- [About minihild](#about-minihild) +- [SIL (Software-in-the-Loop) Host Build](#sil-software-in-the-loop-host-build) + - [Prerequisites](#prerequisites) + - [Compile and Run](#compile-and-run) +- [Yocto Image Build (Raspberry Pi Target)](#yocto-image-build-raspberry-pi-target) + - [Prerequisites](#prerequisites-1) + - [Compile target image](#compile-target-image) +- [Flashing the Image to SD Card](#flashing-the-image-to-sd-card) + - [Option A: Using `bmaptool` (Recommended - Fast & Direct)](#option-a-using-bmaptool-recommended---fast--direct) + - [Option B: Using `dd` (Piped Decompression)](#option-b-using-dd-piped-decompression) +- [Running on Raspberry Pi 3B+](#running-on-raspberry-pi-3b) +- [JSON-RPC 2.0 API Specification](#json-rpc-20-api-specification) + - [`set_relay`](#set_relay) + - [`get_relays`](#get_relays) - [Docs](#docs) - [Copyright and licence](#copyright-and-licence) @@ -70,6 +84,60 @@ This compiles the C++ application, bundles the systemd daemon config (`minihil.s --- +### Flashing the Image to SD Card + +The Yocto build generates a flashable `.wic.bz2` image in the deployment directory: +`sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2` + +Identify your SD card's device name (e.g. `/dev/sdX` or `/dev/mmcblkX`) using `lsblk` or `dmesg`. + +> [!WARNING] +> Double-check the target device name before flashing! Writing to the wrong disk can destroy data on your host system. + +Before flashing, ensure that all partitions on the target SD card are unmounted (otherwise you will get a "Device or resource busy" error): +```bash +sudo umount /dev/sdX* 2>/dev/null || true +``` + +#### Option A: Using `bmaptool` (Recommended - Fast & Direct) +`bmaptool` natively supports compressed images and will automatically decompress the Yocto symlink on-the-fly. +```bash +# Flash directly (replace /dev/sdX with your SD card device) +sudo bmaptool copy sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2 /dev/sdX +``` + +#### Option B: Using `dd` (Piped Decompression) +To avoid modifying the Yocto symlink files and save host disk space, decompress the image on-the-fly and pipe it directly to `dd`: +```bash +# Decompress on-the-fly and flash (replace /dev/sdX with your SD card device) +bzcat sw/build-minihil/tmp/deploy/images/raspberrypi3-64/minihil-image-raspberrypi3-64.rootfs.wic.bz2 | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync +``` + +--- + +### Running on Raspberry Pi 3B+ + +1. **Boot the board**: Insert the flashed SD card into your Raspberry Pi 3B+ and power it on. +2. **Access the console**: + - **Via SSH**: Connect as `root` using the default password `root`: + ```bash + ssh root@ + ``` + - **Via Serial UART**: Connect a USB-to-UART adapter to the Raspberry Pi GPIO header (TX on pin 8, RX on pin 10, GND on pin 6). Access the serial interface using `picocom` or `minicom` (enabled with `115200` baud rate by `ENABLE_UART = "1"` in `local.conf`): + ```bash + picocom -b 115200 /dev/ttyUSB0 + ``` +3. **Verify the Daemon**: Check that the `minihil` server starts automatically on boot: + ```bash + systemctl status minihil + ``` +4. **Test the JSON-RPC interface locally**: Send a command to port 9000 to query the relay states: + ```bash + echo '{"jsonrpc": "2.0", "method": "get_relays", "id": 1}' | nc localhost 9000 + ``` + +--- + ### JSON-RPC 2.0 API Specification You can send JSON-RPC text frames (terminated by `\n`) to port `9000`. diff --git a/sw/meta-minihil/conf/distro/minihil.conf b/sw/meta-minihil/conf/distro/minihil.conf new file mode 100644 index 0000000..4ec4f5d --- /dev/null +++ b/sw/meta-minihil/conf/distro/minihil.conf @@ -0,0 +1,11 @@ +require conf/distro/poky.conf + +DISTRO = "minihil" +DISTRO_NAME = "MiniHIL Linux Distribution" +DISTRO_VERSION = "1.0" + +# Use systemd as the init manager +INIT_MANAGER = "systemd" + +# Accept restricted license for Raspberry Pi wireless firmware +LICENSE_FLAGS_ACCEPTED += "synaptics-killswitch" diff --git a/sw/meta-minihil/conf/layer.conf b/sw/meta-minihil/conf/layer.conf index cfa8a1b..d1aab8b 100644 --- a/sw/meta-minihil/conf/layer.conf +++ b/sw/meta-minihil/conf/layer.conf @@ -11,3 +11,11 @@ BBFILE_PRIORITY_meta-minihil = "6" LAYERDEPENDS_meta-minihil = "core raspberrypi" LAYERSERIES_COMPAT_meta-minihil = "scarthgap" + +# Global configuration defaults for MiniHIL platform +INIT_MANAGER = "systemd" +LICENSE_FLAGS_ACCEPTED += "synaptics-killswitch" + +# Raspberry Pi Specific Settings (meta-raspberrypi) +ENABLE_UART = "1" +GPU_MEM = "128" diff --git a/sw/meta-minihil/conf/templates/default/local.conf.sample b/sw/meta-minihil/conf/templates/default/local.conf.sample index 7823c13..dd269f0 100644 --- a/sw/meta-minihil/conf/templates/default/local.conf.sample +++ b/sw/meta-minihil/conf/templates/default/local.conf.sample @@ -37,16 +37,5 @@ BB_DISKMON_DIRS ??= "\ # DL_DIR ?= "${TOPDIR}/downloads" # SSTATE_DIR ?= "${TOPDIR}/sstate-cache" -# ========================================================================= -# Raspberry Pi Specific Settings (meta-raspberrypi) -# ========================================================================= - -# Enable serial console/UART for hardware debugging -ENABLE_UART = "1" - -# GPU Memory split (in Megabytes) -# 64MB or 128MB is common for headless systems. Increase if running UI/OpenGL. -GPU_MEM = "128" - # Configuration Version (DO NOT EDIT) CONF_VERSION = "2" diff --git a/sw/meta-minihil/recipes-core/base-files/base-files_%.bbappend b/sw/meta-minihil/recipes-core/base-files/base-files_%.bbappend new file mode 100644 index 0000000..ee786a1 --- /dev/null +++ b/sw/meta-minihil/recipes-core/base-files/base-files_%.bbappend @@ -0,0 +1,2 @@ +# Set custom hostname for MiniHIL board +hostname = "minihil" diff --git a/sw/meta-minihil/recipes-core/images/minihil-image.bb b/sw/meta-minihil/recipes-core/images/minihil-image.bb index 1fa7acc..1fb6fae 100644 --- a/sw/meta-minihil/recipes-core/images/minihil-image.bb +++ b/sw/meta-minihil/recipes-core/images/minihil-image.bb @@ -15,5 +15,13 @@ IMAGE_INSTALL:append = " \ curl \ minihil \ libgpiod-tools \ + minihil-wifi-config \ ${CORE_IMAGE_EXTRA_INSTALL} \ " + +# Set default root password to 'root' for SSH login +inherit extrausers +EXTRA_USERS_PARAMS = "usermod -p '\$6\$PPKCFZH0Umomf26n\$HNEXabvmmTxiTTElkkKqupvxItpGIbJ9vQoyljK7dCb3XochlJwz5WRQykybUfH.fojSZKnYPLHPZ2aU75AYU0' root;" + +# Set rootfs partition size to 1GB (1048576 KB) +IMAGE_ROOTFS_SIZE = "1048576" diff --git a/sw/meta-minihil/recipes-core/init-ifupdown/files/interfaces b/sw/meta-minihil/recipes-core/init-ifupdown/files/interfaces new file mode 100644 index 0000000..3dec7cc --- /dev/null +++ b/sw/meta-minihil/recipes-core/init-ifupdown/files/interfaces @@ -0,0 +1,30 @@ +# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) + +# The loopback interface +auto lo +iface lo inet loopback + +# Wireless interfaces (automatically enabled on boot) +auto wlan0 +iface wlan0 inet dhcp + wireless_mode managed + wireless_essid any + wpa-driver wext + wpa-conf /etc/wpa_supplicant.conf + +iface atml0 inet dhcp + +# Wired or wireless interfaces including predictable names +auto eth0 +iface eth0 inet dhcp +iface eth1 inet dhcp + +# Busybox ifupdown won't process /en* correctly +auto /en*=eth +iface eth inet dhcp + +# Ethernet/RNDIS gadget (g_ether) +iface usb0 inet dhcp + +# Bluetooth networking +iface bnep0 inet dhcp diff --git a/sw/meta-minihil/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend b/sw/meta-minihil/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend new file mode 100644 index 0000000..8802adb --- /dev/null +++ b/sw/meta-minihil/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend @@ -0,0 +1 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" diff --git a/sw/meta-minihil/recipes-core/minihil-wifi-config/files/25-wlan0.network b/sw/meta-minihil/recipes-core/minihil-wifi-config/files/25-wlan0.network new file mode 100644 index 0000000..36d3a47 --- /dev/null +++ b/sw/meta-minihil/recipes-core/minihil-wifi-config/files/25-wlan0.network @@ -0,0 +1,5 @@ +[Match] +Name=wlan0 + +[Network] +DHCP=yes diff --git a/sw/meta-minihil/recipes-core/minihil-wifi-config/minihil-wifi-config.bb b/sw/meta-minihil/recipes-core/minihil-wifi-config/minihil-wifi-config.bb new file mode 100644 index 0000000..4e6f84c --- /dev/null +++ b/sw/meta-minihil/recipes-core/minihil-wifi-config/minihil-wifi-config.bb @@ -0,0 +1,31 @@ +SUMMARY = "Wireless configuration for systemd-networkd on MiniHIL" +DESCRIPTION = "Enables DHCP on wlan0 and autostarts wpa_supplicant service under systemd." +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" + +SRC_URI = "file://25-wlan0.network" + +S = "${WORKDIR}" + +do_install() { + # 1. Install systemd-networkd configuration for wlan0 + install -d ${D}${sysconfdir}/systemd/network + install -m 0644 ${WORKDIR}/25-wlan0.network ${D}${sysconfdir}/systemd/network/ + + # 2. Symlink wpa_supplicant-wlan0.conf to wpa_supplicant.conf + # wpa_supplicant@wlan0.service looks for /etc/wpa_supplicant/wpa_supplicant-wlan0.conf + install -d ${D}${sysconfdir}/wpa_supplicant + ln -sf ../wpa_supplicant.conf ${D}${sysconfdir}/wpa_supplicant/wpa_supplicant-wlan0.conf + + # 3. Enable wpa_supplicant@wlan0.service on boot + install -d ${D}${sysconfdir}/systemd/system/multi-user.target.wants + ln -sf ${systemd_system_unitdir}/wpa_supplicant@.service ${D}${sysconfdir}/systemd/system/multi-user.target.wants/wpa_supplicant@wlan0.service +} + +FILES:${PN} += " \ + ${sysconfdir}/systemd/network/25-wlan0.network \ + ${sysconfdir}/wpa_supplicant/wpa_supplicant-wlan0.conf \ + ${sysconfdir}/systemd/system/multi-user.target.wants/wpa_supplicant@wlan0.service \ +" + +RDEPENDS:${PN} += "wpa-supplicant" diff --git a/sw/meta-minihil/recipes-core/minihil/minihil.bb b/sw/meta-minihil/recipes-core/minihil/minihil.bb index 52a7002..cf11a91 100644 --- a/sw/meta-minihil/recipes-core/minihil/minihil.bb +++ b/sw/meta-minihil/recipes-core/minihil/minihil.bb @@ -12,9 +12,9 @@ SRC_URI = "file://minihil" S = "${WORKDIR}/minihil" # Dependencies -DEPENDS = "libgpiod nlohmann-json" +DEPENDS = "libgpiod nlohmann-json openssl" -inherit cmake systemd +inherit cmake pkgconfig systemd # Package the systemd unit SYSTEMD_SERVICE:${PN} = "minihil.service" diff --git a/sw/minihil/src/hardware/gpiod_relay_controller.cpp b/sw/minihil/src/hardware/gpiod_relay_controller.cpp index 53b8175..04bd05c 100644 --- a/sw/minihil/src/hardware/gpiod_relay_controller.cpp +++ b/sw/minihil/src/hardware/gpiod_relay_controller.cpp @@ -8,7 +8,7 @@ namespace minihil { struct GpiodRelayController::Impl { std::unique_ptr<::gpiod::chip> chip; - ::gpiod::line_request request; + std::unique_ptr<::gpiod::line_request> request; }; GpiodRelayController::GpiodRelayController() @@ -67,7 +67,12 @@ bool GpiodRelayController::init() { ::gpiod::request_config req_cfg; req_cfg.set_consumer("minihild"); - m_impl->request = m_impl->chip->request_lines(req_cfg, line_cfg); + m_impl->request = std::make_unique<::gpiod::line_request>( + m_impl->chip->prepare_request() + .set_request_config(req_cfg) + .set_line_config(line_cfg) + .do_request() + ); std::cout << "[GpiodRelayController] GPIO lines requested and configured as OUTPUT." << std::endl; return true; } catch (const std::exception& e) { @@ -81,8 +86,9 @@ bool GpiodRelayController::setRelay(int relayId, bool state) { m_states[relayId] = state; try { + if (!m_impl->request) return false; unsigned int offset = m_relayGpioMap.at(relayId); - m_impl->request.set_value(offset, state ? ::gpiod::line::value::INACTIVE : ::gpiod::line::value::ACTIVE); + m_impl->request->set_value(offset, state ? ::gpiod::line::value::INACTIVE : ::gpiod::line::value::ACTIVE); return true; } catch (const std::exception& e) { std::cerr << "[GpiodRelayController] Error setting relay " << relayId << ": " << e.what() << std::endl;