@springfield/ham-radio-utils 4.7.0 → 4.8.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-channels.d.ts","sourceRoot":"","sources":["../../src/memory/memory-map-channels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEnB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAInB,MAAM,4BAA4B,CAAC;AA2HpC;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,aAAa,GACtB,sBAAsB,EAAE,CAsG1B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,GAAG,aAAa,CAmBzG;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,GAAG,aAAa,CAwJxG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,iBAAiB,GAC9B,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,iBAAiB,GAC9B,UAAU,CAGZ"}
1
+ {"version":3,"file":"memory-map-channels.d.ts","sourceRoot":"","sources":["../../src/memory/memory-map-channels.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEnB,KAAK,YAAY,EACjB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAInB,MAAM,4BAA4B,CAAC;AAoJpC;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,aAAa,GACtB,sBAAsB,EAAE,CAsG1B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,GAAG,aAAa,CAmBzG;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,GAAG,aAAa,CA8JxG;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,iBAAiB,GAC9B,YAAY,CAOd;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,iBAAiB,GAC9B,UAAU,CAGZ"}
@@ -82,6 +82,25 @@ function kenwoodUsedFlag(receiveFrequency, transmitFrequency) {
82
82
  }
83
83
  return 2;
84
84
  }
85
+ /** TM-D710 chmap band codes: 0=118 MHz, 5=144, 6=200, 7=300, 8=400, 9=800. */
86
+ function kenwoodChmapBand(receiveFrequency) {
87
+ if (receiveFrequency < 136_000_000) {
88
+ return 0;
89
+ }
90
+ if (receiveFrequency < 200_000_000) {
91
+ return 5;
92
+ }
93
+ if (receiveFrequency < 300_000_000) {
94
+ return 6;
95
+ }
96
+ if (receiveFrequency < 400_000_000) {
97
+ return 7;
98
+ }
99
+ if (receiveFrequency < 800_000_000) {
100
+ return 8;
101
+ }
102
+ return 9;
103
+ }
85
104
  function asRecord(value) {
86
105
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
87
106
  return undefined;
@@ -307,11 +326,15 @@ export function programToChannelSettings(memoryMap, program) {
307
326
  record[nameField] = channel.name ?? '';
308
327
  }
309
328
  if (extrasStruct) {
310
- extras[index] = {
329
+ const extraRecord = {
311
330
  used: kenwoodUsedFlag(receiveFrequency, transmitFrequency),
312
331
  lockout: channelSettings.skip === 'S' || channelSettings.lockout === true,
313
332
  group: typeof channelSettings.group === 'number' ? channelSettings.group : 0,
314
333
  };
334
+ if (structHasField(extrasStruct, 'band')) {
335
+ extraRecord.band = typeof channelSettings.band === 'number' ? channelSettings.band : kenwoodChmapBand(receiveFrequency);
336
+ }
337
+ extras[index] = extraRecord;
315
338
  }
316
339
  }
317
340
  const bag = { ...program.settings, [bindings.records]: records };
@@ -1 +1 @@
1
- {"version":3,"file":"memory-map-channels.js","sourceRoot":"","sources":["../../src/memory/memory-map-channels.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EAUT,aAAa,GACd,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzE,SAAS,WAAW,CAAC,KAAoC;IACvD,OAAO,OAAO,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,eAAe,CAAC,KAAoC;IAC3D,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACjD,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC;IAC1D,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC;AACvD,CAAC;AAED,SAAS,kBAAkB,CAAC,IAA2B;IACrD,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC,GAAG,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;IACjE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,UAAU,CAAC,IAA2B;IAC7C,OAAO,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AAC7B,CAAC;AAED,SAAS,cAAc,CAAC,MAAgD,EAAE,OAAe;IACvF,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,2BAA2B,CAAC,MAAyC,EAAE,QAAwD;IACtI,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IACxE,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IAEzE,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC1B,OAAO,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC1B,OAAO,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;IAED,kGAAkG;IAClG,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACzB,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,QAAQ,CAAC,iBAAiB,KAAK,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACxG,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,SAAS,oBAAoB,CAC3B,MAAyC,EACzC,QAAwD;IAExD,MAAM,eAAe,GAAG,WAAW,IAAI,MAAM,IAAI,YAAY,IAAI,MAAM,IAAI,WAAW,IAAI,MAAM,CAAC;IAEjG,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO;YACL,WAAW,EAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC1D,YAAY,EAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;SAC7D,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;IACnG,CAAC;IAED,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;QAC3D,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,eAAe,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/C,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,YAAY,EAAE,QAAQ,EAAE,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,eAAe,CAAC,gBAAwB,EAAE,iBAAyB;IAC1E,MAAM,SAAS,GAAG,iBAAiB,IAAI,gBAAgB,CAAC;IAExD,IAAI,SAAS,GAAG,WAAW,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,SAAS,GAAG,WAAW,EAAE,CAAC;QAC5B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,QAAQ,CAAC,KAAoC;IACpD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAA0C,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAyB,EACzB,QAAuB;IAEvB,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC;IAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,MAAM,CAAC;IAC/C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;QAC5B,QAAQ,CAAC,gBAAgB;QACzB,QAAQ,CAAC,iBAAiB;QAC1B,QAAQ,CAAC,WAAW;QACpB,QAAQ,CAAC,YAAY;QACrB,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,QAAQ,GAA6B,EAAE,CAAC;IAE9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;QAEhD,IAAI,QAAQ,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC1E,SAAS;QACX,CAAC;QAED,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,MAAM,aAAa,GAAG,OAAO,UAAU,EAAE,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/F,MAAM,cAAc,GAAG,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,GAAG,aAAa,IAAI,cAAc,CAAC;QAE7C,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;QACxE,MAAM,iBAAiB,GAAG,2BAA2B,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAErD,MAAM,eAAe,GAAkB,EAAE,CAAC;QAE1C,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3D,IAAI,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1D,SAAS;YACX,CAAC;YAED,eAAe,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;QACxC,CAAC;QAED,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;gBAChE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;oBAClD,SAAS;gBACX,CAAC;gBAED,eAAe,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC;YACxC,CAAC;YAED,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC7C,eAAe,CAAC,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,CAAC;QACH,CAAC;QAED,uFAAuF;QACvF,IAAI,OAAO,eAAe,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjD,eAAe,CAAC,aAAa,GAAG,eAAe,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,CAAC;QAED,IAAI,OAAO,eAAe,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9C,eAAe,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7D,CAAC;QAED,IAAI,OAAO,eAAe,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9C,eAAe,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QACzD,CAAC;QAED,IAAI,OAAO,eAAe,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9C,eAAe,CAAC,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,CAAC;QAED,MAAM,YAAY,GAAiB;YACjC,IAAI;YACJ,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,CAAC;YAC7C,iBAAiB,EAAE,SAAS,CAAC,iBAAiB,CAAC;YAC/C,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;SACjC,CAAC;QAEF,QAAQ,CAAC,IAAI,CAAC;YACZ,aAAa,EAAE,KAAK;YACpB,YAAY;YACZ,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;SAChF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAyB,EAAE,QAAuB;IACxF,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC;IAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAkB,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC5C,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE9B,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAyB,EAAE,OAAqB;IACvF,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,CAAC;IAE3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,OAAO,CAAC,QAAQ,CAAC;IAC1B,CAAC;IAED,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzF,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAClH,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACrH,MAAM,KAAK,GAAG,aAAa,EAAE,KAAK,IAAI,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,MAAM,CAAC;IAE/C,MAAM,OAAO,GAAwB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC/E,MAAM,KAAK,GAAwB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAwB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAE9E,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,aAAa,CAAC;QAEvC,IAAI,KAAK,GAAG,CAAC,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;YAChC,SAAS;QACX,CAAC;QAED,IAAI,OAAO,UAAU,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YAChD,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,YAAY,CAAC;QACxC,MAAM,eAAe,GAAG,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAC;QAClD,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC1D,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAC5D,IAAI,MAAM,GAAG,iBAAiB,CAAC;QAC/B,IAAI,MAAM,GAAsB,EAAE,CAAC;QACnC,IAAI,KAAK,GAAG,KAAK,CAAC;QAElB,IAAI,iBAAiB,KAAK,gBAAgB,EAAE,CAAC;YAC3C,MAAM,GAAG,CAAC,CAAC;YACX,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;aAAM,IAAI,iBAAiB,GAAG,gBAAgB,EAAE,CAAC;YAChD,MAAM,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;YAC9C,MAAM,GAAG,GAAG,CAAC;QACf,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;YAC9C,MAAM,GAAG,GAAG,CAAC;QACf,CAAC;QAED,IAAI,eAAe,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACnC,KAAK,GAAG,IAAI,CAAC;YACb,MAAM,GAAG,EAAE,CAAC;YACZ,MAAM,GAAG,iBAAiB,CAAC;QAC7B,CAAC;QAED,MAAM,UAAU,GACd,QAAQ,IAAI,eAAe,IAAI,YAAY,IAAI,cAAc,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACzF,MAAM,mBAAmB,GACvB,WAAW,IAAI,eAAe;YAC9B,YAAY,IAAI,eAAe;YAC/B,YAAY;YACZ,cAAc,CAAC,aAAa,EAAE,WAAW,CAAC;YAC1C,cAAc,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC;QAE9C,MAAM,MAAM,GAAsC;YAChD,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB;YAC7C,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB;YACrE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,WAAW,CAAC;YAC/D,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,YAAY,CAAC;SAClE,CAAC;QAEF,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,MAAM,GAAG,OAAO,eAAe,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YAC7F,MAAM,CAAC,KAAK,GAAG,OAAO,eAAe,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YAC1F,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,CAAC;QAED,IAAI,mBAAmB,EAAE,CAAC;YACxB,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC;YACzB,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;YAC1B,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC;YACzB,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;YAE1B,IAAI,OAAO,CAAC,YAAY,EAAE,IAAI,KAAK,aAAa,CAAC,GAAG,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,KAAK,aAAa,CAAC,GAAG,EAAE,CAAC;gBACxG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;gBACxB,MAAM,CAAC,SAAS,GAAG,kBAAkB,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACvI,CAAC;iBAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;gBACjF,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;YAC3B,CAAC;iBAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC7C,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;YAC1B,CAAC;QACH,CAAC;QAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC;YAC3D,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;gBAC5B,MAAM,CAAC,QAAQ,GAAG,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpE,SAAS;YACX,CAAC;YAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,GAAG,KAAK,KAAK,IAAI,CAAC;gBAC7B,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC;gBACpB,SAAS;YACX,CAAC;YAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,GAAG,KAAK,KAAK,GAAG,CAAC;gBAC5B,MAAM,CAAC,IAAI,GAAG,KAAK,KAAK,GAAG,CAAC;gBAC5B,SAAS;YACX,CAAC;YAED,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;QAExB,IAAI,WAAW,EAAE,CAAC;YAChB,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACzC,CAAC;QAED,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,GAAG;gBACd,IAAI,EAAE,eAAe,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;gBAC1D,OAAO,EAAE,eAAe,CAAC,IAAI,KAAK,GAAG,IAAI,eAAe,CAAC,OAAO,KAAK,IAAI;gBACzE,KAAK,EAAE,OAAO,eAAe,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAkB,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IAEhF,IAAI,QAAQ,CAAC,KAAK,IAAI,WAAW,EAAE,CAAC;QAClC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IAC9B,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;QACpC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAChC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAyB,EACzB,QAAoB,EACpB,YAA+B;IAE/B,MAAM,OAAO,GAAG,eAAe,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEnE,OAAO;QACL,QAAQ,EAAE,kBAAkB,CAAC,SAAS,EAAE,OAAO,CAAC;QAChD,QAAQ,EAAE,uBAAuB,CAAC,SAAS,EAAE,OAAO,CAAC;KACtD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAyB,EACzB,OAAqB,EACrB,QAAoB,EACpB,YAA+B;IAE/B,MAAM,GAAG,GAAG,wBAAwB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACzD,OAAO,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AACjE,CAAC","sourcesContent":["import {\n Frequency,\n type RadioChannel,\n type RadioMemoryConfig,\n type RadioMemoryMap,\n type RadioMemoryMapToneValue,\n type RadioProgram,\n type RadioProgrammedChannel,\n type RadioSettings,\n type RadioSettingValue,\n type RadioTone,\n RadioToneType,\n} from '@springfield/ham-radio-api';\nimport { decodeMemoryMap, encodeMemoryMap } from './memory-map-codec.js';\n\nfunction isToneValue(value: RadioSettingValue | undefined): value is RadioMemoryMapToneValue {\n return Boolean(value && typeof value === 'object' && !Array.isArray(value) && 'mode' in value);\n}\n\nfunction toneToRadioTone(value: RadioSettingValue | undefined): RadioTone {\n if (!isToneValue(value) || value.mode === 'none') {\n return { tone: 0, type: RadioToneType.CTCSS };\n }\n\n if (value.mode === 'ctcss') {\n return { tone: value.value, type: RadioToneType.CTCSS };\n }\n\n return { tone: value.code, type: RadioToneType.DCS };\n}\n\nfunction radioToneToMapTone(tone: RadioTone | undefined): RadioMemoryMapToneValue {\n if (!tone || !tone.tone) {\n return { mode: 'none' };\n }\n\n if (tone.type === RadioToneType.DCS) {\n return { mode: 'dcs', code: Number(tone.tone), polarity: 'N' };\n }\n\n return { mode: 'ctcss', value: Number(tone.tone) };\n}\n\nfunction noneTone(): RadioTone {\n return { tone: 0, type: RadioToneType.CTCSS };\n}\n\nfunction isNoneTone(tone: RadioTone | undefined): boolean {\n return !tone || !tone.tone;\n}\n\nfunction structHasField(struct: { fields: { id: string }[] } | undefined, fieldId: string): boolean {\n return Boolean(struct?.fields.some((field) => field.id === fieldId));\n}\n\nfunction transmitFrequencyFromRecord(record: Record<string, RadioSettingValue>, bindings: NonNullable<RadioMemoryMap['channelBindings']>): number {\n const receiveFrequency = Number(record[bindings.receiveFrequency] ?? 0);\n const offsetOrTransmit = Number(record[bindings.transmitFrequency] ?? 0);\n\n if (record.split === true) {\n return offsetOrTransmit;\n }\n\n if (record.duplex === '+') {\n return receiveFrequency + offsetOrTransmit;\n }\n\n if (record.duplex === '-') {\n return receiveFrequency - offsetOrTransmit;\n }\n\n // Kenwood stores simplex as duplex \"\" and offset 0. Empty duplex is not an absolute TX frequency.\n if (record.duplex === '') {\n return receiveFrequency;\n }\n\n if (record.duplex === undefined) {\n return bindings.transmitFrequency === bindings.receiveFrequency ? receiveFrequency : offsetOrTransmit;\n }\n\n return offsetOrTransmit;\n}\n\nfunction applyKenwoodToneMode(\n record: Record<string, RadioSettingValue>,\n bindings: NonNullable<RadioMemoryMap['channelBindings']>,\n): { receiveTone: RadioTone; transmitTone: RadioTone } {\n const hasToneModeBits = 'tone_mode' in record || 'ctcss_mode' in record || 'dtcs_mode' in record;\n\n if (!hasToneModeBits) {\n return {\n receiveTone: toneToRadioTone(record[bindings.receiveTone]),\n transmitTone: toneToRadioTone(record[bindings.transmitTone]),\n };\n }\n\n if (record.tone_mode === true) {\n return { receiveTone: noneTone(), transmitTone: toneToRadioTone(record[bindings.transmitTone]) };\n }\n\n if (record.ctcss_mode === true) {\n const tone = toneToRadioTone(record[bindings.receiveTone]);\n return { receiveTone: tone, transmitTone: tone };\n }\n\n if (record.dtcs_mode === true) {\n const tone = toneToRadioTone(record.dtcs_code);\n return { receiveTone: tone, transmitTone: tone };\n }\n\n return { receiveTone: noneTone(), transmitTone: noneTone() };\n}\n\nfunction kenwoodUsedFlag(receiveFrequency: number, transmitFrequency: number): number {\n const frequency = transmitFrequency || receiveFrequency;\n\n if (frequency < 150_000_000) {\n return 0;\n }\n\n if (frequency < 400_000_000) {\n return 1;\n }\n\n return 2;\n}\n\nfunction asRecord(value: RadioSettingValue | undefined): Record<string, RadioSettingValue> | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n\n return value as Record<string, RadioSettingValue>;\n}\n\n/**\n * Project decoded memory-map channel structs into RadioProgrammedChannel[].\n */\nexport function bindingsToChannels(\n memoryMap: RadioMemoryMap,\n settings: RadioSettings,\n): RadioProgrammedChannel[] {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return [];\n }\n\n const records = settings[bindings.records];\n const names = bindings.names ? settings[bindings.names] : undefined;\n const extras = bindings.extras ? settings[bindings.extras] : undefined;\n const recordItems = Array.isArray(records) ? records : [];\n const nameItems = Array.isArray(names) ? names : [];\n const extraItems = Array.isArray(extras) ? extras : [];\n const nameField = bindings.nameField ?? 'name';\n const boundFieldIds = new Set([\n bindings.receiveFrequency,\n bindings.transmitFrequency,\n bindings.receiveTone,\n bindings.transmitTone,\n nameField,\n ]);\n\n const channels: RadioProgrammedChannel[] = [];\n\n for (let index = 0; index < recordItems.length; index += 1) {\n const record = asRecord(recordItems[index]);\n const extraRecord = asRecord(extraItems[index]);\n\n if (bindings.extras && extraItems.length > 0 && extraRecord === undefined) {\n continue;\n }\n\n if (!record) {\n continue;\n }\n\n const nameRecord = asRecord(nameItems[index]);\n const nameFromTable = typeof nameRecord?.[nameField] === 'string' ? nameRecord[nameField] : '';\n const nameFromRecord = typeof record[nameField] === 'string' ? record[nameField] : '';\n const name = nameFromTable || nameFromRecord;\n\n const receiveFrequency = Number(record[bindings.receiveFrequency] ?? 0);\n const transmitFrequency = transmitFrequencyFromRecord(record, bindings);\n const tones = applyKenwoodToneMode(record, bindings);\n\n const channelSettings: RadioSettings = {};\n\n for (const [fieldId, fieldValue] of Object.entries(record)) {\n if (boundFieldIds.has(fieldId) || fieldId.startsWith('_')) {\n continue;\n }\n\n channelSettings[fieldId] = fieldValue;\n }\n\n if (extraRecord) {\n for (const [fieldId, fieldValue] of Object.entries(extraRecord)) {\n if (fieldId.startsWith('_') || fieldId === 'used') {\n continue;\n }\n\n channelSettings[fieldId] = fieldValue;\n }\n\n if (typeof extraRecord.lockout === 'boolean') {\n channelSettings.skip = extraRecord.lockout ? 'S' : '';\n }\n }\n\n // Map Chirp lowpower index onto legacy transmitPower watts for UV-5R UI compatibility.\n if (typeof channelSettings.lowpower === 'number') {\n channelSettings.transmitPower = channelSettings.lowpower === 0 ? 5 : 1;\n }\n\n if (typeof channelSettings.wide === 'boolean') {\n channelSettings.mode = channelSettings.wide ? 'FM' : 'NFM';\n }\n\n if (typeof channelSettings.scan === 'boolean') {\n channelSettings.skip = channelSettings.scan ? '' : 'S';\n }\n\n if (typeof channelSettings.skip === 'boolean') {\n channelSettings.skip = channelSettings.skip ? 'S' : '';\n }\n\n const radioChannel: RadioChannel = {\n name,\n receiveFrequency: Frequency(receiveFrequency),\n transmitFrequency: Frequency(transmitFrequency),\n receiveTone: tones.receiveTone,\n transmitTone: tones.transmitTone,\n };\n\n channels.push({\n channelNumber: index,\n radioChannel,\n settings: Object.keys(channelSettings).length > 0 ? channelSettings : undefined,\n });\n }\n\n return channels;\n}\n\n/**\n * Strip channel-bound structs from decoded settings so RadioProgram.settings\n * only contains radio-wide settings.\n */\nexport function settingsWithoutChannels(memoryMap: RadioMemoryMap, settings: RadioSettings): RadioSettings {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return settings;\n }\n\n const next: RadioSettings = { ...settings };\n delete next[bindings.records];\n\n if (bindings.names) {\n delete next[bindings.names];\n }\n\n if (bindings.extras) {\n delete next[bindings.extras];\n }\n\n return next;\n}\n\n/**\n * Merge RadioProgram channels back into a memory-map settings bag for encode.\n */\nexport function programToChannelSettings(memoryMap: RadioMemoryMap, program: RadioProgram): RadioSettings {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return program.settings;\n }\n\n const recordsStruct = memoryMap.structs.find((struct) => struct.id === bindings.records);\n const namesStruct = bindings.names ? memoryMap.structs.find((struct) => struct.id === bindings.names) : undefined;\n const extrasStruct = bindings.extras ? memoryMap.structs.find((struct) => struct.id === bindings.extras) : undefined;\n const count = recordsStruct?.count ?? 0;\n const nameField = bindings.nameField ?? 'name';\n\n const records: RadioSettingValue[] = Array.from({ length: count }, () => null);\n const names: RadioSettingValue[] = Array.from({ length: count }, () => null);\n const extras: RadioSettingValue[] = Array.from({ length: count }, () => null);\n\n for (const programmed of program.channels) {\n const index = programmed.channelNumber;\n\n if (index < 0 || index >= count) {\n continue;\n }\n\n if (typeof programmed.radioChannel === 'string') {\n continue;\n }\n\n const channel = programmed.radioChannel;\n const channelSettings = programmed.settings ?? {};\n const receiveFrequency = Number(channel.receiveFrequency);\n const transmitFrequency = Number(channel.transmitFrequency);\n let offset = transmitFrequency;\n let duplex: RadioSettingValue = '';\n let split = false;\n\n if (transmitFrequency === receiveFrequency) {\n offset = 0;\n duplex = '';\n } else if (transmitFrequency > receiveFrequency) {\n offset = transmitFrequency - receiveFrequency;\n duplex = '+';\n } else {\n offset = receiveFrequency - transmitFrequency;\n duplex = '-';\n }\n\n if (channelSettings.split === true) {\n split = true;\n duplex = '';\n offset = transmitFrequency;\n }\n\n const usesOffset =\n 'duplex' in channelSettings || extrasStruct || structHasField(recordsStruct, 'duplex');\n const usesKenwoodToneBits =\n 'tone_mode' in channelSettings ||\n 'ctcss_mode' in channelSettings ||\n extrasStruct ||\n structHasField(recordsStruct, 'tone_mode') ||\n structHasField(recordsStruct, 'ctcss_mode');\n\n const record: Record<string, RadioSettingValue> = {\n [bindings.receiveFrequency]: receiveFrequency,\n [bindings.transmitFrequency]: usesOffset ? offset : transmitFrequency,\n [bindings.receiveTone]: radioToneToMapTone(channel.receiveTone),\n [bindings.transmitTone]: radioToneToMapTone(channel.transmitTone),\n };\n\n if (usesOffset) {\n record.duplex = typeof channelSettings.duplex === 'string' ? channelSettings.duplex : duplex;\n record.split = typeof channelSettings.split === 'boolean' ? channelSettings.split : split;\n record.offset = offset;\n }\n\n if (usesKenwoodToneBits) {\n record.tone_mode = false;\n record.ctcss_mode = false;\n record.dtcs_mode = false;\n record.cross_mode = false;\n\n if (channel.transmitTone?.type === RadioToneType.DCS || channel.receiveTone?.type === RadioToneType.DCS) {\n record.dtcs_mode = true;\n record.dtcs_code = radioToneToMapTone(channel.transmitTone?.type === RadioToneType.DCS ? channel.transmitTone : channel.receiveTone);\n } else if (!isNoneTone(channel.receiveTone) && !isNoneTone(channel.transmitTone)) {\n record.ctcss_mode = true;\n } else if (!isNoneTone(channel.transmitTone)) {\n record.tone_mode = true;\n }\n }\n\n for (const [key, value] of Object.entries(channelSettings)) {\n if (key === 'transmitPower') {\n record.lowpower = value === 5 || value === 4 || value === 0 ? 0 : 1;\n continue;\n }\n\n if (key === 'mode') {\n record.wide = value === 'FM';\n record.mode = value;\n continue;\n }\n\n if (key === 'skip') {\n record.scan = value !== 'S';\n record.skip = value === 'S';\n continue;\n }\n\n record[key] = value;\n }\n\n if (record.lowpower === undefined) {\n record.lowpower = 0;\n }\n\n if (record.wide === undefined) {\n record.wide = true;\n }\n\n if (record.scan === undefined) {\n record.scan = true;\n }\n\n records[index] = record;\n\n if (namesStruct) {\n names[index] = { [nameField]: channel.name ?? '' };\n } else {\n record[nameField] = channel.name ?? '';\n }\n\n if (extrasStruct) {\n extras[index] = {\n used: kenwoodUsedFlag(receiveFrequency, transmitFrequency),\n lockout: channelSettings.skip === 'S' || channelSettings.lockout === true,\n group: typeof channelSettings.group === 'number' ? channelSettings.group : 0,\n };\n }\n }\n\n const bag: RadioSettings = { ...program.settings, [bindings.records]: records };\n\n if (bindings.names && namesStruct) {\n bag[bindings.names] = names;\n }\n\n if (bindings.extras && extrasStruct) {\n bag[bindings.extras] = extras;\n }\n\n return bag;\n}\n\n/**\n * Decode a full RadioProgram (channels + radio-wide settings) from memory.\n */\nexport function decodeRadioProgram(\n memoryMap: RadioMemoryMap,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): RadioProgram {\n const decoded = decodeMemoryMap(memoryMap, contents, memoryConfig);\n\n return {\n channels: bindingsToChannels(memoryMap, decoded),\n settings: settingsWithoutChannels(memoryMap, decoded),\n };\n}\n\n/**\n * Encode a RadioProgram into an existing memory image (patch in place).\n */\nexport function encodeRadioProgram(\n memoryMap: RadioMemoryMap,\n program: RadioProgram,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): Uint8Array {\n const bag = programToChannelSettings(memoryMap, program);\n return encodeMemoryMap(memoryMap, bag, contents, memoryConfig);\n}\n"]}
1
+ {"version":3,"file":"memory-map-channels.js","sourceRoot":"","sources":["../../src/memory/memory-map-channels.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Frequency,\n type RadioChannel,\n type RadioMemoryConfig,\n type RadioMemoryMap,\n type RadioMemoryMapToneValue,\n type RadioProgram,\n type RadioProgrammedChannel,\n type RadioSettings,\n type RadioSettingValue,\n type RadioTone,\n RadioToneType,\n} from '@springfield/ham-radio-api';\nimport { decodeMemoryMap, encodeMemoryMap } from './memory-map-codec.js';\n\nfunction isToneValue(value: RadioSettingValue | undefined): value is RadioMemoryMapToneValue {\n return Boolean(value && typeof value === 'object' && !Array.isArray(value) && 'mode' in value);\n}\n\nfunction toneToRadioTone(value: RadioSettingValue | undefined): RadioTone {\n if (!isToneValue(value) || value.mode === 'none') {\n return { tone: 0, type: RadioToneType.CTCSS };\n }\n\n if (value.mode === 'ctcss') {\n return { tone: value.value, type: RadioToneType.CTCSS };\n }\n\n return { tone: value.code, type: RadioToneType.DCS };\n}\n\nfunction radioToneToMapTone(tone: RadioTone | undefined): RadioMemoryMapToneValue {\n if (!tone || !tone.tone) {\n return { mode: 'none' };\n }\n\n if (tone.type === RadioToneType.DCS) {\n return { mode: 'dcs', code: Number(tone.tone), polarity: 'N' };\n }\n\n return { mode: 'ctcss', value: Number(tone.tone) };\n}\n\nfunction noneTone(): RadioTone {\n return { tone: 0, type: RadioToneType.CTCSS };\n}\n\nfunction isNoneTone(tone: RadioTone | undefined): boolean {\n return !tone || !tone.tone;\n}\n\nfunction structHasField(struct: { fields: { id: string }[] } | undefined, fieldId: string): boolean {\n return Boolean(struct?.fields.some((field) => field.id === fieldId));\n}\n\nfunction transmitFrequencyFromRecord(record: Record<string, RadioSettingValue>, bindings: NonNullable<RadioMemoryMap['channelBindings']>): number {\n const receiveFrequency = Number(record[bindings.receiveFrequency] ?? 0);\n const offsetOrTransmit = Number(record[bindings.transmitFrequency] ?? 0);\n\n if (record.split === true) {\n return offsetOrTransmit;\n }\n\n if (record.duplex === '+') {\n return receiveFrequency + offsetOrTransmit;\n }\n\n if (record.duplex === '-') {\n return receiveFrequency - offsetOrTransmit;\n }\n\n // Kenwood stores simplex as duplex \"\" and offset 0. Empty duplex is not an absolute TX frequency.\n if (record.duplex === '') {\n return receiveFrequency;\n }\n\n if (record.duplex === undefined) {\n return bindings.transmitFrequency === bindings.receiveFrequency ? receiveFrequency : offsetOrTransmit;\n }\n\n return offsetOrTransmit;\n}\n\nfunction applyKenwoodToneMode(\n record: Record<string, RadioSettingValue>,\n bindings: NonNullable<RadioMemoryMap['channelBindings']>,\n): { receiveTone: RadioTone; transmitTone: RadioTone } {\n const hasToneModeBits = 'tone_mode' in record || 'ctcss_mode' in record || 'dtcs_mode' in record;\n\n if (!hasToneModeBits) {\n return {\n receiveTone: toneToRadioTone(record[bindings.receiveTone]),\n transmitTone: toneToRadioTone(record[bindings.transmitTone]),\n };\n }\n\n if (record.tone_mode === true) {\n return { receiveTone: noneTone(), transmitTone: toneToRadioTone(record[bindings.transmitTone]) };\n }\n\n if (record.ctcss_mode === true) {\n const tone = toneToRadioTone(record[bindings.receiveTone]);\n return { receiveTone: tone, transmitTone: tone };\n }\n\n if (record.dtcs_mode === true) {\n const tone = toneToRadioTone(record.dtcs_code);\n return { receiveTone: tone, transmitTone: tone };\n }\n\n return { receiveTone: noneTone(), transmitTone: noneTone() };\n}\n\nfunction kenwoodUsedFlag(receiveFrequency: number, transmitFrequency: number): number {\n const frequency = transmitFrequency || receiveFrequency;\n\n if (frequency < 150_000_000) {\n return 0;\n }\n\n if (frequency < 400_000_000) {\n return 1;\n }\n\n return 2;\n}\n\n/** TM-D710 chmap band codes: 0=118 MHz, 5=144, 6=200, 7=300, 8=400, 9=800. */\nfunction kenwoodChmapBand(receiveFrequency: number): number {\n if (receiveFrequency < 136_000_000) {\n return 0;\n }\n\n if (receiveFrequency < 200_000_000) {\n return 5;\n }\n\n if (receiveFrequency < 300_000_000) {\n return 6;\n }\n\n if (receiveFrequency < 400_000_000) {\n return 7;\n }\n\n if (receiveFrequency < 800_000_000) {\n return 8;\n }\n\n return 9;\n}\n\nfunction asRecord(value: RadioSettingValue | undefined): Record<string, RadioSettingValue> | undefined {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n\n return value as Record<string, RadioSettingValue>;\n}\n\n/**\n * Project decoded memory-map channel structs into RadioProgrammedChannel[].\n */\nexport function bindingsToChannels(\n memoryMap: RadioMemoryMap,\n settings: RadioSettings,\n): RadioProgrammedChannel[] {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return [];\n }\n\n const records = settings[bindings.records];\n const names = bindings.names ? settings[bindings.names] : undefined;\n const extras = bindings.extras ? settings[bindings.extras] : undefined;\n const recordItems = Array.isArray(records) ? records : [];\n const nameItems = Array.isArray(names) ? names : [];\n const extraItems = Array.isArray(extras) ? extras : [];\n const nameField = bindings.nameField ?? 'name';\n const boundFieldIds = new Set([\n bindings.receiveFrequency,\n bindings.transmitFrequency,\n bindings.receiveTone,\n bindings.transmitTone,\n nameField,\n ]);\n\n const channels: RadioProgrammedChannel[] = [];\n\n for (let index = 0; index < recordItems.length; index += 1) {\n const record = asRecord(recordItems[index]);\n const extraRecord = asRecord(extraItems[index]);\n\n if (bindings.extras && extraItems.length > 0 && extraRecord === undefined) {\n continue;\n }\n\n if (!record) {\n continue;\n }\n\n const nameRecord = asRecord(nameItems[index]);\n const nameFromTable = typeof nameRecord?.[nameField] === 'string' ? nameRecord[nameField] : '';\n const nameFromRecord = typeof record[nameField] === 'string' ? record[nameField] : '';\n const name = nameFromTable || nameFromRecord;\n\n const receiveFrequency = Number(record[bindings.receiveFrequency] ?? 0);\n const transmitFrequency = transmitFrequencyFromRecord(record, bindings);\n const tones = applyKenwoodToneMode(record, bindings);\n\n const channelSettings: RadioSettings = {};\n\n for (const [fieldId, fieldValue] of Object.entries(record)) {\n if (boundFieldIds.has(fieldId) || fieldId.startsWith('_')) {\n continue;\n }\n\n channelSettings[fieldId] = fieldValue;\n }\n\n if (extraRecord) {\n for (const [fieldId, fieldValue] of Object.entries(extraRecord)) {\n if (fieldId.startsWith('_') || fieldId === 'used') {\n continue;\n }\n\n channelSettings[fieldId] = fieldValue;\n }\n\n if (typeof extraRecord.lockout === 'boolean') {\n channelSettings.skip = extraRecord.lockout ? 'S' : '';\n }\n }\n\n // Map Chirp lowpower index onto legacy transmitPower watts for UV-5R UI compatibility.\n if (typeof channelSettings.lowpower === 'number') {\n channelSettings.transmitPower = channelSettings.lowpower === 0 ? 5 : 1;\n }\n\n if (typeof channelSettings.wide === 'boolean') {\n channelSettings.mode = channelSettings.wide ? 'FM' : 'NFM';\n }\n\n if (typeof channelSettings.scan === 'boolean') {\n channelSettings.skip = channelSettings.scan ? '' : 'S';\n }\n\n if (typeof channelSettings.skip === 'boolean') {\n channelSettings.skip = channelSettings.skip ? 'S' : '';\n }\n\n const radioChannel: RadioChannel = {\n name,\n receiveFrequency: Frequency(receiveFrequency),\n transmitFrequency: Frequency(transmitFrequency),\n receiveTone: tones.receiveTone,\n transmitTone: tones.transmitTone,\n };\n\n channels.push({\n channelNumber: index,\n radioChannel,\n settings: Object.keys(channelSettings).length > 0 ? channelSettings : undefined,\n });\n }\n\n return channels;\n}\n\n/**\n * Strip channel-bound structs from decoded settings so RadioProgram.settings\n * only contains radio-wide settings.\n */\nexport function settingsWithoutChannels(memoryMap: RadioMemoryMap, settings: RadioSettings): RadioSettings {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return settings;\n }\n\n const next: RadioSettings = { ...settings };\n delete next[bindings.records];\n\n if (bindings.names) {\n delete next[bindings.names];\n }\n\n if (bindings.extras) {\n delete next[bindings.extras];\n }\n\n return next;\n}\n\n/**\n * Merge RadioProgram channels back into a memory-map settings bag for encode.\n */\nexport function programToChannelSettings(memoryMap: RadioMemoryMap, program: RadioProgram): RadioSettings {\n const bindings = memoryMap.channelBindings;\n\n if (!bindings) {\n return program.settings;\n }\n\n const recordsStruct = memoryMap.structs.find((struct) => struct.id === bindings.records);\n const namesStruct = bindings.names ? memoryMap.structs.find((struct) => struct.id === bindings.names) : undefined;\n const extrasStruct = bindings.extras ? memoryMap.structs.find((struct) => struct.id === bindings.extras) : undefined;\n const count = recordsStruct?.count ?? 0;\n const nameField = bindings.nameField ?? 'name';\n\n const records: RadioSettingValue[] = Array.from({ length: count }, () => null);\n const names: RadioSettingValue[] = Array.from({ length: count }, () => null);\n const extras: RadioSettingValue[] = Array.from({ length: count }, () => null);\n\n for (const programmed of program.channels) {\n const index = programmed.channelNumber;\n\n if (index < 0 || index >= count) {\n continue;\n }\n\n if (typeof programmed.radioChannel === 'string') {\n continue;\n }\n\n const channel = programmed.radioChannel;\n const channelSettings = programmed.settings ?? {};\n const receiveFrequency = Number(channel.receiveFrequency);\n const transmitFrequency = Number(channel.transmitFrequency);\n let offset = transmitFrequency;\n let duplex: RadioSettingValue = '';\n let split = false;\n\n if (transmitFrequency === receiveFrequency) {\n offset = 0;\n duplex = '';\n } else if (transmitFrequency > receiveFrequency) {\n offset = transmitFrequency - receiveFrequency;\n duplex = '+';\n } else {\n offset = receiveFrequency - transmitFrequency;\n duplex = '-';\n }\n\n if (channelSettings.split === true) {\n split = true;\n duplex = '';\n offset = transmitFrequency;\n }\n\n const usesOffset =\n 'duplex' in channelSettings || extrasStruct || structHasField(recordsStruct, 'duplex');\n const usesKenwoodToneBits =\n 'tone_mode' in channelSettings ||\n 'ctcss_mode' in channelSettings ||\n extrasStruct ||\n structHasField(recordsStruct, 'tone_mode') ||\n structHasField(recordsStruct, 'ctcss_mode');\n\n const record: Record<string, RadioSettingValue> = {\n [bindings.receiveFrequency]: receiveFrequency,\n [bindings.transmitFrequency]: usesOffset ? offset : transmitFrequency,\n [bindings.receiveTone]: radioToneToMapTone(channel.receiveTone),\n [bindings.transmitTone]: radioToneToMapTone(channel.transmitTone),\n };\n\n if (usesOffset) {\n record.duplex = typeof channelSettings.duplex === 'string' ? channelSettings.duplex : duplex;\n record.split = typeof channelSettings.split === 'boolean' ? channelSettings.split : split;\n record.offset = offset;\n }\n\n if (usesKenwoodToneBits) {\n record.tone_mode = false;\n record.ctcss_mode = false;\n record.dtcs_mode = false;\n record.cross_mode = false;\n\n if (channel.transmitTone?.type === RadioToneType.DCS || channel.receiveTone?.type === RadioToneType.DCS) {\n record.dtcs_mode = true;\n record.dtcs_code = radioToneToMapTone(channel.transmitTone?.type === RadioToneType.DCS ? channel.transmitTone : channel.receiveTone);\n } else if (!isNoneTone(channel.receiveTone) && !isNoneTone(channel.transmitTone)) {\n record.ctcss_mode = true;\n } else if (!isNoneTone(channel.transmitTone)) {\n record.tone_mode = true;\n }\n }\n\n for (const [key, value] of Object.entries(channelSettings)) {\n if (key === 'transmitPower') {\n record.lowpower = value === 5 || value === 4 || value === 0 ? 0 : 1;\n continue;\n }\n\n if (key === 'mode') {\n record.wide = value === 'FM';\n record.mode = value;\n continue;\n }\n\n if (key === 'skip') {\n record.scan = value !== 'S';\n record.skip = value === 'S';\n continue;\n }\n\n record[key] = value;\n }\n\n if (record.lowpower === undefined) {\n record.lowpower = 0;\n }\n\n if (record.wide === undefined) {\n record.wide = true;\n }\n\n if (record.scan === undefined) {\n record.scan = true;\n }\n\n records[index] = record;\n\n if (namesStruct) {\n names[index] = { [nameField]: channel.name ?? '' };\n } else {\n record[nameField] = channel.name ?? '';\n }\n\n if (extrasStruct) {\n const extraRecord: Record<string, RadioSettingValue> = {\n used: kenwoodUsedFlag(receiveFrequency, transmitFrequency),\n lockout: channelSettings.skip === 'S' || channelSettings.lockout === true,\n group: typeof channelSettings.group === 'number' ? channelSettings.group : 0,\n };\n\n if (structHasField(extrasStruct, 'band')) {\n extraRecord.band = typeof channelSettings.band === 'number' ? channelSettings.band : kenwoodChmapBand(receiveFrequency);\n }\n\n extras[index] = extraRecord;\n }\n }\n\n const bag: RadioSettings = { ...program.settings, [bindings.records]: records };\n\n if (bindings.names && namesStruct) {\n bag[bindings.names] = names;\n }\n\n if (bindings.extras && extrasStruct) {\n bag[bindings.extras] = extras;\n }\n\n return bag;\n}\n\n/**\n * Decode a full RadioProgram (channels + radio-wide settings) from memory.\n */\nexport function decodeRadioProgram(\n memoryMap: RadioMemoryMap,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): RadioProgram {\n const decoded = decodeMemoryMap(memoryMap, contents, memoryConfig);\n\n return {\n channels: bindingsToChannels(memoryMap, decoded),\n settings: settingsWithoutChannels(memoryMap, decoded),\n };\n}\n\n/**\n * Encode a RadioProgram into an existing memory image (patch in place).\n */\nexport function encodeRadioProgram(\n memoryMap: RadioMemoryMap,\n program: RadioProgram,\n contents: Uint8Array,\n memoryConfig: RadioMemoryConfig,\n): Uint8Array {\n const bag = programToChannelSettings(memoryMap, program);\n return encodeMemoryMap(memoryMap, bag, contents, memoryConfig);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springfield/ham-radio-utils",
3
- "version": "4.7.0",
3
+ "version": "4.8.0",
4
4
  "author": "Bryan Hunt",
5
5
  "license": "MIT",
6
6
  "readme": "README.md",
@@ -125,6 +125,31 @@ function kenwoodUsedFlag(receiveFrequency: number, transmitFrequency: number): n
125
125
  return 2;
126
126
  }
127
127
 
128
+ /** TM-D710 chmap band codes: 0=118 MHz, 5=144, 6=200, 7=300, 8=400, 9=800. */
129
+ function kenwoodChmapBand(receiveFrequency: number): number {
130
+ if (receiveFrequency < 136_000_000) {
131
+ return 0;
132
+ }
133
+
134
+ if (receiveFrequency < 200_000_000) {
135
+ return 5;
136
+ }
137
+
138
+ if (receiveFrequency < 300_000_000) {
139
+ return 6;
140
+ }
141
+
142
+ if (receiveFrequency < 400_000_000) {
143
+ return 7;
144
+ }
145
+
146
+ if (receiveFrequency < 800_000_000) {
147
+ return 8;
148
+ }
149
+
150
+ return 9;
151
+ }
152
+
128
153
  function asRecord(value: RadioSettingValue | undefined): Record<string, RadioSettingValue> | undefined {
129
154
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
130
155
  return undefined;
@@ -404,11 +429,17 @@ export function programToChannelSettings(memoryMap: RadioMemoryMap, program: Rad
404
429
  }
405
430
 
406
431
  if (extrasStruct) {
407
- extras[index] = {
432
+ const extraRecord: Record<string, RadioSettingValue> = {
408
433
  used: kenwoodUsedFlag(receiveFrequency, transmitFrequency),
409
434
  lockout: channelSettings.skip === 'S' || channelSettings.lockout === true,
410
435
  group: typeof channelSettings.group === 'number' ? channelSettings.group : 0,
411
436
  };
437
+
438
+ if (structHasField(extrasStruct, 'band')) {
439
+ extraRecord.band = typeof channelSettings.band === 'number' ? channelSettings.band : kenwoodChmapBand(receiveFrequency);
440
+ }
441
+
442
+ extras[index] = extraRecord;
412
443
  }
413
444
  }
414
445