// Package pld reads the X1208 power-loss-detect line. // // The HAT drives GPIO 6 high while mains power is present and low while the // Pi runs on cells. package pld import ( "fmt" "github.com/warthog618/go-gpiocdev" ) const ( // DefaultChip is addressed by name, not by /dev path, so this does not // depend on any distribution-specific symlink. DefaultChip = "gpiochip0" // DefaultLine is the power-loss-detect line on the X1208. DefaultLine = 6 consumer = "x1208-exporter" ) // Line holds the GPIO request open across reads. The kernel grants the request // exclusively, so reacquiring it per read risks EBUSY against our own // not-yet-released handle. type Line struct { chip string offset int line *gpiocdev.Line } // New returns a Line that has not yet been requested. The first Read requests it. func New(chip string, offset int) *Line { if chip == "" { chip = DefaultChip } return &Line{chip: chip, offset: offset} } func (l *Line) ensureOpen() error { if l.line != nil { return nil } line, err := gpiocdev.RequestLine(l.chip, l.offset, gpiocdev.AsInput, gpiocdev.WithConsumer(consumer)) if err != nil { return fmt.Errorf("request %s line %d: %w", l.chip, l.offset, err) } l.line = line return nil } // Close releases the line. It is safe to call more than once. func (l *Line) Close() error { if l.line == nil { return nil } line := l.line l.line = nil return line.Close() } // Read reports whether mains power is present. // // On error the line is released so the next Read requests a fresh one. // // A read that succeeds is not proof that the value is meaningful: a floating // or misconfigured line returns 0 with no error. Callers that act on "no AC" // must corroborate it, not trust this alone. func (l *Line) Read() (acPresent bool, err error) { if err := l.ensureOpen(); err != nil { return false, err } defer func() { if err != nil { _ = l.Close() } }() v, err := l.line.Value() if err != nil { return false, fmt.Errorf("read %s line %d: %w", l.chip, l.offset, err) } return v != 0, nil }