packages feed

fuyu-gpio-0.0.9.0: examples/04-line-watch.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 functions ('runApp', 'monitorApp', 'lineApp'),
-- serving as an intermediate modular phase before refactoring nested brackets with monadic continuation ('ContT').
module Main where

-- High-level resource brackets & exception handling
import Fuyu.GPIO.Chip (Chip, withChip)
import Fuyu.GPIO.Line (withRequest, withConfig, withSettings)
import Fuyu.GPIO.Exception (withGpioApp)

-- Qualified Domain Modules
import qualified Fuyu.GPIO.Chip.Watch as Watch
import qualified Fuyu.GPIO.Line as Line

-- Base & third-party libraries
import Control.Concurrent (forkIO, threadDelay)
import Data.Vector.Storable (singleton)

chipPath :: FilePath
chipPath = "/dev/gpiochip0"

targetOffset :: Line.Offset
targetOffset = Line.Offset 257

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

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

-- 'runApp' centralizes worker threads and watchers to avoid pyramid of doom
runApp :: IO ()
runApp = do
  putStrLn "Opening GPIO chip and starting line status watching..."
  withChip chipPath $ \chip -> do
    -- Register the line watch in the kernel before any interaction
    -- (required so the kernel starts queueing status events for targetOffset)
    Watch.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 <- Watch.waitEvent chip waitTimeoutNs
  case res of
    -- Same pattern as 'Fuyu.GPIO.EdgeEvent.waitEvents'
    Watch.EventReady readyChip -> do
      Watch.withEvent readyChip $ \infoEvent -> do
        -- In this case, we expect a 'Requested' info event type
        eventType <- Watch.eventType infoEvent      
        putStrLn ("Event received! " ++ show eventType)
    Watch.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
    Line.setDirection settings Line.DirAsIs  
    withConfig $ \config -> do
      Line.addSettings config (singleton targetOffset) settings 
      withRequest chip Nothing config $ \request -> do
        name <- Line.chipName request
        putStrLn ("Line request created successfully on chip: " ++ show name)
        threadDelay 500000 -- Hold requested line briefly