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 🙏

© 2025 – Pkg Stats / Ryan Hefner

pico-otp-wasm

v0.1.0

Published

WASM bindings for pico-otp library - Generate OTP data for Raspberry Pi Pico 2 and RP2350 devices

Downloads

5

Readme

pico-otp-wasm

WebAssembly bindings for the pico-otp library, enabling browser-based generation and parsing of OTP (One-Time Programmable) data for Raspberry Pi Pico 2 and other RP2350-based devices.

Features

  • Generate OTP data from JSON whitelabel configurations
  • Parse full OTP dumps (4096 rows) from real devices
  • Parse targeted whitelabel data without requiring complete OTP dumps
  • Structured error handling with detailed error types and context
  • Zero-copy where possible with efficient Uint8Array/Uint16Array/Uint32Array usage
  • TypeScript definitions automatically generated

Building

# Make build script executable
chmod +x build.sh

# Build the WASM module
./build.sh

This will:

  1. Compile the Rust code to WASM using wasm-pack
  2. Generate TypeScript definitions
  3. Create documentation in docs/
  4. Prepare deployment files in deploy/

Quick Start

Basic HTML/JavaScript Usage

<!DOCTYPE html>
<html>
<head>
    <script type="module">
        import init, { json_to_otp } from './pkg/pico_otp_wasm.js';

        async function run() {
            // Initialize the WASM module
            await init();

            // Create JSON configuration
            const json = JSON.stringify({
                device: {
                    vid: "0x1234",
                    pid: "0xabcd",
                    manufacturer: "My Company",
                    product: "My Product"
                }
            });

            try {
                // Generate OTP data
                const otpData = json_to_otp(json);
                
                console.log('USB Boot Flags:', otpData.usb_boot_flags);
                console.log('Row count:', otpData.row_count);
                console.log('ECC rows:', otpData.ecc_rows);
                console.log('ECC bytes:', otpData.ecc_bytes);
            } catch (e) {
                console.error('Error:', e.message);
                console.error('Type:', e.errorType);
            }
        }

        run();
    </script>
</head>
<body>
    <h1>pico-otp WASM Demo</h1>
</body>
</html>

Testing

Open index.html in a web browser (requires a local web server due to WASM CORS restrictions):

# Using Python
python3 -m http.server 8000

# Using Node.js http-server
npx http-server

# Then open http://localhost:8000

API Reference

json_to_otp(json: string): OtpData

Generates OTP data from a JSON whitelabel configuration.

Parameters:

  • json - JSON string following the Raspberry Pi picotool whitelabel schema

Returns: OtpData object containing:

  • usb_boot_flags: number - USB boot flags value (u32)
  • ecc_rows: Uint16Array - ECC-encoded whitelabel rows
  • ecc_bytes: Uint8Array - Same data as little-endian bytes
  • row_count: number - Number of OTP rows required

Throws: Error with errorType property:

  • "Json" - Invalid JSON format
  • "StringTooLong" - String field exceeds maximum (includes maxLength property)
  • "InvalidWhiteLabelData" - Invalid configuration

Example:

const json = JSON.stringify({
    device: {
        vid: "0x1234",
        pid: "0xabcd",
        manufacturer: "ACME Corp 😀",
        product: "Widget Pro 号",
        serial_number: "SN12345 🚀"
    }
});

try {
    const otp = json_to_otp(json);
    
    // Write to device:
    // 1. Write otp.usb_boot_flags to rows 0x059, 0x05a, 0x05b (non-ECC)
    // 2. Write 0x100 to row 0x05c (USB_WHITE_LABEL_ADDR, non-ECC)  
    // 3. Write otp.ecc_rows starting at row 0x100 (with ECC)
    
    console.log(`Generated ${otp.row_count} rows`);
} catch (e) {
    if (e.errorType === "StringTooLong") {
        console.error(`String too long (max: ${e.maxLength})`);
    }
}

full_otp_to_json(non_ecc: Uint32Array, ecc: Uint16Array, strict: boolean): string

Parses a complete OTP dump (4096 rows) and extracts whitelabel configuration as JSON.

Parameters:

  • non_ecc - Uint32Array[4096] containing non-ECC OTP data
  • ecc - Uint16Array[4096] containing ECC OTP data
  • strict - Enable strict validation (recommended: true)

Returns: JSON string containing the whitelabel configuration

Throws: Error with errorType property:

  • "TooFewRows" / "TooManyRows" - Array must be exactly 4096 elements
  • "InvalidWhiteLabelAddress" - WHITE_LABEL_ADDR_VALID bit not set
  • "NonMatchingUsbBootFlags" - USB_BOOT_FLAGS copies don't match (strict mode)
  • "OtpDataError" - Inconsistency in OTP data (includes details property)

Example:

// Read from device using picoflash or similar
const nonEccData = new Uint32Array(4096);
const eccData = new Uint16Array(4096);
// ... populate from device ...

try {
    const json = full_otp_to_json(nonEccData, eccData, true);
    const config = JSON.parse(json);
    console.log('VID:', config.device.vid);
    console.log('PID:', config.device.pid);
} catch (e) {
    console.error(`Parse failed: ${e.message} (${e.errorType})`);
}

whitelabel_otp_to_json(boot_flags: number, rows: Uint16Array, strict: boolean): string

Parses targeted whitelabel OTP data without requiring a full dump.

Parameters:

  • boot_flags - USB boot flags value (from rows 0x059-0x05b)
  • rows - Uint16Array containing whitelabel ECC rows
  • strict - Enable strict validation

Returns: JSON string containing the whitelabel configuration

Throws: Error with errorType property:

  • "TooFewRows" - Insufficient rows (includes requiredRows property)
  • "OtpDataError" - Data inconsistency (includes details property)
  • "InvalidWhiteLabelData" - Invalid structure

Example:

const bootFlags = 0x00000001;
const whitelabelRows = new Uint16Array(256);
// ... populate from device rows 0x100+ ...

try {
    const json = whitelabel_otp_to_json(bootFlags, whitelabelRows, true);
    const config = JSON.parse(json);
    console.log('Config:', config);
} catch (e) {
    if (e.errorType === "TooFewRows") {
        console.error(`Need ${e.requiredRows} rows, got ${whitelabelRows.length}`);
    }
}

Error Handling

All functions throw JavaScript Error objects with an additional errorType property for structured error handling:

try {
    const otp = json_to_otp(invalidJson);
} catch (e) {
    console.error('Message:', e.message);
    console.error('Type:', e.errorType);
    
    // Handle specific error types
    switch (e.errorType) {
        case 'StringTooLong':
            console.error('Max length:', e.maxLength);
            break;
        case 'TooFewRows':
            console.error('Required rows:', e.requiredRows);
            break;
        case 'InvalidWhiteLabelData':
        case 'OtpDataError':
            console.error('Details:', e.details);
            break;
    }
}

Error Types

| errorType | Description | Additional Properties | |-----------|-------------|----------------------| | Json | Invalid JSON format | - | | StringTooLong | String exceeds maximum length | maxLength: number | | TooFewRows | Insufficient OTP rows | requiredRows: number | | TooManyRows | Too many rows provided | providedRows: number | | InvalidWhiteLabelAddress | WHITE_LABEL_ADDR invalid | - | | InvalidWhiteLabelAddressValue | Address points to reserved row | address: number | | NonMatchingUsbBootFlags | Boot flags copies don't match | - | | OtpDataError | Inconsistency in OTP data | details: string | | InvalidWhiteLabelData | Invalid whitelabel structure | details: string | | InternalInconsistency | Library bug detected | details: string |

Integration with pico⚡flash

This WASM module is designed to integrate with pico⚡flash for direct device interaction:

// Read OTP from device
const nonEccData = await picoflash.readOtpNonEcc();
const eccData = await picoflash.readOtpEcc();

// Parse with pico-otp-wasm
const json = full_otp_to_json(nonEccData, eccData, true);
const config = JSON.parse(json);

// Display to user...

// Generate new configuration
const newJson = JSON.stringify(modifiedConfig);
const newOtp = json_to_otp(newJson);

// Write back to device
await picoflash.writeOtpNonEcc(0x059, [newOtp.usb_boot_flags]);
await picoflash.writeOtpNonEcc(0x05a, [newOtp.usb_boot_flags]);
await picoflash.writeOtpNonEcc(0x05b, [newOtp.usb_boot_flags]);
await picoflash.writeOtpNonEcc(0x05c, [0x100]);
await picoflash.writeOtpEcc(0x100, newOtp.ecc_rows);

JSON Schema

The JSON format follows the Raspberry Pi picotool whitelabel schema. See the pico-otp documentation for the complete schema.

Example:

{
  "device": {
    "vid": "0x1234",
    "pid": "0xabcd",
    "manufacturer": "Company Name",
    "product": "Product Name",
    "serial_number": "SN123456",
    "bcd_device": "0x0200"
  },
  "attributes": {
    "power": "0xfa"
  },
  "scsi": {
    "vendor": "VENDOR",
    "product": "PRODUCT",
    "version": "1.00"
  },
  "storage": {
    "volume_label": "VOLUME"
  },
  "uf2": {
    "model": "Model Name",
    "board_id": "Board ID"
  },
  "redirect": {
    "url": "https://example.com",
    "name": "NAME"
  }
}

Development

Prerequisites

  • Rust (latest stable)
  • wasm-pack: cargo install wasm-pack
  • Node.js (for typedoc)

Building

./build.sh

Project Structure

pico-otp-wasm/
├── src/
│   └── lib.rs          # Main WASM bindings
├── pkg/                # Generated WASM output (after build)
├── docs/               # Generated TypeScript docs (after build)
├── deploy/             # Deployment-ready files (after build)
├── Cargo.toml          # Rust dependencies
├── build.sh            # Build script
├── index.html          # Test interface
└── README.md           # This file

License

Same as pico-otp (MIT OR Apache-2.0)

Author

Piers Finlayson (@piers_rocks)

Links