]> git.neil.brown.name Git - freerunner.git/blob - gsm/atchan.py
gsmd: commit 'atchan.py' - missed that when committing gsmd.py
[freerunner.git] / gsm / atchan.py
1
2 #
3 # Handle a connection to an AT device via gsm0710muxd
4 # If this is a 'master', we can reset the modem, else
5 # any misbehaviour requires that we fail (FIXME not implemented)
6 #
7 # We directly support high level commands (get/set_power, reset_modem
8 # etc) but don't know anything about AT commands - we just send them
9 # through and hand back reply.  Replies also go via a callback
10 # We also provide timeout support, but someone else needs to tell us
11 # when to set a timeout, and when to clear it.
12 #
13 # This is usually subclassed by code with an agenda.
14
15 import gobject, sys, os, time
16 from trace import log
17 from socket import *
18
19 class AtChannel:
20     def __init__(self, path = '/var/run/gsm-mux', master = False):
21         self.master = False
22         self.path = path
23         self.connected = False
24         self.command_mode = False
25         self.watcher = None
26         self.sock = None
27         self.power = None
28         self.buf = ""
29         self.linelist = []
30
31         self.pending = False
32         self.timer = None
33
34     def disconnect(self):
35         if self.watcher:
36             gobject.source_remove(self.watcher)
37             self.watcher = None
38         if self.sock:
39             self.sock.close()
40             self.sock = None
41         self.connected = False
42
43     def connect(self):
44         log("connect to", self.path)
45         s = socket(AF_UNIX, SOCK_STREAM)
46         s.connect(self.path)
47         self.watcher = gobject.io_add_watch(s, gobject.IO_IN, self.readdata)
48         self.sock = s
49         self.connected = True
50         self.command_mode = True
51         self.command_pending = False
52
53     def command(self, str):
54         if not self.connected or not self.command_mode:
55             raise ValueError
56         log("send command", str)
57         if not self.command_pending:
58             self.command_pending = str
59         self.sock.sendall(str + '\n')
60         self.set_timeout(30000)
61
62     def readdata(self, io, arg):
63         r = self.sock.recv(1000)
64         r = self.buf + r
65         ra = r.split('\n')
66         self.buf = ra[-1];
67         del ra[-1]
68         for ln in ra:
69             ln = ln.strip('\r')
70             self.getline(ln)
71         return True
72
73     def getline(self, line):
74         if self.command_mode:
75             log("Receive cmd response", line, "to", self.command_pending)
76             if line == "OK" and self.command_pending == "connect":
77                 log("Leaving command mode")
78                 self.command_mode = False
79             if self.pending:
80                 self.pending = False
81                 gobject.source_remove(self.timer)
82                 self.timer = None
83             if self.command_pending:
84                 if line[0:2] == "OK" or line[0:5] == "ERROR":
85                     self.command_pending = False
86                     self.power_done(line)
87         else:
88             log("receive AT response", line)
89             if self.takeline(line):
90                 if self.pending:
91                     self.pending = False
92                     gobject.source_remove(self.timer)
93                     self.timer = None
94
95     def set_power(self, state):
96         if state and self.power == True:
97             return gobject.idle_add(self.power_done)
98         if not state and self.power == False:
99             return gobject.idle_add(self.power_done)
100         # OK, I need to do something
101         if self.connected and not self.command_mode:
102             self.disconnect()
103         if not self.connected:
104             self.connect()
105         self.command_pending = "power"
106         if state:
107             self.command("set_power 1")
108             self.power = True
109         else:
110             self.command("set_power 0")
111             self.power = False
112
113     def reset(self):
114         if self.connected and not self.command_mode:
115             self.disconnect()
116         if not self.connected:
117             self.connect()
118         self.command_pending = "reset"
119         self.command("reset_modem")
120         self.power = True
121
122     def atconnect(self):
123         if not self.connected:
124             self.connect()
125         if not self.command_mode:
126             return self.power_done()
127         self.command_pending = "connect"
128         self.command("connect")
129         
130
131     def atcmd(self, cmd, timeout = 2000):
132         """
133         Send the command, preceeded by 'AT' and set a timeout.
134         self.takeline() should return True when the command
135         has been responded to, otherwise we will call
136         self.timedout() after the time.
137         """
138         self.set_timeout(timeout)
139         log("send AT command", cmd, timeout)
140         self.sock.sendall('AT' + cmd + '\r')
141
142     def timer_fired(self):
143         log("Timer Fired")
144         self.pending = False
145         self.timer = None
146         self.timedout()
147         return False
148     
149     def set_timeout(self, delay):
150         if self.pending:
151             raise ValueError
152         self.timer = gobject.timeout_add(delay, self.timer_fired)
153         self.pending = True
154
155     def cancel_timeout(self):
156         if self.pending:
157             gobject.source_remove(self.timer)
158             self.pending = False
159             
160     def abort_timeout(self):
161         if self.pending:
162             self.cancel_timeout()
163             self.set_timeout(0)
164
165     # these are likely to be over-ridden by a child class
166     def power_done(self, line=None):
167         self.linelist.append(line)
168     def takeline(self, line):
169         self.linelist.append(line)
170
171     def wait_line(self, timeout):
172         self.cancel_timeout()
173         c = gobject.main_context_default()
174         while not self.linelist:
175             c.iteration()
176         l = self.linelist[0]
177         del self.linelist[0]
178         return l