@alexgyver/serial 1.0.10 → 1.0.12
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/.github/workflows/pio-publish.yml +32 -0
- package/.github/workflows/tg-send.yml +35 -0
- package/README.md +16 -2
- package/README_EN.md +45 -0
- package/package.json +6 -6
- package/serial.js +93 -33
- package/serial.min.js +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
name: Publish to PlatformIO Registry
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout release tag
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
ref: ${{ github.event.release.tag_name }}
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.x"
|
|
22
|
+
|
|
23
|
+
- name: Install PlatformIO
|
|
24
|
+
run: pip install -U platformio
|
|
25
|
+
|
|
26
|
+
- name: Check package
|
|
27
|
+
run: pio pkg pack
|
|
28
|
+
|
|
29
|
+
- name: Publish to PlatformIO Registry
|
|
30
|
+
env:
|
|
31
|
+
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
|
32
|
+
run: pio pkg publish --owner gyverlibs --non-interactive
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
name: Telegram Message
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
name: Send Message
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- name: Check if major or minor release
|
|
12
|
+
id: semver
|
|
13
|
+
shell: bash
|
|
14
|
+
run: |
|
|
15
|
+
TAG="${{ github.event.release.tag_name }}"
|
|
16
|
+
VERSION="${TAG#v}"
|
|
17
|
+
PATCH="$(echo "$VERSION" | cut -d. -f3)"
|
|
18
|
+
|
|
19
|
+
if [[ "$PATCH" == "0" ]]; then
|
|
20
|
+
echo "should_send=true" >> "$GITHUB_OUTPUT"
|
|
21
|
+
else
|
|
22
|
+
echo "should_send=false" >> "$GITHUB_OUTPUT"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
- name: send telegram message on release
|
|
26
|
+
if: steps.semver.outputs.should_send == 'true'
|
|
27
|
+
uses: appleboy/telegram-action@master
|
|
28
|
+
with:
|
|
29
|
+
to: ${{ secrets.TELEGRAM_TO }}
|
|
30
|
+
token: ${{ secrets.TELEGRAM_TOKEN }}
|
|
31
|
+
disable_web_page_preview: true
|
|
32
|
+
message: |
|
|
33
|
+
${{ github.event.repository.name }} ${{ github.event.release.tag_name }}
|
|
34
|
+
${{ github.event.release.body }}
|
|
35
|
+
https://github.com/${{ github.repository }}
|
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Serial.js
|
|
2
2
|
Обёртка на Web Serial API
|
|
3
3
|
- Автоматическое переподключение
|
|
4
|
-
-
|
|
4
|
+
- Восстановление ранее разрешённого порта
|
|
5
|
+
- Безопасная работа с несколькими разрешёнными портами
|
|
5
6
|
- Буферизация отправки
|
|
6
7
|
- Буферизация приёма, разделение текста по разделителю
|
|
7
8
|
|
|
@@ -19,6 +20,7 @@ config(params = {});
|
|
|
19
20
|
// baud: 115200
|
|
20
21
|
// auto_open: false
|
|
21
22
|
// reconnect: 1000
|
|
23
|
+
// forgetOtherPorts: true
|
|
22
24
|
|
|
23
25
|
onbin(b);
|
|
24
26
|
ontext(t);
|
|
@@ -32,12 +34,24 @@ onerror(e);
|
|
|
32
34
|
static supported();
|
|
33
35
|
opened();
|
|
34
36
|
selected();
|
|
37
|
+
getInfo();
|
|
35
38
|
getName();
|
|
36
39
|
|
|
37
40
|
select();
|
|
41
|
+
restore();
|
|
42
|
+
getPorts();
|
|
43
|
+
forget();
|
|
38
44
|
open();
|
|
39
45
|
close();
|
|
40
46
|
|
|
41
47
|
sendBin(data);
|
|
42
48
|
sendText(text);
|
|
43
|
-
```
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`select()` использует порт, возвращённый системным диалогом выбора. По умолчанию `forgetOtherPorts: true` - разрешение остаётся только у выбранного порта, поэтому после перезагрузки страницы его можно восстановить автоматически.
|
|
52
|
+
|
|
53
|
+
Для приложений, работающих с несколькими портами, нужен `forgetOtherPorts: false`. В этом режиме библиотека не отзывает чужие разрешения, а `restore()` автоматически выбирает порт только тогда, когда разрешён ровно один. Если портов несколько, надо вызвать `select()`.
|
|
54
|
+
|
|
55
|
+
- `getPorts()` возвращает все ранее разрешённые порты
|
|
56
|
+
- `restore()` восстанавливает порт без системного диалога, если выбор однозначен
|
|
57
|
+
- `forget()` закрывает текущий порт и отзывает только его разрешение
|
package/README_EN.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
This is an automatic translation and may be incorrect in some places. See the source README and examples for authoritative information.
|
|
2
|
+
|
|
3
|
+
# Serial.js
|
|
4
|
+
Wrapper on Web Serial API
|
|
5
|
+
- Automatic reconnection
|
|
6
|
+
- Preservation of the last selected port
|
|
7
|
+
- Shipment buffering
|
|
8
|
+
- Reception buffering, separation of text by separator
|
|
9
|
+
|
|
10
|
+
[demo](https://gyverlibs.github.io/Serial.js/test/)
|
|
11
|
+
|
|
12
|
+
> **Browser**: https://gyverlibs.github.io/Serial.js/Serial.min.js
|
|
13
|
+
|
|
14
|
+
> **Node**: npm i @alexgyver/serial
|
|
15
|
+
|
|
16
|
+
## Doc.
|
|
17
|
+
```js
|
|
18
|
+
constructor(params = {});
|
|
19
|
+
config(params = {});
|
|
20
|
+
// eol: /\r?\n/
|
|
21
|
+
// baud: 115200
|
|
22
|
+
// auto_open: false
|
|
23
|
+
// reconnect: 1000
|
|
24
|
+
|
|
25
|
+
onbin(b);
|
|
26
|
+
ontext(t);
|
|
27
|
+
|
|
28
|
+
onopen():
|
|
29
|
+
onclose():
|
|
30
|
+
onchange(s):
|
|
31
|
+
onselect(name);
|
|
32
|
+
onerror(e);
|
|
33
|
+
|
|
34
|
+
static supported();
|
|
35
|
+
opened();
|
|
36
|
+
selected();
|
|
37
|
+
getName();
|
|
38
|
+
|
|
39
|
+
select();
|
|
40
|
+
open();
|
|
41
|
+
close();
|
|
42
|
+
|
|
43
|
+
sendBin(data);
|
|
44
|
+
sendText(text);
|
|
45
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alexgyver/serial",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "Web Serial API wrapper",
|
|
5
5
|
"main": "./serial.js",
|
|
6
6
|
"module": "./serial.js",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"url": "git+https://github.com/GyverLibs/Serial.js.git"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"webpack": "^5.
|
|
18
|
-
"webpack-cli": "^7.
|
|
19
|
-
"webpack-dev-server": "^
|
|
17
|
+
"webpack": "^5.110.2",
|
|
18
|
+
"webpack-cli": "^7.2.3",
|
|
19
|
+
"webpack-dev-server": "^6.0.0",
|
|
20
20
|
"style-loader": "^4.0.0",
|
|
21
|
-
"css-loader": "^7.1.
|
|
21
|
+
"css-loader": "^7.1.5"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@alexgyver/utils": "^1.2.
|
|
24
|
+
"@alexgyver/utils": "^1.2.18"
|
|
25
25
|
},
|
|
26
26
|
"author": "AlexGyver <alex@alexgyver.ru>",
|
|
27
27
|
"license": "MIT"
|
package/serial.js
CHANGED
|
@@ -25,10 +25,11 @@ export default class SerialJS {
|
|
|
25
25
|
baud: 115200,
|
|
26
26
|
auto_open: false,
|
|
27
27
|
reconnect: 1000,
|
|
28
|
+
forgetOtherPorts: true,
|
|
28
29
|
};
|
|
29
30
|
this.cfg = { ...def, ...params };
|
|
30
31
|
|
|
31
|
-
this.
|
|
32
|
+
this.restore().then(() => this.onselect(this.getName()));
|
|
32
33
|
this.splitter = new StreamSplitter(this.cfg.eol);
|
|
33
34
|
this.splitter.ontext = (t) => {
|
|
34
35
|
try {
|
|
@@ -57,10 +58,14 @@ export default class SerialJS {
|
|
|
57
58
|
return !!this._port;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
getInfo() {
|
|
62
|
+
return this._port?.getInfo() ?? null;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
getName() {
|
|
61
|
-
if (!this._port) return
|
|
66
|
+
if (!this._port) return 'None';
|
|
62
67
|
|
|
63
|
-
switch (this.
|
|
68
|
+
switch (this.getInfo().usbProductId) {
|
|
64
69
|
case 0x55d3: return 'CH343';
|
|
65
70
|
case 0x7584: return 'CH340S';
|
|
66
71
|
case 0x7522: case 0x7523: return 'CH340';
|
|
@@ -74,48 +79,87 @@ export default class SerialJS {
|
|
|
74
79
|
async select() {
|
|
75
80
|
try {
|
|
76
81
|
await this.close();
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
const port = await navigator.serial.requestPort();
|
|
83
|
+
|
|
84
|
+
if (this.cfg.forgetOtherPorts) {
|
|
85
|
+
const ports = await navigator.serial.getPorts();
|
|
86
|
+
for (const p of ports) {
|
|
87
|
+
if (p !== port) await p.forget();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this._port = port;
|
|
83
92
|
} catch (e) {
|
|
84
93
|
this._error(e);
|
|
85
94
|
}
|
|
86
95
|
this.onselect(this.getName());
|
|
87
|
-
if (this.cfg.auto_open) this.open();
|
|
96
|
+
if (this.cfg.auto_open) return this.open();
|
|
97
|
+
return this.selected();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getPorts() {
|
|
101
|
+
return navigator.serial.getPorts();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async restore() {
|
|
105
|
+
const ports = await this.getPorts();
|
|
106
|
+
this._port = this.cfg.forgetOtherPorts
|
|
107
|
+
? (ports[0] ?? null)
|
|
108
|
+
: (ports.length === 1 ? ports[0] : null);
|
|
88
109
|
return this.selected();
|
|
89
110
|
}
|
|
90
111
|
|
|
112
|
+
async forget() {
|
|
113
|
+
await this.close();
|
|
114
|
+
if (!this._port) return false;
|
|
115
|
+
|
|
116
|
+
const port = this._port;
|
|
117
|
+
this._port = null;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await port.forget();
|
|
121
|
+
this.onselect(this.getName());
|
|
122
|
+
return true;
|
|
123
|
+
} catch (e) {
|
|
124
|
+
this._port = port;
|
|
125
|
+
this._error(e);
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
91
130
|
async open() {
|
|
92
|
-
|
|
93
|
-
if (
|
|
131
|
+
if (this.opened()) return true;
|
|
132
|
+
if (this._openPromise) return this._openPromise;
|
|
133
|
+
if (this._state !== SerialJS.State.Closed) return false;
|
|
94
134
|
|
|
95
135
|
if (this.cfg.reconnect) this.retry = true;
|
|
96
136
|
|
|
97
|
-
this.
|
|
98
|
-
|
|
137
|
+
const promise = this._connect();
|
|
138
|
+
this._openPromise = promise;
|
|
139
|
+
const result = await promise;
|
|
140
|
+
if (this._openPromise === promise) this._openPromise = null;
|
|
141
|
+
return result;
|
|
99
142
|
}
|
|
100
|
-
async
|
|
101
|
-
if (this._state !== SerialJS.State.Closed) return;
|
|
102
|
-
|
|
143
|
+
async _connect() {
|
|
103
144
|
this._change(SerialJS.State.Opening);
|
|
104
145
|
|
|
105
146
|
try {
|
|
106
|
-
await this.
|
|
147
|
+
if (!this._port) await this.restore();
|
|
107
148
|
|
|
108
149
|
if (!this._port) {
|
|
109
150
|
throw new Error('No port');
|
|
110
151
|
}
|
|
111
152
|
|
|
112
|
-
if (this._state === SerialJS.State.Closing)
|
|
153
|
+
if (this._state === SerialJS.State.Closing) {
|
|
154
|
+
await this._cleanup();
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
113
157
|
|
|
114
158
|
await this._port.open({ baudRate: this.cfg.baud });
|
|
115
159
|
|
|
116
160
|
if (this._state === SerialJS.State.Closing) {
|
|
117
|
-
await this.
|
|
118
|
-
return;
|
|
161
|
+
await this._cleanup();
|
|
162
|
+
return false;
|
|
119
163
|
}
|
|
120
164
|
|
|
121
165
|
this.writer = this._port.writable.getWriter();
|
|
@@ -123,7 +167,18 @@ export default class SerialJS {
|
|
|
123
167
|
|
|
124
168
|
this._sender.reset();
|
|
125
169
|
this._change(SerialJS.State.Open);
|
|
170
|
+
void this._listen();
|
|
171
|
+
return true;
|
|
172
|
+
} catch (e) {
|
|
173
|
+
this._error(e);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
await this._cleanup();
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
126
179
|
|
|
180
|
+
async _listen() {
|
|
181
|
+
try {
|
|
127
182
|
while (this._state === SerialJS.State.Open) {
|
|
128
183
|
const { value, done } = await this.reader.read();
|
|
129
184
|
|
|
@@ -147,6 +202,10 @@ export default class SerialJS {
|
|
|
147
202
|
this._error(e);
|
|
148
203
|
}
|
|
149
204
|
|
|
205
|
+
await this._cleanup();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async _cleanup() {
|
|
150
209
|
this._sender.reset();
|
|
151
210
|
|
|
152
211
|
try {
|
|
@@ -168,7 +227,7 @@ export default class SerialJS {
|
|
|
168
227
|
|
|
169
228
|
if (this.retry) {
|
|
170
229
|
setTimeout(() => {
|
|
171
|
-
if (this.retry) this.
|
|
230
|
+
if (this.retry) this.open();
|
|
172
231
|
}, this.cfg.reconnect);
|
|
173
232
|
}
|
|
174
233
|
}
|
|
@@ -219,11 +278,16 @@ export default class SerialJS {
|
|
|
219
278
|
async sendBin(data) {
|
|
220
279
|
if (!this.opened() || !this.writer) return false;
|
|
221
280
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
281
|
+
try {
|
|
282
|
+
return await this._sender.run(async () => {
|
|
283
|
+
if (!this.opened() || !this.writer) return false;
|
|
284
|
+
await this.writer.write(data);
|
|
285
|
+
return true;
|
|
286
|
+
});
|
|
287
|
+
} catch (e) {
|
|
288
|
+
if (this.opened()) this._error(e);
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
227
291
|
}
|
|
228
292
|
|
|
229
293
|
//#region private
|
|
@@ -231,11 +295,7 @@ export default class SerialJS {
|
|
|
231
295
|
_decoder = new TextDecoder();
|
|
232
296
|
_sender = new SerialExecutor();
|
|
233
297
|
_state = SerialJS.State.Closed;
|
|
234
|
-
|
|
235
|
-
async _setLastPort() {
|
|
236
|
-
let ports = await navigator.serial.getPorts();
|
|
237
|
-
this._port = ports.length ? ports[0] : null;
|
|
238
|
-
}
|
|
298
|
+
_openPromise = null;
|
|
239
299
|
|
|
240
300
|
_error(e) {
|
|
241
301
|
this.onerror('[SerialJS] ' + e);
|
|
@@ -251,4 +311,4 @@ export default class SerialJS {
|
|
|
251
311
|
case SerialJS.State.Closed: this.onclose(); break;
|
|
252
312
|
}
|
|
253
313
|
}
|
|
254
|
-
}
|
|
314
|
+
}
|
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"};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.
|
|
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,forgetOtherPorts:!0,...t},this.restore().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}getInfo(){return this._port?.getInfo()??null}getName(){if(!this._port)return"None";switch(this.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();const t=await navigator.serial.requestPort();if(this.cfg.forgetOtherPorts){const e=await navigator.serial.getPorts();for(const s of e)s!==t&&await s.forget()}this._port=t}catch(t){this._error(t)}return this.onselect(this.getName()),this.cfg.auto_open?this.open():this.selected()}async getPorts(){return navigator.serial.getPorts()}async restore(){const t=await this.getPorts();return this._port=this.cfg.forgetOtherPorts?t[0]??null:1===t.length?t[0]:null,this.selected()}async forget(){if(await this.close(),!this._port)return!1;const t=this._port;this._port=null;try{return await t.forget(),this.onselect(this.getName()),!0}catch(e){return this._port=t,this._error(e),!1}}async open(){if(this.opened())return!0;if(this._openPromise)return this._openPromise;if(this._state!==r.State.Closed)return!1;this.cfg.reconnect&&(this.retry=!0);const t=this._connect();this._openPromise=t;const e=await t;return this._openPromise===t&&(this._openPromise=null),e}async _connect(){this._change(r.State.Opening);try{if(this._port||await this.restore(),!this._port)throw new Error("No port");return this._state===r.State.Closing?(await this._cleanup(),!1):(await this._port.open({baudRate:this.cfg.baud}),this._state===r.State.Closing?(await this._cleanup(),!1):(this.writer=this._port.writable.getWriter(),this.reader=this._port.readable.getReader(),this._sender.reset(),this._change(r.State.Open),this._listen(),!0))}catch(t){this._error(t)}return await this._cleanup(),!1}async _listen(){try{for(;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)}await this._cleanup()}async _cleanup(){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){if(!this.opened()||!this.writer)return!1;try{return await this._sender.run(async()=>!(!this.opened()||!this.writer||(await this.writer.write(t),0)))}catch(t){return this.opened()&&this._error(t),!1}}_port=null;_decoder=new TextDecoder;_sender=new s;_state=r.State.Closed;_openPromise=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};
|