-------------------------------------------------------------------------------
-- |
-- Module      :  System.Hardware.Haskino.SamplePrograms.Deep.semExample
-- Copyright   :  (c) University of Kansas
-- License     :  BSD3
-- Stability   :  experimental
--
-- This is an example of using semaphores to communicate between two tasks.
-- One task gives a semaphore then delays for 2 seconds.  The other task
-- waits for the semaphore then blinks the led rapidly 3 times.
-------------------------------------------------------------------------------

module System.Hardware.Haskino.SamplePrograms.Deep.SemExample where

import Prelude hiding ((<*))
import Control.Concurrent   (threadDelay)
import Control.Monad.Trans (liftIO)
import Data.Boolean
import Data.Boolean.Numbers
import Data.Word

import System.Hardware.Haskino

blinkDelay :: Expr Word32
blinkDelay = 125

taskDelay :: Expr Word32
taskDelay = 2000

semId :: Expr Word8
semId = 0

myTask1 :: Expr Word8 -> Arduino ()
myTask1 led = do
    setPinModeE led OUTPUT
    loopE $ do
        takeSemE semId
        let count = lit (3::Word32)
        whileE 0 (\x -> x <* count) (\x -> do 
            digitalWriteE led true
            delayMillisE blinkDelay
            digitalWriteE led false
            delayMillisE blinkDelay
            return $ x + 1)
    return ()

myTask2 :: Arduino ()
myTask2 = do
    loopCount <- newRemoteRef $ lit (0 :: Word8)
    loopE $ do
        giveSemE semId
        t <- readRemoteRef loopCount
        writeRemoteRef loopCount $ t+1
        debugE $ showE t
        delayMillisE taskDelay
    return ()

initExample :: Arduino ()
initExample = do
    let led = 13
    -- Create the tasks
    createTaskE 1 $ myTask1 led
    createTaskE 2 myTask2
    -- Schedule the tasks to start in 1 second, the second starting after the first
    scheduleTaskE 1 1000
    scheduleTaskE 2 1050

semExample :: IO ()
semExample = withArduino True "/dev/cu.usbmodem1421" $ do
    initExample
    -- Query to confirm task creation
    tasks <- queryAllTasksE
    liftIO $ print tasks
    task1 <- queryTaskE 1
    liftIO $ print task1
    task2 <- queryTaskE 2
    liftIO $ print task2
    -- Wait for any debug messgaes from Arduino
    debugListen

semExampleProg :: IO ()
semExampleProg = withArduino True "/dev/cu.usbmodem1421" $ do
    initExample
    -- Program the boot tasks
    bootTaskE (lit [1,2])
    return ()

