102 lines
3.0 KiB
TypeScript
102 lines
3.0 KiB
TypeScript
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)
|
|
})
|
|
}
|