Skip to content

Commit 140df3e

Browse files
committed
final fixes and initial release
1 parent 5aca2d2 commit 140df3e

File tree

17 files changed

+253
-87
lines changed

17 files changed

+253
-87
lines changed

.github/workflows/publish.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Publish Package to npmjs
2+
on:
3+
release:
4+
types: [published]
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
# Setup .npmrc file to publish to npm
11+
- uses: actions/setup-node@v4
12+
with:
13+
node-version: '20.x'
14+
registry-url: 'https://registry.npmjs.org'
15+
scope: '@duinoapp'
16+
- run: yarn
17+
- run: yarn build
18+
- run: yarn publish --access public
19+
env:
20+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

LICENSE

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright 2024 Fraser Bullock
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,108 @@ This project aims to achieve the following:
2323
- Support ESP devices
2424
- Platform for easy addition of new protocols
2525

26+
## Usage
27+
28+
install your favourite way
29+
```bash
30+
npm install @duinoapp/upload-multitool
31+
yarn add @duinoapp/upload-multitool
32+
pnpm add @duinoapp/upload-multitool
33+
```
34+
35+
This package exports a few utilities, the main one is upload
36+
37+
```js
38+
import { upload } from '@duinoapp/upload-multitool';
39+
import type { ProgramConfig } from '@duinoapp/upload-multitool';
40+
import { SerialPort } from 'serialport';
41+
42+
const serialport = new SerialPort({ path: '/dev/example', baudRate: 115200 });
43+
44+
const config = {
45+
// for avr boards, the compiled hex
46+
bin: compiled.hex,
47+
// for esp boards, the compiled files and flash settings
48+
files: compiled.files,
49+
flashFreq: compiled.flashFreq,
50+
flashMode: compiled.flashMode,
51+
// baud rate to connect to bootloader
52+
speed: 115200,
53+
// baud rate to use for upload (ESP)
54+
uploadSpeed: 115200,
55+
// the tool to use, avrdude or esptool
56+
tool: 'avr',
57+
// the CPU of the device
58+
cpu: 'atmega328p',
59+
// a standard out interface ({ write(msg: string): void })
60+
stdout: process.stdout,
61+
// whether or not to log to stdout verbosely
62+
verbose: true,
63+
// handle reconnecting to AVR109 devices when connecting to the bootloader
64+
// the device ID changes for the bootloader, meaning in some OS's a new connection is required
65+
// avr109Reconnect?: (opts: ReconnectParams) => Promise<SerialPort>;
66+
} as ProgramConfig;
67+
68+
const res = await upload(serial.port, config);
69+
70+
```
71+
72+
If you want to programmatically check if a tool/cpu is supported:
73+
74+
```js
75+
import { isSupported } from '@duinoapp/upload-multitool';
76+
77+
console.log(isSupported('avr', 'atmega328p')); // true
78+
```
79+
80+
Also exports some helpful utilities:
81+
82+
```js
83+
import { WebSerialPort, SerialPortPromise, WebSerialPortPromise } from '@duinoapp/upload-multitool';
84+
85+
// WebSerialPort is a drop-in web replacement for serialport, with some useful static methods:
86+
87+
// Check whether the current browser supports the Web Serial API
88+
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility
89+
WebSerialPort.isSupported() // true/false
90+
91+
// request a serial connection from the user,
92+
// first param takes requestPort options: https://developer.mozilla.org/en-US/docs/Web/API/Serial/requestPort#parameters
93+
// second params takes the default open options
94+
const serialport = WebSerialPort.requestPort({}, { baudRate: 115200 });
95+
serialport.open((err) => {
96+
if (!err) serialport.write('hello', (err2) => ...)
97+
});
98+
99+
// get a list of the serial connections that have already been requested:
100+
const list = WebSerialPort.list();
101+
102+
// A wrapper util around SerialPort that exposes the same methods but with promises
103+
const serial = new SerialPortPromise(await WebSerialPort.requestPort());
104+
await serial.open();
105+
await serial.write('hello');
106+
107+
// A Merged class of both WebSerialPort and SerialPortPromise, probably use this one
108+
const serial = WebSerialPortPromise.requestPort();
109+
await serial.open();
110+
await serial.write('hello');
111+
```
112+
113+
### Upload return
114+
The upload function will return an object:
115+
```ts
116+
{
117+
// the time it took to complete the upload
118+
time: number
119+
// the final serial port used. In most cases the serial port passes in
120+
// if you pass in a non promise port, internally it will wrap with SerialPortPromise
121+
// if you pass in a promise port, it is likely the same object, you can check with the serialport.key value on SerialPortPromise
122+
// if using AVR109 and a reconnect is needed, this will likely be a new connection.
123+
serialport: SerialPortPromise | WebSerialPortPromise
124+
}
125+
```
126+
127+
26128
## Get in touch
27129
You can contact me in the #multitool-general channel of the duinoapp discord
28130

examples/index.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1">
77
<script src="../dist/index.umd.js"></script>
8-
<script src="../dist/web-serialport.umd.js"></script>
98
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/xterm.css">
109
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/xterm.js"></script>
1110
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"></script>
@@ -32,7 +31,7 @@ <h1>Upload Multitool</h1>
3231
<div id="terminal"></div>
3332
</div>
3433
<script>
35-
const { isSupported, upload } = uploadMultitool;
34+
const { isSupported, upload, WebSerialPort } = uploadMultitool;
3635

3736
const setStatus = (status) => {
3837
document.getElementById('status').innerHTML = status;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "upload-multitool",
2+
"name": "@duinoapp/upload-multitool",
33
"version": "0.0.1",
44
"description": "Micro Controller Uploading Multitool",
55
"main": "dist/index.js",

rollup.config.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,4 @@ module.exports = [{
3333
nodeResolve({ preferBuiltins: false }),
3434
json(),
3535
],
36-
}, {
37-
input: 'dist/serialport/web-serialport.js',
38-
output: [
39-
{
40-
file: 'dist/web-serialport.cjs',
41-
format: 'cjs',
42-
},
43-
{
44-
file: 'dist/web-serialport.mjs',
45-
format: 'esm',
46-
},
47-
{
48-
file: 'dist/web-serialport.umd.js',
49-
format: 'umd',
50-
name: 'WebSerialPort',
51-
},
52-
],
53-
context: 'this',
54-
plugins: [
55-
commonjs({
56-
ignoreGlobal: true,
57-
}),
58-
nodePolyfills({ include: ['buffer'] }),
59-
nodeResolve({ preferBuiltins: false }),
60-
],
6136
}];

src/avr/avr109/avr109.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { SerialPort } from 'serialport/dist/index.d';
22
import { SerialPortPromise } from '../../serialport/serialport-promise';
3-
import { waitForOpen, setDTRRTS } from '../../util/serial-helpers';
3+
import { waitForOpen, castToSPP } from '../../util/serial-helpers';
44
import asyncTimeout from '../../util/async-timeout';
55
import { StdOut } from '../../index';
66

@@ -97,7 +97,7 @@ export default class AVR109 {
9797
this.opts = opts || {};
9898
this.signature = this.opts.signature || 'LUFACDC';
9999
this.quiet = this.opts.quiet || false;
100-
this.serial = serial instanceof SerialPortPromise ? serial : new SerialPortPromise(serial);
100+
this.serial = castToSPP(serial);
101101

102102
this.hasAutoIncrAddr = false;
103103
this.bufferSize = 0;
@@ -446,7 +446,7 @@ export default class AVR109 {
446446
.then((serial: SerialPort | SerialPortPromise) => {
447447
clearTimeout(timeoutId);
448448
if (timedOut) return;
449-
resolve(serial instanceof SerialPortPromise ? serial : new SerialPortPromise(serial));
449+
resolve(castToSPP(serial));
450450
})
451451
.catch(reject);
452452
});
@@ -476,12 +476,12 @@ export default class AVR109 {
476476
await this.serial.open();
477477
await waitForOpen(this.serial);
478478
}
479-
console.log(this.serial?.port);
479+
// console.log(this.serial?.port);
480480
if (this.serial.baudRate !== this.opts.speed) {
481481
await this.serial.update({ baudRate: this.opts.speed || 57600 });
482482
}
483483
await asyncTimeout(200);
484-
console.log('reconnected', Date.now() - ts);
484+
// console.log('reconnected', Date.now() - ts);
485485
}
486486

487487
async exitBootloader() {

src/avr/stk500-v1/stk500-v1.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import { SerialPort } from 'serialport/dist/index.d';
55
import { SerialPortPromise } from '../../serialport/serialport-promise';
6-
import { setDTRRTS } from '../../util/serial-helpers';
6+
import { setDTRRTS, castToSPP } from '../../util/serial-helpers';
77
import asyncTimeout from '../../util/async-timeout';
88
import { StdOut } from '../../index';
99

@@ -76,7 +76,7 @@ export default class STK500v1 {
7676
constructor(serial: SerialPort | SerialPortPromise, opts: STK500v1Options) {
7777
this.opts = opts || {};
7878
this.quiet = this.opts.quiet || false;
79-
this.serial = serial instanceof SerialPortPromise ? serial : new SerialPortPromise(serial);
79+
this.serial = castToSPP(serial);
8080
}
8181

8282
log (...args: any[]) {
@@ -169,7 +169,7 @@ export default class STK500v1 {
169169

170170

171171
async sync(attempts = 3, timeout = 400, ogAttempts = attempts): Promise<Buffer|null> {
172-
this.log(`sync ${attempts}`);
172+
this.log(`sync ${attempts} ${timeout}`);
173173
try {
174174
const res = await this.sendCommand({
175175
cmd: [

src/avr/stk500-v2/stk500-v2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { SerialPort } from 'serialport/dist/index.d';
22
import { SerialPortPromise } from '../../serialport/serialport-promise';
33

44
import statics from './constants';
5-
import { setDTRRTS } from '../../util/serial-helpers';
5+
import { setDTRRTS, castToSPP } from '../../util/serial-helpers';
66
import asyncTimeout from '../../util/async-timeout';
77
import { StdOut } from '../../index';
88

@@ -51,7 +51,7 @@ export default class STK500v2 {
5151

5252
constructor(serial: SerialPort | SerialPortPromise, opts: STK500v2Options) {
5353
this.opts = opts;
54-
this.serial = serial instanceof SerialPortPromise ? serial : new SerialPortPromise(serial);
54+
this.serial = castToSPP(serial);
5555
this.quiet = opts.quiet || false;
5656
this.sequence = 0;
5757
}

src/esp/loader.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { SerialPort } from 'serialport/dist/index.d';
2-
import { SerialPortPromise } from '../serialport/serialport-promise';
32
import pako from 'pako';
43
import MD5 from 'crypto-js/md5';
54
import encBase64 from 'crypto-js/enc-base64';
5+
import { SerialPortPromise } from '../serialport/serialport-promise';
6+
import { castToSPP } from '../util/serial-helpers';
67
import StubLoader from './stub-loader';
78
import roms from './roms/index';
89
import ROM from './roms/rom.d';
@@ -90,7 +91,7 @@ export default class ESPLoader {
9091
constructor(serial: SerialPort | SerialPortPromise, opts = {} as ESPOptions) {
9192
this.opts = opts || {};
9293
this.quiet = this.opts.quiet || false;
93-
this.serial = serial instanceof SerialPortPromise ? serial : new SerialPortPromise(serial);
94+
this.serial = castToSPP(serial);
9495
this.IS_STUB = false;
9596
this.chip = null;
9697
this.stdout = opts.stdout || process?.stdout || {

0 commit comments

Comments
 (0)