#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2007 Johannes Hölzl # # This library is covered by the GNU LGPL, read LICENSE for details. """\ Provides access to the EEPROM in an Silabs CP210x. The data can be directly to the device read or written. """ __author__ = "Johannes Hölzl " __license__ = "GNU LGPL" __version__ = "0.2" import sys import re import string import traceback import optparse from cp210x import usb, valuefile, cp210x from cp210x.eeprom import EEPROM, HexFileError from cp210x.valuefile import read_baudrate_info, update_values, ValuesFileError TRANS_UNDERSCORE = string.maketrans('_', '-') ERR_OK = 0 ERR_WRONG_INPUT = -1 ERR_INTERNAL = -2 ERR_DEVICE_LOCKED = -3 ERR_DEVICE_NOT_FOUND = -4 ERR_DEVICE_ERROR = -5 def error(message, retval=-1): sys.stderr.write(message + "\n") sys.exit(retval) class Option(optparse.Option): TYPES = list(optparse.Option.TYPES) TYPE_CHECKER = dict(optparse.Option.TYPE_CHECKER) for type, (reader, _) in valuefile.TYPES.items(): if type in TYPES: continue TYPES.append(type) def checker(self, name, value, reader=reader): try: return reader(value) except ValueError, err: raise optparse.OptionValueError("option %s: %s" % (name, str(err))) TYPE_CHECKER[type] = checker class OptionParser(optparse.OptionParser): def error(self, msg): error(msg, ERR_WRONG_INPUT) def __init__(self, *args, **kwargs): if 'option_class' not in kwargs: kwargs['option_class'] = Option optparse.OptionParser.__init__(self, *args, **kwargs) def input_file(arg): if arg is None or arg == '-': return sys.stdin else: return file(arg, 'rb') def output_file(arg): if arg is None or arg == '-': return sys.stdout else: return file(arg, 'wb') def options_to_values(options): values = {} for name, type in cp210x.VALUES: if name == "baudrate_table": continue value = getattr(options, name) if value is not None: values[name] = value if options.baudrate_table: baudrate_table = [] for s in options.baudrate_table: try: baudrate, info = s.split(':') except TypeError: error("option --set-baudrate: need two parts separated by ':'", ERR_WRONG_INPUT) try: baudrate_table.append(read_baudrate_info(info) + (int(baudrate), )) except ValueError, err: error("option --set-baudrate: %s" % str(err), ERR_WRONG_INPUT) values['baudrate_table'] = baudrate_table return values def find_device(patterns): usb_patterns = [] for pattern in patterns: if ':' in pattern: try: vidString, pidString = pattern.split(':') vid = int(vidString, 16) pid = int(pidString, 16) except (TypeError, ValueError): error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.", ERR_WRONG_INPUT) usb_patterns.append(dict(idVendor=vid, idProduct=pid)) elif '/' in pattern: try: bus, device = pattern.split('/') usb_patterns.append( (bus, device) ) except (TypeError, ValueError): error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.", ERR_WRONG_INPUT) else: error("Match be either 'ddd/ddd' or 'hhhh:hhhh'.", ERR_WRONG_INPUT) for dev in cp210x.Cp210xProgrammer.list_devices(usb_patterns): return dev error("No devices found", ERR_DEVICE_NOT_FOUND) def read_cp210x(options): dev = find_device(options.match) dev.open() try: eeprom = EEPROM(dev) finally: dev.close() if options.hex_output: eeprom.write_hex_file(output_file(options.hex_output)) if options.ini_output or not options.hex_output: valuefile.write_file(output_file(options.ini_output), eeprom.get_values()) def write_cp210x(options): dev = find_device(options.match) dev.open() try: if options.hex_input or options.force_eeprom: if options.hex_input: eeprom = EEPROM(input_file(options.hex_input)) else: eeprom = EEPROM(dev) values = eeprom.get_values() if options.ini_input: values = valuefile.read_file(input_file(options.ini_input)) update_values(values, options_to_values(options), eeprom) eeprom.set_values(values) eeprom.write_to_cp210x(dev) if options.reset_device: dev.reset() else: if options.ini_input: values = valuefile.read_file(input_file(options.ini_input)) else: values = {} update_values(values, options_to_values(options), dev) dev.set_values(values) if options.reset_device: dev.reset() finally: dev.close() def change_hexfile(options): eeprom = EEPROM(input_file(options.hex_input)) values = {} if options.ini_input: update_values(values, valuefile.read_file(input_file(options.ini_input)), eeprom) update_values(values, options_to_values(options), eeprom) eeprom.set_values(values) if options.ini_output: valuefile.write_file(output_file(options.ini_output), eeprom.get_values()) eeprom.write_hex_file(output_file(options.hex_output)) def parse_hexfile(options): eeprom = EEPROM(input_file(options.hex_input)) valuefile.write_file(output_file(options.ini_output), eeprom.get_values()) parser = OptionParser(version=__version__, description=__doc__) parser.add_option("-r", "--read-cp210x", const=read_cp210x, dest="action", action="store_const") parser.add_option("-w", "--write-cp210x", const=write_cp210x, dest="action", action="store_const") parser.add_option("-c", "--change-hexfile", const=change_hexfile, dest="action", action="store_const") parser.add_option("-p", "--parse-hexfile", const=parse_hexfile, dest="action", action="store_const") parser.add_option("-F", "--hex-input", metavar="FILE") parser.add_option("-f", "--hex-output", metavar="FILE") parser.add_option("-I", "--ini-input", metavar="FILE") parser.add_option("-i", "--ini-output", metavar="FILE") for name, type in cp210x.VALUES: if name == 'baudrate_table': continue parser.add_option("--set-" + name.translate(TRANS_UNDERSCORE), dest=name, metavar=name.upper(), type=type) parser.add_option("--set-baudrate", action="append", dest="baudrate_table") parser.add_option("-m", "--match", action="append", metavar="PATTERN") parser.add_option("--reset-device", action="store_true") parser.add_option("--force-eeprom", action="store_true") parser.set_defaults( action=read_cp210x, hex_input=None, hex_output=None, ini_input=None, ini_output=None, match=[], baudrate_table=[], reset_device=False, force_eeprom=False, ) def main(): (options, _) = parser.parse_args() if not options.match: options.match = ['10C4:EA60', '10C4:EA61','413C:9500' ] options.action(options) if __name__ == '__main__': try: usb.init() main() except cp210x.DeviceLocked: error("Can not write data to device. Device is locked.", ERR_DEVICE_LOCKED) except cp210x.Cp210xError, err: error(str(err), ERR_DEVICE_ERROR) except IOError, err: error(str(err), ERR_OTHER) except HexFileError, err: error(str(err), ERR_OTHER) except ValuesFileError, err: error(str(err), ERR_OTHER) except usb.LibUsbNotInstalled: error("Package 'libusb' not installed.") except SystemExit, err: raise except: traceback.print_exc() sys.exit(ERR_INTERNAL)