GithubHelp home page GithubHelp logo

web-serial-polyfill's Introduction

Serial API Polyfill

An implementation of the Web Serial API on top of the WebUSB API for use with USB-to-serial adapters. Use of this library is limited to hardware and platforms where the device is accessible via the WebUSB API because it has not been claimed by a built-in device driver. This project was used to prototype the design of the Web Serial API and remains useful for platforms (such as Android) which support the WebUSB API but do not support the Web Serial API.

This is also available as an npm package here for convenience.

A demo of this library is provided as part of the serial terminal demo and can be activated by clicking the "Switch to API polyfill" link.

web-serial-polyfill's People

Contributors

a-j-bauer avatar chris-rudmin avatar jameshollyergoogle avatar lanrat avatar reillyeon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web-serial-polyfill's Issues

getInfo method should not reject before opening the port

In the "real" Web Serial API one can query information about the available ports before opening a connection:

const ports = await serial.getPorts();
const info = await ports[0].getInfo();

But results in a rejection with the polyfill:

DOMException: The device must be opened first

How to run demo.html in Chrome on macOS

To get to know this project, I wanted to play around with demo.html on my macOS machine. I had to make some adjustments to demo.html and temporarily prevent macOS from claiming the CDC ACM device. Maybe someone else finds this useful.

Lacking access to an Android device, are there more natural ways to play around with the polyfill?

Get demo.html running in Chrome on macOS

diff --git a/demo.html b/demo.html
index c51c8d3..769acfd 100644
--- a/demo.html
+++ b/demo.html
@@ -31,9 +31,10 @@
 <p>parity: <span id="parity"/></p>
 <button id='getInfo'>Read fdSerial Options</button>
 <p id='ReceivedText'></p>
-<script src="serial.js"></script>
 
-<script>
+<script type="module">
+  import { serial } from './dist/serial.js'
+
   var mySerial;
   let receivedText = '';
   let reader = {};
@@ -81,7 +82,7 @@
     // );
   });
 
-  str2ab = function(str) {
+  const str2ab = function(str) {
     var buf = new ArrayBuffer(str.length); // 2 bytes for each char
     var bufView = new Uint8Array(buf);
     for (var i=0, strLen=str.length; i < strLen; i++) {
@@ -90,7 +91,7 @@
     return buf;
   }
 
-  ab2str = function(buf) {
+  const ab2str = function(buf) {
     return String.fromCharCode.apply(null, new Uint8Array(buf));
   }
 
diff --git a/tsconfig.json b/tsconfig.json
index 39ac6a8..750c576 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,6 @@
 {
   "compilerOptions": {
-    "module": "commonjs",
+    "module": "es2015",
     "lib": ["dom", "es2017"],
     "outDir": "./dist/",
     "sourceMap": true,

Temporary prevent macOS from claiming CDC ACM devices

# Stop macOS from claiming CDC ACM devices.
sudo kextunload -b com.apple.driver.usb.cdc.acm

# Give control back to macOS.
sudo kextload -b com.apple.driver.usb.cdc.acm 

Android: usb.getDevices() succeeds but serial.getDevices() fails

Chrome on Android supports navigator.usb but not navigator.serial so I'm trying to use this polyfill to access a serial device that works from Chrome on Mac & PC.

The command that succeeds in finding and connecting to the device on all platforms, including Android:

navigator.usb.requestDevice({
    filters:[{
        vendorId: 0x0403,
        productId: 0x6001
    }]
}).then(p => console.log({p}))

I would expect the following to work, but it does not:

exports.serial.requestPort({
    filters:[{
        usbVendorId: 0x0403,
        usbProductId: 0x6001
    }]
}).then(p => console.log({p}))

the same command replacing exports.serial with navigator.serial on Mac and Windows succeeds. getPorts() similarly fails

web-serial-polyfill and web-serial desktop and Android

@reillyeon

So I am doing better with web-serial-polyfill getting better speeds on Android, my forked github is here and demo page is here

What I would like to do is make equivalent pages for both polyfill and webUSB, but I can't find a simple webUSB github or code example except for this working demo here which I strangely can't even find the github for it.

I am having some minor issues with polyfill getting the reader and writer objects properties and methods printed and switching from promises to async/await. Other than that things are going well

For both situations my simple working Arduino code is


/*
 * webSerial for testing javascript connection with an arduino
 * 
 * Note: On the Arduino Serial monitor make sure no line-ending or if statements will not work
 * 
 * Android https://hpssjellis.github.io/web-serial-polyfill/index.html
 * Laptops Desktops  https://hpssjellis.github.io/my-examples-of-arduino-webUSB-webSerial/public/index.html
 * IOS     not really sure
 * 
 */



#include <Arduino.h> // Only needed for https://platformio.org/

String readString;

int myDelay = 5000;   // non-block delay in milliseconds
unsigned long myStart; 
int serialMessage = 1;
int myCount=48;      //48 = ascii 0,    58 ascii 9

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);   // onboard LED, HIGH = off
  
  myStart = millis();   // set delay
  randomSeed(analogRead(A0));  // AO pin on XIAO does not have to be connected to anything

}

void loop() {

  if ( (millis() - myStart ) >= myDelay) {       
     myStart = millis();      //  reset the delay time
     myCount++;
     if (myCount >= 58){ // 48 = ascii 0,    58 ascii 9
       myCount = 48;
     }       
     //char myChar = (char)myCount;      
     byte myChar = (byte)myCount;    
     Serial.write(myChar);  
   }

  

  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }

  if (readString.length() > 0) {
    Serial.println(readString);

    if (readString == "a"){
      digitalWrite(LED_BUILTIN, LOW); //onboard LED LOW = on
      Serial.println("LED ON");
    }
    if (readString == "b"){
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED OFF");
    }
    readString="";
  } 
}

  


Any suggestions or opinions are welcome?

This issue started as an issue on the arduino webusb library webusb/arduino#96

add optional parameter signalOptions to open

Background: When opening the serial port on some development devices e.g. Arduino, the device gets reset if DTR is true.
It would be really nice to be able to connect and see periodic serial output of possibly long running programms without the controller restarting when opening the serial port.

The default setting of dataTerminalReady in the open function should be optionally changeable somehow.

Proposal:

    /**
     * a function that opens the device and claims all interfaces needed to
     * control and communicate to and from the serial device
     * @param {SerialOptions} options Object containing serial options
     * @param {SignalOptions} optional signals Object containing signal options
     * @return {Promise<void>} A promise that will resolve when device is ready
     * for communication
     */
    async open(options, signals) {
        this.serialOptions_ = options;
        this.signalOptions_ = signals !== undefined ? signals : { dataTerminalReady: true }
        this.validateOptions();
        try {
            await this.device_.open();
            if (this.device_.configuration === null) {
                await this.device_.selectConfiguration(1);
            }
            await this.device_.claimInterface(this.controlInterface_.interfaceNumber);
            if (this.controlInterface_ !== this.transferInterface_) {
                await this.device_.claimInterface(this.transferInterface_.interfaceNumber);                
            }
            await this.setLineCoding();
            await this.setSignals(this.signalOptions_);
        }
        catch (error) {
            if (this.device_.opened) {
                await this.device_.close();
            }
            throw new Error('Error setting up device: ' + error.toString());
        }
    }

This would also be nice in the existing component:Blink>Serial but I don't know how to make a feature request there.

Adding and removing event listeners

In the "real" Web Serial API it is possible to add and remove Event listener that listen on the connect and disconnect events:

serial.addEventListener('connect', connectHandler);
serial.addEventListener('disconnect', disconnectHandler);

The disconnect listener is IMHO especially important, so that one can clean up after the device has been disconnected.

Harmonize with Blink Serial API implementation

  • Blink doesn't implement setOptions() and getInfo(). The semantics of these are unclear but multiple implementation experience here could be instructive.
  • Blink expects SerialOptions to be passed to open().
  • Blink expects SerialPortRequestOptions to be passed to requestPort().
  • Blink does not provide a SerialPort constructor. The constructor provided by the polyfill is useful for manually constructing a SerialPort from a USBDevice which is something the polyfill can support clients doing outside of the specified Serial API.

Feature request: Design a webpage that informs if webSerial or polyfill works on the device.

@reillyeon

Feature request: Design a webpage that informs if webSerial or polyfill works on the device and prints the results to the page instead of console.log

Background: I presently am testing my students Android cell phones to see which ones work with polyfill. I think my old Samsung S20? used to work but I had to trade it in to get my new phone. My very Old Samsung S8 does not work. The problem with testing is that I have to connect an Arduino to their phone to see if it works. It would be much easier to have the webApp determine if polyfill should work.

Presently I think most Google Pixel phones should work, but would like to know which other phones work and if any developer options can be used to make more phones work with Polyfill.

If someone can show me the code I will write the app.

I think @gohai is close with this p5.js testing program, just the code does not give any feedback about polyfill on the canvas.
gohai/p5.webserial@f899391

My testing is showing that you can't check if webSerial or usb polyfill can be used until you connect a device, so it looks like I am back to connecting Arduinos to student's phones.

Anyone have a list of Phones that work with polyfill or developer options to turn on the ability? Any suggestions?

Vanilla javascript example

Hello, I'm trying to use this package to have my website communicate with my arduino sketch. On desktop chrome I have it working with USB Web Serial from 'navigator'. However in Android this is not made available.
This is where this lib comes useful.
I have found the old demo.html file and the dist/serial.js. However it shows me only the USB_VID/PID I can't get the send/receive function to work.

Would it be possible to share an example on how to use this library?
I like jquery, but plain vanilla javascript would be very helpful.
I have never used .ts files, but if know this is the way to use this lib, I'm open to learn that file format as well. (or at least how this concept is working).

Thanks in advance.

WebSerial update?

@reillyeon can you give a state of webSerial at the moment? I thought I had it working fine about 6 months ago, and went to work with it today and got no interaction after connection from my android chrome, whereas my code works fine from a desktop.

#41

No compiled file published to npm in 1.0.7

In latest version of polyfill, the whole repo is uploaded to npm. There is no compiled js file or dist folder. But package.json still requires js files inside dist folder. As a result, I am unable to import serial.

File structure node_modules/web-serial-polyfill in 1.0.7
image
file structure in 1.0.6
image

NetworkError: Failed to execute 'transferIn' on 'USBDevice': A transfer error has occurred.

As pointed in #57, the web-page faces an issue after X amount of time (or data, or events) has been passed.
The message is:
NetworkError: Failed to execute 'transferIn' on 'USBDevice': A transfer error has occurred.

In order to reproduce the error I made a small web-page and a small Arduino sketch.
Both can found here:
https://github.com/karelv/web-serial-example

And here:
https://karelv.github.io/web-serial-example/

Steps to reproduce:

After I got:
image

And chrome://device-log gives:
image

Compared to the observation in #57 there are only 2 error message (and 2 debug message) whereas in #57 they were countless.
Therefore it is wise to review the javascript code I am using that webpage, maybe there is something wrong on my end.

USB CDC Only

Hi,

I hadn't seen this polyfill until recently although it's only going to work for USB CDC devices.

FTDI USB-to-Serial devices are quite popular and used in many devices (for example, most Arduinos, Raspberry Pi). The FTDI devices require a different approach when communicating with them. The proper way to do it is demonstrated in the Linux kernel driver source. I tried to get FTDI to send me some details but they got super squeamish when I mentioned open source even though the Linux driver is.

I then wrote my own driver, it's not ready yet but it's a good start, I'd be open to it being used here to make the polyfill more compatible.

Thanks.

open() fails with NetworkError: Unable to claim interface

Hi !
I like to use the linked npm package in an Angular application but I'm not able to open the serial port.

This is the test code:

    // implementation with web-serial-polyfill lib
    this.comPort = await serial.requestPort();
    if (this.comPort) {
      console.log(this.comPort);
      await this.comPort.open();
      console.log(this.comPort);
    }

The requestPort() function is working (permission access dialog is shown and populated with the device):

SerialPort {serialOptions_: {…}, device_: USBDevice}
device_: USBDevice {configurations: Array(1), deviceClass: 2, deviceProtocol: 0, deviceSubclass: 2, deviceVersionMajor: 2, …}
serialOptions_: {baudrate: 115200, databits: 8, stopbits: 1, parity: "none", buffersize: 255, …}
transferInterface_: USBInterface {alternates: Array(1), claimed: false, interfaceNumber: 1, alternate: null}
__proto__: Object

but the following open() function always fails:

core.js:4197 ERROR Error: Uncaught (in promise): Error: Error setting up device: NetworkError: Unable to claim interface.
Error: Error setting up device: NetworkError: Unable to claim interface.
    at SerialPort.open (serial.js:88)
    at resolvePromise (zone-evergreen.js:798)
    at zone-evergreen.js:705
    at rejected (tslib.es6.js:72)
    at ZoneDelegate.invoke (zone-evergreen.js:364)
    at Object.onInvoke (core.js:27430)
    at ZoneDelegate.invoke (zone-evergreen.js:363)
    at Zone.run (zone-evergreen.js:123)
    at zone-evergreen.js:857
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:27418)

What's the exact meaning of "Unable to claim interface" ?
The device shouldn't be blocked by an other application. It's listed under /dev/ttyACM0 and I can open it with a serial terminal program like cutecom without problems.

Thanks for any help !

Best regards,
Michael.

NPM package outdated

Could you please publish a new package to NPM, the current one is two years old.

TypeError: serial.SerialPort is not a constructor

I use npm to install and use the demo try to requested manuallly from the webUSB API and it show TypeError: serial.SerialPort is not a constructor
image
image
I am studying mechanical engineering and try to send the data of a sensor to the web through USB.

Create a readable byte stream

The Web Serial API has been updated to create a readable byte stream. This polyfill should do the same in order to allow code to assume the availability of BYOB readers.

Given that WebUSB and Web Bluetooth do not support BYOB reads there would be no performance benefit to this change. WICG/webusb#217 tracks adding a BYOB feature to WebUSB.

Nothing happens after clicking RequestInfo

I downloaded this project, hosted it, opened it in my browser, connected a serial device to it and clicked request info. Nothing happens! I added an alert to recheck if the button click event was being fired correctly, and the alert does pop up, however nothing else happens. Could you help me out with this?

More Details
I am using an RS232 to USB cable that has an OTG adapter attached to it, and connecting my device using this cable to an android tablet.

Implement support for CDC composite gadget

Device info:
cdc composite gadget
cdc composite gadget configuration

I could not use the polyfill to communicate with the device, It stated that there was no in endpoint, and then I changed the alternates and the interfaces that it communicate with but then I got error when I tried to send the control bits.

Maybe it is just some configuration that needed to change?
Thanks for your help

Unable to find interface with class 2

device info:
image
image

the device works well with navigator.serial in crhome 89.
but it will not work with the polyfill code in lower version chrome. it will throw the errror: "Unable to find interface with class 2"

Which phones support Android Polyfill?

@reillyeon

Can we just list the phones that support Android Polyfill

I have it working on a Google Pixel V2. So I am going to guess that it works on all Pixel phones.

I think I had it working on a Samsung Galaxy S19, but it does not presently work on my Galaxy S4, S8 or my latest S22 Ultra. I am going to assume polyfill does not work on the Samsung brand.

Has anyone tried Polyfill with any of these brands?

Samsung     : doesn't work
Google Pixel  2 and 3:  Works, Not for my Pixel 6
OnePlus
Xiaomi   Works (user reported Redmi K40)
Oppo
Vivo
Motorola
LG
Sony
Nokia

If anyone wants to test their phone my WebSerial and Android Polyfill webpage is here The Arduino sketch for it is here but I will inline it below:


/*
 * webSerial for testing javascript connection with an arduino
 * 
 * 
 * Android https://hpssjellis.github.io/web-serial-polyfill/index.html
 * Laptops Desktops  https://hpssjellis.github.io/my-examples-of-arduino-webUSB-webSerial/public/index.html
 * IOS     not really sure
 * 
 */



#include <Arduino.h> // Only needed for https://platformio.org/

String readString;

int myDelay = 5000;   // non-block delay in milliseconds
unsigned long myStart; 
int serialMessage = 1;
int myCount=48;      //48 = ascii 0,    58 ascii 9

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);   // onboard LED, HIGH = off
  
  myStart = millis();   // set delay
  randomSeed(analogRead(A0));  // AO pin on XIAO does not have to be connected to anything

}

void loop() {

  if ( (millis() - myStart ) >= myDelay) {       
     myStart = millis();      //  reset the delay time
     myCount++;
     if (myCount >= 58){ // 48 = ascii 0,    58 ascii 9
       myCount = 48;
     }       
     //char myChar = (char)myCount;      
     byte myChar = (byte)myCount;    
     Serial.write(myChar);  
   }

  

  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }

  if (readString.length() > 0) {
    readString.trim();  // get rid of last weird character
    Serial.println(readString);

    if (readString == "a"){
      digitalWrite(LED_BUILTIN, LOW); //onboard LED LOW = on
      Serial.println("LED ON");
    }
    if (readString == "b"){
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED OFF");
    }
    readString="";
  } 
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.