From 9d406de448f17d14dc14d736d3c05524c3496cc3 Mon Sep 17 00:00:00 2001 From: Stefan Eichenberger Date: Mon, 4 Jul 2016 19:30:50 +0200 Subject: [PATCH] board-descriptor: add python script for bd stuff We had a boar-descriptor module, this script could replace that. It will access directly to the eeprom --- .../board-descriptor/board-descriptor.bb | 36 +++ .../board-descriptor/board-descriptor/bd.json | 62 +++++ .../board-descriptor/board-descriptor/bd.py | 86 +++++++ .../board-descriptor/config.json | 10 + .../board-descriptor/descriptor.py | 222 ++++++++++++++++++ 5 files changed, 416 insertions(+) create mode 100644 recipes-core/board-descriptor/board-descriptor.bb create mode 100644 recipes-core/board-descriptor/board-descriptor/bd.json create mode 100755 recipes-core/board-descriptor/board-descriptor/bd.py create mode 100644 recipes-core/board-descriptor/board-descriptor/config.json create mode 100644 recipes-core/board-descriptor/board-descriptor/descriptor.py diff --git a/recipes-core/board-descriptor/board-descriptor.bb b/recipes-core/board-descriptor/board-descriptor.bb new file mode 100644 index 0000000..12cdcff --- /dev/null +++ b/recipes-core/board-descriptor/board-descriptor.bb @@ -0,0 +1,36 @@ +SUMMARY = "Boarddescriptor Tool" +DESCRIPTION = "Read and write from/to the boarddescriptor" +AUTHOR = "Stefan Eichenberger (stefan.eichenberger@netmodule.com)" + +SECTION = "core" +LICENSE = "GPLv2+" +LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6" +PR = "r0" + +RDEPENDS_${PN} = "python-json" + +SRC_URI = " \ + file://bd.py \ + file://descriptor.py \ + file://config.json \ + file://bd.json \ + " + +S = "${WORKDIR}" + +FILES_${PN} = " \ + ${bindir}/* \ + ${libdir}/* \ + ${sysconfdir}/* \ + " + +do_install () { + install -d ${D}${bindir} + install -m 0755 bd.py ${D}${bindir}/bd + + install -d ${D}${libdir}/python2.7/ + install -m 0644 descriptor.py ${D}${libdir}/python2.7/ + + install -d ${D}${sysconfdir}/bd + install -m 0644 *.json ${D}${sysconfdir}/bd/ +} diff --git a/recipes-core/board-descriptor/board-descriptor/bd.json b/recipes-core/board-descriptor/board-descriptor/bd.json new file mode 100644 index 0000000..42d703b --- /dev/null +++ b/recipes-core/board-descriptor/board-descriptor/bd.json @@ -0,0 +1,62 @@ +{ + "serial": {"id": 1, "type": "String"}, + "production_date": {"id": 2, "type": "Date"}, + "hw_ver": {"id": 3, "type": "UInt8"}, + "hw_rel": {"id": 4, "type": "UInt8"}, + "prod_name": {"id": 5, "type": "String"}, + "prod_variant": {"id": 6, "type": "UInt16"}, + "prod_compatibility": {"id": 7, "type": "String"}, + + "eth_mac": {"id": 8, "type": "MAC"}, + "ip_addr": {"id": 9, "type": "IPV4"}, + "ip_netmask": {"id": 10, "type": "IPV4"}, + "ip_gateway": {"id": 11, "type": "IPV4"}, + + "usb_device_id": {"id": 12, "type": "UInt16"}, + "usb_vendor_id": {"id": 13, "type": "UInt16"}, + + "ram_size": {"id": 14, "type": "UInt32"}, + "ram_size64": { "id": 15, "type": "UInt64"}, + "flash_size": { "id": 16, "type": "UInt32"}, + "flash_size64": { "id": 17, "type": "UInt64"}, + "eeprom_size": { "id": 18, "type": "UInt32"}, + "nv_ram_size": { "id": 19, "type": "UInt32"}, + + "cpu_base_clk": { "id": 20, "type": "UInt32"}, + "cpu_core_clk": { "id": 21, "type": "UInt32"}, + "cpu_bus_clk": { "id": 22, "type": "UInt32"}, + "ram_clk": { "id": 23, "type": "UInt32"}, + + "partition": { "id": 24, "type": "Partition"}, + "partition64": { "id": 25, "type": "Partition64"}, + + "lcd_type": { "id": 26, "type": "UInt16"}, + "lcd_backlight": { "id": 27, "type": "UInt8"}, + "lcd_contrast": { "id": 28, "type": "UInt8"}, + "touch_type": { "id": 29, "type": "UInt16"}, + + "manufacturer_id": { "id": 30, "type": "String"}, + "hmac-sha1-4": { "id": 31, "type": "Hash"}, + "fpga_info": { "id": 32, "type": "UInt32"}, + + "ui_adapter_type": { "id": 4096, "type": "UInt16"}, + "hw_flavor": { "id": 4097, "type": "UInt32"}, + "voltage": { "id": 4098, "type": "UInt8"}, + + "pd_module0": { "id": 4100, "type": "String"}, + "pd_module1": { "id": 4101, "type": "String"}, + "pd_module2": { "id": 4102, "type": "String"}, + "pd_module3": { "id": 4103, "type": "String"}, + "pd_module4": { "id": 4104, "type": "String"}, + "pd_module5": { "id": 4105, "type": "String"}, + "pd_phy0": { "id": 4110, "type": "String"}, + "pd_phy1": { "id": 4111, "type": "String"}, + "pd_dio": { "id": 4120, "type": "String"}, + "pd_serial": { "id": 4121, "type": "String"}, + "pd_sim": { "id": 4122, "type": "String"}, + "pd_led": { "id": 4123, "type": "String"}, + "pd_usbhost": { "id": 4124, "type": "String"}, + + "boot_part": { "id": 32768, "type": "UInt8"}, + "factory_reset": { "id": 32769, "type": "UInt8"} +} diff --git a/recipes-core/board-descriptor/board-descriptor/bd.py b/recipes-core/board-descriptor/board-descriptor/bd.py new file mode 100755 index 0000000..6e4843a --- /dev/null +++ b/recipes-core/board-descriptor/board-descriptor/bd.py @@ -0,0 +1,86 @@ +#!/usr/bin/python + +from optparse import OptionParser +import json +import sys + + +def read_config(config_file): + fd = open(config_file, "r") + config = fd.read() + fd.close() + return json.loads(config) + + +def read_all(bd): + for key, value in bd.items(): + print ("{0}: {1}".format(key, value)) + + +def read_key(bd, key): + print(bd[key]) + + +def main(): + import descriptor + + usage = "usage: %prog [options] arg" + parser = OptionParser(usage) + parser.add_option("-c", "--config", action="store", type="string", + dest="config", + help="Configuration file to load", + default="/etc/bd/config.json") + + parser.add_option("-a", "--read-all", action="store_true", dest="read_all", + help="Read everything from the boarddescriptors", + default=False) + + parser.add_option("-r", "--read-key", action="store", dest="read_key", + type="string", + help="Read key from the boarddescritpors", + default=None) + + parser.add_option("-w", "--write-key", action="store", dest="write_key", + type="string", + help="Try to write key to boarddescriptor", + default=None) + + parser.add_option("-v", "--write-value", action="store", dest="write_val", + type="string", + help="Value to write if -w (must be specified)", + default=None) + + (options, args) = parser.parse_args() + + config = read_config(options.config) + + # Read the tag -> name -> type list + fd = open(config["tag_list"], "r") + config_table = fd.read() + + bd = {} + descs = [] + for eeprom in config["eeprom"]: + for valid_bd in eeprom["valid_bds"]: + desc = descriptor.Descriptor(eeprom["path"], valid_bd["start"], + valid_bd["size"], config_table) + desc.read() + bd.update(desc.get_list()) + descs.append(desc) + + if options.read_all: + read_all(bd) + + if options.read_key is not None: + read_key(bd, options.read_key) + + if options.write_key is not None: + if options.write_val is None: + print("No value write specified, please set -v") + sys.exit(10) + for desc in descs: + desc.set(options.write_key, options.write_val) + + +if __name__ == "__main__": + main() diff --git a/recipes-core/board-descriptor/board-descriptor/config.json b/recipes-core/board-descriptor/board-descriptor/config.json new file mode 100644 index 0000000..a3ab00c --- /dev/null +++ b/recipes-core/board-descriptor/board-descriptor/config.json @@ -0,0 +1,10 @@ +{ + "tag_list": "/etc/bd/bd.json", + "eeprom": [ + { "path": "/sys/bus/i2c/devices/0-0050/eeprom", "valid_bds": [ + {"name": "info", "start": 0, "size": 1024}, + {"name": "settings", "start": 1536, "size": 512} + ] + } + ] +} diff --git a/recipes-core/board-descriptor/board-descriptor/descriptor.py b/recipes-core/board-descriptor/board-descriptor/descriptor.py new file mode 100644 index 0000000..fd80d80 --- /dev/null +++ b/recipes-core/board-descriptor/board-descriptor/descriptor.py @@ -0,0 +1,222 @@ +import json + + +def _array_to_int(data): + # This one works for python2.7 and python3 + import codecs + return int(codecs.encode(data, "hex"), 16) + + +def _array_to_string(data): + return data.decode("utf-8") + + +def _array_to_hash(data): + return bytearray(data) + + +def _array_to_mac(data): + return ':'.join('%02x' % b for b in data) + + +_string_to_type = { + "String": _array_to_string, + "Date": _array_to_string, + "UInt8": _array_to_int, + "UInt16": _array_to_int, + "UInt32": _array_to_int, + "UInt64": _array_to_int, + "MAC": _array_to_mac, + "IPV4": _array_to_string, + "Parition": _array_to_string, + "Parition64": _array_to_string, + "Hash": _array_to_hash +} + + +def _string_to_array(data): + return bytearray(data, "utf8") + + +def _uint_to_array(data, format): + value = int(data) + import struct + return struct.pack(format, value) + + +def _uint8_to_array(data): + return _uint_to_array(data, "B") + + +def _uint16_to_array(data): + return _uint_to_array(data, "H") + + +def _uint32_to_array(data): + return _uint_to_array(data, "L") + + +def _uint64_to_array(data): + return _uint_to_array(data, "Q") + + +def _not_supported_yet(data): + raise NotImplementedError("Setting this type is not supported yet") + +_type_to_value = { + "String": _string_to_array, + "Date": _string_to_array, + "UInt8": _uint8_to_array, + "UInt16": _uint16_to_array, + "UInt32": _uint32_to_array, + "UInt64": _uint64_to_array, + "MAC": _not_supported_yet, + "IPV4": _string_to_array, + "Parition": _string_to_array, + "Parition64": _string_to_array, + "Hash": _not_supported_yet +} + + +class _Tlv: + def __init__(self, tag, length, value, pos): + self.tag = tag + self.length = length + self.value = value + self.pos = pos + + +class _BdRaw: + def _verify_checksum(self, data, should_sum): + is_sum = sum(data) & 0xffff + if is_sum != should_sum: + raise ValueError("Checksum does not match (should: {0}, is: {1}" + .format(should_sum, is_sum)) + + def _get_hw(self, data): + return (data[0] << 8) + data[1] + + def _read_binary(self, data): + i = 0 + self.id = data[i:i + 4] + i += 4 + self.buffer_len = self._get_hw(data[i:]) + i += 2 + self.checksum = self._get_hw(data[i:]) + i += 2 + j = 0 + self.tlvs = [] + while i < self.buffer_len + 8: + # Zero means end of bd + tag = self._get_hw(data[i:i + 2]) + i += 2 + if tag == 0: + i -= 2 + break + length = self._get_hw(data[i:i + 2]) + i += 2 + value = data[i: i + length] + self.tlvs.append(_Tlv(tag, length, value, i)) + i += length + j += 1 + + return i + + def __init__(self, data): + self.is_writable = False + + data_length = self._read_binary(data) + + if self.checksum != 0: + self._verify_checksum(data[8:data_length], self.checksum) + else: + self.is_writable = True + + +class _BdParsed: + def __init__(self, strtype, value): + self.value = self._value_type(strtype, value) + + def _value_type(self, strtype, value): + for key, fun in _string_to_type.items(): + if key == strtype: + return fun(value) + + +class Descriptor: + def __init__(self, file, offset, max_size, config_table): + self.file = file + self.offset = offset + self.max_size = max_size + self.config_table = json.loads(config_table) + + def _read_raw_bd(self): + fd = open(self.file, "rb") + fd.seek(self.offset) + data = fd.read(self.max_size) + fd.close() + + # python2.7 reads string instead of bytearray + if type(data) is str: + data = bytearray(data) + + return _BdRaw(data) + + def _get_name_value(self, tlv): + for key, value in self.config_table.items(): + if tlv.tag == value["id"]: + parsed = _BdParsed(value["type"], tlv.value) + return key, parsed.value + + def _parse_data(self, bdraw): + bdparsed = {} + tlv_by_name = {} + for tlv in bdraw.tlvs: + name, value = self._get_name_value(tlv) + bdparsed[name] = value + tlv_by_name[name] = tlv + + return bdparsed, tlv_by_name + + def read(self): + self.bdraw = self._read_raw_bd() + self.bdparsed, self.tlv_by_name = self._parse_data(self.bdraw) + + def get_list(self): + return self.bdparsed + + def get(self, name): + return self.bdparsed[name] + + def _write_bd(self, pos, data, maxlen): + fd = open(self.file, "r+b") + fd.seek(self.offset + pos, 0) + fd.write(data[0:maxlen]) + fd.close() + + def _do_set(self, name, value, tlv): + for key, config_item in self.config_table.items(): + if tlv.tag == config_item["id"]: + type = config_item["type"] + break + + if type is None: + raise ValueError("Could not found tag type") + + for key, fun in _type_to_value.items(): + if key == type: + self._write_bd(tlv.pos, fun(value), tlv.length) + + def set(self, name, value): + if self.tlv_by_name is None: + raise ImportError("Descriptor not read yet, run read_all first") + + tlv = self.tlv_by_name.get(name) + if tlv is None: + return False + + if not self.bd.is_writable: + raise IOError("This operation is not permitted on \ + this descriptor (ro)") + self._do_set(name, value, tlv) + return True