WebSerial

ํ˜„ํ–‰ ํ‘œ์ค€ โ€” ๋งˆ์ง€๋ง‰ ์—…๋ฐ์ดํŠธ

์ฐธ์—ฌ:
GitHub whatwg/serial (์ƒˆ ์ด์Šˆ, ์—ด๋ฆฐ ์ด์Šˆ)
Matrix์—์„œ ๋Œ€ํ™”ํ•˜๊ธฐ
์ปค๋ฐ‹:
GitHub whatwg/serial/commits
์ด ์ปค๋ฐ‹ ์‹œ์ ์˜ ์Šค๋ƒ…์ƒท
ํ…Œ์ŠคํŠธ:
web-platform-tests serial/ (์ง„ํ–‰ ์ค‘์ธ ์ž‘์—…)
๋ฒˆ์—ญ (๋น„๊ทœ๋ฒ”์ ):
ๆ—ฅๆœฌ่ชž
็ฎ€ไฝ“ไธญๆ–‡
ํ•œ๊ตญ์–ด

์ดˆ๋ก

WebSerial API๋Š” ์›น์‚ฌ์ดํŠธ์—์„œ ์ฝ๊ณ  ์“ฐ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋ฉฐ, ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ†ตํ•ด ์ง๋ ฌ ์žฅ์น˜์—์„œ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ API๋Š” ์›น๊ณผ ๋ฌผ๋ฆฌ์  ์„ธ๊ณ„๋ฅผ ์—ฐ๊ฒฐํ•˜๋ฉฐ, ๋ฌธ์„œ๊ฐ€ ์žฅ์น˜์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ, 3D ํ”„๋ฆฐํ„ฐ ๋ฐ ๊ธฐํƒ€ ์ง๋ ฌ ์žฅ์น˜ ๋“ฑ์ด ์ด์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋Š” ํ•ด์„ค ๋ฌธ์„œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ํ™•์žฅ ์‚ฌํ•ญ: Navigator ์ธํ„ฐํŽ˜์ด์Šค

[Exposed=Window, SecureContext]
partial interface Navigator {
  [SameObject] readonly attribute Serial serial;
};

1.1. serial ์†์„ฑ

๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ, serial ์†์„ฑ์ด ํ•ญ์ƒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์ด๋ฉฐ, ์ด๋Š” Serial ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค.

2. ํ™•์žฅ ์‚ฌํ•ญ: WorkerNavigator ์ธํ„ฐํŽ˜์ด์Šค

[Exposed=DedicatedWorker, SecureContext]
partial interface WorkerNavigator {
  [SameObject] readonly attribute Serial serial;
};

2.1. serial ์†์„ฑ

๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ, serial ์†์„ฑ์ด ํ•ญ์ƒ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค์ด๋ฉฐ, ์ด๋Š” Serial ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค์ž…๋‹ˆ๋‹ค.

3. Serial ์ธํ„ฐํŽ˜์ด์Šค

[Exposed=(DedicatedWorker, Window), SecureContext]
interface Serial : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  Promise<sequence<SerialPort>> getPorts();
  [Exposed=Window] Promise<SerialPort> requestPort(optional SerialPortRequestOptions options = {});
};

3.1. requestPort() ๋ฉ”์„œ๋“œ

์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ๋ฅผ ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•˜๋ฉด ์‚ฌ์ดํŠธ์—๋Š” ์–ด๋– ํ•œ ์žฅ์น˜์—๋„ ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ง๋ ฌ ์žฅ์น˜์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ์‚ฌ์ดํŠธ๋Š” ๋จผ์ € ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: requestPort(). ์ด ํ˜ธ์ถœ์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‚ฌ์ดํŠธ์—์„œ ์ œ์–ดํ•  ์žฅ์น˜๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฌผ์„ ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ๊ฐ€ ํŠน์ • ์žฅ์น˜์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์œผ๋ฉฐ, ๊ทธ ์žฅ์น˜๊ฐ€ ํ•ญ์ƒ USB๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ๋‹ค๋ฉด ์‚ฌ์ดํŠธ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์น˜๋ฅผ ์ œํ•œํ•˜๋Š” ํ•„ํ„ฐ๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ํ˜ธํ™˜๋˜๋Š” ์žฅ์น˜๋งŒ ์„ ํƒํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Arduino ๊ธฐ๋ฐ˜ ๋กœ๋ด‡์„ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋Š” ์‚ฌ์ดํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •ํ•˜์—ฌ ์„ ํƒ ๊ฐ€๋Šฅํ•œ ํฌํŠธ ์ง‘ํ•ฉ์„ USB ์žฅ์น˜๋กœ๋งŒ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์žฅ์น˜๋Š” Arduino์˜ USB ๊ณต๊ธ‰์—…์ฒด ID๋ฅผ ๊ฐ€์ง„ ์žฅ์น˜์ž…๋‹ˆ๋‹ค.
const filter = { usbVendorId: 0x2341 };
const port = await navigator.serial.requestPort({ filters: [filter] });

๋ฐ˜๋ฉด ์‚ฌ์ดํŠธ๊ฐ€ ๋งค์šฐ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์žฅ์น˜๋‚˜ USB-์ง๋ ฌ ๋ณ€ํ™˜๊ธฐ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ๋œ ์žฅ์น˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•œ๋‹ค๋ฉด, ํ•„ํ„ฐ๋ฅผ ์ „ํ˜€ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์ ์ ˆํ•œ ์žฅ์น˜๋ฅผ ์„ ํƒํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const port = await navigator.serial.requestPort();

์‚ฌ์šฉ์ž์—๊ฒŒ ํฌํŠธ ์„ ํƒ์„ ์š”์ฒญํ•˜๋ ค๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ‘œ์‹œํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ์‚ฌ์ดํŠธ์—๋Š” ์ผ์‹œ์  ํ™œ์„ฑํ™”๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋Š” ๋“ฑ์˜ ๋™์ž‘์—์„œ ๋น„๋กฏ๋ฉ๋‹ˆ๋‹ค.

<button id="connect">์—ฐ๊ฒฐ</button>
const connectButton = document.getElementById("connect");
connectButton.addEventListener('click', () => {
  try {
    const port = await navigator.serial.requestPort();
    // |port|์— ์—ฐ๊ฒฐ๋œ ์žฅ์น˜์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์„ ๊ณ„์† ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  } catch (e) {
    // ์žฅ์น˜๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋‹ซ์•˜์Šต๋‹ˆ๋‹ค.
  }
});

์‚ฌ์šฉ์ž๋Š” ์žฅ์น˜๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๊ฒฝ์šฐ Promise ๋Š” ๋‹ค์Œ์œผ๋กœ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค: "NotFoundError" DOMException ์ด๋Š” ์‚ฌ์ดํŠธ์—์„œ ๋ฐ˜๋“œ์‹œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด requestPort() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this์˜ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์˜ ์—ฐ๊ด€๋œ Document๊ฐ€ ์‚ฌ์šฉํ•˜๋„๋ก ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์ •์ฑ…์œผ๋กœ ์ œ์–ด๋˜๋Š” ๊ธฐ๋Šฅ์˜ ์ด๋ฆ„์ด "serial"์ด๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "SecurityError" DOMException ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด, ์ฆ‰ this์˜ ํ•ด๋‹น ๊ฐ์ฒด์— ์ผ์‹œ์  ํ™œ์„ฑํ™”๊ฐ€ ์—†์œผ๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "SecurityError" DOMException ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. ๋งŒ์•ฝ options["filters"] ๊ฐ€ ์žˆ์œผ๋ฉด, ๊ฐ filter์— ๋Œ€ํ•ด, ๊ทธ ๋Œ€์ƒ์€ options["filters"] ์— ์†ํ•˜๋Š” ํ•ญ๋ชฉ์ด๋ฉฐ, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

    1. ๋งŒ์•ฝ filter["bluetoothServiceClassId"] ๊ฐ€ ์žˆ์œผ๋ฉด:

      1. ๋งŒ์•ฝ filter["usbVendorId"] ๊ฐ€ ์žˆ์œผ๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ TypeError๋กœ ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

      2. ๋งŒ์•ฝ filter["usbProductId"] ๊ฐ€ ์žˆ์œผ๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ TypeError๋กœ ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    2. ๋งŒ์•ฝ filter["usbVendorId"] ๊ฐ€ ์—†์œผ๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ TypeError๋กœ ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

      ์ฐธ๊ณ : ์ด ๊ฒ€์‚ฌ๋Š” ๋‹ค์Œ์˜ ๊ฒฐํ•ฉ๋œ ๊ทœ์น™์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค: SerialPortFilter ๋Š” ๋น„์–ด ์žˆ์„ ์ˆ˜ ์—†์œผ๋ฉฐ, ๋งŒ์•ฝ usbProductId ๊ฐ€ ์ง€์ •๋˜์—ˆ๋‹ค๋ฉด usbVendorId ๋„ ๋ฐ˜๋“œ์‹œ ํ•จ๊ป˜ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  5. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

    1. allPorts๋ฅผ ๋นˆ ๋ชฉ๋ก์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค.

    2. ๊ฐ๊ฐ์— ๋Œ€ํ•ด, ๊ทธ ๋Œ€์ƒ์€ ์‹œ์Šคํ…œ์— ๋“ฑ๋ก๋œ Bluetooth ์žฅ์น˜์ž…๋‹ˆ๋‹ค:

      1. ๊ฐ๊ฐ์— ๋Œ€ํ•ด, ๊ทธ ๋Œ€์ƒ์€ BluetoothServiceUUID uuid์ด๋ฉฐ, ์ด๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ํ•ด๋‹น ์žฅ์น˜์ž…๋‹ˆ๋‹ค:

        1. ๋งŒ์•ฝ uuid๊ฐ€ ์ฐจ๋‹จ๋œ Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค UUID๊ฐ€ ์•„๋‹ˆ๋ฉด:

    3. ๊ฐ๊ฐ์— ๋Œ€ํ•ด, ๊ทธ ๋Œ€์ƒ์€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋น„ Bluetooth ์ง๋ ฌ ํฌํŠธ์ž…๋‹ˆ๋‹ค:

      1. port๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: SerialPort ์ด๋Š” ํ•ด๋‹น ํฌํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

      2. ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค: port๋ฅผ allPorts์—.

    4. ์‚ฌ์šฉ์ž์—๊ฒŒ ํฌํŠธ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜์—ฌ ์‚ฌ์ดํŠธ์˜ ์ง๋ ฌ ํฌํŠธ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋„๋ก ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์€ allPorts์— ์žˆ๋Š” ํฌํŠธ ์ค‘ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•˜๋Š” ํฌํŠธ์ด๋ฉฐ, ํ•„ํ„ฐ๋Š” options["filters"] ๊ฐ€ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๊ฐ’์— ์žˆ๋Š” ํ•„ํ„ฐ์ด๊ณ , ์—†์œผ๋ฉด allPorts๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

    5. ์‚ฌ์šฉ์ž๊ฐ€ ํฌํŠธ๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฉด, ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "NotFoundError" DOMException ๊ทธ๋ฆฌ๊ณ  ์ด ๋‹จ๊ณ„๋“ค์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

    6. port๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: SerialPort ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ํฌํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

    7. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ port๋กœ.

  6. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ง๋ ฌ ํฌํŠธ๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์กฐ๊ฑด์€, ์œ ์„  ์ง๋ ฌ ํฌํŠธ์ด๋ฉด์„œ ํ•ด๋‹น ํฌํŠธ๊ฐ€ ์‹œ์Šคํ…œ์— ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ฑฐ๋‚˜, ๋ฌด์„  ์ง๋ ฌ ํฌํŠธ์ด๋ฉด์„œ ํ•ด๋‹น ํฌํŠธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฌด์„  ์žฅ์น˜๊ฐ€ ์‹œ์Šคํ…œ์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

3.1.1. SerialPortRequestOptions ์‚ฌ์ „

dictionary SerialPortRequestOptions {
  sequence<SerialPortFilter> filters;
  sequence<BluetoothServiceUUID> allowedBluetoothServiceClassIds;
};
filters ๋ฉค๋ฒ„, ๋‹ค์Œ ํƒ€์ž… sequence<SerialPortFilter>
์ง๋ ฌ ํฌํŠธ์— ๋Œ€ํ•œ ํ•„ํ„ฐ
allowedBluetoothServiceClassIds ๋ฉค๋ฒ„, ํƒ€์ž… sequence<BluetoothServiceUUID>
๋‹ค์Œ์˜ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค: BluetoothServiceUUID ๊ฐ’์œผ๋กœ, Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค ID๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋น„์Šค ํด๋ž˜์Šค ID๋ฅผ ๊ฐ€์ง„ Bluetooth ํฌํŠธ๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ํฌํŠธ ๋ชฉ๋ก์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ๋‹จ, ์„œ๋น„์Šค ํด๋ž˜์Šค ID๊ฐ€ ์ด ๋ชฉ๋ก์— ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด ์ œ์™ธ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

3.1.2. SerialPortFilter ์‚ฌ์ „

dictionary SerialPortFilter {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId ๋ฉค๋ฒ„, ๋‹ค์Œ ํƒ€์ž… unsigned short
USB ๊ณต๊ธ‰์—…์ฒด ID
usbProductId ๋ฉค๋ฒ„, ๋‹ค์Œ ํƒ€์ž… unsigned short
USB ์ œํ’ˆ ID
bluetoothServiceClassId ๋ฉค๋ฒ„, ํƒ€์ž… BluetoothServiceUUID
Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค ID
์ง๋ ฌ ํฌํŠธ port๊ฐ€ ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•œ๋‹ค๋Š” ๊ฒƒ์€ filter์— ๋Œ€ํ•ด ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค:
  1. info๋ฅผ ๋‹ค์Œ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: port.getInfo().

  2. ๋งŒ์•ฝ filter["bluetoothServiceClassId"] ๊ฐ€ ์žˆ์œผ๋ฉด:

    1. ์ง๋ ฌ ํฌํŠธ๊ฐ€ Bluetooth ์žฅ์น˜์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ฉด, false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    2. ๋งŒ์•ฝ filter["bluetoothServiceClassId"] ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์œผ๋ฉด: info["bluetoothServiceClassId"], true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

    3. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ filter["usbVendorId"] ๊ฐ€ ์—†์œผ๋ฉด, ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: true.

  4. ์ง๋ ฌ ํฌํŠธ๊ฐ€ USB ์žฅ์น˜์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ฉด, false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  5. ๋งŒ์•ฝ info["usbVendorId"] ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ง€ ์•Š์œผ๋ฉด: filter["usbVendorId"], false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  6. ๋งŒ์•ฝ filter["usbProductId"] ๊ฐ€ ์—†์œผ๋ฉด, ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: true.

  7. ๋งŒ์•ฝ info["usbProductId"] ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ง€ ์•Š์œผ๋ฉด: filter["usbProductId"], false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  8. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ง๋ ฌ ํฌํŠธ port๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•œ๋‹ค๋Š” ๊ฒƒ์€, ํ•ด๋‹น ์‹œํ€€์Šค๊ฐ€ SerialPortFilter์˜ ์‹œํ€€์Šค์ด๋ฉฐ, ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค:
  1. ์‹œํ€€์Šค์˜ ๊ฐ filter์— ๋Œ€ํ•ด, ๋‹ค์Œ ํ•˜์œ„ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

    1. ๋งŒ์•ฝ port๊ฐ€ ํ•„ํ„ฐ์™€ ์ผ์น˜ํ•˜๋ฉฐ ๊ทธ ํ•„ํ„ฐ๊ฐ€ filter์ด๋ฉด, ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: true.

  2. false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

3.2. getPorts() ๋ฉ”์„œ๋“œ

USB ์žฅ์น˜๊ฐ€ ์ง๋ ฌ ํฌํŠธ๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋ฉด ํ•ด๋‹น ์žฅ์น˜๋Š” ์‹œ์Šคํ…œ์— ์—ฐ๊ฒฐ๋˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ์—์„œ ๋ถ„๋ฆฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ๊ฐ€ ํฌํŠธ์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์„ ์–ป์œผ๋ฉด, ์ด๋Ÿฌํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์—ฐ๊ฒฐ๋œ ์žฅ์น˜ ์ง‘ํ•ฉ์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ํ˜„์žฌ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์น˜๋“ค์ž…๋‹ˆ๋‹ค.
// ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋  ๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํฌํŠธ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
document.addEventListener('DOMContentLoaded', async () => {
  let ports = await navigator.serial.getPorts();
  // ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์œผ๋กœ UI๋ฅผ ์ฑ„์šฐ๊ฑฐ๋‚˜
  // ์žฅ์น˜์— ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
});

navigator.serial.addEventListener('connect', e => {
  // |e.target|์„ UI์— ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
});

navigator.serial.addEventListener('disconnect', e => {
  // |e.target|์„ UI์—์„œ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์žฅ์น˜๊ฐ€ ์—ด๋ ค ์žˆ์—ˆ๋‹ค๋ฉด
  // ์—ฐ๊ฒฐ ํ•ด์ œ๋ฅผ ์ŠคํŠธ๋ฆผ ์˜ค๋ฅ˜๋กœ๋„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
});
์ด getPorts() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this์˜ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์˜ ์—ฐ๊ด€๋œ Document๊ฐ€ ์‚ฌ์šฉํ•˜๋„๋ก ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์ •์ฑ…์œผ๋กœ ์ œ์–ด๋˜๋Š” ๊ธฐ๋Šฅ์˜ ์ด๋ฆ„์ด "serial"์ด๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "SecurityError" DOMException ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: promise.

  3. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

    1. availablePorts๋ฅผ ๋‹ค์Œ์˜ ์‹œํ€€์Šค๋กœ ๋‘ก๋‹ˆ๋‹ค: ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ง๋ ฌ ํฌํŠธ ์ค‘์—์„œ, ์ด์ „ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์— ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ ํฌํŠธ์ด๋ฉฐ, ํ˜ธ์ถœ ๋Œ€์ƒ์€ requestPort()์ž…๋‹ˆ๋‹ค.

    2. ports๋ฅผ ๋‹ค์Œ์˜ ์‹œํ€€์Šค๋กœ ๋‘ก๋‹ˆ๋‹ค: SerialPort ๊ฐ์ฒด๋“ค๋กœ, ์ด๋“ค์ด ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์€ availablePorts์— ์žˆ๋Š” ํฌํŠธ์ž…๋‹ˆ๋‹ค.

    3. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ports๋กœ.

  4. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

3.3. onconnect ์†์„ฑ

onconnect ๋Š” ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ IDL ์†์„ฑ์ด๋ฉฐ, connect ์ด๋ฒคํŠธ ์œ ํ˜•์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

3.4. ondisconnect ์†์„ฑ

ondisconnect ๋Š” ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ IDL ์†์„ฑ์ด๋ฉฐ, disconnect ์ด๋ฒคํŠธ ์œ ํ˜•์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

4. SerialPort ์ธํ„ฐํŽ˜์ด์Šค

[Exposed=(DedicatedWorker,Window), SecureContext]
interface SerialPort : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  readonly attribute boolean connected;
  readonly attribute ReadableStream? readable;
  readonly attribute WritableStream? writable;

  SerialPortInfo getInfo();

  Promise<undefined> open(SerialOptions options);
  Promise<undefined> setSignals(optional SerialOutputSignals signals = {});
  Promise<SerialInputSignals> getSignals();
  Promise<undefined> close();
  Promise<undefined> forget();
};

์ด ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉฐ, ์ž‘์—…์„ ๋‹ค์Œ์— ํ์ž‰ํ•ฉ๋‹ˆ๋‹ค: ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค.

์ด ๋ถ€๋ชจ ๊ฐ€์ ธ์˜ค๊ธฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋Œ€์ƒ์ธ SerialPort ์— ๋Œ€ํ•ด์„œ๋Š” ๋™์ผํ•œ Serial ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ SerialPort์˜ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์˜ Navigator ๊ฐ์ฒด์˜ serial ๊ฒŒํ„ฐ์ž…๋‹ˆ๋‹ค.

์ธ์Šคํ„ด์Šค์˜ ๋Œ€์ƒ์ธ SerialPort ๋Š” ๋‚ด๋ถ€ ์Šฌ๋กฏ์„ ๊ฐ€์ง„ ์ธ์Šคํ„ด์Šค๋กœ ์ƒ์„ฑ๋˜๋ฉฐ, ํ•ด๋‹น ์Šฌ๋กฏ์€ ๋‹ค์Œ ํ‘œ์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

๋‚ด๋ถ€ ์Šฌ๋กฏ ์ดˆ๊ธฐ๊ฐ’ ์„ค๋ช… (๋น„๊ทœ๋ฒ”์ )
[[state]] "closed" ํ™œ์„ฑ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๋ฉฐ, ๊ทธ ๋Œ€์ƒ์€ SerialPort
[[bufferSize]] undefined ์†ก์ˆ˜์‹ ์„ ์œ„ํ•ด ๋ฒ„ํผ๋งํ•  ๋ฐ์ดํ„ฐ์˜ ์–‘
[[connected]] false ์ง๋ ฌ ํฌํŠธ์˜ ๋…ผ๋ฆฌ์  ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ
[[readable]] null ํ•ด๋‹น ReadableStream ์€ ํฌํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•ฉ๋‹ˆ๋‹ค
[[readFatal]] false ํฌํŠธ์— ์น˜๋ช…์ ์ธ ์ฝ๊ธฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ
[[writable]] null ํ•ด๋‹น WritableStream ์€ ํฌํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค
[[writeFatal]] false ํฌํŠธ์— ์น˜๋ช…์ ์ธ ์“ฐ๊ธฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ”Œ๋ž˜๊ทธ
[[pendingClosePromise]] null ํ•ด๋‹น Promise ๋Š” ๋‹ค์Œ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค: readable ๋ฐ writable ์ด ๋‹ซํžˆ๋Š” ๊ฒƒ

4.1. onconnect ์†์„ฑ

onconnect ๋Š” ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ IDL ์†์„ฑ์ด๋ฉฐ, connect ์ด๋ฒคํŠธ ์œ ํ˜•์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ ์ง๋ ฌ ํฌํŠธ๊ฐ€ ์žˆ๊ณ , ์ด ํ—ˆ์šฉ์€ ์ด์ „์˜ ๋‹ค์Œ ํ˜ธ์ถœ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค: requestPort() ํ•ด๋‹น ํฌํŠธ๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋จ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด, ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ.
  1. port๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: SerialPort ์ด๋Š” ํ•ด๋‹น ํฌํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

  2. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: port.[[connected]] ๋ฅผ true๋กœ.

  3. ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ ์ด๋ฆ„์€ connect ์ด๊ณ , ๋Œ€์ƒ์€ port์ด๋ฉฐ, ์ด๋ฒคํŠธ์˜ bubbles ์†์„ฑ์€ true๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

์ง๋ ฌ ํฌํŠธ๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋จ ์ƒํƒœ์ธ ์กฐ๊ฑด์€, ์œ ์„  ์ง๋ ฌ ํฌํŠธ์ด๋ฉด์„œ ์‹œ์Šคํ…œ์— ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ฑฐ๋‚˜, ๋ฌด์„  ์ง๋ ฌ ํฌํŠธ์ด๋ฉด์„œ ์‹œ์Šคํ…œ์ด ๋ฌด์„  ์žฅ์น˜์— ๋Œ€ํ•œ ํ™œ์„ฑ ์—ฐ๊ฒฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค(์˜ˆ: ์—ด๋ฆฐ Bluetooth L2CAP ์ฑ„๋„).

4.2. ondisconnect ์†์„ฑ

ondisconnect ๋Š” ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ๊ธฐ IDL ์†์„ฑ์ด๋ฉฐ, disconnect ์ด๋ฒคํŠธ ์œ ํ˜•์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ ์ง๋ ฌ ํฌํŠธ๊ฐ€ ์žˆ๊ณ , ์ด ํ—ˆ์šฉ์€ ์ด์ „์˜ ๋‹ค์Œ ํ˜ธ์ถœ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค: requestPort() ํ•ด๋‹น ํฌํŠธ๊ฐ€ ๋” ์ด์ƒ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋จ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:
  1. port๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: SerialPort ์ด๋Š” ํ•ด๋‹น ํฌํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

  2. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: port.[[connected]] ๋ฅผ false๋กœ.

  3. ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๊ทธ ์ด๋ฆ„์€ disconnect ์ด๊ณ , ๋Œ€์ƒ์€ port์ด๋ฉฐ, ์ด๋ฒคํŠธ์˜ bubbles ์†์„ฑ์€ true๋กœ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

4.3. getInfo() ๋ฉ”์„œ๋“œ

์ด getInfo() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. info๋ฅผ ๋นˆ ์ˆœ์„œ ์žˆ๋Š” ๋งต์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค.

  2. ํฌํŠธ๊ฐ€ USB ์žฅ์น˜์˜ ์ผ๋ถ€์ด๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

    1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: info["usbVendorId"] ๋ฅผ ๊ณต๊ธ‰์—…์ฒด ID๋กœ, ๊ทธ ๋Œ€์ƒ์€ ํ•ด๋‹น ์žฅ์น˜์ž…๋‹ˆ๋‹ค.

    2. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: info["usbProductId"] ๋ฅผ ์ œํ’ˆ ID๋กœ, ๊ทธ ๋Œ€์ƒ์€ ํ•ด๋‹น ์žฅ์น˜์ž…๋‹ˆ๋‹ค.

  3. ํฌํŠธ๊ฐ€ Bluetooth ์žฅ์น˜์˜ ์„œ๋น„์Šค์ด๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

    1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: info["bluetoothServiceClassId"] ๋ฅผ ์„œ๋น„์Šค ํด๋ž˜์Šค UUID๋กœ, ์ด๋Š” ํ•ด๋‹น Bluetooth ์„œ๋น„์Šค์˜ ๊ฐ’์ž…๋‹ˆ๋‹ค.

  4. info๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4.3.1. SerialPortInfo ์‚ฌ์ „

dictionary SerialPortInfo {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId ๋ฉค๋ฒ„, ํƒ€์ž… unsigned short
ํฌํŠธ๊ฐ€ USB ์žฅ์น˜์˜ ์ผ๋ถ€์ด๋ฉด ์ด ๋ฉค๋ฒ„๋Š” 16๋น„ํŠธ ๊ณต๊ธ‰์—…์ฒด ID์ด๋ฉฐ, ํ•ด๋‹น ์žฅ์น˜์˜ ID์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด undefined์ž…๋‹ˆ๋‹ค.
usbProductId ๋ฉค๋ฒ„, ํƒ€์ž… unsigned short
ํฌํŠธ๊ฐ€ USB ์žฅ์น˜์˜ ์ผ๋ถ€์ด๋ฉด ์ด ๋ฉค๋ฒ„๋Š” 16๋น„ํŠธ ์ œํ’ˆ ID๋กœ์„œ ํ•ด๋‹น ์žฅ์น˜์˜ ID์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด undefined์ž…๋‹ˆ๋‹ค.
bluetoothServiceClassId ๋ฉค๋ฒ„, ํƒ€์ž… BluetoothServiceUUID
ํฌํŠธ๊ฐ€ Bluetooth ์žฅ์น˜์˜ ์„œ๋น„์Šค์ด๋ฉด ์ด ๋ฉค๋ฒ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค: BluetoothServiceUUID ์ด๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค UUID๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด undefined์ž…๋‹ˆ๋‹ค.

4.4. open() ๋ฉ”์„œ๋“œ

์ง๋ ฌ ํฌํŠธ๋กœ ํ†ต์‹ ํ•˜๊ธฐ ์ „์— ํฌํŠธ๋ฅผ ์—ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํฌํŠธ๋ฅผ ์—ด๋ฉด ์‚ฌ์ดํŠธ์—์„œ ๋ฐ์ดํ„ฐ ์ „์†ก ๋ฐฉ์‹์„ ์ œ์–ดํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์†ก์‹ ๊ณผ ์ˆ˜์‹ ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋ฉฐ, ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ์žฅ์น˜์˜ ๋ฌธ์„œ์—์„œ ์ ์ ˆํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ฐพ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
await port.open({ baudRate: /* ์‚ฌ์šฉํ•  ๋ณด ๋ ˆ์ดํŠธ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค */ });

์ผ๋‹จ open() ์ด ํ•ด๊ฒฐ๋˜๋ฉด readable ๋ฐ writable ์†์„ฑ์— ์ ‘๊ทผํ•˜์—ฌ ๋‹ค์Œ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ReadableStream ๋ฐ WritableStream ์ธ์Šคํ„ด์Šค๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์†ก์‹ ํ•  ๋Œ€์ƒ์€ ์—ฐ๊ฒฐ๋œ ์žฅ์น˜์ž…๋‹ˆ๋‹ค.

์ด open() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "closed"๊ฐ€ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” "InvalidStateError" DOMException ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ options["baudRate"] ๊ฐ€ 0์ด๋ฉด, promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: TypeError ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. ๋งŒ์•ฝ options["dataBits"] ๊ฐ€ 7๋„ 8๋„ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” TypeError ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  5. ๋งŒ์•ฝ options["stopBits"] ๊ฐ€ 1๋„ 2๋„ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” TypeError ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  6. ๋งŒ์•ฝ options["bufferSize"] ๊ฐ€ 0์ด๋ฉด, promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: TypeError ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  7. ์„ ํƒ์ ์œผ๋กœ, ๋งŒ์•ฝ options["bufferSize"] ๊ฐ€ ๋‹ค์Œ๋ณด๋‹ค ํฌ๋ฉด, ์ฆ‰ ๊ตฌํ˜„์ด ์ง€์›ํ•  ์ˆ˜ ์žˆ๋Š” ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด, promise๋ฅผ TypeError๋กœ ๊ฑฐ๋ถ€ํ•˜๊ณ  ์ด์–ด์„œ promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  8. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[state]] ๋ฅผ "opening"์œผ๋กœ.

  9. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค.

    1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ง๋ ฌ ํฌํŠธ๋ฅผ ์—ฝ๋‹ˆ๋‹ค. ์ด๋•Œ ์‚ฌ์šฉํ•  ์—ฐ๊ฒฐ ๋งค๊ฐœ๋ณ€์ˆ˜(๋˜๋Š” ๊ธฐ๋ณธ๊ฐ’)๋Š” options์— ์ง€์ •๋œ ๊ฐ’์ž…๋‹ˆ๋‹ค.

    2. ์–ด๋–ค ์ด์œ ๋กœ๋“  ์ด ์ž‘์—…์ด ์‹คํŒจํ•˜๋ฉด, ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "NetworkError" DOMException ๊ทธ๋ฆฌ๊ณ  ์ด ๋‹จ๊ณ„๋“ค์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

    3. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[state]] ๋ฅผ "opened"๋กœ.

    4. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[bufferSize]] ๋ฅผ ๋‹ค์Œ ๊ฐ’์œผ๋กœ: options["bufferSize"].

    5. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

  10. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4.4.1. SerialOptions ์‚ฌ์ „

dictionary SerialOptions {
  required [EnforceRange] unsigned long baudRate;
  [EnforceRange] octet dataBits = 8;
  [EnforceRange] octet stopBits = 1;
  ParityType parity = "none";
  [EnforceRange] unsigned long bufferSize = 255;
  FlowControlType flowControl = "none";
};
baudRate ๋ฉค๋ฒ„, ํƒ€์ž… unsigned long
๋ณด ๋ ˆ์ดํŠธ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” 0์ด ์•„๋‹Œ ์–‘์ˆ˜ ๊ฐ’์œผ๋กœ, ์ง๋ ฌ ํ†ต์‹ ์„ ์„ค์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•  ๊ฐ’์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ : baudRate ๋Š” ์ด ์‚ฌ์ „์—์„œ ์œ ์ผํ•œ ํ•„์ˆ˜ ๋ฉค๋ฒ„์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์—ฐ๊ฒฐ ๋งค๊ฐœ๋ณ€์ˆ˜์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋ณธ๊ฐ’์ด ์žˆ์ง€๋งŒ, ๊ฐœ๋ฐœ์ž๋Š” ๊ฐ’์„ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ณ ๋ คํ•˜๊ณ  ์—ฐ๊ฒฐํ•˜๋ ค๋Š” ์žฅ์น˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ”ํžˆ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ’์€ ์žˆ์ง€๋งŒ ํ‘œ์ค€ ๋ณด ๋ ˆ์ดํŠธ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ•„์ˆ˜๋กœ ์ง€์ •ํ•˜๋ฉด ์ž„์˜์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์ด ๋ช…์„ธ์—์„œ ์„ ํƒํ–ˆ์„ ๋•Œ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋Š” ํ˜ผ๋ž€์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

dataBits ๋ฉค๋ฒ„, ํƒ€์ž… octet, ๊ธฐ๋ณธ๊ฐ’ 8
ํ”„๋ ˆ์ž„๋‹น ๋ฐ์ดํ„ฐ ๋น„ํŠธ ์ˆ˜์ž…๋‹ˆ๋‹ค. 7 ๋˜๋Š” 8์ž…๋‹ˆ๋‹ค.
stopBits ๋ฉค๋ฒ„, ํƒ€์ž… octet, ๊ธฐ๋ณธ๊ฐ’ 1
ํ”„๋ ˆ์ž„ ๋์˜ ์ •์ง€ ๋น„ํŠธ ์ˆ˜์ž…๋‹ˆ๋‹ค. 1 ๋˜๋Š” 2์ž…๋‹ˆ๋‹ค.
parity ๋ฉค๋ฒ„, ํƒ€์ž… ParityType, ๊ธฐ๋ณธ๊ฐ’ "none"
ํŒจ๋ฆฌํ‹ฐ ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค.
bufferSize ๋ฉค๋ฒ„, ํƒ€์ž… unsigned long, ๊ธฐ๋ณธ๊ฐ’ 255
์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” 0์ด ์•„๋‹Œ ์–‘์ˆ˜ ๊ฐ’์œผ๋กœ, ์ƒ์„ฑํ•  ๋ฒ„ํผ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
flowControl ๋ฉค๋ฒ„, ํƒ€์ž… FlowControlType, ๊ธฐ๋ณธ๊ฐ’ "none"
ํ๋ฆ„ ์ œ์–ด ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค.
4.4.1.1. ParityType ์—ด๊ฑฐํ˜•
enum ParityType {
  "none",
  "even",
  "odd"
};
none
๊ฐ ๋ฐ์ดํ„ฐ ์›Œ๋“œ์— ๋Œ€ํ•ด ํŒจ๋ฆฌํ‹ฐ ๋น„ํŠธ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
even
๋ฐ์ดํ„ฐ ์›Œ๋“œ์™€ ํŒจ๋ฆฌํ‹ฐ ๋น„ํŠธ๋ฅผ ํ•ฉํ•œ ์ „์ฒด๊ฐ€ ์ง์ˆ˜ ํŒจ๋ฆฌํ‹ฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
odd
๋ฐ์ดํ„ฐ ์›Œ๋“œ์™€ ํŒจ๋ฆฌํ‹ฐ ๋น„ํŠธ๋ฅผ ํ•ฉํ•œ ์ „์ฒด๊ฐ€ ํ™€์ˆ˜ ํŒจ๋ฆฌํ‹ฐ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
4.4.1.2. FlowControlType ์—ด๊ฑฐํ˜•
enum FlowControlType {
  "none",
  "hardware"
};
none
ํ๋ฆ„ ์ œ์–ด๊ฐ€ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
hardware
RTS ๋ฐ CTS ์‹ ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•˜๋“œ์›จ์–ด ํ๋ฆ„ ์ œ์–ด๊ฐ€ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.

4.5. connected ์†์„ฑ

์ด connected ๊ฒŒํ„ฐ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: this.[[connected]].

4.6. readable ์†์„ฑ

์ง๋ ฌ ํฌํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ค‘์ฒฉ๋œ ๋‘ ๊ฐœ์˜ ๋ฃจํ”„๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
while (port.readable) {
  const reader = port.readable.getReader();
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        // |reader|๊ฐ€ ์ทจ์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
        break;
      }
      // |value|๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค...
    }
  } catch (error) {
    // |error|๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค...
  } finally {
    reader.releaseLock();
  }
}

๋‚ด๋ถ€ ๋ฃจํ”„๋Š” ํฌํŠธ์—์„œ ๋ฐ์ดํ„ฐ ์ฒญํฌ๋ฅผ ์ฝ๋‹ค๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด "catch" ๋ธ”๋ก์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์™ธ๋ถ€ ๋ฃจํ”„๋Š” ํŒจ๋ฆฌํ‹ฐ ๊ฒ€์‚ฌ ์‹คํŒจ์™€ ๊ฐ™์ด ๋ณต๊ตฌ ๊ฐ€๋Šฅํ•œ ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์ด๋ฅผ ์œ„ํ•ด ์ƒˆ ๋ฆฌ๋”๋ฅผ ์—ฝ๋‹ˆ๋‹ค. ์น˜๋ช…์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด readable ์ด null์ด ๋˜๊ณ  ๋ฃจํ”„๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

์ง๋ ฌ ํฌํŠธ๊ฐ€ ์—ด๋ ค ์žˆ๋Š” ๋™์•ˆ์—๋Š” ๊ณ„์† ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฐ˜ํ™˜๋˜๋Š” ๊ฐ ์ฒญํฌ์˜ ๋ฐ์ดํ„ฐ ์–‘์€, ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์ธ read() ์˜ ํ˜ธ์ถœ ์‹œ์ ์— ๋”ฐ๋ผ ์‚ฌ์‹ค์ƒ ์ž„์˜๋กœ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ์žฅ์น˜์™€ ํ•ด๋‹น ์žฅ์น˜์™€ ํ†ต์‹ ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋ฌด์—‡์„ ์™„์ „ํ•œ ๋ฉ”์‹œ์ง€๋กœ ๊ฐ„์ฃผํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์žฅ์น˜๋Š” ASCII ํ˜•์‹์˜ ํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ŠคํŠธ์™€ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ๋ฉ”์‹œ์ง€๋Š” ์ค„๋ฐ”๊ฟˆ(๋˜๋Š” ์‹œํ€€์Šค "\r\n")์œผ๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•˜๋Š” TransformStream๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ์„ ์ž๋™์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: Uint8Array ์ฒญํฌ๋กœ, ์ด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ readable ์ด๋ฉฐ, ๋ณ€ํ™˜ ๊ฒฐ๊ณผ๋Š” DOMString๋“ค๋กœ, ๊ฐ๊ฐ ์™„์ „ํ•œ ํ…์ŠคํŠธ ํ•œ ์ค„์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

class LineBreakTransformer {
  constructor() {
    this.container = '';
  }

  transform(chunk, controller) {
    this.container += chunk;
    const lines = this.container.split('\r\n');
    this.container = lines.pop();
    lines.forEach(line => controller.enqueue(line));
  }

  flush(controller) {
    controller.enqueue(this.container);
  }
}

const decoder = new TextDecoderStream();
const streamClosed = port.readable.pipeTo(decoder.writable);
const lineReader = decoder.readable
    .pipeThrough(new TransformStream(new LineBreakTransformer()))
    .getReader();

์˜ˆ์ œ 7๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํŒŒ์ดํ”„ ์ฒด์ธ์€ pipeThrough()๋งŒ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. pipeTo()๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์‹œ์ ์€ ์ฒซ ๋ฒˆ์งธ TransformStream ์„ SerialPort ์— ์—ฐ๊ฒฐํ•  ๋•Œ์ด๋ฉฐ, ๊ทธ๋ž˜์•ผ ํฌํŠธ๋ฅผ ๋‹ซ์œผ๋ ค ํ•  ๋•Œ ํŒŒ์ดํ”„ ์ฒด์ธ์ด ๋‹ซํž ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

lineReader.cancel();
await streamClosed;
await port.close();

๋ฉ”์‹œ์ง€ ๊ฒฝ๊ณ„๋ฅผ ์ธ์ฝ”๋”ฉํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๊ฐ ๋ฉ”์‹œ์ง€ ์•ž์— ๊ธธ์ด๋ฅผ ๋ถ™์ด๊ฑฐ๋‚˜, ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋™์•ˆ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ๋‹ค์Œ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. TransformStream ์„ ๊ตฌํ˜„ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๋ฉ”์‹œ์ง€ ๊ฒฝ๊ณ„๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ž‘์—…์€ ๋…์ž์˜ ์—ฐ์Šต ๊ณผ์ œ๋กœ ๋‚จ๊ฒจ ๋‘ก๋‹ˆ๋‹ค.

์ด read() ๋ฉ”์„œ๋“œ๋Š” ๋น„๋™๊ธฐ์ ์ด๋ฉฐ ์‹คํ–‰์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š์ง€๋งŒ, async/await ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์—์„œ๋Š” ์‹คํ–‰์„ ์ฐจ๋‹จํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์—์„œ๋Š” ์‹œ๊ฐ„ ์ œํ•œ์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ผ์ • ๊ธฐ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜์ง€ ๋ชปํ–ˆ์„ ๋•Œ ์ฝ”๋“œ ์‹คํ–‰์„ ๊ณ„์†ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” releaseLock() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ํ˜ธ์ถœ์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค: read() ๊ทธ ์‹œ์ ์€ ํƒ€์ด๋จธ๊ฐ€ ๋งŒ๋ฃŒ๋œ ํ›„์ž…๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ ์ŠคํŠธ๋ฆผ์„ ๋‹ซ์ง€ ์•Š์œผ๋ฏ€๋กœ, ์‹œ๊ฐ„ ์ œํ•œ ์ดํ›„์— ์ˆ˜์‹ ํ•œ ๋ฐ์ดํ„ฐ๋„ ๋‚˜์ค‘์— ์ฝ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, getReader() ๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

async function readWithTimeout(port, timeout) {
  const reader = port.readable.getReader();
  const timer = setTimeout(() => {
    reader.releaseLock();
  }, timeout);
  const result = await reader.read();
  clearTimeout(timer);
  reader.releaseLock();
  return result;
}

์ด ๊ธฐ๋Šฅ์€ releaseLock() ์— ๋‹ค์Œ ๋ณ€๊ฒฝ์œผ๋กœ ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ, whatwg/streams#1168 ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์ตœ๊ทผ์—์•ผ ๊ตฌํ˜„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด readable ๊ฒŒํ„ฐ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. ๋งŒ์•ฝ this.[[readable]] ์ด null์ด ์•„๋‹ˆ๋ฉด, ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: this.[[readable]].

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "opened"๊ฐ€ ์•„๋‹ˆ๋ฉด, null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ this.[[readFatal]] ์ด true์ด๋ฉด, null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. stream์„ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ReadableStream.

  5. pullAlgorithm์„ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‘ก๋‹ˆ๋‹ค:

    1. desiredSize๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์›ํ•˜๋Š” ํฌ๊ธฐ(ํ•˜์ด ์›Œํ„ฐ ๋งˆํฌ๊นŒ์ง€ ์ฑ„์šฐ๊ธฐ ์œ„ํ•œ), ๊ทธ ๋Œ€์ƒ์€ this.[[readable]]์ž…๋‹ˆ๋‹ค.

    2. ๋งŒ์•ฝ this.[[readable]]์˜ ํ˜„์žฌ BYOB ์š”์ฒญ ๋ทฐ ๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด, desiredSize๋ฅผ ๋‹ค์Œ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[readable]]์˜ ํ˜„์žฌ BYOB ์š”์ฒญ ๋ทฐ์˜ ๋ฐ”์ดํŠธ ๊ธธ์ด.

    3. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

    4. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

      1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ตœ๋Œ€ desiredSize๋ฐ”์ดํŠธ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค. ์ฝ๊ธฐ ๋Œ€์ƒ์€ ํฌํŠธ์ด๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”์ดํŠธ ์‹œํ€€์Šค bytes์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

        ์ฐธ๊ณ : this.[[state]] ๊ฐ€ "forgotten"์ด ๋˜๋Š” ๊ฒƒ์€ the port was disconnected์ธ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

      2. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

        1. ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด:

          1. ๋งŒ์•ฝ this.[[readable]]์˜ ํ˜„์žฌ BYOB ์š”์ฒญ ๋ทฐ๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด, ๋‹ค์Œ์„ ์”๋‹ˆ๋‹ค: bytes๋ฅผ ๋‹ค์Œ์—: this.[[readable]]์˜ ํ˜„์žฌ BYOB ์š”์ฒญ ๋ทฐ. ๊ทธ๋ฆฌ๊ณ  view๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: ๋‹ค์Œ this.[[readable]]์˜ ํ˜„์žฌ BYOB ์š”์ฒญ ๋ทฐ๋กœ.

          2. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, view๋ฅผ ๋‹ค์Œ ๊ฒฐ๊ณผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: ์ƒ์„ฑํ•œ Uint8Array ์ด๋ฉฐ, ๊ทธ ์›๋ณธ์€ bytes์ด๊ณ , ์ƒ์„ฑ ์˜์—ญ์€ this์˜ ๊ด€๋ จ Realm์ž…๋‹ˆ๋‹ค.

          3. ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค: view๋ฅผ ๋‹ค์Œ์—: this.[[readable]].

          4. ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

        2. ๋ฒ„ํผ ์˜ค๋ฒ„๋Ÿฐ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "BufferOverrunError" DOMException์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ.

        3. ๋ธŒ๋ ˆ์ดํฌ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "BreakError" DOMException์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•  ๋‹จ๊ณ„๋Š” ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ์ž…๋‹ˆ๋‹ค.

        4. ํ”„๋ ˆ์ด๋ฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "FramingError" DOMException์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•  ๋‹จ๊ณ„๋Š” ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ์ž…๋‹ˆ๋‹ค.

        5. ํŒจ๋ฆฌํ‹ฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "ParityError" DOMException์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ํ•  ๋‹จ๊ณ„๋Š” ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ์ž…๋‹ˆ๋‹ค.

        6. ์šด์˜์ฒด์ œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "UnknownError" DOMException์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ํ•ด๋‹น ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ.

        7. ๋งŒ์•ฝ the port was disconnected์ด๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

          1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[readFatal]] ๋ฅผ true๋กœ,

          2. ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: ์˜ค๋ฅ˜ ๋ฐœ์ƒ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ์ธ์ˆ˜๋Š” "NetworkError" DOMException์ž…๋‹ˆ๋‹ค.

          3. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ ๋‹ซ๊ธฐ.

    5. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  6. cancelAlgorithm์„ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‘ก๋‹ˆ๋‹ค:

    1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

    2. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค.

      1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํฌํŠธ์˜ ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด ๋ฐ ํ•˜๋“œ์›จ์–ด ์ˆ˜์‹  ๋ฒ„ํผ์˜ ๋‚ด์šฉ์„ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

      2. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๊ทธ ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

        1. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ.

        2. ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

    3. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  7. ๋ฐ”์ดํŠธ ์ฝ๊ธฐ๋ฅผ ์ง€์›ํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: stream์— ๋Œ€ํ•ด, pullAlgorithm ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: pullAlgorithm์œผ๋กœ, cancelAlgorithm ์€ cancelAlgorithm์œผ๋กœ ์„ค์ •ํ•˜๊ณ , highWaterMark ๋Š” ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: ๋‹ค์Œ this.[[bufferSize]]๋กœ.

  8. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[readable]] ์„ stream์œผ๋กœ.

  9. stream์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฒ˜๋ฆฌ: ์ฝ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ ๋‹ซ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:
  1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[readable]] ์„ null๋กœ.

  2. ๋งŒ์•ฝ this.[[writable]] ์ด null์ด๊ณ  this.[[pendingClosePromise]] ๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด, ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: this.[[pendingClosePromise]] ๋ฅผ undefined๋กœ.

4.7. writable ์†์„ฑ

๊ฐœ๋ณ„ ๋ฐ์ดํ„ฐ ์ฒญํฌ๋ฅผ ํฌํŠธ์— ์“ฐ๋ ค๋ฉด WritableStreamDefaultWriter ๋ฅผ ํ•„์š”์— ๋”ฐ๋ผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์˜ˆ์ œ๋Š” TextEncoder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DOMString ์„ ํ•„์š”ํ•œ Uint8Array ๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
const encoder = new TextEncoder();
const writer = port.writable.getWriter();
await writer.write(encoder.encode("PING"));
writer.releaseLock();

๋” ํฐ ์ฒญํฌ๋ฅผ ์“ธ ๋•Œ๋Š” ํฌํŠธ๊ฐ€ ์—ญ๋ฐฉํ–ฅ ์••๋ ฅ์„ ์ ์šฉํ•˜๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ง๋ ฌ ์†ก์‹ ๊ธฐ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ฐ ์ง€๋‚˜์น˜๊ฒŒ ๋’ค์ฒ˜์ง€์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. write() ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ Promise ์ด๋ฉฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ๊ธฐ๋ก๋˜๋ฉด ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์ „์†ก ๋ฒ„ํผ์— ์–ด๋А ์ •๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์€ ๋†’์€ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ์œ ์ง€ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•˜์ง€๋งŒ, ์ด Promise ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ๋„ˆ๋ฌด ๋งŽ์€ ๋ฐ์ดํ„ฐ ์ฒญํฌ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์€ ๊ณผ๋„ํ•œ ๋ฒ„ํผ๋ง์„ ํ”ผํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด writable ๊ฒŒํ„ฐ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. ๋งŒ์•ฝ this.[[writable]] ์ด null์ด ์•„๋‹ˆ๋ฉด, ๋‹ค์Œ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: this.[[writable]].

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "opened"๊ฐ€ ์•„๋‹ˆ๋ฉด, null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ this.[[writeFatal]] ์ด true์ด๋ฉด, null์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. stream์„ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด WritableStream.

  5. signal์„ stream์˜ ์‹ ํ˜ธ๋กœ ๋‘ก๋‹ˆ๋‹ค.

  6. writeAlgorithm์„ chunk๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ์˜ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‘ก๋‹ˆ๋‹ค:

    1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

    2. ๋‹จ์–ธ: signal์€ ์ค‘๋‹จ๋จ ์ƒํƒœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

    3. ๋งŒ์•ฝ chunk๋ฅผ IDL ๊ฐ’์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์—†๊ณ , ๊ทธ ํƒ€์ž…์ด BufferSource์ด๋ฉด, promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: TypeError ๊ทธ๋ฆฌ๊ณ  ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: promise. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, ๋ณ€ํ™˜ ๊ฒฐ๊ณผ๋ฅผ source์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

    4. ๋ฒ„ํผ ์†Œ์Šค์˜ ๋ณต์‚ฌ๋ณธ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ source์ด๋ฉฐ, ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์Œ์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค: bytes.

    5. ๋ณ‘๋ ฌ๋กœ, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

      1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ bytes๋ฅผ ํฌํŠธ์— ์”๋‹ˆ๋‹ค. ๋˜๋Š” ๋‚˜์ค‘์— ๋ณ‘ํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ์ฒญํฌ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

        ์ฐธ๊ณ : ์šด์˜์ฒด์ œ๋Š” ๋‹ค์Œ ์‹œ์ ์— ์ด ์ž‘์—…์—์„œ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: bytes์˜ ์ „์†ก์ด ์™„๋ฃŒ๋œ ํ›„๊ฐ€ ์•„๋‹ˆ๋ผ ์ „์†ก ํ์— ๋“ค์–ด๊ฐ„ ์‹œ์ ์ž…๋‹ˆ๋‹ค.

        ์ฐธ๊ณ : this.[[state]] ๊ฐ€ "forgotten"์ด ๋˜๋Š” ๊ฒƒ์€ the port was disconnected์ธ ๊ฒฝ์šฐ์ฒ˜๋Ÿผ ์ทจ๊ธ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

      2. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

        1. ์ฒญํฌ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๊ธฐ๋ก๋˜์—ˆ๊ฑฐ๋‚˜ ๋‚˜์ค‘์— ๋ณ‘ํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ์ €์žฅ๋˜์—ˆ๋‹ค๋ฉด, ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

          ์ฐธ๊ณ : [STREAMS]๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ทœ์ •ํ•ฉ๋‹ˆ๋‹ค: writeAlgorithm์€ ๋‹ค์Œ Promise ๊ฐ€ ํ•ด๊ฒฐ๋œ ํ›„์—๋งŒ ํ˜ธ์ถœ๋˜๋ฉฐ, ์ด๋Š” ์ด์ „์— ์ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ˜ํ™˜๋œ ๊ฐ’์ž…๋‹ˆ๋‹ค. ํšจ์œจ์„ฑ์„ ์œ„ํ•ด ๊ตฌํ˜„์€ ์ด Promise ๋ฅผ ์ผ์ฐ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์—ฌ๋Ÿฌ ์ฒญํฌ๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ, ํ•ด๋‹น ์ฒญํฌ๋Š” WritableStream์˜ ๋‚ด๋ถ€ ํ์—์„œ ๋Œ€๊ธฐํ•˜๋‹ค๊ฐ€ ์šด์˜์ฒด์ œ์— ๋Œ€ํ•œ ๋‹จ์ผ ์š”์ฒญ์œผ๋กœ ๋ณ‘ํ•ฉ๋ฉ๋‹ˆ๋‹ค.

        2. ์šด์˜์ฒด์ œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "UnknownError" DOMException.

        3. ๋งŒ์•ฝ the port was disconnected์ด๋ฉด, ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

          1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[writeFatal]] ์„ true๋กœ.

          2. ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "NetworkError" DOMException.

          3. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ์ฒ˜๋ฆฌ: ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ ๋‹ซ๊ธฐ.

        4. ๋งŒ์•ฝ signal์ด ์ค‘๋‹จ๋จ ์ƒํƒœ์ด๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ signal์˜ ์ค‘๋‹จ ์‚ฌ์œ ๋กœ.

    6. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  7. abortAlgorithm์„ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‘ก๋‹ˆ๋‹ค:

    1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

    2. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค.

      1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํฌํŠธ์˜ ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด ๋ฐ ํ•˜๋“œ์›จ์–ด ์†ก์‹  ๋ฒ„ํผ์˜ ๋‚ด์šฉ์„ ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.

      2. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

        1. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ.

        2. ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

    3. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  8. closeAlgorithm์„ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‘ก๋‹ˆ๋‹ค:

    1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

    2. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค.

      1. ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํฌํŠธ์˜ ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด ๋ฐ ํ•˜๋“œ์›จ์–ด ์†ก์‹  ๋ฒ„ํผ์˜ ๋‚ด์šฉ์„ ํ”Œ๋Ÿฌ์‹œํ•ฉ๋‹ˆ๋‹ค.

      2. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

        1. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค: ๋‹ซ๊ธฐ ์ฒ˜๋ฆฌ: ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ.

        2. ๋งŒ์•ฝ signal์ด ์ค‘๋‹จ๋จ ์ƒํƒœ์ด๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ signal์˜ ์ค‘๋‹จ ์‚ฌ์œ ๋กœ.

        3. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

    3. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  9. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: stream์— ๋Œ€ํ•ด, writeAlgorithm์€ ๋‹ค์Œ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: writeAlgorithm, abortAlgorithm์€ ๋‹ค์Œ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: abortAlgorithm, closeAlgorithm์€ ๋‹ค์Œ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: closeAlgorithm, highWaterMark๋Š” ๋‹ค์Œ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[bufferSize]], ๊ทธ๋ฆฌ๊ณ  sizeAlgorithm์€ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ์„ธ๋Š” ํฌ๊ธฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  10. ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค: ๋‹ค์Œ ์ค‘๋‹จ ๋‹จ๊ณ„๋ฅผ signal์—.

    1. ํฌํŠธ์— ์“ฐ๊ธฐ ์œ„ํ•œ ๋ชจ๋“  ์šด์˜์ฒด์ œ ํ˜ธ์ถœ์ด ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ ์–‘๊ณผ ๊ด€๊ณ„์—†์ด ๊ฐ€๋Šฅํ•œ ํ•œ ๋นจ๋ฆฌ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  11. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[writable]] ์„ stream์œผ๋กœ.

  12. stream์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์ฒ˜๋ฆฌ: ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์ŠคํŠธ๋ฆผ ๋‹ซ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:
  1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[writable]] ์„ null๋กœ.

  2. ๋งŒ์•ฝ this.[[readable]] ์ด null์ด๊ณ  this.[[pendingClosePromise]] ๊ฐ€ null์ด ์•„๋‹ˆ๋ฉด, ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: this.[[pendingClosePromise]] ๋ฅผ undefined๋กœ.

4.8. setSignals() ๋ฉ”์„œ๋“œ

์ง๋ ฌ ํฌํŠธ์—๋Š” ์žฅ์น˜ ๊ฐ์ง€ ๋ฐ ํ๋ฆ„ ์ œ์–ด๋ฅผ ์œ„ํ•œ ์—ฌ๋Ÿฌ ์ถ”๊ฐ€ ์‹ ํ˜ธ๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์กฐํšŒํ•˜๊ณ  ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ผ๋ถ€ ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋ ค๋ฉด ๋จผ์ € "ํ”„๋กœ๊ทธ๋ž˜๋ฐ" ๋ชจ๋“œ์— ์ง„์ž…ํ•ด์•ผ ํ•˜๋ฉฐ, ์ด๋ฅผ ์œ„ํ•ด "๋ฐ์ดํ„ฐ ๋‹จ๋ง ์ค€๋น„"(๋˜๋Š” DTR) ์‹ ํ˜ธ๋ฅผ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
await port.setSignals({ dataTerminalReady: false });
await new Promise(resolve => setTimeout(resolve, 200));
await port.setSignals({ dataTerminalReady: true });
์ด setSignals() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "opened"๊ฐ€ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” "InvalidStateError" DOMException ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. signals์— ๋ช…์‹œ๋œ ๋ฉค๋ฒ„๊ฐ€ ๋ชจ๋‘ ์—†์œผ๋ฉด, ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ TypeError๋กœ ๊ทธ๋ฆฌ๊ณ  promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

    ์ฐธ๊ณ : ์ด์ƒ์ ์œผ๋กœ๋Š” ๋‹ค์Œ์— ์ง€์ •๋œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ, ์ฆ‰ signals์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์›์ž์ ์œผ๋กœ ์ ์šฉํ•ด์•ผ ํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ๊ฐ€ ์ด ๋‹จ๊ณ„๋“ค์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” POSIX ๋ฐ Windows API๋Š” ๋ชจ๋‘ ์ด๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์•„๋ž˜์— ์ œ์‹œ๋œ ์ˆœ์„œ์— ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜์กดํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

    1. ๋งŒ์•ฝ signals["dataTerminalReady"] ๊ฐ€ ์žˆ์œผ๋ฉด, ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜(true์ธ ๊ฒฝ์šฐ) ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค( false์ธ ๊ฒฝ์šฐ). ๋Œ€์ƒ์€ ์ง๋ ฌ ํฌํŠธ์˜ "๋ฐ์ดํ„ฐ ๋‹จ๋ง ์ค€๋น„" ๋˜๋Š” "DTR" ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

    2. ๋งŒ์•ฝ signals["requestToSend"] ๊ฐ€ ์žˆ์œผ๋ฉด, ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜(true์ธ ๊ฒฝ์šฐ) ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค( false์ธ ๊ฒฝ์šฐ). ๋Œ€์ƒ์€ ์ง๋ ฌ ํฌํŠธ์˜ "์†ก์‹  ์š”์ฒญ" ๋˜๋Š” "RTS" ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

    3. ๋งŒ์•ฝ signals["break"] ๊ฐ€ ์žˆ์œผ๋ฉด, ์šด์˜์ฒด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•˜๊ฑฐ๋‚˜(true์ธ ๊ฒฝ์šฐ) ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค( false์ธ ๊ฒฝ์šฐ). ๋Œ€์ƒ์€ ์ง๋ ฌ ํฌํŠธ์˜ "๋ธŒ๋ ˆ์ดํฌ" ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

      ์ฐธ๊ณ : "๋ธŒ๋ ˆ์ดํฌ" ์‹ ํ˜ธ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋Œ€์—ญ ๋‚ด ์‹ ํ˜ธ๋กœ ๊ตฌํ˜„๋˜๋ฉฐ, ์†ก์‹ ์„ ์„ "๋งˆํฌ" ์ „์••์œผ๋กœ ์œ ์ง€ํ•˜๋ฏ€๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ๋ง‰์Šต๋‹ˆ๋‹ค.

    4. ์šด์˜์ฒด์ œ๊ฐ€ ์ด๋Ÿฌํ•œ ์‹ ํ˜ธ ์ค‘ ์–ด๋А ๊ฒƒ์˜ ์ƒํƒœ๋ผ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ๋ชปํ•˜๊ณ , ๊ทธ ์ด์œ ๊ฐ€ ๋ฌด์—‡์ด๋“ , ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "NetworkError" DOMException.

    5. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

  5. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4.8.1. SerialOutputSignals ์‚ฌ์ „

dictionary SerialOutputSignals {
  boolean dataTerminalReady;
  boolean requestToSend;
  boolean break;
};
dataTerminalReady, ํƒ€์ž… boolean
๋ฐ์ดํ„ฐ ๋‹จ๋ง ์ค€๋น„ (DTR)
requestToSend, ๋‹ค์Œ ํƒ€์ž… boolean
์†ก์‹  ์š”์ฒญ (RTS)
break, ํƒ€์ž… boolean
๋ธŒ๋ ˆ์ดํฌ

4.9. getSignals() ๋ฉ”์„œ๋“œ

์ด getSignals() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "opened"๊ฐ€ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” "InvalidStateError" DOMException ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

    1. ์šด์˜์ฒด์ œ์— ์ œ์–ด ์‹ ํ˜ธ์˜ ์ƒํƒœ๋ฅผ ์กฐํšŒํ•˜๋ฉฐ, ์ด ์‹ ํ˜ธ๋Š” ์ง๋ ฌ ํฌํŠธ์— ์—ฐ๊ฒฐ๋œ ์žฅ์น˜๊ฐ€ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ์‹ ํ˜ธ์ž…๋‹ˆ๋‹ค.

    2. ์šด์˜์ฒด์ œ๊ฐ€ ์ด๋Ÿฌํ•œ ์‹ ํ˜ธ์˜ ์ƒํƒœ๋ฅผ ์•Œ์•„๋‚ด์ง€ ๋ชปํ•˜๊ณ , ๊ทธ ์ด์œ ๊ฐ€ ๋ฌด์—‡์ด๋“ , ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ ๋‹ค์Œ์œผ๋กœ: "NetworkError" DOMException ๊ทธ๋ฆฌ๊ณ  ์ด ๋‹จ๊ณ„๋“ค์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

    3. dataCarrierDetect๋ฅผ true๋กœ ๋‘๋Š” ์กฐ๊ฑด์€ "๋ฐ์ดํ„ฐ ๋ฐ˜์†กํŒŒ ๊ฐ์ง€" ๋˜๋Š” "DCD" ์‹ ํ˜ธ๊ฐ€ ์žฅ์น˜์— ์˜ํ•ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์ด๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋กœ ๋‘ก๋‹ˆ๋‹ค.

    4. clearToSend๋ฅผ true๋กœ ๋‘๋Š” ์กฐ๊ฑด์€ "์†ก์‹  ํ—ˆ๊ฐ€" ๋˜๋Š” "CTS" ์‹ ํ˜ธ๊ฐ€ ์ด๋ฏธ ์žฅ์น˜์— ์˜ํ•ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์ด๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋กœ ๋‘ก๋‹ˆ๋‹ค.

    5. ringIndicator๋ฅผ true๋กœ ๋‘๋Š” ์กฐ๊ฑด์€ "ํ˜ธ์ถœ ํ‘œ์‹œ" ๋˜๋Š” "RI" ์‹ ํ˜ธ๊ฐ€ ์ด๋ฏธ ์žฅ์น˜์— ์˜ํ•ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์ด๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋กœ ๋‘ก๋‹ˆ๋‹ค.

    6. dataSetReady๋ฅผ true๋กœ ๋‘๋Š” ์กฐ๊ฑด์€ "๋ฐ์ดํ„ฐ ์„ธํŠธ ์ค€๋น„" ๋˜๋Š” "DSR" ์‹ ํ˜ธ๊ฐ€ ์ด๋ฏธ ์žฅ์น˜์— ์˜ํ•ด ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์ด๋ฉฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด false๋กœ ๋‘ก๋‹ˆ๋‹ค.

    7. signals๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ˆœ์„œ ์žˆ๋Š” ๋งต ยซ[ "dataCarrierDetect" โ†’ dataCarrierDetect, "clearToSend" โ†’ clearToSend, "ringIndicator" โ†’ ringIndicator, "dataSetReady" โ†’ dataSetReady ]ยป.

    8. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ signals๋กœ.

  4. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4.9.1. SerialInputSignals ์‚ฌ์ „

dictionary SerialInputSignals {
  required boolean dataCarrierDetect;
  required boolean clearToSend;
  required boolean ringIndicator;
  required boolean dataSetReady;
};
dataCarrierDetect ๋ฉค๋ฒ„, ํƒ€์ž… boolean
๋ฐ์ดํ„ฐ ๋ฐ˜์†กํŒŒ ๊ฐ์ง€ (DCD)
clearToSend ๋ฉค๋ฒ„, ๋‹ค์Œ ํƒ€์ž… boolean
์†ก์‹  ํ—ˆ๊ฐ€ (CTS)
ringIndicator ๋ฉค๋ฒ„, ํƒ€์ž… boolean
ํ˜ธ์ถœ ํ‘œ์‹œ (RI)
dataSetReady ๋ฉค๋ฒ„, ํƒ€์ž… boolean
๋ฐ์ดํ„ฐ ์„ธํŠธ ์ค€๋น„ (DSR)

4.10. close() ๋ฉ”์„œ๋“œ

ํฌํŠธ์™€์˜ ํ†ต์‹ ์ด ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉด ํฌํŠธ๋ฅผ ๋‹ซ๊ณ  ์‹œ์Šคํ…œ์—์„œ ๊ด€๋ จ ๋ฆฌ์†Œ์Šค๋ฅผ ํ•ด์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ํ˜ธ์ถœํ•˜๋ฉด: port.close() ์•”๋ฌต์ ์œผ๋กœ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค: port.readable.cancel() ๋ฐ port.writable.abort() ์ด๋Š” ๋น„์šฐ๊ธฐ ์œ„ํ•œ ๊ฒƒ์œผ๋กœ, ๋ฒ„ํผ๋ง๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค์Œ์„ ํ˜ธ์ถœํ–ˆ๋‹ค๋ฉด: port.readable.getReader() ๋˜๋Š” port.writable.getWriter() ์ŠคํŠธ๋ฆผ์€ ์ž ๊ธฐ๋ฉฐ ํฌํŠธ๋ฅผ ๋‹ซ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž๋Š” ์ง„ํ–‰ ์ค‘์ธ ์ฝ๊ธฐ ๋˜๋Š” ์“ฐ๊ธฐ ์ž‘์—…์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํฌํŠธ๊ฐ€ ๋‹ซํžˆ๊ธฐ ์ „์— ๋ฒ„ํผ๋ง๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋˜๋„๋ก ๋ณด์žฅํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ Promise ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋ฉฐ, ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ writer.close()์ž…๋‹ˆ๋‹ค.

const encoder = new TextEncoder();
const writer = port.writable.getWriter();
writer.write(encoder.encode("A long message that will take..."));
await writer.close();
await port.close();

์ „์†ก๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฒ„๋ฆฌ๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋Œ€์‹  ๋‹ค์Œ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: writer.abort().

๋งŒ์•ฝ TransformStream ์ด ํŒŒ์ดํ”„๋กœ ์—ฐ๊ฒฐ๋œ ๋Œ€์ƒ์ด port.writable ์ด๋ผ๋ฉด, ๋‹ค์Œ Promise ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ, ์ฆ‰ writer.close() ๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’์˜ ํ•ด๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ํŒŒ์ดํ”„ ์ฒด์ธ์ด ๋‹ซํžˆ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๋ฉฐ, ์ด๋ฅผ ์œ„ํ•ด Promise ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ pipeTo() ์ด๋ฉฐ, ๋Œ€์‹  ์ด ๊ฐ’์˜ ํ•ด๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.

const encoder = new TextEncoderStream();
const writableStreamClosed = encoder.readable.pipeTo(port.writable);
const writer = encoder.writable.getWriter();
writer.write("A long message that will take...");
writer.close();
await writableStreamClosed;
await port.close();

ํฌํŠธ์—์„œ ์ฒญํฌ๋ฅผ ์ฝ๊ธฐ ์œ„ํ•ด ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์˜ˆ์ œ 4์—์„œ์ฒ˜๋Ÿผ, ๋จผ์ € ๋ฃจํ”„๋ฅผ ์ข…๋ฃŒํ•œ ํ›„ ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค: port.close().

let keepReading = true;
let reader;

async function readUntilClosed() {
  while (port.readable && keepReading) {
    reader = port.readable.getReader();
    try {
      while (true) {
        const { value, done } = await reader.read();
        if (done) {
          // |reader|๊ฐ€ ์ทจ์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
          break;
        }
        // |value|๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค...
      }
    } catch (error) {
      // |error|๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค...
    } finally {
      reader.releaseLock();
    }
  }

  await port.close();
}

const closed = readUntilClosed();

// ์–ผ๋งˆ ํ›„...
keepReading = false;
reader.cancel();
await closed;

๋‹ค์Œ์„ ํ˜ธ์ถœํ•˜๋ฉด: reader.cancel() ๋‹ค์Œ ํ˜ธ์ถœ์ด reader.read() ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋˜์–ด, ๋‚ด๋ถ€ ๋ฃจํ”„๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ๋‹ค์Œ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค: reader.releaseLock(). ๊ทธ๋Ÿฌ๋ฉด ์™ธ๋ถ€ ๋ฃจํ”„๋Š” keepReading์ด false๋กœ ์„ค์ •๋˜์—ˆ์œผ๋ฏ€๋กœ ์ข…๋ฃŒ๋˜๋ฉฐ, ์ŠคํŠธ๋ฆผ์˜ ์ž ๊ธˆ์ด ํ•ด์ œ๋˜์–ด port.close() ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ: port.close() ๊ทธ ์‹œ์ ์„ ๋‹ค์Œ Promise ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ ์งํ›„๋กœ ํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ์ด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ reader.cancel() ์ž…๋‹ˆ๋‹ค. ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ ํ˜ธ์ถœ์„ port.close() readUntilClosed()์˜ ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์— ๋‘๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์น˜๋ช…์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ port.readable ์ด null์ด ๋  ๋•Œ๋„ ํฌํŠธ๊ฐ€ ๋‹ซํž™๋‹ˆ๋‹ค.

์ด close() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. promise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  2. ๋งŒ์•ฝ this.[[state]] ๊ฐ€ "opened"๊ฐ€ ์•„๋‹ˆ๋ฉด, promise๋ฅผ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑฐ๋ถ€ ์‚ฌ์œ ๋Š” "InvalidStateError" DOMException ์ด๋ฉฐ, promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  3. cancelPromise๋ฅผ ๋‹ค์Œ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ทจ์†Œ, ๋Œ€์ƒ์€ this.[[readable]] ์ด๋ฉฐ, ๋˜๋Š” ๋‹ค์Œ์œผ๋กœ ํ•ด๊ฒฐ๋œ ํ”„๋กœ๋ฏธ์Šค๋กœ ๋‘ก๋‹ˆ๋‹ค: undefined, ๋งŒ์•ฝ this.[[readable]] ์ด null์ด๋ฉด.

  4. abortPromise๋ฅผ ๋‹ค์Œ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ค‘๋‹จ, ๋Œ€์ƒ์€ this.[[writable]] ์ด๋ฉฐ, ๋˜๋Š” ๋‹ค์Œ์œผ๋กœ ํ•ด๊ฒฐ๋œ ํ”„๋กœ๋ฏธ์Šค๋กœ ๋‘ก๋‹ˆ๋‹ค: undefined, ๋งŒ์•ฝ this.[[writable]] ์ด null์ด๋ฉด.

  5. pendingClosePromise๋ฅผ ๋‹ค์Œ์œผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ์ƒˆ๋กœ์šด ํ”„๋กœ๋ฏธ์Šค.

  6. ๋งŒ์•ฝ this.[[readable]] ๋ฐ this.[[writable]] ์ด null์ด๋ฉด, ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: pendingClosePromise๋ฅผ undefined๋กœ.

  7. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[pendingClosePromise]] ๋ฅผ ๋‹ค์Œ์œผ๋กœ: pendingClosePromise.

  8. combinedPromise๋ฅผ ๋‹ค์Œ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: ๋ชจ๋‘๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํ”„๋กœ๋ฏธ์Šค ๊ฐ€์ ธ์˜ค๊ธฐ, ์ธ์ˆ˜๋Š” ยซcancelPromise, abortPromise, pendingClosePromiseยป์ž…๋‹ˆ๋‹ค.

  9. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[state]] ๋ฅผ "closing"์œผ๋กœ.

  10. ๋ฐ˜์‘ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ combinedPromise์ž…๋‹ˆ๋‹ค.

  11. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

4.11. forget() ๋ฉ”์„œ๋“œ

์ง๋ ฌ ํฌํŠธ์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ์ž๋ฐœ์ ์œผ๋กœ ์ฒ ํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋ถ€์—ฌํ•œ ๊ถŒํ•œ์ž…๋‹ˆ๋‹ค.
// ์ง๋ ฌ ํฌํŠธ๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
const port = await navigator.serial.requestPort();

// ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‚˜์ค‘์—... ์ง๋ ฌ ํฌํŠธ์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ์ฒ ํšŒํ•ฉ๋‹ˆ๋‹ค.
await port.forget();
์ด forget() ๋ฉ”์„œ๋“œ์˜ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
  1. ์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ๊ฐ€ ์ด ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด(์˜ˆ: ๊ถŒํ•œ์ด ๊ด€๋ฆฌ์ž ์ •์ฑ…์— ์˜ํ•ด ๋ถ€์—ฌ๋œ ๊ฒฝ์šฐ), ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: ๋‹ค์Œ์œผ๋กœ ํ•ด๊ฒฐ๋œ ํ”„๋กœ๋ฏธ์Šค: undefined.

  2. ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ๋ฐฉ์‹์€ ๋ณ‘๋ ฌ์ž…๋‹ˆ๋‹ค:

    1. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[state]] ๋ฅผ "forgetting"์œผ๋กœ.

    2. ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค: this๋ฅผ ์‹œ์Šคํ…œ์˜ ์ง๋ ฌ ํฌํŠธ ์‹œํ€€์Šค์—์„œ. ํ•ด๋‹น ์‹œํ€€์Šค๋Š” ์ด์ „ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ ํฌํŠธ๋“ค์ด๋ฉฐ, ํ˜ธ์ถœ ๋Œ€์ƒ์€ requestPort()์ž…๋‹ˆ๋‹ค.

    3. ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค: this.[[state]] ๋ฅผ "forgotten"์œผ๋กœ.

    4. ์ „์—ญ ์ž‘์—…์„ ํ์— ๋„ฃ์Šต๋‹ˆ๋‹ค. ๋Œ€์ƒ์€ ๊ด€๋ จ ์ „์—ญ ๊ฐ์ฒด์ด๋ฉฐ, ์ด๋Š” this์˜ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์ด๋•Œ ์ง๋ ฌ ํฌํŠธ ์ž‘์—… ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค: promise๋ฅผ undefined๋กœ.

  3. promise๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

5. ์ฐจ๋‹จ ๋ชฉ๋ก

์ด ๋ช…์„ธ๋Š” ๋‹ค์Œ ์œ„์น˜์— ์žˆ๋Š” ์ฐจ๋‹จ ๋ชฉ๋ก ํŒŒ์ผ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค: https://github.com/whatwg/serial ์ €์žฅ์†Œ์ด๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์›น์‚ฌ์ดํŠธ๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํฌํŠธ ์ง‘ํ•ฉ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•œ ๊ฒฐ๊ณผ๋Š” Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค ID ์ฐจ๋‹จ ๋ชฉ๋ก ํŒŒ์‹ฑ์ด๋ฉฐ, ๊ทธ ์œ„์น˜์ธ URL url์—์„œ ์–ป๋Š” ๊ฒฐ๊ณผ๋Š” ๋ชฉ๋ก์œผ๋กœ, ๊ทธ ํ•ญ๋ชฉ์€ UUID ๊ฐ’์ด๋ฉฐ ์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋น„์Šค ID๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์ด ์ง๋ ฌ ํฌํŠธ ํ”„๋กœํŒŒ์ผ ์„œ๋น„์Šค ํด๋ž˜์Šค ID๋Š” BluetoothServiceUUID ์ด๋ฉฐ, ๊ฐ’์€ "00001101-0000-1000-8000-00805f9b34fb"์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น BluetoothServiceUUID serviceUuid๊ฐ€ ์ฐจ๋‹จ๋œ Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค UUID์ธ ์กฐ๊ฑด์€ ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค:
  1. uuid๋ฅผ ๋‹ค์Œ ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: BluetoothUUID.getService() ์ธ์ˆ˜๋Š” serviceUuid์ž…๋‹ˆ๋‹ค.

  2. blocklist๋ฅผ ๋‹ค์Œ์˜ ๊ฒฐ๊ณผ๋กœ ๋‘ก๋‹ˆ๋‹ค: Bluetooth ์„œ๋น„์Šค ํด๋ž˜์Šค ID ์ฐจ๋‹จ ๋ชฉ๋ก ํŒŒ์‹ฑ, ๋Œ€์ƒ ์œ„์น˜๋Š” https://github.com/whatwg/serial/blob/main/bluetooth-service-blocklist.txt์ž…๋‹ˆ๋‹ค.

  3. ๋งŒ์•ฝ blocklist๊ฐ€ ํฌํ•จํ•˜๋Š” ๊ฐ’์ด uuid์ด๋ฉด, true๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  4. ๋งŒ์•ฝ uuid์™€ ๊ฐ™์€ ๊ฒƒ์ด ์ง๋ ฌ ํฌํŠธ ํ”„๋กœํŒŒ์ผ ์„œ๋น„์Šค ํด๋ž˜์Šค ID์ด๋ฉด, ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: false.

  5. ๋งŒ์•ฝ uuid๊ฐ€ ๋๋‚˜๋Š” ๊ฐ’์ด "-0000-1000-8000-00805f9b34fb"์ด๋ฉด, ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค: true.

  6. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, false๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

6. ํ†ตํ•ฉ

6.1. ๊ถŒํ•œ ์ •์ฑ…

์ด ๋ช…์„ธ๋Š” ๋…ธ์ถœ๋œ ๋ฉ”์„œ๋“œ์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ •์˜ํ•˜๋ฉฐ, ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์€ serial ์†์„ฑ์œผ๋กœ, ์ด ์†์„ฑ์€ Navigator ๊ฐ์ฒด์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์˜ ๊ธฐ๋Šฅ ์ด๋ฆ„์€ "serial"์ž…๋‹ˆ๋‹ค.

์ด ๊ธฐ๋ณธ ํ—ˆ์šฉ ๋ชฉ๋ก์€ ์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด 'self'์ž…๋‹ˆ๋‹ค.

7. ๋ณด์•ˆ ๊ณ ๋ ค ์‚ฌํ•ญ

์ด ์ ˆ์€ ๋น„๊ทœ๋ฒ”์ ์ž…๋‹ˆ๋‹ค.

์ด API๋Š” ๋‹ค์Œ๊ณผ ์œ ์‚ฌํ•œ ๋ณด์•ˆ ์œ„ํ—˜์„ ์ˆ˜๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค: [WEBBLUETOOTH] ๋ฐ [WEBUSB], ๋”ฐ๋ผ์„œ ์—ฌ๊ธฐ์—๋„ ์ด๋“ค๋กœ๋ถ€ํ„ฐ ์–ป์€ ๊ตํ›ˆ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ์œ„ํ˜‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ์ฃผ๋œ ์™„ํ™”์ฑ…์€ requestPort() ํŒจํ„ด์œผ๋กœ, ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์„ ์š”๊ตฌํ•˜๋ฉฐ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์žฅ์น˜์— ๋Œ€ํ•œ ์ ‘๊ทผ๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์žฅ์น˜๋ฅผ ์—ด๊ฑฐํ•˜์—ฌ ์ทจ์•ฝํ•œ ์žฅ์น˜์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†๊ฒŒ ํ•˜๋ฏ€๋กœ ๋“œ๋ผ์ด๋ธŒ๋ฐ”์ด ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๋ฉฐ, ๋Œ€์‹  ์ ‘๊ทผ์„ ์›ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ช…์‹œ์ ์œผ๋กœ ์•Œ๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„์€ ์‚ฌ์ดํŠธ๊ฐ€ ํ˜„์žฌ ์žฅ์น˜์™€ ํ†ต์‹ ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์‹œ๊ฐ์  ํ‘œ์‹œ์™€ ํ•ด๋‹น ๊ถŒํ•œ์„ ์–ธ์ œ๋“ ์ง€ ์ฒ ํšŒํ•  ์ˆ˜ ์žˆ๋Š” ์ œ์–ด ์ˆ˜๋‹จ์„ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ช…์„ธ๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ์—์„œ ์ œ๊ณต๋˜์–ด์•ผ ํ•œ๋‹ค๊ณ  ์š”๊ตฌํ•˜๋ฉฐ, ์ด๋Š” ๋„คํŠธ์›Œํฌ ๊ธฐ๋ฐ˜ ๊ณต๊ฒฉ์ž์˜ ์•…์„ฑ ์ฝ”๋“œ ์ฃผ์ž…์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์„ ๊ฒฐ์ •ํ•  ๋•Œ ํ‘œ์‹œ๋˜๋Š” ์‚ฌ์ดํŠธ์˜ ์‹ ์›์ด ์ •ํ™•ํ•จ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด ๋ช…์„ธ๋Š” ์ตœ์ƒ์œ„ ๋ฌธ์„œ๊ฐ€ ๋‹ค์Œ์„ ํ†ตํ•ด ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉํ•œ ํ›„์—๋งŒ [PERMISSIONS-POLICY], ๊ต์ฐจ ์ถœ์ฒ˜ iframe์ด API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฒฐํ•ฉํ•˜๋ฉด [CSP3], ์ด๋Ÿฌํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์•…์„ฑ ์ฝ”๋“œ ์ฃผ์ž… ๊ณต๊ฒฉ์œผ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•ด ์ค๋‹ˆ๋‹ค.

๋‚จ์•„ ์žˆ๋Š” ์šฐ๋ ค๋Š” ์—ฐ๊ฒฐ๋œ ์žฅ์น˜๊ฐ€ ํ”ผ์‹ฑ ๊ณต๊ฒฉ์œผ๋กœ ์•…์šฉ๋˜๋Š” ๊ฒƒ์œผ๋กœ, ์‚ฌ์šฉ์ž๋ฅผ ์„ค๋“ํ•˜์—ฌ ์•…์„ฑ ์‚ฌ์ดํŠธ์— ์žฅ์น˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๊ฒŒ ํ•˜๋Š” ๊ณต๊ฒฉ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณต๊ฒฉ์€ ์žฅ์น˜์˜ ์›๋ž˜ ๊ธฐ๋Šฅ์„ ์•…์šฉํ•˜๊ฑฐ๋‚˜ ์žฅ์น˜์— ์•…์„ฑ ํŽŒ์›จ์–ด๋ฅผ ์„ค์น˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ํŽŒ์›จ์–ด๋Š” ๋‹ค์‹œ ํ˜ธ์ŠคํŠธ ์ปดํ“จํ„ฐ๋ฅผ ๊ณต๊ฒฉํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ŠคํŠธ ์†Œํ”„ํŠธ์›จ์–ด๋Š” ์—ฐ๊ฒฐ๋œ ์žฅ์น˜์˜ ์ž…๋ ฅ์„ ์ œ๋Œ€๋กœ ๊ฒ€์ฆํ•˜์ง€ ์•Š์•„ ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ถ„์•ผ์˜ ๋ณด์•ˆ ์—ฐ๊ตฌ๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ณต๊ธ‰์—…์ฒด๊ฐ€ ์—ฐ๊ฒฐ๋œ ์žฅ์น˜๋ฅผ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋„๋ก ์œ ๋„ํ•ด ์™”์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์œ ํ˜•์˜ ๊ณต๊ฒฉ์„ ์™„์ „ํžˆ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์—†์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์—์„œ ์žฅ์น˜๋กœ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ๋Š” ๋‚ด์šฉ์„ ํ•ด์„ํ•  ์ˆ˜ ์—†๋Š” ๋ฐ”์ดํŠธ ์‹œํ€€์Šค์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํŠน์ • ์œ ํ˜•์˜ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์ฐจ๋‹จํ•˜๋ ค๋Š” ์‹œ๋„์— ๋Œ€ํ•ด์„œ๋Š” ๊ทธ๋Ÿผ์—๋„ ํ•ด๋‹น ์œ ํ˜•์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ ค๋Š” ์žฅ์น˜ ์ œ์กฐ์—…์ฒด๊ฐ€ ์šฐํšŒ ๋ฐฉ๋ฒ•์„ ๋งˆ๋ จํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์—์ด์ „ํŠธ๋Š” ์žฅ์น˜ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ์ถ”๊ฐ€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

๋‹ค์Œ์˜ ๊ตฌํ˜„๋“ค์€ [WEBBLUETOOTH] ๋ฐ [WEBUSB], ์ด๋Ÿฌํ•œ ์™„ํ™”์ฑ…์„ ์‹คํ—˜ํ•ด ์™”์ง€๋งŒ, ๊ทธ ํšจ๊ณผ์—๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ์งธ, ์žฅ์น˜์˜ ์•…์šฉ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ์ •์˜ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด API๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ ๊ฐœ๋ฐœ ๋ณด๋“œ์— ํŽŒ์›จ์–ด๋ฅผ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ด API์˜ ํ•ต์‹ฌ ์‚ฌ์šฉ ์‚ฌ๋ก€๋กœ, ์ด๋Ÿฌํ•œ ์žฅ์น˜๊ฐ€ ๊ต์œก ๋ฐ ์ทจ๋ฏธ ์‹œ์žฅ์—์„œ ํ”ํžˆ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณด๋“œ๋Š” ํŽŒ์›จ์–ด ์„œ๋ช… ๊ฒ€์ฆ์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์‰ฝ๊ฒŒ ์•…์„ฑ ์žฅ์น˜๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณด๋“œ๋Š” ๋ถ„๋ช…ํžˆ ์•…์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ฐจ๋‹จํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ทจ์•ฝํ•œ ์žฅ์น˜ ๋ชฉ๋ก์„ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ USB ๋ฐ Bluetooth์— ์ž˜ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ํ”„๋กœํ† ์ฝœ๋“ค์ด ์žฅ์น˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋Œ€์—ญ ์™ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ •์˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ ์žฅ์น˜์˜ ์ œ์กฐ์‚ฌ์™€ ๋ชจ๋ธ์€ ํ˜ธ์ŠคํŠธ์— ๊ฐ€์ƒ ์ง๋ ฌ ํฌํŠธ๋กœ ํ‘œ์‹œ๋˜๋”๋ผ๋„ ์‰ฝ๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฒ”์šฉ USB-์ง๋ ฌ ๋˜๋Š” Bluetooth-์ง๋ ฌ ์–ด๋Œ‘ํ„ฐ๋ฟ ์•„๋‹ˆ๋ผ "์‹ค์ œ" ์ง๋ ฌ ํฌํŠธ๋ฅผ ๊ฐ–์ถ˜ ์‹œ์Šคํ…œ๋„ ์žˆ์œผ๋ฉฐ, DB-25, DE-9 ๋˜๋Š” RJ-45 ์ปค๋„ฅํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š” ์—ฐ๊ฒฐ๋œ ์žฅ์น˜์˜ ์‹ ์›์„ ์•Œ์•„๋‚ด๊ธฐ ์œ„ํ•ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฏ€๋กœ, ํ•ด๋‹น ์žฅ์น˜์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

8. ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ ๊ณ ๋ ค ์‚ฌํ•ญ

์ด ์ ˆ์€ ๋น„๊ทœ๋ฒ”์ ์ž…๋‹ˆ๋‹ค.

์ง๋ ฌ ํฌํŠธ์™€ ์ง๋ ฌ ์žฅ์น˜์—๋Š” ๋‘ ์ข…๋ฅ˜์˜ ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํฌํŠธ๊ฐ€ USB ๋˜๋Š” Bluetooth ์žฅ์น˜์ธ ๊ฒฝ์šฐ, ๊ณต๊ธ‰์—…์ฒด ๋ฐ ์ œํ’ˆ ID(์ œ์กฐ์‚ฌ์™€ ๋ชจ๋ธ์„ ์‹๋ณ„ํ•จ)์™€ ๊ฐ™์€ ์‹๋ณ„์ž๋ฟ ์•„๋‹ˆ๋ผ ์ผ๋ จ๋ฒˆํ˜ธ ๋˜๋Š” MAC ์ฃผ์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง๋ ฌ ์žฅ์น˜ ์ž์ฒด์—๋„ ๊ณ ์œ ํ•œ ์‹๋ณ„์ž๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ง๋ ฌ ํฌํŠธ๋ฅผ ํ†ตํ•ด ๋ณด๋‚ธ ๋ช…๋ น์œผ๋กœ ์ด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฅ์น˜์—๋Š” ์‹๋ณ„ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด ๋‹ค๋ฅธ ์‚ฌ์ ์ธ ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฅ์น˜ ๊ถŒํ•œ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„์€ ์žฅ์น˜ ์‹๋ณ„์ž, ์˜ˆ๋ฅผ ๋“ค์–ด USB ๊ณต๊ธ‰์—…์ฒด ID, ์ œํ’ˆ ID ๋ฐ ์ผ๋ จ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์„ค์ • ํŒŒ์ผ์— ์ €์žฅํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ ์žฅ์น˜์˜ ์•ˆ์ •์ ์ธ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ’์€ ์‚ฌ์ดํŠธ์™€ ์ง์ ‘ ๊ณต์œ ๋˜์ง€ ์•Š์œผ๋ฉฐ, ๊ถŒํ•œ์ด ์ฒ ํšŒ๋˜๊ฑฐ๋‚˜ ์‚ฌ์ดํŠธ ๋ฐ์ดํ„ฐ ์ „์ฒด๊ฐ€ ์‚ญ์ œ๋˜๋ฉด ํ•จ๊ป˜ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

์ ‘๊ทผ์„ ํ—ˆ์šฉ๋ฐ›์€ ํŽ˜์ด์ง€๊ฐ€ ์žฅ์น˜์— ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š” ๋ช…๋ น์„ ํ†ตํ•ด ํŽ˜์ด์ง€๋Š” ์žฅ์น˜์— ์ €์žฅ๋œ ๋‹ค๋ฅธ ๋ฏผ๊ฐํ•œ ์ •๋ณด์—๋„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ยงโ€ฏ7 ๋ณด์•ˆ ๊ณ ๋ ค ์‚ฌํ•ญ์—์„œ ์–ธ๊ธ‰ํ•œ ์ด์œ ๋กœ, ์ด๋ฅผ ๋ง‰๋Š” ๊ฒƒ์€ ๋น„ํ˜„์‹ค์ ์ด๋ฉฐ ๋˜ํ•œ ํŽ˜์ด์ง€๊ฐ€ ์ด ์ •๋ณด์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์‹œ๋„ํ•˜๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„์€ ์‚ฌ์ดํŠธ๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์น˜์— ๋Œ€ํ•œ ์™„์ „ํ•œ ์ œ์–ด๊ถŒ์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•ด์•ผ ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์—†์ด ์žฅ์น˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‹ค์Œ requestPort() ๋ฉ”์„œ๋“œ์˜ ์˜๋„์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์ดํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์žฅ์น˜๋ฅผ ๋ชฐ๋ž˜ ์—ด๊ฑฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŒŒ์ผ ์„ ํƒ๊ธฐ UI์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ ์ „์ฒด๋ฅผ ์•Œ ์ˆ˜ ์—†์œผ๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ํŒŒ์ผ์ด๋‚˜ ๋””๋ ‰ํ„ฐ๋ฆฌ๋งŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„์€ ์‚ฌ์ดํŠธ๊ฐ€ ์ด๋Ÿฌํ•œ ๊ถŒํ•œ์„ ์‚ฌ์šฉํ•  ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆด ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ์œ„ํ•ด ํ‘œ์‹œ ์•„์ด์ฝ˜์„ ํƒญ์ด๋‚˜ ์ฃผ์†Œ ํ‘œ์‹œ์ค„์— ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

"๋น„๊ณต๊ฐœ" ๋˜๋Š” "์‹œํฌ๋ฆฟ" ํƒ์ƒ‰ ๋ชจ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ตฌํ˜„์€ ์‚ฌ์šฉ์ž์˜ ์ผ๋ฐ˜ ํ”„๋กœํ•„์— ์žˆ๋Š” ๊ถŒํ•œ์ด ์ด๋Ÿฌํ•œ ์„ธ์…˜์œผ๋กœ ์ด์–ด์ง€์ง€ ์•Š๋„๋ก ํ•˜๊ณ , ํ•ด๋‹น ์„ธ์…˜์—์„œ ๋ถ€์—ฌ๋œ ๊ถŒํ•œ์ด ์„ธ์…˜ ์ข…๋ฃŒ ํ›„์—๋„ ์œ ์ง€๋˜์ง€ ์•Š๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌํ˜„์€ ์ด๋Ÿฌํ•œ ์„ธ์…˜์—์„œ ์žฅ์น˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•  ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฒฝ๊ณ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์‹๋ณ„ ์ •๋ณด๋ฅผ ์ง์ ‘ ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ์žฅ์น˜ ์‹๋ณ„์ž ๋ฐ ๊ธฐํƒ€ ๊ณ ์œ  ์†์„ฑ์„ ์•ž์„œ ์–ธ๊ธ‰ํ•œ ์žฅ์น˜์™€์˜ ํ†ต์‹ ์„ ํ†ตํ•ด ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ์…˜ ๊ฐ„์— ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์žฅ์น˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์ด ์›น ๋ณด์•ˆ ๋ชจ๋ธ์˜ ๊ธฐ์กด ๊ฒฉ๋ฆฌ ๊ฒฝ๊ณ„๋ฅผ ์–ด๋–ป๊ฒŒ ํ—ˆ๋ฌด๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด, ์ด API๊ฐ€ ๋ถ€์—ฌํ•˜๋Š” ๊ธฐ๋Šฅ์— ๋†€๋ž„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์•ˆ UI์™€ ๋ฌธ์„œ๋Š” ์‚ฌ์ดํŠธ์— ์žฅ์น˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜๋ฉด ์‚ฌ์ดํŠธ๊ฐ€ ์žฅ์น˜์™€ ๊ทธ ์•ˆ์— ํฌํ•จ๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ์ˆ˜ ์žˆ์Œ์„ ์„ค๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌ์˜ ๋ง

๋‹ค์Œ ๋ถ„๋“ค๊ป˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค: Anatol Ulrich, Chris Mumford, Clรฉment Menard, Domenic Denicola, Dominique Hazael-Massieux, Florian Loitsch, Florian Scholz, Francis Gulotta, Franรงois Beaufort, Jack Hsieh, Keavon Chambers, Kenneth Rohde Christiansen, Marcos Cรกceres, Matt Reynolds, Jesse Melhuish, Michael Kohler, Ms2ger, Rick Waldron, Sankha Narayan Guria, Simon Pieters, Suz Hinton, Travis Leithead, ๊ทธ๋ฆฌ๊ณ  Vincent Scheib ์—ฌ๋Ÿฌ๋ถ„์˜ ํ›Œ๋ฅญํ•œ ๊ธฐ์—ฌ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด ํ‘œ์ค€์˜ ์ž‘์„ฑ์ž๋Š” Reilly Grant์ž…๋‹ˆ๋‹ค. (Google, reillyg@google.com).

์ง€์‹์žฌ์‚ฐ๊ถŒ

์ €์ž‘๊ถŒ ยฉ WHATWG (Apple, Google, Mozilla, Microsoft). ์ด ์ €์ž‘๋ฌผ์—๋Š” ํฌ๋ฆฌ์—์ดํ‹ฐ๋ธŒ ์ปค๋จผ์ฆˆ ์ €์ž‘์žํ‘œ์‹œ 4.0 ๊ตญ์ œ ๋ผ์ด์„ ์Šค๊ฐ€ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด ์ €์ž‘๋ฌผ์˜ ์ผ๋ถ€๊ฐ€ ์†Œ์Šค ์ฝ”๋“œ์— ํฌํ•จ๋˜๋Š” ๊ฒฝ์šฐ, ์†Œ์Šค ์ฝ”๋“œ์— ํฌํ•จ๋œ ํ•ด๋‹น ๋ถ€๋ถ„์—๋Š” BSD 3-Clause ๋ผ์ด์„ ์Šค๊ฐ€ ๋Œ€์‹  ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ƒ‰์ธ

์šฉ์–ด ์ •์˜: ์ด ๋ช…์„ธ

์šฉ์–ด ์ •์˜: ์ฐธ์กฐ ๋ฌธ์„œ

์ฐธ๊ณ  ๋ฌธํ—Œ

๊ทœ๋ฒ”์  ์ฐธ๊ณ  ๋ฌธํ—Œ

[DOM]
Anne van Kesteren. DOM ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; ์™ธ. HTML ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY]
Ian Clelland; Ari Chivukula. ๊ถŒํ•œ ์ •์ฑ…. URL: https://w3c.github.io/webappsec-permissions-policy/
[STREAMS]
Adam Rice; ์™ธ. ์ŠคํŠธ๋ฆผ ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://streams.spec.whatwg.org/
[WEBBLUETOOTH]
Reilly Grant. WebBluetooth ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://bluetooth.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://webidl.spec.whatwg.org/

๋น„๊ทœ๋ฒ”์  ์ฐธ๊ณ  ๋ฌธํ—Œ

[CSP3]
Mike West; Antonio Sartori. ์ฝ˜ํ…์ธ  ๋ณด์•ˆ ์ •์ฑ… ๋ ˆ๋ฒจ 3. URL: https://w3c.github.io/webappsec-csp/
[WEBUSB]
Reilly Grant. WebUSB ํ‘œ์ค€. ํ˜„ํ–‰ ํ‘œ์ค€. URL: https://usb.spec.whatwg.org/

IDL ์ƒ‰์ธ

[Exposed=Window, SecureContext]
partial interface Navigator {
  [SameObject] readonly attribute Serial serial;
};

[Exposed=DedicatedWorker, SecureContext]
partial interface WorkerNavigator {
  [SameObject] readonly attribute Serial serial;
};

[Exposed=(DedicatedWorker, Window), SecureContext]
interface Serial : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  Promise<sequence<SerialPort>> getPorts();
  [Exposed=Window] Promise<SerialPort> requestPort(optional SerialPortRequestOptions options = {});
};

dictionary SerialPortRequestOptions {
  sequence<SerialPortFilter> filters;
  sequence<BluetoothServiceUUID> allowedBluetoothServiceClassIds;
};

dictionary SerialPortFilter {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};

[Exposed=(DedicatedWorker,Window), SecureContext]
interface SerialPort : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  readonly attribute boolean connected;
  readonly attribute ReadableStream? readable;
  readonly attribute WritableStream? writable;

  SerialPortInfo getInfo();

  Promise<undefined> open(SerialOptions options);
  Promise<undefined> setSignals(optional SerialOutputSignals signals = {});
  Promise<SerialInputSignals> getSignals();
  Promise<undefined> close();
  Promise<undefined> forget();
};

dictionary SerialPortInfo {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};

dictionary SerialOptions {
  required [EnforceRange] unsigned long baudRate;
  [EnforceRange] octet dataBits = 8;
  [EnforceRange] octet stopBits = 1;
  ParityType parity = "none";
  [EnforceRange] unsigned long bufferSize = 255;
  FlowControlType flowControl = "none";
};

enum ParityType {
  "none",
  "even",
  "odd"
};

enum FlowControlType {
  "none",
  "hardware"
};

dictionary SerialOutputSignals {
  boolean dataTerminalReady;
  boolean requestToSend;
  boolean break;
};

dictionary SerialInputSignals {
  required boolean dataCarrierDetect;
  required boolean clearToSend;
  required boolean ringIndicator;
  required boolean dataSetReady;
};

โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN
โš MDN