hemokit-0.4.0: src/Hemokit/Start.hs
{-# LANGUAGE NamedFieldPuns #-}
-- | Some convenience for building applications that want to read Emotiv data.
--
-- You can use this if you are writing an EEG application and don't want to do
-- the whole device selection / opening yourself.
module Hemokit.Start
( EmotivArgs (..)
, emotivArgsParser
, parseModel
, getEmotivDeviceFromArgs
) where
import Data.List
import Options.Applicative
import Hemokit hiding (serial)
-- | Commonly used options for EEG command line applications.
-- Mainly deals with input selection.
data EmotivArgs = EmotivArgs
{ model :: EmotivModel -- ^ What model to use for decryption.
, serial :: Maybe SerialNumber -- ^ What serial to use for decryption.
-- Also allows to pick a certain device.
, fromFile :: Maybe FilePath -- ^ Use the given device or dump file for input.
-- If not given, HIDAPI is used.
} deriving (Eq, Show)
-- | EEG model command line parser.
parseModel :: Monad m => String -> m EmotivModel
parseModel s = case s of
"consumer" -> return Consumer
"developer" -> return Developer
_ -> fail "Model is not valid. Must be 'consumer' or 'developer'."
-- | Command line parser for EEG selection. See `EmotivArgs`.
emotivArgsParser :: Parser EmotivArgs
emotivArgsParser = EmotivArgs
<$> nullOption
( long "model" <> metavar "MODEL"
<> reader parseModel <> value Consumer
<> help "Consumer or Developer model, Consumer by default" )
<*> (optional . nullOption)
( long "serial" <> metavar "SERIALNUMBER"
<> maybeReader makeSerialNumberFromString "Serial number of has invalid format"
<> help "The serial to use. If no --from-file is given, this will select the device" )
<*> (optional . strOption)
( long "from-file" <> metavar "PATH"
<> help "The file path to read from (e.g. /dev/hidraw0 or myfile.dump)" )
where
maybeReader mbFn msg = reader $ maybe (fail msg) pure . mbFn
-- | Depending on some common EEG-choice-related user input, list devices or
-- try to open the correct device.
getEmotivDeviceFromArgs :: EmotivArgs -> IO (Either String EmotivDevice)
getEmotivDeviceFromArgs EmotivArgs{ model, serial, fromFile } = case fromFile of
-- File given, use device file / file handle
Just f | Just s <- serial -> Right <$> openEmotivDeviceFile model s f
| otherwise -> fail "A serial number must be provided when using --from-file"
-- No file given, use HIDAPI to select the device
Nothing -> do
devices <- getEmotivDevices
case devices of
[] -> 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
-- The user selected no serial, we just use the last device
_ -> Right <$> openEmotivDevice model (last devices)