phone/src/pins/index.ts
2025-11-19 13:19:18 -08:00

88 lines
2.2 KiB
TypeScript

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<Type.ChipInfo[]> {
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