diff options
-rw-r--r-- | changelog.md | 2 | ||||
-rw-r--r-- | readme.md | 31 | ||||
-rw-r--r-- | src/Xmobar/Plugins/Monitors.hs | 8 | ||||
-rw-r--r-- | src/Xmobar/Plugins/Monitors/Wireless.hs | 73 | ||||
-rw-r--r-- | xmobar.cabal | 14 |
5 files changed, 106 insertions, 22 deletions
diff --git a/changelog.md b/changelog.md index a52fce3..93fa31e 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,8 @@ _New features_ - New more efficient time coalescing strategy for monitor updates, available with the threaded runtime: use the `with_threaded` flag to enable it (see #410; thanks to Tomáš Janoušek). + - `Wireless` supports current nl80211 API on Linux now, old Wext ioctls still + available as compile-time option (thanks to Paul Fertser). ## Version 0.32 (December, 2019) @@ -117,11 +117,15 @@ Otherwise, you'll need to install them yourself. option is needed for the MBox and Mail plugins to work. Requires the [hinotify] package. -- `with_iwlib` Support for wireless cards. Enables the Wireless - plugin. No Haskell library is required, but you will need the - [iwlib] C library and headers in your system (e.g., install - `libiw-dev` in Debian-based systems or `wireless_tools` on Arch - Linux). +- `with_nl80211` Support for wireless cards on Linux via nl80211 (all + upstream drivers). Enables the Wireless plugin. Requires [netlink] + and [cereal] packages. + +- `with_iwlib` Support for wireless cards via Wext ioctls + (deprecated). Enables the Wireless plugin. No Haskell library is + required, but you will need the [iwlib] C library and headers in your + system (e.g., install `libiw-dev` in Debian-based systems or + `wireless_tools` on Arch Linux). Conflicts with `with_nl80211`. - `with_alsa` Support for ALSA sound cards. Enables the Volume plugin. Requires the [alsa-mixer] package. To install the latter, @@ -820,18 +824,21 @@ specification, such as `("clear", "<icon=weather-clear.xbm/>")`. ### `Wireless Interface Args RefreshRate` -- If set to "", the interface is looked up in /proc/net/wireless. +- If set to "", first suitable wireless interface is used. - Aliases to the interface name with the suffix "wi": thus, `Wireless "wlan0" []` can be used as `%wlan0wi%`, and `Wireless "" []` as `%wi%`. - Args: default monitor arguments, plus: - `--quality-icon-pattern`: dynamic string for connection quality in `qualityipat`. - Variables that can be used with the `-t`/`--template` argument: - `essid`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat` -- Thresholds refer to link quality in a `[0, 100]` scale -- Default template: `<essid> <quality>` -- Requires the C library [iwlib] (part of the wireless tools suite) - installed in your system. In addition, to activate this plugin you - must pass `--flags="with_iwlib"` during compilation + `ssid`, `signal`, `quality`, `qualitybar`, `qualityvbar`, `qualityipat` +- Thresholds refer to link quality on a `[0, 100]` scale. Note that + `quality` is calculated from `signal` (in dBm) by a possibly lossy + conversion. It is also not taking into account many factors such as + noise level, air busy time, transcievers' capabilities and the + others which can have drastic impact on the link performance. +- Default template: `<ssid> <quality>` +- To activate this plugin you must pass `--flags="with_nl80211"` or + `--flags="with_iwlib"` during compilation ### `Memory Args RefreshRate` diff --git a/src/Xmobar/Plugins/Monitors.hs b/src/Xmobar/Plugins/Monitors.hs index d6fc0a0..322d401 100644 --- a/src/Xmobar/Plugins/Monitors.hs +++ b/src/Xmobar/Plugins/Monitors.hs @@ -42,7 +42,7 @@ import Xmobar.Plugins.Monitors.CatInt #ifdef UVMETER import Xmobar.Plugins.Monitors.UVMeter #endif -#ifdef IWLIB +#if defined IWLIB || defined USE_NL80211 import Xmobar.Plugins.Monitors.Wireless #endif #ifdef LIBMPD @@ -85,7 +85,7 @@ data Monitors = Network Interface Args Rate #ifdef UVMETER | UVMeter Station Args Rate #endif -#ifdef IWLIB +#if defined IWLIB || defined USE_NL80211 | Wireless Interface Args Rate #endif #ifdef LIBMPD @@ -142,7 +142,7 @@ instance Exec Monitors where #ifdef UVMETER alias (UVMeter s _ _) = "uv " ++ s #endif -#ifdef IWLIB +#if defined IWLIB || defined USE_NL80211 alias (Wireless i _ _) = i ++ "wi" #endif #ifdef LIBMPD @@ -186,7 +186,7 @@ instance Exec Monitors where #ifdef UVMETER start (UVMeter s a r) = startUVMeter s a r #endif -#ifdef IWLIB +#if defined IWLIB || defined USE_NL80211 start (Wireless i a r) = runM a wirelessConfig (runWireless i) r #endif #ifdef LIBMPD diff --git a/src/Xmobar/Plugins/Monitors/Wireless.hs b/src/Xmobar/Plugins/Monitors/Wireless.hs index f2b1e6a..28aba50 100644 --- a/src/Xmobar/Plugins/Monitors/Wireless.hs +++ b/src/Xmobar/Plugins/Monitors/Wireless.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE TypeApplications, CPP #-} ----------------------------------------------------------------------------- -- | -- Module : Plugins.Monitors.Wireless @@ -8,16 +9,68 @@ -- Stability : unstable -- Portability : unportable -- --- A monitor reporting ESSID and link quality for wireless interfaces +-- A monitor reporting SSID and signal level for wireless interfaces -- ----------------------------------------------------------------------------- module Xmobar.Plugins.Monitors.Wireless (wirelessConfig, runWireless) where import System.Console.GetOpt +import Data.Maybe (fromMaybe) import Xmobar.Plugins.Monitors.Common + +#ifdef IWLIB import Network.IWlib +#elif defined USE_NL80211 +import Control.Exception (bracket) +import qualified Data.Map as M +import GHC.Int (Int8) +import Data.Maybe (listToMaybe) +import Control.Monad.IO.Class (liftIO) +import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT) +import Data.ByteString.Char8 (unpack) +import Data.Serialize.Put (runPut, putWord32host, putByteString) +import Data.Serialize.Get (runGet) + +import System.Linux.Netlink hiding (query) +import System.Linux.Netlink.GeNetlink.NL80211 +import System.Linux.Netlink.GeNetlink.NL80211.StaInfo +import System.Linux.Netlink.GeNetlink.NL80211.Constants +import System.Posix.IO (closeFd) + +data IwData = IwData { wiEssid :: String, wiSignal :: Maybe Int, wiQuality :: Int } + +getWirelessInfo :: String -> IO IwData +getWirelessInfo ifname = do + bracket makeNL80211Socket (closeFd . getFd) (\s -> do + iflist <- getInterfaceList s + iwdata <- runMaybeT $ do + ifidx <- MaybeT . return $ foldr (\(n, i) z -> + if (ifname == "" || ifname == n) then Just i else z) + Nothing + iflist + scanp <- liftIO (getConnectedWifi s ifidx) >>= + MaybeT . return . listToMaybe + bssid <- MaybeT . return $ M.lookup eNL80211_ATTR_BSS (packetAttributes scanp) >>= + rightToMaybe . runGet getAttributes >>= + M.lookup eNL80211_BSS_BSSID + stap <- liftIO (query s eNL80211_CMD_GET_STATION True $ M.fromList + [(eNL80211_ATTR_IFINDEX, runPut $ putWord32host ifidx), + (eNL80211_ATTR_MAC, runPut $ putByteString bssid)]) >>= + MaybeT . return . listToMaybe + let ssid = fromMaybe "" $ getWifiAttributes scanp >>= M.lookup eWLAN_EID_SSID >>= + return . unpack + signal = staInfoFromPacket stap >>= staSignalMBM >>= + return . fromIntegral @Int8 . fromIntegral + qlty = fromMaybe (-1) (round @Float . (/ 0.7) . (+ 110) . + clamp (-110) (-40) . fromIntegral <$> signal) + MaybeT . return $ Just $ IwData ssid signal qlty + return $ fromMaybe (IwData "" Nothing (-1)) iwdata) + where + rightToMaybe = either (const Nothing) Just + clamp lb up v = if v < lb then lb else if v > up then up else v +#endif newtype WirelessOpts = WirelessOpts { qualityIconPattern :: Maybe IconPattern @@ -36,29 +89,41 @@ options = wirelessConfig :: IO MConfig wirelessConfig = - mkMConfig "<essid> <quality>" - ["essid", "quality", "qualitybar", "qualityvbar", "qualityipat"] + mkMConfig "<ssid> <quality>" + ["ssid", "essid", "signal", "quality", "qualitybar", "qualityvbar", "qualityipat"] runWireless :: String -> [String] -> Monitor String runWireless iface args = do opts <- io $ parseOptsWith options defaultOpts args +#ifdef IWLIB iface' <- if "" == iface then io findInterface else return iface +#else + let iface' = iface +#endif wi <- io $ getWirelessInfo iface' na <- getConfigValue naString let essid = wiEssid wi qlty = fromIntegral $ wiQuality wi e = if essid == "" then na else essid ep <- showWithPadding e +#ifdef USE_NL80211 + let s = wiSignal wi +#else + let s = if qlty >= 0 then Just (qlty * 0.7 - 110) else Nothing +#endif + sp <- showWithPadding $ fromMaybe "" (show <$> s) q <- if qlty >= 0 then showPercentWithColors (qlty / 100) else showWithPadding "" qb <- showPercentBar qlty (qlty / 100) qvb <- showVerticalBar qlty (qlty / 100) qipat <- showIconPattern (qualityIconPattern opts) (qlty / 100) - parseTemplate [ep, q, qb, qvb, qipat] + parseTemplate [ep, ep, sp, q, qb, qvb, qipat] +#ifdef IWLIB findInterface :: IO String findInterface = do c <- readFile "/proc/net/wireless" let nds = lines c return $ if length nds > 2 then takeWhile (/= 'c') (nds!!2) else [] +#endif diff --git a/xmobar.cabal b/xmobar.cabal index f23275f..b29b987 100644 --- a/xmobar.cabal +++ b/xmobar.cabal @@ -40,7 +40,11 @@ flag with_inotify default: False flag with_iwlib - description: Wireless info support. Required for the Wireless plugin, needs iwlib installed. + description: Wireless info support via Wext ioctls (deprecated). Required for the Wireless plugin, needs iwlib installed. + default: False + +flag with_nl80211 + description: Wireless info support via nl80211. Required for the Wireless plugin on systems running Linux, the kernel. default: False flag with_mpd @@ -209,12 +213,18 @@ library exposed-modules: Xmobar.Plugins.Mail, Xmobar.Plugins.MBox cpp-options: -DINOTIFY - if flag(with_iwlib) || flag(all_extensions) + if flag(with_iwlib) extra-libraries: iw build-depends: iwlib >= 0.1.0 && < 0.2 exposed-modules: Xmobar.Plugins.Monitors.Wireless cpp-options: -DIWLIB + if flag(with_nl80211) || flag(all_extensions) + build-depends: netlink >= 1.1.1.0, + cereal >= 0.5.8.1 + exposed-modules: Xmobar.Plugins.Monitors.Wireless + cpp-options: -DUSE_NL80211 + if flag(with_mpd) || flag(all_extensions) build-depends: libmpd >= 0.9.0.10 exposed-modules: Xmobar.Plugins.Monitors.MPD |