@springfield/ham-radio-api 17.1.0 → 17.3.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.
@@ -12,6 +12,19 @@ export type RadioSettingValue = RadioSettingScalar | RadioSettingValue[] | {
12
12
  };
13
13
  /** UI widget hint for schema-driven forms. */
14
14
  export type RadioMemoryMapWidget = "integer" | "select" | "switch" | "text" | "number";
15
+ /**
16
+ * Decoded tone value for UV-5R-style tone words (before RadioTone binding).
17
+ */
18
+ export type RadioMemoryMapToneValue = {
19
+ mode: "none";
20
+ } | {
21
+ mode: "ctcss";
22
+ value: number;
23
+ } | {
24
+ mode: "dcs";
25
+ code: number;
26
+ polarity: "N" | "R";
27
+ };
15
28
  /** How a field's raw bits/bytes become a setting value. */
16
29
  export type RadioMemoryMapValueKind = {
17
30
  kind: "integer";
@@ -44,6 +57,29 @@ export type RadioMemoryMapValueKind = {
44
57
  kind: "bbcd";
45
58
  /** Number of packed BCD bytes (Chirp bbcd). */
46
59
  length: number;
60
+ } | {
61
+ /**
62
+ * Chirp lbcd: little-endian integer whose hex digits are the decimal
63
+ * frequency digits (Hz / scale). UV-5R channel freqs use length 4, scale 10.
64
+ */
65
+ kind: "lbcd";
66
+ length: number;
67
+ /** Multiplier after interpreting hex-as-decimal (default 10 → Hz). */
68
+ scale?: number;
69
+ } | {
70
+ /**
71
+ * UV-5R-style tone word (typically ul16):
72
+ * - 0 / 0xFFFF → none
73
+ * - >= ctcssMin → CTCSS (raw = Hz * 10)
74
+ * - else DCS index into `values` (1-based); reverseOffset adds R polarity
75
+ */
76
+ kind: "tone";
77
+ /** Ordered DCS codes (Chirp UV5R_DTCS). */
78
+ values: number[];
79
+ /** Minimum raw value treated as CTCSS (Chirp uses 0x0258). */
80
+ ctcssMin?: number;
81
+ /** Added to DCS index for reverse polarity (Chirp uses 0x69). */
82
+ reverseOffset?: number;
47
83
  };
48
84
  /** UI metadata for a non-reserved field. */
49
85
  export interface RadioMemoryMapFieldUi {
@@ -56,14 +92,14 @@ export interface RadioMemoryMapFieldUi {
56
92
  }
57
93
  /**
58
94
  * One field in a sequential struct.
59
- * Bitfields pack into the current byte from LSB; width bits are consumed.
95
+ * Bitfields pack into the current byte MSB-first (Chirp-style).
60
96
  */
61
97
  export interface RadioMemoryMapField {
62
98
  id: string;
63
99
  /**
64
100
  * Storage type:
65
101
  * - u8 / u16: whole bytes (u16 is little-endian, Chirp ul16)
66
- * - bits: bitfield of `width` bits within the current byte (LSB-first)
102
+ * - bits: bitfield of `width` bits within the current byte (MSB-first)
67
103
  * - char: ASCII byte (length via value.kind ascii or count)
68
104
  */
69
105
  type: "u8" | "u16" | "bits" | "char";
@@ -74,6 +110,13 @@ export interface RadioMemoryMapField {
74
110
  value?: RadioMemoryMapValueKind;
75
111
  ui?: RadioMemoryMapFieldUi;
76
112
  }
113
+ /**
114
+ * When the first byte of a repeated struct instance equals `equals`,
115
+ * the slot is treated as empty (Chirp: RX freq first byte 0xFF).
116
+ */
117
+ export interface RadioMemoryMapEmptyWhen {
118
+ equals: number;
119
+ }
77
120
  /**
78
121
  * A named struct at a radio EEPROM seek address.
79
122
  * Fields are laid out sequentially from `seek`.
@@ -85,18 +128,43 @@ export interface RadioMemoryMapStruct {
85
128
  fields: RadioMemoryMapField[];
86
129
  /**
87
130
  * Repeat this struct `count` times with `stride` bytes between entries.
88
- * Used for PTT-ID code tables.
131
+ * Used for channel tables and PTT-ID code tables.
89
132
  */
90
133
  count?: number;
91
134
  stride?: number;
135
+ /** Occupancy rule for repeated structs (e.g. empty channel slots). */
136
+ emptyWhen?: RadioMemoryMapEmptyWhen;
137
+ /**
138
+ * When encoding, fill missing/null instances with 0xFF for `stride` bytes
139
+ * (Chirp-like channel clear). Defaults to false.
140
+ */
141
+ clearEmpty?: boolean;
142
+ }
143
+ /**
144
+ * Maps decoded struct fields onto portable RadioChannel fields.
145
+ * Remaining record fields become RadioProgrammedChannel.settings.
146
+ */
147
+ export interface RadioMemoryMapChannelBindings {
148
+ /** Struct id of the channel record array. */
149
+ records: string;
150
+ /** Optional parallel name table struct id. */
151
+ names?: string;
152
+ /** Field id within the names struct (default "name"). */
153
+ nameField?: string;
154
+ receiveFrequency: string;
155
+ transmitFrequency: string;
156
+ receiveTone: string;
157
+ transmitTone: string;
92
158
  }
93
159
  /**
94
- * Complete memory-map definition for a radio model's settings.
160
+ * Complete memory-map definition for a radio model's settings and channels.
95
161
  */
96
162
  export interface RadioMemoryMap {
97
163
  /** Optional map version for tooling. */
98
164
  version?: string;
99
165
  description?: string;
100
166
  structs: RadioMemoryMapStruct[];
167
+ /** Optional projection from channel structs into RadioProgram.channels. */
168
+ channelBindings?: RadioMemoryMapChannelBindings;
101
169
  }
102
170
  //# sourceMappingURL=memory-map.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-map.d.ts","sourceRoot":"","sources":["../../src/radio/memory-map.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,qDAAqD;AACrD,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAElE,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,GAAG,iBAAiB,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAAA;CAAE,CAAC;AAEhH,8CAA8C;AAC9C,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvF,2DAA2D;AAC3D,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjC;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEN,4CAA4C;AAC5C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,oBAAoB,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,EAAE,CAAC,EAAE,qBAAqB,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC"}
1
+ {"version":3,"file":"memory-map.d.ts","sourceRoot":"","sources":["../../src/radio/memory-map.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { RadioMemorySegment } from "./memory-segment.js";
1
2
  /**
2
3
  * A byte in a send or expect array.
3
4
  *
@@ -54,6 +55,10 @@ export interface RadioReadStep {
54
55
  /**
55
56
  * Chunked memory write: repeat an exchange across named segments.
56
57
  * `$data` in `send` emits the current chunk from the memory buffer.
58
+ *
59
+ * Optional `chunkSize` overrides `memoryConfig.chunkSize` (UV-5R clone writes 16-byte blocks).
60
+ * Optional `delay` is milliseconds to wait after each accepted block (UV-5R clone waits 50ms).
61
+ * Optional `skip` lists inclusive radio-address ranges that must not be uploaded.
57
62
  */
58
63
  export interface RadioWriteStep {
59
64
  description?: string;
@@ -62,6 +67,9 @@ export interface RadioWriteStep {
62
67
  send: RadioByteToken[];
63
68
  expect: RadioExpect;
64
69
  timeout?: number;
70
+ chunkSize?: number;
71
+ delay?: number;
72
+ skip?: RadioMemorySegment[];
65
73
  };
66
74
  }
67
75
  export type RadioProtocolStep = RadioExchange | RadioReadStep | RadioWriteStep;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/radio/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,cAAc,EAAE,GAAG,gBAAgB,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACD;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,MAAM,EAAE,WAAW,CAAC;QACpB,GAAG,CAAC,EAAE,aAAa,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,MAAM,EAAE,WAAW,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,cAAc,CAAC"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/radio/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG,cAAc,EAAE,GAAG,gBAAgB,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,aAAa,GACrB;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACD;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,MAAM,EAAE,WAAW,CAAC;QACpB,GAAG,CAAC,EAAE,aAAa,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,IAAI,EAAE,cAAc,EAAE,CAAC;QACvB,MAAM,EAAE,WAAW,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,kBAAkB,EAAE,CAAC;KAC7B,CAAC;CACH;AAED,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,aAAa,GAAG,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springfield/ham-radio-api",
3
- "version": "17.1.0",
3
+ "version": "17.3.0",
4
4
  "author": "Bryan Hunt",
5
5
  "files": [
6
6
  "dist/",
@@ -14,6 +14,14 @@ export type RadioSettingValue = RadioSettingScalar | RadioSettingValue[] | { [ke
14
14
  /** UI widget hint for schema-driven forms. */
15
15
  export type RadioMemoryMapWidget = "integer" | "select" | "switch" | "text" | "number";
16
16
 
17
+ /**
18
+ * Decoded tone value for UV-5R-style tone words (before RadioTone binding).
19
+ */
20
+ export type RadioMemoryMapToneValue =
21
+ | { mode: "none" }
22
+ | { mode: "ctcss"; value: number }
23
+ | { mode: "dcs"; code: number; polarity: "N" | "R" };
24
+
17
25
  /** How a field's raw bits/bytes become a setting value. */
18
26
  export type RadioMemoryMapValueKind =
19
27
  | { kind: "integer"; min?: number; max?: number }
@@ -41,6 +49,31 @@ export type RadioMemoryMapValueKind =
41
49
  kind: "bbcd";
42
50
  /** Number of packed BCD bytes (Chirp bbcd). */
43
51
  length: number;
52
+ }
53
+ | {
54
+ /**
55
+ * Chirp lbcd: little-endian integer whose hex digits are the decimal
56
+ * frequency digits (Hz / scale). UV-5R channel freqs use length 4, scale 10.
57
+ */
58
+ kind: "lbcd";
59
+ length: number;
60
+ /** Multiplier after interpreting hex-as-decimal (default 10 → Hz). */
61
+ scale?: number;
62
+ }
63
+ | {
64
+ /**
65
+ * UV-5R-style tone word (typically ul16):
66
+ * - 0 / 0xFFFF → none
67
+ * - >= ctcssMin → CTCSS (raw = Hz * 10)
68
+ * - else DCS index into `values` (1-based); reverseOffset adds R polarity
69
+ */
70
+ kind: "tone";
71
+ /** Ordered DCS codes (Chirp UV5R_DTCS). */
72
+ values: number[];
73
+ /** Minimum raw value treated as CTCSS (Chirp uses 0x0258). */
74
+ ctcssMin?: number;
75
+ /** Added to DCS index for reverse polarity (Chirp uses 0x69). */
76
+ reverseOffset?: number;
44
77
  };
45
78
 
46
79
  /** UI metadata for a non-reserved field. */
@@ -55,14 +88,14 @@ export interface RadioMemoryMapFieldUi {
55
88
 
56
89
  /**
57
90
  * One field in a sequential struct.
58
- * Bitfields pack into the current byte from LSB; width bits are consumed.
91
+ * Bitfields pack into the current byte MSB-first (Chirp-style).
59
92
  */
60
93
  export interface RadioMemoryMapField {
61
94
  id: string;
62
95
  /**
63
96
  * Storage type:
64
97
  * - u8 / u16: whole bytes (u16 is little-endian, Chirp ul16)
65
- * - bits: bitfield of `width` bits within the current byte (LSB-first)
98
+ * - bits: bitfield of `width` bits within the current byte (MSB-first)
66
99
  * - char: ASCII byte (length via value.kind ascii or count)
67
100
  */
68
101
  type: "u8" | "u16" | "bits" | "char";
@@ -74,6 +107,14 @@ export interface RadioMemoryMapField {
74
107
  ui?: RadioMemoryMapFieldUi;
75
108
  }
76
109
 
110
+ /**
111
+ * When the first byte of a repeated struct instance equals `equals`,
112
+ * the slot is treated as empty (Chirp: RX freq first byte 0xFF).
113
+ */
114
+ export interface RadioMemoryMapEmptyWhen {
115
+ equals: number;
116
+ }
117
+
77
118
  /**
78
119
  * A named struct at a radio EEPROM seek address.
79
120
  * Fields are laid out sequentially from `seek`.
@@ -85,18 +126,44 @@ export interface RadioMemoryMapStruct {
85
126
  fields: RadioMemoryMapField[];
86
127
  /**
87
128
  * Repeat this struct `count` times with `stride` bytes between entries.
88
- * Used for PTT-ID code tables.
129
+ * Used for channel tables and PTT-ID code tables.
89
130
  */
90
131
  count?: number;
91
132
  stride?: number;
133
+ /** Occupancy rule for repeated structs (e.g. empty channel slots). */
134
+ emptyWhen?: RadioMemoryMapEmptyWhen;
135
+ /**
136
+ * When encoding, fill missing/null instances with 0xFF for `stride` bytes
137
+ * (Chirp-like channel clear). Defaults to false.
138
+ */
139
+ clearEmpty?: boolean;
140
+ }
141
+
142
+ /**
143
+ * Maps decoded struct fields onto portable RadioChannel fields.
144
+ * Remaining record fields become RadioProgrammedChannel.settings.
145
+ */
146
+ export interface RadioMemoryMapChannelBindings {
147
+ /** Struct id of the channel record array. */
148
+ records: string;
149
+ /** Optional parallel name table struct id. */
150
+ names?: string;
151
+ /** Field id within the names struct (default "name"). */
152
+ nameField?: string;
153
+ receiveFrequency: string;
154
+ transmitFrequency: string;
155
+ receiveTone: string;
156
+ transmitTone: string;
92
157
  }
93
158
 
94
159
  /**
95
- * Complete memory-map definition for a radio model's settings.
160
+ * Complete memory-map definition for a radio model's settings and channels.
96
161
  */
97
162
  export interface RadioMemoryMap {
98
163
  /** Optional map version for tooling. */
99
164
  version?: string;
100
165
  description?: string;
101
166
  structs: RadioMemoryMapStruct[];
167
+ /** Optional projection from channel structs into RadioProgram.channels. */
168
+ channelBindings?: RadioMemoryMapChannelBindings;
102
169
  }
@@ -1,3 +1,5 @@
1
+ import type { RadioMemorySegment } from "./memory-segment.js";
2
+
1
3
  /**
2
4
  * A byte in a send or expect array.
3
5
  *
@@ -61,6 +63,10 @@ export interface RadioReadStep {
61
63
  /**
62
64
  * Chunked memory write: repeat an exchange across named segments.
63
65
  * `$data` in `send` emits the current chunk from the memory buffer.
66
+ *
67
+ * Optional `chunkSize` overrides `memoryConfig.chunkSize` (UV-5R clone writes 16-byte blocks).
68
+ * Optional `delay` is milliseconds to wait after each accepted block (UV-5R clone waits 50ms).
69
+ * Optional `skip` lists inclusive radio-address ranges that must not be uploaded.
64
70
  */
65
71
  export interface RadioWriteStep {
66
72
  description?: string;
@@ -69,6 +75,9 @@ export interface RadioWriteStep {
69
75
  send: RadioByteToken[];
70
76
  expect: RadioExpect;
71
77
  timeout?: number;
78
+ chunkSize?: number;
79
+ delay?: number;
80
+ skip?: RadioMemorySegment[];
72
81
  };
73
82
  }
74
83