@ham2k/extension-sdk 0.12.13 → 0.12.14
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.
- package/dist/index.d.ts +37 -2
- package/dist/index.js +7 -0
- package/docs/distribution.md +1 -1
- package/docs/hooks.md +91 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// @ham2k/extension-sdk 0.12.
|
|
1
|
+
// @ham2k/extension-sdk 0.12.14
|
|
2
2
|
/** Experimental v1 panel scene contract. All coordinates are in the scene's viewBox. */
|
|
3
3
|
export interface PanelScene {
|
|
4
4
|
version: 1;
|
|
@@ -1537,6 +1537,7 @@ export interface ExtensionManifest {
|
|
|
1537
1537
|
requiresLocation?: boolean;
|
|
1538
1538
|
requiresRadioRead?: boolean;
|
|
1539
1539
|
requiresRadioWrite?: boolean;
|
|
1540
|
+
requiresRadioRaw?: boolean;
|
|
1540
1541
|
requiresClusterRead?: boolean;
|
|
1541
1542
|
requiresClusterSpot?: boolean;
|
|
1542
1543
|
requiresClusterCommand?: boolean;
|
|
@@ -2095,15 +2096,44 @@ export interface PanelRadioSet extends PanelRadioTarget {
|
|
|
2095
2096
|
}
|
|
2096
2097
|
/** @deprecated `setRadio`'s argument through extension API 6. */
|
|
2097
2098
|
export type PanelRadioTune = PanelRadioSet;
|
|
2099
|
+
/**
|
|
2100
|
+
* Commands in the radio's own protocol — exactly one of `text` or `bytes`, up to 4096 bytes
|
|
2101
|
+
* (extension API 11). Where the app's driver keeps one question on the wire (CI-V, Yaesu binary,
|
|
2102
|
+
* HRD, Commander, flrig) each command waits its turn in that queue, and on a FlexRadio is numbered
|
|
2103
|
+
* like the driver's own; the reply is then the answers to these commands alone. Elsewhere the bytes
|
|
2104
|
+
* are written as given. See hooks.md for what each protocol takes.
|
|
2105
|
+
*/
|
|
2106
|
+
export interface PanelRadioRaw extends PanelRadioTarget {
|
|
2107
|
+
/** Sent as UTF-8: Kenwood, Yaesu and Elecraft ASCII, rigctld, N3FJP, SmartSDR, HRD, Commander, flrig. */
|
|
2108
|
+
text?: string;
|
|
2109
|
+
/** Each 0…255: Icom CI-V, Yaesu's binary protocol. */
|
|
2110
|
+
bytes?: number[];
|
|
2111
|
+
/**
|
|
2112
|
+
* How long to wait for the reply, up to 2000 ms; omitted or 0, the call answers once the commands
|
|
2113
|
+
* are handed to the driver. Where they are written as given, the reply is everything the radio
|
|
2114
|
+
* sent in that time — the answers to the app's own polls included.
|
|
2115
|
+
*/
|
|
2116
|
+
replyMs?: number;
|
|
2117
|
+
/** Ends the reply early, just after the first occurrence of this text or these bytes. Needs `replyMs`. */
|
|
2118
|
+
until?: string | number[];
|
|
2119
|
+
}
|
|
2120
|
+
export interface PanelRadioRawResult extends PanelRadioResult {
|
|
2121
|
+
/** What came back within `replyMs`, possibly nothing, at most 64 KiB; absent without `replyMs`. `text` is it as UTF-8. */
|
|
2122
|
+
reply?: {
|
|
2123
|
+
text: string;
|
|
2124
|
+
bytes: number[];
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2098
2127
|
export interface PanelRadioResult {
|
|
2099
2128
|
/** Accepted by the host; confirmation still comes from reported state. */
|
|
2100
2129
|
accepted: boolean;
|
|
2101
2130
|
/**
|
|
2102
2131
|
* `stopped`: a scope change while no display has the scope running — nothing was sent.
|
|
2132
|
+
* `busy`: eight raw commands to this radio are already waiting (extension API 11).
|
|
2103
2133
|
* `unsupported`: this radio, or the app's keying, cannot do it — keying calls on a radio that
|
|
2104
2134
|
* is not the logging radio, or with the app's keying off.
|
|
2105
2135
|
*/
|
|
2106
|
-
reason?: "changed" | "disconnected" | "transmitting" | "invalid" | "stopped" | "unsupported";
|
|
2136
|
+
reason?: "changed" | "disconnected" | "transmitting" | "invalid" | "stopped" | "unsupported" | "busy";
|
|
2107
2137
|
state: PanelRadioState | null;
|
|
2108
2138
|
}
|
|
2109
2139
|
/** @deprecated `PanelRadioResult`'s name through extension API 6. */
|
|
@@ -2565,6 +2595,11 @@ export declare const host: {
|
|
|
2565
2595
|
}): Promise<PanelRadioResult>;
|
|
2566
2596
|
/** Stops all CW, voice and PTT the app is keying, and a tune it started (extension API 9), as Escape does. Needs `requiresRadioWrite` and extension API 7. */
|
|
2567
2597
|
stopRadioTransmit(args: PanelRadioTarget): Promise<PanelRadioResult>;
|
|
2598
|
+
/**
|
|
2599
|
+
* Writes any command in the radio's own protocol — one that transmits included — and collects the
|
|
2600
|
+
* reply for `replyMs`. Needs `requiresRadioRaw` and extension API 11.
|
|
2601
|
+
*/
|
|
2602
|
+
sendRadioRaw(args: PanelRadioRaw): Promise<PanelRadioRawResult>;
|
|
2568
2603
|
/** The app's DX cluster connection, as Settings shows it. Needs `requiresClusterRead` and extension API 10. */
|
|
2569
2604
|
clusterStatus(): Promise<ClusterStatus>;
|
|
2570
2605
|
/** The node's recent lines after `after`, oldest first, at most `limit` of the newest. Needs `requiresClusterRead` and extension API 10. */
|
package/dist/index.js
CHANGED
|
@@ -197,6 +197,13 @@ const host = {
|
|
|
197
197
|
async stopRadioTransmit(args) {
|
|
198
198
|
return await hostCallFn()("stopRadioTransmit", { ...args });
|
|
199
199
|
},
|
|
200
|
+
/**
|
|
201
|
+
* Writes any command in the radio's own protocol — one that transmits included — and collects the
|
|
202
|
+
* reply for `replyMs`. Needs `requiresRadioRaw` and extension API 11.
|
|
203
|
+
*/
|
|
204
|
+
async sendRadioRaw(args) {
|
|
205
|
+
return await hostCallFn()("sendRadioRaw", { ...args });
|
|
206
|
+
},
|
|
200
207
|
/** The app's DX cluster connection, as Settings shows it. Needs `requiresClusterRead` and extension API 10. */
|
|
201
208
|
async clusterStatus() {
|
|
202
209
|
return await hostCallFn()("clusterStatus", {});
|
package/docs/distribution.md
CHANGED
|
@@ -573,7 +573,7 @@ counts as the catalog's own here. The row and the details show the track, and
|
|
|
573
573
|
the details' **Follow stable releases only** puts it back on stable; an
|
|
574
574
|
uninstall or a file install clears it with the rest of the record.
|
|
575
575
|
|
|
576
|
-
At most once
|
|
576
|
+
At most once a day — on launch and on resume — the app asks the
|
|
577
577
|
catalog whether anything installed has a newer release, and says so in the
|
|
578
578
|
status bar and on the row; the notice comes down with the last update taken.
|
|
579
579
|
It never installs unasked: the notice's **Update all** is the panel's own,
|
package/docs/hooks.md
CHANGED
|
@@ -2115,7 +2115,9 @@ same shape as `requiresLocation`, and shown to the operator at install:
|
|
|
2115
2115
|
`host.setRadioConnection()` and `host.setRadioSpectrum()` — and transmitting
|
|
2116
2116
|
with them: `host.sendRadioCw()`, `host.playRadioVoice()`, `host.setRadioPtt()`
|
|
2117
2117
|
and `host.stopRadioTransmit()` — and implies read, since a command answers with the
|
|
2118
|
-
radio's state.
|
|
2118
|
+
radio's state. `"requiresRadioRaw": true` (extension API 11) also allows
|
|
2119
|
+
`host.sendRadioRaw()`, any command in the radio's own protocol, and implies
|
|
2120
|
+
write. An undeclared call rejects rather than answering null.
|
|
2119
2121
|
A capability belongs to the bundle that declared it, and to the sub-extensions
|
|
2120
2122
|
that bundle defines under its own key. A separately installed bundle never
|
|
2121
2123
|
inherits one through its name: `rigpanel-themes` gets nothing from `rigpanel`.
|
|
@@ -2231,6 +2233,61 @@ not paced, and not refused for a transmission in progress.
|
|
|
2231
2233
|
connection using the same selection and identity checks. Acceptance starts the
|
|
2232
2234
|
operation; follow reported connection state for completion. It does not switch
|
|
2233
2235
|
the hardware's mains power or initiate transmission.
|
|
2236
|
+
|
|
2237
|
+
`host.sendRadioRaw({id, selection?, text | bytes, replyMs?, until?})`
|
|
2238
|
+
(extension API 11, `requiresRadioRaw`) sends commands in the radio's own
|
|
2239
|
+
protocol — exactly one of `text`, sent as UTF-8, or `bytes`, each 0…255, up
|
|
2240
|
+
to 4096 bytes. **Nothing about them is checked.** They may transmit, change
|
|
2241
|
+
any setting or put the radio somewhere the app's own controls never would;
|
|
2242
|
+
that is what the operator agreed to at install, where the grant is shown in
|
|
2243
|
+
those words. It reaches any local radio through the same `id`/`selection`
|
|
2244
|
+
check as `setRadio`, with keying on or off, and is neither paced nor refused
|
|
2245
|
+
for a transmission in progress. One radio's calls go one at a time, in order,
|
|
2246
|
+
so that one call's reply window never holds the next one's answer, and past
|
|
2247
|
+
eight waiting the next is refused as `busy`; the app's own polls may come
|
|
2248
|
+
between two calls.
|
|
2249
|
+
|
|
2250
|
+
- `replyMs`, up to 2000: how long to wait for the reply. Omitted or 0, the
|
|
2251
|
+
call answers as soon as the commands are handed to the driver, with no
|
|
2252
|
+
`reply`.
|
|
2253
|
+
- `until`, text or bytes, needs `replyMs`: the reply ends just after its first
|
|
2254
|
+
occurrence.
|
|
2255
|
+
- The answer carries `reply: {text, bytes}`, possibly empty, at most 64 KiB,
|
|
2256
|
+
with `text` its UTF-8 reading.
|
|
2257
|
+
|
|
2258
|
+
What the commands are, and what the reply holds, is the protocol's. Where the
|
|
2259
|
+
app's driver keeps one question on the wire and reads the next reply as its
|
|
2260
|
+
answer, a raw command waits its turn in that queue — written beside it, its
|
|
2261
|
+
answer would be read as the answer to the driver's question — or, on a
|
|
2262
|
+
FlexRadio, is numbered as the driver's own are. The reply is then the answers
|
|
2263
|
+
to the raw commands alone, as the radio sent them, once each has come or the
|
|
2264
|
+
window closes:
|
|
2265
|
+
|
|
2266
|
+
| Radio | Commands | Reply |
|
|
2267
|
+
|---|---|---|
|
|
2268
|
+
| Icom CI-V | `bytes`: whole frames, `FE FE` … `FD`, one at a time; the app addresses each to the radio from itself, whatever its address bytes say | each frame's answer frame (`FB`/`FA` or its data) |
|
|
2269
|
+
| Yaesu binary (FT-817/857/897) | `bytes`: five-byte commands | what the radio sends for each before it falls quiet; not read by the app |
|
|
2270
|
+
| FlexRadio | `text`: one command per line, without `C<seq>\|` — the app numbers each like its own | each one's `R` line |
|
|
2271
|
+
| Ham Radio Deluxe | `text`: one command per line, without the radio's context — the app adds it | each one's reply text, one per line |
|
|
2272
|
+
| DXLab Commander | `text`: one whole message (`<command:10>CmdGetFreq<parameters:0>`) | the field it is answered with; without `replyMs` it goes out as a set, waiting for nothing |
|
|
2273
|
+
| flrig | `text`: one XML-RPC call (`<?xml …?><methodCall>…`) — the app posts it | the response's body |
|
|
2274
|
+
|
|
2275
|
+
Every other radio's commands are written as given — several back to back
|
|
2276
|
+
(`FA00014074000;MD2;`) in one write, none of the app's own between them —
|
|
2277
|
+
since each of their answers names what it answers: Kenwood, Elecraft and
|
|
2278
|
+
Yaesu ASCII, rigctld, N3FJP, Guohetec. The reply there is everything the
|
|
2279
|
+
connection received in the window, the answers to the app's own polls
|
|
2280
|
+
included, so `until` is worth setting.
|
|
2281
|
+
|
|
2282
|
+
The app's driver still reads what the radio sends, so a raw command's effect
|
|
2283
|
+
shows in `readRadio` as a change made at the front panel would — and a command
|
|
2284
|
+
that confuses the driver confuses the app. A radio that is not connected
|
|
2285
|
+
answers `disconnected`; one whose driver takes no raw commands (a placeholder
|
|
2286
|
+
radio), `unsupported`; a malformed call, or commands that are not the
|
|
2287
|
+
protocol's (CI-V bytes that are not whole frames), `invalid`. A refusal heard
|
|
2288
|
+
within a second of a raw command on a protocol whose refusals name no command
|
|
2289
|
+
(`?;`, rigctld's `RPRT`) is taken as the raw command's, not counted against the
|
|
2290
|
+
app's own reads.
|
|
2234
2291
|
On a host with the panadapter enabled, `readRadio()` carries `spectrum`: null
|
|
2235
2292
|
for a radio without a scope, otherwise its settings as the radio reports them
|
|
2236
2293
|
(`mode`, `spanHz`, `lowHz`/`highHz`, `refLevelDb`, `speed`), what it accepts
|
|
@@ -2422,6 +2479,39 @@ row/entry→`LookupRow` transform. See `DataFileManager`
|
|
|
2422
2479
|
(`fetchType: 'raw'` — the parsed Hams of Note index is cached as JSON and
|
|
2423
2480
|
replayed through `onLoadRawData` at startup, issue #17).
|
|
2424
2481
|
|
|
2482
|
+
### N1MM call history files
|
|
2483
|
+
|
|
2484
|
+
N1MM Logger+'s call history files are uploaded to
|
|
2485
|
+
[n1mmwp.hamdocs.com](https://n1mmwp.hamdocs.com/mmfiles/categories/callhistory/)
|
|
2486
|
+
under a new name with every update (`CWOPS_4002.txt`), and downloaded by a
|
|
2487
|
+
form POST that carries a nonce from the file's own page, so no URL points at
|
|
2488
|
+
the current one. A `url` of `n1mm-history:<stem>` asks the host to find it
|
|
2489
|
+
(extension API 11):
|
|
2490
|
+
|
|
2491
|
+
```ts
|
|
2492
|
+
{ key: 'cwops-history', url: 'n1mm-history:CWOPS', fetchType: 'raw', maxAgeInDays: 7, /* … */ }
|
|
2493
|
+
```
|
|
2494
|
+
|
|
2495
|
+
- **Which file:** the newest one, by publish date, whose name is the stem or
|
|
2496
|
+
the stem followed by `-` or `_` (extension and case aside). `CWOPS` takes
|
|
2497
|
+
`CWOPS_4002.txt` and `CWOPS_4000-CCC.txt`, never `CWOPSOPEN_2026-002.txt`,
|
|
2498
|
+
though N1MM's search lists all three; to follow one variant only, name it
|
|
2499
|
+
(`n1mm-history:CWOPS_4000-CCC`). The search is read newest first, page by
|
|
2500
|
+
page, until a page lists one of the stem's files.
|
|
2501
|
+
- **When:** N1MM sends no ETag; the chosen file's name, publish date and page
|
|
2502
|
+
stand in for one, so a re-upload under the same name still counts as new. A
|
|
2503
|
+
refresh whose newest file is the one last downloaded stops after the search,
|
|
2504
|
+
like a 304. A forced refresh (RELOAD, Refresh) downloads it regardless.
|
|
2505
|
+
- **What arrives:** the file as served, in N1MM's format — a `!!Order!!,…`
|
|
2506
|
+
column line, `#` comment lines, then CSV rows. `fetchType: 'raw'` is the one
|
|
2507
|
+
that fits; `rawToJSONData` parses it. `url` in its arguments is the
|
|
2508
|
+
`n1mm-history:` string, not the file's address.
|
|
2509
|
+
- **Failures:** a stem nothing matches, a refused download, or a page that no
|
|
2510
|
+
longer has the shape the host reads fails the download with
|
|
2511
|
+
`N1mmCallHistoryUnavailable` — a notice on a refresh the operator asked for,
|
|
2512
|
+
an upload for the background passes. The requests and parsing are
|
|
2513
|
+
`halo_core`'s `n1mm_call_history.dart`, shared by the app and the CLI.
|
|
2514
|
+
|
|
2425
2515
|
### How CSV rows reach `csvToLookupEntry`
|
|
2426
2516
|
|
|
2427
2517
|
An extension writes a **per-row** mapper; the kernel synthesizes the batch
|