webserial-flasher 1.0.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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/autoDetect.d.ts +24 -0
  4. package/dist/autoDetect.d.ts.map +1 -0
  5. package/dist/autoDetect.js +66 -0
  6. package/dist/autoDetect.js.map +1 -0
  7. package/dist/boards/database.d.ts +17 -0
  8. package/dist/boards/database.d.ts.map +1 -0
  9. package/dist/boards/database.js +957 -0
  10. package/dist/boards/database.js.map +1 -0
  11. package/dist/core/constants.d.ts +44 -0
  12. package/dist/core/constants.d.ts.map +1 -0
  13. package/dist/core/constants.js +56 -0
  14. package/dist/core/constants.js.map +1 -0
  15. package/dist/core/errors.d.ts +45 -0
  16. package/dist/core/errors.d.ts.map +1 -0
  17. package/dist/core/errors.js +92 -0
  18. package/dist/core/errors.js.map +1 -0
  19. package/dist/core/types.d.ts +138 -0
  20. package/dist/core/types.d.ts.map +1 -0
  21. package/dist/core/types.js +3 -0
  22. package/dist/core/types.js.map +1 -0
  23. package/dist/index.d.ts +24 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +25 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/protocol/avr109/programmer.d.ts +78 -0
  28. package/dist/protocol/avr109/programmer.d.ts.map +1 -0
  29. package/dist/protocol/avr109/programmer.js +324 -0
  30. package/dist/protocol/avr109/programmer.js.map +1 -0
  31. package/dist/protocol/hexParser.d.ts +12 -0
  32. package/dist/protocol/hexParser.d.ts.map +1 -0
  33. package/dist/protocol/hexParser.js +133 -0
  34. package/dist/protocol/hexParser.js.map +1 -0
  35. package/dist/protocol/picoboot/constants.d.ts +65 -0
  36. package/dist/protocol/picoboot/constants.d.ts.map +1 -0
  37. package/dist/protocol/picoboot/constants.js +80 -0
  38. package/dist/protocol/picoboot/constants.js.map +1 -0
  39. package/dist/protocol/picoboot/programmer.d.ts +73 -0
  40. package/dist/protocol/picoboot/programmer.d.ts.map +1 -0
  41. package/dist/protocol/picoboot/programmer.js +278 -0
  42. package/dist/protocol/picoboot/programmer.js.map +1 -0
  43. package/dist/protocol/picoboot/uf2.d.ts +51 -0
  44. package/dist/protocol/picoboot/uf2.d.ts.map +1 -0
  45. package/dist/protocol/picoboot/uf2.js +119 -0
  46. package/dist/protocol/picoboot/uf2.js.map +1 -0
  47. package/dist/protocol/receiveData.d.ts +3 -0
  48. package/dist/protocol/receiveData.d.ts.map +1 -0
  49. package/dist/protocol/receiveData.js +72 -0
  50. package/dist/protocol/receiveData.js.map +1 -0
  51. package/dist/protocol/sendCommand.d.ts +14 -0
  52. package/dist/protocol/sendCommand.d.ts.map +1 -0
  53. package/dist/protocol/sendCommand.js +48 -0
  54. package/dist/protocol/sendCommand.js.map +1 -0
  55. package/dist/protocol/stk500v2/constants.d.ts +57 -0
  56. package/dist/protocol/stk500v2/constants.d.ts.map +1 -0
  57. package/dist/protocol/stk500v2/constants.js +62 -0
  58. package/dist/protocol/stk500v2/constants.js.map +1 -0
  59. package/dist/protocol/stk500v2/frame.d.ts +14 -0
  60. package/dist/protocol/stk500v2/frame.d.ts.map +1 -0
  61. package/dist/protocol/stk500v2/frame.js +116 -0
  62. package/dist/protocol/stk500v2/frame.js.map +1 -0
  63. package/dist/protocol/stk500v2/programmer.d.ts +92 -0
  64. package/dist/protocol/stk500v2/programmer.d.ts.map +1 -0
  65. package/dist/protocol/stk500v2/programmer.js +482 -0
  66. package/dist/protocol/stk500v2/programmer.js.map +1 -0
  67. package/dist/protocol/updi/constants.d.ts +107 -0
  68. package/dist/protocol/updi/constants.d.ts.map +1 -0
  69. package/dist/protocol/updi/constants.js +130 -0
  70. package/dist/protocol/updi/constants.js.map +1 -0
  71. package/dist/protocol/updi/link.d.ts +82 -0
  72. package/dist/protocol/updi/link.d.ts.map +1 -0
  73. package/dist/protocol/updi/link.js +241 -0
  74. package/dist/protocol/updi/link.js.map +1 -0
  75. package/dist/protocol/updi/programmer.d.ts +89 -0
  76. package/dist/protocol/updi/programmer.d.ts.map +1 -0
  77. package/dist/protocol/updi/programmer.js +359 -0
  78. package/dist/protocol/updi/programmer.js.map +1 -0
  79. package/dist/stk500.d.ts +101 -0
  80. package/dist/stk500.d.ts.map +1 -0
  81. package/dist/stk500.js +426 -0
  82. package/dist/stk500.js.map +1 -0
  83. package/dist/transport/IPicobootTransport.d.ts +25 -0
  84. package/dist/transport/IPicobootTransport.d.ts.map +1 -0
  85. package/dist/transport/IPicobootTransport.js +10 -0
  86. package/dist/transport/IPicobootTransport.js.map +1 -0
  87. package/dist/transport/ITransport.d.ts +33 -0
  88. package/dist/transport/ITransport.d.ts.map +1 -0
  89. package/dist/transport/ITransport.js +4 -0
  90. package/dist/transport/ITransport.js.map +1 -0
  91. package/dist/transport/NodeSerialTransport.d.ts +35 -0
  92. package/dist/transport/NodeSerialTransport.d.ts.map +1 -0
  93. package/dist/transport/NodeSerialTransport.js +102 -0
  94. package/dist/transport/NodeSerialTransport.js.map +1 -0
  95. package/dist/transport/NodeUSBTransport.d.ts +24 -0
  96. package/dist/transport/NodeUSBTransport.d.ts.map +1 -0
  97. package/dist/transport/NodeUSBTransport.js +146 -0
  98. package/dist/transport/NodeUSBTransport.js.map +1 -0
  99. package/dist/transport/WebSerialTransport.d.ts +63 -0
  100. package/dist/transport/WebSerialTransport.d.ts.map +1 -0
  101. package/dist/transport/WebSerialTransport.js +159 -0
  102. package/dist/transport/WebSerialTransport.js.map +1 -0
  103. package/package.json +79 -0
package/dist/stk500.js ADDED
@@ -0,0 +1,426 @@
1
+ // STK500v1 programmer — main class.
2
+ //
3
+ // Full rewrite addressing:
4
+ // - DTR/RTS reset before sync (bootloader entry)
5
+ // - Chip erase before programming
6
+ // - Real verify (readback + byte comparison, not echo validation)
7
+ // - Complete setOptions (all 20 SET_DEVICE parameters)
8
+ // - Typed errors (STK500SyncError, STK500SignatureMismatchError, etc.)
9
+ // - Retry with configurable backoff
10
+ // - Transport abstraction (Node.js SerialPort or WebSerial)
11
+ // - Levelled logging (debug / info / warn / error)
12
+ import Constants from './core/constants.js';
13
+ import { STK500SyncError, STK500SignatureMismatchError, STK500VerifyError, STK500ProtocolError, STK500InvalidHexError, } from './core/errors.js';
14
+ import sendCommand from './protocol/sendCommand.js';
15
+ import { parseIntelHex } from './protocol/hexParser.js';
16
+ function sleep(ms) {
17
+ return new Promise((resolve) => setTimeout(resolve, ms));
18
+ }
19
+ export class STK500 {
20
+ constructor(transport, board, opts = {}) {
21
+ this.transport = transport;
22
+ this.board = board;
23
+ this.syncAttempts = opts.retry?.syncAttempts ?? 5;
24
+ this.retryDelayMs = opts.retry?.retryDelayMs ?? 200;
25
+ if (opts.quiet) {
26
+ this.log = () => { };
27
+ }
28
+ else if (opts.logger) {
29
+ this.log = opts.logger;
30
+ }
31
+ else {
32
+ this.log = (level, msg) => {
33
+ /* istanbul ignore next */
34
+ if (typeof console !== 'undefined') {
35
+ console.log(`[webserial-flasher] [${level}] ${msg}`);
36
+ }
37
+ };
38
+ }
39
+ }
40
+ // ─── Reset ────────────────────────────────────────────────────────────────
41
+ /**
42
+ * Toggle DTR or RTS to force the Arduino into bootloader mode.
43
+ * Skipped automatically when board.resetMethod === 'none' or when
44
+ * the transport does not implement setSignals().
45
+ */
46
+ async resetDevice() {
47
+ const method = this.board.resetMethod ?? 'dtr';
48
+ const delay = this.board.resetDelayMs ?? 200;
49
+ if (method === 'none') {
50
+ this.log('debug', 'resetDevice: skipped (resetMethod=none)');
51
+ return;
52
+ }
53
+ if (!this.transport.setSignals) {
54
+ this.log('debug', 'resetDevice: transport has no setSignals() — skipping');
55
+ return;
56
+ }
57
+ this.log('info', `resetDevice: toggling ${method.toUpperCase()}`);
58
+ const low = method === 'dtr' ? { dtr: false } : { rts: false };
59
+ const high = method === 'dtr' ? { dtr: true } : { rts: true };
60
+ await this.transport.setSignals(low);
61
+ await sleep(delay);
62
+ await this.transport.setSignals(high);
63
+ await sleep(delay); // Give bootloader time to start listening
64
+ }
65
+ // ─── Sync ─────────────────────────────────────────────────────────────────
66
+ /**
67
+ * Send GET_SYNC up to `attempts` times.
68
+ * Throws STK500SyncError if all attempts fail.
69
+ */
70
+ async sync(attempts) {
71
+ this.log('debug', `sync (max ${attempts} attempts)`);
72
+ for (let i = 1; i <= attempts; i++) {
73
+ try {
74
+ const data = await sendCommand(this.transport, {
75
+ cmd: [Constants.Cmnd_STK_GET_SYNC],
76
+ responseData: Constants.OK_RESPONSE,
77
+ timeout: this.board.timeout,
78
+ });
79
+ this.log('debug', `sync OK on attempt ${i}`);
80
+ return data;
81
+ }
82
+ catch (err) {
83
+ this.log('debug', `sync attempt ${i}/${attempts} failed: ${err instanceof Error ? err.message : String(err)}`);
84
+ if (i < attempts)
85
+ await sleep(this.retryDelayMs);
86
+ }
87
+ }
88
+ throw new STK500SyncError(attempts);
89
+ }
90
+ // ─── Signature ────────────────────────────────────────────────────────────
91
+ /**
92
+ * Read the device signature and verify it matches board.signature.
93
+ * Throws STK500SignatureMismatchError when wrong board type is selected.
94
+ */
95
+ async verifySignature() {
96
+ this.log('debug', 'verifySignature');
97
+ // Response: [INSYNC, sig0, sig1, sig2, OK] = 5 bytes
98
+ const data = await sendCommand(this.transport, {
99
+ cmd: [Constants.Cmnd_STK_READ_SIGN],
100
+ responseLength: 5,
101
+ timeout: this.board.timeout,
102
+ });
103
+ const actual = data.subarray(1, 4); // Strip INSYNC and OK framing
104
+ const expected = this.board.signature;
105
+ if (!actual.every((b, i) => b === expected[i])) {
106
+ throw new STK500SignatureMismatchError(expected, actual);
107
+ }
108
+ const fmt = (b) => Array.from(b).map((x) => `0x${x.toString(16).padStart(2, '0')}`).join(', ');
109
+ this.log('info', `signature verified: [${fmt(actual)}]`);
110
+ return data;
111
+ }
112
+ /**
113
+ * Read the raw device signature without matching against a board.
114
+ * Useful for auto-detecting the board type.
115
+ */
116
+ async getSignature() {
117
+ this.log('debug', 'getSignature');
118
+ const data = await sendCommand(this.transport, {
119
+ cmd: [Constants.Cmnd_STK_READ_SIGN],
120
+ responseLength: 5,
121
+ timeout: this.board.timeout,
122
+ });
123
+ return data.subarray(1, 4);
124
+ }
125
+ // ─── Device Configuration ─────────────────────────────────────────────────
126
+ /**
127
+ * Send SET_DEVICE with full 20-parameter configuration.
128
+ * Merges board defaults with any override values passed in `options`.
129
+ * Previously sent only 2 of the required 20 parameters — now complete.
130
+ */
131
+ async setOptions(options = {}) {
132
+ this.log('debug', 'setOptions');
133
+ const b = this.board;
134
+ const o = options;
135
+ await sendCommand(this.transport, {
136
+ cmd: [
137
+ Constants.Cmnd_STK_SET_DEVICE,
138
+ o['devicecode'] ?? b.deviceCode ?? 0,
139
+ o['revision'] ?? 0,
140
+ o['progtype'] ?? b.progType ?? 0,
141
+ o['parmode'] ?? b.parMode ?? 0,
142
+ o['polling'] ?? b.polling ?? 0,
143
+ o['selftimed'] ?? b.selfTimed ?? 0,
144
+ o['lockbytes'] ?? b.lockBytes ?? 0,
145
+ o['fusebytes'] ?? b.fuseBytes ?? 0,
146
+ o['flashpollval1'] ?? b.flashPollVal1 ?? 0xff,
147
+ o['flashpollval2'] ?? b.flashPollVal2 ?? 0xff,
148
+ o['eeprompollval1'] ?? b.eepromPollVal1 ?? 0xff,
149
+ o['eeprompollval2'] ?? b.eepromPollVal2 ?? 0xff,
150
+ // Page size as two bytes (high, low)
151
+ (b.pageSize >> 8) & 0xff,
152
+ b.pageSize & 0xff,
153
+ // EEPROM size as two bytes
154
+ ((b.eepromSize ?? 0) >> 8) & 0xff,
155
+ (b.eepromSize ?? 0) & 0xff,
156
+ // Flash size as four bytes (MSB first)
157
+ ((b.flashSize ?? 0) >> 24) & 0xff,
158
+ ((b.flashSize ?? 0) >> 16) & 0xff,
159
+ ((b.flashSize ?? 0) >> 8) & 0xff,
160
+ (b.flashSize ?? 0) & 0xff,
161
+ ],
162
+ responseData: Constants.OK_RESPONSE,
163
+ timeout: this.board.timeout,
164
+ });
165
+ }
166
+ // ─── Programming Mode ─────────────────────────────────────────────────────
167
+ async enterProgrammingMode() {
168
+ this.log('debug', 'enterProgrammingMode');
169
+ return sendCommand(this.transport, {
170
+ cmd: [Constants.Cmnd_STK_ENTER_PROGMODE],
171
+ responseData: Constants.OK_RESPONSE,
172
+ timeout: this.board.timeout,
173
+ });
174
+ }
175
+ async exitProgrammingMode() {
176
+ this.log('debug', 'exitProgrammingMode');
177
+ return sendCommand(this.transport, {
178
+ cmd: [Constants.Cmnd_STK_LEAVE_PROGMODE],
179
+ responseData: Constants.OK_RESPONSE,
180
+ timeout: this.board.timeout,
181
+ });
182
+ }
183
+ // ─── Erase ────────────────────────────────────────────────────────────────
184
+ /** Erase the entire flash. Must be called before programming. */
185
+ async chipErase() {
186
+ this.log('info', 'chipErase');
187
+ await sendCommand(this.transport, {
188
+ cmd: [Constants.Cmnd_STK_CHIP_ERASE],
189
+ responseData: Constants.OK_RESPONSE,
190
+ timeout: this.board.timeout,
191
+ });
192
+ await sleep(this.board.eraseDelayMs ?? 10);
193
+ }
194
+ // ─── Address / Page Helpers ───────────────────────────────────────────────
195
+ async loadAddress(useaddr) {
196
+ return sendCommand(this.transport, {
197
+ cmd: [Constants.Cmnd_STK_LOAD_ADDRESS, useaddr & 0xff, (useaddr >> 8) & 0xff],
198
+ responseData: Constants.OK_RESPONSE,
199
+ timeout: this.board.timeout,
200
+ });
201
+ }
202
+ async loadPage(writeBytes) {
203
+ if (writeBytes.length > this.board.pageSize) {
204
+ throw new STK500ProtocolError(`loadPage: ${writeBytes.length} bytes exceeds page size ${this.board.pageSize}`);
205
+ }
206
+ // Command: [CMND, size_high, size_low, 'F'(0x46=Flash), ...data..., CRC_EOP]
207
+ const cmd = new Uint8Array([
208
+ Constants.Cmnd_STK_PROG_PAGE,
209
+ (writeBytes.length >> 8) & 0xff,
210
+ writeBytes.length & 0xff,
211
+ 0x46, // 'F' = Flash
212
+ ...writeBytes,
213
+ Constants.Sync_CRC_EOP,
214
+ ]);
215
+ return sendCommand(this.transport, {
216
+ cmd,
217
+ responseData: Constants.OK_RESPONSE,
218
+ timeout: this.board.timeout,
219
+ });
220
+ }
221
+ /**
222
+ * Read one page from device flash.
223
+ * Returns only the data bytes (INSYNC/OK framing stripped).
224
+ */
225
+ async readPage(wordAddr, size) {
226
+ await this.loadAddress(wordAddr);
227
+ // Response: [INSYNC, ...size data bytes..., OK] = size + 2
228
+ const response = await sendCommand(this.transport, {
229
+ cmd: [
230
+ Constants.Cmnd_STK_READ_PAGE,
231
+ (size >> 8) & 0xff,
232
+ size & 0xff,
233
+ 0x46, // 'F' = Flash
234
+ ],
235
+ responseLength: size + 2,
236
+ timeout: this.board.timeout,
237
+ });
238
+ return response.subarray(1, size + 1);
239
+ }
240
+ // ─── Universal SPI (fuse / lock bit access) ───────────────────────────────
241
+ /**
242
+ * Issue a raw 4-byte SPI command via the STK500v1 UNIVERSAL command (0x56).
243
+ * Returns the 4th byte of the SPI response, which is the data byte.
244
+ *
245
+ * Example: await stk.universalSpi([0x50, 0x00, 0x00, 0x00]) → low fuse byte
246
+ */
247
+ async universalSpi(spiCmd) {
248
+ const response = await sendCommand(this.transport, {
249
+ cmd: [Constants.Cmnd_STK_UNIVERSAL, ...spiCmd],
250
+ responseLength: 6, // [INSYNC, r0, r1, r2, r3, OK]
251
+ timeout: this.board.timeout,
252
+ });
253
+ return response[4] ?? 0; // 4th SPI response byte
254
+ }
255
+ /**
256
+ * Read all fuse bytes via SPI UNIVERSAL commands.
257
+ * Returns { low, high, ext, lock } fuse values.
258
+ */
259
+ async readFuses() {
260
+ this.log('debug', 'readFuses');
261
+ const low = await this.universalSpi([0x50, 0x00, 0x00, 0x00]);
262
+ const high = await this.universalSpi([0x58, 0x08, 0x00, 0x00]);
263
+ const ext = await this.universalSpi([0x50, 0x08, 0x00, 0x00]);
264
+ const lock = await this.universalSpi([0x58, 0x00, 0x00, 0x00]);
265
+ this.log('info', `fuses: low=0x${low.toString(16)} high=0x${high.toString(16)} ext=0x${ext.toString(16)} lock=0x${lock.toString(16)}`);
266
+ return { low, high, ext, lock };
267
+ }
268
+ /**
269
+ * Write fuse bytes via SPI UNIVERSAL commands.
270
+ * @param fuse Which fuse to write: 'low' | 'high' | 'ext' | 'lock'
271
+ * @param val New fuse value
272
+ */
273
+ async writeFuse(fuse, val) {
274
+ this.log('debug', `writeFuse: ${fuse}=0x${val.toString(16)}`);
275
+ const cmds = {
276
+ low: [0xAC, 0xA0, 0x00, val],
277
+ high: [0xAC, 0xA8, 0x00, val],
278
+ ext: [0xAC, 0xA4, 0x00, val],
279
+ lock: [0xAC, 0xE0, 0x00, val],
280
+ };
281
+ await this.universalSpi(cmds[fuse]);
282
+ await sleep(10); // fuse write delay
283
+ }
284
+ /**
285
+ * Write one EEPROM page.
286
+ * @param byteAddr Byte address in EEPROM (NOT word address)
287
+ * @param data Data to write (length ≤ board.pageSize)
288
+ */
289
+ async writeEepromPage(byteAddr, data) {
290
+ // EEPROM uses byte addresses and memType 'E' (0x45)
291
+ const addrForLoad = this.board.use8BitAddresses ? byteAddr : byteAddr >> 1;
292
+ await this.loadAddress(addrForLoad);
293
+ const cmd = new Uint8Array([
294
+ Constants.Cmnd_STK_PROG_PAGE,
295
+ (data.length >> 8) & 0xff,
296
+ data.length & 0xff,
297
+ 0x45, // 'E' = EEPROM
298
+ ...data,
299
+ Constants.Sync_CRC_EOP,
300
+ ]);
301
+ await sendCommand(this.transport, {
302
+ cmd,
303
+ responseData: Constants.OK_RESPONSE,
304
+ timeout: this.board.timeout,
305
+ });
306
+ }
307
+ /**
308
+ * Read one EEPROM page.
309
+ * @param byteAddr Byte address in EEPROM
310
+ * @param size Number of bytes to read
311
+ */
312
+ async readEepromPage(byteAddr, size) {
313
+ const addrForLoad = this.board.use8BitAddresses ? byteAddr : byteAddr >> 1;
314
+ await this.loadAddress(addrForLoad);
315
+ const response = await sendCommand(this.transport, {
316
+ cmd: [
317
+ Constants.Cmnd_STK_READ_PAGE,
318
+ (size >> 8) & 0xff,
319
+ size & 0xff,
320
+ 0x45, // 'E' = EEPROM
321
+ ],
322
+ responseLength: size + 2,
323
+ timeout: this.board.timeout,
324
+ });
325
+ return response.subarray(1, size + 1);
326
+ }
327
+ // ─── Upload ───────────────────────────────────────────────────────────────
328
+ async upload(hexData, progressCallback) {
329
+ this.log('info', 'upload: parsing HEX');
330
+ const { data: hex, byteCount } = parseIntelHex(hexData);
331
+ this.log('info', `upload: ${byteCount} bytes to write`);
332
+ // Phase G: HEX size validation
333
+ if (this.board.flashSize && byteCount > this.board.flashSize) {
334
+ throw new STK500InvalidHexError(`HEX too large: ${byteCount} bytes exceeds flash size ${this.board.flashSize} bytes`);
335
+ }
336
+ let pageaddr = 0;
337
+ while (pageaddr < hex.length) {
338
+ const useaddr = this.board.use8BitAddresses ? pageaddr : pageaddr >> 1;
339
+ const chunkSize = Math.min(this.board.pageSize, hex.length - pageaddr);
340
+ const chunk = hex.subarray(pageaddr, pageaddr + chunkSize);
341
+ await this.loadAddress(useaddr);
342
+ await this.loadPage(chunk);
343
+ pageaddr += chunkSize;
344
+ await sleep(4); // Brief yield — device writes the page to flash
345
+ progressCallback?.((pageaddr / hex.length) * 100);
346
+ }
347
+ this.log('info', 'upload complete');
348
+ }
349
+ // ─── Verify ───────────────────────────────────────────────────────────────
350
+ /**
351
+ * Read back flash and compare byte-by-byte against the HEX source.
352
+ *
353
+ * Fixed vs original: the original sent READ_PAGE but discarded the response,
354
+ * making verify() a no-op. This version actually reads and compares.
355
+ */
356
+ async verify(hexData, progressCallback) {
357
+ this.log('info', 'verify: parsing HEX');
358
+ const { data: hex, byteCount } = parseIntelHex(hexData);
359
+ this.log('info', `verify: checking ${byteCount} bytes`);
360
+ let pageaddr = 0;
361
+ while (pageaddr < hex.length) {
362
+ const useaddr = this.board.use8BitAddresses ? pageaddr : pageaddr >> 1;
363
+ const chunkSize = Math.min(this.board.pageSize, hex.length - pageaddr);
364
+ const expected = hex.subarray(pageaddr, pageaddr + chunkSize);
365
+ const actual = await this.readPage(useaddr, chunkSize);
366
+ for (let i = 0; i < chunkSize; i++) {
367
+ if (actual[i] !== expected[i]) {
368
+ throw new STK500VerifyError(pageaddr + i, expected[i], actual[i]);
369
+ }
370
+ }
371
+ pageaddr += chunkSize;
372
+ await sleep(4);
373
+ progressCallback?.((pageaddr / hex.length) * 100);
374
+ }
375
+ this.log('info', 'verify OK — flash matches HEX');
376
+ }
377
+ // ─── bootload (main entry point) ──────────────────────────────────────────
378
+ /**
379
+ * Complete programming sequence:
380
+ * reset → sync → verify signature → configure device →
381
+ * enter prog mode → erase chip → upload → verify → exit prog mode
382
+ *
383
+ * @param hexData Intel HEX string or binary
384
+ * @param progressCallback Called with (status, 0–100) at each stage
385
+ */
386
+ async bootload(hexData, progressCallback) {
387
+ const progress = (status, pct) => {
388
+ this.log('info', `${status} (${Math.round(pct)}%)`);
389
+ progressCallback?.(status, pct);
390
+ };
391
+ // 1 ── Reset device so bootloader is listening
392
+ progress('Resetting device', 0);
393
+ await this.resetDevice();
394
+ // 2 ── Sync: retry several times — bootloader may need a moment
395
+ progress('Syncing', 5);
396
+ await this.sync(this.syncAttempts);
397
+ await this.sync(3); // Second sync for reliability
398
+ // 3 ── Confirm we're talking to the expected chip
399
+ progress('Verifying signature', 15);
400
+ await this.verifySignature();
401
+ // 4 ── Send device parameters
402
+ progress('Configuring device', 20);
403
+ await this.setOptions();
404
+ // 5 ── Enter programming mode
405
+ progress('Entering programming mode', 25);
406
+ await this.enterProgrammingMode();
407
+ // 6 ── Erase flash before writing
408
+ progress('Erasing chip', 30);
409
+ await this.chipErase();
410
+ // 7 ── Write firmware (35 → 75%)
411
+ progress('Uploading', 35);
412
+ await this.upload(hexData, (pct) => {
413
+ progress('Uploading', 35 + pct * 0.40);
414
+ });
415
+ // 8 ── Read back and verify (75 → 95%)
416
+ progress('Verifying', 75);
417
+ await this.verify(hexData, (pct) => {
418
+ progress('Verifying', 75 + pct * 0.20);
419
+ });
420
+ // 9 ── Exit programming mode — board resets and runs new firmware
421
+ progress('Exiting programming mode', 95);
422
+ await this.exitProgrammingMode();
423
+ progress('Complete', 100);
424
+ }
425
+ }
426
+ //# sourceMappingURL=stk500.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stk500.js","sourceRoot":"","sources":["../src/stk500.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface IPicobootTransport {
2
+ /**
3
+ * Send a 32-byte PICOBOOT command packet to the USB OUT endpoint.
4
+ * Must be called before any data phase.
5
+ */
6
+ sendCommand(cmd: Uint8Array): Promise<void>;
7
+ /**
8
+ * Read up to `maxLength` bytes from the USB IN endpoint.
9
+ * Used for both data reads (READ command) and status responses.
10
+ */
11
+ receiveBytes(maxLength: number): Promise<Uint8Array>;
12
+ /**
13
+ * Send raw bytes to the USB OUT endpoint.
14
+ * Used for the data phase of a WRITE command.
15
+ */
16
+ sendBytes(data: Uint8Array): Promise<void>;
17
+ /**
18
+ * Issue a USB control transfer to reset the PICOBOOT interface state machine.
19
+ * Should be called before the first command to ensure a clean state.
20
+ */
21
+ resetInterface(): Promise<void>;
22
+ /** Release the USB interface and close the device. */
23
+ close(): Promise<void>;
24
+ }
25
+ //# sourceMappingURL=IPicobootTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IPicobootTransport.d.ts","sourceRoot":"","sources":["../../src/transport/IPicobootTransport.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAErD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C;;;OAGG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC,sDAAsD;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,10 @@
1
+ // USB transport abstraction for the PICOBOOT protocol (RP2040 / RP2350 BOOTSEL mode).
2
+ //
3
+ // PICOBOOT is a USB vendor-class bulk-transfer protocol exposed on interface 1
4
+ // of the RP2040 when held in BOOTSEL mode (VID=0x2E8A, PID=0x0003).
5
+ //
6
+ // Implementations:
7
+ // NodeUSBTransport — Node.js, uses the 'usb' npm package (libusb)
8
+ // (future) WebUSBTransport — browser, once RP2350 advertises WebUSB BOS descriptor
9
+ export {};
10
+ //# sourceMappingURL=IPicobootTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IPicobootTransport.js","sourceRoot":"","sources":["../../src/transport/IPicobootTransport.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,EAAE;AACF,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,mBAAmB;AACnB,oEAAoE;AACpE,qFAAqF"}
@@ -0,0 +1,33 @@
1
+ export interface SerialSignals {
2
+ dtr?: boolean;
3
+ rts?: boolean;
4
+ }
5
+ export interface ISTKTransport {
6
+ /** Send raw bytes to the device */
7
+ write(data: Uint8Array): Promise<void>;
8
+ /** Subscribe to incoming data chunks */
9
+ on(event: 'data', handler: (chunk: Uint8Array) => void): void;
10
+ /** Unsubscribe a data handler */
11
+ off(event: 'data', handler: (chunk: Uint8Array) => void): void;
12
+ /**
13
+ * Set hardware handshake signals.
14
+ * Optional — not all transports support it.
15
+ * Used to toggle DTR/RTS for Arduino bootloader entry.
16
+ */
17
+ setSignals?(opts: SerialSignals): Promise<void>;
18
+ /**
19
+ * Send a BREAK condition on the serial line.
20
+ * Required for UPDI protocol — used to reset the UPDI state machine.
21
+ *
22
+ * Implementations should hold TX low for ≥ 12 bit-times (e.g. by sending 0x00
23
+ * at 300 baud, which produces a ~33 ms BREAK period at 115200 operating speed).
24
+ * WebSerialTransport closes/reopens the port; NodeSerialTransport uses hardware
25
+ * SET{brk} if available, falling back to the low-baud approach.
26
+ *
27
+ * Optional — only required for UPDI.
28
+ */
29
+ sendBreak?(): Promise<void>;
30
+ /** Release all resources */
31
+ close(): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=ITransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITransport.d.ts","sourceRoot":"","sources":["../../src/transport/ITransport.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC,wCAAwC;IACxC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAE9D,iCAAiC;IACjC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAE/D;;;;OAIG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;;;;;;;;;OAUG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,4BAA4B;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB"}
@@ -0,0 +1,4 @@
1
+ // Minimal transport interface that stk500 requires.
2
+ // Decouples the protocol logic from any specific I/O backend (Node.js, WebSerial, mock).
3
+ export {};
4
+ //# sourceMappingURL=ITransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ITransport.js","sourceRoot":"","sources":["../../src/transport/ITransport.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,yFAAyF"}
@@ -0,0 +1,35 @@
1
+ import type { ISTKTransport, SerialSignals } from './ITransport.js';
2
+ /**
3
+ * Minimal duck-type interface of the Node.js `serialport` SerialPort class.
4
+ * This avoids a hard dependency on the `serialport` package.
5
+ */
6
+ export interface NodeSerialPortLike {
7
+ write(data: Buffer | Uint8Array | readonly number[], callback?: (err: Error | null | undefined) => void): boolean;
8
+ on(event: 'data', listener: (data: Buffer) => void): this;
9
+ removeListener(event: 'data', listener: (data: Buffer) => void): this;
10
+ set?(options: {
11
+ dtr?: boolean;
12
+ rts?: boolean;
13
+ brk?: boolean;
14
+ }, callback?: (err: Error | null | undefined) => void): void;
15
+ drain?(callback?: (err: Error | null | undefined) => void): void;
16
+ close?(callback?: (err: Error | null | undefined) => void): void;
17
+ }
18
+ export declare class NodeSerialTransport implements ISTKTransport {
19
+ private readonly port;
20
+ private readonly handlerMap;
21
+ constructor(port: NodeSerialPortLike);
22
+ write(data: Uint8Array): Promise<void>;
23
+ on(_event: 'data', handler: (chunk: Uint8Array) => void): void;
24
+ off(_event: 'data', handler: (chunk: Uint8Array) => void): void;
25
+ setSignals(opts: SerialSignals): Promise<void>;
26
+ /**
27
+ * Send a BREAK condition for UPDI.
28
+ *
29
+ * Uses hardware SET{brk} if the port supports it (serialport >= 10).
30
+ * Holds TX low for ~12 ms (≥ 12 bit-times at any supported baud rate).
31
+ */
32
+ sendBreak(): Promise<void>;
33
+ close(): Promise<void>;
34
+ }
35
+ //# sourceMappingURL=NodeSerialTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeSerialTransport.d.ts","sourceRoot":"","sources":["../../src/transport/NodeSerialTransport.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,CACH,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,MAAM,EAAE,EAC7C,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,GACjD,OAAO,CAAC;IACX,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACtE,GAAG,CAAC,CACF,OAAO,EAAE;QAAE,GAAG,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,OAAO,CAAC;QAAC,GAAG,CAAC,EAAE,OAAO,CAAA;KAAE,EACxD,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,GACjD,IAAI,CAAC;IACR,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI,CAAC;IACjE,KAAK,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,GAAG,IAAI,CAAC;CAClE;AAED,qBAAa,mBAAoB,YAAW,aAAa;IAO3C,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAGvB;gBAEyB,IAAI,EAAE,kBAAkB;IAE/C,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5C,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAM9D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAQzD,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAUpD;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB1B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAmB7B"}