UNPKG

@okee-tech/rppal

Version:

Raspberry Pi peripheral access library for Node.js using `napi-rs` bindings from Rust's `rppal` crate

168 lines (138 loc) 4.39 kB
// mock/i2c.js const DEBUG = process.env.RPPAL_MOCK_DEBUG === "1"; const log = (msg) => { if (DEBUG) console.debug(`[RPPAL Mock] ${msg}`); }; class Capabilities { constructor() { this.addr10Bit = true; this.i2CBlockRead = true; this.i2CBlockWrite = true; this.smbusQuickCommand = true; this.smbusReceiveByte = true; this.smbusSendByte = true; this.smbusReadByte = true; this.smbusWriteByte = true; this.smbusReadWord = true; this.smbusWriteWord = true; this.smbusProcessCall = true; this.smbusBlockRead = true; this.smbusBlockWrite = true; this.smbusBlockProcessCall = true; this.smbusPec = true; this.smbusHostNotify = true; } } class I2C { constructor(bus = 1) { this.bus = bus; this.clockSpeed = 100000; // Default to 100kHz this.addr10Bit = false; this.timeoutMillis = null; this.capabilities = new Capabilities(); this.deviceStorage = new Map(); } async getCapabilities() { return this.capabilities; } async getBus() { return this.bus; } async getClockSpeed() { return this.clockSpeed; } async getAddr10Bit() { return this.addr10Bit; } async setAddr10Bit(newValue) { this.addr10Bit = newValue; } async getTimeoutMillis() { return this.timeoutMillis; } async setTimeoutMillis(newValue) { if (newValue < 0) throw new Error("Timeout value cannot be negative"); this.timeoutMillis = newValue; } async read(address, bufferSize = 1) { this.validateAddress(address); // Return mock data from device storage or generate mock data const deviceData = this.deviceStorage.get(address) || []; return deviceData .slice(0, bufferSize) .concat(Array(Math.max(0, bufferSize - deviceData.length)).fill(0)); } async write(address, data) { this.validateAddress(address); this.validateData(data); // Store the written data for later reading this.deviceStorage.set(address, [...data]); } async writeRead(address, writeData, readBufferSize = 1) { await this.write(address, writeData); return this.read(address, readBufferSize); } async blockRead(address, command, bufferSize = 1) { this.validateAddress(address); this.validateCommand(command); // Generate mock data based on command and address const mockData = Array(bufferSize) .fill(0) .map((_, i) => (command + i) % 256); return mockData; } async blockWrite(address, command, data) { this.validateAddress(address); this.validateCommand(command); this.validateData(data); // Store the command and data for potential later reading const combinedData = [command, ...data]; this.deviceStorage.set(address, combinedData); } validateAddress(address) { if (!Number.isInteger(address)) { throw new Error("Address must be an integer"); } const maxAddr = this.addr10Bit ? 1023 : 127; if (address < 0 || address > maxAddr) { throw new Error( `Address must be between 0 and ${maxAddr} for ${ this.addr10Bit ? "10-bit" : "7-bit" } addressing` ); } } validateCommand(command) { if (!Number.isInteger(command) || command < 0 || command > 255) { throw new Error("Command must be an integer between 0 and 255"); } } validateData(data) { if (!Array.isArray(data) || data.length === 0) { throw new Error("Data must be a non-empty array of numbers"); } if ( !data.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255) ) { throw new Error("All data bytes must be integers between 0 and 255"); } } // Method to simulate I2C errors or specific device behaviors simulateError(errorType) { switch (errorType) { case "timeout": throw new Error("I2C operation timed out"); case "nack": throw new Error("Device did not acknowledge"); case "bus_error": throw new Error("Bus error occurred"); default: throw new Error("Unknown error type"); } } // Method to reset the mock device storage resetDevices() { this.deviceStorage.clear(); } } module.exports = { I2C, Capabilities };