Embedded Mastery Series · Volume 1 · Companion

Bench Tools

Mac- and Linux-side helper scripts that pair with the Volume 1 labs. These don't run on the NUCLEO — they run on your development host, providing the network endpoints, fixtures, and scaffolding the embedded labs need.

fake_ntp_server.py — Local SNTPv4 server for §S12.2

The Stage 12.2 lab points the board's SNTPv4 client at 192.168.100.230:123. Rather than rely on the public NTP pool (which would require routing the bench from the P2P 192.168.100.0/24 subnet onto the wider internet), the lab runs a minimal SNTPv4 server on your Mac that responds with the host's current time. About 50 lines of stdlib Python; no third-party dependencies.

Setup

  1. Plug the Ethernet adapter into the Mac and wire it directly to the NUCLEO's CN14 RJ45.
  2. Configure the Mac's adapter to a static IP on the bench subnet: 192.168.100.230 / 255.255.255.0, no gateway, no DNS. (System Settings → Network → that adapter → Details → TCP/IP → Configure IPv4 = Manually).
  3. Save fake_ntp_server.py below to your Mac.
  4. Run with sudo (UDP port 123 is privileged):
sudo python3 fake_ntp_server.py

Expected output once the board boots and starts polling:

[fake-ntp] listening on 0.0.0.0:123
[fake-ntp] replied to 192.168.100.10:54321 with ntp_seconds=3964258245
[fake-ntp] replied to 192.168.100.10:54321 with ntp_seconds=3964258250

On the board's VCP you should see human-readable UTC timestamps updating every 5 s:

NTP sync: 2026-05-03 16:30:45 UTC (unix_ts=1777854645)
NTP sync: 2026-05-03 16:30:50 UTC (unix_ts=1777854650)

Source — fake_ntp_server.py

--- BEGIN EMBED:fake_ntp_server_py ---
#!/usr/bin/env python3
"""Minimal SNTPv4 server for V1 S12.2 NTP client lab.

Listens on UDP :123, responds with current Unix time converted to NTP
epoch (seconds since 1900-01-01). Bind to 192.168.100.230 to match the
board's hard-coded NTP_SERVER_IP. Run with sudo (port < 1024).
"""
import socket
import struct
import time

NTP_TO_UNIX_OFFSET = 2208988800  # seconds between 1900-01-01 and 1970-01-01

def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(("0.0.0.0", 123))
    print("[fake-ntp] listening on 0.0.0.0:123")
    while True:
        data, addr = sock.recvfrom(2048)
        if len(data) < 48:
            continue
        ntp_seconds = int(time.time()) + NTP_TO_UNIX_OFFSET
        ntp_fraction = 0
        # LI=0, VN=4, Mode=4 (server) → 0x24
        # Stratum=1, Poll=4, Precision=-20 (~1us)
        resp = bytearray(48)
        resp[0] = 0x24
        resp[1] = 1     # stratum 1
        resp[2] = 4     # poll
        resp[3] = 0xEC  # precision -20 (signed int8)
        # Reference identifier 'LOCL'
        resp[12:16] = b"LOCL"
        # Reference timestamp
        resp[16:20] = struct.pack(">I", ntp_seconds)
        resp[20:24] = struct.pack(">I", 0)
        # Originate timestamp = client's transmit timestamp (bytes 40..47 of req)
        resp[24:32] = data[40:48]
        # Receive timestamp
        resp[32:36] = struct.pack(">I", ntp_seconds)
        resp[36:40] = struct.pack(">I", 0)
        # Transmit timestamp
        resp[40:44] = struct.pack(">I", ntp_seconds)
        resp[44:48] = struct.pack(">I", ntp_fraction)
        sock.sendto(bytes(resp), addr)
        print(f"[fake-ntp] replied to {addr[0]}:{addr[1]} with ntp_seconds={ntp_seconds}")

if __name__ == "__main__":
    main()
--- END EMBED:fake_ntp_server_py ---

Other bench helpers

The Volume 1 bench loop ships a small set of build/flash/capture shell scripts under bench/ in the GitHub repo (iterate.sh, flash.sh, capture.sh, vcp.sh) — these automate the headless STM32CubeIDE build, ST-Programmer-CLI flash, and tio-based VCP capture. They're convenience for the maintainers' day-to-day work, not required for the customer's normal lab flow (the labs are written to be run interactively in STM32CubeIDE).

If you want the same automation on your bench: clone github.com/pbwarmu017/Mastering-Series-Books and run bench/README.md's setup steps.

Volume 1 — STM32H5 · Bench Tools · Source rev v2.8 · Last revised 2026-05-03