poe-svelte-ui-lib 1.71.0 → 1.72.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.
package/README.md CHANGED
@@ -61,7 +61,7 @@ npm install poe-svelte-ui-lib
61
61
 
62
62
  **Битовые поля конфигурации** — `bitFieldGet(word, start, end)`/`bitFieldSet(word, start, end, value)`: поле `start..end` 32-битного слова `{GROUP}.Cfg` (Select/Input с `bitMode`) обычной арифметикой, без знаковых 32-битных операций JS — бит 31 разбирается и собирается корректно, результат всегда 0..2³²−1; тест против эталона на BigInt — `tests/bitField.test.mjs`.
63
63
 
64
- **Ядро протоколов** — `poe-svelte-ui-lib/protocols` (без Svelte, работает и под Node без Vite): общий для DevCloud, WebApp и SYP-DevTerminal CBOR-кодек (RFC 8949) — `encodeCbor`/`decodeCbor`, `CborEncoder`/`CborDecoder`; `valueToCbor`/`cborToValue` — обычные значения, двоичные данные как `Uint8Array` (WebSocket, хранилище, телеметрия); `jsonToCbor`/`cborToJson` — JSON-совместимые значения, двоичные данные в base64, строки под ключами с `BIN` — байты (поля ввода терминала и отладки). Пакет `poe_cbor_pkt` — indefinite-массив объектов `[[TrgBusID, SrcBusID, Cmd, Payload, CRC16], …]` (CAN, RS485): `encodePacket`/`decodePacket` (разбор с начала буфера — `complete` с длиной, `incomplete` для потока или `garbage`; объекты одному адресату не склеиваются, порядок сохраняется, неверный CRC — флаг `crcOk`), `objectsFor` (свой адрес и broadcast `BROADCAST_BUS_ID = 0xFFFF`), `EXTERNAL_BUS_ID = 0x0000` — `SrcBusID` терминала и отладки, `makeCmd(header, argument, reply = true)`/`splitCmd` — `Cmd`: заголовок в битах 14-15, аргумент в битах 1-13 (0..8191), флаг ответа в бите 0 (как `CMD`/`CMD_NR` прошивки), `packetObjectCrc`; контрольные суммы `crc16Kermit` и `crc8Rohc` — строго побайтные, как в `common.c` прошивок. Байты совпадают с `poe_cbor_pkt.c` прошивки — проверка `npm run TestProtocols` (`tests/protocols.test.mjs`, эталонные пакеты собраны прошивочным кодом). Рамка xPOE-Debug (UART-консоль `system_console`, `[SOH] HDR [US] ARG [STX] VAL [ETX] CRC8 [US] FHS [EOT]`): `encodeXPoeDebugFrame` — команда устройству, `createXPoeDebugParser().push(байты)` — потоковый разбор кадров, строк Teleplot (`plot`) и прочего текста (`raw`), с проверкой CRC `crc8Rohc` строго побайтно, как `crc8_rohc` в `common.c` прошивок. CAN/CAN FD через slcan-адаптер (`can_service` прошивки): `canFragments`/`encodeCanPacket` — нарезка пакета на кадры как `CAN_Send` (бит 10 ID — «последний», биты 0..9 — `packetId`, по 8 / 64 байта), `encodeSlcanFrame`, `createCanParser().push(байты)` — разбор кадров slcan со сборкой фрагментов и обрезкой паддинга CAN FD. RS485 — сырой поток пакетов: `createPacketStreamParser().push(байты)` (пауза обрывает недособранное, мусор пропускается по байту). Открытие slcan-адаптера — `slcanOpenCommands(скорость, скоростьДанных?)`. Поле Value команды xPOE-Debug из ввода — `xPoeDebugValueFromText` (hex как есть, JSON → CBOR). Графики Teleplot (строки PLOT `>Группа.Имя:Значение`) — `createPlotGroups({ gapMs })`: `push(серия, значение, время)` раскладывает по группам (префикс до точки) и держит серии в порядке устройства — пачка значений идёт подряд, новая начинается после паузы дольше `gapMs` (50 мс) или с повтора имени, порядок берётся из последней пачки; `data(группа)` — последние значения. Словарь протокола — `HEADER_CODES`, `DEFAULT_ARGUMENT_CODES` (генерируется из мастер-словаря `src/lib/protocols/dictionary.yaml` — `npm run Dictionary`, перед упаковкой автоматически; сам файл поставляется как `poe-svelte-ui-lib/protocols/dictionary.yaml`, `.framework/Dictionary.yaml` прошивок — его справочные копии, сборка прошивок сверяет с ними `api_cmd.h`), `parseArgumentDictionary` (строки `- [Строка, Enum, Число]`), `nameByCode`. Своих копий протоколов и словаря в приложениях не держим: терминал и отладка облака читают и пишут порт сырыми байтами, разбор и сборка — здесь.
64
+ **Ядро протоколов** — `poe-svelte-ui-lib/protocols` (без Svelte, работает и под Node без Vite): общий для DevCloud, WebApp и SYP-DevTerminal CBOR-кодек (RFC 8949) — `encodeCbor`/`decodeCbor`, `CborEncoder`/`CborDecoder`; `valueToCbor`/`cborToValue` — обычные значения, двоичные данные как `Uint8Array` (WebSocket, хранилище, телеметрия); `jsonToCbor`/`cborToJson` — JSON-совместимые значения, двоичные данные в base64, строки под ключами с `BIN` — байты (поля ввода терминала и отладки). Пакет `poe_cbor_pkt` — indefinite-массив объектов `[[TrgBusID, SrcBusID, Cmd, Payload, CRC16], …]` (CAN, RS485): `encodePacket`/`decodePacket` (разбор с начала буфера — `complete` с длиной, `incomplete` для потока или `garbage`; объекты одному адресату не склеиваются, порядок сохраняется, неверный CRC — флаг `crcOk`), `objectsFor` (свой адрес и broadcast `BROADCAST_BUS_ID = 0xFFFF`), `EXTERNAL_BUS_ID = 0x0000` — `SrcBusID` терминала и отладки, `makeCmd(header, argument, reply = true)`/`splitCmd` — `Cmd`: заголовок в битах 14-15, аргумент в битах 1-13 (0..8191), флаг ответа в бите 0 (как `CMD`/`CMD_NR` прошивки), `packetObjectCrc`; контрольные суммы `crc16Kermit` и `crc8Rohc` — строго побайтные, как в `common.c` прошивок. Байты совпадают с `poe_cbor_pkt.c` прошивки — проверка `npm run TestProtocols` (`tests/protocols.test.mjs`, эталонные пакеты собраны прошивочным кодом). Рамка xPOE-Debug (UART-консоль `system_console`, `[SOH] HDR [US] ARG [STX] VAL [ETX] CRC8 [US] FHS [EOT]`): `encodeXPoeDebugFrame` — команда устройству, `createXPoeDebugParser().push(байты)` — потоковый разбор кадров и текста вне кадров (`raw`), с проверкой CRC `crc8Rohc` строго побайтно, как `crc8_rohc` в `common.c` прошивок. CAN/CAN FD через slcan-адаптер (`can_service` прошивки): `canFragments`/`encodeCanPacket` — нарезка пакета на кадры как `CAN_Send` (бит 10 ID — «последний», биты 0..9 — `packetId`, по 8 / 64 байта), `encodeSlcanFrame`, `createCanParser().push(байты)` — разбор кадров slcan со сборкой фрагментов и обрезкой паддинга CAN FD. RS485 — сырой поток пакетов: `createPacketStreamParser().push(байты)` (пауза обрывает недособранное, мусор пропускается по байту). Открытие slcan-адаптера — `slcanOpenCommands(скорость, скоростьДанных?)`. Поле Value команды xPOE-Debug из ввода — `xPoeDebugValueFromText` (hex как есть, JSON → CBOR). Графики отладки — кадр `OK! DebPlot` (`SC_PLOT` прошивки, `DEB_PLOT_ARGUMENT`): `debPlotValues(value)` — пары `[имя, число]` из hex CBOR-карты `VALUE`, `createPlotGroups().update(пары)` раскладывает по группам (префикс до точки) в порядке карты и возвращает обновлённые группы, `data(группа)` — последние значения. Словарь протокола — `HEADER_CODES`, `DEFAULT_ARGUMENT_CODES` (генерируется из мастер-словаря `src/lib/protocols/dictionary.yaml` — `npm run Dictionary`, перед упаковкой автоматически; сам файл поставляется как `poe-svelte-ui-lib/protocols/dictionary.yaml`, `.framework/Dictionary.yaml` прошивок — его справочные копии, сборка прошивок сверяет с ними `api_cmd.h`), `parseArgumentDictionary` (строки `- [Строка, Enum, Число]`), `nameByCode`. Своих копий протоколов и словаря в приложениях не держим: терминал и отладка облака читают и пишут порт сырыми байтами, разбор и сборка — здесь.
65
65
 
66
66
  **Шапка смарт-виджета** (`WidgetHeader`): значок, заголовок и сворачивание слева, «?» в правом краю; правая часть (режимы, «Обновить» и т. п.) стоит в той же строке, а если не помещается — уходит второй строкой под заголовок и там переносится.
67
67
 
@@ -9,6 +9,7 @@
9
9
  - [Restart, A_RESTART, 1] # SET: перезагрузка устройства
10
10
  - [DefCfg, A_DEF_CONFIG, 2] # SET: сброс конфигурации к заводской
11
11
  - [DlFW, A_DOWNLOAD_FIRMWARE, 3] # SET: скачивание прошивки с сервера (http_client)
12
+ - [DebPlot, A_DEB_PLOT, 4] # OK!: значения графиков отладки — CBOR-карта {"Имя": float32} (SC_PLOT)
12
13
  - [RstNVS, A_RESET_NVS, 5] # SET: очистка NVS и перезагрузка
13
14
  - [LocTime, A_LOCAL_TIME, 6] # GET: локальное время устройства
14
15
  - [Update, A_UPDATE, 7] # OK!/ER!: обновление данных в интерфейсе (DevCloud ретранслирует DataStream)
@@ -4,6 +4,7 @@ export const DEFAULT_ARGUMENT_CODES = {
4
4
  Restart: 1,
5
5
  DefCfg: 2,
6
6
  DlFW: 3,
7
+ DebPlot: 4,
7
8
  RstNVS: 5,
8
9
  LocTime: 6,
9
10
  Update: 7,
@@ -6,7 +6,7 @@ export { CborToValue, ValueToCbor, cborToValue, valueToCbor } from "./cbor/value
6
6
  export { CborToJson, JsonToCbor, cborToJson, jsonToCbor } from "./cbor/json.js";
7
7
  export { crc16Kermit, crc8Rohc } from "./crc.js";
8
8
  export { BROADCAST_BUS_ID, makeCmd, splitCmd, EXTERNAL_BUS_ID, packetObjectCrc, encodePacket, decodePacket, objectsFor, createPacketStreamParser, type PacketObject, type DecodedPacketObject, type PacketParse, } from "./packet.js";
9
- export { createPlotGroups, type PlotPoint } from "./plotGroups.js";
9
+ export { createPlotGroups, debPlotValues, DEB_PLOT_ARGUMENT, type PlotPoint } from "./plotGroups.js";
10
10
  export { encodeXPoeDebugFrame, createXPoeDebugParser, xPoeDebugValueFromText, type XPoeDebugItem } from "./xPoeDebug.js";
11
11
  export { CAN_FINAL_BIT, CAN_PACKET_ID_MASK, canFragments, encodeSlcanFrame, encodeCanPacket, createCanParser, slcanOpenCommands, type CanFrame, type CanMessage, } from "./can.js";
12
12
  export { HEADER_CODES, DEFAULT_ARGUMENT_CODES, parseArgumentDictionary, nameByCode } from "./dictionary.js";
@@ -12,9 +12,9 @@ export { CborToJson, JsonToCbor, cborToJson, jsonToCbor } from "./cbor/json.js";
12
12
  /* Контрольные суммы и пакет poe_cbor_pkt [[TrgBusID, SrcBusID, Cmd, Payload, CRC16], …] (CAN, RS485) */
13
13
  export { crc16Kermit, crc8Rohc } from "./crc.js";
14
14
  export { BROADCAST_BUS_ID, makeCmd, splitCmd, EXTERNAL_BUS_ID, packetObjectCrc, encodePacket, decodePacket, objectsFor, createPacketStreamParser, } from "./packet.js";
15
- /* Группы графиков Teleplot (строки PLOT): серии в порядке устройства, график на группу */
16
- export { createPlotGroups } from "./plotGroups.js";
17
- /* Рамка xPOE-Debug (UART-консоль system_console): сборка команды и потоковый разбор кадров, строк Teleplot и текста */
15
+ /* Графики отладки: кадр OK! DebPlot (SC_PLOT прошивки) — значения из CBOR-карты, график на группу, серии в порядке устройства */
16
+ export { createPlotGroups, debPlotValues, DEB_PLOT_ARGUMENT } from "./plotGroups.js";
17
+ /* Рамка xPOE-Debug (UART-консоль system_console): сборка команды и потоковый разбор кадров и текста */
18
18
  export { encodeXPoeDebugFrame, createXPoeDebugParser, xPoeDebugValueFromText } from "./xPoeDebug.js";
19
19
  /* CAN/CAN FD через slcan-адаптер: нарезка пакета на кадры как в can_service прошивки, кадры slcan, потоковый разбор со сборкой фрагментов */
20
20
  export { CAN_FINAL_BIT, CAN_PACKET_ID_MASK, canFragments, encodeSlcanFrame, encodeCanPacket, createCanParser, slcanOpenCommands, } from "./can.js";
@@ -1,11 +1,11 @@
1
+ export declare const DEB_PLOT_ARGUMENT = "DebPlot";
1
2
  export interface PlotPoint {
2
3
  name: string;
3
4
  value: number;
4
5
  }
5
- export declare const createPlotGroups: ({ gapMs }?: {
6
- gapMs?: number | undefined;
7
- }) => {
8
- push(series: string, value: number, now?: number): string | null;
6
+ export declare const debPlotValues: (value: string) => [string, number][];
7
+ export declare const createPlotGroups: () => {
8
+ update(values: [string, number][]): string[];
9
9
  data(group: string): PlotPoint[];
10
10
  clear(): void;
11
11
  };
@@ -1,34 +1,44 @@
1
- export const createPlotGroups = ({ gapMs = 50 } = {}) => {
1
+ /* $lib/protocols/plotGroups.ts */
2
+ /* Графики отладки: кадр xPOE-Debug OK! DebPlot (SC_PLOT прошивки), VALUE — hex CBOR-карты {"Группа.Имя": float32, …} в порядке вызова.
3
+ График на группу — префикс имени до первой точки, без префикса — общая группа ""; серии в порядке карты, у серий, которых в кадре нет, — после них */
4
+ import { cborToValue } from "./cbor/value.js";
5
+ import { xPoeDebugValueFromText } from "./xPoeDebug.js";
6
+ export const DEB_PLOT_ARGUMENT = "DebPlot";
7
+ /* Значения графиков из VALUE кадра DebPlot (hex CBOR-карты); не карта — пустой список */
8
+ export const debPlotValues = (value) => {
9
+ try {
10
+ const decoded = cborToValue(xPoeDebugValueFromText(value));
11
+ const entries = decoded instanceof Map ? [...decoded] : decoded && typeof decoded === "object" ? Object.entries(decoded) : [];
12
+ return entries.filter((e) => typeof e[0] === "string" && typeof e[1] === "number" && Number.isFinite(e[1]));
13
+ }
14
+ catch {
15
+ return [];
16
+ }
17
+ };
18
+ export const createPlotGroups = () => {
2
19
  const groups = new Map();
3
20
  return {
4
- /* Значение серии (now — время прихода, мс); возвращает группу или null, если значение не число */
5
- push(series, value, now = Date.now()) {
6
- if (!series || !Number.isFinite(value))
7
- return null;
8
- const dot = series.indexOf(".");
9
- const group = dot > 0 ? series.slice(0, dot) : "";
10
- const name = dot > 0 ? series.slice(dot + 1) : series;
11
- let g = groups.get(group);
12
- if (!g)
13
- groups.set(group, (g = { values: new Map(), burst: [], last: now }));
14
- if (now - g.last > gapMs || g.burst.includes(name)) {
15
- const ordered = new Map();
16
- for (const n of g.burst)
17
- ordered.set(n, g.values.get(n));
18
- for (const [n, v] of g.values)
19
- if (!ordered.has(n))
20
- ordered.set(n, v);
21
- g.values = ordered;
22
- g.burst = [];
21
+ /* Значения одного кадра; возвращает группы, которые обновились */
22
+ update(values) {
23
+ const fresh = new Map();
24
+ for (const [series, value] of values) {
25
+ const dot = series.indexOf(".");
26
+ const group = dot > 0 ? series.slice(0, dot) : "";
27
+ if (!fresh.has(group))
28
+ fresh.set(group, new Map());
29
+ fresh.get(group).set(dot > 0 ? series.slice(dot + 1) : series, value);
30
+ }
31
+ for (const [group, ordered] of fresh) {
32
+ for (const [name, value] of groups.get(group) ?? [])
33
+ if (!ordered.has(name))
34
+ ordered.set(name, value);
35
+ groups.set(group, ordered);
23
36
  }
24
- g.last = now;
25
- g.burst.push(name);
26
- g.values.set(name, value);
27
- return group;
37
+ return [...fresh.keys()];
28
38
  },
29
- /* Последние значения серий группы в порядке устройства */
39
+ /* Последние значения серий группы */
30
40
  data(group) {
31
- return Array.from(groups.get(group)?.values ?? [], ([name, value]) => ({ name, value }));
41
+ return Array.from(groups.get(group) ?? [], ([name, value]) => ({ name, value }));
32
42
  },
33
43
  clear() {
34
44
  groups.clear();
@@ -12,10 +12,6 @@ export type XPoeDebugItem = {
12
12
  crc: string;
13
13
  crcOk: boolean;
14
14
  freeHeap: string;
15
- } | {
16
- type: "plot";
17
- name: string;
18
- value: string;
19
15
  } | {
20
16
  type: "raw";
21
17
  text: string;
@@ -1,7 +1,7 @@
1
1
  /* $lib/protocols/xPoeDebug.ts */
2
2
  /* Рамка xPOE-Debug (system_console прошивки): [SOH] HEADER [US] ARGUMENT [STX] VALUE [ETX] CRC8 [US] FHS [EOT] \n — CRC8 двумя hex-символами
3
3
  по HEADER+ARGUMENT+VALUE (crc8Rohc), FHS (свободная куча) только у кадров устройства. Устройство шлёт VALUE текстом (лог или hex-дамп CBOR),
4
- устройству VALUE уходит сырыми байтами CBOR. Между кадрами — текст: строки Teleplot «>Имя:Значение» (PLOT) и прочий вывод (RAW) */
4
+ устройству VALUE уходит сырыми байтами CBOR. Значения графиков — кадр OK! DebPlot (createPlotGroups). Текст между кадрами — RAW (вывод загрузчика и т.п.) */
5
5
  import { crc8Rohc } from "./crc.js";
6
6
  import { jsonToCbor } from "./cbor/json.js";
7
7
  export const SOH = 0x01;
@@ -23,16 +23,13 @@ export const encodeXPoeDebugFrame = (header, argument, value) => {
23
23
  const crc = crc8Rohc(crc8Rohc(crc8Rohc(0xff, headerBytes), argumentBytes), value);
24
24
  return new Uint8Array([SOH, ...headerBytes, US, ...argumentBytes, STX, ...value, ETX, ...encoder.encode(hex2(crc)), EOT]);
25
25
  };
26
- /* Строки текста вне кадров: Teleplot «>Имя:Значение» → plot, остальное → raw; пустые и с управляющими символами пропускаются */
26
+ /* Строки текста вне кадров → raw; пустые и с управляющими символами пропускаются */
27
27
  const textItems = (bytes) => decoder
28
28
  .decode(bytes)
29
29
  .split("\n")
30
30
  .map((line) => line.trim())
31
31
  .filter((line) => line && ![...line].some((char) => char.charCodeAt(0) < 0x20 && char !== "\t"))
32
- .map((line) => {
33
- const colon = line.indexOf(":");
34
- return line.startsWith(">") && colon > 1 ? { type: "plot", name: line.slice(1, colon), value: line.slice(colon + 1) } : { type: "raw", text: line };
35
- });
32
+ .map((line) => ({ type: "raw", text: line }));
36
33
  /* Кадр от SOH до EOT включительно; без разделителей — null (пропускается, как в прошивке и Rust-терминале) */
37
34
  const frameItem = (frame) => {
38
35
  const us = frame.indexOf(US);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.71.0",
3
+ "version": "1.72.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Oleg-Perevyshin/ElementsUI.git"