packages feed

hemokit 0.6.0 → 0.6.1

raw patch · 9 files changed

+50/−40 lines, 9 filesdep +hspecdep +textdep ~cipher-aesdep ~optparse-applicative

Dependencies added: hspec, text

Dependency ranges changed: cipher-aes, optparse-applicative

Files

README.md view
@@ -34,7 +34,7 @@ hemokit-dump - Examples ----------------------- -*hemokit-dump* can print EEG data, format it as JSON, serve it via Websockets, and read from real devices and dump files.+*hemokit-dump* can print EEG data, format it as JSON, serve it via TCP or Websockets, and read from real devices and dump files.   * Output EEG *cumulative state* for an automatically found device:@@ -52,17 +52,22 @@ * Output only the data the device sends (no cumulative state), and format the output as JSON:    ```bash-  sudo hemokit-dump --mode packets --json+  sudo hemokit-dump --mode packets --format json   ``` -* Instead of from a real device, read data recorded to a file, and serve it via JSON over a Websockets server on port `1234`:+  The `--format` flag allows you to change the way the output is printed.+  The output of `--mode state --format spaced` is especially easy to work with. +* Instead of from a real device, read data recorded to a file, and serve it via JSON over a TCP server on port `1234`:+   ```bash   sudo cat /dev/hidraw1 > encrypted.dump  # Dump data to a file-  sudo hemokit-dump --from-file encrypted.dump --serial SN...GM --serve 0.0.0.0:1234 --json+  sudo hemokit-dump --from-file encrypted.dump --serial SN...GM --serve 0.0.0.0:1234 --format json   ```    Here you **have** to specify the serial since HIDAPI is not used to obtain it automatically.+  +  If you prefer a Websockets server over a raw TCP server, use `ws://0.0.0.0:1234` instead.  * Output decrypted raw data to stdout: @@ -73,7 +78,7 @@ * Both print the data from the EEG **and** store the original data for later use:    ```bash-  sudo cat /dev/hidraw1 | tee >(hemokit-dump --from-file - --serial SN...GM --json) > encrypted.dump+  sudo cat /dev/hidraw1 | tee >(hemokit-dump --from-file - --serial SN...GM --format json) > encrypted.dump   ```    We use `tee` and shell process substitution to duplicate the data stream, and tell *hemokit-dump* to read from `-` (stdin).
apps/Dump.hs view
@@ -10,8 +10,6 @@ import qualified Data.ByteString.Lazy.Char8 as BSL8 import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Builder as Builder-import qualified Data.ByteString.Lazy.Builder.ASCII as Builder-import qualified Data.ByteString.Base64 as Base64 import           Data.Function (fix) import           Data.IORef import           Data.List@@ -27,7 +25,7 @@ import           Hemokit import           Hemokit.Start -import           Hemokit.Internal.Utils (withJustM)+import           Hemokit.Internal.Utils (withJustM, textBase64) import           SocketUtils (makeTCPServer) import           WebsocketUtils (makeWSServer) @@ -79,9 +77,6 @@         <> help ("Serve output via a TCP server, e.g. 127.0.0.1:1234 " ++                  "(port 1234, only localhost) or 0.0.0.0:1234 (all interfaces). " ++                  "Use 'ws://' before the host to serve via websockets") )-  where-    -- TODO https://github.com/pcapriotti/optparse-applicative/issues/48-    eitherReader str2either = reader (either fail return . str2either)   -- | `DumpMode` command line parser.@@ -226,7 +221,7 @@ instance ToJSON EmotivState  instance ToJSON EmotivRawData where-  toJSON = toJSON . Base64.encode . emotivRawDataBytes+  toJSON = toJSON . textBase64 . emotivRawDataBytes  instance ToJSON Sensor where   toJSON = toJSON . show
apps/DumpConduit.hs view
@@ -11,8 +11,6 @@ import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Char8 as BSL8 import qualified Data.ByteString.Lazy.Builder as Builder-import qualified Data.ByteString.Lazy.Builder.ASCII as Builder-import qualified Data.ByteString.Base64 as Base64 import           Data.Conduit import qualified Data.Conduit.List as CL import           Data.Function (fix)@@ -30,6 +28,7 @@ import           Hemokit import           Hemokit.Conduit import           Hemokit.Start+import           Hemokit.Internal.Utils (textBase64)   -- | Arguments for the EEG dump application.@@ -79,9 +78,6 @@         <> help ("Serve output via a TCP server, e.g. 127.0.0.1:1234 " ++                  "(port 1234, only localhost) or 0.0.0.0:1234 (all interfaces). " ++                  "Use 'ws://' before the host to serve via websockets") )-  where-    -- TODO https://github.com/pcapriotti/optparse-applicative/issues/48-    eitherReader str2either = reader (either fail return . str2either)   -- | `DumpMode` command line parser.@@ -233,7 +229,7 @@ instance ToJSON EmotivState  instance ToJSON EmotivRawData where-  toJSON = toJSON . Base64.encode . emotivRawDataBytes+  toJSON = toJSON . textBase64 . emotivRawDataBytes  instance ToJSON Sensor where   toJSON = toJSON . show
apps/Mouse.hs view
@@ -23,8 +23,8 @@    putStrLn $ "AvailableDevices:\n" ++ ppShow devices -  device <- openEmotivDevice model $ case devices of d:_ -> d-                                                     []  -> error "no Epoc devices found"+  device <- openEmotivDevice model $ case reverse devices of d:_ -> d+                                                             []  -> error "no Epoc devices found"    m'xConnection <- connect   xy <- newIORef (0,0)
hemokit.cabal view
@@ -1,5 +1,5 @@ name:          hemokit-version:       0.6.0+version:       0.6.1 license:       MIT copyright:     2013 Niklas Hambüchen <mail@nh2.me>, Patrick Chilton <chpatrick@gmail.com> author:        Niklas Hambüchen <mail@nh2.me>, Patrick Chilton <chpatrick@gmail.com>@@ -7,7 +7,7 @@ category:      Bioinformatics build-type:    Simple stability:     experimental-tested-with:   GHC==7.6.2+tested-with:   GHC==7.6.3, GHC==7.8.1 cabal-version: >= 1.10 homepage:      https://github.com/nh2/haskell-hemokit bug-reports:   https://github.com/nh2/haskell-hemokit/issues@@ -63,15 +63,17 @@   build-depends:       base                   >= 4 && < 5     , aeson                  >= 0.6.1.0+    , base64-bytestring      >= 1.0.0.1     , bytestring             >= 0.9.2.1-    , cipher-aes             >= 0.1.7+    , cipher-aes             >= 0.2.0     , conduit                >= 1     , deepseq                >= 1.2     , deepseq-generics       >= 0.1     , hidapi                 >= 0.1.2     , mtl                    >= 2.1.2     , network-simple         >= 0.3.0-    , optparse-applicative   >= 0.5.2.1+    , optparse-applicative   >= 0.7.0+    , text                   >= 0.11.1.1     , vector                 >= 0.9     , websockets             >= 0.8.0.0   hs-source-dirs:@@ -111,10 +113,9 @@       base     , hemokit     , aeson                  >= 0.6.1.0-    , base64-bytestring      >= 1.0.0.1     , bytestring             >= 0.9.2.1     , network-simple         >= 0.3.0-    , optparse-applicative   >= 0.5.2.1+    , optparse-applicative   >= 0.7.0     , pretty-show            >= 1.0     , split                  >= 0.2.2     , time                   >= 1.4@@ -134,11 +135,10 @@       base     , hemokit     , aeson                  >= 0.6.1.0-    , base64-bytestring      >= 1.0.0.1     , bytestring             >= 0.9.2.1     , conduit                >= 1     , network-simple         >= 0.3.0-    , optparse-applicative   >= 0.5.2.1+    , optparse-applicative   >= 0.7.0     , pretty-show            >= 1.0     , split                  >= 0.2.2     , time                   >= 1.4@@ -199,6 +199,7 @@       base     , hemokit     , bytestring             >= 0.9.2.1+    , hspec                  >= 1.8.3     , HUnit                  >= 1.2     , vector                 >= 0.9   ghc-options: -Wall
src/Hemokit.hs view
@@ -112,7 +112,7 @@     sn x | x >= 0    = index num x          | otherwise = sn (BS.length num + x)     c = fromIntegral . ord-    key = initKey . BS.pack $ start ++ middle ++ end+    key = initAES . BS.pack $ start ++ middle ++ end      start =        [ sn (-1), 0, sn (-2)]     middle = case typ of
src/Hemokit/Internal/Utils.hs view
@@ -1,9 +1,15 @@ module Hemokit.Internal.Utils   ( withJustM   , untilNothing+  , textBase64   ) where +import qualified Data.ByteString as BS+import qualified Data.ByteString.Base64 as Base64+import           Data.Text (Text)+import qualified Data.Text.Encoding as T + -- | If the monad retuns a Just, runs the function on its contents. -- Returns True if the action was executed. withJustM :: (Monad m) => m (Maybe a) -> (a -> m ()) -> m Bool@@ -16,3 +22,12 @@ untilNothing act f = act `withJustM` (\x -> f x >> again)   where     again = untilNothing act f >> return () -- void would be nicer+++-- | Base64-encodes a ByteString as Text.+--+-- This cannot fail since Base64 is ASCII.+textBase64 :: BS.ByteString -> Text+textBase64 bs = case T.decodeUtf8' (Base64.encode bs) of+  Left ex -> error $ "textBase64: BUG: base64 encoding cannot be encoded: " ++ show ex -- this cannot happen+  Right t -> t
src/Hemokit/Start.hs view
@@ -12,7 +12,6 @@   , getEmotivDeviceFromArgs   ) where -import           Data.List import           Options.Applicative import           System.IO (stdin) @@ -81,12 +80,12 @@         [] -> fail "No devices found."         _  -> case serial of -          -- Pick the device with the serial the user wants-          Just s -> case find ((Just s ==) . deviceInfoSerial) devices of-                      Nothing -> fail $ "No device with serial " ++ show s-                      Just d  -> Right <$> openEmotivDevice model d+          -- Pick the last device with the serial the user wants+          Just s -> case reverse [ d | d <- devices, deviceInfoSerial d == Just s ] of+                      []  -> fail $ "No device with serial " ++ show s+                      d:_ -> print d >> Right <$> openEmotivDevice model d            -- TODO Do smarter auto detection, e.g. filter for Emotiv vendorIDs           --      or the "EPOC BCI" product string.           -- The user selected no serial, we just use the last device-          _      -> Right <$> openEmotivDevice model (last devices)+          _      -> print (last devices) >> Right <$> openEmotivDevice model (last devices)
test/Tests.hs view
@@ -31,10 +31,9 @@      let encrypted = "S\a\205\165\195\182\244\DC4\NAKo\255K\\\247\146>tB\144q\165-\192\221\CANSa\150V,@\180"         decrypted = decrypt _SERIAL Consumer encrypted-        decrypted_expected = "P}::\199\183\221\193|!\250h\205\NUL\NUL\NUL\STX\ENQX\r\162E|\218)\ETB\155\US\224gi9"+        rawData_expected = makeEmotivRawData "P}::\199\183\221\193|!\250h\205\NUL\NUL\NUL\STX\ENQX\r\162E|\218)\ETB\155\US\224gi9"         packet_expected = EmotivPacket-          { packetRawData = makeEmotivRawData decrypted_expected-          , packetCounter = 80+          { packetCounter = 80           , packetBattery = Nothing           , packetGyroX   = -1           , packetGyroY   = 8@@ -42,5 +41,5 @@           , packetQuality = Just (FC6, 0)           } -    it "decrypts a valid packet" $ emotivRawDataBytes decrypted @?= decrypted_expected-    it "parses a valid packet"   $ parsePacket decrypted        @?= packet_expected+    it "decrypts a valid packet" $ decrypted             @?= rawData_expected+    it "parses a valid packet"   $ parsePacket decrypted @?= packet_expected