Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need prototype implementation #18

Closed
3 tasks
marcoscaceres opened this issue Nov 5, 2013 · 11 comments
Closed
3 tasks

Need prototype implementation #18

marcoscaceres opened this issue Nov 5, 2013 · 11 comments

Comments

@marcoscaceres
Copy link
Contributor

Would be great to have a prototype implementation.

The setup would be something like:

  • Arduino: connected over firmata to Node.js.
  • Local server: Node + socket.io or similar.
  • Browser: web socket connection to server plus some yet-to-be determined stream library (that we can wrap to provide the same functionality as the WHATWG Streams proposal). We can then wrap everything up and pretend it’s running locally.

It should be fast enough to demonstrate the API working and provide basic read/write operations.

@reconbot
Copy link
Contributor

reconbot commented Nov 5, 2013

This may be answered elsewhere but node-serialport uses buffers for data, would we want to use strings?

@JayBeavers
Copy link
Collaborator

I have a starting point that's pretty close to your scenario that I called 'TrendyCompass':

https://github.com/JayBeavers/node-reflecta/tree/master/samples/TrendyCompass

This uses web sockets, nodejs, html5 canvas, and an arduino with a compass attached.

I have a javascript implementation of the reflecta protocol, currently packaged as node-reflecta, which could be refactored to forward the raw data over web sockets rather than send structured events.

@marcoscaceres
Copy link
Contributor Author

Will definitely check this out. Almost started on this last weekend, but literally spent all my free time reading the Streams spec. It's a really good read. I encourage everyone working on this spec to read that one - as we are building onto of it!

@JayBeavers
Copy link
Collaborator

I'd like to suggest that we factor this and start simpler. Step 1 might be an implementation of the API in NodeJS -- e.g. a refactoring of the node-serialport API. Step 2 could be a web sockets proxy that exposes the same interface. Step 3 would be an app that consumes the web sockets proxy API.

@marcoscaceres
Copy link
Contributor Author

Agree, that would work... the only part that I'm worried about is the streams API part. The rest should be fairly trivial to do given that node-serialport API already handles hooking up serial ports with the underlying system.

@reconbot
Copy link
Contributor

I'm working on this here serialport/node-serialport#1679 I'm hoping the next cut of serialport's binding layer can be a good candidate for the web serial api. The major difference is streams, I don't use them. You can implement any kind of stream or async iterator on top of binding layer but wanted to avoid any particular system because;

  1. For many years node-serialport has been tied to node streams and I find them difficult to reason about
  2. pull-streams/databags, whatwg streams, async iterators, highlandjs, observables, etc - we have many competing ways to do data over time, some of them I love, some of them I've never used, everyone has their favorite. There's no need to pick one.

I went with a composable core a year or two ago. Now I'm rewriting it to reflect the discussions we had here.

It's bound to change a little as I bring the 3 major platforms inline with the abstract, but I quite like where it landed. I'm looking for feedback on the api design, particular around the read behavior. I used to throw a disconnected error that you were supposed to swallow, but instead now allow for resolving 0 bytes, as a pending read during close doesn't need to error. (Writes on the other hand should error as they're intentional things that are failing.)

Naming is also hard.

Anyway, let me know what you think.
serialport/node-serialport#1679 (comment)

export interface PortInfo {
    readonly path: string;
    readonly locationId?: string;
    readonly manufacturer?: string;
    readonly pnpId?: string;
    readonly productId?: string;
    readonly serialNumber?: string;
    readonly vendorId?: string;
}
export interface LocalState {
    readonly baudRate: number;
    readonly brk: boolean;
    readonly dataBits: 5 | 6 | 7 | 8;
    readonly dtr: boolean;
    readonly lock: boolean;
    readonly parity: 'none' | 'even' | 'mark' | 'odd' | 'space';
    readonly rts: boolean;
    readonly rtscts: boolean;
    readonly stopBits: 1 | 1.5 | 2;
}

export interface ConstructorOptions extends PortInfo, LocalState {
    readonly descriptor: number;
}
export interface OpenOptions extends LocalState {
    readonly path: string;
}

export interface RemoteState {
    readonly cts: boolean;
    readonly dcd: boolean;
    readonly dsr: boolean;
}
/**
 * You never have to use `Binding` objects directly. SerialPort uses them to access the underlying hardware.
 */
export declare class AbstractBinding implements PortInfo, LocalState {
    locationId?: string;
    manufacturer?: string;
    path: string;
    pnpId?: string;
    productId?: string;
    serialNumber?: string;
    vendorId?: string;
    baudRate: number;
    brk: boolean;
    dataBits: 5 | 6 | 7 | 8;
    dtr: boolean;
    lock: boolean;
    parity: 'none' | 'even' | 'mark' | 'odd' | 'space';
    rts: boolean;
    rtscts: boolean;
    stopBits: 1 | 1.5 | 2;
    descriptor: number;
    hasClosed: boolean;
    /**
     * Retrieves a list of available serial ports with metadata. The `comName` must be guaranteed, and all other fields should be undefined if unavailable. The `path` is either the path or an identifier (eg `COM1`) used to open the serialport.
     */
    static list(): Promise<ReadonlyArray<PortInfo>>;
    /**
     * Opens a connection to the serial port referenced by the path.
     */
    static open<T>(this: T, options: OpenOptions): Promise<T>;
    constructor(opt: ConstructorOptions);
    /**
     * Closes an open connection
     */
    close(): Promise<void>;
    /**
     * Drain waits until all output data is transmitted to the serial port. An in progress write should be completed before this returns.
     */
    drain(): Promise<void>;
    /**
     * Flush (discard) data received but not read, and written but not transmitted.
     */
    flush(): Promise<void>;
    /**
     * Get the remote state flags (CTS, DSR, DCD) on the open port.
     */
    getRemoteState(): Promise<RemoteState>;
    /**
     * Request a number of bytes from the SerialPort. This function is similar to Node's [`fs.read`](http://nodejs.org/api/fs.html#fs_fs_read_fd_buffer_offset_length_position_callback) except it will always read at least one byte while the port is open. In progress reads must resolve with any available data when the port is closed, if there is no data when a port is closed read 0 bytes.
     */
    read(buffer: Buffer, offset: number, length: number): Promise<number>;
    /**
     * Set local state on an open port including updating baudRate and control flags. The state is represented on the object as well as resolved in the promise.
     */
    setLocalState(options: Partial<LocalState>): Promise<LocalState>;
    /**
     * Write bytes to the SerialPort. Only call when there is no pending write operation. In progress writes must error when the port is closed.
     */
    write(buffer: Buffer): Promise<void>;
}

@reillyeon
Copy link
Collaborator

I'm also interested in building a prototype implementation on top of either the Chrome Apps chrome.serial API or the WebUSB API (for USB-to-serial converters). I think this will be very helpful in exploring whether or not WHATWG Streams work for us.

@reconbot
Copy link
Contributor

reconbot commented Nov 16, 2018 via email

@reillyeon
Copy link
Collaborator

My team is working on a prototype built on top of WebUSB. We will try to get something released publicly as soon as possible. It can be tested on platforms like Linux and macOS where you can unload drivers from the command line or on Android where there are helpfully no serial drivers to begin with.

@marcoscaceres
Copy link
Contributor Author

@reillyeon, this can probably be closed, right? The prototype is in Chrome.

@reillyeon
Copy link
Collaborator

There are actually two prototype implementations, one in Chromium and the other in a polyfill.

Closing this issue as suggested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants