npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ticalc-usb

v1.1.2

Published

A library to communicate with TI graphing calculators through WebUSB

Downloads

8

Readme

Build Status Version on NPM Downloads on NPM Maintainability Test Coverage License

ticalc-usb

ticalc-usb is a Javascript library to communicate with Texas Instruments graphing calculators over WebUSB. It also has a module that can parse TI files (*.8?p / *.8?g files). As I only own a TI-84 Plus, development is highly skewed towards that device, but other devices should be fairly simple to add.

Check out ticalc.link to see the library in action.

Status of this library

This library is currently very experimental. I have successfully communicated with my TI-84 Plus with it, and sent files to it. However, it comes with absolutely no guarantees that it can handle other models or even other versions of the TI-84 Plus, nor that it can properly parse and send any file you throw at it. So be warned.

If you run into issues, please report them or submit a PR.

Usage

ticalc-usb is available through NPM and can be installed as a dependency using NPM or Yarn:

npm install --save ticalc-usb

You can then import both modules of the library in your project like this:

const { ticalc, tifiles } = require('ticalc-usb');

ticalc

The ticalc module exposes these regular functions:

  • browserSupported() - returns true if ticalc-usb can work in the current browser
  • models() - returns an array of objects that represent available calculator models, so we can show that to the user.
  • addEventListener(event, handler) - allows you to subscribe to connect and disconnect events. Your event handler will be called with a calculator object as a parameter.

And these async functions:

  • init() - initialise the library. This binds event handlers to navigator.usb and connects to previously connected devices. Not calling this results in crappy connect/disconnect events.
  • choose() - triggers a WebUSB dialog in which the user can choose a supported calculator. A successful choice will lead to a connect event.

Please note that the Promises that both init and choose return can be rejected if the user selects a device that is not supported. Unfortunately Texas Instruments reused their USB product IDs, so we can't be more specific up front. You'll probably want to catch this error and show the user an appropriate message. Also, choose will reject if the user selects no device at all.

A somewhat complete example:

ticalc.addEventListener('connect', async calculator => {
  if ( await calculator.isReady() ) {
    // Type "HELLO", key values for TI-83/84 Plus taken from
    // https://github.com/debrouxl/tilibs/blob/master/libticalcs/trunk/src/keys83p.h
    await calculator.pressKey(0xA1);
    await calculator.pressKey(0x9E);
    await calculator.pressKey(0xA5);
    await calculator.pressKey(0xA5);
    await calculator.pressKey(0xA8);

    // Get available memory
    console.log(await calculator.getFreeMem());
  }
});

try {
  // Initialise the library
  await ticalc.init();

  // Ask user to pick a device. Don't do this on page load, browsers don't like
  // that, plus `init` may already have fired a `connect` event. Call this
  // function when the user clicks on a button.
  await ticalc.choose();
} catch(e) {
  // Handle unsupported or no device selected
  console.error(e);
}

On calculator objects you can call five async methods, three of which are shown in the example above:

  • isReady() - return true if calculator is connected and listening
  • pressKey(key) - remotely press a key on the calculator
  • getFreeMem() - get free RAM and Flash memory
  • sendFile(file) - send a given file object to the calculator (silent transfer)
  • getStorageDetails(file) - check if a given file object fits in the available storage

And one regular method:

  • canReceive(file) - tells you if a file is valid for this calculator

tifiles

The tifiles module exposes these functions:

  • parseFile(bindata) - expects a Uint8Array and returns a file object
  • isValid(file) - tells you if the file you have parsed is a valid calculator file

Combined with ticalc, we can use these functions to send a TI file to a connected calculator:

// Load file (make sure readFile returns a Uint8Array)
const file = tifiles.parseFile(readFile(filename));

if ( !tifiles.isValid(file) )
  return console.error('The file you have selected does not seem to be a valid calculator file');

// Assuming we received a calculator object from the `connect` event
if ( !calculator.canReceive(file) )
  return console.error(`The file you have selected does not appear to be a valid file for your ${calculator.name}`);

await calculator.sendFile(file);

Special features

The init and choose functions can take an options object. This exposes some special features that most people will not need, but do come in handy sometimes.

Choosing the right support level

By default, ticalc-usb will only successfully resolve the choose promise if the connected calculator has the status supported. You can be more adventurous and also allow calculators that have partial-support, beta support or that are experimental.

If you want your user to be able to select any possible Texas Instruments device, not just the ones that have any support at all, use none.

You have to pass this alternative supportLevel as an option to the init function:

await ticalc.init({ supportLevel: 'beta' });

I use this feature in ticalc.link to allow users to experiment with newly added devices, and to submit support requests for unsupported devices.

Injecting a different WebUSB object

By default, ticalc-usb will check to see if your web browser supports WebUSB and then take navigator.usb and wrap it in an object that adds logging and recording for debugging purposes. You can override this behaviour by supplying another object that implements the WebUSB API.

For example, you can use thegecko's Node.js WebUSB implementation by handing it to init and choose:

const usb = require('webusb').usb;
await ticalc.init({ usb });
await ticalc.choose({ usb });

Getting the debug recording

The default WebUSB wrapper records all interactions with the WebUSB API. You can get the recording by asking ticalc for it. ticalc.getRecording() returns an instance of Recorder.

const recording = ticalc.getRecording().getSteps();

Developing

The easiest way to work on this library is to work on a project that makes use of it. I use ticalc.link for this, and if you don't have a project of your own in mind, you can use it too.

First, check out both repositories:

git clone [email protected]:Timendus/ticalc.link.git
git clone [email protected]:Timendus/ticalc-usb.git

Then, make sure your changes to ticalc-usb are watched and get transpiled when you make a change:

cd ticalc-usb
npm install
npm start

In another terminal, make sure you also have the tests running, so you don't break things by accident:

cd ticalc-usb
npm run watch-tests

And finally, in yet another terminal, use your local ticalc-usb as a dependency for ticalc.link and serve the website:

cd ticalc.link
sed -i.bak 's/"ticalc-usb": ".*"/"ticalc-usb": "file:\/\/..\/ticalc-usb"/g' package.json && rm package.json.bak
npm install
npm start

(Note: If you don't have sed on your machine, manually replace the version matcher for ticalc-usb in ticalc.link's package.json file with file://../ticalc-usb.)

ticalc.link should now be running on localhost:8080 with the local version of ticalc-usb. Any changes to ticalc-usb should trigger a reload of the website automatically.