{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
module System.Hardware.Arduino.Firmata where
import Control.Concurrent (newEmptyMVar, readMVar, withMVar, modifyMVar_, threadDelay)
import Control.Monad (when, unless, void)
import Control.Monad.State (StateT(..), gets)
import Control.Monad.Trans (liftIO)
import Data.Bits ((.&.), shiftR, setBit)
import Data.Maybe (fromMaybe)
import Data.Time (getCurrentTime, utctDayTime)
import System.Timeout (timeout)
import Data.Word (Word8)
import qualified Data.Map as M
import System.Hardware.Arduino.Data
import System.Hardware.Arduino.Comm
import qualified System.Hardware.Arduino.Utils as U
queryFirmware :: Arduino (Word8, Word8, String)
queryFirmware :: Arduino (Word8, Word8, String)
queryFirmware = do
Request -> Arduino ()
send Request
QueryFirmware
Response
r <- Arduino Response
recv
case Response
r of
Firmware Word8
v1 Word8
v2 String
m -> (Word8, Word8, String) -> Arduino (Word8, Word8, String)
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Word8
v1, Word8
v2, String
m)
Response
_ -> String -> [String] -> Arduino (Word8, Word8, String)
forall a. String -> [String] -> Arduino a
die String
"queryFirmware: Got unexpected response for query firmware call: " [Response -> String
forall a. Show a => a -> String
show Response
r]
delay :: Int -> Arduino ()
delay :: Int -> Arduino ()
delay = IO () -> Arduino ()
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Arduino ()) -> (Int -> IO ()) -> Int -> Arduino ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> IO ()
U.delay
time :: Arduino a -> Arduino (Int, a)
time :: forall a. Arduino a -> Arduino (Int, a)
time Arduino a
a = do Integer
start <- Arduino Integer
tick
a
r <- Arduino a
a
Integer
end <- a
r a -> Arduino Integer -> Arduino Integer
forall a b. a -> b -> b
`seq` Arduino Integer
tick
(Int, a) -> Arduino (Int, a)
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> Int
toMicroSeconds (Integer
end Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
start), a
r)
where
tick :: Arduino Integer
tick = do DiffTime
t <- IO DiffTime -> Arduino DiffTime
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO DiffTime -> Arduino DiffTime)
-> IO DiffTime -> Arduino DiffTime
forall a b. (a -> b) -> a -> b
$ UTCTime -> DiffTime
utctDayTime (UTCTime -> DiffTime) -> IO UTCTime -> IO DiffTime
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO UTCTime
getCurrentTime
let precision :: Integer
precision = Integer
1000000000000 :: Integer
Integer -> Arduino Integer
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Integer -> Arduino Integer)
-> (DiffTime -> Integer) -> DiffTime -> Arduino Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Rational -> Integer
forall b. Integral b => Rational -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Rational -> Integer)
-> (DiffTime -> Rational) -> DiffTime -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Rational
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
precision Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
*) (Rational -> Rational)
-> (DiffTime -> Rational) -> DiffTime -> Rational
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiffTime -> Rational
forall a. Real a => a -> Rational
toRational (DiffTime -> Arduino Integer) -> DiffTime -> Arduino Integer
forall a b. (a -> b) -> a -> b
$ DiffTime
t
toMicroSeconds :: Integer -> Int
toMicroSeconds :: Integer -> Int
toMicroSeconds Integer
t = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Integer
t Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
1000000
timeOut :: Int -> Arduino a -> Arduino (Maybe a)
timeOut :: forall a. Int -> Arduino a -> Arduino (Maybe a)
timeOut Int
to (Arduino (StateT ArduinoState -> IO (a, ArduinoState)
f)) = StateT ArduinoState IO (Maybe a) -> Arduino (Maybe a)
forall a. StateT ArduinoState IO a -> Arduino a
Arduino ((ArduinoState -> IO (Maybe a, ArduinoState))
-> StateT ArduinoState IO (Maybe a)
forall s (m :: * -> *) a. (s -> m (a, s)) -> StateT s m a
StateT (\ArduinoState
st -> do
Maybe (a, ArduinoState)
mbRes <- Int -> IO (a, ArduinoState) -> IO (Maybe (a, ArduinoState))
forall a. Int -> IO a -> IO (Maybe a)
timeout Int
to (ArduinoState -> IO (a, ArduinoState)
f ArduinoState
st)
case Maybe (a, ArduinoState)
mbRes of
Maybe (a, ArduinoState)
Nothing -> (Maybe a, ArduinoState) -> IO (Maybe a, ArduinoState)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe a
forall a. Maybe a
Nothing, ArduinoState
st)
Just (a
a, ArduinoState
st') -> (Maybe a, ArduinoState) -> IO (Maybe a, ArduinoState)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Maybe a
forall a. a -> Maybe a
Just a
a, ArduinoState
st')))
setPinMode :: Pin -> PinMode -> Arduino ()
setPinMode :: Pin -> PinMode -> Arduino ()
setPinMode Pin
p' PinMode
m = do
IPin
p <- Pin -> Arduino IPin
getInternalPin Pin
p'
[Request]
extras <- IPin -> PinMode -> Arduino [Request]
registerPinMode IPin
p PinMode
m
Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ IPin -> PinMode -> Request
SetPinMode IPin
p PinMode
m
(Request -> Arduino ()) -> [Request] -> Arduino ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Request -> Arduino ()
send [Request]
extras
digitalWrite :: Pin -> Bool -> Arduino ()
digitalWrite :: Pin -> Bool -> Arduino ()
digitalWrite Pin
p' Bool
v = do
(IPin
p, PinData
pd) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"digitalWrite" Pin
p' PinMode
OUTPUT
case PinData -> Maybe (Either Bool Int)
pinValue PinData
pd of
Just (Left Bool
b) | Bool
b Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
v -> () -> Arduino ()
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Maybe (Either Bool Int)
_ -> do (Word8
lsb, Word8
msb) <- IPin -> Bool -> Arduino (Word8, Word8)
computePortData IPin
p Bool
v
Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Port -> Word8 -> Word8 -> Request
DigitalPortWrite (IPin -> Port
pinPort IPin
p) Word8
lsb Word8
msb
pullUpResistor :: Pin -> Bool -> Arduino ()
pullUpResistor :: Pin -> Bool -> Arduino ()
pullUpResistor Pin
p' Bool
v = do
(IPin
p, PinData
_) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"pullUpResistor" Pin
p' PinMode
INPUT
(Word8
lsb, Word8
msb) <- IPin -> Bool -> Arduino (Word8, Word8)
computePortData IPin
p Bool
v
Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Port -> Word8 -> Word8 -> Request
DigitalPortWrite (IPin -> Port
pinPort IPin
p) Word8
lsb Word8
msb
digitalRead :: Pin -> Arduino Bool
digitalRead :: Pin -> Arduino Bool
digitalRead Pin
p' = do
(IPin
_, PinData
pd) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"digitalRead" Pin
p' PinMode
INPUT
Bool -> Arduino Bool
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Arduino Bool) -> Bool -> Arduino Bool
forall a b. (a -> b) -> a -> b
$ case PinData -> Maybe (Either Bool Int)
pinValue PinData
pd of
Just (Left Bool
v) -> Bool
v
Maybe (Either Bool Int)
_ -> Bool
False
waitFor :: Pin -> Arduino Bool
waitFor :: Pin -> Arduino Bool
waitFor Pin
p = [Bool] -> Bool
forall a. HasCallStack => [a] -> a
head ([Bool] -> Bool) -> Arduino [Bool] -> Arduino Bool
forall a b. (a -> b) -> Arduino a -> Arduino b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Pin] -> Arduino [Bool]
waitAny [Pin
p]
waitAny :: [Pin] -> Arduino [Bool]
waitAny :: [Pin] -> Arduino [Bool]
waitAny [Pin]
ps = ((Bool, Bool) -> Bool) -> [(Bool, Bool)] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, Bool) -> Bool
forall a b. (a, b) -> b
snd ([(Bool, Bool)] -> [Bool])
-> Arduino [(Bool, Bool)] -> Arduino [Bool]
forall a b. (a -> b) -> Arduino a -> Arduino b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Pin] -> Arduino [(Bool, Bool)]
waitGeneric [Pin]
ps
waitAnyHigh :: [Pin] -> Arduino [Bool]
waitAnyHigh :: [Pin] -> Arduino [Bool]
waitAnyHigh [Pin]
ps = do
[Bool]
curVals <- (Pin -> Arduino Bool) -> [Pin] -> Arduino [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Pin -> Arduino Bool
digitalRead [Pin]
ps
Bool -> Arduino () -> Arduino ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and [Bool]
curVals) (Arduino () -> Arduino ()) -> Arduino () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Arduino [Bool] -> Arduino ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Arduino [Bool] -> Arduino ()) -> Arduino [Bool] -> Arduino ()
forall a b. (a -> b) -> a -> b
$ [Pin] -> Arduino [Bool]
waitAnyLow [Pin]
ps
[(Bool, Bool)]
vs <- [Pin] -> Arduino [(Bool, Bool)]
waitGeneric [Pin]
ps
if (Bool
False, Bool
True) (Bool, Bool) -> [(Bool, Bool)] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [(Bool, Bool)]
vs
then [Bool] -> Arduino [Bool]
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Bool] -> Arduino [Bool]) -> [Bool] -> Arduino [Bool]
forall a b. (a -> b) -> a -> b
$ ((Bool, Bool) -> Bool) -> [(Bool, Bool)] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, Bool) -> Bool
forall a b. (a, b) -> b
snd [(Bool, Bool)]
vs
else [Pin] -> Arduino [Bool]
waitAnyHigh [Pin]
ps
waitAnyLow :: [Pin] -> Arduino [Bool]
waitAnyLow :: [Pin] -> Arduino [Bool]
waitAnyLow [Pin]
ps = do
[Bool]
curVals <- (Pin -> Arduino Bool) -> [Pin] -> Arduino [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Pin -> Arduino Bool
digitalRead [Pin]
ps
Bool -> Arduino () -> Arduino ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
or [Bool]
curVals) (Arduino () -> Arduino ()) -> Arduino () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Arduino [Bool] -> Arduino ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Arduino [Bool] -> Arduino ()) -> Arduino [Bool] -> Arduino ()
forall a b. (a -> b) -> a -> b
$ [Pin] -> Arduino [Bool]
waitAnyHigh [Pin]
ps
[(Bool, Bool)]
vs <- [Pin] -> Arduino [(Bool, Bool)]
waitGeneric [Pin]
ps
if (Bool
True, Bool
False) (Bool, Bool) -> [(Bool, Bool)] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [(Bool, Bool)]
vs
then [Bool] -> Arduino [Bool]
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Bool] -> Arduino [Bool]) -> [Bool] -> Arduino [Bool]
forall a b. (a -> b) -> a -> b
$ ((Bool, Bool) -> Bool) -> [(Bool, Bool)] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map (Bool, Bool) -> Bool
forall a b. (a, b) -> b
snd [(Bool, Bool)]
vs
else [Pin] -> Arduino [Bool]
waitAnyLow [Pin]
ps
waitGeneric :: [Pin] -> Arduino [(Bool, Bool)]
waitGeneric :: [Pin] -> Arduino [(Bool, Bool)]
waitGeneric [Pin]
ps = do
[Bool]
curVals <- (Pin -> Arduino Bool) -> [Pin] -> Arduino [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Pin -> Arduino Bool
digitalRead [Pin]
ps
MVar ()
semaphore <- IO (MVar ()) -> Arduino (MVar ())
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO (MVar ())
forall a. IO (MVar a)
newEmptyMVar
let wait :: Arduino [(Bool, Bool)]
wait = do MVar () -> Arduino ()
digitalWakeUp MVar ()
semaphore
IO () -> Arduino ()
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Arduino ()) -> IO () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ MVar () -> IO ()
forall a. MVar a -> IO a
readMVar MVar ()
semaphore
[Bool]
newVals <- (Pin -> Arduino Bool) -> [Pin] -> Arduino [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Pin -> Arduino Bool
digitalRead [Pin]
ps
if [Bool]
curVals [Bool] -> [Bool] -> Bool
forall a. Eq a => a -> a -> Bool
== [Bool]
newVals
then Arduino [(Bool, Bool)]
wait
else [(Bool, Bool)] -> Arduino [(Bool, Bool)]
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return ([(Bool, Bool)] -> Arduino [(Bool, Bool)])
-> [(Bool, Bool)] -> Arduino [(Bool, Bool)]
forall a b. (a -> b) -> a -> b
$ [Bool] -> [Bool] -> [(Bool, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Bool]
curVals [Bool]
newVals
Arduino [(Bool, Bool)]
wait
pulse :: Pin -> Bool -> Int -> Maybe Int -> Arduino (Maybe Int)
pulse :: Pin -> Bool -> Int -> Maybe Int -> Arduino (Maybe Int)
pulse Pin
p' Bool
v Int
duration Maybe Int
mbTo = do
(IPin
p, PinData
_) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"pulse" Pin
p' PinMode
INPUT
let to :: Int
to = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
maxAllowed Maybe Int
mbTo
maxAllowed :: Int
maxAllowed = Int
2147483647
bad :: Int -> Bool
bad Int
x = Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
x Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxAllowed
Bool -> Arduino () -> Arduino ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ((Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Int -> Bool
bad [Int
duration, Int
to]) (Arduino () -> Arduino ()) -> Arduino () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ String -> [String] -> Arduino ()
forall a. String -> [String] -> Arduino a
die (String
"Invalid duration/time-out values for pulse on pin " String -> String -> String
forall a. [a] -> [a] -> [a]
++ IPin -> String
forall a. Show a => a -> String
show IPin
p)
[ String
"Values should be between 0 and " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
maxAllowed
, String
"Received: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int, Int) -> String
forall a. Show a => a -> String
show (Int
duration, Int
to)
]
Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ IPin -> Bool -> Word32 -> Word32 -> Request
Pulse IPin
p Bool
v (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
duration) (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
to)
Response
r <- Arduino Response
recv
case Response
r of
PulseResponse IPin
pOut Word32
d | IPin
p IPin -> IPin -> Bool
forall a. Eq a => a -> a -> Bool
== IPin
pOut -> case Word32
d of
Word32
0 -> Maybe Int -> Arduino (Maybe Int)
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Int
forall a. Maybe a
Nothing
Word32
i -> Maybe Int -> Arduino (Maybe Int)
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Maybe Int
forall a. a -> Maybe a
Just (Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
i))
Response
_ -> String -> [String] -> Arduino (Maybe Int)
forall a. String -> [String] -> Arduino a
die (String
"pulseIn: Got unexpected response for Pulse call on pin: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Pin -> String
forall a. Show a => a -> String
show Pin
p') [Response -> String
forall a. Show a => a -> String
show Response
r]
pulseOut_hostTiming :: Pin
-> Bool
-> Int
-> Int
-> Arduino ()
pulseOut_hostTiming :: Pin -> Bool -> Int -> Int -> Arduino ()
pulseOut_hostTiming Pin
p' Bool
pulseValue Int
dBefore Int
dAfter
| Int
dBefore Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
dAfter Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0
= String -> [String] -> Arduino ()
forall a. String -> [String] -> Arduino a
die (String
"pulseOut: Invalid delay amounts: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Int, Int) -> String
forall a. Show a => a -> String
show (Int
dBefore, Int
dAfter))
[ String
"Pre-delay and pulse-amounts must be non-negative."]
| Bool
True
= do (IPin
p, PinData
pd) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"pulseOut_hostTiming" Pin
p' PinMode
OUTPUT
let curPort :: Port
curPort = IPin -> Port
pinPort IPin
p
curIndex :: Word8
curIndex = IPin -> Word8
pinPortIndex IPin
p
MVar BoardState
bs <- (ArduinoState -> MVar BoardState) -> Arduino (MVar BoardState)
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets ArduinoState -> MVar BoardState
boardState
((Word8, Word8)
setMask, (Word8, Word8)
resetMask) <- IO ((Word8, Word8), (Word8, Word8))
-> Arduino ((Word8, Word8), (Word8, Word8))
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ((Word8, Word8), (Word8, Word8))
-> Arduino ((Word8, Word8), (Word8, Word8)))
-> IO ((Word8, Word8), (Word8, Word8))
-> Arduino ((Word8, Word8), (Word8, Word8))
forall a b. (a -> b) -> a -> b
$ MVar BoardState
-> (BoardState -> IO ((Word8, Word8), (Word8, Word8)))
-> IO ((Word8, Word8), (Word8, Word8))
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar MVar BoardState
bs ((BoardState -> IO ((Word8, Word8), (Word8, Word8)))
-> IO ((Word8, Word8), (Word8, Word8)))
-> (BoardState -> IO ((Word8, Word8), (Word8, Word8)))
-> IO ((Word8, Word8), (Word8, Word8))
forall a b. (a -> b) -> a -> b
$ \BoardState
bst -> do
let values :: [(Word8, Maybe (Either Bool Int))]
values = [(IPin -> Word8
pinPortIndex IPin
sp, PinData -> Maybe (Either Bool Int)
pinValue PinData
spd) | (IPin
sp, PinData
spd) <- Map IPin PinData -> [(IPin, PinData)]
forall k a. Map k a -> [(k, a)]
M.assocs (BoardState -> Map IPin PinData
pinStates BoardState
bst), Port
curPort Port -> Port -> Bool
forall a. Eq a => a -> a -> Bool
== IPin -> Port
pinPort IPin
sp, PinData -> PinMode
pinMode PinData
pd PinMode -> [PinMode] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PinMode
INPUT, PinMode
OUTPUT]]
getVal :: Bool -> Word8 -> Bool
getVal Bool
nv Word8
i
| Word8
i Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
curIndex = Bool
nv
| Just (Just (Left Bool
ov)) <- Word8
i Word8
-> [(Word8, Maybe (Either Bool Int))]
-> Maybe (Maybe (Either Bool Int))
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` [(Word8, Maybe (Either Bool Int))]
values = Bool
ov
| Bool
True = Bool
False
mkMask :: Bool -> (a, b)
mkMask Bool
val = let [Bool
b0, Bool
b1, Bool
b2, Bool
b3, Bool
b4, Bool
b5, Bool
b6, Bool
b7] = (Word8 -> Bool) -> [Word8] -> [Bool]
forall a b. (a -> b) -> [a] -> [b]
map (Bool -> Word8 -> Bool
getVal Bool
val) [Word8
0 .. Word8
7]
lsb :: a
lsb = ((Int, Bool) -> a -> a) -> a -> [(Int, Bool)] -> a
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(Int
i, Bool
b) a
m -> if Bool
b then a
m a -> Int -> a
forall a. Bits a => a -> Int -> a
`setBit` Int
i else a
m) a
0 ([Int] -> [Bool] -> [(Int, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0..] [Bool
b0, Bool
b1, Bool
b2, Bool
b3, Bool
b4, Bool
b5, Bool
b6])
msb :: b
msb = ((Int, Bool) -> b -> b) -> b -> [(Int, Bool)] -> b
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (\(Int
i, Bool
b) b
m -> if Bool
b then b
m b -> Int -> b
forall a. Bits a => a -> Int -> a
`setBit` (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
7) else b
m) b
0 ([Int] -> [Bool] -> [(Int, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
7..] [Bool
b7])
in (a
lsb, b
msb)
((Word8, Word8), (Word8, Word8))
-> IO ((Word8, Word8), (Word8, Word8))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> (Word8, Word8)
forall {a} {b}. (Bits a, Bits b, Num a, Num b) => Bool -> (a, b)
mkMask Bool
pulseValue, Bool -> (Word8, Word8)
forall {a} {b}. (Bits a, Bits b, Num a, Num b) => Bool -> (a, b)
mkMask (Bool -> Bool
not Bool
pulseValue))
let writeThrough :: (Word8, Word8) -> Arduino ()
writeThrough (Word8
lsb, Word8
msb) = Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Port -> Word8 -> Word8 -> Request
DigitalPortWrite Port
curPort Word8
lsb Word8
msb
(Word8, Word8) -> Word8
forall a b. (a, b) -> a
fst (Word8, Word8)
setMask Word8 -> Arduino () -> Arduino ()
forall a b. a -> b -> b
`seq` (Word8, Word8) -> Word8
forall a b. (a, b) -> b
snd (Word8, Word8)
setMask Word8 -> Arduino () -> Arduino ()
forall a b. a -> b -> b
`seq` (Word8, Word8) -> Word8
forall a b. (a, b) -> a
fst (Word8, Word8)
resetMask Word8 -> Arduino () -> Arduino ()
forall a b. a -> b -> b
`seq` (Word8, Word8) -> Word8
forall a b. (a, b) -> b
snd (Word8, Word8)
resetMask Word8 -> Arduino () -> Arduino ()
forall a b. a -> b -> b
`seq` (Word8, Word8) -> Arduino ()
writeThrough (Word8, Word8)
resetMask
IO () -> Arduino ()
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Arduino ()) -> IO () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Int -> IO ()
threadDelay Int
dBefore
(Word8, Word8) -> Arduino ()
writeThrough (Word8, Word8)
setMask
IO () -> Arduino ()
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Arduino ()) -> IO () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Int -> IO ()
threadDelay Int
dAfter
(Word8, Word8) -> Arduino ()
writeThrough (Word8, Word8)
resetMask
IO () -> Arduino ()
forall a. IO a -> Arduino a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Arduino ()) -> IO () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ MVar BoardState -> (BoardState -> IO BoardState) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar BoardState
bs ((BoardState -> IO BoardState) -> IO ())
-> (BoardState -> IO BoardState) -> IO ()
forall a b. (a -> b) -> a -> b
$ \BoardState
bst -> BoardState -> IO BoardState
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return BoardState
bst{pinStates = M.insert p PinData{pinMode = OUTPUT, pinValue = Just (Left (not pulseValue))}(pinStates bst)}
{-# ANN pulseOut_hostTiming "HLint: ignore Use camelCase" #-}
pulseIn_hostTiming :: Pin -> Bool -> Maybe Int -> Arduino (Maybe Int)
pulseIn_hostTiming :: Pin -> Bool -> Maybe Int -> Arduino (Maybe Int)
pulseIn_hostTiming Pin
p Bool
v Maybe Int
mbTo = case Maybe Int
mbTo of
Maybe Int
Nothing -> Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Arduino Int -> Arduino (Maybe Int)
forall a b. (a -> b) -> Arduino a -> Arduino b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Arduino Int
measure
Just Int
to -> Int -> Arduino Int -> Arduino (Maybe Int)
forall a. Int -> Arduino a -> Arduino (Maybe a)
timeOut Int
to Arduino Int
measure
where waitTill :: (Bool -> Bool) -> Arduino ()
waitTill Bool -> Bool
f = do Bool
curVal <- Pin -> Arduino Bool
digitalRead Pin
p
Bool -> Arduino () -> Arduino ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
f Bool
curVal) (Arduino () -> Arduino ()) -> Arduino () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ (Bool -> Bool) -> Arduino ()
waitTill Bool -> Bool
f
measure :: Arduino Int
measure = do (Bool -> Bool) -> Arduino ()
waitTill (Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
v)
(Int
t, ()
_) <- Arduino () -> Arduino (Int, ())
forall a. Arduino a -> Arduino (Int, a)
time (Arduino () -> Arduino (Int, ()))
-> Arduino () -> Arduino (Int, ())
forall a b. (a -> b) -> a -> b
$ (Bool -> Bool) -> Arduino ()
waitTill (Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Bool
v)
Int -> Arduino Int
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Arduino Int) -> Int -> Arduino Int
forall a b. (a -> b) -> a -> b
$ Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
t
{-# ANN pulseIn_hostTiming "HLint: ignore Use camelCase" #-}
analogRead :: Pin -> Arduino Int
analogRead :: Pin -> Arduino Int
analogRead Pin
p' = do
(IPin
_, PinData
pd) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"analogRead" Pin
p' PinMode
ANALOG
Int -> Arduino Int
forall a. a -> Arduino a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Arduino Int) -> Int -> Arduino Int
forall a b. (a -> b) -> a -> b
$ case PinData -> Maybe (Either Bool Int)
pinValue PinData
pd of
Just (Right Int
v) -> Int
v
Maybe (Either Bool Int)
_ -> Int
0
analogWrite :: Pin -> Int -> Arduino ()
analogWrite :: Pin -> Int -> Arduino ()
analogWrite Pin
p' Int
dc = do
(IPin
p, PinData
_) <- String -> Pin -> PinMode -> Arduino (IPin, PinData)
convertAndCheckPin String
"analogWrite" Pin
p' PinMode
PWM
Bool -> Arduino () -> Arduino ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
dc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
dc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
255) (Arduino () -> Arduino ()) -> Arduino () -> Arduino ()
forall a b. (a -> b) -> a -> b
$ String -> [String] -> Arduino ()
forall a. String -> [String] -> Arduino a
die (String
"Invalid duty-cycle value for PWM write on pin " String -> String -> String
forall a. [a] -> [a] -> [a]
++ IPin -> String
forall a. Show a => a -> String
show IPin
p)
[ String
"Values should be between 0 and 255"
, String
"Received: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
dc
]
Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ IPin -> Word8 -> Word8 -> Request
AnalogPinWrite IPin
p (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lsb) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
msb)
where lsb :: Int
lsb = Int
dc Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f
msb :: Int
msb = (Int
dc Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f
setAnalogSamplingInterval :: Int -> Arduino ()
setAnalogSamplingInterval :: Int -> Arduino ()
setAnalogSamplingInterval Int
i
| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
10 Bool -> Bool -> Bool
|| Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
16383
= String -> [String] -> Arduino ()
forall a. String -> [String] -> Arduino a
die (String
"hArduino: setAnalogSamplingInterval: Allowed interval is [10, 16383] ms, received: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
i) []
| Bool
True
= Request -> Arduino ()
send (Request -> Arduino ()) -> Request -> Arduino ()
forall a b. (a -> b) -> a -> b
$ Word8 -> Word8 -> Request
SamplingInterval (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
lsb) (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
msb)
where lsb :: Int
lsb = Int
i Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f
msb :: Int
msb = (Int
i Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. Int
0x7f