signalk-garmin-keypad-plugin 1.0.2

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/n2k.js ADDED
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildDisplaySelect = exports.buildSleepWake = exports.setFingerprint = exports.ensureCounterAbove = exports.decodeCounter = exports.resetCounters = exports.buildPageNav = exports.buildSavePreset = exports.buildSelectPreset = exports.extractGroupIdFromPayload = exports.setGroupId = void 0;
4
+ const protocol_1 = require("./protocol");
5
+ let currentGroupId = protocol_1.DEFAULT_GROUP_ID;
6
+ function setGroupId(groupId) {
7
+ currentGroupId = groupId;
8
+ }
9
+ exports.setGroupId = setGroupId;
10
+ // Group ID is at payload bytes 7-10 in both 0xe5 and 0xe7 messages.
11
+ function extractGroupIdFromPayload(payload) {
12
+ if (!payload || !Buffer.isBuffer(payload) || payload.length < 11)
13
+ return null;
14
+ const id = payload.slice(7, 11);
15
+ if (id.every(b => b === 0))
16
+ return null;
17
+ return id;
18
+ }
19
+ exports.extractGroupIdFromPayload = extractGroupIdFromPayload;
20
+ // --- PGN 61184 builders (field-based, encoded by canboatjs) ---
21
+ function buildButtonPgn(command, paramName, paramValue, src) {
22
+ return {
23
+ pgn: protocol_1.PGN_SINGLE,
24
+ dst: protocol_1.DEFAULT_DST,
25
+ prio: protocol_1.DEFAULT_PRIO,
26
+ src,
27
+ 'Manufacturer Code': 229,
28
+ 'Industry Code': 4,
29
+ 'Command': command,
30
+ 'Product ID': protocol_1.PRODUCT_ID,
31
+ 'Unknown 1': protocol_1.UNK1,
32
+ 'Unknown 2': protocol_1.UNK2,
33
+ [paramName]: paramValue
34
+ };
35
+ }
36
+ function buildSelectPreset(index, src = protocol_1.DEFAULT_SRC) {
37
+ if (!Number.isInteger(index) || index < 0 || index > 3) {
38
+ throw new Error(`Preset index must be 0-3, got ${index}`);
39
+ }
40
+ return buildButtonPgn(protocol_1.CMD_SELECT_PRESET, 'Preset Index', index, src);
41
+ }
42
+ exports.buildSelectPreset = buildSelectPreset;
43
+ function buildSavePreset(index, src = protocol_1.DEFAULT_SRC) {
44
+ if (!Number.isInteger(index) || index < 0 || index > 3) {
45
+ throw new Error(`Preset index must be 0-3, got ${index}`);
46
+ }
47
+ return buildButtonPgn(protocol_1.CMD_SAVE_PRESET, 'Preset Index', index, src);
48
+ }
49
+ exports.buildSavePreset = buildSavePreset;
50
+ function buildPageNav(direction, src = protocol_1.DEFAULT_SRC) {
51
+ const param = direction === 'next' ? 0 : 1;
52
+ return buildButtonPgn(protocol_1.CMD_PAGE_NAV, 'Direction', param, src);
53
+ }
54
+ exports.buildPageNav = buildPageNav;
55
+ // --- PGN 126720 builders (payload as pre-built Buffer) ---
56
+ // Per-property sequence counters (mimics real keypad behavior).
57
+ // Each property name maintains its own independent counter.
58
+ // Counter space is 10-bit (0-1023), wrapping at 1024.
59
+ // Bytes 5-6 encode counter C as: byte5 = 0x8e + (C & 7) * 0x10, byte6 = C >> 3.
60
+ // T6 must stay in 0x00-0x7f range (max counter 1023); displays silently
61
+ // reject messages with T6 >= 0x80.
62
+ const propertyCounters = new Map();
63
+ const MAX_SEQ = 0x3FF; // 1023 — maximum valid counter value
64
+ function resetCounters() {
65
+ propertyCounters.clear();
66
+ }
67
+ exports.resetCounters = resetCounters;
68
+ function decodeCounter(t5, t6) {
69
+ return (t6 << 3) | ((t5 - 0x8e) >> 4);
70
+ }
71
+ exports.decodeCounter = decodeCounter;
72
+ // Next buildTrailing call will send (stored + 1) & MAX_SEQ.
73
+ function ensureCounterAbove(property, minSeq) {
74
+ var _a;
75
+ const current = (_a = propertyCounters.get(property)) !== null && _a !== void 0 ? _a : -1;
76
+ const clamped = minSeq & MAX_SEQ;
77
+ if (current < clamped) {
78
+ propertyCounters.set(property, clamped);
79
+ }
80
+ }
81
+ exports.ensureCounterAbove = ensureCounterAbove;
82
+ // Keypad fingerprint bytes — must match the fingerprint stored on the GNX
83
+ // displays for the property being set. Displays persist the fingerprint of
84
+ // the last keypad that successfully changed each property and reject commands
85
+ // from a different fingerprint. Auto-discovered from bus traffic or set
86
+ // manually via config.
87
+ let keypadFingerprint = null;
88
+ function setFingerprint(fp) {
89
+ keypadFingerprint = fp;
90
+ }
91
+ exports.setFingerprint = setFingerprint;
92
+ function buildTrailing(property) {
93
+ var _a, _b, _c;
94
+ const prev = (_a = propertyCounters.get(property)) !== null && _a !== void 0 ? _a : -1;
95
+ const seq = (prev + 1) & MAX_SEQ;
96
+ propertyCounters.set(property, seq);
97
+ const buf = Buffer.alloc(7);
98
+ buf[0] = 0x2e;
99
+ buf[1] = 0x80 | (Math.random() * 128 | 0); // T1: random nonce, bit 7 must be set or displays reject
100
+ buf[2] = 0xb0; // T2: 1-bit state flag — 0xb0 is safe constant
101
+ buf[3] = (_b = keypadFingerprint === null || keypadFingerprint === void 0 ? void 0 : keypadFingerprint[0]) !== null && _b !== void 0 ? _b : 0; // T3: keypad fingerprint byte 1
102
+ buf[4] = (_c = keypadFingerprint === null || keypadFingerprint === void 0 ? void 0 : keypadFingerprint[1]) !== null && _c !== void 0 ? _c : 0; // T4: keypad fingerprint byte 2
103
+ buf[5] = 0x8e + (seq & 7) * 0x10; // T5: counter low bits
104
+ buf[6] = (seq >> 3) & 0x7f; // T6: counter high bits (must be 0x00-0x7f)
105
+ return buf;
106
+ }
107
+ function buildPropertyPayload(property, value) {
108
+ const strLen = property.length + 1;
109
+ const strBuf = Buffer.from(property + '\0', 'ascii');
110
+ const valueBuf = Buffer.from([value]);
111
+ // Skip first byte of header (command byte 0xe5) — canboatjs writes it from PGN Match
112
+ return Buffer.concat([
113
+ (0, protocol_1.buildPropertyHeader)(currentGroupId).slice(1),
114
+ Buffer.from([strLen]),
115
+ strBuf,
116
+ protocol_1.PROPERTY_SEPARATOR,
117
+ valueBuf,
118
+ buildTrailing(property)
119
+ ]);
120
+ }
121
+ function buildPropertyPgn(property, value, src) {
122
+ return {
123
+ pgn: protocol_1.PGN_FAST,
124
+ dst: protocol_1.DEFAULT_DST,
125
+ prio: protocol_1.DEFAULT_PRIO,
126
+ src,
127
+ 'Manufacturer Code': 229,
128
+ 'Industry Code': 4,
129
+ 'Command': 0xe5,
130
+ 'Payload': buildPropertyPayload(property, value)
131
+ };
132
+ }
133
+ function buildSleepWake(sleep, src = protocol_1.DEFAULT_SRC) {
134
+ return buildPropertyPgn(protocol_1.PROP_SLEEP, sleep ? protocol_1.SLEEP : protocol_1.WAKE, src);
135
+ }
136
+ exports.buildSleepWake = buildSleepWake;
137
+ function buildDisplaySelect(index, src = protocol_1.DEFAULT_SRC) {
138
+ if (!Number.isInteger(index) || index < 0) {
139
+ throw new Error(`Display index must be a non-negative integer, got ${index}`);
140
+ }
141
+ return buildPropertyPgn(protocol_1.PROP_DISPLAY, index, src);
142
+ }
143
+ exports.buildDisplaySelect = buildDisplaySelect;
package/dist/pgns.d.ts ADDED
@@ -0,0 +1,169 @@
1
+ export const PGNs: ({
2
+ PGN: number;
3
+ Id: string;
4
+ Description: string;
5
+ Type: string;
6
+ Complete: boolean;
7
+ Length: number;
8
+ Fields: ({
9
+ Order: number;
10
+ Id: string;
11
+ Name: string;
12
+ BitLength: number;
13
+ BitOffset: number;
14
+ BitStart: number;
15
+ Match: number;
16
+ FieldType: string;
17
+ LookupEnumeration: string;
18
+ Signed: boolean;
19
+ Resolution?: undefined;
20
+ } | {
21
+ Order: number;
22
+ Id: string;
23
+ Name: string;
24
+ BitLength: number;
25
+ BitOffset: number;
26
+ BitStart: number;
27
+ FieldType: string;
28
+ Match?: undefined;
29
+ LookupEnumeration?: undefined;
30
+ Signed?: undefined;
31
+ Resolution?: undefined;
32
+ } | {
33
+ Order: number;
34
+ Id: string;
35
+ Name: string;
36
+ BitLength: number;
37
+ BitOffset: number;
38
+ BitStart: number;
39
+ FieldType: string;
40
+ Resolution: number;
41
+ Signed: boolean;
42
+ Match: number;
43
+ LookupEnumeration?: undefined;
44
+ } | {
45
+ Order: number;
46
+ Id: string;
47
+ Name: string;
48
+ BitLength: number;
49
+ BitOffset: number;
50
+ BitStart: number;
51
+ FieldType: string;
52
+ Resolution: number;
53
+ Signed: boolean;
54
+ Match?: undefined;
55
+ LookupEnumeration?: undefined;
56
+ })[];
57
+ } | {
58
+ PGN: number;
59
+ Id: string;
60
+ Description: string;
61
+ Type: string;
62
+ Complete: boolean;
63
+ Fields: ({
64
+ Order: number;
65
+ Id: string;
66
+ Name: string;
67
+ BitLength: number;
68
+ BitOffset: number;
69
+ BitStart: number;
70
+ Match: number;
71
+ FieldType: string;
72
+ LookupEnumeration: string;
73
+ Signed: boolean;
74
+ Resolution?: undefined;
75
+ } | {
76
+ Order: number;
77
+ Id: string;
78
+ Name: string;
79
+ BitLength: number;
80
+ BitOffset: number;
81
+ BitStart: number;
82
+ FieldType: string;
83
+ Match?: undefined;
84
+ LookupEnumeration?: undefined;
85
+ Signed?: undefined;
86
+ Resolution?: undefined;
87
+ } | {
88
+ Order: number;
89
+ Id: string;
90
+ Name: string;
91
+ BitLength: number;
92
+ BitOffset: number;
93
+ BitStart: number;
94
+ FieldType: string;
95
+ Resolution: number;
96
+ Signed: boolean;
97
+ Match: number;
98
+ LookupEnumeration?: undefined;
99
+ } | {
100
+ Order: number;
101
+ Id: string;
102
+ Name: string;
103
+ BitLength: number;
104
+ BitOffset: number;
105
+ BitStart: number;
106
+ FieldType: string;
107
+ Signed: boolean;
108
+ Match?: undefined;
109
+ LookupEnumeration?: undefined;
110
+ Resolution?: undefined;
111
+ })[];
112
+ Length?: undefined;
113
+ } | {
114
+ PGN: number;
115
+ Id: string;
116
+ Description: string;
117
+ Type: string;
118
+ Complete: boolean;
119
+ Length: number;
120
+ Fields: ({
121
+ Order: number;
122
+ Id: string;
123
+ Name: string;
124
+ BitLength: number;
125
+ BitOffset: number;
126
+ BitStart: number;
127
+ Match: number;
128
+ FieldType: string;
129
+ LookupEnumeration: string;
130
+ Signed: boolean;
131
+ Resolution?: undefined;
132
+ } | {
133
+ Order: number;
134
+ Id: string;
135
+ Name: string;
136
+ BitLength: number;
137
+ BitOffset: number;
138
+ BitStart: number;
139
+ FieldType: string;
140
+ Match?: undefined;
141
+ LookupEnumeration?: undefined;
142
+ Signed?: undefined;
143
+ Resolution?: undefined;
144
+ } | {
145
+ Order: number;
146
+ Id: string;
147
+ Name: string;
148
+ BitLength: number;
149
+ BitOffset: number;
150
+ BitStart: number;
151
+ FieldType: string;
152
+ Resolution: number;
153
+ Signed: boolean;
154
+ Match: number;
155
+ LookupEnumeration?: undefined;
156
+ } | {
157
+ Order: number;
158
+ Id: string;
159
+ Name: string;
160
+ BitLength: number;
161
+ BitOffset: number;
162
+ BitStart: number;
163
+ FieldType: string;
164
+ Signed: boolean;
165
+ Match?: undefined;
166
+ LookupEnumeration?: undefined;
167
+ Resolution?: undefined;
168
+ })[];
169
+ })[];