Create a radio module
A HamBench radio module is JSON only. It does not ship executable code. Encode and decode use MemoryMapRadioCodec in @springfield/ham-radio-utils. The generic driver in @springfield/ham-radio-driver runs the protocol DSL.
Ship configs/, src/shared/schemas/, and src/shared/memory-maps/ in a GitHub Release zip. Tests may use TypeScript; they are not part of the zip.
Layout
radio-module-example/
├── package.json
├── configs/
│ └── example-radio.json
├── src/shared/
│ ├── schemas/
│ │ ├── channel-schema.json
│ │ └── settings-schema.json
│ └── memory-maps/
│ └── example-settings.json
└── test/
├── unit/
└── integration/See radio-module-baofeng and radio-module-kenwood.
package.json
{
"name": "@springfield/radio-module-example",
"version": "1.0.0",
"description": "JSON radio module",
"files": ["configs/", "src/shared/schemas/", "src/shared/memory-maps/"],
"springfield": {
"pluginType": "radio-module",
"manufacturer": "Example",
"configPath": "configs",
"sharedPath": "src/shared",
"capabilities": {
"dslProtocols": true,
"memoryRead": true,
"memoryWrite": true
}
}
}Do not set main, types, or a codec factory path. There is no module entrypoint.
Radio JSON
Each configs/*.json file is one radio. It owns protocol steps, serial settings, memory segments, schema $refs, a memory-map $ref, and codec.type: "memoryMap".
{
"id": {
"model": "example-radio",
"name": "Example Radio",
"manufacturer": "Example"
},
"version": "1.0.0",
"capabilities": {
"memoryRead": true,
"memoryWrite": true,
"channelProgramming": true,
"settingsProgramming": true,
"liveControl": false
},
"settingsSchema": {
"model": "example-radio",
"settingsSchema": { "$ref": "../src/shared/schemas/settings-schema.json" },
"channelSchema": { "$ref": "../src/shared/schemas/channel-schema.json" }
},
"memoryMap": { "$ref": "../src/shared/memory-maps/example-settings.json" },
"codec": { "type": "memoryMap" },
"serialConfig": {
"baudRate": 9600,
"dataBits": 8,
"stopBits": 1,
"parity": "none"
},
"memoryConfig": {
"chunkSize": 64,
"addressSize": 2,
"addressEndianness": "big",
"segments": {
"channels": { "startAddress": 0, "endAddress": 1023 }
}
},
"readMemory": [],
"writeMemory": []
}- Protocol: Protocol DSL (
send/expect,read/write, orcatRead/catWrite). - Memory packing: Memory-map DSL. Declare
groupson the map so the Settings tab can show labeled sections in the left nav; nestedgroupsplus fieldui.subgroupbecome headed sections in the panel. Each fieldui.groupmatches a top-level groupid. - Live VFO: set
capabilities.liveControland acatblock. That is still JSON, not code. - If the PC port accepts more than one baud, list
serialConfig.baudRatesand setbaudRateto the default.
pack:release stamps package.json's version into every configs/*.json version field. Do not bump those fields by hand. It also writes dist-release/catalog-module.json from those configs for the official catalog index.
What HamBench loads
The desktop app downloads the zip, keeps JSON only, and uses:
- The protocol steps with the generic driver
codec.type: "memoryMap"plus the referenced map withcreateMemoryMapCodec()from@springfield/ham-radio-utils
No TypeScript from the module is imported or executed.
Tests
Tests live in the module repo and may import HamBench packages. They are not shipped in the release zip.
import { createMemoryMapCodec } from '@springfield/ham-radio-utils';
import { MockLogLayer } from 'loglayer';
const codec = createMemoryMapCodec({
radioModel: config.id.model,
memoryMap,
memoryConfig: config.memoryConfig,
logger: new MockLogLayer(),
});Publish
See Publish a module. Users install from the app: Install radios.