From: Neil Brown Date: Sun, 15 Feb 2009 11:40:51 +0000 (+1100) Subject: gsmd: commit 'atchan.py' - missed that when committing gsmd.py X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=79240212941bdf38a54a9356ecc338f0753ed83c;p=freerunner.git gsmd: commit 'atchan.py' - missed that when committing gsmd.py --- diff --git a/gsm/atchan.py b/gsm/atchan.py new file mode 100644 index 0000000..cb40dc1 --- /dev/null +++ b/gsm/atchan.py @@ -0,0 +1,178 @@ + +# +# Handle a connection to an AT device via gsm0710muxd +# If this is a 'master', we can reset the modem, else +# any misbehaviour requires that we fail (FIXME not implemented) +# +# We directly support high level commands (get/set_power, reset_modem +# etc) but don't know anything about AT commands - we just send them +# through and hand back reply. Replies also go via a callback +# We also provide timeout support, but someone else needs to tell us +# when to set a timeout, and when to clear it. +# +# This is usually subclassed by code with an agenda. + +import gobject, sys, os, time +from trace import log +from socket import * + +class AtChannel: + def __init__(self, path = '/var/run/gsm-mux', master = False): + self.master = False + self.path = path + self.connected = False + self.command_mode = False + self.watcher = None + self.sock = None + self.power = None + self.buf = "" + self.linelist = [] + + self.pending = False + self.timer = None + + def disconnect(self): + if self.watcher: + gobject.source_remove(self.watcher) + self.watcher = None + if self.sock: + self.sock.close() + self.sock = None + self.connected = False + + def connect(self): + log("connect to", self.path) + s = socket(AF_UNIX, SOCK_STREAM) + s.connect(self.path) + self.watcher = gobject.io_add_watch(s, gobject.IO_IN, self.readdata) + self.sock = s + self.connected = True + self.command_mode = True + self.command_pending = False + + def command(self, str): + if not self.connected or not self.command_mode: + raise ValueError + log("send command", str) + if not self.command_pending: + self.command_pending = str + self.sock.sendall(str + '\n') + self.set_timeout(30000) + + def readdata(self, io, arg): + r = self.sock.recv(1000) + r = self.buf + r + ra = r.split('\n') + self.buf = ra[-1]; + del ra[-1] + for ln in ra: + ln = ln.strip('\r') + self.getline(ln) + return True + + def getline(self, line): + if self.command_mode: + log("Receive cmd response", line, "to", self.command_pending) + if line == "OK" and self.command_pending == "connect": + log("Leaving command mode") + self.command_mode = False + if self.pending: + self.pending = False + gobject.source_remove(self.timer) + self.timer = None + if self.command_pending: + if line[0:2] == "OK" or line[0:5] == "ERROR": + self.command_pending = False + self.power_done(line) + else: + log("receive AT response", line) + if self.takeline(line): + if self.pending: + self.pending = False + gobject.source_remove(self.timer) + self.timer = None + + def set_power(self, state): + if state and self.power == True: + return gobject.idle_add(self.power_done) + if not state and self.power == False: + return gobject.idle_add(self.power_done) + # OK, I need to do something + if self.connected and not self.command_mode: + self.disconnect() + if not self.connected: + self.connect() + self.command_pending = "power" + if state: + self.command("set_power 1") + self.power = True + else: + self.command("set_power 0") + self.power = False + + def reset(self): + if self.connected and not self.command_mode: + self.disconnect() + if not self.connected: + self.connect() + self.command_pending = "reset" + self.command("reset_modem") + self.power = True + + def atconnect(self): + if not self.connected: + self.connect() + if not self.command_mode: + return self.power_done() + self.command_pending = "connect" + self.command("connect") + + + def atcmd(self, cmd, timeout = 2000): + """ + Send the command, preceeded by 'AT' and set a timeout. + self.takeline() should return True when the command + has been responded to, otherwise we will call + self.timedout() after the time. + """ + self.set_timeout(timeout) + log("send AT command", cmd, timeout) + self.sock.sendall('AT' + cmd + '\r') + + def timer_fired(self): + log("Timer Fired") + self.pending = False + self.timer = None + self.timedout() + return False + + def set_timeout(self, delay): + if self.pending: + raise ValueError + self.timer = gobject.timeout_add(delay, self.timer_fired) + self.pending = True + + def cancel_timeout(self): + if self.pending: + gobject.source_remove(self.timer) + self.pending = False + + def abort_timeout(self): + if self.pending: + self.cancel_timeout() + self.set_timeout(0) + + # these are likely to be over-ridden by a child class + def power_done(self, line=None): + self.linelist.append(line) + def takeline(self, line): + self.linelist.append(line) + + def wait_line(self, timeout): + self.cancel_timeout() + c = gobject.main_context_default() + while not self.linelist: + c.iteration() + l = self.linelist[0] + del self.linelist[0] + return l