mirror of
https://github.com/chirimen-oh/node-web-i2c.git
synced 2025-01-18 08:05:10 +00:00
6d341aaaf7
Ref. #45 Co-authored-by: akihiko kigure <akihiko.kigure@lifewood-m1.local>
307 lines
7.8 KiB
TypeScript
307 lines
7.8 KiB
TypeScript
import { openPromisified } from 'i2c-bus';
|
|
|
|
/**
|
|
* I2C Port Map Max サイズ
|
|
*/
|
|
const I2CPortMapSizeMax = 32;
|
|
|
|
/**
|
|
* Uint16 Max サイズ
|
|
*/
|
|
const Uint16Max = 65535;
|
|
|
|
/**
|
|
*
|
|
* Uint16型変換処理
|
|
* @param parseString 変換文字列
|
|
* @return Uint16型変換値
|
|
*/
|
|
function parseUint16(parseString: string) {
|
|
const n = Number.parseInt(parseString, 10);
|
|
if (0 <= n && n <= Uint16Max) return n;
|
|
else throw new RangeError(`Must be between 0 and ${Uint16Max}.`);
|
|
}
|
|
|
|
/** ポート番号 */
|
|
type PortNumber = number;
|
|
/** ポート名 */
|
|
type PortName = string;
|
|
|
|
/** I2C Slave アドレス */
|
|
type I2CSlaveAddress = number;
|
|
|
|
/**
|
|
* I2CAccess クラス
|
|
*/
|
|
export class I2CAccess {
|
|
private readonly _ports: I2CPortMap;
|
|
|
|
/**
|
|
* Creates an instance of GPIOAccess.
|
|
* @param ports ポート番号
|
|
*/
|
|
constructor(ports?: I2CPortMap) {
|
|
this._ports = ports == null ? new I2CPortMap() : ports;
|
|
}
|
|
|
|
/**
|
|
* ポート情報取得処理
|
|
* @return 現在のポート情報
|
|
*/
|
|
get ports(): I2CPortMap {
|
|
return this._ports;
|
|
}
|
|
}
|
|
|
|
/** Different from Web I2C API specification. */
|
|
export class I2CPortMap extends Map<PortNumber, I2CPort> {
|
|
getByName(portName: PortName): I2CPort | undefined {
|
|
const matches = /^i2c-(\d+)$/.exec(portName);
|
|
return matches == null ? undefined : this.get(parseUint16(matches[1]));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* I2CPort クラス
|
|
*/
|
|
export class I2CPort {
|
|
private readonly _portNumber: PortNumber;
|
|
|
|
/**
|
|
* Creates an instance of GPIOPort.
|
|
* @param portNumber ポート番号
|
|
*/
|
|
constructor(portNumber: PortNumber) {
|
|
this._portNumber = parseUint16(portNumber.toString());
|
|
}
|
|
|
|
/**
|
|
* ポート番号取得処理
|
|
* @return 現在のポート番号
|
|
*/
|
|
get portNumber(): PortNumber {
|
|
return this._portNumber;
|
|
}
|
|
|
|
/**
|
|
* ポート名取得処理
|
|
* @return 現在のポート名
|
|
*/
|
|
get portName(): string {
|
|
return `i2c-${this.portNumber}`;
|
|
}
|
|
|
|
/**
|
|
* I2CSlave 接続デバイスオープン処理
|
|
* @param slaveAddress 接続デバイス情報のアドレス
|
|
* @return I2CSlaveDevice インスタンスの生成の完了
|
|
*/
|
|
async open(slaveAddress: I2CSlaveAddress): Promise<I2CSlaveDevice> {
|
|
const bus = await openPromisified(this.portNumber).catch((error) => {
|
|
throw new OperationError(error);
|
|
});
|
|
|
|
return {
|
|
slaveAddress,
|
|
/**
|
|
* @function
|
|
* I2C 読み取り処理
|
|
* @param registerNumber 読み取りアドレス
|
|
*/
|
|
read8: (registerNumber) =>
|
|
bus.readByte(slaveAddress, registerNumber).catch((error) => {
|
|
throw new OperationError(error);
|
|
}),
|
|
/**
|
|
* @function
|
|
* I2C 読み取り処理
|
|
* @param registerNumber 読み取りアドレス
|
|
*/
|
|
read16: (registerNumber) =>
|
|
bus.readWord(slaveAddress, registerNumber).catch((error) => {
|
|
throw new OperationError(error);
|
|
}),
|
|
/**
|
|
* @function
|
|
* I2c s/I2c/I2C 書き込み処理
|
|
* @param registerNumber 書き込みアドレス
|
|
* @param byte 書き込みの値(バイト)
|
|
*/
|
|
write8: async (registerNumber, byte) => {
|
|
try {
|
|
await bus.writeByte(slaveAddress, registerNumber, byte);
|
|
return byte;
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込み処理
|
|
* @param registerNumber 書き込みアドレス
|
|
* @param word 書き込みの値(ワード)
|
|
*/
|
|
write16: async (registerNumber, word) => {
|
|
try {
|
|
await bus.writeWord(slaveAddress, registerNumber, word);
|
|
return word;
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
/**
|
|
* @function
|
|
* I2c bytes 読み取りバイト処理
|
|
* Different from Web I2C API specification.
|
|
*/
|
|
readByte: async () => {
|
|
try {
|
|
const byte = await bus.receiveByte(slaveAddress);
|
|
return byte;
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
/**
|
|
* @function
|
|
* I2c bytes 読み取りバイト処理
|
|
* Different from Web I2C API specification.
|
|
* @param length 読み取る配列の長さ
|
|
*/
|
|
readBytes: async (length) => {
|
|
try {
|
|
const { bytesRead, buffer } = await bus.i2cRead(
|
|
slaveAddress,
|
|
length,
|
|
Buffer.allocUnsafe(length)
|
|
);
|
|
return new Uint8Array(buffer.slice(0, bytesRead));
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込みバイト処理
|
|
* Different from Web I2C API specification.
|
|
* @param byte 書き込みの値
|
|
*/
|
|
writeByte: async (byte) => {
|
|
try {
|
|
await bus.sendByte(slaveAddress, byte);
|
|
return byte;
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込み処理
|
|
* Different from Web I2C API specification.
|
|
* @param bytes 書き込みの値の配列
|
|
*/
|
|
writeBytes: async (bytes) => {
|
|
try {
|
|
const { bytesWritten, buffer } = await bus.i2cWrite(
|
|
slaveAddress,
|
|
bytes.length,
|
|
Buffer.from(bytes)
|
|
);
|
|
return new Uint8Array(buffer.slice(0, bytesWritten));
|
|
} catch (error: any) {
|
|
throw new OperationError(error);
|
|
}
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* I2CSlaveDevice クラス
|
|
*/
|
|
export interface I2CSlaveDevice {
|
|
/** I2C Slave アドレス */
|
|
readonly slaveAddress: I2CSlaveAddress;
|
|
|
|
/**
|
|
* @function
|
|
* I2C 読み取り処理
|
|
* @param registerNumber 読み取りアドレス
|
|
*/
|
|
read8(registerNumber: number): Promise<number>;
|
|
/**
|
|
* @function
|
|
* I2C 読み取り処理
|
|
* @param registerNumber 読み取りアドレス
|
|
*/
|
|
read16(registerNumber: number): Promise<number>;
|
|
/**
|
|
* @function
|
|
* I2c s/I2c/I2C 書き込み処理
|
|
* @param registerNumber 書き込みアドレス
|
|
* @param value 書き込みの値(バイト)
|
|
*/
|
|
write8(registerNumber: number, value: number): Promise<number>;
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込み処理
|
|
* @param registerNumber 書き込みアドレス
|
|
* @param value 書き込みの値(ワード)
|
|
*/
|
|
write16(registerNumber: number, value: number): Promise<number>;
|
|
|
|
/**
|
|
* @function
|
|
* I2c bytes 読み取りバイト処理
|
|
* Different from Web I2C API specification.
|
|
*/
|
|
readByte(): Promise<number>;
|
|
/**
|
|
* @function
|
|
* I2c bytes 読み取りバイト処理
|
|
* Different from Web I2C API specification.
|
|
* @param length 読み取る配列の長さ
|
|
*/
|
|
readBytes(length: number): Promise<Uint8Array>;
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込みバイト処理
|
|
* Different from Web I2C API specification.
|
|
* @param byte 書き込みの値
|
|
*/
|
|
writeByte(byte: number): Promise<number>;
|
|
/**
|
|
* @function
|
|
* I2c bytes 書き込みバイト配列処理
|
|
* Different from Web I2C API specification.
|
|
* @param bytes 書き込みの値の配列
|
|
*/
|
|
writeBytes(bytes: Array<number>): Promise<Uint8Array>;
|
|
}
|
|
|
|
/**
|
|
* 操作エラー
|
|
*/
|
|
export class OperationError extends Error {
|
|
/**
|
|
* Creates an instance of OperationError.
|
|
* @param message エラーメッセージ
|
|
*/
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = this.constructor.name;
|
|
}
|
|
}
|
|
|
|
// Web I2Cの仕様に基づく意図的なasync関数の使用なので、ルールを無効化
|
|
// eslint-disable-next-line
|
|
export async function requestI2CAccess(): Promise<I2CAccess> {
|
|
const ports = new I2CPortMap(
|
|
[...Array(I2CPortMapSizeMax).keys()].map((portNumber) => [
|
|
portNumber,
|
|
new I2CPort(portNumber),
|
|
])
|
|
);
|
|
|
|
return new I2CAccess(ports);
|
|
}
|