ARMmbed/dapjs

Prepare dapjs for "direct" use in web apps

philipphenkel opened this issue · 7 comments

I would love to use dapjs directly in my web apps with full benefits of type safety. Today, dap.bundle.js has to be included to use dapjs in a web app. The bundle is pure JavaScript, and thus we lose the benefits of TypeScript.

I plan to use dapjs (edit: the source files, not the library) with create-react-app and would need to get the following steps resolved:

  • compliant with TypeScript 3.0
  • compliant with "strictNullChecks": true
  • compliant with "noImplicitReturns": true
  • get rid of Node.js dependencies in code and project structure, e.g. do not reference hid.ts and usb.ts

I'm confused as to what you are asking for here. Dapjs is already written in Typescript and as browsers don't natively support it, it has to be bundled into JavaScript for use in the browser.

The browserify task in the gulp file already ignores the node specific libraries, so the output bundle is already set up to only target WebUSB.

Finally, to use dapjs with Typescript projects, just import it from npm. The types should be correctly set up.

I want to use dapjs as first class citzien in my app, e.g.

import { DAPLink } from './dapjs/daplink';
import { WebUSB } from './dapjs/transport/webusb';

I failed to add types to the dap.bundle.js because usb and hid are currently referenced via index.ts files. Is there a way to use the bundle with types without any modification?

I'm currently preparing a PR that allows to use dapjs source files directly in a pure web project (copy instead of library dependency). The changes are not web-specific and might be beneficial for the project - at least if you didn't decide against stricter checks for a good reason.

Just wondering if this went anywhere. I'm currently making a webapp that involves serial communication between a micro:bit and would love to directly import the DAPLink and WebUSB modules into the project directly.

My project setup is currently using NodeJS as the server, TypeScript for the client-side code which is then compiled to JS, then finally make browser compatible by using Browserify.

If I try to import DAPLink and WebUSB using import {DAPLink, WebUSB} from 'dapjs'; then Browserify complains that it could not find the module in \node_modules\dapjs\bundles. I can resolve this by directly importing from the dapjs\lib\ folder like so:

import { WebUSB } from "dapjs/lib/transport/webusb";
import { DAPLink } from "dapjs/lib/daplink";

If I then try to perform any serial communication with this device, the data sent and received seems corrupt. Could this be caused by the dependency of NodeJS.Timer? Here is a quick mockup example of the code I use to communicate to a micro:bit using DAPjs.

import * as $ from "jquery";
import { WebUSB } from 'dapjs/lib/transport/webusb';
import { DAPLink } from 'dapjs/lib/daplink';

const BAUD_RATE = 115200;

const connectButton = $('#connect');
const sendButton = $('#send');

let bridge;

connectButton.on("click", () => {
    selectDevice();
})

function selectDevice() {
    navigator.usb.requestDevice({
        filters: [{vendorId: 0xD28}]
    })
    .then(device => {
        connectDevice(device, BAUD_RATE);
    })
    .catch(error => {
        console.log(error);
    });
}

function connectDevice(device: any, baud: number) {
    const transport = new WebUSB(device);
    const target = new DAPLink(transport);

    navigator.usb.addEventListener("disconnect", () => {
       console.log("Disconnected");
       target.startSerialRead();
       target.disconnect();
    });

    target.on(DAPLink.EVENT_SERIAL_DATA, data => {
        console.log("Received: " + data.trim());
    });

    return target.connect()
        .then(() => {
            target.setSerialBaudrate(baud);
            return target.getSerialBaudrate();
        })
        .then(baud => {
            target.startSerialRead();
            console.log(`Listening at ${baud} baud...`);
            bridge = target;
        });
}

sendButton.on("click", () => {
    bridge.serialWrite("TEST\n");
    console.log("Sending test");
})

This exact code in JS using <script type="text/javascript" src="bundles/dap.bundle.js"></script> works almost flawlessly, but when using direct imports and Browserify things get ugly. Here's some example output from a micro:bit that stores whatever text it receives and sends it back on button A:

Listening at 115200 baud...

Received: �Listening on 115200   
Test:5          est:3

Received: �Testening on 115200   
Test:5          est:3

Received: �Test       
Test:7                     


Received: �Test
Test:8                        
Test:9 

Received: �Testÿÿÿ           
Test:6             st:0  

Any updates/info on your webapp-friendly DAPjs would be appreciated!

I have a version that works well in the context of
https://www.webusb-programmer.com/

It looks like this project is not interested in PRs. I could create a fork and share my changes.

Import styles as outlined by @Taylor-Woodcock Are the right way of accessing types which aren't exposed at the top level.

import { WebUSB } from "dapjs/lib/transport/webusb";
import { DAPLink } from "dapjs/lib/daplink";

I don't think this has any bearing on the serial issue mentioned.
I have exposed the ability to change the serial delay in #38 which may fix this.

@philipphenkel The NodeJs.Timer inclusion was an oversight and shouldn't exist. I'll write a web example which use the types.
Upgrading to the latest versions of TS, Node and gulp should also be undertaken which I can take a look at. Your PR went some way to doing this and apologies it has got stale.

@thegecko No need to apologize. I'm looking forward to the improvements.

Brilliant news! Looking forward to these changes.