-- Module to make GPIO via the sysfs gpio class interface easy -- for simple Lua applications. -- simplest minimal module framework, just return M local M = { _NAME=(...), _VERSION="v0.001", } -- Utility functions private to the module local P = require "posix" -- write str to the named file function putfile(name,str) local f = assert(io.open(name,"w")) f:write(str) f:close() end -- read the named file and return its content function getfile(name) local f = assert(io.open(name,"r")) local str f:read"*a" f:close() return str end -- transform a list into a set for quick lookup function SET(t) local s = {} for _,v in ipairs(t) do s[v] = true end return s end -- container for GPIO functions, alias to M local gpio=M gpio.pins1_1 = SET{ -- Original RPi A, B 0, 1, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, 24, 25, } gpio.pins1_2 = SET{ -- Rev 2 A, B 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 22, 23, 24, 25, 27} gpio.pins2_0 = SET{ -- A+, B+, 2A, 2B 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27} -- default to RPi B+ board -- TODO: Read /proc/cpuinfo and get this right based on the -- Hardware and Revision fields. For now, just assume -- what I have will work. gpio.pins = gpio.pins2_0 -- export a sysfs pin to userland function gpio.export(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/export",tostring(pin)) end -- return a sysfs pin to the kernel function gpio.unexport(pin) assert(gpio.pins[pin], "Can't use pin") putfile("/sys/class/gpio/unexport",tostring(pin)) end -- userland path to a specific pin's atribute file function gpio.pinpath(pin,attr) return ("/sys/class/gpio/gpio%d/%s"):format(pin,attr) end -- set pin direction function gpio.direction(pin,dir) local path = gpio.pinpath(pin, "direction") --print("Setting "..path.." to "..dir) putfile(path, dir) end -- set pin edge detector function gpio.edge(pin,edge) local path = gpio.pinpath(pin, "edge") --print("Setting "..path.." to "..edge) putfile(path, edge) end -- blocking wait with timeout for an edge on a pin function gpio.wait(pin) assert(gpio.pins[pin], "Can't use pin") local path = gpio.pinpath(pin, "value") if not gpio.pinfd then gpio.pinfd = P.open(path, P.O_RDONLY) end local p = gpio.pinfd if not gpio.fds then gpio.fds = {} end if not gpio.fds[p] then gpio.fds[p] = {events={}, revents={}} end gpio.fds[p].events.PRI=true local ret = P.poll(gpio.fds, 10000) if ret == 0 then return 0 end P.lseek(p,0,P.SEEK_SET) ret = tonumber(P.read(p,8)) --P.close(p) --gpio.pinfd = nil return ret end --Example --[===[ -- Use pin P1-28 aka GPIO7 for SPLear alerts -- local gpio = require "sysfsgpio" gpio.export(7) gpio.direction(7,"in") gpio.edge(7,"rising") while(true) do local r = gpio.wait(7) if r == 0 then --print"timeout" elseif r==1 then local tim = P.gettimeofday() print("eek "..tim.sec..'.'..tim.usec) else print("???", r) end end if gpio.pinfd then P.close(gpio.pinfd) end --]===] -- TODO: Do some minimal validation that there actually is -- a sysfs and error out if not. return M