1#!/usr/bin/env python
2#
3# rfkill control code
4#
5# Copyright (c) 2015	Intel Corporation
6#
7# Author: Johannes Berg <johannes.berg@intel.com>
8#
9# This software may be distributed under the terms of the BSD license.
10# See README for more details.
11
12import struct
13import fcntl
14import os
15
16(TYPE_ALL,
17 TYPE_WLAN,
18 TYPE_BLUETOOTH,
19 TYPE_UWB,
20 TYPE_WIMAX,
21 TYPE_WWAN,
22 TYPE_GPS,
23 TYPE_FM,
24 TYPE_NFC) = list(range(9))
25
26(_OP_ADD,
27 _OP_DEL,
28 _OP_CHANGE,
29 _OP_CHANGE_ALL) = list(range(4))
30
31_type_names = {
32    TYPE_ALL: "all",
33    TYPE_WLAN: "Wireless LAN",
34    TYPE_BLUETOOTH: "Bluetooth",
35    TYPE_UWB: "Ultra-Wideband",
36    TYPE_WIMAX: "WiMAX",
37    TYPE_WWAN: "Wireless WAN",
38    TYPE_GPS: "GPS",
39    TYPE_FM: "FM",
40    TYPE_NFC: "NFC",
41}
42
43# idx, type, op, soft, hard
44_event_struct = '@IBBBB'
45_event_sz = struct.calcsize(_event_struct)
46
47class RFKillException(Exception):
48    pass
49
50class RFKill(object):
51    def __init__(self, idx):
52        self._idx = idx
53        self._type = None
54
55    @property
56    def idx(self):
57        return self._idx
58
59    @property
60    def name(self):
61        return open('/sys/class/rfkill/rfkill%d/name' % self._idx, 'r').read().rstrip()
62
63    @property
64    def type(self):
65        if not self._type:
66            for r, s, h in RFKill.list():
67                if r.idx == self.idx:
68                    self._type = r._type
69                    break
70        return self._type
71
72    @property
73    def type_name(self):
74        return _type_names.get(self._type, "unknown")
75
76    @property
77    def blocked(self):
78        l = RFKill.list()
79        for r, s, h in l:
80            if r.idx == self.idx:
81                return (s, h)
82        raise RFKillException("RFKill instance no longer exists")
83
84    @property
85    def soft_blocked(self):
86        return self.blocked[0]
87
88    @soft_blocked.setter
89    def soft_blocked(self, block):
90        if block:
91            self.block()
92        else:
93            self.unblock()
94
95    @property
96    def hard_blocked(self):
97        return self.blocked[1]
98
99    def block(self):
100        rfk = open('/dev/rfkill', 'wb')
101        s = struct.pack(_event_struct, self.idx, TYPE_ALL, _OP_CHANGE, 1, 0)
102        rfk.write(s)
103        rfk.close()
104
105    def unblock(self):
106        rfk = open('/dev/rfkill', 'wb')
107        s = struct.pack(_event_struct, self.idx, TYPE_ALL, _OP_CHANGE, 0, 0)
108        rfk.write(s)
109        rfk.close()
110
111    @classmethod
112    def block_all(cls, t=TYPE_ALL):
113        rfk = open('/dev/rfkill', 'wb')
114        print(rfk)
115        s = struct.pack(_event_struct, 0, t, _OP_CHANGE_ALL, 1, 0)
116        rfk.write(s)
117        rfk.close()
118
119    @classmethod
120    def unblock_all(cls, t=TYPE_ALL):
121        rfk = open('/dev/rfkill', 'wb')
122        s = struct.pack(_event_struct, 0, t, _OP_CHANGE_ALL, 0, 0)
123        rfk.write(s)
124        rfk.close()
125
126    @classmethod
127    def list(cls):
128        res = []
129        rfk = open('/dev/rfkill', 'rb', buffering=0)
130        fd = rfk.fileno()
131        flgs = fcntl.fcntl(fd, fcntl.F_GETFL)
132        fcntl.fcntl(fd, fcntl.F_SETFL, flgs | os.O_NONBLOCK)
133        while True:
134            try:
135                d = rfk.read(_event_sz)
136                if d == None:
137                    break
138                _idx, _t, _op, _s, _h = struct.unpack(_event_struct, d)
139                if _op != _OP_ADD:
140                    continue
141                r = RFKill(_idx)
142                r._type = _t
143                res.append((r, _s, _h))
144            except IOError:
145                break
146        return res
147
148if __name__ == "__main__":
149    for r, s, h in RFKill.list():
150        print("%d: %s: %s" % (r.idx, r.name, r.type_name))
151        print("\tSoft blocked: %s" % ("yes" if s else "no"))
152        print("\tHard blocked: %s" % ("yes" if h else "no"))
153