{"id":20046033,"url":"https://github.com/johntalton/mcp2221","last_synced_at":"2025-05-05T09:31:24.890Z","repository":{"id":37789970,"uuid":"322129027","full_name":"johntalton/mcp2221","owner":"johntalton","description":"MCP 2221 Controler Library","archived":false,"fork":false,"pushed_at":"2024-07-09T17:56:49.000Z","size":1575,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-10T17:59:19.282Z","etag":null,"topics":["nodejs","stream","usb","webhid"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johntalton.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-12-16T23:40:32.000Z","updated_at":"2024-07-09T17:56:52.000Z","dependencies_parsed_at":"2024-06-19T03:18:04.854Z","dependency_job_id":"16776d0d-12f7-41c6-a792-0d2bbfa8eea4","html_url":"https://github.com/johntalton/mcp2221","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johntalton%2Fmcp2221","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johntalton%2Fmcp2221/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johntalton%2Fmcp2221/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johntalton%2Fmcp2221/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johntalton","download_url":"https://codeload.github.com/johntalton/mcp2221/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224436921,"owners_count":17310929,"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":["nodejs","stream","usb","webhid"],"created_at":"2024-11-13T11:20:32.508Z","updated_at":"2024-11-13T11:20:33.029Z","avatar_url":"https://github.com/johntalton.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MCP2221\nFull featured MCP2221 library with WebHID and node support over StreamAPI 🥳\n\n[![npm Version](http://img.shields.io/npm/v/@johntalton/mcp2221.svg)](https://www.npmjs.com/package/@johntalton/mcp2221)\n![GitHub package.json version](https://img.shields.io/github/package-json/v/johntalton/mcp2221)\n[![CI](https://github.com/johntalton/mcp2221/actions/workflows/CI.yml/badge.svg)](https://github.com/johntalton/mcp2221/actions/workflows/CI.yml)\n![GitHub](https://img.shields.io/github/license/johntalton/mcp2221)\n[![Downloads Per Month](http://img.shields.io/npm/dm/@johntalton/mcp2221.svg)](https://www.npmjs.com/package/@johntalton/mcp2221)\n![GitHub last commit](https://img.shields.io/github/last-commit/johntalton/mcp2221)\n\nStandard [Adafruit](https://www.adafruit.com/product/4471) link.\n\n- [Features](#features)\n- [Stream API](#stream-api)\n  - [WebHID](#web-hid)\n  - [Node-HID](#node-hid)\n- [I²C](#direct-api) (raw)\n- [`I2CBus`](#i2cbus-abstraction-recommended)\n- [Security](#security)\n\n\n![i2c scan](https://raw.githubusercontent.com/johntalton/mcp2221/main/examples/mcp2221-scan.png?raw=true)\n\n# Features\n\nSupport full range of command and functionality, including:\n\n- Password Protected\n    - Access Password setting\n    - New password Flash writes\n    - Alter Security settings\n    - no guard against humans\n\n- Status\n    - Reset\n    - Clear Interrupt\n    - I²C Diagnostics\n    - ADC output\n\n- General Purpose\n    - Digital In / Out (Gpio)\n    - ADC 3x\n    - DAC\n    - Clock\n    - Interrupt on Change (with variable edge detection)\n    - USB Host Suspend and Configuration state\n\n- I²C\n    - standard direct methods\n    - addition `I2CBus` abstraction support\n\n- USB\n    - USB Descriptor support\n    - vendor / product Id\n    - requested mA\n    - etc\n\n\n# Example\n\nThe following example gives the outline of the usage pattern for creating the binding layer between the underlying HID implementations and this chip library.\n\n```javascript\nimport { MCP2221 } from '@johntalton/mcp2221'\n\nconst hidDevice = { /* likely navigator.hid.getDevices() ... etc */ }\nconst source = new HIDStreamSource(hidDevice)\nconst chip = MCP2221.from(source)\n\n// do something with the chip\nconst { adc } = await chip.common.status()\nconst { ch0, ch1, ch2 } = adc\n```\n\n# Stream API\n\nIndividual HID implementations are abstracted over the [Stream API](https://developer.mozilla.org/en-US/docs/Web/API/Streams_API) that supports BYOB (bring you own buffer) and Byte specific stream.\n\nAs such, the interface `HIDStreamSource` is used to normalize the sources  into a stream.\n\nTwo examples of Stream Sources are given bellow: WebHID and Node-HID.\n\n## Web HID\n\nThe [WebHID](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API) interface provides a robust browser based HID implementation ([browser support](https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API#browser_compatibility))\n\nThe example code above can be updated to use the the concrete `WebHIDStreamSource`.\n\nThe API has several way of acquiring a `HIDDevice`, most common is to make a request for existing connected devices via [`navigator.hid.getDevices()`](https://developer.mozilla.org/en-US/docs/Web/API/HID/getDevices).\n\n\nNOTE: an un-packaged version of WebHIDStraemSource can be found [here](https://github.com/johntalton/webapp-device-playground/blob/main/public/util/hid-stream.js). (future package publication may be forthcoming)\n\n## Node HID\n\nNodeJS provides several HID binding packages.  In the following example we will use the [`node-hid`](https://github.com/node-hid/node-hid) package.\n\nAs with WebHID, there are several interaction patters, and device discovery techniques. The following code explicit opens the device by vID/pID (note that the MCP2221 has the ability to \"change\" its IDs, it's defaults are used here).\n\nNOTE: the current NodeHIDStreamSource is un-packaged, and can be found [here](https://github.com/johntalton/webapp-device-playground/blob/main/service/node-hid-stream.js)\n\n\n```javascript\nimport { MCP2221 } from '@johntalton/mcp2221'\nimport HID from 'node-hid'\nimport { NodeHIDStreamSource } from './hid-stream-source.js'\n\nconst VENDOR_ID = 1240\nconst PRODUCT_ID = 221\nconst hid = await HID.HIDAsync.open(VENDOR_ID, PRODUCT_ID)\nconst source = new NodeHIDStreamSource(hid)\nconst chip = MCP2221.from(source)\n\n// do something with the chip, like clear the interrupt flag\nawait chip.sram.set({ gp: { interrupt: { clear: true } } })\n\n```\n\n## USB Descriptors\n\nSetting the USB descriptors can effect how the device is discovered.  HID implementation code should take into account those variation (as well as vendor and product ID assignments).\n\n![usb descriptors](https://raw.githubusercontent.com/johntalton/mcp2221/main/examples/mcp2221-descriptors.png?raw=true)\n\nNote: Descriptors are considered parts of the FLASH and are subject to [Security](#security) restriction.\n\n\n# I²C\n\n## `I2CBus` abstraction (recommended)\n\nBasic usage of such API can be useful in some instances. However, due to complexities and error checking logic, it is recommended to use the [`I2CBus`](https://github.com/johntalton/i2c-bus-mcp2221) abstraction layer\n\n\n## Direct API\n\nThe MCP2221 exposes several low-level I²C constructs.\nThese can be used to build custom bus interactions\n\nNote: the chip's I²C state machine can hang / crash is care is not taken to check status and appropriately cancel transaction.  `I2CBus` usage is encouraged, and may also be a good reference.\n\nThe following example is simplification from the the above `I2CBus` implementation [code](https://github.com/johntalton/i2c-bus-mcp2221/blob/main/src/utils/read.ts).\n\n```javascript\nconst chip // chip from base examples\n\n// request a read of length 3 bytes from address 0x70 (7-bit address)\nconst REQUESTED_I2C_BYTE_LENGTH = 3\n\n// start the request\nconst { status } = await chip.i2c.readData({\n    address: 0x70,\n    length: REQUESTED_I2C_BYTE_LENGTH\n})\nif(status !== 'success') { throw new Error('☠️') }\n// check i2c state and other transfer values for readiness\n\n//\n// it is almost sertian that a call to `status` is needed, the commands \"success\" status value is not sufficiant for checking the state of the bus\n// const { status, i2cStateName, ... } = await device.common.status({ opaque })\n// if (__i2cStatusIsNotOk__) { throw new Error('😢') }\n\n// if that all went well then attempt to get the buffer\n// here we allow the chip to allocate the buffer\n// BYOB can be used here also for performance / efficiency\nconst { validData, buffer, readBackBytes } = await chip.i2c.readGetData()\nif(!validData) { throw new Error('🧨') }\nif(readBackBytes === REQUESTED_I2C_BYTE_LENGTH) { throw new Error('👎') }\n\n\n// process the data\n// check if the returned buffer is a view and coheres it into a Uint8Array\nconst u8 = ArrayBuffer.isView(buffer) ?\n    new Uint8Array(buffer, buffer.byteOffset, buffer.byteLength) :\n    new Uint8Array(buffer)\n\n// deconstruct TypedArray\nconst [ one, two, three ] = u8\n\n\n```\n\n# Security\n\nWhile the chips SRAM settings (gpio etc) can be changed at will, these settings must explicit be save into FLASH.\n\nUnder normal conditions the chip's Security setting is \"Unlocked\".  This allows for writing to the FLASH without restriction.\n\nHowever, if set to \"Password Protected\", the chip will enforce the sending of the password (once per \"session\") prior to FLASH writes.\n\nFailure to set the password during a \"session\" will prevent further password attempts until the \"session\" is over.\n\nNote:  Assumption about string padding (space vs null), justification and encoding (ut-8 etc) effect password byte representation.  It is \"wise\" to use the same software to get AND set the password.\n\n![password failure](https://raw.githubusercontent.com/johntalton/mcp2221/main/examples/mcp2221-no-password-error.png?raw=true)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohntalton%2Fmcp2221","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohntalton%2Fmcp2221","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohntalton%2Fmcp2221/lists"}