0001 ### BITPIM 0002 ### 0003 ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 0004 ### 0005 ### This program is free software; you can redistribute it and/or modify 0006 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0007 ### 0008 ### $Id: bitflingscan.py 2741 2006-01-09 03:32:08Z sawecw $ 0009 0010 """Scans the available bitfling ports in the same way as comscan and usbscan work 0011 as well as providing the rest of the BitFling interface""" 0012 0013 import sys 0014 import common 0015 0016 try: 0017 import bitfling.client as bitfling 0018 except ImportError: 0019 bitfling=None 0020 0021 def IsBitFlingEnabled(): 0022 if bitfling is None: 0023 return False 0024 return True 0025 0026 class BitFlingIsNotConfiguredException(Exception): pass 0027 0028 class flinger: 0029 0030 def __init__(self, certverifier=None): 0031 self.certverifier=certverifier 0032 self.unconfigure() 0033 0034 def isconfigured(self): 0035 return self.username is not None and \ 0036 self.password is not None and \ 0037 self.host is not None and \ 0038 self.port is not None 0039 0040 def _configure(self): 0041 if not self.isconfigured(): 0042 raise BitFlingIsNotConfiguredException("BitFling needs to be configured") 0043 if self.client is None: 0044 self.client=bitfling.client(self.username, self.password, self.host, self.port, self.certverifier) 0045 0046 def configure(self, username, password, host, port): 0047 self.client=None 0048 self.username=username 0049 self.password=password 0050 self.host=host 0051 self.port=port 0052 0053 def unconfigure(self): 0054 self.username=self.password=self.host=self.port=self.client=None 0055 0056 def getversion(self): 0057 self._configure() 0058 return self.client.getversion() 0059 0060 def SetCertVerifier(self, certverifier): 0061 self.certverifier=certverifier 0062 0063 def scan(self): 0064 if not self.isconfigured(): 0065 return [] 0066 self._configure() 0067 ports=self.client.scan() 0068 for p in range(len(ports)): 0069 ports[p]['BitFling']=True 0070 ports[p]['name']='bitfling::'+ports[p]['name'] 0071 return ports 0072 0073 # All the device methods 0074 0075 def deviceopen(self, port, baud, timeout, hardwareflow, softwareflow): 0076 self._configure() 0077 return self.client.deviceopen(port, baud, timeout, hardwareflow, softwareflow) 0078 0079 def deviceclose(self, handle): 0080 try: 0081 self._configure() 0082 # we don't care about close's failing 0083 self.client.deviceclose(handle) 0084 except: 0085 pass 0086 0087 def devicesetbaudrate(self, handle, rate): 0088 self._configure() 0089 return self.client.devicesetbaudrate(handle, rate) 0090 0091 def devicesetdtr(self, handle, dtr): 0092 self._configure() 0093 return self.client.devicesetdtr(handle, dtr) 0094 0095 def devicesetrts(self, handle, rts): 0096 self._configure() 0097 return self.client.devicesetrts(handle, rts) 0098 0099 def devicewrite(self, handle, data): 0100 self._configure() 0101 return self.client.devicewrite(handle, data) 0102 0103 def devicesendatcommand(self, handle, sendatcommand, ignoreerror): 0104 self._configure() 0105 res=self.client.devicesendatcommand(handle, sendatcommand, ignoreerror) 0106 if res==0: 0107 raise 0108 elif res==1: 0109 res=[] 0110 return res 0111 0112 def devicereaduntil(self, handle, char, numfailures): 0113 self._configure() 0114 return self.client.devicereaduntil(handle, char, numfailures) 0115 0116 def deviceread(self, handle, numchars): 0117 self._configure() 0118 return self.client.deviceread(handle, numchars) 0119 0120 def devicereadsome(self, handle, numchars): 0121 self._configure() 0122 return self.client.devicereadsome(handle, numchars) 0123 0124 def devicewritethenreaduntil(self, handle, data, char, numfailures): 0125 self._configure() 0126 return self.client.devicewritethenreaduntil(handle, data, char, numfailures) 0127 0128 # ensure there is a singleton 0129 flinger=flinger() 0130 0131 encode=common.obfus_encode 0132 decode=common.obfus_decode 0133 0134 # Unfortunately we have to do some magic to deal with threads 0135 # correctly. This code is called both from the gui/foreground thread 0136 # (eg when calling the scan function) as well as from the background 0137 # thread (eg when talking to a port over the protocol). We also have 0138 # to deal with certificate verification issues, since the cert 0139 # verification has to happen in the gui/foreground. 0140 0141 # The way we solve this problem is to have a dedicated thread for 0142 # running the flinger code in. We hide this from the various callers 0143 # by automatically transferring control to the bitfling thread and 0144 # back again using Queue.Queue's 0145 0146 import thread 0147 import threading 0148 import Queue 0149 0150 class BitFlingWorkerThread(threading.Thread): 0151 0152 def __init__(self): 0153 threading.Thread.__init__(self) 0154 self.setName("BitFling worker thread") 0155 self.setDaemon(True) 0156 self.q=Queue.Queue() 0157 self.resultqueues={} 0158 self.eventloops={} 0159 0160 def run(self): 0161 while True: 0162 q,func,args,kwargs=self.q.get() 0163 try: 0164 res=func(*args, **kwargs) 0165 q.put( (res, None) ) 0166 except: 0167 q.put( (None, sys.exc_info()) ) 0168 0169 def callfunc(self, func, args, kwargs): 0170 qres=self.getresultqueue() 0171 self.q.put( (qres, func, args, kwargs) ) 0172 # do we need event loop? 0173 loopfunc=self.eventloops.get(thread.get_ident(), None) 0174 if loopfunc is not None: 0175 while qres.empty(): 0176 loopfunc() 0177 res, exc = qres.get() 0178 if exc is not None: 0179 ex=exc[1] 0180 ex.gui_exc_info=exc 0181 raise ex 0182 return res 0183 0184 def getresultqueue(self): 0185 """Return the thread specific result Queue object 0186 0187 They are automatically allocated on demand""" 0188 q=self.resultqueues.get(thread.get_ident(), None) 0189 if q is not None: 0190 return q 0191 q=Queue.Queue() 0192 self.resultqueues[thread.get_ident()]=q 0193 return q 0194 0195 def setthreadeventloop(self, eventfunc): 0196 """Sets the eventloopfunction used for this thread""" 0197 self.eventloops[thread.get_ident()]=eventfunc 0198 0199 class CallWrapper: 0200 """Provides proxy method wrappers so that all method calls can be redirected to worker thread 0201 0202 This works in a very similar way to how xmlrpclib wraps client side xmlrpc 0203 """ 0204 0205 class MethodIndirect: 0206 def __init__(self, func): 0207 self.func=func 0208 0209 def __call__(self, *args, **kwargs): 0210 return CallWrapper.worker.callfunc(self.func, args, kwargs) 0211 0212 worker=None 0213 object=None 0214 0215 def __init__(self, worker, object): 0216 CallWrapper.worker=worker 0217 CallWrapper.object=object 0218 0219 def __getattr__(self, name): 0220 if hasattr(self.worker, name): 0221 return getattr(self.worker, name) 0222 v=getattr(self.object, name) 0223 if callable(v): 0224 return self.MethodIndirect(v) 0225 return v 0226 0227 0228 if IsBitFlingEnabled(): 0229 BitFlingWorkerThread=BitFlingWorkerThread() 0230 BitFlingWorkerThread.start() 0231 0232 # wrap it all up 0233 flinger=CallWrapper(BitFlingWorkerThread, flinger) 0234 else: 0235 class flinger: 0236 def __getattr__(self, name): 0237 if name=="scan": return self.scan 0238 raise Exception("BitFling is not enabled") 0239 def __setattr__(self, name, value): 0240 raise Exception("BitFling is not enabled") 0241 def scan(self): 0242 return [] 0243 flinger=flinger() 0244 0245 0246 class CommConnection: 0247 # The constructor takes the same arguments as commport.CommConnection, but many 0248 # are ignored 0249 def __init__(self, logtarget, port, baud=115200, timeout=3, hardwareflow=0, 0250 softwareflow=0, autolistfunc=None, autolistargs=None, configparameters=None): 0251 assert port.startswith("bitfling::") 0252 self.logtarget=logtarget 0253 self.port=port 0254 self.baud=baud 0255 self.timeout=timeout 0256 self.hardwareflow=hardwareflow 0257 self.softwareflow=softwareflow 0258 self.handle=None 0259 self._openport() 0260 0261 def _openport(self): 0262 if self.handle is not None: 0263 self.close() 0264 self.log("Opening port %s, %d baud, timeout %f, hardwareflow %d, softwareflow %d" % 0265 (self.port, self.baud, float(self.timeout), self.hardwareflow, self.softwareflow) ) 0266 self.handle=flinger.deviceopen(self.port[len("bitfling::"):], self.baud, self.timeout, self.hardwareflow, 0267 self.softwareflow) 0268 0269 def IsAuto(self): 0270 return False 0271 0272 def close(self): 0273 if self.handle is not None: 0274 flinger.deviceclose(self.handle) 0275 self.handle=None 0276 0277 def reset(self): 0278 self._openport() 0279 0280 def log(self, str): 0281 if self.logtarget: 0282 self.logtarget.log(self.port+": "+str) 0283 0284 def logdata(self, str, data): 0285 if self.logtarget: 0286 self.logtarget.logdata(self.port+": "+str, data) 0287 0288 def setbaudrate(self, rate): 0289 res=flinger.devicesetbaudrate(self.handle, rate) 0290 if res: 0291 self.baud=rate 0292 return res 0293 0294 def setdtr(self, dtr): 0295 res=flinger.devicesetdtr(self.handle, dtr) 0296 return res 0297 0298 def setrts(self, rts): 0299 res=flinger.devicesetrts(self.handle, rts) 0300 return res 0301 0302 def write(self, data, log=True): 0303 if log: 0304 self.logdata("Writing", data) 0305 flinger.devicewrite(self.handle, data) 0306 0307 def sendatcommand(self, atcommand, ignoreerror=False): 0308 res=flinger.devicesendatcommand(self.handle, atcommand, ignoreerror) 0309 return res 0310 0311 def read(self, numchars=1, log=True): 0312 res=flinger.deviceread(self.handle, numchars) 0313 if log: 0314 self.logdata("Reading exact data - requested "+`numchars`, res) 0315 return res 0316 0317 def readsome(self, log=True, numchars=-1): 0318 res=flinger.devicereadsome(self.handle, numchars) 0319 if log: 0320 self.logdata("Reading remaining data", res) 0321 return res 0322 0323 def readuntil(self, char, log=True, logsuccess=True, numfailures=0): 0324 res=flinger.devicereaduntil(self.handle, char, numfailures) 0325 if log: 0326 pass # ::TODO: something when we get a timeout exception 0327 if logsuccess: 0328 self.logdata("Read completed", res) 0329 return res 0330 0331 # composite methods which reduce round trips 0332 def writethenreaduntil(self, data, logwrite, char, logreaduntil=True, logreaduntilsuccess=True, numfailures=0): 0333 if logwrite: 0334 self.logdata("Writing", data) 0335 res=flinger.devicewritethenreaduntil(self.handle, data, char, numfailures) 0336 if logreaduntilsuccess: 0337 self.logdata("Read completed", res) 0338 return res 0339
Generated by PyXR 0.9.4