packages feed

fuyu-gpio-0.1.0.0: examples/03-monitor.hs

-- In this example we will learn how to monitor GPIO line status changes across processes using chip watching.
-- This example structures the application into modular helper blocks ('runApp', 'monitorApp', 'lineApp'),
-- serving as an intermediate modular phase before introducing resource management with 'Control.Monad.Managed'
-- in the next example (04-led-and-button.hs) to eliminate deeply nested brackets.
module Main where

-- High-level resource brackets & exception handling.
import Fuyu.GPIO

-- Qualified Domain Modules.
-- Same as Fuyu.GPIO.EdgeEvent I sugest an qualified import. 
import qualified Fuyu.GPIO.Monitor as Monitor  

-- Base & third-party libraries.
import Control.Concurrent (forkIO, threadDelay)

myChipPath :: FilePath
myChipPath = "/dev/gpiochip0"

targetOffset :: Offset
targetOffset = Offset 257

waitTimeoutNs :: Monitor.Timeout
waitTimeoutNs = Monitor.Nanoseconds 5000000000 -- 5 seconds

main :: IO ()
main = do
  putStrLn "Starting line status event monitor..."
  runApp 
  putStrLn "Line status event monitor completed successfully."

-- We could use some modular application blocks as the next ones to avoid
-- "super nested" functions. Personally I sugest to use this kind of organization
-- or use managed package (next example) for medium size programs.

-- 'runApp' centralizes worker threads and watchers organized in structured blocks.
runApp :: IO ()
runApp = do
  putStrLn "Opening GPIO chip and starting line status watching..."
  withChip myChipPath $ \chip -> do
    -- Register the line watch in the kernel before any interaction
    -- (required so the kernel starts queueing status events for targetOffset)
    Monitor.withWatchLine chip targetOffset $ \_lineInfo -> do
      _ <- forkIO $ lineApp chip
      monitorApp chip 

-- 'monitorApp' waits for status change events using 'waitEvent' and security token 'ReadyChip'
monitorApp :: Chip -> IO ()
monitorApp chip = do     
  putStrLn "Waiting for line status change event (timeout: 5s)..."
  res <- Monitor.waitEvent chip waitTimeoutNs
  case res of
    -- Same pattern as 'Fuyu.GPIO.EdgeEvent.waitEvents'
    Monitor.EventReady readyChip -> do
      Monitor.withEvent readyChip $ \infoEvent -> do
        -- In this case, we expect a 'Requested' info event type
        eventType <- Monitor.eventType infoEvent      
        putStrLn ("Event received! " ++ show eventType)
    Monitor.TimeoutResult -> putStrLn "Wait timed out (timeout)."

-- 'lineApp' simulates line interactions (requesting access to targetOffset) in a concurrent thread
lineApp :: Chip -> IO () 
lineApp chip = do   
  withSettings $ \settings -> do
    setDirection settings DirAsIs  
    withConfig $ \config -> do
      addSettings config [targetOffset] settings 
      withRequest chip Nothing config $ \request -> do
        name <- chipName request
        putStrLn ("Line request created successfully on chip: " ++ show name)
        threadDelay 500000 -- Hold requested line briefly