summaryrefslogtreecommitdiffhomepage
path: root/IWlib.hsc
blob: 6d8b50764a72d5599eeda087b67de93f4e802670 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
-----------------------------------------------------------------------------
-- |
-- Module      :  IWlib
-- Copyright   :  (c) Jose A Ortega Ruiz
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
--  A partial binding to iwlib
--
-----------------------------------------------------------------------------

{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}


module IWlib (WirelessInfo(..), getWirelessInfo) where

import Foreign
import Foreign.C.Types
import Foreign.C.String

data WirelessInfo = WirelessInfo { wiEssid :: String,  wiQuality :: Int }
                  deriving Show

#include <iwlib.h>

data WCfg
data WStats
data WRange

foreign import ccall "iwlib.h iw_sockets_open"
  c_iw_open :: IO CInt

foreign import ccall "unistd.h close"
  c_iw_close :: CInt -> IO ()

foreign import ccall "iwlib.h iw_get_basic_config"
  c_iw_basic_config :: CInt -> CString -> Ptr WCfg -> IO CInt

foreign import ccall "iwlib.h iw_get_stats"
  c_iw_stats :: CInt -> CString -> Ptr WStats -> Ptr WRange -> CInt -> IO CInt

foreign import ccall "iwlib.h iw_get_range_info"
  c_iw_range :: CInt -> CString -> Ptr WRange -> IO CInt

getWirelessInfo :: String -> IO WirelessInfo
getWirelessInfo iface =
  allocaBytes (#size struct wireless_config) $ \wc ->
  allocaBytes (#size struct iw_statistics) $ \stats ->
  allocaBytes (#size struct iw_range) $ \rng ->
  withCString iface $ \istr -> do
    i <- c_iw_open
    bcr <- c_iw_basic_config i istr wc
    str <- c_iw_stats i istr stats rng 1
    rgr <- c_iw_range i istr rng
    c_iw_close i
    if (bcr < 0) then return nullInfo else
      do hase <- (#peek struct wireless_config, has_essid) wc :: IO CInt
         eon <- (#peek struct wireless_config, essid_on) wc :: IO CInt
         essid <- if hase /= 0 && eon /= 0 then
                    do l <- (#peek struct wireless_config, essid_len) wc
                       let e = (#ptr struct wireless_config, essid) wc
                       peekCStringLen (e, fromIntegral (l :: CInt))
                  else return ""
         q <- if str >= 0 && rgr >=0 then
                do qualv <- xqual $ (#ptr struct iw_statistics, qual) stats
                   mv <- xqual $ (#ptr struct iw_range, max_qual) rng
                   let mxv = if mv /= 0 then fromIntegral mv else 1
                   return $ fromIntegral qualv / mxv
              else return (-1)
         let qv = round (100 * (q :: Double))
         return $ WirelessInfo { wiEssid = essid, wiQuality = min 100 qv }
    where nullInfo = WirelessInfo { wiEssid = "", wiQuality = -1 }
          xqual p = let qp = (#ptr struct iw_param, value) p in
            (#peek struct iw_quality, qual) qp :: IO CChar