import { readdir } from "node:fs/promises" import { gpiod, cstr } from "./ffi" import { Output } from "./output" import { Input } from "./input" import type * as Type from "./types" import { GPIOError, PermissionError, PinInUseError, ChipNotFoundError, InvalidConfigError, } from "./errors" class GPIO { #chipPath: string constructor(options?: { chip?: string }) { this.#chipPath = options?.chip ?? "/dev/gpiochip0" } output(pin: number, options?: Type.OutputOptions): Output { return new Output(this.#chipPath, pin, options) } input(pin: number, options?: Type.InputOptions): Input { return new Input(this.#chipPath, pin, options) } async listChips(): Promise { const chips: Type.ChipInfo[] = [] try { const files = await readdir("/dev") const chipFiles = files.filter((f) => f.startsWith("gpiochip")) for (const file of chipFiles) { const path = `/dev/${file}` try { const chip = gpiod.gpiod_chip_open(cstr(path)) if (!chip) continue const info = gpiod.gpiod_chip_get_info(chip) if (!info) { gpiod.gpiod_chip_close(chip) continue } const name = gpiod.gpiod_chip_info_get_name(info) const label = gpiod.gpiod_chip_info_get_label(info) const numLines = gpiod.gpiod_chip_info_get_num_lines(info) chips.push({ path, name: String(name || ""), label: String(label || ""), numLines: Number(numLines), }) gpiod.gpiod_chip_close(chip) } catch { continue } } } catch { // /dev might not be accessible, return empty array } return chips } static Error = GPIOError static PermissionError = PermissionError static PinInUseError = PinInUseError static ChipNotFoundError = ChipNotFoundError static InvalidConfigError = InvalidConfigError } namespace GPIO { export type PullMode = Type.PullMode export type EdgeMode = Type.EdgeMode export type InputOptions = Type.InputOptions export type OutputOptions = Type.OutputOptions export type InputEvent = Type.InputEvent } export default GPIO