def bootload_8(paddr, hex_file, power_communicator):
    """ Bootload a 8 port power module.

    :param paddr: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    """
    reader = HexReader(hex_file)

    print "E%d - Going to bootloader" % paddr
    power_communicator.do_command(paddr, bootloader_goto(), 10)

    print "E%d - Reading chip id" % paddr
    id = power_communicator.do_command(paddr, bootloader_read_id())
    if id[0] != 213:
        raise Exception("Unknown chip id: %d" % id[0])

    print "E%d - Writing vector tabel" % paddr
    for address in range(0, 1024, 128):      # 0x000 - 0x400
        print " Writing %d" % address
        bytes = reader.get_bytes_8(address)
        power_communicator.do_command(paddr, bootloader_write_code(POWER_API_8_PORTS), *bytes)

    print "E%d -  Writing code" % paddr
    for address in range(8192, 44032, 128):  # 0x2000 - 0xAC00
        print " Writing %d" % address
        bytes = reader.get_bytes_8(address)
        power_communicator.do_command(paddr, bootloader_write_code(POWER_API_8_PORTS), *bytes)

    print "E%d - Jumping to application" % paddr
    power_communicator.do_command(paddr, bootloader_jump_application())
Exemple #2
0
def bootload_12(paddr, hex_file, power_communicator, verbose=False):
    """ Bootload a 12 port power module.

    :param paddr: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    :param verbose: Show serial command on output if verbose is True.
    """
    reader = HexReader(hex_file)

    print "E%d - Going to bootloader" % paddr
    power_communicator.do_command(paddr, bootloader_goto(), 10)

    print "E%d - Erasing code" % paddr
    for page in range(6, 64):
        power_communicator.do_command(paddr, bootloader_erase_code(), page)

    print "E%d -  Writing code" % paddr
    for address in range(0x1D006000, 0x1D03FFFB, 128):
        bytes = reader.get_bytes_12(address)
        power_communicator.do_command(
            paddr, bootloader_write_code(POWER_API_12_PORTS), *bytes)

    print "E%d - Jumping to application" % paddr
    power_communicator.do_command(paddr, bootloader_jump_application())
Exemple #3
0
def bootload_12(module_address, hex_file, power_communicator):
    """
    Bootload a 12 port power module.

    :param module_address: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    """
    logger.info('E{0} - Version: {1}'.format(
        module_address,
        get_module_firmware_version(module_address, power_communicator)))
    logger.info('E{0} - Start bootloading'.format(module_address))

    try:
        logger.info('E{0} - Reading calibration data'.format(module_address))
        calibration_data = list(
            power_communicator.do_command(module_address, read_eeprom(12, 100),
                                          *[256, 100]))
        logger.info('E{0} - Calibration data: {1}'.format(
            module_address, ','.join([str(d) for d in calibration_data])))
    except Exception as ex:
        logger.info('E{0} - Could not read calibration data: {1}'.format(
            module_address, ex))
        calibration_data = None

    reader = HexReader(hex_file)

    logger.info('E{0} - Going to bootloader'.format(module_address))
    power_communicator.do_command(module_address, bootloader_goto(), 10)

    try:
        logger.info('E{0} - Erasing code...'.format(module_address))
        for page in range(6, 64):
            power_communicator.do_command(module_address,
                                          bootloader_erase_code(), page)

        logger.info('E{0} - Writing code...'.format(module_address))
        for address in range(0x1D006000, 0x1D03FFFB, 128):
            data = reader.get_bytes_version_12(address)
            power_communicator.do_command(
                module_address, bootloader_write_code(POWER_API_12_PORTS),
                *data)
    finally:
        logger.info('E{0} - Jumping to application'.format(module_address))
        power_communicator.do_command(module_address,
                                      bootloader_jump_application())

    if calibration_data is not None:
        time.sleep(1)
        logger.info('E{0} - Restoring calibration data'.format(module_address))
        power_communicator.do_command(module_address, write_eeprom(12, 100),
                                      *([256] + calibration_data))

    logger.info('E{0} - Done'.format(module_address))
Exemple #4
0
def bootload_power_module(module_address, hex_file, power_communicator,
                          version):
    """
    Bootload a 8 port power module.

    :param module_address: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    :param version: Version of the provided hexfile
    """
    firmware_version, hardware_version = get_module_firmware_version(
        module_address, power_api.POWER_MODULE, power_communicator)
    logger.info('P{0} - Version: {1} ({2})'.format(module_address,
                                                   firmware_version,
                                                   hardware_version))
    if firmware_version == version:
        logger.info('P{0} - Already up-to-date. Skipping')
        return
    logger.info('P{0} - Start bootloading'.format(module_address))
    reader = HexReader(hex_file)

    logger.info('P{0} - Going to bootloader'.format(module_address))
    power_communicator.do_command(
        module_address, power_api.bootloader_goto(power_api.POWER_MODULE), 10)

    logger.info('P{0} - Reading chip id'.format(module_address))
    chip_id = power_communicator.do_command(module_address,
                                            power_api.bootloader_read_id())
    if chip_id[0] != 213:
        raise Exception('Unknown chip id: {0}'.format(chip_id[0]))

    logger.info('P{0} - Writing vector tabel'.format(module_address))
    for address in range(0, 1024, 128):  # 0x000 - 0x400
        data = reader.get_bytes_version_8(address)
        power_communicator.do_command(
            module_address,
            power_api.bootloader_write_code(power_api.POWER_MODULE), *data)

    logger.info('P{0} -  Writing code'.format(module_address))
    for address in range(8192, 44032, 128):  # 0x2000 - 0xAC00
        data = reader.get_bytes_version_8(address)
        power_communicator.do_command(
            module_address,
            power_api.bootloader_write_code(power_api.POWER_MODULE), *data)

    logger.info('P{0} - Jumping to application'.format(module_address))
    power_communicator.do_command(module_address,
                                  power_api.bootloader_jump_application())

    logger.info('P{0} - Done'.format(module_address))
Exemple #5
0
def bootload_8(module_address, hex_file, power_communicator):
    """
    Bootload a 8 port power module.

    :param module_address: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    """
    logger.info('E{0} - Version: {0}'.format(
        module_address,
        get_module_firmware_version(module_address, power_communicator)))
    logger.info('E{0} - Start bootloading'.format(module_address))
    reader = HexReader(hex_file)

    logger.info('E{0} - Going to bootloader'.format(module_address))
    power_communicator.do_command(module_address, bootloader_goto(), 10)

    logger.info('E{0} - Reading chip id'.format(module_address))
    chip_id = power_communicator.do_command(module_address,
                                            bootloader_read_id())
    if chip_id[0] != 213:
        raise Exception('Unknown chip id: {0}'.format(chip_id[0]))

    logger.info('E{0} - Writing vector tabel'.format(module_address))
    for address in range(0, 1024, 128):  # 0x000 - 0x400
        data = reader.get_bytes_version_8(address)
        power_communicator.do_command(module_address,
                                      bootloader_write_code(POWER_API_8_PORTS),
                                      *data)

    logger.info('E{0} -  Writing code'.format(module_address))
    for address in range(8192, 44032, 128):  # 0x2000 - 0xAC00
        data = reader.get_bytes_version_8(address)
        power_communicator.do_command(module_address,
                                      bootloader_write_code(POWER_API_8_PORTS),
                                      *data)

    logger.info('E{0} - Jumping to application'.format(module_address))
    power_communicator.do_command(module_address,
                                  bootloader_jump_application())

    logger.info('E{0} - Done'.format(module_address))
def bootload_12(paddr, hex_file, power_communicator):
    """ Bootload a 12 port power module.

    :param paddr: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    """
    reader = HexReader(hex_file)

    print "E%d - Going to bootloader" % paddr
    power_communicator.do_command(paddr, bootloader_goto(), 10)

    print "E%d - Erasing code" % paddr
    for page in range(6, 64):
        power_communicator.do_command(paddr, bootloader_erase_code(), page)

    print "E%d -  Writing code" % paddr
    for address in range(0x1D006000, 0x1D03FFFB, 128):
        bytes = reader.get_bytes_12(address)
        power_communicator.do_command(paddr, bootloader_write_code(POWER_API_12_PORTS), *bytes)

    print "E%d - Jumping to application" % paddr
    power_communicator.do_command(paddr, bootloader_jump_application())
Exemple #7
0
def bootload_8(paddr, hex_file, power_communicator, verbose=False):
    """ Bootload a 8 port power module.

    :param paddr: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    :param verbose: Show serial command on output if verbose is True.
    """
    reader = HexReader(hex_file)

    print "E%d - Going to bootloader" % paddr
    power_communicator.do_command(paddr, bootloader_goto(), 10)

    print "E%d - Reading chip id" % paddr
    id = power_communicator.do_command(paddr, bootloader_read_id())
    if id[0] != 213:
        raise Exception("Unknown chip id: %d" % id[0])

    print "E%d - Writing vector tabel" % paddr
    for address in range(0, 1024, 128):  # 0x000 - 0x400
        print " Writing %d" % address
        bytes = reader.get_bytes_8(address)
        power_communicator.do_command(paddr,
                                      bootloader_write_code(POWER_API_8_PORTS),
                                      *bytes)

    print "E%d -  Writing code" % paddr
    for address in range(8192, 44032, 128):  # 0x2000 - 0xAC00
        print " Writing %d" % address
        bytes = reader.get_bytes_8(address)
        power_communicator.do_command(paddr,
                                      bootloader_write_code(POWER_API_8_PORTS),
                                      *bytes)

    print "E%d - Jumping to application" % paddr
    power_communicator.do_command(paddr, bootloader_jump_application())
    def do_command(self, address, cmd, *data):
        """ Send a command over the serial port and block until an answer is received.
        If the power module does not respond within the timeout period, a
        CommunicationTimedOutException is raised.

        :param address: Address of the power module
        :type address: 2 bytes string
        :param cmd: the command to execute
        :type cmd: :class`PowerCommand`
        :param data: data for the command
        :raises: :class`CommunicationTimedOutException` if power module did not respond in time
        :raises: :class`InAddressModeException` if communicator is in address mode
        :returns: dict containing the output fields of the command
        """
        if self.__address_mode:
            raise InAddressModeException()

        def do_once(_address, _cmd, *_data):
            """ Send the command once. """
            cid = self.__get_cid()
            send_data = _cmd.create_input(_address, cid, *_data)
            self.__write_to_serial(send_data)

            if _address == power_api.BROADCAST_ADDRESS:
                return None  # No reply on broadcast messages !
            else:
                tries = 0
                while True:
                    # In this loop we might receive data that didn't match the expected header. This might happen
                    # if we for some reason had a timeout on the previous call, and we now read the response
                    # to that call. In this case, we just re-try (up to 3 times), as the correct data might be
                    # next in line.
                    header, response_data = self.__read_from_serial()
                    if not _cmd.check_header(header, _address, cid):
                        if _cmd.is_nack(header, _address, cid) and response_data == "\x02":
                            raise UnkownCommandException()
                        tries += 1
                        LOGGER.warning("Header did not match command ({0})".format(tries))
                        if tries == 3:
                            raise Exception("Header did not match command ({0})".format(tries))
                    else:
                        break

                self.__last_success = time.time()
                return _cmd.read_output(response_data)

        with self.__serial_lock:
            try:
                return do_once(address, cmd, *data)
            except UnkownCommandException:
                # This happens when the module is stuck in the bootloader.
                LOGGER.error("Got UnkownCommandException")
                do_once(address, power_api.bootloader_jump_application())
                time.sleep(1)
                return self.do_command(address, cmd, *data)
            except CommunicationTimedOutException:
                # Communication timed out, try again.
                return do_once(address, cmd, *data)
            except Exception as ex:
                LOGGER.exception("Unexpected error: {0}".format(ex))
                time.sleep(0.25)
                return do_once(address, cmd, *data)
Exemple #9
0
    def do_command(self, address, cmd, *data):
        # type: (int, PowerCommand, DataType) -> Tuple[Any, ...]
        """ Send a command over the serial port and block until an answer is received.
        If the power module does not respond within the timeout period, a
        CommunicationTimedOutException is raised.

        :param address: Address of the power module
        :type address: 2 bytes string
        :param cmd: the command to execute
        :param data: data for the command
        :raises: :class`CommunicationTimedOutException` if power module did not respond in time
        :raises: :class`InAddressModeException` if communicator is in address mode
        :returns: dict containing the output fields of the command
        """
        if self.__address_mode:
            raise InAddressModeException()

        def do_once(_address, _cmd, *_data):
            # type: (int, PowerCommand, DataType) -> Tuple[Any, ...]
            """ Send the command once. """
            try:
                cid = self.__get_cid()
                send_data = _cmd.create_input(_address, cid, *_data)
                self.__write_to_serial(send_data)

                if _address == power_api.BROADCAST_ADDRESS:
                    self.__communication_stats_calls['calls_succeeded'].append(
                        time.time())
                    self.__communication_stats_calls[
                        'calls_succeeded'] = self.__communication_stats_calls[
                            'calls_succeeded'][-50:]
                    return ()  # No reply on broadcast messages !
                else:
                    tries = 0
                    while True:
                        # In this loop we might receive data that didn't match the expected header. This might happen
                        # if we for some reason had a timeout on the previous call, and we now read the response
                        # to that call. In this case, we just re-try (up to 3 times), as the correct data might be
                        # next in line.
                        header, response_data = self.__read_from_serial()
                        if not _cmd.check_header(header, _address, cid):
                            if _cmd.is_nack(
                                    header, _address,
                                    cid) and response_data == bytearray([2]):
                                raise UnkownCommandException('Unknown command')
                            tries += 1
                            logger.warning(
                                "Header did not match command ({0})".format(
                                    tries))
                            if tries == 3:
                                raise Exception(
                                    "Header did not match command ({0})".
                                    format(tries))
                        else:
                            break

                    self.__last_success = time.time()
                    return_data = _cmd.read_output(response_data)
                    self.__communication_stats_calls['calls_succeeded'].append(
                        time.time())
                    self.__communication_stats_calls[
                        'calls_succeeded'] = self.__communication_stats_calls[
                            'calls_succeeded'][-50:]
                    return return_data
            except CommunicationTimedOutException:
                self.__communication_stats_calls['calls_timedout'].append(
                    time.time())
                self.__communication_stats_calls[
                    'calls_timedout'] = self.__communication_stats_calls[
                        'calls_timedout'][-50:]
                raise

        with self.__serial_lock:
            try:
                return do_once(address, cmd, *data)
            except UnkownCommandException:
                # This happens when the module is stuck in the bootloader.
                logger.error("Got UnkownCommandException")
                do_once(address, power_api.bootloader_jump_application())
                time.sleep(1)
                return self.do_command(address, cmd, *data)
            except CommunicationTimedOutException:
                # Communication timed out, try again.
                return do_once(address, cmd, *data)
            except Exception as ex:
                logger.exception("Unexpected error: {0}".format(ex))
                time.sleep(0.25)
                return do_once(address, cmd, *data)
    def do_command(self, address, cmd, *data):
        """ Send a command over the serial port and block until an answer is received.
        If the power module does not respond within the timeout period, a
        CommunicationTimedOutException is raised.

        :param address: Address of the power module
        :type address: 2 bytes string
        :param cmd: the command to execute
        :type cmd: :class`PowerCommand`
        :param data: data for the command
        :raises: :class`CommunicationTimedOutException` if power module did not respond in time
        :raises: :class`InAddressModeException` if communicator is in address mode
        :returns: dict containing the output fields of the command
        """
        if self.__address_mode:
            raise InAddressModeException()

        def do_once(_address, _cmd, *_data):
            """ Send the command once. """
            cid = self.__get_cid()
            send_data = _cmd.create_input(_address, cid, *_data)
            self.__write_to_serial(send_data)

            if _address == power_api.BROADCAST_ADDRESS:
                return None  # No reply on broadcast messages !
            else:
                header = None
                response_data = None
                try:
                    tries = 0
                    while True:
                        # In this loop we might receive data that didn't match the expected header. This might happen
                        # if we for some reason had a timeout on the previous call, and we now read the response
                        # to that call. In this case, we just re-try (up to 3 times), as the correct data might be
                        # next in line.
                        header, response_data = self.__read_from_serial()
                        if not _cmd.check_header(header, _address, cid):
                            if _cmd.is_nack(header, _address,
                                            cid) and response_data == "\x02":
                                raise UnkownCommandException()
                            tries += 1
                            LOGGER.warning(
                                "Header did not match command ({0})".format(
                                    tries))
                            if tries == 3:
                                raise Exception(
                                    "Header did not match command ({0})".
                                    format(tries))
                            else:
                                if not self.__verbose:
                                    self.__log('writing to', send_data)
                                    self.__log('reading header from', header)
                                    self.__log('reading data from',
                                               response_data)
                        else:
                            break
                except:
                    if not self.__verbose:
                        self.__log('writing to', send_data)
                        self.__log('reading header from', header)
                        self.__log('reading data from', response_data)
                    raise

                self.__last_success = time.time()
                return _cmd.read_output(response_data)

        with self.__serial_lock:
            try:
                return do_once(address, cmd, *data)
            except UnkownCommandException:
                # This happens when the module is stuck in the bootloader.
                LOGGER.error("Got UnkownCommandException")
                do_once(address, power_api.bootloader_jump_application())
                time.sleep(1)
                return self.do_command(address, cmd, *data)
            except CommunicationTimedOutException:
                # Communication timed out, try again.
                LOGGER.error("First communication timed out")
                return do_once(address, cmd, *data)
            except Exception as ex:
                LOGGER.exception("Unexpected error: {0}".format(ex))
                time.sleep(0.25)
                return do_once(address, cmd, *data)
Exemple #11
0
def bootload_energy_module(module_address, hex_file, power_communicator,
                           version):
    """
    Bootload a 12 port power module.

    :param module_address: The address of a power module (integer).
    :param hex_file: The filename of the hex file to write.
    :param power_communicator: Communication with the power modules.
    :param version: Version of the provided hexfile
    """
    firmware_version, hardware_version = get_module_firmware_version(
        module_address, power_api.ENERGY_MODULE, power_communicator)
    logger.info('E{0} - Version: {1} ({2})'.format(module_address,
                                                   firmware_version,
                                                   hardware_version))
    if firmware_version == version:
        logger.info('E{0} - Already up-to-date. Skipping')
        return
    logger.info('E{0} - Start bootloading'.format(module_address))

    try:
        logger.info('E{0} - Reading calibration data'.format(module_address))
        calibration_data = list(
            power_communicator.do_command(module_address,
                                          power_api.read_eeprom(12, 100),
                                          *[256, 100]))
        logger.info('E{0} - Calibration data: {1}'.format(
            module_address, ','.join([str(d) for d in calibration_data])))
    except Exception as ex:
        logger.info('E{0} - Could not read calibration data: {1}'.format(
            module_address, ex))
        calibration_data = None

    reader = HexReader(hex_file)

    logger.info('E{0} - Going to bootloader'.format(module_address))
    power_communicator.do_command(
        module_address, power_api.bootloader_goto(power_api.ENERGY_MODULE), 10)
    logger.info('E{0} - Bootloader version: {1}'.format(
        module_address,
        get_module_firmware_version(module_address, power_api.ENERGY_MODULE,
                                    power_communicator)))

    try:
        logger.info('E{0} - Erasing code...'.format(module_address))
        for page in range(6, 64):
            power_communicator.do_command(module_address,
                                          power_api.bootloader_erase_code(),
                                          page)

        logger.info('E{0} - Writing code...'.format(module_address))
        for address in range(0x1D006000, 0x1D03FFFB, 128):
            data = reader.get_bytes_version_12(address)
            power_communicator.do_command(
                module_address,
                power_api.bootloader_write_code(power_api.ENERGY_MODULE),
                *data)
    finally:
        logger.info('E{0} - Jumping to application'.format(module_address))
        power_communicator.do_command(module_address,
                                      power_api.bootloader_jump_application())

    tries = 0
    while True:
        try:
            tries += 1
            logger.info(
                'E{0} - Waiting for application...'.format(module_address))
            logger.info('E{0} - Version: {1}'.format(
                module_address,
                get_module_firmware_version(module_address,
                                            power_api.ENERGY_MODULE,
                                            power_communicator)))
            break
        except Exception:
            if tries >= 3:
                raise
            time.sleep(1)

    if calibration_data is not None:
        time.sleep(1)
        logger.info('E{0} - Restoring calibration data'.format(module_address))
        power_communicator.do_command(module_address,
                                      power_api.write_eeprom(12, 100),
                                      *([256] + calibration_data))

    logger.info('E{0} - Done'.format(module_address))