PyXR

c:\projects\bitpim\src \ bitflingscan.py



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