import type { Pointer } from "bun:ffi" import { gpiod, GPIOD_LINE_DIRECTION_INPUT, GPIOD_LINE_DIRECTION_OUTPUT } from "./ffi" import { cstr, mapPullToLibgpiod, mapEdgeToLibgpiod } from "./utils" import type { PullMode, EdgeMode } from "./types" type LineRequestResult = { chip: Pointer request: Pointer } export type InputLineConfig = { chipPath: string offset: number pull: PullMode debounce: number edge: EdgeMode } export type OutputLineConfig = { chipPath: string offset: number initialValue: 0 | 1 } const cleanup = (message: string): never => { throw new Error(message) } const requestLine = ( chipPath: string, offset: number, consumer: string, configureSettings: (settings: Pointer) => void ): LineRequestResult => { const chip = gpiod.gpiod_chip_open(cstr(chipPath)) if (!chip) cleanup("Failed to open GPIO chip") const settings = gpiod.gpiod_line_settings_new() if (!settings) { gpiod.gpiod_chip_close(chip) cleanup("Failed to create line settings") } configureSettings(settings!) const lineConfig = gpiod.gpiod_line_config_new() if (!lineConfig) { gpiod.gpiod_line_settings_free(settings) gpiod.gpiod_chip_close(chip) cleanup("Failed to create line config") } const offsets = new Uint32Array([offset]) const ret = gpiod.gpiod_line_config_add_line_settings(lineConfig, offsets, 1, settings) gpiod.gpiod_line_settings_free(settings) if (ret !== 0) { gpiod.gpiod_line_config_free(lineConfig) gpiod.gpiod_chip_close(chip) cleanup("Failed to add line settings") } const requestConfig = gpiod.gpiod_request_config_new() if (!requestConfig) { gpiod.gpiod_line_config_free(lineConfig) gpiod.gpiod_chip_close(chip) cleanup("Failed to create request config") } gpiod.gpiod_request_config_set_consumer(requestConfig, cstr(consumer)) const request = gpiod.gpiod_chip_request_lines(chip, requestConfig, lineConfig) gpiod.gpiod_request_config_free(requestConfig) gpiod.gpiod_line_config_free(lineConfig) if (!request) { gpiod.gpiod_chip_close(chip) cleanup("Failed to request GPIO line") } return { chip: chip!, request: request! } } export const requestInputLine = (config: InputLineConfig): LineRequestResult => { return requestLine(config.chipPath, config.offset, "bun-gpio-input", (settings) => { gpiod.gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_INPUT) gpiod.gpiod_line_settings_set_bias(settings, mapPullToLibgpiod(config.pull)) gpiod.gpiod_line_settings_set_edge_detection(settings, mapEdgeToLibgpiod(config.edge)) if (config.debounce > 0) { gpiod.gpiod_line_settings_set_debounce_period_us(settings, config.debounce * 1000) } }) } export const requestOutputLine = (config: OutputLineConfig): LineRequestResult => { return requestLine(config.chipPath, config.offset, "bun-gpio", (settings) => { gpiod.gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT) gpiod.gpiod_line_settings_set_output_value(settings, config.initialValue) }) }