PyXR

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



0001 #!/usr/bin/env python
0002 
0003 ### BITPIM
0004 ###
0005 ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com>
0006 ###
0007 ### This program is free software; you can redistribute it and/or modify
0008 ### it under the terms of the BitPim license as detailed in the LICENSE file.
0009 ###
0010 ### $Id: comdiagnose.py 4656 2008-08-02 15:57:20Z hjelmn $
0011 
0012 """Generate opinions on the attached com devices"""
0013 
0014 # Standard modules
0015 import re
0016 import sys
0017 
0018 # My modules
0019 import comscan
0020 import usbscan
0021 import bitflingscan
0022 
0023 def diagnose(portlist, phonemodule):
0024     """Returns data suitable for use in com port settings dialog
0025 
0026     @param portlist: A list of ports as returned by L{comscan.comscan}()
0027     @return: A list of tuples (whattodisplay, portselected, htmldiagnosis)
0028     """
0029     res=[]
0030     # we sort into 3 lists
0031     # available
0032     # not available but active
0033     # the rest
0034     available=[]
0035     bfavailable=[]
0036     bfrest=[]
0037     notavailablebutactive=[]
0038     therest=[]
0039     for port in portlist:
0040         if port.has_key("available") and port["available"]:
0041             if port.has_key("BitFling"):
0042                 bfavailable.append(port)
0043             else:
0044                 available.append(port)
0045             continue
0046         if not port.has_key("BitFling") and (port.has_key("available") and port.has_key("active") and port["active"]):
0047             notavailablebutactive.append(port)
0048             continue
0049         if port.has_key("BitFling"):
0050             bfrest.append(port)
0051         else:
0052             therest.append(port)
0053 
0054     if len(available):
0055         whattodisplay="===== Available Ports ===== "
0056         portselected=None
0057         htmldiagnosis="<p>These ports are open and can be selected"
0058         res.append( (whattodisplay, portselected, htmldiagnosis) )
0059         for port in available:
0060             likely=islikelyport(port, phonemodule)
0061             whattodisplay=port['description']
0062             if likely:
0063                 whattodisplay="(*) "+whattodisplay
0064             portselected=port['name']
0065             if likely:
0066                 htmldiagnosis="<p>This port is likely to be your phone.  The port is available and can be selected.<p>"+genhtml(port)
0067             else:
0068                 htmldiagnosis="<p>This port is available and can be selected.<p>"+genhtml(port)
0069             res.append( (whattodisplay, portselected, htmldiagnosis) )
0070 
0071     if len(notavailablebutactive):
0072         whattodisplay="===== Ports not available ====="
0073         portselected=None
0074         htmldiagnosis="<p>These ports are active, but cannot be used because they are in use by another program or device driver, you do not have permissions to access them, or a device driver is required."
0075         res.append( (whattodisplay, portselected, htmldiagnosis) )
0076         for port in notavailablebutactive:
0077             whattodisplay=port['description']
0078             portselected=port['name']
0079             htmldiagnosis="<p>This port is active but not available for use.<p>"+genhtml(port)
0080             res.append( (whattodisplay, portselected, htmldiagnosis) )
0081         
0082     if len(therest):
0083         whattodisplay="===== Inoperable Ports ====="
0084         portselected=None
0085         htmldiagnosis="""<p>These ports are known to your operating system, but cannot be used.  
0086         This may be because the device is not plugged in (such as on a USB to serial cable) or because 
0087         you don't have sufficient permissions to use them."""
0088         res.append( (whattodisplay, portselected, htmldiagnosis) )
0089         for port in therest:
0090             whattodisplay=port['description']
0091             portselected=port['name']
0092             htmldiagnosis="""<p>This port should not be selected.  If you believe it is the correct
0093             port, you should cause it to become available such as by plugging in the cable or ensuring
0094             you have correct permissions.  Press refresh once you have done so and it should be listed
0095             under available. Note that the name may change as it becomes available.<p>"""+genhtml(port)
0096             res.append( (whattodisplay, portselected, htmldiagnosis) )
0097 
0098     if len(bfavailable):
0099         whattodisplay="===== BitFling Available Ports ===== "
0100         portselected=None
0101         htmldiagnosis="<p>These BitFling ports are open and can be selected"
0102         res.append( (whattodisplay, portselected, htmldiagnosis) )
0103         for port in bfavailable:
0104             likely=islikelyport(port, phonemodule)
0105             whattodisplay=port['description']
0106             if likely:
0107                 whattodisplay="(*) "+whattodisplay
0108             portselected=port['name']
0109             if likely:
0110                 htmldiagnosis="<p>This port is likely to be your phone.  The port is available and can be selected.<p>"+genhtml(port)
0111             else:
0112                 htmldiagnosis="<p>This port is available and can be selected.<p>"+genhtml(port)
0113             res.append( (whattodisplay, portselected, htmldiagnosis) )
0114 
0115     if len(bfrest):
0116         whattodisplay="===== BitFling Other Ports ===== "
0117         portselected=None
0118         htmldiagnosis="<p>These BitFling ports exist but are not available"
0119         res.append( (whattodisplay, portselected, htmldiagnosis) )
0120         for port in bfrest:
0121             likely=islikelyport(port, phonemodule)
0122             whattodisplay=port['description']
0123             if likely:
0124                 whattodisplay="(*) "+whattodisplay
0125             portselected=port['name']
0126             if likely:
0127                 htmldiagnosis="<p>This port is likely to be your phone.  The port is available and can be selected.<p>"+genhtml(port)
0128             else:
0129                 htmldiagnosis="<p>This port is available and can be selected.<p>"+genhtml(port)
0130             res.append( (whattodisplay, portselected, htmldiagnosis) )
0131 
0132 
0133     return res
0134 
0135 def htmlify(text):
0136     text=re.sub("&", "&amp;", text)
0137     text=re.sub("<", "&lt;", text)
0138     text=re.sub(">", "&gt;", text)
0139     return text
0140 
0141 def genhtml(port):
0142     """Returns nice html describing a port dict"""
0143     sfont='<font size="-1">'
0144     efont='</font>'
0145     res='<table width="100%"><tr><th width="20%">Property<th width="40%">Value<th width="40%">Description</tr>\n'
0146     keys=port.keys()
0147     keys.sort()
0148     for k in keys:
0149         # property
0150         if k.startswith('usb-') and not k.endswith('string'):
0151             # ignore these
0152             continue
0153         res+='<tr><td valign="top">'+sfont+k+efont+'</td><td valign="top">\n'
0154         # value
0155         if k=='active' or k=='available':
0156             if port[k]:
0157                 res+=sfont+"True"+efont
0158             else:
0159                 res+=sfont+"False"+efont
0160         elif k=='driverdate':
0161             # XML-RPC converts tuples to lists, so we have to convert back again here
0162             res+=sfont+("%d-%d-%d" % tuple(port[k]))+efont
0163         elif k=='driverstatus':
0164             res+=sfont+`port[k]`+efont # should print it nicer at some point
0165         else:
0166             if isinstance(port[k], type("")):
0167                 res+=sfont+htmlify(port[k])+efont
0168             else:
0169                 res+=sfont+`port[k]`+efont
0170         res+='</td><td valign="top">'
0171         # description
0172         if k=='name':
0173             res+=sfont+"This is the name the port is known to your operating system as"+efont
0174         elif k=='available':
0175             if port[k]:
0176                 res+=sfont+"It was possible to open this port"+efont
0177             else:
0178                 res+=sfont+"It was not possible to open this port"+efont
0179         elif k=='active':
0180             if port[k]:
0181                 res+=sfont+"Your operating system shows this driver and port is correctly configured and a device attached"+efont
0182             else:
0183                 res+=sfont+"This driver/port combination is not currently running"+efont
0184         elif k=='driverstatus':
0185             res+=sfont+"""This is low level detail.  If problem is non-zero then you need to look in the
0186             control panel for an explanation as to why this driver/device is not working."""+efont
0187         elif k=='hardwareinstance':
0188             res+=sfont+"""This is how the device is named internally.  For example USB devices include
0189             the vendor (VID) and product (PID) identities"""+efont
0190         elif k=="libusb":
0191             res+=sfont+"""This indicates if the usb library is in use to access this device.  Operating system
0192             device drivers (if any) are bypassed when BitPim talks to the device"""+efont
0193         elif k=="driver-required":
0194             res+=sfont+"""This indicates if you must use a device driver, not direct USB access"""+efont
0195         elif k=="BitFling":
0196             res+=sfont+"""This indicates that the port is being accessed from a remote machine via BitFling,"""+efont
0197         elif k=="protocol":
0198             res+=sfont+"""This is the protocol the USB device claims to speak"""+efont
0199         elif k=="class":
0200             if port[k]=="serial":
0201                 res+=sfont+"""This is a serial connection"""+efont
0202             elif port[k]=="modem":
0203                 res+=sfont+"""This is a modem connection"""+efont
0204             else:
0205                 res+=sfont+"""The port type (serial, modem etc)"""+efont
0206         elif k=='PID':
0207             res+=sfont+'Product ID'+efont
0208         elif k=='VID':
0209             res+=sfont+'Vendor ID'+efont
0210         else:
0211             res+="&nbsp;"
0212 
0213         # tail it
0214         res+="</td></tr>\n"
0215 
0216     res+="\n</table>"
0217 
0218     return res
0219 
0220 def islikelyport(port, phonemodule):
0221     return islikelyportscore(port, phonemodule)>=0
0222 
0223 def islikelyportscore(port, phonemodule):
0224     """Returns a port score.
0225 
0226     @return: -1 if no match, 0 best match, 1 next etc
0227     """
0228 
0229     usbids=phonemodule.Profile.usbids
0230     deviceclasses=phonemodule.Profile.deviceclasses
0231 
0232     # it must be the right class
0233     if port.has_key("class") and port["class"] not in deviceclasses:
0234         return -1
0235 
0236     score=0
0237     # check the usbids
0238     for vid,pid,iface in usbids:
0239         score+=1
0240         if port.has_key("libusb"):
0241             if port['usb-vendor#']==vid and \
0242                    port['usb-product#']==pid and \
0243                    port['usb-interface#']==iface:
0244                 return score
0245         if port.has_key('hardwareinstance'):
0246             v=port['hardwareinstance'].lower()
0247             str="vid_%04x&pid_%04x" % (vid,pid)
0248             if v.find(str)>=0:
0249                 return score
0250 
0251     # LG phones generall have ports named cu.name-BTDIAG-1 or cu.name-SerialPort-1 where name is the bluetooth id of the phone
0252     if sys.platform=='darwin' and (port['name'].lower().find('btdiag') > 0 or port['name'].lower().find('serialport') > 0):
0253         return score
0254 
0255     score+=10
0256     # did it have a usb id that didn't match?
0257     if port.has_key("libusb"):
0258         return -1
0259 
0260     # did the hardware instance have usb info?
0261     if port.has_key("hardwareinstance") and \
0262        re.search("vid_([0-9a-f]){4}&pid_([0-9a-f]){4}", port['hardwareinstance'], re.I) is not None:
0263         return -1
0264 
0265     # are we on non-windows platform?  if so, just be happy if 'usb' is in the name or the driver name
0266     if sys.platform!='win32' and ( \
0267         port['name'].lower().find('usb')>0 or port.get("driver","").lower().find('usb')>=0):
0268         return score
0269 
0270     # if we are on windows check to see if this phone supports bluetooth as we may have a bluetooth comport 
0271     # we check that the bluetooth device contains the manufacturers ID for the phone, this filters
0272     # other bluetooth devices from the search, on windows the 'hardwareinstance' contains BTHENUM indicating 
0273     # a bluetooth device and the manufacturer's ID
0274     if sys.platform=='win32' and (getattr(phonemodule.Profile, 'bluetooth_mfg_id', 0) != 0) and \
0275         port['hardwareinstance'].find('BTHENUM\\')==0 and \
0276         port['hardwareinstance'].find(getattr(phonemodule.Profile, 'bluetooth_mfg_id', 'XXX'))>0:
0277         return score
0278 
0279     # ok, not then
0280     return -1
0281             
0282 def autoguessports(phonemodule):
0283     """Returns a list of ports (most likely first) for finding the phone on"""
0284     # this function also demonsrates the use of list comprehensions :-)
0285     res=[]
0286     # we only care about available ports
0287     ports=[(islikelyportscore(port, phonemodule), port) for port in comscan.comscan()+usbscan.usbscan()+bitflingscan.flinger.scan() if port['available']]
0288     # sort on score
0289     ports.sort()
0290     # return all ones with score >=0
0291     return [ (port['name'], port) for score,port in ports if score>=0]
0292 
0293 
0294 
0295 
0296 if __name__=='__main__':
0297     import common
0298     print autoguessports(common.importas("phones.com_lgvx4400"))
0299 

Generated by PyXR 0.9.4