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
74 changes: 71 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**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)

Expand Down Expand Up @@ -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@<rpi-ip-address>
```
- **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`.
Expand Down
11 changes: 11 additions & 0 deletions sw/meta-minihil/conf/distro/minihil.conf
Original file line number Diff line number Diff line change
@@ -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"
8 changes: 8 additions & 0 deletions sw/meta-minihil/conf/layer.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
11 changes: 0 additions & 11 deletions sw/meta-minihil/conf/templates/default/local.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 2 additions & 0 deletions sw/meta-minihil/recipes-core/base-files/base-files_%.bbappend
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Set custom hostname for MiniHIL board
hostname = "minihil"
8 changes: 8 additions & 0 deletions sw/meta-minihil/recipes-core/images/minihil-image.bb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
30 changes: 30 additions & 0 deletions sw/meta-minihil/recipes-core/init-ifupdown/files/interfaces
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Match]
Name=wlan0

[Network]
DHCP=yes
Original file line number Diff line number Diff line change
@@ -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"
4 changes: 2 additions & 2 deletions sw/meta-minihil/recipes-core/minihil/minihil.bb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 9 additions & 3 deletions sw/minihil/src/hardware/gpiod_relay_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down