@alexgyver/serial 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -5,7 +5,11 @@
5
5
  - Буферизация отправки
6
6
  - Буферизация приёма, разделение текста по разделителю
7
7
 
8
- > npm i @alexgyver/serial
8
+ [demo](https://gyverlibs.github.io/Serial.js/test/)
9
+
10
+ > **Browser**: https://gyverlibs.github.io/Serial.js/Serial.min.js
11
+
12
+ > **Node**: npm i @alexgyver/serial
9
13
 
10
14
  ## Дока
11
15
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alexgyver/serial",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Web Serial API wrapper",
5
5
  "main": "./serial.js",
6
6
  "module": "./serial.js",
@@ -14,13 +14,14 @@
14
14
  "url": "git+https://github.com/GyverLibs/Serial.js.git"
15
15
  },
16
16
  "devDependencies": {
17
- "webpack": "^5.103.0",
18
- "webpack-cli": "^6.0.1",
19
- "webpack-dev-server": "^5.2.2",
20
- "html-webpack-plugin": "^5.6.5"
17
+ "webpack": "^5.106.2",
18
+ "webpack-cli": "^7.0.2",
19
+ "webpack-dev-server": "^5.2.4",
20
+ "style-loader": "^4.0.0",
21
+ "css-loader": "^7.1.4"
21
22
  },
22
23
  "dependencies": {
23
- "@alexgyver/utils": "^1.2.4"
24
+ "@alexgyver/utils": "^1.2.6"
24
25
  },
25
26
  "author": "AlexGyver <alex@alexgyver.ru>",
26
27
  "license": "MIT"
package/serial.js CHANGED
@@ -1,4 +1,4 @@
1
- import { sleep, ShiftBuffer, StreamSplitter } from "@alexgyver/utils";
1
+ import { sleep, StreamSplitter, SerialExecutor } from "@alexgyver/utils";
2
2
 
3
3
  export default class SerialJS {
4
4
  static State = {
@@ -8,17 +8,14 @@ export default class SerialJS {
8
8
  Closing: 'closing',
9
9
  };
10
10
 
11
- //#region handlers
12
- onbin = null;
13
11
  ontext = null;
14
-
12
+ onbin(b) { }
15
13
  onopen() { }
16
14
  onclose() { }
17
15
  onchange(s) { }
18
16
  onselect(name) { }
19
17
  onerror(e) { }
20
18
 
21
- //#region constructor
22
19
  constructor(params = {}) {
23
20
  const def = {
24
21
  eol: /\r?\n/,
@@ -26,14 +23,21 @@ export default class SerialJS {
26
23
  auto_open: false,
27
24
  reconnect: 1000,
28
25
  };
26
+
29
27
  this.cfg = { ...def, ...params };
30
28
 
31
- this._setLastPort().then(() => this.onselect(this.getName()));
32
29
  this.splitter = new StreamSplitter(this.cfg.eol);
33
- this.splitter.ontext = (t) => this.ontext(t);
30
+ this.splitter.ontext = (t) => {
31
+ try {
32
+ if (this.ontext) this.ontext(t);
33
+ } catch (e) {
34
+ this._error(e);
35
+ }
36
+ };
37
+
38
+ this._setLastPort().then(() => this.onselect(this.getName()));
34
39
  }
35
40
 
36
- //#region methods
37
41
  config(params = {}) {
38
42
  this.cfg = { ...this.cfg, ...params };
39
43
  this.splitter.eol = this.cfg.eol;
@@ -44,7 +48,7 @@ export default class SerialJS {
44
48
  }
45
49
 
46
50
  opened() {
47
- return this._state == SerialJS.State.Open;
51
+ return this._state === SerialJS.State.Open;
48
52
  }
49
53
 
50
54
  selected() {
@@ -62,133 +66,211 @@ export default class SerialJS {
62
66
  case 0x0402: case 0x0403: case 0x0404: case 0x0405: case 0x6001: case 0x0602: case 0x6010: return 'FT232';
63
67
  case 0x9500: case 0x0102: case 0x0501: case 0x80a9: case 0xea60: case 0xea61: case 0xea63: return 'CP210x';
64
68
  }
69
+
65
70
  return 'Unknown';
66
71
  }
67
72
 
68
73
  async select() {
69
74
  try {
70
75
  await this.close();
76
+
71
77
  this._port = null;
72
- let ports = await navigator.serial.getPorts();
73
- for (let p of ports) await p.forget();
78
+
79
+ const ports = await navigator.serial.getPorts();
80
+ for (const p of ports) await p.forget();
81
+
74
82
  await sleep(50);
75
83
  await navigator.serial.requestPort();
76
84
  await this._setLastPort();
77
85
  } catch (e) {
78
86
  this._error(e);
79
87
  }
88
+
80
89
  this.onselect(this.getName());
90
+
81
91
  if (this.cfg.auto_open) this.open();
92
+
82
93
  return this.selected();
83
94
  }
84
95
 
85
96
  async open() {
86
- if (this.cfg.reconnect) this.retry = true;
87
- await this._open();
97
+ return this._lifecycle.runNothrow(async () => {
98
+ const ports = await navigator.serial.getPorts();
99
+ if (!ports.length) return false;
100
+
101
+ if (this.cfg.reconnect) this.retry = true;
102
+
103
+ await this._open();
104
+
105
+ return this.opened();
106
+ });
88
107
  }
108
+
89
109
  async _open() {
90
- if (this.opened()) return;
110
+ if (this.opened() || this._state === SerialJS.State.Opening) return;
111
+
91
112
  this._change(SerialJS.State.Opening);
92
113
 
93
114
  try {
94
115
  await this._close();
95
116
  await this._setLastPort();
117
+
118
+ if (!this._port) {
119
+ this._change(SerialJS.State.Closed);
120
+ return;
121
+ }
122
+
96
123
  await this._port.open({ baudRate: this.cfg.baud });
124
+
97
125
  this.writer = this._port.writable.getWriter();
98
126
  this.reader = this._port.readable.getReader();
99
- this._buffer.clear();
127
+
128
+ this._sender.reset();
100
129
  this._change(SerialJS.State.Open);
101
130
 
102
- while (this._state == SerialJS.State.Open) {
131
+ while (this._state === SerialJS.State.Open) {
103
132
  const { value, done } = await this.reader.read();
133
+
104
134
  if (done) break;
135
+
105
136
  if (value) {
106
- if (this.onbin) this.onbin(value);
107
- if (this.ontext) this.splitter.write(this._decoder.decode(value, { stream: true }));
137
+ try {
138
+ this.onbin(value);
139
+ } catch (e) {
140
+ this._error(e);
141
+ }
142
+
143
+ if (this.ontext) {
144
+ this.splitter.write(
145
+ this._decoder.decode(value, { stream: true })
146
+ );
147
+ }
108
148
  }
109
149
  }
110
150
  } catch (e) {
111
151
  this._error(e);
112
- this._change(SerialJS.State.Closed);
113
- if (this.retry) setTimeout(() => this._open(), this.cfg.reconnect);
114
152
  }
115
153
 
116
- if (this.reader) this.reader.releaseLock();
117
- if (this.writer) this.writer.releaseLock();
154
+ this._sender.reset();
155
+
156
+ if (this._state !== SerialJS.State.Closing) {
157
+ this._change(SerialJS.State.Closing);
158
+ }
159
+
160
+ try {
161
+ if (this.reader) this.reader.releaseLock();
162
+ } catch (e) { }
163
+
164
+ try {
165
+ if (this.writer) this.writer.releaseLock();
166
+ } catch (e) { }
167
+
118
168
  this.reader = null;
119
169
  this.writer = null;
120
170
 
121
171
  try {
122
- await this._port.close();
123
- this._change(SerialJS.State.Closed);
172
+ if (this._port) await this._port.close();
124
173
  } catch (e) { }
174
+
175
+ this._change(SerialJS.State.Closed);
176
+
177
+ if (this.retry) {
178
+ setTimeout(() => this._lifecycle.runNothrow(() => this._open()), this.cfg.reconnect);
179
+ }
125
180
  }
126
181
 
127
182
  async close() {
128
- this.retry = false;
129
- await this._close();
183
+ return this._lifecycle.runNothrow(async () => {
184
+ this.retry = false;
185
+ this._sender.reset();
186
+ await this._close();
187
+ return true;
188
+ });
130
189
  }
190
+
131
191
  async _close() {
132
192
  switch (this._state) {
133
- case SerialJS.State.Closed: return;
193
+ case SerialJS.State.Closed:
194
+ return;
195
+
196
+ case SerialJS.State.Opening:
134
197
  case SerialJS.State.Open:
135
- if (this.reader) await this.reader.cancel();
136
198
  this._change(SerialJS.State.Closing);
199
+
200
+ if (this.reader) {
201
+ try {
202
+ await this.reader.cancel();
203
+ } catch (e) { }
204
+ }
205
+
206
+ break;
207
+
208
+ case SerialJS.State.Closing:
137
209
  break;
138
210
  }
139
211
 
140
212
  let i = 0;
141
- while (this._state == SerialJS.State.Closing) {
213
+
214
+ while (this._state === SerialJS.State.Closing) {
142
215
  await sleep(10);
216
+
143
217
  if (++i > 200) {
144
218
  this._error('Close timeout');
145
219
  this._change(SerialJS.State.Closed);
146
220
  break;
147
221
  }
148
222
  }
149
-
150
223
  }
151
224
 
152
225
  async sendText(text) {
153
- await this.sendBin((new TextEncoder()).encode(text));
226
+ return this.sendBin(new TextEncoder().encode(text));
154
227
  }
155
228
 
156
229
  async sendBin(data) {
157
- this._buffer.push(data);
158
- this._send();
230
+ if (!this.opened() || !this.writer) return false;
231
+
232
+ return this._sender.runNothrow(async () => {
233
+ if (!this.opened() || !this.writer) return false;
234
+
235
+ await this.writer.write(data);
236
+ return true;
237
+ });
159
238
  }
160
239
 
161
- //#region private
162
240
  _port = null;
163
241
  _state = SerialJS.State.Closed;
164
- _buffer = new ShiftBuffer();
242
+
243
+ reader = null;
244
+ writer = null;
245
+ retry = false;
246
+
165
247
  _decoder = new TextDecoder();
248
+ _sender = new SerialExecutor();
249
+ _lifecycle = new SerialExecutor();
166
250
 
167
- async _send() {
168
- if (this._busy) return;
169
- this._busy = true;
170
- while (this._buffer.length && this.writer) {
171
- let d = this._buffer.shiftAll();
172
- try {
173
- await this.writer.write(d);
174
- } catch (e) { }
175
- }
176
- this._busy = false;
177
- }
178
251
  async _setLastPort() {
179
- let ports = await navigator.serial.getPorts();
252
+ const ports = await navigator.serial.getPorts();
180
253
  this._port = ports.length ? ports[0] : null;
181
254
  }
182
255
 
183
256
  _error(e) {
184
257
  this.onerror('[SerialJS] ' + e);
185
258
  }
259
+
186
260
  _change(s) {
261
+ if (this._state === s) return;
262
+
187
263
  this._state = s;
188
264
  this.onchange(s);
265
+
189
266
  switch (s) {
190
- case SerialJS.State.Open: this.onopen(); break;
191
- case SerialJS.State.Closed: this.onclose(); break;
267
+ case SerialJS.State.Open:
268
+ this.onopen();
269
+ break;
270
+
271
+ case SerialJS.State.Closed:
272
+ this.onclose();
273
+ break;
192
274
  }
193
275
  }
194
276
  }
package/test/index.html CHANGED
@@ -3,8 +3,7 @@
3
3
 
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
7
- <script src="script.js" type="module" defer="defer"></script>
6
+ <script src="./script.js" type="module"></script>
8
7
  <title>Serial test</title>
9
8
  </head>
10
9
 
package/test/script.js CHANGED
@@ -1,4 +1,5 @@
1
- import SerialJS from "https://gyverlibs.github.io/Serial.js/serial.min.js";
1
+ import SerialJS from 'https://gyverlibs.github.io/Serial.js/Serial.min.js'
2
+ // import SerialJS from "../serial";
2
3
 
3
4
  let i = 0;
4
5
  let ser = new SerialJS();
@@ -1,39 +1,24 @@
1
1
  const path = require('path');
2
- const PACKAGE = require('./package.json');
3
- const HtmlWebpackPlugin = require('html-webpack-plugin');
4
2
 
5
3
  module.exports = {
6
- entry: {
7
- index: './test_dev/script.js',
8
- },
9
-
4
+ entry: './test/script.js',
10
5
  output: {
11
6
  filename: 'script.js',
12
- path: path.resolve(__dirname, 'dev'),
13
- clean: true,
7
+ path: path.resolve(__dirname, 'test'),
8
+ clean: false,
9
+ },
10
+ module: {
11
+ rules: [
12
+ {
13
+ test: /\.css$/,
14
+ use: ['style-loader', 'css-loader'],
15
+ }
16
+ ]
14
17
  },
15
-
16
- plugins: [
17
- new HtmlWebpackPlugin({
18
- template: `./test_dev/index.html`,
19
- filename: `index.html`,
20
- inject: true,
21
- minify: false,
22
- version: PACKAGE.version,
23
- title: PACKAGE.title,
24
- }),
25
- ],
26
-
27
18
  devServer: {
28
- watchFiles: ['test_dev/*.html'],
29
- static: path.resolve(__dirname, './dev'),
19
+ static: path.resolve(__dirname, 'test'),
30
20
  hot: true,
31
21
  open: true,
32
22
  },
33
-
34
- watchOptions: {
35
- poll: 1000,
36
- },
37
-
38
23
  mode: 'development',
39
24
  };
@@ -1,18 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
7
- <script src="script.js" type="module" defer="defer"></script>
8
- <title>Serial test</title>
9
- </head>
10
-
11
- <body>
12
- <button id="select_b">select</button>
13
- <button id="open_b">open</button>
14
- <button id="close_b">close</button>
15
- <button id="send_b">send</button>
16
- </body>
17
-
18
- </html>
@@ -1,31 +0,0 @@
1
- import SerialJS from "../serial";
2
-
3
- let i = 0;
4
- let ser = new SerialJS();
5
-
6
- // control
7
- select_b.onclick = () => ser.select();
8
- open_b.onclick = () => ser.open();
9
- close_b.onclick = () => ser.close();
10
- send_b.onclick = () => ser.sendText('Hello ' + i++);
11
-
12
- // read
13
- // ser.onbin = b => console.log(b);
14
- ser.ontext = t => console.log(t);
15
-
16
- // state
17
- // ser.onopen = () => {
18
- // console.log('Opened', ser.getName());
19
- // }
20
- // ser.onclose = () => {
21
- // console.log('Closed');
22
- // }
23
- ser.onchange = s => {
24
- console.log(s);
25
- }
26
- ser.onerror = e => {
27
- console.log(e);
28
- }
29
- ser.onselect = (port) => {
30
- console.log('select', port);
31
- }