--- /dev/null
+
+#
+# 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