{"id":13762844,"url":"https://github.com/Timendus/ticalc-usb","last_synced_at":"2025-05-10T15:31:59.792Z","repository":{"id":42753502,"uuid":"279583015","full_name":"Timendus/ticalc-usb","owner":"Timendus","description":"A library to communicate with TI graphing calculators through WebUSB","archived":false,"fork":false,"pushed_at":"2023-03-14T17:26:35.000Z","size":893,"stargazers_count":23,"open_issues_count":25,"forks_count":2,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-05-12T06:21:33.199Z","etag":null,"topics":["calculator","es6","javascript","ti-84","ti-84-plus","usb","webusb"],"latest_commit_sha":null,"homepage":"https://ticalc.link","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Timendus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-14T12:46:56.000Z","updated_at":"2024-08-03T14:05:38.983Z","dependencies_parsed_at":"2024-08-03T14:16:07.022Z","dependency_job_id":null,"html_url":"https://github.com/Timendus/ticalc-usb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fticalc-usb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fticalc-usb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fticalc-usb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Timendus%2Fticalc-usb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Timendus","download_url":"https://codeload.github.com/Timendus/ticalc-usb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224974208,"owners_count":17401100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calculator","es6","javascript","ti-84","ti-84-plus","usb","webusb"],"created_at":"2024-08-03T14:00:58.946Z","updated_at":"2024-11-16T21:30:46.561Z","avatar_url":"https://github.com/Timendus.png","language":"JavaScript","funding_links":["https://ko-fi.com/T6T0DOOWP"],"categories":["Libraries"],"sub_categories":[],"readme":"[![Build Status](https://github.com/timendus/ticalc-usb/actions/workflows/test.yaml/badge.svg)](https://github.com/Timendus/ticalc-usb/actions/workflows/test.yaml)\n[![Version on NPM](https://img.shields.io/npm/v/ticalc-usb)](https://www.npmjs.com/package/ticalc-usb)\n[![Downloads on NPM](https://img.shields.io/npm/dt/ticalc-usb)](https://www.npmjs.com/package/ticalc-usb)\n[![Maintainability](https://api.codeclimate.com/v1/badges/06bc064d98df904cc4b7/maintainability)](https://codeclimate.com/github/Timendus/ticalc-usb/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/06bc064d98df904cc4b7/test_coverage)](https://codeclimate.com/github/Timendus/ticalc-usb/test_coverage)\n[![License](https://img.shields.io/github/license/timendus/ticalc-usb)](LICENSE)\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/T6T0DOOWP)\n\n# ticalc-usb\n\n`ticalc-usb` is a Javascript library to communicate with Texas Instruments\ngraphing calculators over WebUSB. It also has a module that can parse TI files\n(`*.8?p` / `*.8?g` files). As I only own a TI-84 Plus, development is highly\nskewed towards that device, but other devices should be fairly simple to add.\n\nCheck out [ticalc.link](http://ticalc.link) to see the library in action.\n\n## Status of this library\n\nThis library is currently very experimental. I have successfully communicated\nwith my TI-84 Plus with it, and sent files to it. However, it comes with\nabsolutely no guarantees that it can handle other models or even other versions\nof the TI-84 Plus, nor that it can properly parse and send any file you throw at\nit. So be warned.\n\nIf you run into issues, please\n[report them](https://github.com/Timendus/ticalc-usb/issues/new) or submit a PR.\n\n## Usage\n\n`ticalc-usb` is [available through NPM](https://www.npmjs.com/package/ticalc-usb)\nand can be installed as a dependency using NPM or Yarn:\n\n```bash\nnpm install --save ticalc-usb\n```\n\nYou can then import both modules of the library in your project like this:\n\n```javascript\nconst { ticalc, tifiles } = require('ticalc-usb');\n```\n\n### `ticalc`\n\nThe `ticalc` module exposes these regular functions:\n\n  * `browserSupported()` - returns true if `ticalc-usb` can work in the current\n    browser\n  * `models()` - returns an array of objects that represent available calculator models,\n    so we can show that to the user.\n  * `addEventListener(event, handler)` - allows you to subscribe to `connect`\n    and `disconnect` events. Your event handler will be called with a calculator\n    object as a parameter.\n\nAnd these async functions:\n\n  * `init()` - initialise the library. This binds event handlers to\n    `navigator.usb` and connects to previously connected devices. Not calling\n    this results in crappy connect/disconnect events.\n  * `choose()` - triggers a WebUSB dialog in which the user can choose a\n    supported calculator. A successful choice will lead to a `connect` event.\n\nPlease note that the Promises that both `init` and `choose` return can be\nrejected if the user selects a device that is not supported. Unfortunately Texas\nInstruments reused their USB product IDs, so we can't be more specific up front.\nYou'll probably want to catch this error and show the user an appropriate\nmessage. Also, `choose` will reject if the user selects no device at all.\n\nA somewhat complete example:\n\n```javascript\nticalc.addEventListener('connect', async calculator =\u003e {\n  if ( await calculator.isReady() ) {\n    // Type \"HELLO\", key values for TI-83/84 Plus taken from\n    // https://github.com/debrouxl/tilibs/blob/master/libticalcs/trunk/src/keys83p.h\n    await calculator.pressKey(0xA1);\n    await calculator.pressKey(0x9E);\n    await calculator.pressKey(0xA5);\n    await calculator.pressKey(0xA5);\n    await calculator.pressKey(0xA8);\n\n    // Get available memory\n    console.log(await calculator.getFreeMem());\n  }\n});\n\ntry {\n  // Initialise the library\n  await ticalc.init();\n\n  // Ask user to pick a device. Don't do this on page load, browsers don't like\n  // that, plus `init` may already have fired a `connect` event. Call this\n  // function when the user clicks on a button.\n  await ticalc.choose();\n} catch(e) {\n  // Handle unsupported or no device selected\n  console.error(e);\n}\n```\n\nOn calculator objects you can call five async methods, three of which are shown\nin the example above:\n\n  * `isReady()` - return true if calculator is connected and listening\n  * `pressKey(key)` - remotely press a key on the calculator\n  * `getFreeMem()` - get free RAM and Flash memory\n  * `sendFile(file)` - send a given file object to the calculator (silent transfer)\n  * `getStorageDetails(file)` - check if a given file object fits in the available storage\n\nAnd one regular method:\n\n  * `canReceive(file)` - tells you if a file is valid for this calculator\n\n### `tifiles`\n\nThe `tifiles` module exposes these functions:\n\n  * `parseFile(bindata)` - expects a Uint8Array and returns a file object\n  * `isValid(file)` - tells you if the file you have parsed is a valid calculator file\n\nCombined with `ticalc`, we can use these functions to send a TI file to a\nconnected calculator:\n\n```javascript\n// Load file (make sure readFile returns a Uint8Array)\nconst file = tifiles.parseFile(readFile(filename));\n\nif ( !tifiles.isValid(file) )\n  return console.error('The file you have selected does not seem to be a valid calculator file');\n\n// Assuming we received a calculator object from the `connect` event\nif ( !calculator.canReceive(file) )\n  return console.error(`The file you have selected does not appear to be a valid file for your ${calculator.name}`);\n\nawait calculator.sendFile(file);\n```\n\n### Special features\n\nThe `init` and `choose` functions can take an options object. This exposes some\nspecial features that most people will not need, but do come in handy sometimes.\n\n#### Choosing the right support level\n\nBy default, `ticalc-usb` will only successfully resolve the `choose` promise if\nthe connected calculator has the status `supported`. You can be more adventurous\nand also allow calculators that have `partial-support`, `beta` support or that\nare `experimental`.\n\nIf you want your user to be able to select any possible Texas Instruments\ndevice, not just the ones that have any support at all, use `none`.\n\nYou have to pass this alternative `supportLevel` as an option to the `init`\nfunction:\n\n```javascript\nawait ticalc.init({ supportLevel: 'beta' });\n```\n\nI use this feature in [ticalc.link](http://ticalc.link) to allow users to\nexperiment with newly added devices, and to submit support requests for\nunsupported devices.\n\n#### Injecting a different WebUSB object\n\nBy default, `ticalc-usb` will check to see if your web browser supports WebUSB\nand then take `navigator.usb` and wrap it in an object that adds logging and\nrecording for debugging purposes. You can override this behaviour by supplying\nanother object that implements the WebUSB API.\n\nFor example, you can use\n[thegecko's Node.js WebUSB implementation](https://github.com/thegecko/webusb)\nby handing it to `init` and `choose`:\n\n```javascript\nconst usb = require('webusb').usb;\nawait ticalc.init({ usb });\nawait ticalc.choose({ usb });\n```\n\n#### Getting the debug recording\n\nThe default WebUSB wrapper records all interactions with the WebUSB API. You can\nget the recording by asking `ticalc` for it. `ticalc.getRecording()` returns an\ninstance of [Recorder](src/webusb/recorder.js).\n\n```javascript\nconst recording = ticalc.getRecording().getSteps();\n```\n\n## Developing\n\nThe easiest way to work on this library is to work on a project that makes use\nof it. I use [ticalc.link](http://ticalc.link) for this, and if you don't have a\nproject of your own in mind, you can use it too.\n\nFirst, check out both repositories:\n\n```bash\ngit clone git@github.com:Timendus/ticalc.link.git\ngit clone git@github.com:Timendus/ticalc-usb.git\n```\n\nThen, make sure your changes to `ticalc-usb` are watched and get transpiled when\nyou make a change:\n\n```bash\ncd ticalc-usb\nnpm install\nnpm start\n```\n\nIn another terminal, make sure you also have the tests running, so you don't\nbreak things by accident:\n\n```bash\ncd ticalc-usb\nnpm run watch-tests\n```\n\nAnd finally, in yet another terminal, use your local `ticalc-usb` as a\ndependency for `ticalc.link` and serve the website:\n\n```bash\ncd ticalc.link\nsed -i.bak 's/\"ticalc-usb\": \".*\"/\"ticalc-usb\": \"file:\\/\\/..\\/ticalc-usb\"/g' package.json \u0026\u0026 rm package.json.bak\nnpm install\nnpm start\n```\n\n_(Note: If you don't have sed on your machine, manually replace the version\nmatcher for `ticalc-usb` in `ticalc.link`'s `package.json` file with\n`file://../ticalc-usb`.)_\n\n`ticalc.link` should now be running on [localhost:8080](http://localhost:8080)\nwith the local version of `ticalc-usb`. Any changes to `ticalc-usb` should\ntrigger a reload of the website automatically.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTimendus%2Fticalc-usb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTimendus%2Fticalc-usb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTimendus%2Fticalc-usb/lists"}