cp210x-program 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. # Copyright (c) 2007 Johannes Hölzl <johannes.hoelzl@gmx.de>
  4. #
  5. # This library is covered by the GNU LGPL, read LICENSE for details.
  6. """\
  7. Provides access to the EEPROM of a Silabs CP210x. The data can be directly
  8. read from or written to the device.
  9. """
  10. __author__ = "Johannes Hölzl <johannes.hoelzl@gmx.de>"
  11. __license__ = "GNU LGPL"
  12. __version__ = "1.0"
  13. import sys
  14. import re
  15. import string
  16. import traceback
  17. import optparse
  18. from cp210x import valuefile, cp210x
  19. from cp210x.eeprom import EEPROM, HexFileError
  20. from cp210x.valuefile import read_baudrate_info, update_values, ValuesFileError
  21. TRANS_UNDERSCORE = string.maketrans('_', '-')
  22. ERR_OK = 0
  23. ERR_WRONG_INPUT = -1
  24. ERR_INTERNAL = -2
  25. ERR_DEVICE_LOCKED = -3
  26. ERR_DEVICE_NOT_FOUND = -4
  27. ERR_DEVICE_ERROR = -5
  28. ERR_OTHER = -100
  29. def error(message, retval=-1):
  30. sys.stderr.write(message + "\n")
  31. sys.exit(retval)
  32. class Option(optparse.Option):
  33. TYPES = list(optparse.Option.TYPES)
  34. TYPE_CHECKER = dict(optparse.Option.TYPE_CHECKER)
  35. for type, (reader, _) in valuefile.TYPES.items():
  36. if type in TYPES:
  37. continue
  38. TYPES.append(type)
  39. def checker(self, name, value, reader=reader):
  40. try:
  41. return reader(value)
  42. except ValueError, err:
  43. raise optparse.OptionValueError("option %s: %s" % (name,
  44. str(err)))
  45. TYPE_CHECKER[type] = checker
  46. class OptionParser(optparse.OptionParser):
  47. def error(self, msg):
  48. error(msg, ERR_WRONG_INPUT)
  49. def __init__(self, *args, **kwargs):
  50. if 'option_class' not in kwargs:
  51. kwargs['option_class'] = Option
  52. optparse.OptionParser.__init__(self, *args, **kwargs)
  53. def input_file(arg):
  54. if arg is None or arg == '-':
  55. return sys.stdin
  56. else:
  57. return file(arg, 'rb')
  58. def output_file(arg):
  59. if arg is None or arg == '-':
  60. return sys.stdout
  61. else:
  62. return file(arg, 'wb')
  63. def options_to_values(options):
  64. values = {}
  65. for name, type in cp210x.VALUES:
  66. if name == "baudrate_table":
  67. continue
  68. value = getattr(options, name)
  69. if value is not None:
  70. values[name] = value
  71. if options.baudrate_table:
  72. baudrate_table = []
  73. for s in options.baudrate_table:
  74. try:
  75. baudrate, info = s.split(':')
  76. except TypeError:
  77. error("option --set-baudrate: need two parts separated by ':'",
  78. ERR_WRONG_INPUT)
  79. try:
  80. baudrate_table.append(read_baudrate_info(info) +
  81. (int(baudrate), ))
  82. except ValueError, err:
  83. error("option --set-baudrate: %s" % str(err),
  84. ERR_WRONG_INPUT)
  85. values['baudrate_table'] = baudrate_table
  86. return values
  87. def find_device(patterns):
  88. usb_patterns = []
  89. for pattern in patterns:
  90. if ':' in pattern:
  91. try:
  92. vidString, pidString = pattern.split(':')
  93. vid = int(vidString, 16)
  94. pid = int(pidString, 16)
  95. except (TypeError, ValueError):
  96. error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.",
  97. ERR_WRONG_INPUT)
  98. usb_patterns.append(dict(idVendor=vid, idProduct=pid))
  99. elif '/' in pattern:
  100. try:
  101. busString, addressString = pattern.split('/')
  102. bus = int(busString)
  103. address = int(addressString)
  104. except (TypeError, ValueError):
  105. error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.",
  106. ERR_WRONG_INPUT)
  107. usb_patterns.append(dict(bus=bus, address=address))
  108. else:
  109. error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.",
  110. ERR_WRONG_INPUT)
  111. for dev in cp210x.Cp210xProgrammer.list_devices(usb_patterns):
  112. return dev
  113. error("No devices found", ERR_DEVICE_NOT_FOUND)
  114. def read_cp210x(options):
  115. usbdev = find_device(options.match)
  116. dev = cp210x.Cp210xProgrammer(usbdev)
  117. eeprom = EEPROM(dev)
  118. if options.hex_output:
  119. eeprom.write_hex_file(output_file(options.hex_output))
  120. if options.ini_output or not options.hex_output:
  121. valuefile.write_file(output_file(options.ini_output), eeprom.get_values())
  122. def write_cp210x(options):
  123. usbdev = find_device(options.match)
  124. dev = cp210x.Cp210xProgrammer(usbdev)
  125. if options.hex_input or options.force_eeprom:
  126. if options.hex_input:
  127. eeprom = EEPROM(input_file(options.hex_input))
  128. else:
  129. eeprom = EEPROM(dev)
  130. values = eeprom.get_values()
  131. if options.ini_input:
  132. values = valuefile.read_file(input_file(options.ini_input))
  133. update_values(values, options_to_values(options), eeprom)
  134. eeprom.set_values(values)
  135. eeprom.write_to_cp210x(dev)
  136. else:
  137. if options.ini_input:
  138. values = valuefile.read_file(input_file(options.ini_input))
  139. else:
  140. values = {}
  141. update_values(values, options_to_values(options), dev)
  142. dev.set_values(values)
  143. if options.reset_device:
  144. dev.reset()
  145. def change_hexfile(options):
  146. eeprom = EEPROM(input_file(options.hex_input))
  147. values = {}
  148. if options.ini_input:
  149. update_values(values,
  150. valuefile.read_file(input_file(options.ini_input)),
  151. eeprom)
  152. update_values(values, options_to_values(options), eeprom)
  153. eeprom.set_values(values)
  154. if options.ini_output:
  155. valuefile.write_file(output_file(options.ini_output),
  156. eeprom.get_values())
  157. eeprom.write_hex_file(output_file(options.hex_output))
  158. def parse_hexfile(options):
  159. eeprom = EEPROM(input_file(options.hex_input))
  160. valuefile.write_file(output_file(options.ini_output), eeprom.get_values())
  161. parser = OptionParser(version=__version__, description=__doc__)
  162. parser.add_option("-r", "--read-cp210x", const=read_cp210x,
  163. dest="action", action="store_const")
  164. parser.add_option("-w", "--write-cp210x", const=write_cp210x,
  165. dest="action", action="store_const")
  166. parser.add_option("-c", "--change-hexfile", const=change_hexfile,
  167. dest="action", action="store_const")
  168. parser.add_option("-p", "--parse-hexfile", const=parse_hexfile,
  169. dest="action", action="store_const")
  170. parser.add_option("-F", "--hex-input", metavar="FILE")
  171. parser.add_option("-f", "--hex-output", metavar="FILE")
  172. parser.add_option("-I", "--ini-input", metavar="FILE")
  173. parser.add_option("-i", "--ini-output", metavar="FILE")
  174. for name, type in cp210x.VALUES:
  175. if name == 'baudrate_table':
  176. continue
  177. parser.add_option("--set-" + name.translate(TRANS_UNDERSCORE),
  178. dest=name, metavar=name.upper(), type=type)
  179. parser.add_option("--set-baudrate", action="append", dest="baudrate_table")
  180. parser.add_option("-m", "--match", action="append", metavar="PATTERN")
  181. parser.add_option("--reset-device", action="store_true")
  182. parser.add_option("--force-eeprom", action="store_true")
  183. parser.set_defaults(
  184. action=read_cp210x,
  185. hex_input=None,
  186. hex_output=None,
  187. ini_input=None,
  188. ini_output=None,
  189. match=[],
  190. baudrate_table=[],
  191. reset_device=False,
  192. force_eeprom=False,
  193. )
  194. def main():
  195. (options, _) = parser.parse_args()
  196. if not options.match:
  197. options.match = ['10C4:EA60', '10C4:EA61']
  198. options.action(options)
  199. if __name__ == '__main__':
  200. try:
  201. main()
  202. except cp210x.DeviceLocked:
  203. error("Can not write data to device. Device is locked.",
  204. ERR_DEVICE_LOCKED)
  205. except cp210x.Cp210xError, err:
  206. error(str(err), ERR_DEVICE_ERROR)
  207. except IOError, err:
  208. error(str(err), ERR_OTHER)
  209. except HexFileError, err:
  210. error(str(err), ERR_OTHER)
  211. except ValuesFileError, err:
  212. error(str(err), ERR_OTHER)
  213. except SystemExit, err:
  214. raise
  215. except:
  216. traceback.print_exc()
  217. sys.exit(ERR_INTERNAL)