+
+Fri Dec 28 16:29:37 2012 advance idle chooses 0, 29000
+Fri Dec 28 16:29:37 2012 Sleeping for 29.000000 seconds
+Fri Dec 28 16:29:56 2012 received EOF
+Fri Dec 28 16:29:56 2012 Force state to reset
+Fri Dec 28 16:29:56 2012 advance reset chooses 0, 3600000
+Fri Dec 28 16:29:56 2012 Sleeping for 3600.000000 seconds
+Traceback (most recent call last):
+ File "/usr/local/bin/atchan.py", line 72, in readdata
+ self.getline(None)
+ File "/usr/local/bin/atchan.py", line 90, in getline
+ self.takeline(line)
+ File "/usr/local/bin/gsmd", line 795, in takeline
+ self.advance()
+ File "/usr/local/bin/gsmd", line 778, in advance
+ self.set_timeout(delay)
+ File "/usr/local/bin/atchan.py", line 129, in set_timeout
+ raise ValueError
+ValueError
+Fri Dec 28 16:29:56 2012 received EOF
+Fri Dec 28 16:29:56 2012 Force state to reset
+Fri Dec 28 16:29:56 2012 advance reset chooses 0, 3600000
+Fri Dec 28 16:29:56 2012 Sleeping for 3600.000000 seconds
+Traceback (most recent call last):
+ File "/usr/local/bin/atchan.py", line 72, in readdata
+ self.getline(None)
+ File "/usr/local/bin/atchan.py", line 90, in getline
+ self.takeline(line)
+ File "/usr/local/bin/gsmd", line 849, in takeline
+ self.main.takeline(line)
+ File "/usr/local/bin/gsmd", line 795, in takeline
+ self.advance()
+ File "/usr/local/bin/gsmd", line 778, in advance
+ self.set_timeout(delay)
+ File "/usr/local/bin/atchan.py", line 129, in set_timeout
+ raise ValueError
+ValueError
+Fri Dec 28 16:30:06 2012 Timer Fired
+Fri Dec 28 16:30:06 2012 advance reset chooses 0, 3600000
+Fri Dec 28 16:30:06 2012 Sleeping for 3600.000000 seconds
+
+
+
Sun Dec 23 10:36:08 2012 send AT command +CPAS 2000
Sun Dec 23 10:36:08 2012 received AT response +CPAS: 4
Sun Dec 23 10:36:08 2012 call_status got +CPAS: 4
def takeline(self, channel, line):
if line == None:
- channel.set_state('reset')
+ channel.force_state('reset')
channel.advance()
return
m = self.ok.match(line)
def timeout(self, channel):
if channel.state['retries'] >= 5:
if self.critical:
- channel.set_state('reset')
+ channel.force_state('reset')
channel.advance()
return
channel.state['retries'] += 1
def start(self, channel):
if self.newstate:
state = self.newstate
- elif channel.statechanged:
- state = channel.nextstate
- channel.statechanged = False
+ elif channel.nextstate:
+ state = channel.nextstate.pop(0)
else:
state = None
if state:
channel.gstate = state
channel.tasknum = None
- if not channel.statechanged:
- channel.nextstate = state
log("ChangeStateAction chooses", channel.gstate)
n = len(control[channel.gstate])
channel.lastrun = n * [0]
control = {}
# For flight mode, we turn the power off.
-control['flight'] = [
+control['to-flight'] = [
AtAction(at='+CFUN=0'),
PowerAction('off'),
+ ChangeStateAction('flight')
+]
+control['flight'] = [
BlockSuspendAction(False),
]
# For suspend, we want power on, but no wakups for status or cellid
control['suspend'] = [
+ AtAction(check='+CFUN?', ok='\+CFUN: [14]', at='+CFUN=1', timeout=10000),
AtAction(check='+CPAS', ok='\+CPAS: (\d)', handle = call_status),
- AtAction(check='+CFUN?', ok='\+CFUN: 1', at='+CFUN=1', timeout=10000),
CheckSMS(),
ChangeStateAction(None), # allow async state change
AtAction(at='+CNMI=1,1,0,0,0'),
]
control['resume'] = [
BlockSuspendAction(True),
+ AtAction(check='+CFUN?', ok='\+CFUN: [14]', at='+CFUN=1', timeout=10000),
+ AtAction(check='+CPAS', ok='\+CPAS: (\d)', handle = call_status),
AtAction(at='+CNMI=1,1,2,0,0', critical=False),
AtAction(at='_OSQI=1', critical=False),
AtAction(at='+CREG=2'),
#AtAction(check='+COPS?', ok='\+COPS: \d+,\d+,"([^"]*)"', at='+COPS=0',
# record=('carrier', '\\1'), timeout=10000, repeat=37000),
# Make sure to use both 2G and 3G
- AtAction(at='_OPSYS=3,2'),
+ AtAction(at='_OPSYS=3,2', critical=False),
# get signal string
AtAction(check='+CSQ', ok='\+CSQ: (\d+),(\d+)',
record=('signal_strength','\\1/32'), repeat=29000)
self.altpath = altpath
self.altchan = CarrierDetect(altpath, self)
self.gstate = None
- self.nextstate = None
- self.statechanged = False
+ self.nextstate = []
record('carrier','')
record('cell','')
l = recall('call')
log("Check call got", l)
if l == "":
- if self.nextstate not in ['hangup', 'idle']:
+ if self.gstate != 'idle':
global incoming_num
incoming_num = None
self.set_state('hangup')
calllog_end('incoming')
calllog_end('outgoing')
elif l == 'answer':
- if self.nextstate == 'incoming':
+ if self.gstate == 'incoming':
record('status', 'on-call')
record('incoming','')
set_alert('ring', None)
self.set_state('answer')
else:
- if self.nextstate == 'idle':
+ if self.gstate == 'idle':
global calling
calling = True
self.args['number'] = l
else:
if not self.flightmode:
self.flightmode = True
- self.set_state('flight')
+ self.set_state('to-flight')
def do_suspend(self):
self.suspend_pending = True
- if self.nextstate not in ['flight', 'resume']:
+ if self.gstate not in ['flight', 'resume']:
print "do suspend sets suspend"
self.set_state('suspend')
else:
return False
def do_resume(self):
- if self.nextstate == 'suspend':
+ if self.gstate == 'suspend':
self.set_state('resume')
def set_state(self, state):
# this happens asynchronously so we must be careful
# about changing things. Just record the new state
# and abort any timeout
+ if state == self.gstate or state in self.nextstate:
+ log("state already destined to be", state)
+ return
log("state should become", state)
- self.nextstate = state
- self.statechanged = True
+ self.nextstate.append(state)
self.abort_timeout()
+ def force_state(self, state):
+ # immediately go to new state - must be called carefully
+ log("Force state to", state);
+ self.cancel_timeout()
+ self.nextstate = []
+ self.gstate = state
+
def advance(self):
# 'advance' is called by a 'Task' when it has finished
# It may have called 'set_state' first either to report
self.tasknum = None
(t, delay) = self.next_cmd()
log("advance %s chooses %d, %d" % (self.gstate, t, delay))
- if delay and self.statechanged:
+ if delay and self.nextstate:
# time to effect 'set_state' synchronously
- self.statechanged = False
- self.gstate = self.nextstate
+ self.gstate = self.nextstate.pop(0)
log("state becomes", self.gstate)
n = len(control[self.gstate])
self.lastrun = n * [0]
return False
if line == None:
- self.set_state('reset')
+ self.force_state('reset')
self.advance()
if not line:
return False
sub states. That is bad.
- resume is immediately replaced by 'suspend' which hangs around longer
than we want... I guess the cpas and cfun and checksms should protect
- against staying in suspend... but how?
\ No newline at end of file
+ against staying in suspend... but how?
+
+
+I need to queue state change requests so no state misses out.
+i.e. I don't want 'resume' to be immediately replaced by 'incoming' before it
+has a chance to do anything.
+But I sometimes check the 'next' state when responding to 'async' actions.
+What does that mean when there is a queue of 'next' states?
+
+check_call: if EMPTY not hangup or idle, - enter hangup
+ if ANSWER and is 'incoming' - enter 'on-call'
+ if NUMBER and is 'idle' - enter 'call'
+ This can be gstate
+do_suspend: if not 'flight' or 'resume', enter 'suspend'
+ This can be gstate
+do_resume: if 'suspend' become 'resume'
+ This can be just 'gstate'
+
+We sometimes check gstate directly:
+ incoming: if not on-call, incoming, answer : set to incoming
+ no_carrier: if not 'idle', set to 'idle'
+ call_status0: if 'on-call, incoming, call, clear call
+ if not idle or suspend, become idle
+ call_status3: if not 'incoming' or 'answer', become 'incoming'