module Monky.Examples.Wifi.Poll
( WifiFormat (..)
, WifiPollHandle
, Direction(..)
, getWifiHandle
, getWifiHandle'
, guessWifiHandle
, guessWifiHandle'
)
where
import Data.Int (Int8)
import Data.Maybe (fromMaybe)
import Data.Word (Word8)
import Formatting
import Monky.Examples.Utility
import qualified Monky.Examples.Wifi.Event as E
import Monky.Modules
import Monky.Wifi
import System.Linux.Netlink.GeNetlink.NL80211
import System.Linux.Netlink.GeNetlink.NL80211.StaInfo
import Data.Text (Text)
import qualified Data.Text as T
import Control.Applicative ((<|>), (<$>), (<*>), pure)
data WifiPollHandle = WH SSIDSocket Interface ((WifiStats, Maybe NL80211Packet) -> Text) Text
data Direction
= DirTX
| DirRX
deriving (Show, Eq)
data WifiFormat
= FormatMCS Direction
| FormatMCSMin
| FormatWifiWidth
| FormatBitrate Direction
| FormatBitrateMin
| FormatSignal
| FormatSignalAverage
| FormatChannel
| FormatName
| FormatFreq
| FormatText Text
deriving (Show, Eq)
doMBM :: Int8 -> Word8
doMBM e =
let noiseFloor = 90
signalMax = 20
clamped = min signalMax $ max noiseFloor $ e
in fromIntegral $ 100 (signalMax clamped)
getFromDir :: Direction -> StaInfo -> Maybe StaRate
getFromDir DirTX = staTXRate
getFromDir DirRX = staRXRate
pollToEvt :: WifiFormat -> E.WifiFormat
pollToEvt FormatChannel = E.FormatChannel
pollToEvt FormatName = E.FormatName
pollToEvt FormatFreq = E.FormatFreq
pollToEvt (FormatText t) = E.FormatText t
pollToEvt x = error $ "Tried to convert " ++ show x ++ "to Evt? This really shouldn't ever happen"
getExtFun :: WifiFormat -> (WifiStats, StaInfo) -> Text
getExtFun (FormatMCS dir) (_, info) =
case getFromDir dir info of
Nothing -> "No Rate"
Just x -> case rateMCS x <|> rateVHTMCS x of
Nothing -> "No MCS"
Just y -> sformat int y
getExtFun FormatMCSMin (_, info) = fromMaybe "No Rate" $ do
rx <- staRXRate info
tx <- staTXRate info
rmcs <- getMCS rx
tmcs <- getMCS tx
pure . sformat int $ min rmcs tmcs
where getMCS x = rateMCS x <|> rateVHTMCS x
getExtFun FormatWifiWidth (_, info) =
case staTXRate info of
Nothing -> "No Rate"
Just x -> case rateWidthFlag x of
Width5MHz -> "5MHz"
Width10MHz -> "10MHz"
Width20MHz -> "20MHz"
Width40MHz -> "40MHz"
Width80MHz -> "80MHz"
Width160MHz -> "160MHz"
getExtFun (FormatBitrate dir) (_, info) =
case getFromDir dir info of
Nothing -> "No Rate"
Just x -> maybe
"No Bitrate"
(flip convertUnitSI "b" . (* 1e5))
(rateBitrate x)
getExtFun FormatBitrateMin (_, info) =
let tx = rateBitrate =<< staTXRate info
rx = rateBitrate =<< staRXRate info
in case min <$> rx <*> tx of
Nothing -> "No rates"
Just x -> convertUnitSI (x * 1e5) "b"
getExtFun FormatSignal (_, info) =
case staSignalMBM info of
Nothing -> "No strength"
Just x -> sformat int . doMBM $ fromIntegral x
getExtFun FormatSignalAverage (_, info) =
case staSignalMBMA info of
Nothing -> "No strength"
Just x -> sformat int . doMBM $ fromIntegral x
getExtFun x (stats, _) = E.getTextify (pollToEvt x) stats
getExtFunction :: [WifiFormat] -> (WifiStats, StaInfo) -> Text
getExtFunction xs = T.concat . (sequence . map getExtFun $ xs)
getCombiFun :: [WifiFormat] -> ((WifiStats, Maybe NL80211Packet) -> Text)
getCombiFun xs (stat, ext) =
let fun = getExtFunction xs
info = staInfoFromPacket =<< ext
in case info of
Just x -> fun (stat, x)
Nothing -> "Couldn't get wifi station info"
instance PollModule WifiPollHandle where
getOutput (WH s i f d) = do
ret <- getCurrentWifiStats s i
case ret of
Nothing -> pure . pure $ MonkyPlain d
Just x -> do
ext <- getExtendedWifi s i x
pure . pure . MonkyPlain $ f (x, ext)
getWifiHandle'
:: ((WifiStats, Maybe NL80211Packet) -> Text)
-> Text
-> String
-> IO WifiPollHandle
getWifiHandle' f d n = do
s <- getSSIDSocket
i <- fromMaybe (error ("Could not find interface: " ++ n)) <$> getInterface s n
return (WH s i f d)
getWifiHandle
:: [WifiFormat]
-> Text
-> String
-> IO WifiPollHandle
getWifiHandle f d n =
getWifiHandle' (getCombiFun f) d n
guessWifiHandle'
:: ((WifiStats, Maybe NL80211Packet) -> Text)
-> Text
-> IO WifiPollHandle
guessWifiHandle' f d = do
s <- getSSIDSocket
i <- fromMaybe (error "Couldn't find any NL80211 interface") <$> guessInterface s
return (WH s i f d)
guessWifiHandle
:: [WifiFormat]
-> Text
-> IO WifiPollHandle
guessWifiHandle f d =
guessWifiHandle' (getCombiFun f) d