Blazor app with can interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.4 KiB

CLAUDE.md — IO Module Blazor Dashboard

Project Overview

Blazor Server app (.NET 10) for monitoring and controlling the STM32H723ZG Nucleo IO module. Communicates over CAN (via PCAN-USB adapter) and serial (via ST-Link VCP).

Architecture

PCAN Hardware ──► CanWorker (IHostedService) ──► CanService (singleton) ──► Razor pages
ST-Link VCP   ──► SerialPortService (singleton, event-driven)           ──► SerialTerminal.razor
  • Blazor Server — all C# runs server-side; browser connects via WebSocket/SignalR
  • No background worker for serialSystem.IO.Ports.SerialPort fires DataReceived events internally; SerialPortService handles buffering directly

Key Files

File Purpose
Services/ICanService.cs / CanService.cs PCAN adapter: send, receive, filter, signal extraction
Services/ISerialPortService.cs / SerialPortService.cs Serial port: open/close, send lines, receive buffer
CanWorker.cs IHostedService — continuous CAN RX loop, loads config from appsettings.json
Models/CanModels.cs CanMessageDto, CanFilter, CanBitmask
Components/Pages/Home.razor Button status + termination toggles + CAN message list
Components/Pages/CanMonitor.razor Full CAN UI: connect, stream, filters, bitmasks, send
Components/Pages/SerialTerminal.razor Serial terminal for NVMEM commands

CAN Sending Pattern

// PcanMessage.Data is read-only — pass data via the constructor, NOT object initializer + CopyTo
var data = new byte[8];
data[0] = payload;
var msg = new PcanMessage(0x240, MessageType.Standard, 8, data, false);
var result = CanService.Write(msg);  // returns PcanStatus.OK on success

UI State Update Pattern

Pages poll CanService.GetLatestMessages() via a Timer (50ms on Home, 100ms on CanMonitor):

_updateTimer = new Timer(_ => InvokeAsync(() => { /* update state */ StateHasChanged(); }), null, 0, 50);

Serial terminal subscribes to ISerialPortService.DataReceived event instead of polling.

CAN Message Map

ID Direction Handler
0x210 RX User button → button1Active in Home.razor
0x220 RX CN9-29 button → button2Active
0x230 RX CN9-30 button → button3Active
0x240 TX Termination control — sent from Home.razor:SendTermination()
0x250 RX Termination pin status — bit0=TERM_ON, bit1=TERM_OFF; syncs _termOn/_termOff in Home.razor
0x241 TX NVMEM write — sent from SerialTerminal via CAN (if needed)
0x242 TX NVMEM read request
0x243 RX NVMEM read response

CAN Config (appsettings.json)

"CanOptions": {
  "Channel": "",          // empty = auto-scan PCAN USB
  "Bitrate": "Pcan500",
  "Filters": [],          // CanFilter objects
  "Bitmasks": []          // CanBitmask objects for signal extraction
}

Serial Port Notes

  • SerialPortService is a singleton — only one port open at a time
  • Buffers last 200 lines; sent lines prefixed > , received prefixed <
  • NVMEM commands: r <addr_hex> <len> and w <addr_hex> <bytes...> at 115200 baud
  • Full command reference: ../STM32Nucleo/docs/NVMEMCommands.md

Build / Run

dotnet run --project IOModuleTestBlazor

Requires PCAN-Basic drivers installed. Serial port access requires the app to run with permission to open COM ports (no special config needed on Windows).