Module bitflingscan
[hide private]
[frames] | no frames]

Source Code for Module bitflingscan

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: bitflingscan.py 2741 2006-01-09 03:32:08Z sawecw $ 
  9   
 10  """Scans the available bitfling ports in the same way as comscan and usbscan work 
 11  as well as providing the rest of the BitFling interface""" 
 12   
 13  import sys 
 14  import common 
 15   
 16  try: 
 17      import bitfling.client as bitfling 
 18  except ImportError: 
 19      bitfling=None 
 20   
21 -def IsBitFlingEnabled():
22 if bitfling is None: 23 return False 24 return True
25
26 -class BitFlingIsNotConfiguredException(Exception): pass
27
28 -class flinger:
29
30 - def __init__(self, certverifier=None):
31 self.certverifier=certverifier 32 self.unconfigure()
33
34 - def isconfigured(self):
35 return self.username is not None and \ 36 self.password is not None and \ 37 self.host is not None and \ 38 self.port is not None
39
40 - def _configure(self):
41 if not self.isconfigured(): 42 raise BitFlingIsNotConfiguredException("BitFling needs to be configured") 43 if self.client is None: 44 self.client=bitfling.client(self.username, self.password, self.host, self.port, self.certverifier)
45
46 - def configure(self, username, password, host, port):
47 self.client=None 48 self.username=username 49 self.password=password 50 self.host=host 51 self.port=port
52
53 - def unconfigure(self):
54 self.username=self.password=self.host=self.port=self.client=None
55
56 - def getversion(self):
57 self._configure() 58 return self.client.getversion()
59
60 - def SetCertVerifier(self, certverifier):
61 self.certverifier=certverifier
62
63 - def scan(self):
64 if not self.isconfigured(): 65 return [] 66 self._configure() 67 ports=self.client.scan() 68 for p in range(len(ports)): 69 ports[p]['BitFling']=True 70 ports[p]['name']='bitfling::'+ports[p]['name'] 71 return ports
72 73 # All the device methods 74
75 - def deviceopen(self, port, baud, timeout, hardwareflow, softwareflow):
76 self._configure() 77 return self.client.deviceopen(port, baud, timeout, hardwareflow, softwareflow)
78
79 - def deviceclose(self, handle):
80 try: 81 self._configure() 82 # we don't care about close's failing 83 self.client.deviceclose(handle) 84 except: 85 pass
86
87 - def devicesetbaudrate(self, handle, rate):
88 self._configure() 89 return self.client.devicesetbaudrate(handle, rate)
90
91 - def devicesetdtr(self, handle, dtr):
92 self._configure() 93 return self.client.devicesetdtr(handle, dtr)
94
95 - def devicesetrts(self, handle, rts):
96 self._configure() 97 return self.client.devicesetrts(handle, rts)
98
99 - def devicewrite(self, handle, data):
100 self._configure() 101 return self.client.devicewrite(handle, data)
102
103 - def devicesendatcommand(self, handle, sendatcommand, ignoreerror):
104 self._configure() 105 res=self.client.devicesendatcommand(handle, sendatcommand, ignoreerror) 106 if res==0: 107 raise 108 elif res==1: 109 res=[] 110 return res
111
112 - def devicereaduntil(self, handle, char, numfailures):
113 self._configure() 114 return self.client.devicereaduntil(handle, char, numfailures)
115
116 - def deviceread(self, handle, numchars):
117 self._configure() 118 return self.client.deviceread(handle, numchars)
119
120 - def devicereadsome(self, handle, numchars):
121 self._configure() 122 return self.client.devicereadsome(handle, numchars)
123
124 - def devicewritethenreaduntil(self, handle, data, char, numfailures):
125 self._configure() 126 return self.client.devicewritethenreaduntil(handle, data, char, numfailures)
127 128 # ensure there is a singleton 129 flinger=flinger() 130 131 encode=common.obfus_encode 132 decode=common.obfus_decode 133 134 # Unfortunately we have to do some magic to deal with threads 135 # correctly. This code is called both from the gui/foreground thread 136 # (eg when calling the scan function) as well as from the background 137 # thread (eg when talking to a port over the protocol). We also have 138 # to deal with certificate verification issues, since the cert 139 # verification has to happen in the gui/foreground. 140 141 # The way we solve this problem is to have a dedicated thread for 142 # running the flinger code in. We hide this from the various callers 143 # by automatically transferring control to the bitfling thread and 144 # back again using Queue.Queue's 145 146 import thread 147 import threading 148 import Queue 149
150 -class BitFlingWorkerThread(threading.Thread):
151
152 - def __init__(self):
153 threading.Thread.__init__(self) 154 self.setName("BitFling worker thread") 155 self.setDaemon(True) 156 self.q=Queue.Queue() 157 self.resultqueues={} 158 self.eventloops={}
159
160 - def run(self):
161 while True: 162 q,func,args,kwargs=self.q.get() 163 try: 164 res=func(*args, **kwargs) 165 q.put( (res, None) ) 166 except: 167 q.put( (None, sys.exc_info()) )
168
169 - def callfunc(self, func, args, kwargs):
170 qres=self.getresultqueue() 171 self.q.put( (qres, func, args, kwargs) ) 172 # do we need event loop? 173 loopfunc=self.eventloops.get(thread.get_ident(), None) 174 if loopfunc is not None: 175 while qres.empty(): 176 loopfunc() 177 res, exc = qres.get() 178 if exc is not None: 179 ex=exc[1] 180 ex.gui_exc_info=exc 181 raise ex 182 return res
183
184 - def getresultqueue(self):
185 """Return the thread specific result Queue object 186 187 They are automatically allocated on demand""" 188 q=self.resultqueues.get(thread.get_ident(), None) 189 if q is not None: 190 return q 191 q=Queue.Queue() 192 self.resultqueues[thread.get_ident()]=q 193 return q
194
195 - def setthreadeventloop(self, eventfunc):
196 """Sets the eventloopfunction used for this thread""" 197 self.eventloops[thread.get_ident()]=eventfunc
198
199 -class CallWrapper:
200 """Provides proxy method wrappers so that all method calls can be redirected to worker thread 201 202 This works in a very similar way to how xmlrpclib wraps client side xmlrpc 203 """ 204
205 - class MethodIndirect:
206 - def __init__(self, func):
207 self.func=func
208
209 - def __call__(self, *args, **kwargs):
210 return CallWrapper.worker.callfunc(self.func, args, kwargs)
211 212 worker=None 213 object=None 214
215 - def __init__(self, worker, object):
218
219 - def __getattr__(self, name):
220 if hasattr(self.worker, name): 221 return getattr(self.worker, name) 222 v=getattr(self.object, name) 223 if callable(v): 224 return self.MethodIndirect(v) 225 return v
226 227 228 if IsBitFlingEnabled(): 229 BitFlingWorkerThread=BitFlingWorkerThread() 230 BitFlingWorkerThread.start() 231 232 # wrap it all up 233 flinger=CallWrapper(BitFlingWorkerThread, flinger) 234 else:
235 - class flinger:
236 - def __getattr__(self, name):
237 if name=="scan": return self.scan 238 raise Exception("BitFling is not enabled")
239 - def __setattr__(self, name, value):
240 raise Exception("BitFling is not enabled")
241 - def scan(self):
242 return []
243 flinger=flinger() 244 245
246 -class CommConnection:
247 # The constructor takes the same arguments as commport.CommConnection, but many 248 # are ignored
249 - def __init__(self, logtarget, port, baud=115200, timeout=3, hardwareflow=0, 250 softwareflow=0, autolistfunc=None, autolistargs=None, configparameters=None):
251 assert port.startswith("bitfling::") 252 self.logtarget=logtarget 253 self.port=port 254 self.baud=baud 255 self.timeout=timeout 256 self.hardwareflow=hardwareflow 257 self.softwareflow=softwareflow 258 self.handle=None 259 self._openport()
260
261 - def _openport(self):
262 if self.handle is not None: 263 self.close() 264 self.log("Opening port %s, %d baud, timeout %f, hardwareflow %d, softwareflow %d" % 265 (self.port, self.baud, float(self.timeout), self.hardwareflow, self.softwareflow) ) 266 self.handle=flinger.deviceopen(self.port[len("bitfling::"):], self.baud, self.timeout, self.hardwareflow, 267 self.softwareflow)
268
269 - def IsAuto(self):
270 return False
271
272 - def close(self):
273 if self.handle is not None: 274 flinger.deviceclose(self.handle) 275 self.handle=None
276
277 - def reset(self):
278 self._openport()
279
280 - def log(self, str):
281 if self.logtarget: 282 self.logtarget.log(self.port+": "+str)
283
284 - def logdata(self, str, data):
285 if self.logtarget: 286 self.logtarget.logdata(self.port+": "+str, data)
287
288 - def setbaudrate(self, rate):
289 res=flinger.devicesetbaudrate(self.handle, rate) 290 if res: 291 self.baud=rate 292 return res
293
294 - def setdtr(self, dtr):
295 res=flinger.devicesetdtr(self.handle, dtr) 296 return res
297
298 - def setrts(self, rts):
299 res=flinger.devicesetrts(self.handle, rts) 300 return res
301
302 - def write(self, data, log=True):
303 if log: 304 self.logdata("Writing", data) 305 flinger.devicewrite(self.handle, data)
306
307 - def sendatcommand(self, atcommand, ignoreerror=False):
308 res=flinger.devicesendatcommand(self.handle, atcommand, ignoreerror) 309 return res
310
311 - def read(self, numchars=1, log=True):
312 res=flinger.deviceread(self.handle, numchars) 313 if log: 314 self.logdata("Reading exact data - requested "+`numchars`, res) 315 return res
316
317 - def readsome(self, log=True, numchars=-1):
318 res=flinger.devicereadsome(self.handle, numchars) 319 if log: 320 self.logdata("Reading remaining data", res) 321 return res
322
323 - def readuntil(self, char, log=True, logsuccess=True, numfailures=0):
324 res=flinger.devicereaduntil(self.handle, char, numfailures) 325 if log: 326 pass # ::TODO: something when we get a timeout exception 327 if logsuccess: 328 self.logdata("Read completed", res) 329 return res
330 331 # composite methods which reduce round trips
332 - def writethenreaduntil(self, data, logwrite, char, logreaduntil=True, logreaduntilsuccess=True, numfailures=0):
333 if logwrite: 334 self.logdata("Writing", data) 335 res=flinger.devicewritethenreaduntil(self.handle, data, char, numfailures) 336 if logreaduntilsuccess: 337 self.logdata("Read completed", res) 338 return res
339