packages feed

kafka-device-spacenav (empty) → 0.1.5.0

raw patch · 8 files changed

+368/−0 lines, 8 filesdep +aesondep +basedep +binarysetup-changed

Dependencies added: aeson, base, binary, bytestring, cereal, kafka-device, milena

Files

+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2016 Brian W Bush++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ReadMe.md view
@@ -0,0 +1,14 @@+Linux joystick events via a Kafka message broker+================================================++This package contains functions for passing Linux device events from a [SpaceNavigator](http://www.3dconnexion.com/products/spacemouse/spacenavigator.html) to topics on a [Kafka message broker](https://kafka.apache.org/).+++Clients+-------++The simple Kafka client that produces events from the joystick can be run, for example, as follows:++	cabal run kafka-device-spacenav -- /dev/input/spacenavigator spacenav-client localhost 9092 events spacenav++Also see https://hackage.haskell.org/package/kafka-device/.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ kafka-device-spacenav.cabal view
@@ -0,0 +1,50 @@+name:                kafka-device-spacenav+version:             0.1.5.0+synopsis:            Linux SpaceNavigator events via a Kafka message broker+description:         This package contains functions for passing Linux device events from a SpaceNavigator \<<http://www.3dconnexion.com/products/spacemouse/spacenavigator.html>\> to topics on a Kafka message broker \<<https://kafka.apache.org/>\>.  Also see \<<https://hackage.haskell.org/package/kafka-device/>\>.+license:             MIT+license-file:        LICENSE+author:              Brian W Bush <consult@brianwbush.info>+maintainer:          Brian W Bush <consult@brianwbush.info>+copyright:           (c) 2016 Brian W Bush+category:            Hardware+build-type:          Simple+cabal-version:       >= 1.10+stability:           Experimental+homepage:            https://bitbucket.org/functionally/kafka-device-spacenav+bug-reports:         https://bwbush.atlassian.net/projects/HKAFDEV/issues/+package-url:         https://bitbucket.org/functionally/kafka-device-spacenav/downloads/kafka-device-spacenav-0.1.5.0.tar.gz++extra-source-files:  ReadMe.md++source-repository head+  type: git+  location: https://bitbucket.org/functionally/kafka-device-spacenav+ +library+  exposed-modules:  Network.UI.Kafka.SpaceNav+                    System.Hardware.Linux.Input+                    System.Hardware.Linux.SpaceNav+  build-depends:    base         >= 4.8 && < 5+               ,    aeson+               ,    binary+               ,    bytestring+               ,    cereal+               ,    kafka-device+               ,    milena+  hs-source-dirs:   src+  ghc-options:      -Wall+  default-language: Haskell2010++executable kafka-device-spacenav+  main-is:          Main.hs+  build-depends:    base+               ,    aeson+               ,    binary+               ,    bytestring+               ,    cereal+               ,    kafka-device+               ,    milena+  hs-source-dirs:   src+  ghc-options:      -Wall+  default-language: Haskell2010
+ src/Main.hs view
@@ -0,0 +1,46 @@+{-|+Module      :  Main+Copyright   :  (c) 2016 Brian W Bush+License     :  MIT+Maintainer  :  Brian W Bush <consult@brianwbush.info>+Stability   :  Experimental+Portability :  Linux++Produce events for a Kafka topic from a SpaceNavigator \<<http://www.3dconnexion.com/products/spacemouse/spacenavigator.html>\> on Linux.+-}+++module Main (+-- * Main entry+  main+) where+++import Data.String (IsString(fromString))+import Network.UI.Kafka.SpaceNav (spacenavLoop)+import System.Environment (getArgs)+++-- The main action.+main :: IO ()+main =+  do+    args <- getArgs+    case args of+      [device, client, host, port, topic, sensor] ->+        do+          putStrLn $ "Device:        " ++ device+          putStrLn $ "Kafka client:  " ++ client+          putStrLn $ "Kafka address: (" ++ host ++ "," ++ port ++ ")"+          putStrLn $ "Kafka topic:   " ++ topic+          putStrLn $ "Sensor name:   " ++ sensor+          (_, loop) <-+            spacenavLoop+              device+              (fromString client)+              (fromString host, toEnum $ read port)+              (fromString topic)+              sensor+          result <- loop+          either print return result+      _ -> putStrLn "USAGE: kafka-device-spacenav device client host port topic sensor"
+ src/Network/UI/Kafka/SpaceNav.hs view
@@ -0,0 +1,60 @@+{-|+Module      :  Network.UI.Kafka.SpaceNav+Copyright   :  (c) 2016 Brian W Bush+License     :  MIT+Maintainer  :  Brian W Bush <consult@brianwbush.info>+Stability   :  Experimental+Portability :  Linux++Produce events for a Kafka topic from a SpaceNavigator \<<http://www.3dconnexion.com/products/spacemouse/spacenavigator.html>\> on Linux.+-}+++{-# LANGUAGE RecordWildCards #-}+++module Network.UI.Kafka.SpaceNav (+-- * Event handling+  spacenavLoop+) where+++import Data.ByteString.Lazy.Char8 (hGet)+import Network.Kafka (KafkaAddress, KafkaClientId)+import Network.Kafka.Protocol (TopicName)+import Network.UI.Kafka (ExitAction, LoopAction, Sensor, producerLoop)+import Network.UI.Kafka.Types (Button(..), Event(..), Toggle(..))+import System.Hardware.Linux.SpaceNav (SpaceNav(..), byteLength, interpretSpaceNav)+import System.IO (IOMode(ReadMode), hClose, openFile)+++-- | Produce events for a Kafka topic from a Linux SpaceNav.+spacenavLoop :: FilePath                    -- ^ The path to the spacenav device, e.g. "\/dev\/input\/spacenav0".+             -> KafkaClientId               -- ^ A Kafka client identifier for the producer.+             -> KafkaAddress                -- ^ The address of the Kafka broker.+             -> TopicName                   -- ^ The Kafka topic name.+             -> Sensor                      -- ^ The name of the sensor producing events.+             -> IO (ExitAction, LoopAction) -- ^ Action to create the exit and loop actions.+spacenavLoop path client address topic sensor =+  do+    spacenav <- openFile path ReadMode+    (exit, loop) <-+      producerLoop client address topic sensor+        $ translate+        . interpretSpaceNav+        <$> hGet spacenav byteLength+    return+      (+        do+          exit+          hClose spacenav+      , loop+      )+++-- | Translate a SpaceNavigator event on Linux into events for Kafka.+translate :: SpaceNav -- ^ The SpaceNavigator event.+          -> [Event]  -- ^ The corresponding events for Kafka.+translate SpaceNavButton{..} = [ButtonEvent (IndexButton number, if pressed then Down else Up)]+translate SpaceNavAnalog{..} = [AnalogEvent number setting]+translate SpaceNavNull       = []
+ src/System/Hardware/Linux/Input.hs view
@@ -0,0 +1,64 @@+{-|+Module      :  System.Hardware.Linux.Input+Copyright   :  (c) 2016 Brian W Bush+License     :  MIT+Maintainer  :  Brian W Bush <consult@brianwbush.info>+Stability   :  Experimental+Portability :  Linux++Parse events from Linux /dev/input streams.  See \<<https://github.com/torvalds/linux/blob/master/include/uapi/linux/input.h>\> for details.+-}+++{-# LANGUAGE RecordWildCards #-}+++module System.Hardware.Linux.Input (+-- * Types+  InputEvent(..)+, byteLength+) where+++import Data.Binary (Binary(..), encode)+import Data.Binary.Get (getWordhost, getWord16host, getWord32host)+import Data.Binary.Put (putWordhost, putWord16host, putWord32host)+import Data.Word (Word16, Word32)++import qualified Data.ByteString.Lazy as BS (length)++-- | Input events from Linux /dev/input streams.  See \<<https://github.com/torvalds/linux/blob/master/include/uapi/linux/input.h>\> for details.+data InputEvent =+  InputEvent+  {+    timeval :: (Word, Word) -- ^ The time stamp in seconds and microseconds.+  , typ     :: Word16       -- ^ The event type.+  , code    :: Word16       -- ^ The event code.+  , value   :: Word32       -- ^ The event value.+  }+  deriving (Eq, Ord, Read, Show)++instance Binary InputEvent where+  get =+    do+      timeval <- (,) <$> getWordhost <*> getWordhost+      typ     <- getWord16host+      code    <- getWord16host+      value   <- getWord32host+      return InputEvent{..}+  put InputEvent{..} =+    do+      putWordhost $ fst timeval+      putWordhost $ snd timeval+      putWord16host typ+      putWord16host code+      putWord32host value+++-- | The number of bytes in an input event.+byteLength :: Integral a => a+byteLength =+  fromIntegral+    . BS.length+    . encode+    $ InputEvent (0, 0) 0 0 0
+ src/System/Hardware/Linux/SpaceNav.hs view
@@ -0,0 +1,112 @@+{-|+Module      :  System.Hardware.Linux.SpaceNav+Copyright   :  (c) 2016 Brian W Bush+License     :  MIT+Maintainer  :  Brian W Bush <consult@brianwbush.info>+Stability   :  Experimental+Portability :  Linux++Interpret events from a SpaceNavigator \<<http://www.3dconnexion.com/products/spacemouse/spacenavigator.html>\>.+-}+++{-# LANGUAGE DeriveGeneric   #-}+{-# LANGUAGE RecordWildCards #-}+++module System.Hardware.Linux.SpaceNav (+-- * Types and sizes+  SpaceNav(..)+, byteLength+-- * Event handling+, interpretSpaceNav+, readSpaceNav+) where+++import Data.Aeson.Types (FromJSON, ToJSON)+import Data.Binary (Binary(..), decode)+import Data.Bits ((.&.), complement, shift)+import Data.ByteString.Lazy.Char8 as BS (ByteString, readFile, splitAt)+import Data.Serialize (Serialize)+import Data.Word (Word32)+import GHC.Generics (Generic)+import System.Hardware.Linux.Input (InputEvent(..), byteLength)+++-- | SpaceNavigator data.+data SpaceNav =+    SpaceNavButton+    {+      timestamp :: Integer -- ^ The event timestamp, in POSIX picoseconds.+    , number    :: Int     -- ^ The button number.+    , pressed   :: Bool    -- ^ Whether the button is depressed.+    }+  | SpaceNavAnalog+    {+      timestamp :: Integer -- ^ The event timestamp, in POSIX picoseconds.+    , number    :: Int     -- ^ The axis number.+    , setting   :: Double  -- ^ The data value.+    }+  | SpaceNavNull+    deriving (Eq, Generic, Ord, Read, Show)++instance FromJSON SpaceNav++instance ToJSON SpaceNav++instance Binary SpaceNav++instance Serialize SpaceNav+++-- | Interpret SpaceNavigator event bytes on a Linux input deviceThis interpretation is based on \<<https://github.com/vrpn/vrpn/blob/master/vrpn_3DConnexion.h>\> and \<<https://github.com/vrpn/vrpn/blob/master/vrpn_3DConnexion.c>\>.+interpretSpaceNav :: ByteString -- ^ The bytes from /dev/input.+                  -> SpaceNav   -- ^ The corresponding SpaceNavigator data.+interpretSpaceNav x =+  let+    InputEvent{..} = decode x+    (seconds, microseconds) = timeval+    seconds' = fromIntegral seconds :: Integer+    microseconds' = fromIntegral microseconds :: Integer+    timestamp = (10^(6 :: Int) * seconds' + microseconds') * 10^(6 :: Int)+  in+    case typ of+      0x01 -> let+               number = fromIntegral $ code .&. 0x00ff+               pressed = value /= 0+             in+               SpaceNavButton{..}+      0x02 -> let+                number = fromIntegral code+                setting = fromIntegral (twosComplement value) / 400+              in+                SpaceNavAnalog{..}+      _    -> SpaceNavNull+++-- | Decode a two's complement.+twosComplement :: Word32 -- ^ The two's complement.+               -> Int    -- ^ The corresponding integer.+twosComplement x =+  fromIntegral (x' .&. complement mask) - fromIntegral (x' .&. mask)+    where+      x' = fromIntegral x :: Int+      mask = 1 `shift` 31+++-- | Read a stream of SpaceNavigator data.+readSpaceNav :: FilePath      -- ^ The SpaceNavigator device, e.g., "\/dev\/input\/spacenav0".+             -> IO [SpaceNav] -- ^ Action to read the SpaceNavigator data.+readSpaceNav path =+  let+    chunks :: ByteString -> [ByteString]+    chunks x =+      let+        (y, ys) = BS.splitAt 8 x+      in+        y : chunks ys+  in+    map interpretSpaceNav+      . chunks +      <$> BS.readFile path