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
@@ -0,0 +1,102 @@
1
+ // Node.js transport adapter for webserial-flasher.
2
+ // Works with the `serialport` npm package (https://serialport.io).
3
+ //
4
+ // Usage:
5
+ // import { SerialPort } from 'serialport';
6
+ // const port = new SerialPort({ path: '/dev/ttyACM0', baudRate: 115200, autoOpen: false });
7
+ // await port.open(); // or pass openImmediately:true
8
+ // const transport = new NodeSerialTransport(port);
9
+ // const stk = new STK500(transport, board);
10
+ // await stk.bootload(hex);
11
+ // await transport.close();
12
+ export class NodeSerialTransport {
13
+ constructor(port) {
14
+ this.port = port;
15
+ // Map user handlers → wrapped handlers so removeListener works correctly
16
+ this.handlerMap = new Map();
17
+ }
18
+ async write(data) {
19
+ return new Promise((resolve, reject) => {
20
+ this.port.write(data, (err) => {
21
+ if (err)
22
+ reject(err);
23
+ else
24
+ resolve();
25
+ });
26
+ });
27
+ }
28
+ on(_event, handler) {
29
+ const wrapped = (buf) => handler(new Uint8Array(buf));
30
+ this.handlerMap.set(handler, wrapped);
31
+ this.port.on('data', wrapped);
32
+ }
33
+ off(_event, handler) {
34
+ const wrapped = this.handlerMap.get(handler);
35
+ if (wrapped) {
36
+ this.port.removeListener('data', wrapped);
37
+ this.handlerMap.delete(handler);
38
+ }
39
+ }
40
+ async setSignals(opts) {
41
+ if (!this.port.set)
42
+ return; // Port implementation doesn't support signal control
43
+ return new Promise((resolve, reject) => {
44
+ this.port.set(opts, (err) => {
45
+ if (err)
46
+ reject(err);
47
+ else
48
+ resolve();
49
+ });
50
+ });
51
+ }
52
+ /**
53
+ * Send a BREAK condition for UPDI.
54
+ *
55
+ * Uses hardware SET{brk} if the port supports it (serialport >= 10).
56
+ * Holds TX low for ~12 ms (≥ 12 bit-times at any supported baud rate).
57
+ */
58
+ async sendBreak() {
59
+ if (!this.port.set) {
60
+ throw new Error('NodeSerialTransport: sendBreak() requires port.set() ' +
61
+ '(not available on this port implementation)');
62
+ }
63
+ await new Promise((resolve, reject) => {
64
+ this.port.set({ brk: true }, (err) => {
65
+ if (err)
66
+ reject(err);
67
+ else
68
+ resolve();
69
+ });
70
+ });
71
+ await new Promise((r) => setTimeout(r, 12)); // ≥12 ms = ≥12 bit-times @ 1 Mbaud
72
+ await new Promise((resolve, reject) => {
73
+ this.port.set({ brk: false }, (err) => {
74
+ if (err)
75
+ reject(err);
76
+ else
77
+ resolve();
78
+ });
79
+ });
80
+ await new Promise((r) => setTimeout(r, 2)); // settling
81
+ }
82
+ async close() {
83
+ this.handlerMap.clear();
84
+ if (this.port.drain) {
85
+ await new Promise((resolve) => {
86
+ this.port.drain((err) => {
87
+ if (err) { /* ignore drain errors on close */ }
88
+ resolve();
89
+ });
90
+ });
91
+ }
92
+ if (this.port.close) {
93
+ await new Promise((resolve) => {
94
+ this.port.close((err) => {
95
+ if (err) { /* ignore */ }
96
+ resolve();
97
+ });
98
+ });
99
+ }
100
+ }
101
+ }
102
+ //# sourceMappingURL=NodeSerialTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeSerialTransport.js","sourceRoot":"","sources":["../../src/transport/NodeSerialTransport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { IPicobootTransport } from './IPicobootTransport.js';
2
+ export declare class NodeUSBTransport implements IPicobootTransport {
3
+ private readonly device;
4
+ private readonly iface;
5
+ private readonly outEp;
6
+ private readonly inEp;
7
+ private constructor();
8
+ /**
9
+ * Find the first RP2040 / RP2350 in BOOTSEL mode, claim the PICOBOOT
10
+ * interface, and return a ready-to-use transport instance.
11
+ *
12
+ * @param vid USB Vendor ID (default: 0x2E8A — Raspberry Pi)
13
+ * @param pid USB Product ID (default: 0x0003 — RP2040 USBBOOT)
14
+ * @throws STK500ProtocolError if the 'usb' package is missing or no device found
15
+ */
16
+ static open(vid?: number, pid?: number): Promise<NodeUSBTransport>;
17
+ sendCommand(cmd: Uint8Array): Promise<void>;
18
+ receiveBytes(maxLength: number): Promise<Uint8Array>;
19
+ sendBytes(data: Uint8Array): Promise<void>;
20
+ resetInterface(): Promise<void>;
21
+ close(): Promise<void>;
22
+ private _transferOut;
23
+ }
24
+ //# sourceMappingURL=NodeUSBTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeUSBTransport.d.ts","sourceRoot":"","sources":["../../src/transport/NodeUSBTransport.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAIlE,qBAAa,gBAAiB,YAAW,kBAAkB;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAElC,OAAO;IASP;;;;;;;OAOG;WACU,IAAI,CAAC,GAAG,SAAS,EAAE,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoElE,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAWpD,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1C,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAa5B,OAAO,CAAC,YAAY;CAQrB"}
@@ -0,0 +1,146 @@
1
+ // Node.js USB transport for the PICOBOOT protocol.
2
+ // Requires the 'usb' npm package: npm install usb
3
+ //
4
+ // Usage:
5
+ // const transport = await NodeUSBTransport.open();
6
+ // const pico = new PicoBoot(transport);
7
+ // await pico.bootload(uf2Data);
8
+ // await transport.close();
9
+ import { PICOBOOT_INTERFACE } from '../protocol/picoboot/constants.js';
10
+ import { STK500ProtocolError } from '../core/errors.js';
11
+ export class NodeUSBTransport {
12
+ constructor(device, iface, outEp, inEp) {
13
+ this.device = device;
14
+ this.iface = iface;
15
+ this.outEp = outEp;
16
+ this.inEp = inEp;
17
+ }
18
+ // ── Factory ────────────────────────────────────────────────────────────────
19
+ /**
20
+ * Find the first RP2040 / RP2350 in BOOTSEL mode, claim the PICOBOOT
21
+ * interface, and return a ready-to-use transport instance.
22
+ *
23
+ * @param vid USB Vendor ID (default: 0x2E8A — Raspberry Pi)
24
+ * @param pid USB Product ID (default: 0x0003 — RP2040 USBBOOT)
25
+ * @throws STK500ProtocolError if the 'usb' package is missing or no device found
26
+ */
27
+ static async open(vid = 0x2E8A, pid = 0x0003) {
28
+ // Dynamic import: 'usb' is an optional peer dependency.
29
+ // The new Function wrapper prevents TypeScript from resolving 'usb' statically,
30
+ // avoiding build errors when the package is not installed.
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ let usbModule;
33
+ try {
34
+ // eslint-disable-next-line no-new-func
35
+ usbModule = await (new Function('m', 'return import(m)'))('usb');
36
+ }
37
+ catch {
38
+ throw new STK500ProtocolError("Package 'usb' is not installed. Run: npm install usb");
39
+ }
40
+ const device = (usbModule.findByIds ?? usbModule.default?.findByIds)?.(vid, pid);
41
+ if (!device) {
42
+ throw new STK500ProtocolError(`No device found in BOOTSEL mode ` +
43
+ `(VID=0x${vid.toString(16).toUpperCase()}, PID=0x${pid.toString(16).toUpperCase()}). ` +
44
+ 'Hold the BOOTSEL button while connecting USB.');
45
+ }
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ const dev = device;
48
+ dev.open();
49
+ // Interface 1 = PICOBOOT (vendor class 0xFF).
50
+ // If the device only exposes 1 interface (MSD without PICOBOOT), that is interface 0.
51
+ const ifaceCount = dev.interfaces?.length ?? 0;
52
+ const ifaceIndex = ifaceCount >= 2 ? PICOBOOT_INTERFACE : 0;
53
+ const iface = dev.interface(ifaceIndex);
54
+ // Detach kernel driver on Linux / macOS if necessary
55
+ try {
56
+ if (iface.isKernelDriverActive?.()) {
57
+ iface.detachKernelDriver();
58
+ }
59
+ }
60
+ catch {
61
+ // Not available on Windows — silently ignore
62
+ }
63
+ iface.claim();
64
+ // Discover OUT and IN bulk endpoints dynamically (endpoint addresses vary
65
+ // between bootrom revisions)
66
+ let outEp = null;
67
+ let inEp = null;
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ for (const ep of iface.endpoints) {
70
+ if (ep.direction === 'out')
71
+ outEp = ep;
72
+ else if (ep.direction === 'in')
73
+ inEp = ep;
74
+ }
75
+ if (!outEp || !inEp) {
76
+ try {
77
+ dev.close();
78
+ }
79
+ catch { /* ignore */ }
80
+ throw new STK500ProtocolError('PICOBOOT bulk endpoints not found. ' +
81
+ 'Is the device in BOOTSEL mode?');
82
+ }
83
+ return new NodeUSBTransport(dev, iface, outEp, inEp);
84
+ }
85
+ // ── IPicobootTransport ─────────────────────────────────────────────────────
86
+ async sendCommand(cmd) {
87
+ return this._transferOut(cmd);
88
+ }
89
+ async receiveBytes(maxLength) {
90
+ if (maxLength === 0)
91
+ return new Uint8Array(0);
92
+ return new Promise((resolve, reject) => {
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ this.inEp.transfer(maxLength, (err, data) => {
95
+ if (err)
96
+ reject(err);
97
+ else
98
+ resolve(data ? new Uint8Array(data) : new Uint8Array(0));
99
+ });
100
+ });
101
+ }
102
+ async sendBytes(data) {
103
+ return this._transferOut(data);
104
+ }
105
+ async resetInterface() {
106
+ // PICOBOOT_RESET control transfer (bmRequestType=0x41, bRequest=0x41)
107
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
+ const dev = this.device;
109
+ const iface = this.iface;
110
+ return new Promise((resolve, reject) => {
111
+ dev.controlTransfer(0x41, // bmRequestType: host→device, class, interface
112
+ 0x41, // bRequest: PICOBOOT_RESET
113
+ 0, // wValue
114
+ iface.interfaceNumber ?? 1, // wIndex
115
+ Buffer.alloc(0), (err) => { if (err)
116
+ reject(err);
117
+ else
118
+ resolve(); });
119
+ });
120
+ }
121
+ async close() {
122
+ try {
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ await new Promise((res) => this.iface.release(true, () => res()));
125
+ }
126
+ catch { /* ignore */ }
127
+ try {
128
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
129
+ this.device.close();
130
+ }
131
+ catch { /* ignore */ }
132
+ }
133
+ // ── Private ────────────────────────────────────────────────────────────────
134
+ _transferOut(data) {
135
+ return new Promise((resolve, reject) => {
136
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
137
+ this.outEp.transfer(Buffer.from(data), (err) => {
138
+ if (err)
139
+ reject(err);
140
+ else
141
+ resolve();
142
+ });
143
+ });
144
+ }
145
+ }
146
+ //# sourceMappingURL=NodeUSBTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeUSBTransport.js","sourceRoot":"","sources":["../../src/transport/NodeUSBTransport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import type { ISTKTransport, SerialSignals } from './ITransport.js';
2
+ export interface WebSerialPortFilter {
3
+ usbVendorId?: number;
4
+ usbProductId?: number;
5
+ }
6
+ type WebSerialPort = any;
7
+ /** Options passed to WebSerial port.open() */
8
+ export interface WebSerialOpenOptions {
9
+ /** Baud rate (required) */
10
+ baudRate: number;
11
+ /** Data bits (default: 8) */
12
+ dataBits?: 7 | 8;
13
+ /** Stop bits (default: 1) — use 2 for UPDI */
14
+ stopBits?: 1 | 2;
15
+ /** Parity (default: 'none') — use 'even' for UPDI */
16
+ parity?: 'none' | 'even' | 'odd';
17
+ /** Flow control (default: 'none') */
18
+ flowControl?: 'none' | 'hardware';
19
+ }
20
+ export declare class WebSerialTransport implements ISTKTransport {
21
+ private readonly port;
22
+ private writer;
23
+ private reader;
24
+ private readLoopActive;
25
+ private readonly listeners;
26
+ private lastOpenOptions;
27
+ constructor(port: WebSerialPort);
28
+ /** Check whether WebSerial is available in the current environment */
29
+ static isSupported(): boolean;
30
+ /**
31
+ * Show the browser's port-picker dialog and return a transport wrapping the selected port.
32
+ * @param filters - Optional USB vendor/product ID filters to narrow the list shown to the user
33
+ */
34
+ static requestPort(filters?: WebSerialPortFilter[]): Promise<WebSerialTransport>;
35
+ /**
36
+ * Return transports for all previously-approved ports (no dialog).
37
+ * Useful for re-connecting without prompting the user again.
38
+ */
39
+ static getPorts(): Promise<WebSerialTransport[]>;
40
+ /** Open the serial port at the given baud rate with optional serial settings */
41
+ open(baudRate: number, options?: Partial<WebSerialOpenOptions>): Promise<void>;
42
+ /**
43
+ * Send a BREAK condition to reset the UPDI state machine.
44
+ *
45
+ * Implementation: close the port, reopen at 300 baud 8N1, transmit 0x00
46
+ * (which produces a ~33 ms break period relative to 115200 baud), then
47
+ * reopen at the original settings.
48
+ *
49
+ * The current port must have been opened with open() before calling this.
50
+ */
51
+ sendBreak(): Promise<void>;
52
+ /** Internal helper: close writer, reader, and port without clearing lastOpenOptions */
53
+ private _closePort;
54
+ /** Set DTR/RTS hardware signals to trigger Arduino bootloader entry */
55
+ setSignals(opts: SerialSignals): Promise<void>;
56
+ write(data: Uint8Array): Promise<void>;
57
+ on(_event: 'data', handler: (data: Uint8Array) => void): void;
58
+ off(_event: 'data', handler: (data: Uint8Array) => void): void;
59
+ private startReadLoop;
60
+ close(): Promise<void>;
61
+ }
62
+ export {};
63
+ //# sourceMappingURL=WebSerialTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSerialTransport.d.ts","sourceRoot":"","sources":["../../src/transport/WebSerialTransport.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEpE,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,KAAK,aAAa,GAAG,GAAG,CAAC;AAEzB,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IACjB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACjC,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACnC;AAED,qBAAa,kBAAmB,YAAW,aAAa;IAO1C,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,MAAM,CAAwD;IACtE,OAAO,CAAC,MAAM,CAAwD;IACtE,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyC;IACnE,OAAO,CAAC,eAAe,CAAqC;gBAE/B,IAAI,EAAE,aAAa;IAEhD,sEAAsE;IACtE,MAAM,CAAC,WAAW,IAAI,OAAO;IAI7B;;;OAGG;WACU,WAAW,CACtB,OAAO,GAAE,mBAAmB,EAAO,GAClC,OAAO,CAAC,kBAAkB,CAAC;IAW9B;;;OAGG;WACU,QAAQ,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAOtD,gFAAgF;IAC1E,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpF;;;;;;;;OAQG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBhC,uFAAuF;YACzE,UAAU;IAYxB,uEAAuE;IACjE,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9C,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5C,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAI7D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI;IAI9D,OAAO,CAAC,aAAa;IAiBf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
@@ -0,0 +1,159 @@
1
+ // Browser WebSerial API transport for webserial-flasher.
2
+ // Works in Chrome 89+ and Edge 89+. Not available in Firefox or Safari.
3
+ //
4
+ // Usage:
5
+ // const transport = await WebSerialTransport.requestPort([{ usbVendorId: 0x2341 }]);
6
+ // await transport.open(115200);
7
+ // const stk = new STK500(transport, board);
8
+ // await stk.bootload(hex);
9
+ // await transport.close();
10
+ export class WebSerialTransport {
11
+ constructor(port) {
12
+ this.port = port;
13
+ this.writer = null;
14
+ this.reader = null;
15
+ this.readLoopActive = false;
16
+ this.listeners = new Set();
17
+ this.lastOpenOptions = null;
18
+ }
19
+ /** Check whether WebSerial is available in the current environment */
20
+ static isSupported() {
21
+ return typeof navigator !== 'undefined' && 'serial' in navigator;
22
+ }
23
+ /**
24
+ * Show the browser's port-picker dialog and return a transport wrapping the selected port.
25
+ * @param filters - Optional USB vendor/product ID filters to narrow the list shown to the user
26
+ */
27
+ static async requestPort(filters = []) {
28
+ if (!WebSerialTransport.isSupported()) {
29
+ throw new Error('WebSerial API is not supported. Use Chrome 89+ or Edge 89+.');
30
+ }
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ const port = await navigator.serial.requestPort({ filters });
33
+ return new WebSerialTransport(port);
34
+ }
35
+ /**
36
+ * Return transports for all previously-approved ports (no dialog).
37
+ * Useful for re-connecting without prompting the user again.
38
+ */
39
+ static async getPorts() {
40
+ if (!WebSerialTransport.isSupported())
41
+ return [];
42
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
+ const ports = await navigator.serial.getPorts();
44
+ return ports.map((p) => new WebSerialTransport(p));
45
+ }
46
+ /** Open the serial port at the given baud rate with optional serial settings */
47
+ async open(baudRate, options) {
48
+ const opts = {
49
+ baudRate,
50
+ dataBits: options?.dataBits ?? 8,
51
+ stopBits: options?.stopBits ?? 1,
52
+ parity: options?.parity ?? 'none',
53
+ flowControl: options?.flowControl ?? 'none',
54
+ };
55
+ this.lastOpenOptions = opts;
56
+ await this.port.open(opts);
57
+ this.writer = this.port.writable.getWriter();
58
+ this.reader = this.port.readable.getReader();
59
+ this.readLoopActive = true;
60
+ this.startReadLoop();
61
+ }
62
+ /**
63
+ * Send a BREAK condition to reset the UPDI state machine.
64
+ *
65
+ * Implementation: close the port, reopen at 300 baud 8N1, transmit 0x00
66
+ * (which produces a ~33 ms break period relative to 115200 baud), then
67
+ * reopen at the original settings.
68
+ *
69
+ * The current port must have been opened with open() before calling this.
70
+ */
71
+ async sendBreak() {
72
+ if (!this.lastOpenOptions) {
73
+ throw new Error('WebSerialTransport: call open() before sendBreak()');
74
+ }
75
+ const originalOptions = { ...this.lastOpenOptions };
76
+ // 1. Tear down current connection
77
+ await this._closePort();
78
+ // 2. Reopen at 300 baud to generate a BREAK pulse
79
+ await this.port.open({ baudRate: 300, dataBits: 8, stopBits: 1, parity: 'none', flowControl: 'none' });
80
+ const breakWriter = this.port.writable.getWriter();
81
+ await breakWriter.write(new Uint8Array([0x00])); // 0x00 at 300 baud ≈ 33 ms low
82
+ await new Promise((r) => setTimeout(r, 50)); // ensure byte clocks out
83
+ breakWriter.releaseLock();
84
+ await this.port.close();
85
+ // 3. Reopen at original settings
86
+ await this.port.open(originalOptions);
87
+ this.writer = this.port.writable.getWriter();
88
+ this.reader = this.port.readable.getReader();
89
+ this.readLoopActive = true;
90
+ this.startReadLoop();
91
+ }
92
+ /** Internal helper: close writer, reader, and port without clearing lastOpenOptions */
93
+ async _closePort() {
94
+ this.readLoopActive = false;
95
+ this.listeners.clear();
96
+ try {
97
+ await this.reader?.cancel();
98
+ }
99
+ catch { /* ignore */ }
100
+ try {
101
+ this.reader?.releaseLock();
102
+ }
103
+ catch { /* ignore */ }
104
+ try {
105
+ await this.writer?.abort();
106
+ }
107
+ catch { /* ignore */ }
108
+ try {
109
+ this.writer?.releaseLock();
110
+ }
111
+ catch { /* ignore */ }
112
+ try {
113
+ await this.port.close();
114
+ }
115
+ catch { /* ignore */ }
116
+ this.reader = null;
117
+ this.writer = null;
118
+ }
119
+ /** Set DTR/RTS hardware signals to trigger Arduino bootloader entry */
120
+ async setSignals(opts) {
121
+ // WebSerialPort.setSignals is defined in the WebSerial spec
122
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
+ await this.port.setSignals(opts);
124
+ }
125
+ async write(data) {
126
+ if (!this.writer)
127
+ throw new Error('Transport not open — call open() first');
128
+ await this.writer.write(data);
129
+ }
130
+ on(_event, handler) {
131
+ this.listeners.add(handler);
132
+ }
133
+ off(_event, handler) {
134
+ this.listeners.delete(handler);
135
+ }
136
+ startReadLoop() {
137
+ void (async () => {
138
+ while (this.readLoopActive) {
139
+ try {
140
+ const { value, done } = await this.reader.read();
141
+ if (done || !this.readLoopActive)
142
+ break;
143
+ if (value && value.byteLength > 0) {
144
+ this.listeners.forEach((fn) => fn(value));
145
+ }
146
+ }
147
+ catch {
148
+ // Port closed externally or connection lost — stop loop silently
149
+ break;
150
+ }
151
+ }
152
+ })();
153
+ }
154
+ async close() {
155
+ this.lastOpenOptions = null;
156
+ await this._closePort();
157
+ }
158
+ }
159
+ //# sourceMappingURL=WebSerialTransport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSerialTransport.js","sourceRoot":"","sources":["../../src/transport/WebSerialTransport.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "webserial-flasher",
3
+ "version": "1.0.0",
4
+ "description": "Multi-protocol firmware flasher — STK500v1, STK500v2, AVR109, UPDI, PICOBOOT (RP2040) — ESM, TypeScript, Node.js + WebSerial browser support.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "lint": "eslint src",
22
+ "build": "tsc",
23
+ "test": "tsx --test test/unit/*.test.ts test/integration/*.test.ts",
24
+ "test:unit": "tsx --test test/unit/*.test.ts",
25
+ "test:integration": "tsx --test test/integration/*.test.ts",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/vielang/webserial-flasher.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/vielang/webserial-flasher/issues"
34
+ },
35
+ "homepage": "https://github.com/vielang/webserial-flasher#readme",
36
+ "keywords": [
37
+ "arduino",
38
+ "stk500",
39
+ "stk500v2",
40
+ "avr109",
41
+ "updi",
42
+ "picoboot",
43
+ "avr",
44
+ "attiny",
45
+ "atmega",
46
+ "rp2040",
47
+ "raspberry-pi-pico",
48
+ "avrdude",
49
+ "typescript",
50
+ "esm",
51
+ "webserial",
52
+ "webusb",
53
+ "firmware",
54
+ "flasher"
55
+ ],
56
+ "author": "Vie Lang <chongnguoithuong@gmail.com>",
57
+ "license": "MIT",
58
+ "engines": {
59
+ "node": ">=18.0.0"
60
+ },
61
+ "peerDependencies": {
62
+ "usb": ">=2.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "usb": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "devDependencies": {
70
+ "@eslint/js": "^9.16.0",
71
+ "@types/node": "^22.10.1",
72
+ "eslint": "^9.16.0",
73
+ "globals": "^15.13.0",
74
+ "serialport": "^12.0.0",
75
+ "tsx": "^4.19.2",
76
+ "typescript": "^5.7.2",
77
+ "typescript-eslint": "^8.18.0"
78
+ }
79
+ }