1""" 2gpscap - GPS/AIS capability dictionary class. 3 4This file is Copyright (c) 2010 by the GPSD project 5SPDX-License-Identifier: BSD-2-clause 6""" 7# This code runs compatibly under Python 2 and 3.x for x >= 2. 8# Preserve this property! 9from __future__ import absolute_import, print_function, division 10 11try: 12 import configparser 13except ImportError: 14 import ConfigParser as configparser 15 16 17class GPSDictionary(configparser.RawConfigParser): 18 def __init__(self, *files): 19 "Initialize the capability dictionary" 20 configparser.RawConfigParser.__init__(self) 21 if not files: 22 files = ["gpscap.ini", "/usr/share/gpsd/gpscap.ini"] 23 try: 24 self.read(files, encoding='utf-8') 25 except TypeError: 26 self.read(files) # For Python 2.6 27 # Resolve uses= members 28 while True: 29 keepgoing = False 30 for section in self.sections(): 31 if self.has_option(section, "uses"): 32 parent = self.get(section, "uses") 33 if self.has_option(parent, "uses"): 34 continue 35 # Found a parent section without a uses = part. 36 for heritable in self.options(parent): 37 if not self.has_option(section, heritable): 38 self.set(section, 39 heritable, 40 self.get(parent, heritable)) 41 keepgoing = True 42 self.remove_option(section, "uses") 43 if not keepgoing: 44 break 45 # Sanity check: All items must have a type field. 46 for section in self.sections(): 47 if not self.has_option(section, "type"): 48 raise configparser.Error("%s has no type" % section) 49 50 if (self.get(section, "type") 51 not in ("engine", "vendor", "device")): 52 raise configparser.Error("%s has invalid type" % section) 53 # Sanity check: All devices must point at a vendor object. 54 # Side effect: build the lists of vendors and devices. 55 self.vendors = [] 56 self.devices = [] 57 for section in self.sections(): 58 if self.get(section, "type") == "vendor": 59 self.vendors.append(section) 60 if self.get(section, "type") == "device": 61 self.devices.append(section) 62 self.vendors.sort() 63 for section in self.sections(): 64 if self.get(section, "type") == "device": 65 if not self.has_option(section, "vendor"): 66 raise configparser.Error("%s has no vendor" % section) 67 if self.get(section, "vendor") not in self.vendors: 68 raise configparser.Error("%s has invalid vendor" % section) 69 70 def HTMLDump(self, ofp): 71 thead = """ 72<table style='border:1px solid gray;font-size:small;background-color:#CCCCCC'> 73<caption>Listing %s devices from %s vendors</caption> 74<tr> 75<th>Name</th> 76<th>Packaging</th> 77<th>Engine</th> 78<th>Interface</th> 79<th>Tested with</th> 80<th>NMEA version</th> 81<th>PPS</th> 82<th style='width:50%%'>Notes</th> 83</tr> 84""" 85 vhead1 = "<tr><td style='text-align:center;' colspan='8'>" \ 86 "<a href='%s'>%s</a></td></tr>\n" 87 vhead2 = "<tr><td style='text-align:center;' colspan='8'>" \ 88 "<a href='%s'>%s</a><br><p>%s</p></td></tr>\n" 89 hotpluggables = ("pl2303", "CP2101") 90 ofp.write(thead % (len(self.devices), len(self.vendors))) 91 for vendor in self.vendors: 92 if self.has_option(vendor, "notes"): 93 ofp.write(vhead2 % (self.get(vendor, "vendor_site"), vendor, 94 self.get(vendor, "notes"))) 95 else: 96 ofp.write(vhead1 % (self.get(vendor, "vendor_site"), vendor)) 97 relevant = [] 98 for dev in self.devices: 99 if self.get(dev, "vendor") == vendor: 100 relevant.append(dev) 101 relevant.sort() 102 for dev in relevant: 103 rowcolor = "white" 104 if self.get(dev, "packaging") == "OEM module": 105 rowcolor = "#32CD32" 106 elif self.get(dev, "packaging") == "chipset": 107 rowcolor = "#FFFFE0" 108 elif self.get(dev, "packaging") == "handset": 109 rowcolor = "#00FFFF" 110 elif self.get(dev, "packaging") == "hansdfree": 111 rowcolor = "#008B8B" 112 113 ofp.write("<tr itemscope itemtype='http://schema.org/Product'" 114 " style='background-color:%s'>\n" % rowcolor) 115 namefield = dev 116 if self.has_option(dev, "techdoc"): 117 namefield = "<a href='%s'>%s</a>" \ 118 % (self.get(dev, "techdoc"), dev) 119 if ((self.has_option(dev, "discontinued") and 120 self.getboolean(dev, "discontinued"))): 121 namefield = namefield + " <img title='Device " \ 122 "discontinued' src='discontinued.png' " \ 123 "alt='Discontinued icon'>" 124 ofp.write("<td itemprop='name'>%s</td>\n" % namefield) 125 ofp.write("<td>%s</td>\n" % self.get(dev, "packaging")) 126 engine = self.get(dev, "engine") 127 if self.has_option(engine, "techdoc"): 128 engine = "<a href='%s'>%s</a>" \ 129 % (self.get(engine, "techdoc"), engine) 130 if self.has_option(dev, "subtype"): 131 engine += " (" + self.get(dev, "subtype") + ")" 132 ofp.write("<td>%s</td>\n" % engine) 133 interfaces = self.get(dev, "interfaces") 134 if self.has_option(dev, "pps"): 135 interfaces += ",PPS" 136 ofp.write("<td>%s</td>\n" % interfaces) 137 testfield = "" 138 if self.has_option(dev, "tested"): 139 tested = self.get(dev, "tested") 140 if tested == "regression": 141 testfield += "<img title='Have regression test' " \ 142 "src='regression.png' " \ 143 "alt='Regression-test icon'>" 144 else: 145 testfield += tested 146 if ((self.has_option(dev, "configurable") and 147 self.get(dev, "configurable") == 'insane')): 148 testfield += "<img title='Requires -b option' " \ 149 "src='noconfigure.png' " \ 150 "alt='No-configure icon'>" 151 if self.get(dev, "rating") == "excellent": 152 testfield += "<img src='star.png' alt='Star icon'>" \ 153 "<img src='star.png' alt='Star icon'>" \ 154 "<img src='star.png' alt='Star icon'>" \ 155 "<img src='star.png' alt='Star icon'>" 156 elif self.get(dev, "rating") == "good": 157 testfield += "<img src='star.png' alt='Star icon'>" \ 158 "<img src='star.png' alt='Star icon'>" \ 159 "<img src='star.png' alt='Star icon'>" 160 elif self.get(dev, "rating") == "fair": 161 testfield += "<img src='star.png' alt='Star icon'>" \ 162 "<img src='star.png' alt='Star icon'>" 163 elif self.get(dev, "rating") == "poor": 164 testfield += "<img src='star.png' alt='Star icon'>" 165 elif self.get(dev, "rating") == "broken": 166 testfield += "<img title='Device is broken' " \ 167 "src='bomb.png' alt='Bomb icon'>" 168 if ((self.has_option(dev, "usbchip") and 169 self.get(dev, "usbchip") in hotpluggables)): 170 testfield += "<img title='udev hotplug' " \ 171 "src='hotplug.png' alt='Hotplug icon'>" 172 ofp.write("<td>%s</td>\n" % testfield) 173 nmea = " " 174 if self.has_option(dev, "nmea"): 175 nmea = self.get(dev, "nmea") 176 ofp.write("<td>%s</td>\n" % nmea) 177 if ((self.has_option(dev, "pps") and 178 self.get(dev, "pps") == "True")): 179 pps_accuracy = time_offset = "" 180 if self.has_option(dev, "pps_accuracy"): 181 pps_accuracy = self.get(dev, "pps_accuracy") 182 if self.has_option(dev, "time_offset"): 183 time_offset = self.get(dev, "time_offset") 184 if pps_accuracy and time_offset: 185 ofp.write("<td>%s<br>%s</td>\n" 186 % (pps_accuracy, time_offset)) 187 else: 188 ofp.write("<td>?<br>\n") 189 else: 190 ofp.write("<td>No</td>\n") 191 if self.has_option(dev, "notes"): 192 notes = self.get(dev, "notes") 193 else: 194 notes = "" 195 if self.has_option(dev, "submitter"): 196 notes += " Reported by %s." % self.get( 197 dev, "submitter").replace("@", "@").replace( 198 "<", "<").replace(">", ">") 199 ofp.write("<td itemscope itemtype='http://schema.org/" 200 "description'>%s</td>\n" % notes) 201 ofp.write("</tr>\n") 202 ofp.write("</table>\n") 203 204 205if __name__ == "__main__": 206 import sys 207 try: 208 d = GPSDictionary() 209 d.HTMLDump(sys.stdout) 210 except configparser.Error as e: 211 sys.stderr.write(sys.argv[0] + ":%s\n" % e) 212 raise SystemExit(1) 213