@springfield/ham-radio-utils 4.5.1 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"memory-map-codec.js","sourceRoot":"","sources":["../../src/memory/memory-map-codec.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RadioMemoryConfig,\n RadioMemoryMap,\n RadioMemoryMapField,\n RadioMemoryMapStruct,\n RadioMemoryMapValueKind,\n RadioSettings,\n RadioSettingValue,\n} from '@springfield/ham-radio-api';\n\nconst DEFAULT_DTMF_CHARSET = '0123456789 *#ABCD';\n\n/**\n * Parse a seek address from a number or hex/decimal string.\n */\nexport function parseSeekAddress(seek: number | string): number {\n if (typeof seek === 'number') {\n return seek;\n }\n\n const trimmed = seek.trim();\n\n if (/^0x/i.test(trimmed)) {\n return Number.parseInt(trimmed, 16);\n }\n\n return Number.parseInt(trimmed, 10);\n}\n\n/**\n * Map a radio EEPROM address to an offset in the memory buffer.\n *\n * Packed buffers (driver read) concatenate segments in config order.\n * Sparse buffers that cover the highest segment end address use absolute offsets.\n */\nexport function radioAddressToBufferOffset(\n radioAddress: number,\n memoryConfig: RadioMemoryConfig,\n bufferLength: number,\n): number {\n const segments = Object.values(memoryConfig.segments);\n const maxEndAddress = Math.max(...segments.map((segment) => segment.endAddress));\n\n if (bufferLength >= maxEndAddress + 1) {\n return radioAddress;\n }\n\n let offset = 0;\n\n for (const segment of segments) {\n if (radioAddress >= segment.startAddress && radioAddress <= segment.endAddress) {\n return offset + (radioAddress - segment.startAddress);\n }\n\n offset += segment.endAddress - segment.startAddress + 1;\n }\n\n throw new Error(`Radio address 0x${radioAddress.toString(16)} is not in any memory segment`);\n}\n\nfunction bufferOffsetFor(radioAddress: number, memoryConfig: RadioMemoryConfig, contents: Uint8Array): number {\n return radioAddressToBufferOffset(radioAddress, memoryConfig, contents.length);\n}\n\nfunction readByte(contents: Uint8Array, offset: number): number {\n if (offset < 0 || offset >= contents.length) {\n throw new RangeError(`Memory-map read out of bounds at offset ${offset}`);\n }\n\n return contents[offset];\n}\n\nfunction writeByte(contents: Uint8Array, offset: number, value: number): void {\n if (offset < 0 || offset >= contents.length) {\n throw new RangeError(`Memory-map write out of bounds at offset ${offset}`);\n }\n\n contents[offset] = value & 0xff;\n}\n\nfunction decodeRawValue(kind: RadioMemoryMapValueKind | undefined, raw: number | number[]): RadioSettingValue {\n if (!kind) {\n return typeof raw === 'number' ? raw : raw;\n }\n\n switch (kind.kind) {\n case 'integer':\n return typeof raw === 'number' ? raw : raw[0];\n case 'boolean':\n return (typeof raw === 'number' ? raw : raw[0]) !== 0;\n case 'enum': {\n const index = typeof raw === 'number' ? raw : raw[0];\n return kind.values[index] ?? kind.values[0] ?? '';\n }\n case 'ascii': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let text = '';\n\n for (const byte of bytes) {\n if (byte === 0xff || byte === 0x00) {\n break;\n }\n\n text += String.fromCodePoint(byte);\n }\n\n return text.trimEnd();\n }\n case 'digits': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let value = 0;\n\n for (const digit of bytes) {\n value = value * 10 + (digit & 0x0f);\n }\n\n return value * (kind.scale ?? 1);\n }\n case 'dtmf': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n const charset = kind.charset ?? DEFAULT_DTMF_CHARSET;\n let text = '';\n\n for (const byte of bytes) {\n if (byte >= 0x1f) {\n break;\n }\n\n if (byte < charset.length) {\n text += charset[byte];\n }\n }\n\n return text;\n }\n case 'bbcd': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let value = 0;\n\n for (const byte of bytes) {\n value = value * 100 + ((byte >> 4) & 0x0f) * 10 + (byte & 0x0f);\n }\n\n return value;\n }\n case 'lbcd': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let word = 0;\n\n for (let index = 0; index < bytes.length; index += 1) {\n word |= bytes[index] << (8 * index);\n }\n\n if (word === 0xff_ff_ff_ff || bytes.every((byte) => byte === 0xff)) {\n return null;\n }\n\n return Number.parseInt(word.toString(16), 10) * (kind.scale ?? 10);\n }\n case 'tone': {\n const rawValue = typeof raw === 'number' ? raw : raw[0] | (raw[1] << 8);\n const ctcssMin = kind.ctcssMin ?? 0x0258;\n const reverseOffset = kind.reverseOffset ?? 0x69;\n\n if (rawValue === 0 || rawValue === 0xffff) {\n return { mode: 'none' };\n }\n\n if (rawValue >= ctcssMin) {\n return { mode: 'ctcss', value: rawValue };\n }\n\n let index = rawValue;\n let polarity: 'N' | 'R' = 'N';\n\n if (rawValue > reverseOffset) {\n index = rawValue - reverseOffset;\n polarity = 'R';\n } else {\n index = rawValue - 1;\n }\n\n const code = kind.values[index] ?? 0;\n return { mode: 'dcs', code, polarity };\n }\n default: {\n const exhaustive: never = kind;\n return exhaustive;\n }\n }\n}\n\nfunction encodeRawValue(kind: RadioMemoryMapValueKind | undefined, value: RadioSettingValue, byteLength: number): number[] {\n const bytes = Array.from({ length: byteLength }, () => 0xff);\n\n if (!kind) {\n if (typeof value === 'number') {\n bytes[0] = value & 0xff;\n }\n\n return bytes;\n }\n\n switch (kind.kind) {\n case 'integer': {\n bytes[0] = typeof value === 'number' ? value & 0xff : 0;\n return bytes;\n }\n case 'boolean': {\n bytes[0] = value ? 1 : 0;\n return bytes;\n }\n case 'enum': {\n const index = typeof value === 'string' ? kind.values.indexOf(value) : -1;\n bytes[0] = index >= 0 ? index : 0;\n return bytes;\n }\n case 'ascii': {\n const text = typeof value === 'string' ? value : '';\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = index < text.length ? (text.codePointAt(index) ?? 0xff) : 0xff;\n }\n\n return bytes;\n }\n case 'digits': {\n const scale = kind.scale ?? 1;\n let numeric = typeof value === 'number' ? Math.round(value / scale) : 0;\n\n for (let index = byteLength - 1; index >= 0; index -= 1) {\n bytes[index] = numeric % 10;\n numeric = Math.floor(numeric / 10);\n }\n\n return bytes;\n }\n case 'dtmf': {\n const text = typeof value === 'string' ? value : '';\n const charset = kind.charset ?? DEFAULT_DTMF_CHARSET;\n\n for (let index = 0; index < byteLength; index += 1) {\n if (index < text.length) {\n const charIndex = charset.indexOf(text[index]);\n bytes[index] = charIndex >= 0 ? charIndex : 0xff;\n } else {\n bytes[index] = 0xff;\n }\n }\n\n return bytes;\n }\n case 'bbcd': {\n let numeric = typeof value === 'number' ? value : 0;\n const digits: number[] = [];\n\n for (let index = 0; index < byteLength * 2; index += 1) {\n digits.unshift(numeric % 10);\n numeric = Math.floor(numeric / 10);\n }\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = ((digits[index * 2] & 0x0f) << 4) | (digits[index * 2 + 1] & 0x0f);\n }\n\n return bytes;\n }\n case 'lbcd': {\n if (value === null || value === undefined) {\n return Array.from({ length: byteLength }, () => 0xff);\n }\n\n const scale = kind.scale ?? 10;\n const hz = typeof value === 'number' ? value : 0;\n let word = Number.parseInt(Math.round(hz / scale).toString(10), 16);\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = word & 0xff;\n word >>= 8;\n }\n\n return bytes;\n }\n case 'tone': {\n const ctcssMin = kind.ctcssMin ?? 0x0258;\n const reverseOffset = kind.reverseOffset ?? 0x69;\n let rawValue = 0;\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const tone = value as { mode?: string; value?: number; code?: number; polarity?: string };\n\n if (tone.mode === 'ctcss' && typeof tone.value === 'number') {\n rawValue = tone.value;\n } else if (tone.mode === 'dcs' && typeof tone.code === 'number') {\n const index = kind.values.indexOf(tone.code);\n rawValue = index >= 0 ? index + 1 : 0;\n\n if (tone.polarity === 'R') {\n rawValue += reverseOffset;\n }\n }\n }\n\n if (rawValue >= ctcssMin || rawValue === 0) {\n // CTCSS or none: write LE u16\n }\n\n bytes[0] = rawValue & 0xff;\n bytes[1] = (rawValue >> 8) & 0xff;\n return bytes;\n }\n default: {\n const exhaustive: never = kind;\n return exhaustive;\n }\n }\n}\n\nfunction fieldByteLength(field: RadioMemoryMapField): number {\n if (field.type === 'u16') {\n return 2;\n }\n\n if (field.type === 'bits') {\n return 0;\n }\n\n if (\n field.value?.kind === 'ascii' ||\n field.value?.kind === 'digits' ||\n field.value?.kind === 'dtmf' ||\n field.value?.kind === 'bbcd' ||\n field.value?.kind === 'lbcd'\n ) {\n return field.value.length;\n }\n\n if (field.value?.kind === 'tone') {\n return 2;\n }\n\n return 1;\n}\n\n/**\n * Chirp-style bitfields: declaration order is MSB → LSB within each byte.\n */\nclass BitfieldCursor {\n private radioAddress: number;\n private bitIndex = -1;\n private currentByte = 0;\n private dirty = false;\n\n constructor(\n private readonly contents: Uint8Array,\n private readonly memoryConfig: RadioMemoryConfig,\n startRadioAddress: number,\n ) {\n this.radioAddress = startRadioAddress;\n }\n\n private load(): void {\n if (this.bitIndex >= 0) {\n return;\n }\n\n this.currentByte = readByte(this.contents, bufferOffsetFor(this.radioAddress, this.memoryConfig, this.contents));\n this.bitIndex = 7;\n this.dirty = false;\n }\n\n private flushByte(): void {\n if (this.dirty) {\n writeByte(this.contents, bufferOffsetFor(this.radioAddress, this.memoryConfig, this.contents), this.currentByte);\n this.dirty = false;\n }\n }\n\n read(width: number): number {\n let result = 0;\n\n for (let bit = 0; bit < width; bit += 1) {\n this.load();\n result = (result << 1) | ((this.currentByte >> this.bitIndex) & 1);\n this.bitIndex -= 1;\n\n if (this.bitIndex < 0) {\n this.radioAddress += 1;\n }\n }\n\n return result;\n }\n\n write(width: number, value: number): void {\n for (let bit = width - 1; bit >= 0; bit -= 1) {\n this.load();\n const mask = 1 << this.bitIndex;\n\n if ((value >> bit) & 1) {\n this.currentByte |= mask;\n } else {\n this.currentByte &= ~mask;\n }\n\n this.dirty = true;\n this.bitIndex -= 1;\n\n if (this.bitIndex < 0) {\n this.flushByte();\n this.radioAddress += 1;\n }\n }\n }\n\n /**\n * Absolute radio address of the next unused byte after this bitfield group.\n */\n nextRadioAddress(): number {\n this.flushByte();\n\n if (this.bitIndex >= 0) {\n return this.radioAddress + 1;\n }\n\n return this.radioAddress;\n }\n}\n\nfunction decodeStruct(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): Record<string, RadioSettingValue> {\n const base = parseSeekAddress(struct.seek) + instanceIndex * (struct.stride ?? 0);\n const result: Record<string, RadioSettingValue> = {};\n let radioAddress = base;\n let bitCursor: BitfieldCursor | undefined;\n\n for (const field of struct.fields) {\n if (field.type === 'bits') {\n if (!bitCursor) {\n bitCursor = new BitfieldCursor(contents, memoryConfig, radioAddress);\n }\n\n const raw = bitCursor.read(field.width ?? 1);\n\n if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value ?? { kind: 'integer' }, raw);\n }\n\n continue;\n }\n\n if (bitCursor) {\n radioAddress = bitCursor.nextRadioAddress();\n bitCursor = undefined;\n }\n\n const length = fieldByteLength(field);\n const bytes: number[] = [];\n\n for (let index = 0; index < length; index += 1) {\n bytes.push(readByte(contents, bufferOffsetFor(radioAddress + index, memoryConfig, contents)));\n }\n\n if (field.type === 'u16') {\n if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value ?? { kind: 'integer' }, bytes);\n }\n } else if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value, length === 1 ? bytes[0] : bytes);\n }\n\n radioAddress += length;\n }\n\n return result;\n}\n\nfunction encodeStruct(\n struct: RadioMemoryMapStruct,\n values: Record<string, RadioSettingValue>,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): void {\n const base = parseSeekAddress(struct.seek) + instanceIndex * (struct.stride ?? 0);\n let radioAddress = base;\n let bitCursor: BitfieldCursor | undefined;\n let bitStartAddress = base;\n\n for (const field of struct.fields) {\n if (field.type === 'bits') {\n if (!bitCursor) {\n bitStartAddress = radioAddress;\n bitCursor = new BitfieldCursor(contents, memoryConfig, bitStartAddress);\n }\n\n const width = field.width ?? 1;\n\n if (field.reserved) {\n // Advance by reading existing bits (preserves memory)\n bitCursor.read(width);\n } else {\n const encoded = encodeRawValue(field.value ?? { kind: 'integer' }, values[field.id] ?? 0, 1);\n bitCursor.write(width, encoded[0]);\n }\n\n continue;\n }\n\n if (bitCursor) {\n radioAddress = bitCursor.nextRadioAddress();\n bitCursor = undefined;\n }\n\n const length = fieldByteLength(field);\n\n if (field.reserved) {\n radioAddress += length;\n continue;\n }\n\n const settingValue = values[field.id];\n\n if (field.type === 'u16') {\n const encoded = encodeRawValue(field.value ?? { kind: 'integer' }, settingValue ?? 0, 2);\n let value = 0;\n\n if (field.value?.kind === 'tone') {\n value = (encoded[0] & 0xff) | ((encoded[1] & 0xff) << 8);\n } else {\n value = (encoded[0] ?? 0) & 0xffff;\n }\n\n writeByte(contents, bufferOffsetFor(radioAddress, memoryConfig, contents), value & 0xff);\n writeByte(contents, bufferOffsetFor(radioAddress + 1, memoryConfig, contents), (value >> 8) & 0xff);\n } else {\n const encoded = encodeRawValue(field.value, settingValue ?? (field.value?.kind === 'ascii' ? '' : 0), length);\n\n for (let index = 0; index < length; index += 1) {\n writeByte(contents, bufferOffsetFor(radioAddress + index, memoryConfig, contents), encoded[index]);\n }\n }\n\n radioAddress += length;\n }\n\n if (bitCursor) {\n bitCursor.nextRadioAddress();\n }\n}\n\nfunction isStructInstanceEmpty(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): boolean {\n if (!struct.emptyWhen) {\n return false;\n }\n\n const base = parseSeekAddress(struct.seek) + instanceIndex * (struct.stride ?? 0);\n const firstByte = readByte(contents, bufferOffsetFor(base, memoryConfig, contents));\n return firstByte === struct.emptyWhen.equals;\n}\n\nfunction clearStructInstance(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): void {\n const base = parseSeekAddress(struct.seek) + instanceIndex * (struct.stride ?? 0);\n const length = struct.stride ?? 16;\n\n for (let index = 0; index < length; index += 1) {\n writeByte(contents, bufferOffsetFor(base + index, memoryConfig, contents), 0xff);\n }\n}\n\n/**\n * Decode radio-wide settings from a memory image using a JSON memory map.\n */\nexport function decodeMemoryMap(\n memoryMap: RadioMemoryMap,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): RadioSettings {\n const settings: RadioSettings = {};\n\n for (const struct of memoryMap.structs) {\n const count = struct.count ?? 1;\n\n if (count > 1) {\n const items: RadioSettingValue[] = [];\n\n for (let index = 0; index < count; index += 1) {\n if (isStructInstanceEmpty(struct, contents, memoryConfig, index)) {\n items.push(null);\n } else {\n items.push(decodeStruct(struct, contents, memoryConfig, index));\n }\n }\n\n settings[struct.id] = items;\n } else {\n settings[struct.id] = decodeStruct(struct, contents, memoryConfig, 0);\n }\n }\n\n return settings;\n}\n\n/**\n * Encode radio-wide settings into an existing memory image in place.\n * Returns the same buffer for convenience.\n */\nexport function encodeMemoryMap(\n memoryMap: RadioMemoryMap,\n settings: RadioSettings,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): Uint8Array {\n for (const struct of memoryMap.structs) {\n const count = struct.count ?? 1;\n const value = settings[struct.id];\n\n if (count > 1) {\n const items = Array.isArray(value) ? value : [];\n\n for (let index = 0; index < count; index += 1) {\n const item = items[index];\n\n if (item === null || item === undefined) {\n if (struct.clearEmpty) {\n clearStructInstance(struct, contents, memoryConfig, index);\n }\n\n continue;\n }\n\n const record =\n item && typeof item === 'object' && !Array.isArray(item) ? (item as Record<string, RadioSettingValue>) : {};\n encodeStruct(struct, record, contents, memoryConfig, index);\n }\n } else {\n const record =\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, RadioSettingValue>) : {};\n encodeStruct(struct, record, contents, memoryConfig, 0);\n }\n }\n\n return contents;\n}\n"]}
1
+ {"version":3,"file":"memory-map-codec.js","sourceRoot":"","sources":["../../src/memory/memory-map-codec.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RadioMemoryConfig,\n RadioMemoryMap,\n RadioMemoryMapField,\n RadioMemoryMapStruct,\n RadioMemoryMapValueKind,\n RadioSettings,\n RadioSettingValue,\n} from '@springfield/ham-radio-api';\n\nconst DEFAULT_DTMF_CHARSET = '0123456789 *#ABCD';\n\n/**\n * Parse a seek address from a number or hex/decimal string.\n */\nexport function parseSeekAddress(seek: number | string): number {\n if (typeof seek === 'number') {\n return seek;\n }\n\n const trimmed = seek.trim();\n\n if (/^0x/i.test(trimmed)) {\n return Number.parseInt(trimmed, 16);\n }\n\n return Number.parseInt(trimmed, 10);\n}\n\n/**\n * Map a radio EEPROM address to an offset in the memory buffer.\n *\n * Packed buffers (driver read) concatenate segments in config order.\n * Sparse buffers that cover the highest segment end address use absolute offsets.\n */\nexport function radioAddressToBufferOffset(\n radioAddress: number,\n memoryConfig: RadioMemoryConfig,\n bufferLength: number,\n): number {\n const segments = Object.values(memoryConfig.segments);\n const maxEndAddress = Math.max(...segments.map((segment) => segment.endAddress));\n\n if (bufferLength >= maxEndAddress + 1) {\n return radioAddress;\n }\n\n let offset = 0;\n\n for (const segment of segments) {\n if (radioAddress >= segment.startAddress && radioAddress <= segment.endAddress) {\n return offset + (radioAddress - segment.startAddress);\n }\n\n offset += segment.endAddress - segment.startAddress + 1;\n }\n\n throw new Error(`Radio address 0x${radioAddress.toString(16)} is not in any memory segment`);\n}\n\nfunction bufferOffsetFor(radioAddress: number, memoryConfig: RadioMemoryConfig, contents: Uint8Array): number {\n return radioAddressToBufferOffset(radioAddress, memoryConfig, contents.length);\n}\n\nfunction readByte(contents: Uint8Array, offset: number): number {\n if (offset < 0 || offset >= contents.length) {\n throw new RangeError(`Memory-map read out of bounds at offset ${offset}`);\n }\n\n return contents[offset];\n}\n\nfunction writeByte(contents: Uint8Array, offset: number, value: number): void {\n if (offset < 0 || offset >= contents.length) {\n throw new RangeError(`Memory-map write out of bounds at offset ${offset}`);\n }\n\n contents[offset] = value & 0xff;\n}\n\nfunction decodeInteger(raw: number | number[]): number {\n if (typeof raw === 'number') {\n return raw;\n }\n\n let value = 0;\n\n for (let index = 0; index < raw.length; index += 1) {\n value += raw[index] * 256 ** index;\n }\n\n return value;\n}\n\nfunction encodeInteger(value: RadioSettingValue, byteLength: number): number[] {\n let numeric = typeof value === 'number' ? value : 0;\n const bytes: number[] = [];\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes.push(numeric & 0xff);\n numeric = Math.floor(numeric / 256);\n }\n\n return bytes;\n}\n\n/**\n * Radio address of repeated-struct instance `index`, including Kenwood-style\n * grouped stride (N records + pad bytes per clone block).\n */\nexport function structInstanceAddress(struct: RadioMemoryMapStruct, instanceIndex: number): number {\n const seek = parseSeekAddress(struct.seek);\n const stride = struct.stride ?? 0;\n const groupSize = struct.groupSize;\n\n if (!groupSize) {\n return seek + instanceIndex * stride;\n }\n\n const groupPad = struct.groupPad ?? 0;\n const groupIndex = Math.floor(instanceIndex / groupSize);\n const indexInGroup = instanceIndex % groupSize;\n\n return seek + groupIndex * (stride * groupSize + groupPad) + indexInGroup * stride;\n}\n\nfunction decodeRawValue(kind: RadioMemoryMapValueKind | undefined, raw: number | number[]): RadioSettingValue {\n if (!kind) {\n return typeof raw === 'number' ? raw : raw;\n }\n\n switch (kind.kind) {\n case 'integer':\n return decodeInteger(raw);\n case 'boolean':\n return (typeof raw === 'number' ? raw : raw[0]) !== 0;\n case 'enum': {\n const index = typeof raw === 'number' ? raw : raw[0];\n return kind.values[index] ?? kind.values[0] ?? '';\n }\n case 'ascii': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let text = '';\n\n for (const byte of bytes) {\n if (byte === 0xff || byte === 0x00) {\n break;\n }\n\n text += String.fromCodePoint(byte);\n }\n\n return text.trimEnd();\n }\n case 'digits': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let value = 0;\n\n for (const digit of bytes) {\n value = value * 10 + (digit & 0x0f);\n }\n\n return value * (kind.scale ?? 1);\n }\n case 'dtmf': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n const charset = kind.charset ?? DEFAULT_DTMF_CHARSET;\n let text = '';\n\n for (const byte of bytes) {\n if (byte >= 0x1f) {\n break;\n }\n\n if (byte < charset.length) {\n text += charset[byte];\n }\n }\n\n return text;\n }\n case 'bbcd': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let value = 0;\n\n for (const byte of bytes) {\n value = value * 100 + ((byte >> 4) & 0x0f) * 10 + (byte & 0x0f);\n }\n\n return value;\n }\n case 'lbcd': {\n const bytes = typeof raw === 'number' ? [raw] : raw;\n let word = 0;\n\n for (let index = 0; index < bytes.length; index += 1) {\n word |= bytes[index] << (8 * index);\n }\n\n if (word === 0xff_ff_ff_ff || bytes.every((byte) => byte === 0xff)) {\n return null;\n }\n\n return Number.parseInt(word.toString(16), 10) * (kind.scale ?? 10);\n }\n case 'tone': {\n const rawValue = typeof raw === 'number' ? raw : raw[0] | (raw[1] << 8);\n const ctcssMin = kind.ctcssMin ?? 0x0258;\n const reverseOffset = kind.reverseOffset ?? 0x69;\n\n if (rawValue === 0 || rawValue === 0xffff) {\n return { mode: 'none' };\n }\n\n if (rawValue >= ctcssMin) {\n return { mode: 'ctcss', value: rawValue };\n }\n\n let index = rawValue;\n let polarity: 'N' | 'R' = 'N';\n\n if (rawValue > reverseOffset) {\n index = rawValue - reverseOffset;\n polarity = 'R';\n } else {\n index = rawValue - 1;\n }\n\n const code = kind.values[index] ?? 0;\n return { mode: 'dcs', code, polarity };\n }\n case 'ctcss-index': {\n const index = decodeInteger(raw);\n const tenths = kind.values[index] ?? kind.values[0] ?? 0;\n return { mode: 'ctcss', value: tenths };\n }\n case 'dcs-index': {\n const index = decodeInteger(raw);\n const code = kind.values[index] ?? 0;\n return { mode: 'dcs', code, polarity: 'N' };\n }\n default: {\n const exhaustive: never = kind;\n return exhaustive;\n }\n }\n}\n\nfunction encodeRawValue(kind: RadioMemoryMapValueKind | undefined, value: RadioSettingValue, byteLength: number): number[] {\n const bytes = Array.from({ length: byteLength }, () => 0xff);\n\n if (!kind) {\n if (typeof value === 'number') {\n bytes[0] = value & 0xff;\n }\n\n return bytes;\n }\n\n switch (kind.kind) {\n case 'integer': {\n return encodeInteger(value, byteLength);\n }\n case 'boolean': {\n bytes[0] = value ? 1 : 0;\n return bytes;\n }\n case 'enum': {\n const index = typeof value === 'string' ? kind.values.indexOf(value) : -1;\n bytes[0] = index >= 0 ? index : 0;\n return bytes;\n }\n case 'ascii': {\n const text = typeof value === 'string' ? value : '';\n const pad = kind.pad ?? 0xff;\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = index < text.length ? (text.codePointAt(index) ?? pad) : pad;\n }\n\n return bytes;\n }\n case 'digits': {\n const scale = kind.scale ?? 1;\n let numeric = typeof value === 'number' ? Math.round(value / scale) : 0;\n\n for (let index = byteLength - 1; index >= 0; index -= 1) {\n bytes[index] = numeric % 10;\n numeric = Math.floor(numeric / 10);\n }\n\n return bytes;\n }\n case 'dtmf': {\n const text = typeof value === 'string' ? value : '';\n const charset = kind.charset ?? DEFAULT_DTMF_CHARSET;\n\n for (let index = 0; index < byteLength; index += 1) {\n if (index < text.length) {\n const charIndex = charset.indexOf(text[index]);\n bytes[index] = charIndex >= 0 ? charIndex : 0xff;\n } else {\n bytes[index] = 0xff;\n }\n }\n\n return bytes;\n }\n case 'bbcd': {\n let numeric = typeof value === 'number' ? value : 0;\n const digits: number[] = [];\n\n for (let index = 0; index < byteLength * 2; index += 1) {\n digits.unshift(numeric % 10);\n numeric = Math.floor(numeric / 10);\n }\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = ((digits[index * 2] & 0x0f) << 4) | (digits[index * 2 + 1] & 0x0f);\n }\n\n return bytes;\n }\n case 'lbcd': {\n if (value === null || value === undefined) {\n return Array.from({ length: byteLength }, () => 0xff);\n }\n\n const scale = kind.scale ?? 10;\n const hz = typeof value === 'number' ? value : 0;\n let word = Number.parseInt(Math.round(hz / scale).toString(10), 16);\n\n for (let index = 0; index < byteLength; index += 1) {\n bytes[index] = word & 0xff;\n word >>= 8;\n }\n\n return bytes;\n }\n case 'tone': {\n const ctcssMin = kind.ctcssMin ?? 0x0258;\n const reverseOffset = kind.reverseOffset ?? 0x69;\n let rawValue = 0;\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const tone = value as { mode?: string; value?: number; code?: number; polarity?: string };\n\n if (tone.mode === 'ctcss' && typeof tone.value === 'number') {\n rawValue = tone.value;\n } else if (tone.mode === 'dcs' && typeof tone.code === 'number') {\n const index = kind.values.indexOf(tone.code);\n rawValue = index >= 0 ? index + 1 : 0;\n\n if (tone.polarity === 'R') {\n rawValue += reverseOffset;\n }\n }\n }\n\n if (rawValue >= ctcssMin || rawValue === 0) {\n // CTCSS or none: write LE u16\n }\n\n bytes[0] = rawValue & 0xff;\n bytes[1] = (rawValue >> 8) & 0xff;\n return bytes;\n }\n case 'ctcss-index': {\n const tone = value && typeof value === 'object' && !Array.isArray(value) ? (value as { mode?: string; value?: number }) : undefined;\n const tenths = tone?.mode === 'ctcss' && typeof tone.value === 'number' ? tone.value : 0;\n const index = kind.values.indexOf(tenths);\n return encodeInteger(index >= 0 ? index : 0, byteLength);\n }\n case 'dcs-index': {\n const tone = value && typeof value === 'object' && !Array.isArray(value) ? (value as { mode?: string; code?: number }) : undefined;\n const code = tone?.mode === 'dcs' && typeof tone.code === 'number' ? tone.code : 0;\n const index = kind.values.indexOf(code);\n return encodeInteger(index >= 0 ? index : 0, byteLength);\n }\n default: {\n const exhaustive: never = kind;\n return exhaustive;\n }\n }\n}\n\nfunction fieldByteLength(field: RadioMemoryMapField): number {\n if (field.type === 'u32') {\n return 4;\n }\n\n if (field.type === 'u16') {\n return 2;\n }\n\n if (field.type === 'bits') {\n return 0;\n }\n\n if (\n field.value?.kind === 'ascii' ||\n field.value?.kind === 'digits' ||\n field.value?.kind === 'dtmf' ||\n field.value?.kind === 'bbcd' ||\n field.value?.kind === 'lbcd'\n ) {\n return field.value.length;\n }\n\n if (field.value?.kind === 'tone') {\n return 2;\n }\n\n return 1;\n}\n\n/**\n * Chirp-style bitfields: declaration order is MSB → LSB within each byte.\n */\nclass BitfieldCursor {\n private radioAddress: number;\n private bitIndex = -1;\n private currentByte = 0;\n private dirty = false;\n\n constructor(\n private readonly contents: Uint8Array,\n private readonly memoryConfig: RadioMemoryConfig,\n startRadioAddress: number,\n ) {\n this.radioAddress = startRadioAddress;\n }\n\n private load(): void {\n if (this.bitIndex >= 0) {\n return;\n }\n\n this.currentByte = readByte(this.contents, bufferOffsetFor(this.radioAddress, this.memoryConfig, this.contents));\n this.bitIndex = 7;\n this.dirty = false;\n }\n\n private flushByte(): void {\n if (this.dirty) {\n writeByte(this.contents, bufferOffsetFor(this.radioAddress, this.memoryConfig, this.contents), this.currentByte);\n this.dirty = false;\n }\n }\n\n read(width: number): number {\n let result = 0;\n\n for (let bit = 0; bit < width; bit += 1) {\n this.load();\n result = (result << 1) | ((this.currentByte >> this.bitIndex) & 1);\n this.bitIndex -= 1;\n\n if (this.bitIndex < 0) {\n this.radioAddress += 1;\n }\n }\n\n return result;\n }\n\n write(width: number, value: number): void {\n for (let bit = width - 1; bit >= 0; bit -= 1) {\n this.load();\n const mask = 1 << this.bitIndex;\n\n if ((value >> bit) & 1) {\n this.currentByte |= mask;\n } else {\n this.currentByte &= ~mask;\n }\n\n this.dirty = true;\n this.bitIndex -= 1;\n\n if (this.bitIndex < 0) {\n this.flushByte();\n this.radioAddress += 1;\n }\n }\n }\n\n /**\n * Absolute radio address of the next unused byte after this bitfield group.\n */\n nextRadioAddress(): number {\n this.flushByte();\n\n if (this.bitIndex >= 0) {\n return this.radioAddress + 1;\n }\n\n return this.radioAddress;\n }\n}\n\nfunction decodeStruct(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): Record<string, RadioSettingValue> {\n const base = structInstanceAddress(struct, instanceIndex);\n const result: Record<string, RadioSettingValue> = {};\n let radioAddress = base;\n let bitCursor: BitfieldCursor | undefined;\n\n for (const field of struct.fields) {\n if (field.type === 'bits') {\n if (!bitCursor) {\n bitCursor = new BitfieldCursor(contents, memoryConfig, radioAddress);\n }\n\n const raw = bitCursor.read(field.width ?? 1);\n\n if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value ?? { kind: 'integer' }, raw);\n }\n\n continue;\n }\n\n if (bitCursor) {\n radioAddress = bitCursor.nextRadioAddress();\n bitCursor = undefined;\n }\n\n const length = fieldByteLength(field);\n const bytes: number[] = [];\n\n for (let index = 0; index < length; index += 1) {\n bytes.push(readByte(contents, bufferOffsetFor(radioAddress + index, memoryConfig, contents)));\n }\n\n if (field.type === 'u16' || field.type === 'u32') {\n if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value ?? { kind: 'integer' }, bytes);\n }\n } else if (!field.reserved) {\n result[field.id] = decodeRawValue(field.value, length === 1 ? bytes[0] : bytes);\n }\n\n radioAddress += length;\n }\n\n return result;\n}\n\nfunction encodeStruct(\n struct: RadioMemoryMapStruct,\n values: Record<string, RadioSettingValue>,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): void {\n const base = structInstanceAddress(struct, instanceIndex);\n let radioAddress = base;\n let bitCursor: BitfieldCursor | undefined;\n let bitStartAddress = base;\n\n for (const field of struct.fields) {\n if (field.type === 'bits') {\n if (!bitCursor) {\n bitStartAddress = radioAddress;\n bitCursor = new BitfieldCursor(contents, memoryConfig, bitStartAddress);\n }\n\n const width = field.width ?? 1;\n\n if (field.reserved) {\n // Advance by reading existing bits (preserves memory)\n bitCursor.read(width);\n } else {\n const encoded = encodeRawValue(field.value ?? { kind: 'integer' }, values[field.id] ?? 0, 1);\n bitCursor.write(width, encoded[0]);\n }\n\n continue;\n }\n\n if (bitCursor) {\n radioAddress = bitCursor.nextRadioAddress();\n bitCursor = undefined;\n }\n\n const length = fieldByteLength(field);\n\n if (field.reserved) {\n radioAddress += length;\n continue;\n }\n\n const settingValue = values[field.id];\n\n if (field.type === 'u16' || field.type === 'u32') {\n const encoded = encodeRawValue(field.value ?? { kind: 'integer' }, settingValue ?? 0, length);\n\n for (let index = 0; index < length; index += 1) {\n writeByte(contents, bufferOffsetFor(radioAddress + index, memoryConfig, contents), encoded[index] ?? 0);\n }\n } else {\n const encoded = encodeRawValue(field.value, settingValue ?? (field.value?.kind === 'ascii' ? '' : 0), length);\n\n for (let index = 0; index < length; index += 1) {\n writeByte(contents, bufferOffsetFor(radioAddress + index, memoryConfig, contents), encoded[index]);\n }\n }\n\n radioAddress += length;\n }\n\n if (bitCursor) {\n bitCursor.nextRadioAddress();\n }\n}\n\nfunction isStructInstanceEmpty(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): boolean {\n if (!struct.emptyWhen) {\n return false;\n }\n\n const base = structInstanceAddress(struct, instanceIndex);\n const firstByte = readByte(contents, bufferOffsetFor(base, memoryConfig, contents));\n return firstByte === struct.emptyWhen.equals;\n}\n\nfunction clearStructInstance(\n struct: RadioMemoryMapStruct,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n instanceIndex: number,\n): void {\n const base = structInstanceAddress(struct, instanceIndex);\n const length = struct.stride ?? 16;\n\n for (let index = 0; index < length; index += 1) {\n writeByte(contents, bufferOffsetFor(base + index, memoryConfig, contents), 0xff);\n }\n}\n\n/**\n * Decode radio-wide settings from a memory image using a JSON memory map.\n */\nexport function decodeMemoryMap(\n memoryMap: RadioMemoryMap,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): RadioSettings {\n const settings: RadioSettings = {};\n\n for (const struct of memoryMap.structs) {\n const count = struct.count ?? 1;\n\n if (count > 1) {\n const items: RadioSettingValue[] = [];\n\n for (let index = 0; index < count; index += 1) {\n if (isStructInstanceEmpty(struct, contents, memoryConfig, index)) {\n items.push(null);\n } else {\n items.push(decodeStruct(struct, contents, memoryConfig, index));\n }\n }\n\n settings[struct.id] = items;\n } else {\n settings[struct.id] = decodeStruct(struct, contents, memoryConfig, 0);\n }\n }\n\n return settings;\n}\n\n/**\n * Encode radio-wide settings into an existing memory image in place.\n * Returns the same buffer for convenience.\n */\nexport function encodeMemoryMap(\n memoryMap: RadioMemoryMap,\n settings: RadioSettings,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): Uint8Array {\n for (const struct of memoryMap.structs) {\n const count = struct.count ?? 1;\n const value = settings[struct.id];\n\n if (count > 1) {\n const items = Array.isArray(value) ? value : [];\n\n for (let index = 0; index < count; index += 1) {\n const item = items[index];\n\n if (item === null || item === undefined) {\n if (struct.clearEmpty) {\n clearStructInstance(struct, contents, memoryConfig, index);\n }\n\n continue;\n }\n\n const record =\n item && typeof item === 'object' && !Array.isArray(item) ? (item as Record<string, RadioSettingValue>) : {};\n encodeStruct(struct, record, contents, memoryConfig, index);\n }\n } else {\n const record =\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, RadioSettingValue>) : {};\n encodeStruct(struct, record, contents, memoryConfig, 0);\n }\n }\n\n return contents;\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type { RadioCodec, RadioMemory, RadioMemoryConfig, RadioMemoryMap, RadioModelId, RadioProgram } from '@springfield/ham-radio-api';
2
+ import type { ILogLayer } from 'loglayer';
3
+ /**
4
+ * Compute the sparse image size that covers every configured memory segment.
5
+ */
6
+ export declare function memoryImageSize(memoryConfig: RadioMemoryConfig): number;
7
+ /**
8
+ * Create a Chirp-like empty EEPROM image filled with 0xFF.
9
+ */
10
+ export declare function createEmptyMemoryImage(totalSize: number): Uint8Array;
11
+ export interface MemoryMapRadioCodecOptions {
12
+ radioModel: RadioModelId;
13
+ memoryMap: RadioMemoryMap;
14
+ memoryConfig: RadioMemoryConfig;
15
+ logger?: ILogLayer;
16
+ }
17
+ /**
18
+ * Generic RadioCodec driven entirely by a JSON memory map + memoryConfig.
19
+ * Radio modules that ship DSL JSON do not need TypeScript codecs.
20
+ */
21
+ export declare class MemoryMapRadioCodec implements RadioCodec {
22
+ private readonly radioModel;
23
+ private readonly memoryMap;
24
+ private readonly memoryConfig;
25
+ private readonly logger;
26
+ constructor(options: MemoryMapRadioCodecOptions);
27
+ decode(memory: RadioMemory): RadioProgram;
28
+ encode(program: RadioProgram, memory: RadioMemory): RadioMemory;
29
+ }
30
+ /**
31
+ * Create a memory-map codec from hydrated radio config fields.
32
+ */
33
+ export declare function createMemoryMapCodec(options: MemoryMapRadioCodecOptions): RadioCodec;
34
+ //# sourceMappingURL=memory-map-radio-codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-map-radio-codec.d.ts","sourceRoot":"","sources":["../../src/memory/memory-map-radio-codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,YAAY,EACb,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAG1C;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,iBAAiB,GAAG,MAAM,CAGvE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAIpE;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,YAAY,CAAC;IACzB,SAAS,EAAE,cAAc,CAAC;IAC1B,YAAY,EAAE,iBAAiB,CAAC;IAChC,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,UAAU;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAE/C,YAAY,OAAO,EAAE,0BAA0B,EAK9C;IAED,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,YAAY,CAOxC;IAED,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,GAAG,WAAW,CA0B9D;CACF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,0BAA0B,GAAG,UAAU,CAEpF"}
@@ -0,0 +1,72 @@
1
+ import { decodeRadioProgram, encodeRadioProgram } from './memory-map-channels.js';
2
+ /**
3
+ * Compute the sparse image size that covers every configured memory segment.
4
+ */
5
+ export function memoryImageSize(memoryConfig) {
6
+ const ends = Object.values(memoryConfig.segments).map((segment) => segment.endAddress);
7
+ return Math.max(...ends) + 1;
8
+ }
9
+ /**
10
+ * Create a Chirp-like empty EEPROM image filled with 0xFF.
11
+ */
12
+ export function createEmptyMemoryImage(totalSize) {
13
+ const memory = new Uint8Array(totalSize);
14
+ memory.fill(0xff);
15
+ return memory;
16
+ }
17
+ /**
18
+ * Generic RadioCodec driven entirely by a JSON memory map + memoryConfig.
19
+ * Radio modules that ship DSL JSON do not need TypeScript codecs.
20
+ */
21
+ export class MemoryMapRadioCodec {
22
+ radioModel;
23
+ memoryMap;
24
+ memoryConfig;
25
+ logger;
26
+ constructor(options) {
27
+ this.radioModel = options.radioModel;
28
+ this.memoryMap = options.memoryMap;
29
+ this.memoryConfig = options.memoryConfig;
30
+ this.logger = options.logger;
31
+ }
32
+ decode(memory) {
33
+ try {
34
+ return decodeRadioProgram(this.memoryMap, memory.contents, this.memoryConfig);
35
+ }
36
+ catch (error) {
37
+ this.logger?.withError(error).warn('Failed to decode radio program from memory map');
38
+ return { channels: [], settings: {} };
39
+ }
40
+ }
41
+ encode(program, memory) {
42
+ const totalSize = memoryImageSize(this.memoryConfig);
43
+ const contents = memory.contents.length > 0 ? new Uint8Array(memory.contents) : createEmptyMemoryImage(totalSize);
44
+ if (contents.length < totalSize) {
45
+ const expanded = createEmptyMemoryImage(totalSize);
46
+ expanded.set(contents);
47
+ try {
48
+ encodeRadioProgram(this.memoryMap, program, expanded, this.memoryConfig);
49
+ }
50
+ catch (error) {
51
+ this.logger?.withError(error).warn('Failed to encode radio program into memory map');
52
+ }
53
+ this.logger?.debug(`Memory size: ${expanded.length} bytes`);
54
+ return { contents: expanded, radioModel: this.radioModel };
55
+ }
56
+ try {
57
+ encodeRadioProgram(this.memoryMap, program, contents, this.memoryConfig);
58
+ }
59
+ catch (error) {
60
+ this.logger?.withError(error).warn('Failed to encode radio program into memory map');
61
+ }
62
+ this.logger?.debug(`Memory size: ${contents.length} bytes`);
63
+ return { contents, radioModel: this.radioModel };
64
+ }
65
+ }
66
+ /**
67
+ * Create a memory-map codec from hydrated radio config fields.
68
+ */
69
+ export function createMemoryMapCodec(options) {
70
+ return new MemoryMapRadioCodec(options);
71
+ }
72
+ //# sourceMappingURL=memory-map-radio-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-map-radio-codec.js","sourceRoot":"","sources":["../../src/memory/memory-map-radio-codec.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RadioCodec,\n RadioMemory,\n RadioMemoryConfig,\n RadioMemoryMap,\n RadioModelId,\n RadioProgram,\n} from '@springfield/ham-radio-api';\nimport type { ILogLayer } from 'loglayer';\nimport { decodeRadioProgram, encodeRadioProgram } from './memory-map-channels.js';\n\n/**\n * Compute the sparse image size that covers every configured memory segment.\n */\nexport function memoryImageSize(memoryConfig: RadioMemoryConfig): number {\n const ends = Object.values(memoryConfig.segments).map((segment) => segment.endAddress);\n return Math.max(...ends) + 1;\n}\n\n/**\n * Create a Chirp-like empty EEPROM image filled with 0xFF.\n */\nexport function createEmptyMemoryImage(totalSize: number): Uint8Array {\n const memory = new Uint8Array(totalSize);\n memory.fill(0xff);\n return memory;\n}\n\nexport interface MemoryMapRadioCodecOptions {\n radioModel: RadioModelId;\n memoryMap: RadioMemoryMap;\n memoryConfig: RadioMemoryConfig;\n logger?: ILogLayer;\n}\n\n/**\n * Generic RadioCodec driven entirely by a JSON memory map + memoryConfig.\n * Radio modules that ship DSL JSON do not need TypeScript codecs.\n */\nexport class MemoryMapRadioCodec implements RadioCodec {\n private readonly radioModel: RadioModelId;\n private readonly memoryMap: RadioMemoryMap;\n private readonly memoryConfig: RadioMemoryConfig;\n private readonly logger: ILogLayer | undefined;\n\n constructor(options: MemoryMapRadioCodecOptions) {\n this.radioModel = options.radioModel;\n this.memoryMap = options.memoryMap;\n this.memoryConfig = options.memoryConfig;\n this.logger = options.logger;\n }\n\n decode(memory: RadioMemory): RadioProgram {\n try {\n return decodeRadioProgram(this.memoryMap, memory.contents, this.memoryConfig);\n } catch (error) {\n this.logger?.withError(error).warn('Failed to decode radio program from memory map');\n return { channels: [], settings: {} };\n }\n }\n\n encode(program: RadioProgram, memory: RadioMemory): RadioMemory {\n const totalSize = memoryImageSize(this.memoryConfig);\n const contents =\n memory.contents.length > 0 ? new Uint8Array(memory.contents) : createEmptyMemoryImage(totalSize);\n\n if (contents.length < totalSize) {\n const expanded = createEmptyMemoryImage(totalSize);\n expanded.set(contents);\n try {\n encodeRadioProgram(this.memoryMap, program, expanded, this.memoryConfig);\n } catch (error) {\n this.logger?.withError(error).warn('Failed to encode radio program into memory map');\n }\n\n this.logger?.debug(`Memory size: ${expanded.length} bytes`);\n return { contents: expanded, radioModel: this.radioModel };\n }\n\n try {\n encodeRadioProgram(this.memoryMap, program, contents, this.memoryConfig);\n } catch (error) {\n this.logger?.withError(error).warn('Failed to encode radio program into memory map');\n }\n\n this.logger?.debug(`Memory size: ${contents.length} bytes`);\n return { contents, radioModel: this.radioModel };\n }\n}\n\n/**\n * Create a memory-map codec from hydrated radio config fields.\n */\nexport function createMemoryMapCodec(options: MemoryMapRadioCodecOptions): RadioCodec {\n return new MemoryMapRadioCodec(options);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-map-ui.d.ts","sourceRoot":"","sources":["../../src/memory/memory-map-ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,qBAAqB,CAAC;IAC1B,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC;AAyBD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,cAAc,GAAG,qBAAqB,EAAE,CA8C3F;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,cAAc,GAAG,qBAAqB,EAAE,CA+BlG;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,iBAAiB,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,SAAS,CAAC,GACtD,MAAM,CAkCR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAc5G"}
1
+ {"version":3,"file":"memory-map-ui.d.ts","sourceRoot":"","sources":["../../src/memory/memory-map-ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAEpC;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,qBAAqB,CAAC;IAC1B,KAAK,CAAC,EAAE,uBAAuB,CAAC;CACjC;AAyBD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,cAAc,GAAG,qBAAqB,EAAE,CAkD3F;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,SAAS,EAAE,cAAc,GAAG,qBAAqB,EAAE,CAsClG;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,iBAAiB,GAAG,SAAS,EACpC,KAAK,EAAE,IAAI,CAAC,qBAAqB,EAAE,OAAO,GAAG,SAAS,CAAC,GACtD,MAAM,CAkCR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAc5G"}
@@ -29,6 +29,9 @@ export function collectMemoryMapUiFields(memoryMap) {
29
29
  if (memoryMap.channelBindings.names) {
30
30
  channelStructIds.add(memoryMap.channelBindings.names);
31
31
  }
32
+ if (memoryMap.channelBindings.extras) {
33
+ channelStructIds.add(memoryMap.channelBindings.extras);
34
+ }
32
35
  }
33
36
  for (const struct of memoryMap.structs) {
34
37
  if (channelStructIds.has(struct.id)) {
@@ -67,22 +70,28 @@ export function collectChannelMemoryMapUiFields(memoryMap) {
67
70
  return [];
68
71
  }
69
72
  const struct = memoryMap.structs.find((entry) => entry.id === bindings.records);
73
+ const extrasStruct = bindings.extras ? memoryMap.structs.find((entry) => entry.id === bindings.extras) : undefined;
70
74
  if (!struct) {
71
75
  return [];
72
76
  }
73
77
  const boundIds = channelBoundFieldIds(memoryMap);
74
78
  const fields = [];
75
- for (const field of struct.fields) {
76
- if (field.reserved || !field.ui || boundIds.has(field.id)) {
79
+ for (const source of [struct, extrasStruct]) {
80
+ if (!source) {
77
81
  continue;
78
82
  }
79
- fields.push({
80
- path: field.id,
81
- structId: struct.id,
82
- fieldId: field.id,
83
- ui: field.ui,
84
- value: field.value,
85
- });
83
+ for (const field of source.fields) {
84
+ if (field.reserved || !field.ui || boundIds.has(field.id)) {
85
+ continue;
86
+ }
87
+ fields.push({
88
+ path: field.id,
89
+ structId: source.id,
90
+ fieldId: field.id,
91
+ ui: field.ui,
92
+ value: field.value,
93
+ });
94
+ }
86
95
  }
87
96
  return fields;
88
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-map-ui.js","sourceRoot":"","sources":["../../src/memory/memory-map-ui.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RadioMemoryMap,\n RadioMemoryMapFieldUi,\n RadioMemoryMapValueKind,\n RadioSettingValue,\n} from '@springfield/ham-radio-api';\n\n/**\n * Flattened field descriptor for schema-driven settings UI.\n */\nexport interface RadioMemoryMapUiField {\n /** Dot path into decoded settings, e.g. settings.squelch or pttid.0.code */\n path: string;\n structId: string;\n fieldId: string;\n arrayIndex?: number;\n ui: RadioMemoryMapFieldUi;\n value?: RadioMemoryMapValueKind;\n}\n\nfunction channelBoundFieldIds(memoryMap: RadioMemoryMap): Set<string> {\n const bindings = memoryMap.channelBindings;\n const ids = new Set<string>();\n\n if (!bindings) {\n return ids;\n }\n\n for (const key of [\n bindings.receiveFrequency,\n bindings.transmitFrequency,\n bindings.receiveTone,\n bindings.transmitTone,\n bindings.nameField,\n ]) {\n if (key) {\n ids.add(key);\n }\n }\n\n return ids;\n}\n\n/**\n * Collect writable UI fields from a memory map, in declaration order.\n * Channel-bound structs are skipped (use {@link collectChannelMemoryMapUiFields}).\n */\nexport function collectMemoryMapUiFields(memoryMap: RadioMemoryMap): RadioMemoryMapUiField[] {\n const fields: RadioMemoryMapUiField[] = [];\n const channelStructIds = new Set<string>();\n\n if (memoryMap.channelBindings) {\n channelStructIds.add(memoryMap.channelBindings.records);\n\n if (memoryMap.channelBindings.names) {\n channelStructIds.add(memoryMap.channelBindings.names);\n }\n }\n\n for (const struct of memoryMap.structs) {\n if (channelStructIds.has(struct.id)) {\n continue;\n }\n\n const count = struct.count ?? 1;\n\n for (let index = 0; index < count; index += 1) {\n for (const field of struct.fields) {\n if (field.reserved || !field.ui) {\n continue;\n }\n\n const path =\n count > 1 ? `${struct.id}.${index}.${field.id}` : `${struct.id}.${field.id}`;\n\n const label =\n count > 1 && field.ui.label.indexOf('%') === -1\n ? `${field.ui.label} ${index + 1}`\n : field.ui.label;\n\n fields.push({\n path,\n structId: struct.id,\n fieldId: field.id,\n arrayIndex: count > 1 ? index : undefined,\n ui: { ...field.ui, label },\n value: field.value,\n });\n }\n }\n }\n\n return fields;\n}\n\n/**\n * Collect per-channel UI fields from the `channelBindings.records` struct.\n * Skips reserved fields, fields without `ui`, and fields bound onto RadioChannel.\n */\nexport function collectChannelMemoryMapUiFields(memoryMap: RadioMemoryMap): RadioMemoryMapUiField[] {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return [];\n }\n\n const struct = memoryMap.structs.find((entry) => entry.id === bindings.records);\n\n if (!struct) {\n return [];\n }\n\n const boundIds = channelBoundFieldIds(memoryMap);\n const fields: RadioMemoryMapUiField[] = [];\n\n for (const field of struct.fields) {\n if (field.reserved || !field.ui || boundIds.has(field.id)) {\n continue;\n }\n\n fields.push({\n path: field.id,\n structId: struct.id,\n fieldId: field.id,\n ui: field.ui,\n value: field.value,\n });\n }\n\n return fields;\n}\n\n/**\n * Format a decoded memory-map field value for read-only display (e.g. channel table).\n */\nexport function formatMemoryMapFieldValue(\n value: RadioSettingValue | undefined,\n field: Pick<RadioMemoryMapUiField, 'value' | 'fieldId'>,\n): string {\n if (value === undefined || value === null) {\n return '';\n }\n\n if (field.value?.kind === 'enum' && typeof value === 'string') {\n return value;\n }\n\n if (field.value?.kind === 'boolean' || typeof value === 'boolean') {\n if (field.fieldId === 'wide') {\n return value ? 'Wide' : 'Narrow';\n }\n\n if (field.fieldId === 'scan') {\n return value ? 'On' : 'Off';\n }\n\n return value ? 'On' : 'Off';\n }\n\n if (field.fieldId === 'lowpower' && typeof value === 'number') {\n return value === 0 ? 'High' : 'Low';\n }\n\n if (field.fieldId === 'scode' && typeof value === 'number') {\n return String(value + 1);\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n\n return '';\n}\n\n/**\n * Group UI fields by their ui.group key, preserving first-seen group order.\n */\nexport function groupMemoryMapUiFields(fields: RadioMemoryMapUiField[]): Map<string, RadioMemoryMapUiField[]> {\n const groups = new Map<string, RadioMemoryMapUiField[]>();\n\n for (const field of fields) {\n const existing = groups.get(field.ui.group);\n\n if (existing) {\n existing.push(field);\n } else {\n groups.set(field.ui.group, [field]);\n }\n }\n\n return groups;\n}\n"]}
1
+ {"version":3,"file":"memory-map-ui.js","sourceRoot":"","sources":["../../src/memory/memory-map-ui.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n RadioMemoryMap,\n RadioMemoryMapFieldUi,\n RadioMemoryMapValueKind,\n RadioSettingValue,\n} from '@springfield/ham-radio-api';\n\n/**\n * Flattened field descriptor for schema-driven settings UI.\n */\nexport interface RadioMemoryMapUiField {\n /** Dot path into decoded settings, e.g. settings.squelch or pttid.0.code */\n path: string;\n structId: string;\n fieldId: string;\n arrayIndex?: number;\n ui: RadioMemoryMapFieldUi;\n value?: RadioMemoryMapValueKind;\n}\n\nfunction channelBoundFieldIds(memoryMap: RadioMemoryMap): Set<string> {\n const bindings = memoryMap.channelBindings;\n const ids = new Set<string>();\n\n if (!bindings) {\n return ids;\n }\n\n for (const key of [\n bindings.receiveFrequency,\n bindings.transmitFrequency,\n bindings.receiveTone,\n bindings.transmitTone,\n bindings.nameField,\n ]) {\n if (key) {\n ids.add(key);\n }\n }\n\n return ids;\n}\n\n/**\n * Collect writable UI fields from a memory map, in declaration order.\n * Channel-bound structs are skipped (use {@link collectChannelMemoryMapUiFields}).\n */\nexport function collectMemoryMapUiFields(memoryMap: RadioMemoryMap): RadioMemoryMapUiField[] {\n const fields: RadioMemoryMapUiField[] = [];\n const channelStructIds = new Set<string>();\n\n if (memoryMap.channelBindings) {\n channelStructIds.add(memoryMap.channelBindings.records);\n\n if (memoryMap.channelBindings.names) {\n channelStructIds.add(memoryMap.channelBindings.names);\n }\n\n if (memoryMap.channelBindings.extras) {\n channelStructIds.add(memoryMap.channelBindings.extras);\n }\n }\n\n for (const struct of memoryMap.structs) {\n if (channelStructIds.has(struct.id)) {\n continue;\n }\n\n const count = struct.count ?? 1;\n\n for (let index = 0; index < count; index += 1) {\n for (const field of struct.fields) {\n if (field.reserved || !field.ui) {\n continue;\n }\n\n const path =\n count > 1 ? `${struct.id}.${index}.${field.id}` : `${struct.id}.${field.id}`;\n\n const label =\n count > 1 && field.ui.label.indexOf('%') === -1\n ? `${field.ui.label} ${index + 1}`\n : field.ui.label;\n\n fields.push({\n path,\n structId: struct.id,\n fieldId: field.id,\n arrayIndex: count > 1 ? index : undefined,\n ui: { ...field.ui, label },\n value: field.value,\n });\n }\n }\n }\n\n return fields;\n}\n\n/**\n * Collect per-channel UI fields from the `channelBindings.records` struct.\n * Skips reserved fields, fields without `ui`, and fields bound onto RadioChannel.\n */\nexport function collectChannelMemoryMapUiFields(memoryMap: RadioMemoryMap): RadioMemoryMapUiField[] {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return [];\n }\n\n const struct = memoryMap.structs.find((entry) => entry.id === bindings.records);\n const extrasStruct = bindings.extras ? memoryMap.structs.find((entry) => entry.id === bindings.extras) : undefined;\n\n if (!struct) {\n return [];\n }\n\n const boundIds = channelBoundFieldIds(memoryMap);\n const fields: RadioMemoryMapUiField[] = [];\n\n for (const source of [struct, extrasStruct]) {\n if (!source) {\n continue;\n }\n\n for (const field of source.fields) {\n if (field.reserved || !field.ui || boundIds.has(field.id)) {\n continue;\n }\n\n fields.push({\n path: field.id,\n structId: source.id,\n fieldId: field.id,\n ui: field.ui,\n value: field.value,\n });\n }\n }\n\n return fields;\n}\n\n/**\n * Format a decoded memory-map field value for read-only display (e.g. channel table).\n */\nexport function formatMemoryMapFieldValue(\n value: RadioSettingValue | undefined,\n field: Pick<RadioMemoryMapUiField, 'value' | 'fieldId'>,\n): string {\n if (value === undefined || value === null) {\n return '';\n }\n\n if (field.value?.kind === 'enum' && typeof value === 'string') {\n return value;\n }\n\n if (field.value?.kind === 'boolean' || typeof value === 'boolean') {\n if (field.fieldId === 'wide') {\n return value ? 'Wide' : 'Narrow';\n }\n\n if (field.fieldId === 'scan') {\n return value ? 'On' : 'Off';\n }\n\n return value ? 'On' : 'Off';\n }\n\n if (field.fieldId === 'lowpower' && typeof value === 'number') {\n return value === 0 ? 'High' : 'Low';\n }\n\n if (field.fieldId === 'scode' && typeof value === 'number') {\n return String(value + 1);\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n\n return '';\n}\n\n/**\n * Group UI fields by their ui.group key, preserving first-seen group order.\n */\nexport function groupMemoryMapUiFields(fields: RadioMemoryMapUiField[]): Map<string, RadioMemoryMapUiField[]> {\n const groups = new Map<string, RadioMemoryMapUiField[]>();\n\n for (const field of fields) {\n const existing = groups.get(field.ui.group);\n\n if (existing) {\n existing.push(field);\n } else {\n groups.set(field.ui.group, [field]);\n }\n }\n\n return groups;\n}\n"]}
@@ -40,7 +40,8 @@
40
40
  "receiveFrequency": { "type": "string", "minLength": 1 },
41
41
  "transmitFrequency": { "type": "string", "minLength": 1 },
42
42
  "receiveTone": { "type": "string", "minLength": 1 },
43
- "transmitTone": { "type": "string", "minLength": 1 }
43
+ "transmitTone": { "type": "string", "minLength": 1 },
44
+ "extras": { "type": "string", "minLength": 1 }
44
45
  },
45
46
  "additionalProperties": false
46
47
  },
@@ -105,7 +106,8 @@
105
106
  "required": ["kind", "length"],
106
107
  "properties": {
107
108
  "kind": { "const": "ascii" },
108
- "length": { "type": "integer", "minimum": 1 }
109
+ "length": { "type": "integer", "minimum": 1 },
110
+ "pad": { "type": "integer", "minimum": 0, "maximum": 255 }
109
111
  },
110
112
  "additionalProperties": false
111
113
  },
@@ -162,6 +164,32 @@
162
164
  "reverseOffset": { "type": "integer" }
163
165
  },
164
166
  "additionalProperties": false
167
+ },
168
+ {
169
+ "type": "object",
170
+ "required": ["kind", "values"],
171
+ "properties": {
172
+ "kind": { "const": "ctcss-index" },
173
+ "values": {
174
+ "type": "array",
175
+ "items": { "type": "integer" },
176
+ "minItems": 1
177
+ }
178
+ },
179
+ "additionalProperties": false
180
+ },
181
+ {
182
+ "type": "object",
183
+ "required": ["kind", "values"],
184
+ "properties": {
185
+ "kind": { "const": "dcs-index" },
186
+ "values": {
187
+ "type": "array",
188
+ "items": { "type": "integer" },
189
+ "minItems": 1
190
+ }
191
+ },
192
+ "additionalProperties": false
165
193
  }
166
194
  ]
167
195
  },
@@ -172,7 +200,7 @@
172
200
  "id": { "type": "string", "minLength": 1 },
173
201
  "type": {
174
202
  "type": "string",
175
- "enum": ["u8", "u16", "bits", "char"]
203
+ "enum": ["u8", "u16", "u32", "bits", "char"]
176
204
  },
177
205
  "width": { "type": "integer", "minimum": 1, "maximum": 8 },
178
206
  "reserved": { "type": "boolean" },
@@ -194,6 +222,8 @@
194
222
  },
195
223
  "count": { "type": "integer", "minimum": 1 },
196
224
  "stride": { "type": "integer", "minimum": 1 },
225
+ "groupSize": { "type": "integer", "minimum": 1 },
226
+ "groupPad": { "type": "integer", "minimum": 0 },
197
227
  "emptyWhen": { "$ref": "#/definitions/emptyWhen" },
198
228
  "clearEmpty": { "type": "boolean" }
199
229
  },
@@ -120,6 +120,10 @@
120
120
  "odd"
121
121
  ],
122
122
  "default": "none"
123
+ },
124
+ "rtscts": {
125
+ "type": "boolean",
126
+ "description": "Hardware RTS/CTS flow control (Kenwood TH-D74 clone on macOS)"
123
127
  }
124
128
  }
125
129
  },
@@ -270,6 +274,11 @@
270
274
  "required": [
271
275
  "expect"
272
276
  ]
277
+ },
278
+ {
279
+ "required": [
280
+ "setBaudRate"
281
+ ]
273
282
  }
274
283
  ],
275
284
  "additionalProperties": false,
@@ -289,6 +298,12 @@
289
298
  "description": "Timeout in milliseconds",
290
299
  "minimum": 1,
291
300
  "default": 5000
301
+ },
302
+ "setBaudRate": {
303
+ "type": "integer",
304
+ "description": "Switch serial baud rate before send/expect (TH-D74 clone transfers at 57600)",
305
+ "minimum": 1200,
306
+ "maximum": 115200
292
307
  }
293
308
  }
294
309
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springfield/ham-radio-utils",
3
- "version": "4.5.1",
3
+ "version": "4.7.0",
4
4
  "author": "Bryan Hunt",
5
5
  "license": "MIT",
6
6
  "readme": "README.md",
@@ -30,7 +30,7 @@
30
30
  "test:unit": "tsx --test test/unit/**/*.test.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@springfield/ham-radio-api": "^17.3.0",
33
+ "@springfield/ham-radio-api": "^17.4.0",
34
34
  "ajv": "^8.20.0",
35
35
  "ajv-formats": "^3.0.1",
36
36
  "fishery": "^2.4.0",
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export * from './memory/segmented-memory.js';
2
2
  export * from './memory/memory-map-codec.js';
3
3
  export * from './memory/memory-map-channels.js';
4
4
  export * from './memory/memory-map-ui.js';
5
+ export * from './memory/memory-map-radio-codec.js';
5
6
 
6
7
  export * from './test-utils/radio-channel-factory.js';
7
8
  export * from './test-utils/radio-programmed-channel-factory.js';