@alexgyver/serial 1.0.9 → 1.0.11
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/package.json +1 -1
- package/serial.js +41 -63
- package/serial.min.js +1 -1
package/package.json
CHANGED
package/serial.js
CHANGED
|
@@ -8,14 +8,17 @@ export default class SerialJS {
|
|
|
8
8
|
Closing: 'closing',
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
//#region handlers
|
|
12
|
+
onbin = null;
|
|
11
13
|
ontext = null;
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
onopen() { }
|
|
14
16
|
onclose() { }
|
|
15
17
|
onchange(s) { }
|
|
16
18
|
onselect(name) { }
|
|
17
19
|
onerror(e) { }
|
|
18
20
|
|
|
21
|
+
//#region constructor
|
|
19
22
|
constructor(params = {}) {
|
|
20
23
|
const def = {
|
|
21
24
|
eol: /\r?\n/,
|
|
@@ -23,21 +26,20 @@ export default class SerialJS {
|
|
|
23
26
|
auto_open: false,
|
|
24
27
|
reconnect: 1000,
|
|
25
28
|
};
|
|
26
|
-
|
|
27
29
|
this.cfg = { ...def, ...params };
|
|
28
30
|
|
|
31
|
+
this._setLastPort().then(() => this.onselect(this.getName()));
|
|
29
32
|
this.splitter = new StreamSplitter(this.cfg.eol);
|
|
30
33
|
this.splitter.ontext = (t) => {
|
|
31
34
|
try {
|
|
32
|
-
|
|
35
|
+
this.ontext?.(t);
|
|
33
36
|
} catch (e) {
|
|
34
37
|
this._error(e);
|
|
35
38
|
}
|
|
36
39
|
};
|
|
37
|
-
|
|
38
|
-
this._setLastPort().then(() => this.onselect(this.getName()));
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
//#region methods
|
|
41
43
|
config(params = {}) {
|
|
42
44
|
this.cfg = { ...this.cfg, ...params };
|
|
43
45
|
this.splitter.eol = this.cfg.eol;
|
|
@@ -48,7 +50,7 @@ export default class SerialJS {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
opened() {
|
|
51
|
-
return this._state
|
|
53
|
+
return this._state == SerialJS.State.Open;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
selected() {
|
|
@@ -56,7 +58,7 @@ export default class SerialJS {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
getName() {
|
|
59
|
-
if (!this._port) return
|
|
61
|
+
if (!this._port) return 'None';
|
|
60
62
|
|
|
61
63
|
switch (this._port.getInfo().usbProductId) {
|
|
62
64
|
case 0x55d3: return 'CH343';
|
|
@@ -66,62 +68,56 @@ export default class SerialJS {
|
|
|
66
68
|
case 0x0402: case 0x0403: case 0x0404: case 0x0405: case 0x6001: case 0x0602: case 0x6010: return 'FT232';
|
|
67
69
|
case 0x9500: case 0x0102: case 0x0501: case 0x80a9: case 0xea60: case 0xea61: case 0xea63: return 'CP210x';
|
|
68
70
|
}
|
|
69
|
-
|
|
70
71
|
return 'Unknown';
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
async select() {
|
|
74
75
|
try {
|
|
75
76
|
await this.close();
|
|
76
|
-
|
|
77
77
|
this._port = null;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for (const p of ports) await p.forget();
|
|
81
|
-
|
|
78
|
+
let ports = await navigator.serial.getPorts();
|
|
79
|
+
for (let p of ports) await p.forget();
|
|
82
80
|
await sleep(50);
|
|
83
81
|
await navigator.serial.requestPort();
|
|
84
82
|
await this._setLastPort();
|
|
85
83
|
} catch (e) {
|
|
86
84
|
this._error(e);
|
|
87
85
|
}
|
|
88
|
-
|
|
89
86
|
this.onselect(this.getName());
|
|
90
|
-
|
|
91
87
|
if (this.cfg.auto_open) this.open();
|
|
92
|
-
|
|
93
88
|
return this.selected();
|
|
94
89
|
}
|
|
95
90
|
|
|
96
91
|
async open() {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (!ports.length) return false;
|
|
100
|
-
|
|
101
|
-
if (this.cfg.reconnect) this.retry = true;
|
|
92
|
+
const ports = await navigator.serial.getPorts();
|
|
93
|
+
if (!ports.length) return false;
|
|
102
94
|
|
|
103
|
-
|
|
95
|
+
if (this.cfg.reconnect) this.retry = true;
|
|
104
96
|
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
this._open();
|
|
98
|
+
return true;
|
|
107
99
|
}
|
|
108
|
-
|
|
109
100
|
async _open() {
|
|
110
|
-
if (this.
|
|
101
|
+
if (this._state !== SerialJS.State.Closed) return;
|
|
111
102
|
|
|
112
103
|
this._change(SerialJS.State.Opening);
|
|
113
104
|
|
|
114
105
|
try {
|
|
115
|
-
await this._close();
|
|
116
106
|
await this._setLastPort();
|
|
117
107
|
|
|
118
108
|
if (!this._port) {
|
|
119
|
-
|
|
120
|
-
return;
|
|
109
|
+
throw new Error('No port');
|
|
121
110
|
}
|
|
122
111
|
|
|
112
|
+
if (this._state === SerialJS.State.Closing) return;
|
|
113
|
+
|
|
123
114
|
await this._port.open({ baudRate: this.cfg.baud });
|
|
124
115
|
|
|
116
|
+
if (this._state === SerialJS.State.Closing) {
|
|
117
|
+
await this._port.close();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
125
121
|
this.writer = this._port.writable.getWriter();
|
|
126
122
|
this.reader = this._port.readable.getReader();
|
|
127
123
|
|
|
@@ -135,7 +131,7 @@ export default class SerialJS {
|
|
|
135
131
|
|
|
136
132
|
if (value) {
|
|
137
133
|
try {
|
|
138
|
-
this.onbin(value);
|
|
134
|
+
this.onbin?.(value);
|
|
139
135
|
} catch (e) {
|
|
140
136
|
this._error(e);
|
|
141
137
|
}
|
|
@@ -153,10 +149,6 @@ export default class SerialJS {
|
|
|
153
149
|
|
|
154
150
|
this._sender.reset();
|
|
155
151
|
|
|
156
|
-
if (this._state !== SerialJS.State.Closing) {
|
|
157
|
-
this._change(SerialJS.State.Closing);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
152
|
try {
|
|
161
153
|
if (this.reader) this.reader.releaseLock();
|
|
162
154
|
} catch (e) { }
|
|
@@ -175,25 +167,27 @@ export default class SerialJS {
|
|
|
175
167
|
this._change(SerialJS.State.Closed);
|
|
176
168
|
|
|
177
169
|
if (this.retry) {
|
|
178
|
-
setTimeout(() =>
|
|
170
|
+
setTimeout(() => {
|
|
171
|
+
if (this.retry) this._open();
|
|
172
|
+
}, this.cfg.reconnect);
|
|
179
173
|
}
|
|
180
174
|
}
|
|
181
175
|
|
|
182
176
|
async close() {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return true;
|
|
188
|
-
});
|
|
177
|
+
this.retry = false;
|
|
178
|
+
this._sender.reset();
|
|
179
|
+
await this._close();
|
|
180
|
+
return true;
|
|
189
181
|
}
|
|
190
|
-
|
|
191
182
|
async _close() {
|
|
192
183
|
switch (this._state) {
|
|
193
184
|
case SerialJS.State.Closed:
|
|
194
185
|
return;
|
|
195
186
|
|
|
196
187
|
case SerialJS.State.Opening:
|
|
188
|
+
this._change(SerialJS.State.Closing);
|
|
189
|
+
break;
|
|
190
|
+
|
|
197
191
|
case SerialJS.State.Open:
|
|
198
192
|
this._change(SerialJS.State.Closing);
|
|
199
193
|
|
|
@@ -204,13 +198,9 @@ export default class SerialJS {
|
|
|
204
198
|
}
|
|
205
199
|
|
|
206
200
|
break;
|
|
207
|
-
|
|
208
|
-
case SerialJS.State.Closing:
|
|
209
|
-
break;
|
|
210
201
|
}
|
|
211
202
|
|
|
212
203
|
let i = 0;
|
|
213
|
-
|
|
214
204
|
while (this._state === SerialJS.State.Closing) {
|
|
215
205
|
await sleep(10);
|
|
216
206
|
|
|
@@ -231,32 +221,25 @@ export default class SerialJS {
|
|
|
231
221
|
|
|
232
222
|
return this._sender.runNothrow(async () => {
|
|
233
223
|
if (!this.opened() || !this.writer) return false;
|
|
234
|
-
|
|
235
224
|
await this.writer.write(data);
|
|
236
225
|
return true;
|
|
237
226
|
});
|
|
238
227
|
}
|
|
239
228
|
|
|
229
|
+
//#region private
|
|
240
230
|
_port = null;
|
|
241
|
-
_state = SerialJS.State.Closed;
|
|
242
|
-
|
|
243
|
-
reader = null;
|
|
244
|
-
writer = null;
|
|
245
|
-
retry = false;
|
|
246
|
-
|
|
247
231
|
_decoder = new TextDecoder();
|
|
248
232
|
_sender = new SerialExecutor();
|
|
249
|
-
|
|
233
|
+
_state = SerialJS.State.Closed;
|
|
250
234
|
|
|
251
235
|
async _setLastPort() {
|
|
252
|
-
|
|
236
|
+
let ports = await navigator.serial.getPorts();
|
|
253
237
|
this._port = ports.length ? ports[0] : null;
|
|
254
238
|
}
|
|
255
239
|
|
|
256
240
|
_error(e) {
|
|
257
241
|
this.onerror('[SerialJS] ' + e);
|
|
258
242
|
}
|
|
259
|
-
|
|
260
243
|
_change(s) {
|
|
261
244
|
if (this._state === s) return;
|
|
262
245
|
|
|
@@ -264,13 +247,8 @@ export default class SerialJS {
|
|
|
264
247
|
this.onchange(s);
|
|
265
248
|
|
|
266
249
|
switch (s) {
|
|
267
|
-
case SerialJS.State.Open:
|
|
268
|
-
|
|
269
|
-
break;
|
|
270
|
-
|
|
271
|
-
case SerialJS.State.Closed:
|
|
272
|
-
this.onclose();
|
|
273
|
-
break;
|
|
250
|
+
case SerialJS.State.Open: this.onopen(); break;
|
|
251
|
+
case SerialJS.State.Closed: this.onclose(); break;
|
|
274
252
|
}
|
|
275
253
|
}
|
|
276
254
|
}
|
package/serial.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const t=t=>new Promise(e=>setTimeout(e,t));class e{ontext=null;constructor(t=/\r?\n/,e=!1){this.eol=t,this.skip=e}reset(){this._buf=""}write(t){if(!this.ontext)return;if(!this.eol)return void this.ontext(t);this._buf+=t;let e=this._buf.split(this.eol);1!=e.length&&(e[e.length-1].length?this._buf=e.pop():(this._buf="",e.pop()),this.skip&&(e.shift(),this.skip=!1),e.forEach(t=>this.ontext(t)))}_buf=""}class s{constructor(){this._session=0,this.reset()}run(t){const e=this._session,s=this._queue.then(()=>{if(e!==this._session)throw new Error("Queue empty");return t()});return this._queue=s.catch(()=>{}),s}runNothrow(t){return this.run(t).catch(()=>null)}reset(){this._session++,this._queue=Promise.resolve()}}class r{static State={Closed:"closed",Opening:"opening",Open:"open",Closing:"closing"};ontext=null;
|
|
1
|
+
const t=t=>new Promise(e=>setTimeout(e,t));class e{ontext=null;constructor(t=/\r?\n/,e=!1){this.eol=t,this.skip=e}reset(){this._buf=""}write(t){if(!this.ontext)return;if(!this.eol)return void this.ontext(t);this._buf+=t;let e=this._buf.split(this.eol);1!=e.length&&(e[e.length-1].length?this._buf=e.pop():(this._buf="",e.pop()),this.skip&&(e.shift(),this.skip=!1),e.forEach(t=>this.ontext(t)))}_buf=""}class s{constructor(){this._session=0,this.reset()}run(t){const e=this._session,s=this._queue.then(()=>{if(e!==this._session)throw new Error("Queue empty");return t()});return this._queue=s.catch(()=>{}),s}runNothrow(t){return this.run(t).catch(()=>null)}reset(){this._session++,this._queue=Promise.resolve()}}class r{static State={Closed:"closed",Opening:"opening",Open:"open",Closing:"closing"};onbin=null;ontext=null;onopen(){}onclose(){}onchange(t){}onselect(t){}onerror(t){}constructor(t={}){this.cfg={eol:/\r?\n/,baud:115200,auto_open:!1,reconnect:1e3,...t},this._setLastPort().then(()=>this.onselect(this.getName())),this.splitter=new e(this.cfg.eol),this.splitter.ontext=t=>{try{this.ontext?.(t)}catch(t){this._error(t)}}}config(t={}){this.cfg={...this.cfg,...t},this.splitter.eol=this.cfg.eol}static supported(){return"serial"in navigator}opened(){return this._state==r.State.Open}selected(){return!!this._port}getName(){if(!this._port)return"None";switch(this._port.getInfo().usbProductId){case 21971:return"CH343";case 30084:return"CH340S";case 29986:case 29987:return"CH340";case 21778:case 21795:case 21892:return"CH341";case 1026:case 1027:case 1028:case 1029:case 24577:case 1538:case 24592:return"FT232";case 38144:case 258:case 1281:case 32937:case 6e4:case 60001:case 60003:return"CP210x"}return"Unknown"}async select(){try{await this.close(),this._port=null;let e=await navigator.serial.getPorts();for(let t of e)await t.forget();await t(50),await navigator.serial.requestPort(),await this._setLastPort()}catch(t){this._error(t)}return this.onselect(this.getName()),this.cfg.auto_open&&this.open(),this.selected()}async open(){return!!(await navigator.serial.getPorts()).length&&(this.cfg.reconnect&&(this.retry=!0),this._open(),!0)}async _open(){if(this._state===r.State.Closed){this._change(r.State.Opening);try{if(await this._setLastPort(),!this._port)throw new Error("No port");if(this._state===r.State.Closing)return;if(await this._port.open({baudRate:this.cfg.baud}),this._state===r.State.Closing)return void await this._port.close();for(this.writer=this._port.writable.getWriter(),this.reader=this._port.readable.getReader(),this._sender.reset(),this._change(r.State.Open);this._state===r.State.Open;){const{value:t,done:e}=await this.reader.read();if(e)break;if(t){try{this.onbin?.(t)}catch(t){this._error(t)}this.ontext&&this.splitter.write(this._decoder.decode(t,{stream:!0}))}}}catch(t){this._error(t)}this._sender.reset();try{this.reader&&this.reader.releaseLock()}catch(t){}try{this.writer&&this.writer.releaseLock()}catch(t){}this.reader=null,this.writer=null;try{this._port&&await this._port.close()}catch(t){}this._change(r.State.Closed),this.retry&&setTimeout(()=>{this.retry&&this._open()},this.cfg.reconnect)}}async close(){return this.retry=!1,this._sender.reset(),await this._close(),!0}async _close(){switch(this._state){case r.State.Closed:return;case r.State.Opening:this._change(r.State.Closing);break;case r.State.Open:if(this._change(r.State.Closing),this.reader)try{await this.reader.cancel()}catch(t){}}let e=0;for(;this._state===r.State.Closing;)if(await t(10),++e>200){this._error("Close timeout"),this._change(r.State.Closed);break}}async sendText(t){return this.sendBin((new TextEncoder).encode(t))}async sendBin(t){return!(!this.opened()||!this.writer)&&this._sender.runNothrow(async()=>!(!this.opened()||!this.writer||(await this.writer.write(t),0)))}_port=null;_decoder=new TextDecoder;_sender=new s;_state=r.State.Closed;async _setLastPort(){let t=await navigator.serial.getPorts();this._port=t.length?t[0]:null}_error(t){this.onerror("[SerialJS] "+t)}_change(t){if(this._state!==t)switch(this._state=t,this.onchange(t),t){case r.State.Open:this.onopen();break;case r.State.Closed:this.onclose()}}}export{r as default};
|