Web Serial API
The Serial API provides a way for websites to read and write from a
serial device through script. Such an API would bridge the web and the physical
world, by allowing documents to communicate with devices such as
microcontrollers, 3D printers, and other serial devices.
There is also a companion explainer
document.
Extensions to the {{Navigator}} interface
[Exposed=Window, SecureContext]
partial interface Navigator {
[SameObject] readonly attribute Serial serial;
};
serial attribute
When getting, the {{Navigator/serial}} attribute always returns the same
instance of the {{Serial}} object.
Extensions to the {{WorkerNavigator}} interface
[Exposed=DedicatedWorker, SecureContext]
partial interface WorkerNavigator {
[SameObject] readonly attribute Serial serial;
};
serial attribute
When getting, the {{WorkerNavigator/serial}} attribute always returns the same
instance of
the {{Serial}} object.
{{Serial}} interface
[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 = {});
};
requestPort() method
The {{Serial/requestPort()}} method steps are:
- Let |promise:Promise| be [=a new promise=].
-
If [=this=]'s [=relevant global object=]'s [=associated Document=] is
not [=allowed to use=] the [=policy-controlled feature=] named
`"serial"`, [=reject=] |promise| with a "{{SecurityError}}"
{{DOMException}} and return |promise|.
-
If the [=relevant global object=] of [=this=] does not have [=transient
activation=], [=reject=] |promise| with a "{{SecurityError}}"
{{DOMException}} and return |promise|.
-
If |options|["{{SerialPortRequestOptions/filters}}"] is present, then
for each |filter:SerialPortFilter| in
|options|["{{SerialPortRequestOptions/filters}}"] run the following
steps:
-
If |filter|["{{SerialPortFilter/usbVendorId}}"] is not present,
[=reject=] |promise| with a {{TypeError}} and return |promise|.
This check implements the combined rule that a
{{SerialPortFilter}} cannot be empty and if
{{SerialPortFilter/usbProductId}} is specified then
{{SerialPortFilter/usbVendorId}} must also be specified.
- Run the following steps [=in parallel=]:
-
Prompt the user to grant the site access to a serial port by
presenting them with a list of available ports that [=match any
filter=] in |options|["{{SerialPortRequestOptions/filters}}"] if
present and all available ports otherwise.
-
If the user does not choose a port, [=queue a global task=] on the
[=relevant global object=] of [=this=] using the [=serial port task
source=] to [=reject=] |promise| with an {{"AbortError"}}
{{DOMException}} and abort these steps.
-
Let |port:SerialPort| be a {{SerialPort}} representing the port
chosen by the user.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=resolve=]
|promise| with |port|.
- Return |promise|.
SerialPortRequestOptions dictionary
dictionary SerialPortRequestOptions {
sequence<SerialPortFilter> filters;
};
- filters member
- Filters for serial ports
SerialPortFilter dictionary
dictionary SerialPortFilter {
unsigned short usbVendorId;
unsigned short usbProductId;
};
- usbVendorId member
- USB Vendor ID
- usbProductId member
- USB Product ID
A serial port matches the filter
|filter:SerialPortFilter| if these steps return `true`:
-
If |filter|["{{SerialPortFilter/usbVendorId}}"] is not present, return
`true`.
- If the serial port is not part of a USB device, return `false`.
-
If the USB device's vendor ID is not equal to
|filter|["{{SerialPortFilter/usbVendorId}}"], return `false`.
-
If |filter|["{{SerialPortFilter/usbProductId}}"] is not present, return
`true`.
-
If the USB device's product ID is not equal to
|filter|["{{SerialPortFilter/usbProductId}}"], return `false`.
- Otherwise, return `true`.
A serial port matches any filter in
a sequence of {{SerialPortFilter}} if these steps return `true`:
- For each |filter| in the sequence, run these sub-steps:
- If the serial port does not [=match the filter=] |filter|, return false.
- Return true.
getPorts() method
The {{Serial/getPorts()}} method steps are:
- Let |promise:Promise| be [=a new promise=].
-
If [=this=]'s [=relevant global object=]'s [=associated Document=] is
not [=allowed to use=] the [=policy-controlled feature=] named
`"serial"`, [=reject=] |promise| with a "{{SecurityError}}"
{{DOMException}} and return |promise|.
-
Run the following steps [=in parallel=]:
-
Let |availablePorts| be the sequence of available serial ports on
the system which the user has allowed the site to access as the
result of a previous call to {{Serial/requestPort()}}.
-
Let |ports| be the sequence of the {{SerialPort}}s representing the
ports in |availablePorts|.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=resolve=]
|promise| with |ports|.
- Return |promise|.
onconnect attribute
{{Serial/onconnect}} is an [=event handler IDL attribute=] for the
connect event type.
ondisconnect attribute
{{Serial/ondisconnect}} is an [=event handler IDL attribute=] for the
disconnect event type.
SerialPort interface
[Exposed=(DedicatedWorker,Window), SecureContext]
interface SerialPort : EventTarget {
attribute EventHandler onconnect;
attribute EventHandler ondisconnect;
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();
};
Methods on this interface typically complete asynchronously, queuing work on
the serial port task source.
The [=get the parent=] algorithm for {{SerialPort}} returns the same
{{Serial}} instance that is returned by the {{SerialPort}}'s [=relevant global
object=]'s {{Navigator}} object's {{Navigator/serial}} getter.
Instances of {{SerialPort}} are created with the internal slots described in
the following table:
Internal slot
| Initial value
| Description (non-normative)
|
[[\state]]
| `"closed"`
| Tracks the active state of the {{SerialPort}}
|
[[\bufferSize]]
| undefined
| The amount of data to buffer for transmit and receive
|
[[\readable]]
| `null`
| A {{ReadableStream}} that receives data from the port
|
[[\readFatal]]
`false`
| A flag indicating that the port has encountered a fatal read error
|
[[\writable]]
| `null`
| A {{WritableStream}} that transmits data to the port
|
[[\writeFatal]]
`false`
| A flag indicating that the port has encountered a fatal write error
|
[[\pendingClosePromise]]
| `null`
|
A {{Promise}} used to wait for {{SerialPort/readable}} and
{{SerialPort/writable}} to close
| | |
onconnect attribute
{{SerialPort/onconnect}} is an [=event handler IDL attribute=] for the
{{connect}} event type.
When a serial port becomes available on the system that the user has allowed
the site to access as the result of a previous call to
{{Serial/requestPort()}}, run the following steps:
- Let |port:SerialPort| be a {{SerialPort}} representing the port.
-
[=Fire an event=] named {{connect}} at |port| with its {{Event/bubbles}}
attribute initialized to `true`.
ondisconnect attribute
{{SerialPort/ondisconnect}} is an [=event handler IDL attribute=] for the
{{disconnect}} event type.
When a serial port becomes unavailable on the system that the user has
allowed the site to access as the result of a previous call to
{{Serial/requestPort()}}, run the following steps:
- Let |port:SerialPort| be a {{SerialPort}} representing the port.
-
[=Fire an event=] named {{disconnect}} at |port| with its
{{Event/bubbles}} attribute initialized to `true`.
getInfo() method
The {{SerialPort/getInfo()}} method steps are:
- Let |info:SerialPortInfo| be a [=new=] {{SerialPortInfo}} dictionary.
- If the port is part of a USB device, perform the following steps:
-
Set |info|["{{SerialPortInfo/usbVendorId}}"] to the vendor ID of the
device.
-
Set |info|["{{SerialPortInfo/usbProductId}}"] to the product ID of the
device.
- Return |info|.
SerialPortInfo dictionary
dictionary SerialPortInfo {
unsigned short usbVendorId;
unsigned short usbProductId;
};
- usbVendorId member
-
If the port is part of a USB device this member will be the 16-bit vendor
ID of that device. Otherwise it will be `undefined`.
- usbProductId member
-
If the port is part of a USB device this member will be the 16-bit product
ID of that device. Otherwise it will be `undefined`.
open() method
The {{SerialPort/open()}} method steps are:
- Let |promise| be [=a new promise=].
-
If [=this=].{{[[state]]}} is not `"closed"`, reject |promise| with an
"{{InvalidStateError}}" {{DOMException}} and return |promise|.
-
If |options|["{{SerialOptions/dataBits}}"] is not 7 or 8, reject
|promise| with {{TypeError}} and return |promise|.
-
If |options|["{{SerialOptions/stopBits}}"] is not 1 or 2, reject
|promise| with {{TypeError}} and return |promise|.
-
If |options|["{{SerialOptions/bufferSize}}"] is 0, reject |promise| with
{{TypeError}} and return |promise|.
-
Optionally, if |options|["{{SerialOptions/bufferSize}}"] is larger than
the implementation is able to support, reject |promise| with a
{{TypeError}} and return |promise|.
- Set [=this=].{{[[state]]}} to `"opening"`.
- Perform the following steps [=in parallel=].
-
Invoke the operating system to open the serial port using the
connection parameters (or their defaults) specified in |options|.
-
If this fails for any reason, [=queue a global task=] on the
[=relevant global object=] of [=this=] using the [=serial port task
source=] to [=reject=] |promise| with a "{{NetworkError}}"
{{DOMException}} and abort these steps.
- Set [=this=].{{[[state]]}} to `"opened"`.
-
Set [=this=].{{[[bufferSize]]}} to
|options|["{{SerialOptions/bufferSize}}"].
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=resolve=]
|promise| with `undefined`.
- Return |promise|.
SerialOptions dictionary
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 member
-
A positive, non-zero value indicating the baud rate at which serial
communication should be established.
{{SerialOptions/baudRate}} is the only required member of this
dictionary. While there are common default for other connection
parameters it is important for developers to consider and consult with
the documentation for devices they intend to connect to determine the
correct values. While some values are common there is no standard baud
rate. Requiring this parameter reduces the potential for confusion if an
arbitrary default were chosen by this specification.
- dataBits member
- The number of data bits per frame. Either 7 or 8.
- stopBits member
- The number of stop bits at the end of a frame. Either 1 or 2.
- parity member
- The parity mode.
- bufferSize member
-
A positive, non-zero value indicating the size of the read and write
buffers that should be created.
- flowControl member
- The flow control mode.
ParityType enum
enum ParityType {
"none",
"even",
"odd"
};
- none
- No parity bit is sent for each data word.
- even
- Data word plus parity bit has even parity.
- odd
- Data word plus parity bit has odd parity.
FlowControlType enum
enum FlowControlType {
"none",
"hardware"
};
- none
- No flow control is enabled.
- hardware
- Hardware flow control using the RTS and CTS signals is enabled.
readable attribute
The {{SerialPort/readable}} getter steps are:
-
If [=this=].{{[[readable]]}} is not `null`, return
[=this=].{{[[readable]]}}.
- If [=this=].{{[[state]]}} is not `"opened"`, return `null`.
- If [=this=].{{[[readFatal]]}} is `true`, return `null`.
- Let |stream| be a [=new=] {{ReadableStream}}.
-
Let |pullAlgorithm| be the following steps:
-
Let |desiredSize| be the
desired size
of [=this=].{{[[readable]]}}'s
internal queue.
-
Run the following steps [=in parallel=]:
-
Invoke the operating system to read up to |desiredSize| bytes
from the port, putting the result in the [=byte sequence=]
|bytes|.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to run the
following steps:
-
If no errors were encountered run the following steps:
-
Let |buffer| be a [=new=] {{ArrayBuffer}} created from |bytes|.
-
Let |chunk| be a [=new=] {{Uint8Array}} view over |buffer|,
who's length is the length of |bytes|.
-
Invoke [=ReadableStream/enqueue=] on
[=this=].{{[[readable]]}} with |chunk|.
-
If a buffer overrun condition was encountered, invoke
[=ReadableStream/error=] on [=this=].{{[[readable]]}} with a
"
BufferOverrunError
" {{DOMException}} and
invoke the steps to [=handle closing the readable stream=].
-
If a break condition was encountered, invoke
[=ReadableStream/error=] on [=this=].{{[[readable]]}} with a
"
BreakError
" {{DOMException}} and invoke the
steps to [=handle closing the readable stream=].
-
If a framing error was encountered, invoke
[=ReadableStream/error=] on [=this=].{{[[readable]]}} with a
"
FramingError
" {{DOMException}} and invoke the
steps to [=handle closing the readable stream=].
-
If a parity error was encountered, invoke
[=ReadableStream/error=] on [=this=].{{[[readable]]}} with a
"
ParityError
" {{DOMException}} and invoke the
steps to [=handle closing the readable stream=].
-
If an operating system error was encountered, invoke
[=ReadableStream/error=] on [=this=].{{[[readable]]}} with
an "{{UnknownError}}" {{DOMException}} and invoke the steps
to [=handle closing the readable stream=].
-
If the port was disconnected, run the following steps:
- Set [=this=].{{[[readFatal]]}} to `true`,
-
Invoke [=ReadableStream/error=] on
[=this=].{{[[readable]]}} with a "{{NetworkError}}"
{{DOMException}}.
-
Invoke the steps to [=handle closing the readable
stream=].
- Return [=a promise resolved with=] `undefined`.
The {{Promise}} returned by this algorithm is immediately resolved so
that it does not block canceling the stream. [[STREAMS]] specifies that
this algorithm will not be invoked again until a chunk is enqueued.
-
Let |cancelAlgorithm| be the following steps:
- Let |promise| be [=a new promise=].
-
Run the following steps [=in parallel=].
-
Invoke the operating system to discard the contents of all
software and hardware receive buffers for the port.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to run the
following steps:
-
Invoke the steps to [=handle closing the readable stream=].
- [=Resolve=] |promise| with `undefined`.
- Return |promise|.
-
[=ReadableStream/Set up=] |stream| with
pullAlgorithm
set to |pullAlgorithm|,
cancelAlgorithm
set to |cancelAlgorithm|,
highWaterMark
set to [=this=].{{[[bufferSize]]}}, and
sizeAlgorithm
set to a byte-counting size algorithm.
- Set [=this=].{{[[readable]]}} to |stream|.
- Return |stream|.
To handle closing the readable stream perform the following
steps:
- Set [=this=].{{[[readable]]}} to `null`.
-
If [=this=].{{[[writable]]}} is `null` and
[=this=].{{[[pendingClosePromise]]}} is not `null`, [=resolve=]
[=this=].{{[[pendingClosePromise]]}} with `undefined`.
writable attribute
The {{SerialPort/writable}} getter steps are:
-
If [=this=].{{[[writable]]}} is not `null`, return
[=this=].{{[[writable]]}}.
- If [=this=].{{[[state]]}} is not `"opened"`, return `null`.
- If [=this=].{{[[writeFatal]]}} is `true`, return `null`.
- Let |stream:WritableStream| be a [=new=] {{WritableStream}}.
- Let |writeAlgorithm| be the following steps, given |chunk|:
- Let |promise:Promise| be [=a new promise=].
-
If |chunk| cannot be [=converted to an IDL value=] of type
{{BufferSource}}, reject |promise| with a {{TypeError}} and return
|promise|. Otherwise, save the result of the conversion in
|source:BufferSource|.
-
[=Get a copy of the buffer source=] |source| and save the result in
|bytes|.
-
[=In parallel=], run the following steps:
-
Invoke the operating system to write |bytes| to the port.
Alternately, store the chunk for future coalescing.
The operating system may return from this operation once
|bytes| has been queued for transmission rather than after it
has been transmitted.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to run the
following steps:
-
If the chunk was successfully written, or was stored for
future coalescing, [=resolve=] |promise| with `undefined`.
[[STREAMS]] specifies that |writeAlgorithm| will only be
invoked after the {{Promise}} returned by a previous
invocation of this algorithm has resolved. For efficiency
an implementation is allowed to resolve this {{Promise}}
early in order to coalesce multiple chunks waiting in the
{{WritableStream}}'s internal queue into a single request
to the operating system.
-
If an operating system error was encountered, [=reject=]
|promise| with an "{{UnknownError}}" {{DOMException}}.
-
If the port was disconnected, run the following steps:
- Set [=this=].{{[[writeFatal]]}} to `true`.
-
[=Reject=] |promise| with a "{{NetworkError}}"
{{DOMException}}.
-
Invoke the steps to [=handle closing the writable
stream=].
- Return |promise|.
-
Let |abortAlgorithm| be the following steps:
- Let |promise| be [=a new promise=].
- Run the following steps [=in parallel=].
-
Invoke the operating system to discard the contents of all
software and hardware transmit buffers for the port.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to run the
following steps:
-
Invoke the steps to [=handle closing the writable stream=].
- [=Resolve=] |promise| with `undefined`.
- Return |promise|.
[[STREAMS]] specifies that |abortAlgorithm| will only be invoked after
the {{Promise}} returned by a previous invocation of |writeAlgorithm|
(if any) has resolved. This blocks abort on completion of the most
recent write operation. This could be fixed by passing an
{{AbortSignal}} to |writeAlgorithm|.
This enhancement is tracked in
whatwg/streams#1015.
-
Let |closeAlgorithm| be the following steps:
- Let |promise| be [=a new promise=].
- Run the following steps [=in parallel=].
-
Invoke the operating system to flush the contents of all
software and hardware transmit buffers for the port.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to run the
following steps:
-
Invoke the steps to [=handle closing the writable stream=].
- [=Resolve=] |promise| with `undefined`.
- Return |promise|.
-
[=WritableStream/Set up=] |stream| with
writeAlgorithm
set to |writeAlgorithm|,
abortAlgorithm
set to |abortAlgorithm|,
closeAlgorithm
set to |closeAlgorithm|,
highWaterMark
set to [=this=].{{[[bufferSize]]}}, and
sizeAlgorithm
set to a byte-counting size algorithm.
- Set [=this=].{{[[writable]]}} to |stream|.
- Return |stream|.
To handle closing the writable stream perform the following
steps:
- Set [=this=].{{[[writable]]}} to `null`.
-
If [=this=].{{[[readable]]}} is `null` and
[=this=].{{[[pendingClosePromise]]}} is not `null`, [=resolve=]
[=this=].{{[[pendingClosePromise]]}} with `undefined`.
setSignals() method
The {{SerialPort/setSignals()}} method steps are:
- Let |promise| be [=a new promise=].
-
If [=this=].{{[[state]]}} is not `"opened"`, reject |promise| with an
"{{InvalidStateError}}" {{DOMException}} and return |promise|.
-
If all of the specified members of |signals| are not present reject |promise|
with {{TypeError}} and return |promise|.
- Perform the following steps [=in parallel=]:
-
If |signals|["{{SerialOutputSignals/dataTerminalReady}}"] is
present, invoke the operating system to either assert (if `true`) or
deassert (if `false`) the "data terminal ready" or "DTR" signal on
the serial port.
-
If |signals|["{{SerialOutputSignals/requestToSend}}"] is present,
invoke the operating system to either assert (if `true`) or deassert
(if `false`) the "request to send" or "RTS" signal on the serial
port.
-
If |signals|["{{SerialOutputSignals/break}}"] is present, invoke the
operating system to either assert (if `true`) or deassert (if
`false`) the "break" signal on the serial port.
The "break" signal is typically implemented as an in-band signal
by holding the transmit line at the "mark" voltage and thus
prevents data transmission for as long as it remains asserted.
-
If the operating system fails to change the state of any of these
signals for any reason, [=queue a global task=] on the [=relevant
global object=] of [=this=] using the [=serial port task source=] to
reject |promise| with a "{{NetworkError}}" {{DOMException}}.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=resolve=]
|promise| with `undefined`.
- Return |promise|.
SerialOutputSignals dictionary
dictionary SerialOutputSignals {
boolean dataTerminalReady;
boolean requestToSend;
boolean break;
};
- dataTerminalReady
- Data Terminal Ready (DTR)
- requestToSend
- Request To Send (RTS)
- break
- Break
getSignals() method
The {{SerialPort/getSignals()}} method steps are:
- Let |promise:Promise| be [=a new promise=].
-
If [=this=].{{[[state]]}} is not `"opened"`, reject |promise| with an
"{{InvalidStateError}}" {{DOMException}} and return |promise|.
- Perform the following steps [=in parallel=]:
-
Query the operating system for the status of the control signals
that may be asserted by the device connected to the serial port.
-
If the operating system fails to determine the status of these
signals for any reason, [=queue a global task=] on the [=relevant
global object=] of [=this=] using the [=serial port task source=] to
reject |promise| with a "{{NetworkError}}" {{DOMException}} and
abort these steps.
-
Let |signals:SerialInputSignals| be a [=new=]
{{SerialInputSignals}}.
-
Set |signals|["{{SerialInputSignals/dataCarrierDetect}}"] to `true`
if the "data carrier detect" or "DCD" signal has been asserted by
the device, and `false` otherwise.
-
Set |signals|["{{SerialInputSignals/clearToSend}}"] to `true` if the
"clear to send" or "CTS" signal has been asserted by the device, and
`false` otherwise.
-
Set |signals|["{{SerialInputSignals/dataCarrierDetect}}"] to `true`
if the "ring indicator" or "RI" signal has been asserted by the
device, and `false` otherwise.
-
Set |signals|["{{SerialInputSignals/dataCarrierDetect}}"] to `true`
if the "data set ready" or "DSR" signal has been asserted by the
device, and `false` otherwise.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=resolve=]
|promise| with |signals|.
- Return |promise|.
SerialInputSignals dictionary
dictionary SerialInputSignals {
required boolean dataCarrierDetect;
required boolean clearToSend;
required boolean ringIndicator;
required boolean dataSetReady;
};
- dataCarrierDetect member
- Data Carrier Detect (DCD)
- clearToSend member
- Clear To Send (CTS)
- ringIndicator member
- Ring Indicator (RI)
- dataSetReady member
- Data Set Ready (DSR)
close() method
The {{SerialPort/close()}} method steps are:
- Let |promise| be [=a new promise=].
-
Let |cancelPromise:Promise| be the result of invoking
[=ReadableStream/cancel=] on [=this=].{{[[readable]]}} or [=a promise
resolved with=] `undefined` if [=this=].{{[[readable]]}} is `null`.
-
Let |abortPromise:Promise| be the result of invoking
[=WritableStream/abort=] on [=this=].{{[[writable]]}} or [=a promise
resolved with=] `undefined` if [=this=].{{[[writable]]}} is `null`.
- Let |pendingClosePromise| be [=a new promise=].
-
If [=this=].{{[[readable]]}} and [=this=].{{[[writable]]}} are `null`,
[=resolve=] |pendingClosePromise| with `undefined`.
- Set [=this=].{{[[pendingClosePromise]]}} to |pendingClosePromise|.
-
Let |combinedPromise:Promise| be the result of [=getting a promise to
wait for all=] with «|cancelPromise|, |abortPromise|,
|pendingClosePromise|».
- Set [=this=].{{[[state]]}} to `"closing"`.
-
[=promise/React=] to |combinedPromise|.
-
If |combinedPromise| was fulfilled, then:
-
Run the following steps [=in parallel=]:
-
Invoke the operating system to close the serial port and
release any associated resources.
- Set [=this=].{{[[state]]}} to `"closed"`.
-
Set [=this=].{{[[readFatal]]}} and
[=this=].{{[[writeFatal]]}} to `false`.
- Set [=this=].{{[[pendingClosePromise]]}} to `null`.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to
[=resolve=] |promise| with `undefined`.
-
If |combinedPromise| was rejected with reason |r|, then:
- Set [=this=].{{[[pendingClosePromise]]}} to `null`.
-
[=Queue a global task=] on the [=relevant global object=] of
[=this=] using the [=serial port task source=] to [=reject=]
|promise| with |r|.
- Return |promise|.
Acknowledgements
The following people contributed to the development of this document.