packages feed

blink1 0.3.1 → 0.4

raw patch · 9 files changed

+265/−37 lines, 9 filesdep +blink1dep −bindings-libusbdep ~basedep ~textnew-component:exe:blink1PVP ok

version bump matches the API change (PVP)

Dependencies added: blink1

Dependencies removed: bindings-libusb

Dependency ranges changed: base, text

API changes (from Hackage documentation)

- System.Hardware.Blink1.Linux: closeRaw :: Blink1Raw -> IO ()
- System.Hardware.Blink1.USB: closeUSB :: Blink1USB -> IO ()
+ System.Hardware.Blink1: closeBlink1 :: Blink1 b => b -> IO ()
+ System.Hardware.Blink1: data LED
+ System.Hardware.Blink1: fadeToColor2 :: Blink1 b => b -> Maybe LED -> Delay -> RGB8 -> IO ()
+ System.Hardware.Blink1: getColor2 :: Blink1 b => b -> LED -> IO RGB8
+ System.Hardware.Blink1: getPlaying2 :: Blink1 b => b -> IO (Maybe (PatternStep, PatternStep, Word8, Word8))
+ System.Hardware.Blink1: playPattern2 :: Blink1 b => b -> (PatternStep, PatternStep) -> Word8 -> IO ()
+ System.Hardware.Blink1: savePatterns2 :: Blink1 b => b -> IO ()
+ System.Hardware.Blink1: setColor2 :: Blink1 b => b -> Maybe LED -> RGB8 -> IO ()
+ System.Hardware.Blink1: setServerDown2 :: Blink1 b => b -> Bool -> Delay -> Bool -> (PatternStep, PatternStep) -> IO ()
+ System.Hardware.Blink1.Class: blink1Product :: Word16
+ System.Hardware.Blink1.Class: blink1Vendor :: Word16
+ System.Hardware.Blink1.Class: class Blink1 b
+ System.Hardware.Blink1.Class: closeBlink1 :: Blink1 b => b -> IO ()
+ System.Hardware.Blink1.Class: readBlink1 :: Blink1 b => b -> Int -> IO [Word8]
+ System.Hardware.Blink1.Class: writeBlink1 :: Blink1 b => b -> [Word8] -> IO ()
+ System.Hardware.Blink1.Dummy: data Blink1Dummy
+ System.Hardware.Blink1.Dummy: instance Blink1 Blink1Dummy
+ System.Hardware.Blink1.Dummy: openDummy :: Bool -> Blink1Dummy
+ System.Hardware.Blink1.Types: Delay :: Word16 -> Delay
+ System.Hardware.Blink1.Types: EEBootMode :: EEPROMAddr
+ System.Hardware.Blink1.Types: EEOSCCAL :: EEPROMAddr
+ System.Hardware.Blink1.Types: EEPatternStart :: EEPROMAddr
+ System.Hardware.Blink1.Types: EESerialNum :: Word8 -> EEPROMAddr
+ System.Hardware.Blink1.Types: LED :: Word8 -> LED
+ System.Hardware.Blink1.Types: PatternStep :: Word8 -> PatternStep
+ System.Hardware.Blink1.Types: RGB :: !a -> !a -> !a -> RGB a
+ System.Hardware.Blink1.Types: black :: RGB8
+ System.Hardware.Blink1.Types: blue :: RGB a -> !a
+ System.Hardware.Blink1.Types: data EEPROMAddr
+ System.Hardware.Blink1.Types: data RGB a
+ System.Hardware.Blink1.Types: delayCentiseconds :: Delay -> Word16
+ System.Hardware.Blink1.Types: green :: RGB a -> !a
+ System.Hardware.Blink1.Types: instance (Num a, Ord a, Bounded a) => Monoid (RGB a)
+ System.Hardware.Blink1.Types: instance Applicative RGB
+ System.Hardware.Blink1.Types: instance Bounded Delay
+ System.Hardware.Blink1.Types: instance Bounded EEPROMAddr
+ System.Hardware.Blink1.Types: instance Bounded LED
+ System.Hardware.Blink1.Types: instance Bounded PatternStep
+ System.Hardware.Blink1.Types: instance Enum Delay
+ System.Hardware.Blink1.Types: instance Enum EEPROMAddr
+ System.Hardware.Blink1.Types: instance Enum LED
+ System.Hardware.Blink1.Types: instance Enum PatternStep
+ System.Hardware.Blink1.Types: instance Eq Delay
+ System.Hardware.Blink1.Types: instance Eq EEPROMAddr
+ System.Hardware.Blink1.Types: instance Eq LED
+ System.Hardware.Blink1.Types: instance Eq PatternStep
+ System.Hardware.Blink1.Types: instance Fractional Delay
+ System.Hardware.Blink1.Types: instance Functor RGB
+ System.Hardware.Blink1.Types: instance HasResolution Delay
+ System.Hardware.Blink1.Types: instance Num Delay
+ System.Hardware.Blink1.Types: instance Num LED
+ System.Hardware.Blink1.Types: instance Num PatternStep
+ System.Hardware.Blink1.Types: instance Num a => Num (RGB a)
+ System.Hardware.Blink1.Types: instance Ord Delay
+ System.Hardware.Blink1.Types: instance Ord EEPROMAddr
+ System.Hardware.Blink1.Types: instance Ord LED
+ System.Hardware.Blink1.Types: instance Ord PatternStep
+ System.Hardware.Blink1.Types: instance Read Delay
+ System.Hardware.Blink1.Types: instance Read LED
+ System.Hardware.Blink1.Types: instance Read PatternStep
+ System.Hardware.Blink1.Types: instance Read RGB8
+ System.Hardware.Blink1.Types: instance Real Delay
+ System.Hardware.Blink1.Types: instance RealFrac Delay
+ System.Hardware.Blink1.Types: instance Show Delay
+ System.Hardware.Blink1.Types: instance Show LED
+ System.Hardware.Blink1.Types: instance Show PatternStep
+ System.Hardware.Blink1.Types: instance Show RGB8
+ System.Hardware.Blink1.Types: newtype Delay
+ System.Hardware.Blink1.Types: newtype LED
+ System.Hardware.Blink1.Types: newtype PatternStep
+ System.Hardware.Blink1.Types: patternStep :: PatternStep -> Word8
+ System.Hardware.Blink1.Types: red :: RGB a -> !a
+ System.Hardware.Blink1.Types: second :: Delay
+ System.Hardware.Blink1.Types: serialNumLen :: Word8
+ System.Hardware.Blink1.Types: type RGB8 = RGB Word8
+ System.Hardware.Blink1.Types: whichLED :: LED -> Word8
+ System.Linux.HIDRaw: DevInfo :: Word32 -> Word16 -> Word16 -> DevInfo
+ System.Linux.HIDRaw: data DevInfo
+ System.Linux.HIDRaw: devBustype :: DevInfo -> Word32
+ System.Linux.HIDRaw: devInfo :: Fd -> IO DevInfo
+ System.Linux.HIDRaw: devProduct :: DevInfo -> Word16
+ System.Linux.HIDRaw: devVendor :: DevInfo -> Word16
+ System.Linux.HIDRaw: getFeature :: Fd -> Int -> IO [Word8]
+ System.Linux.HIDRaw: instance Storable DevInfo
+ System.Linux.HIDRaw: setFeature :: Fd -> [Word8] -> IO ()

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012-2013, Dylan Simon+Copyright (c) 2012-2014, Dylan Simon All rights reserved.  Redistribution and use in source and binary forms, with or without
System/Hardware/Blink1.hs view
@@ -1,15 +1,33 @@+{-|++  To use any of these functions, you first must open a blink(1) device (providing the 'System.Hardware.Blink1.Class.Blink' interface).+  Currently "System.Hardware.Blink1.Linux" and "System.Hardware.Blink1.USB" are provided.++  The functions ending with 2 provide functionality available on the blink(1) mk2, so are only likely to work if 'getVersion' returns @('2',_)@++-}+ module System.Hardware.Blink1   ( RGB(..), RGB8   , Delay(..)   , PatternStep+  , LED +  , closeBlink1   , getVersion+  , getColor2   , setColor+  , setColor2   , fadeToColor+  , fadeToColor2   , setServerDown+  , setServerDown2   , playPattern+  , playPattern2+  , getPlaying2   , setPattern   , getPattern+  , savePatterns2   , getSerialNum   , setSerialNum   , testBlink1@@ -50,46 +68,82 @@  getVersion :: Blink1 b => b -> IO (Char,Char) getVersion b = do-  _:_:maj:min:_ <- request b 'v' []-  return (chr (fi maj), chr (fi min))+  _:_:mj:mn:_ <- request b 'v' []+  return (chr (fi mj), chr (fi mn))  rgb :: RGB8 -> [Word8] rgb (RGB r g b) = [r,g,b]  delay :: Delay -> [Word8] delay d = [i $ t `shiftR` 8, i t] where -  t = truncate (100 * d) :: Word16+  t = delayCentiseconds d   i = fi :: Word16 -> Word8 -pos :: PatternStep -> [Word8]-pos p = [fi (fromEnum p)]+bool :: Bool -> Word8+bool = fi . fromEnum +pos :: PatternStep -> Word8+pos = patternStep++led :: Maybe LED -> Word8+led = maybe 0 whichLED++-- | query the current color.+getColor2 :: Blink1 b => b -> LED -> IO RGB8+getColor2 dev n = do+  _:r:g:b:_ <- request dev 'r' [0,0,0,0,0,led (Just n)]+  return $ RGB r g b+ -- | set the given color now setColor :: Blink1 b => b -> RGB8 -> IO ()-setColor b c = command b 'n' $ rgb c+setColor b = setColor2 b Nothing +-- | Although documented, this does not appear to work correctly.+setColor2 :: Blink1 b => b -> Maybe LED -> RGB8 -> IO ()+setColor2 b n c = command b 'n' $ rgb c ++ [0,0,led n]+ fadeToColor :: Blink1 b => b -> Delay -> RGB8 -> IO ()-fadeToColor b d c = command b 'c' $ rgb c ++ delay d+fadeToColor b = fadeToColor2 b Nothing --- | enable/disable serverdown mode+fadeToColor2 :: Blink1 b => b -> Maybe LED -> Delay -> RGB8 -> IO ()+fadeToColor2 b n d c = command b 'c' $ rgb c ++ delay d ++ [led n]++-- | enable/disable serverdown mode with the given timeout setServerDown :: Blink1 b => b -> Bool -> Delay -> IO ()-setServerDown b o d = command b 'D' $ fi (fromEnum o) : delay d+setServerDown b o d = setServerDown2 b o d False (PatternStep 0, PatternStep 0) +-- | enable/disable serverdown mode with the given timeout, optionally staying on afterwards, over the given pattern range+setServerDown2 :: Blink1 b => b -> Bool -> Delay -> Bool -> (PatternStep, PatternStep) -> IO ()+setServerDown2 b o d s (sp,ep) = command b 'D' $ bool o : delay d ++ [bool s, pos sp, pos ep]+ -- | stop or start playing the sequence at the given position playPattern :: Blink1 b => b -> Maybe PatternStep -> IO () playPattern b Nothing = command b 'p' [0]-playPattern b (Just p) = command b 'p' $ 1 : pos p+playPattern b (Just p) = command b 'p' [1, pos p] +-- | loop the sequence over a range some number of times.+playPattern2 :: Blink1 b => b -> (PatternStep, PatternStep) -> Word8 -> IO ()+playPattern2 b (sp, ep) n = command b 'p' [1, pos sp, pos ep, n]++-- | query the current play state.+getPlaying2 :: Blink1 b => b -> IO (Maybe (PatternStep, PatternStep, Word8, Word8))+getPlaying2 b = do+  _:a:sp:ep:n:i:_ <- request b 'S' []+  return $ if a > 0 then Just (PatternStep sp, PatternStep ep, n, i) else Nothing+ -- | set the sequence pattern for the given position setPattern :: Blink1 b => b -> PatternStep -> Delay -> RGB8 -> IO ()-setPattern b p d c = command b 'P' $ rgb c ++ delay d ++ pos p+setPattern b p d c = command b 'P' $ rgb c ++ delay d ++ [pos p]  getPattern :: Blink1 b => b -> PatternStep -> IO (Delay, RGB8)-getPattern b p = do-  _:r:g:b:d1:d2:_ <- request b 'R' $ rgb black ++ delay 0 ++ pos p+getPattern dev p = do+  _:r:g:b:d1:d2:_ <- request dev 'R' $ rgb black ++ delay 0 ++ [pos p]   return (fi (i d1 `shiftL` 8 .|. i d2) / 100, RGB r g b)   where i = fi :: Word8 -> Word16 +savePatterns2 :: Blink1 b => b -> IO ()+savePatterns2 b = command b 'W' [0xBE,0xEF,0xCA,0xFE]+ eeaddr :: EEPROMAddr -> Word8 eeaddr = fi . fromEnum @@ -101,11 +155,13 @@ writeEEPROM :: Blink1 b => b -> EEPROMAddr -> Word8 -> IO () writeEEPROM b a v = command b 'E' [eeaddr a, v] +-- | This is only supported on mk1 devices. getSerialNum :: Blink1 b => b -> IO Word32 getSerialNum b =   foldl' (\l -> (l `shiftL` 8 .|.) . fi) 0 `liftM`      mapM (readEEPROM b . EESerialNum) [0..pred serialNumLen] +-- | This is only supported on mk1 devices. setSerialNum :: Blink1 b => b -> Word32 -> IO () setSerialNum b s = mapM_ w [0..pred serialNumLen] where   w i = writeEEPROM b (EESerialNum i) $ fi $ s `shiftR` (8*(3-fi i))
System/Hardware/Blink1/Class.hs view
@@ -1,6 +1,5 @@ module System.Hardware.Blink1.Class   ( Blink1(..)-  , Word8   , blink1Vendor, blink1Product   ) where 
+ System/Hardware/Blink1/Dummy.hs view
@@ -0,0 +1,22 @@+module System.Hardware.Blink1.Dummy+  ( Blink1Dummy+  , openDummy+  ) where++import Data.Char (chr)+import Data.List (intercalate)+import System.Hardware.Blink1.Class++data Blink1Dummy = Blink1Dummy+  { _verbose :: Bool+  }++openDummy :: Bool -> Blink1Dummy+openDummy = Blink1Dummy++instance Blink1 Blink1Dummy where+  writeBlink1 (Blink1Dummy False) _ = return ()+  writeBlink1 (Blink1Dummy True) (1:c:l) = putStrLn (chr (fromIntegral c):':':intercalate "," (map show l))+  writeBlink1 (Blink1Dummy True) l = print l+  readBlink1 _ n = return (replicate n 0)+  closeBlink1 _ = return ()
System/Hardware/Blink1/Linux.hs view
@@ -1,14 +1,20 @@+{-|++  Blink(1) hardware interface using Linux's /dev/hidraw* devices.++-}+ module System.Hardware.Blink1.Linux   ( Blink1Raw   , openRawDev   , openRawHID   , openRawHIDs-  , closeRaw   ) where  import Control.Exception (onException, bracket) import Control.Monad import Data.List (isPrefixOf, genericLength)+import Data.Word (Word8) import Foreign.C.Error (errnoToIOError, eFTYPE) -- hack import Numeric (readHex) import System.IO.Error (mkIOError, fullErrorType, doesNotExistErrorType)@@ -37,9 +43,9 @@ findRawDev = pds dp hiddir where   hiddir = "/sys/bus/hid/devices"   pds f d = bracket (openDirStream d) closeDirStream r where-    r d = do-      e <- readDirStream d-      if null e then return mzero else liftM2 mplus (f e) (r d)+    r ds = do+      e <- readDirStream ds+      if null e then return mzero else liftM2 mplus (f e) (r ds)   dp f | null (do       (_,':':vs) <- rh f       (v,':':ps) <- rh vs
System/Hardware/Blink1/Types.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP, GeneralizedNewtypeDeriving, FlexibleInstances, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-name-shadowing #-} module System.Hardware.Blink1.Types   ( RGB(..), RGB8   , black@@ -7,6 +8,7 @@   , PatternStep(..)   , EEPROMAddr(..)   , serialNumLen+  , LED(..)   ) where  import Control.Applicative@@ -120,12 +122,12 @@       ), s)  --- | positions are counted 0-11-newtype PatternStep = PatternStep Word8 deriving (Eq, Ord, Enum, Num, Show, Read)+-- | positions are counted 0-11 on mk1, 0-31 on mk2+newtype PatternStep = PatternStep { patternStep :: Word8 } deriving (Eq, Ord, Enum, Num, Show, Read)  instance Bounded PatternStep where   minBound = PatternStep 0-  maxBound = PatternStep 11+  maxBound = PatternStep 31 -- 11 on mk1  data EEPROMAddr   = EEOSCCAL@@ -154,3 +156,10 @@ instance Bounded EEPROMAddr where   minBound = EEOSCCAL   maxBound = EEPatternStart++-- | LEDs are 1-based (0 means "all")+newtype LED = LED { whichLED :: Word8 } deriving (Eq, Ord, Enum, Num, Show, Read)++instance Bounded LED where+  minBound = LED 1+  maxBound = LED maxBound
System/Hardware/Blink1/USB.hs view
@@ -1,12 +1,18 @@+{-|++  Blink(1) hardware interface using libusb.++-}+ module System.Hardware.Blink1.USB   ( Blink1USB   , openUSB   , openUSBs-  , closeUSB   , getSerialNumber   ) where  import Control.Monad+import Data.Word (Word8) import System.IO.Error (mkIOError, doesNotExistErrorType) import System.USB import qualified Data.Vector as V@@ -28,11 +34,11 @@  openDev :: Device -> IO Blink1USB openDev d = do-  d <- openDevice d-  kda <- kernelDriverActive d interface-  when kda $ detachKernelDriver d interface-  claimInterface d interface-  return $ Blink1USB d+  dev <- openDevice d+  kda <- kernelDriverActive dev interface+  when kda $ detachKernelDriver dev interface+  claimInterface dev interface+  return $ Blink1USB dev  openUSB :: IO Blink1USB openUSB = do
blink1.cabal view
@@ -1,5 +1,5 @@ Name:		blink1-Version:	0.3.1+Version:	0.4 Author:		Dylan Simon Maintainer:     dylan@dylex.net License:        BSD3@@ -8,8 +8,8 @@ Description:    Provides an interface to the ThingM blink(1) LED <http://thingm.com/products/blink-1.html> similar to (but not dependent on) <http://github.com/todbot/blink1> via Linux hidraw or the libusb-based usb package. Category:	Hardware Build-Type:	Simple-Cabal-Version:	>= 1.6-tested-with:	GHC == 7.6.1+Cabal-Version:	>= 1.8+tested-with:	GHC == 7.8.3  Source-Repository head     Type:	git@@ -20,15 +20,24 @@  Library     Build-Depends:	base == 4.*-    Exposed-Modules:    System.Hardware.Blink1-    Other-Modules:      System.Hardware.Blink1.Types, System.Hardware.Blink1.Class-    ghc-options:        -Wall -fno-warn-name-shadowing+    Exposed-Modules:    System.Hardware.Blink1, System.Hardware.Blink1.Types, System.Hardware.Blink1.Class, System.Hardware.Blink1.Dummy+    ghc-options: -Wall      if os(linux)         Build-Depends:	unix-        Exposed-Modules: System.Hardware.Blink1.Linux-        Other-Modules:	System.Linux.HIDRaw+        Exposed-Modules: System.Hardware.Blink1.Linux, System.Linux.HIDRaw      if flag(usb)-        Build-Depends:  usb, bindings-libusb, vector, text, bytestring+        Build-Depends:  usb, vector, text < 1.2, bytestring         Exposed-Modules: System.Hardware.Blink1.USB++Executable blink1+    main-is: blink1.hs+    build-depends: base, blink1+    if os(linux)+        build-depends: unix+        CPP-options: -DUSE_LINUX+    if flag(usb)+        Build-Depends: usb, vector, text < 1.2, bytestring+        CPP-options: -DUSE_USB+    ghc-options: -Wall
+ blink1.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE CPP, RankNTypes #-}++import Control.Applicative ((<$>), (<|>))+import Control.Monad (foldM)+import Data.Maybe (fromMaybe)+import System.Environment (getArgs)+import System.Exit (exitFailure)+import qualified System.Console.GetOpt as Opt++import System.Hardware.Blink1+import System.Hardware.Blink1.Class (Blink1)+import System.Hardware.Blink1.Dummy (Blink1Dummy, openDummy)+#ifdef USE_LINUX+import System.Hardware.Blink1.Linux (Blink1Raw, openRawHID, openRawDev)+#endif+#ifdef USE_USB+import System.Hardware.Blink1.USB (Blink1USB, openUSB)+#endif++data Dev+  = NoDev+  | DummyDev Blink1Dummy+#ifdef USE_LINUX+  | LinuxRawDev Blink1Raw+#endif+#ifdef USE_USB+  | USBDev Blink1USB+#endif++withDev :: Dev -> (forall b . Blink1 b => b -> a) -> a+withDev NoDev _ = error "No device opened"+withDev (DummyDev b) f = f b+#ifdef USE_LINUX+withDev (LinuxRawDev b) f = f b+#endif+#ifdef USE_USB+withDev (USBDev b) f = f b+#endif++withDev_ :: Dev -> (forall b . Blink1 b => b -> IO ()) -> IO ()+withDev_ NoDev _ = return ()+withDev_ d f = withDev d f++data State = State +  { dev :: !Dev+  , led :: Maybe LED+  , time :: Delay+  }++opening :: IO Dev -> State -> IO State+opening o s = do+  withDev_ (dev s) closeBlink1+  d <- o+  return s{ dev = d }++close :: State -> IO State+close = opening (return NoDev)++run :: (forall b . Blink1 b => b -> IO a) -> (a -> IO ()) -> State -> IO State+run f g s = withDev (dev s) f >>= g >> return s++options :: [Opt.OptDescr (State -> IO State)]+options =+  [ Opt.Option "D" ["dummy"]+      (Opt.NoArg $ opening (return $ DummyDev $ openDummy True))+      "open a dummy blink(1) device"+#ifdef USE_LINUX+  , Opt.Option "L" ["hidraw"]+      (Opt.OptArg (\f -> opening (LinuxRawDev <$> maybe openRawHID openRawDev f)) "DEVICE")+      "open a linux hidraw device"+#endif+#ifdef USE_USB+  , Opt.Option "U" ["usb"]+      (Opt.NoArg $ opening (USBDev <$> openUSB))+      "open a libusb device"+#endif+  , Opt.Option "V" ["version"]+      (Opt.NoArg $ run getVersion (\(a, b) -> putStrLn [a,'.',b]))+      "get the version number"+  , Opt.Option "T" ["test"]+      (Opt.NoArg $ run testBlink1 (putStrLn . either (\r -> "unexpected: " ++ show r) (\r -> if r then "pass" else "fail")))+      "issue the test command"+  , Opt.Option "S" ["serial"]+      (Opt.NoArg $ run getSerialNum print)+      "get the serial number (only works on mk1)"+  , Opt.Option "l" ["led"]+      (Opt.OptArg (\l s -> return s{ led = fmap (toEnum . read) l }) "INDEX")+      "apply the next actions only to LED INDEX [all]"+  , Opt.Option "g" ["get"]+      (Opt.OptArg (\l s -> do+        withDev (dev s) getColor2 (fromMaybe 0 (fmap (toEnum . read) l <|> led s)) >>= print+        return s) "LED")+      "get the current color of the LED"+  , Opt.Option "s" ["set"]+      (Opt.ReqArg (\c s -> do+        withDev (dev s) setColor2 (led s) (read c)+        return s) "RGB")+      "set the color immediately"+  , Opt.Option "t" ["time"]+      (Opt.ReqArg (\t s -> return s{ time = read t }) "DELAY")+      "set the delay/fade time for the next actions"+  , Opt.Option "f" ["fade"]+      (Opt.ReqArg (\c s -> do+        withDev (dev s) fadeToColor2 (led s) (time s) (read c)+        return s) "RGB")+      "fade to color over DELAY"+  ]++usage :: String+usage = Opt.usageInfo "Usage: blink1 [OPTIONS]" options++main :: IO State+main = do+  args <- getArgs+  r <- case Opt.getOpt Opt.RequireOrder options args of+    (r, [], []) -> return r+    (_, _, err) -> do+      mapM_ putStrLn err+      putStrLn usage+      exitFailure+  foldM (flip ($)) (State NoDev Nothing 0) r >>= close