FlashTool Module#

LENZ BiSS Protocol Implementation

Provides BiSS encoder protocol standarts and utilities.

Author:

LENZ ENCODERS, 2020-2026

class lenz_flashtool.flashtool.BiSSFaultState(*values)#

Bases: IntEnum

BiSS interface fault state enumeration.

Defines possible fault states reported by the BiSS interface.

BISS_FAULT_IDL = 1#
BISS_FAULT_READ_CRC = 3#
BISS_FAULT_WRITE = 2#
BISS_NO_FAULTS = 0#
class lenz_flashtool.flashtool.FlashTool(port_description_prefixes=('XR21V',), baud_rate=12000000)#

Bases: SerialIOMixin, BiSSIOMixin, EncoderControlMixin, DataStreamingMixin, BootloaderMixin

Main interface for interacting with BiSS C encoders via FlashTool device, connected to a serial port. FlashTool device has 2 channels for encoder connection. Commands perform on channel 2 if not mentioned.

This class provides methods for: - Establishing serial communication with FlashTool device - Sending commands and data to the encoder - Reading encoder status and data - Performing firmware updates - Executing calibration routines

The class implements the singleton pattern to ensure only one connection exists.

Typical usage:
>>> with FlashTool() as ft:
...     ft.biss_read_snum()  # Read serial number of the encoder (on channel 2)
...     ft.encoder_power_cycle()  # Perform power cycle on channel 2
...     ft.biss_write_command('reboot2bl')  # Reboot to bootloader
close()#

Closes the serial port connection and performs cleanup.

Executes all registered cleanup handlers, closes the serial port, restores original signal handlers, and resets the singleton instance. Logs the closure of the connection.

Returns:

None

Example

>>> ft = FlashTool()
>>> ft.close()
INFO: FlashTool: COM3 closed.
enable_signal_handling(signals=(Signals.SIGINT,))#

Enables signal handling for the specified signals to ensure proper cleanup.

Registers signal handlers to call the close method when the specified signals are received, preserving the original handlers for restoration during cleanup.

Parameters:

signals (Tuple[int, ...]) – Tuple of signal numbers to handle (e.g., signal.SIGINT). Defaults to (signal.SIGINT,).

Returns:

The FlashTool instance for method chaining.

Return type:

FlashTool

Example

>>> ft = FlashTool().enable_signal_handling((signal.SIGINT, signal.SIGTERM))
register_cleanup(handler)#

Registers a cleanup function to be executed during close or on SIGINT.

Allows scripts to define custom cleanup operations, such as resetting hardware states or closing additional resources, which are called when the FlashTool connection is closed.

Parameters:

handler (Callable[[], None]) – A callable with no arguments that performs cleanup operations.

Returns:

The FlashTool instance for method chaining.

Return type:

FlashTool

Example

>>> def custom_cleanup():
...     elmo.motor_off()
...     print("Cleaning up resources. Stopping motor.")
>>> ft = FlashTool().register_cleanup(custom_cleanup)
exception lenz_flashtool.flashtool.FlashToolError(message, error_type=UARTErrorType.ERROR_TYPE_NONE, error_code=UARTErrorCode.UART_ERROR_NONE, fault_state=None)#

Bases: Exception

Custom exception for FlashTool errors with detailed error information.

This exception provides rich context about what went wrong, including error type, specific error code, and BiSS fault state when applicable.

error_type#

Type of error (UART or BiSS)

error_code#

Specific error code

fault_state#

BiSS fault state (if applicable)

message#

Human-readable error message

BISS_FAULT_MESSAGES = {BiSSFaultState.BISS_NO_FAULTS: 'No BiSS faults', BiSSFaultState.BISS_FAULT_IDL: 'BiSS IDLE fault', BiSSFaultState.BISS_FAULT_WRITE: 'BiSS write fault', BiSSFaultState.BISS_FAULT_READ_CRC: 'BiSS read CRC fault'}#
ERROR_MESSAGES = {UARTErrorCode.UART_ERROR_NONE: 'No UART errors', UARTErrorCode.UART_ERROR_CRC: 'UART CRC error', UARTErrorCode.UART_ERROR_QUEUE_FULL: 'UART queue full', UARTErrorCode.UART_ERROR_BISS: 'BiSS communication error', UARTErrorCode.UART_ERROR_BISS_WRITE_FAULT: 'BiSS write fault', UARTErrorCode.UART_ERROR_BISS_READ_FAULT: 'BiSS read fault', UARTErrorCode.UART_ERROR_LEN_DATA_IS_ZERO: 'Zero length data', UARTErrorCode.UART_ERROR_LEN_IS_NOT_CORRECT: 'Incorrect data length', UARTErrorCode.UART_ERROR_INVALID_CMD: 'Incorrect cmd', UARTErrorCode.UART_ERROR_INVALID_MODE: 'Incorrect mode'}#
property details: Dict[str, Any]#

Return detailed error information as a dictionary.

Returns:

Dictionary with error_type, error_code, fault_state, and message

is_biss_error()#

Check if this is a BiSS-related error.

Return type:

bool

Returns:

True if error type is BiSS, False otherwise

is_uart_error()#

Check if this is a UART-related error.

Return type:

bool

Returns:

True if error type is UART, False otherwise

class lenz_flashtool.flashtool.UARTErrorCode(*values)#

Bases: IntEnum

UART error code enumeration.

Specific error codes providing detailed information about UART errors.

UART_ERROR_BISS = 3#
UART_ERROR_BISS_READ_FAULT = 5#
UART_ERROR_BISS_WRITE_FAULT = 4#
UART_ERROR_CRC = 1#
UART_ERROR_INVALID_CMD = 8#
UART_ERROR_INVALID_MODE = 9#
UART_ERROR_LEN_DATA_IS_ZERO = 6#
UART_ERROR_LEN_IS_NOT_CORRECT = 7#
UART_ERROR_NONE = 0#
UART_ERROR_QUEUE_FULL = 2#
class lenz_flashtool.flashtool.UARTErrorType(*values)#

Bases: IntEnum

UART error type classification.

Defines the high-level category of error reported by the device.

ERROR_TYPE_BISS = 1#
ERROR_TYPE_NONE = 0#
ERROR_TYPE_UART = 2#
class lenz_flashtool.flashtool.UartBootloaderSeq#

Bases: object

UART_SEQ_ANSWER_TO_EXIT_BL = [0, 0, 0, 0, 0]#

Response sequence acknowledging successful bootloader exit.

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0F][UART_SEQ_EXIT_BL][CHECKSUM] Response: [DATA_SIZE][REG_ADDR][0x1F][UART_SEQ_ANSWER_TO_EXIT_BL][CHECKSUM]

Command Sequence:
Request:
>>> :0500000f00000001ffXX  # [0x00, 0x00, 0x00, 0x01, 0xFF] + checksum
Response:
>>> :0500001f0000000000XX  # [0x00, 0x00, 0x00, 0x00, 0x00] + checksum
Usage:
  • Validated in reboot_to_fw_irs() to confirm bootloader exit

  • All-zero pattern is expected for successful operation

  • Non-zero response indicates bootloader exit failure

Note

  • The device typically resets immediately after sending this response

  • Communication should be re-established in normal firmware mode after reset

  • Timeout may occur if waiting for further responses after this sequence

Type:

list

UART_SEQ_ANSWER_TO_STAY_IN_BL_FT = [6, 177, 78, 249]#

Response sequence to keep device in bootloader mode (FlashTool variant).

Response:
  • 4-byte acknowledgment sequence confirming bootloader mode entry

  • Byte order: [0x06, 0xB1, 0x4E, 0xF9] (FlashTool format)

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0F][UART_SEQ_STAY_IN_BL][CHECKSUM] Response: [DATA_SIZE][REG_ADDR][0x1F][UART_SEQ_ANSWER_TO_STAY_IN_BL][CHECKSUM]

Command Sequence:
Request:
>>> :0400000f0531f6b9XX  # [0x05, 0x31, 0xF6, 0xB9] + checksum
Response:
>>> :0400001ff94eb106XX  # [0x06, 0xB1, 0x4E, 0xF9] + checksum
Usage:
  • Typically sent immediately after device reset/power cycle

  • Must be acknowledged before proceeding with firmware operations

  • Data and address fields may contain specific handshake parameters

Type:

list

UART_SEQ_ANSWER_TO_STAY_IN_BL_IRS = [249, 78, 177, 6]#

Response sequence to keep device in bootloader mode (IRS variant).

Response:
  • 4-byte acknowledgment sequence confirming bootloader mode entry

  • Byte order: [0xF9, 0x4E, 0xB1, 0x06] (IRS format)

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0F][UART_SEQ_STAY_IN_BL][CHECKSUM] Response: [DATA_SIZE][REG_ADDR][0x1F][UART_SEQ_ANSWER_TO_STAY_IN_BL][CHECKSUM]

Command Sequence:
Request:
>>> :0400000f0531f6b9XX  # [0x05, 0x31, 0xF6, 0xB9] + checksum
Response:
>>> :0400001ff94eb106XX  # [0x06, 0xB1, 0x4E, 0xF9] + checksum
Usage:
  • Typically sent immediately after device reset/power cycle

  • Must be acknowledged before proceeding with firmware operations

  • Data and address fields may contain specific handshake parameters

Type:

list

UART_SEQ_EXIT_BL = [0, 0, 0, 1, 255]#

Request sequence to exit bootloader mode and jump to main firmware.

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0F][UART_SEQ_EXIT_BL][CHECKSUM] Response: [DATA_SIZE][REG_ADDR][0x1F][UART_SEQ_ANSWER_TO_EXIT_BL][CHECKSUM]

Command Sequence:
Request:
>>> :0500000f00000001ffXX  # [0x00, 0x00, 0x00, 0x01, 0xFF] + checksum
Response:
>>> :0500001f0000000000XX  # [0x00, 0x00, 0x00, 0x00, 0x00] + checksum
Usage:
  • Sent after successful firmware upload and verification

  • Device will reset and begin executing main firmware after acknowledgment

  • The 0xFF byte typically triggers the actual reset or jump operation

Note

  • Ensure all firmware operations are complete before sending this command

  • Device may perform immediate reset after sending the response

  • The all-zero response indicates command acceptance before reset

Type:

list

UART_SEQ_STAY_IN_BL = [5, 49, 246, 185]#

Request sequence to keep device in bootloader mode and prevent firmware execution.

Response:
  • 4-byte acknowledgment sequence confirming bootloader mode entry

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0F][UART_SEQ_STAY_IN_BL][CHECKSUM] Response: [DATA_SIZE][REG_ADDR][0x1F][UART_SEQ_ANSWER_TO_STAY_IN_BL][CHECKSUM]

Command Sequence:
Request:
>>> :0400000f0531f6b9df  # [0x05, 0x31, 0xF6, 0xB9] + checksum
Response:
>>> :0400001ff94eb106df  # [0x06, 0xB1, 0x4E, 0xF9] + checksum
Usage:
  • Typically sent immediately after device reset/power cycle

  • Must be acknowledged before proceeding with firmware operations

  • Data and address fields may contain specific handshake parameters

Type:

list

class lenz_flashtool.flashtool.UartCmd(*values)#

Bases: IntEnum

Enumeration of UART commands for communication with the FlashTool system.

This class defines all the hexadecimal command codes used for controlling power, channel selection, and data communication with the FlashTool hardware.

CMD_CH1_POWER_OFF = 8#

Command to power off encoder on channel 1.

Usage:
  • Sent to deactivate power to the secondary encoder (channel 1)

  • Useful for power management in dual-encoder systems

  • Typically used during maintenance or reconfiguration

  • Expects no additional parameters

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x08][DUMMY_DATA][CHECKSUM] Response: None

Examples

>>>  :01004008DDDA
>>>  :04000008DDAADDAAE6
Type:

int

CMD_CH1_POWER_ON = 9#

Command to power on the encoder on channel 1.

Usage:
  • Sent to activate power to the secondary encoder (channel 1)

  • Should be preceded by channel selection if needed

  • Requires stabilization time (0.1s) before encoder communication

  • Expects no additional parameters

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x09][DUMMY_DATA][CHECKSUM] Response: None

Examples

>>>  :0100000903F3
>>>  :0300A009A0A0A173
Type:

int

CMD_NVRST = 131#

Command to perform a non-volatile reset of the FlashTool.

Usage:
  • Clears any temporary settings

  • Requires stabilization time (0.1s) before encoder communication

  • Data and address in packet doesn’t matter

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x83][DUMMY_DATA][CHECKSUM] Response: None

Examples

>>>  :01004083221A
>>>  :0400408311111111F5
Type:

int

CMD_POWER_OFF = 11#

Command to power off encoder on channel 2.

Usage:
  • Sent to deactivate power to the encoder connected to channel 2

  • Typically used during maintenance or reconfiguration

  • Expects no additional parameters

  • Data and address in packet doesn’t matter

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x0B][DUMMY_DATA][CHECKSUM] Response: None

Examples

>>>  :0100400BFFB5
>>>  :0400400B111111116D
Type:

int

CMD_POWER_ON = 12#

Command to power on the encoder on channel 2.

Usage:
  • Sent to activate power to the encoder connected to channel 2

  • Should be followed by a stabilization delay (0.1s) before communication

  • Expects no additional parameters

  • Data and address in packet doesn’t matter

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x0C][DUMMY_DATA][CHECKSUM] Response: None

Examples

>>>  :0100400C0AA9
>>>  :0300400CAABBCC80
Type:

int

CMD_REBOOT_TO_BL = 255#

Command to reboot to bootloader.

Usage:
  • Used for entering bootloader

  • Address in packet doesn’t matter

Note

Need to use bootloader cmd to reboot to main fw.

Packet Structure:
  • Request: [0x01][REG_ADDR][0xFF][DUMMY_DATA][CHECKSUM]

Example

>>> :010000ff0000
Type:

int

CMD_SELECT_CH1_MODE = 14#

Command to select FlashTool channel 1 SPI mode. Works for BISS_MODE_SPI_SPI.

Usage:
  • Sent before any channel-specific operations

  • Parameter:

    0x00 for CH1_LENZ_BISS, 0x01 for CH1_LIR_SSI, 0x02 for CH1_LIR_BISS_21B

  • Defines all subsequent communications via SPI for channel 1

  • Address in packet doesn’t matter

Note

FlashTool current sensor mode is persistent until changed or power cycled Default: CH1_LENZ_BISS (0x00)

Packet Structure:

Request: [01][REG_ADDR][0x0E][CHANNEL_BYTE][CHECKSUM] Where CHANNEL_BYTE is 0x00 or 0x01 or 0x02

Example

>>> :0100000e01ed  Select channel 1 SPI mode - CH1_LENZ_BISS
CMD_SELECT_FLASHTOOL_CURRENT_SENSOR_MODE = 17#

Command to select FlashTool current sensor mode.

Black FlashTool has Current Sensor mode. Green FlashTool has NOT Current Sensor mode.

Usage:
  • Sent before any channel-specific operations

  • Parameter:

    0x00 for CURRENT_SENSOR_MODE_DISABLE, 0x01 for CURRENT_SENSOR_MODE_ENABLE

  • Defines all subsequent communications via SPI, AB (incremental), UART for channels 1 and 2 until changed

  • Address in packet doesn’t matter

Note

FlashTool current sensor mode is persistent until changed or power cycled Default: CURRENT_SENSOR_MODE_ENABLE (0x01)

Packet Structure:

Request: [01][REG_ADDR][0x11][CHANNEL_BYTE][CHECKSUM] Where CHANNEL_BYTE is 0x00 or 0x01

Example

>>> :0100001101ed  Select current sensor mode - CURRENT_SENSOR_MODE_ENABLE
Type:

int

CMD_SELECT_FLASHTOOL_MODE = 1#

Command to select FlashTool mode for communication.

Usage:
  • Sent before any channel-specific operations

  • Parameter:

    0x00 for BISS_MODE_SPI_SPI, 0x01 for BISS_MODE_AB_UART, 0x02 for BISS_MODE_SPI_UART_IRS, 0x03 for BISS_MODE_AB_SPI 0x04 for BISS_MODE_DEFAULT_SPI

  • Defines all subsequent communications via SPI, AB (incremental), UART for channels 1 and 2 until changed

  • Address in packet doesn’t matter

Note

FlashTool mode is persistent until changed or power cycled Default: BISS_MODE_DEFAULT_SPI (0x04) - Channel 1: Without communication, Channel 2: SPI

Packet Structure:

Request: [01][REG_ADDR][0x01][CHANNEL_BYTE][CHECKSUM] Where CHANNEL_BYTE is 0x00, 0x01, 0x02 or 0x03

Example

>>> :0100000100FE  Select FlashTool mode - BISS_MODE_SPI_SPI
Type:

int

CMD_SELECT_SPI_CH = 10#

Command to select SPI communication channel.

Usage:
  • Sent before any channel-specific operations

  • Parameter: 0x00 for channel 1, 0x01 for channel 2

  • Affects all subsequent SPI communications until changed

Note

Channel selection is persistent until changed or power cycled Default: Channel 2 (0x01)

Packet Structure:

Request: [01][REG_ADDR][0x0A][CHANNEL_BYTE][CHECKSUM] Where CHANNEL_BYTE is 0x00 or 0x01

Example

>>> :0100400A00F4  Select channel 1
Type:

int

CMD_VAL_ADD = 16#

Value added to CMD in the Response Packet

Response:

[DUMMY_DATA_SIZE][REG_ADDR][CMD+CMD_VAL_ADD][DUMMY_DATA][CHECKSUM]

Type:

int

HEX_IRS_ENC_WRITE_READ_CMD = 15#

Command to write data to encoder registers.

Usage:
  • Used for configuration and parameter setting

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0D][DATA_MSB][DATA_LSB][CHECKSUM] Response: None

Example

>>>  :0100400D05AD
Type:

int

HEX_READ_ANGLE_TWO_ENC_AB_SPI = 120#

Command to read angle data via AB (incremental) interface over SPI.

Usage:
  • SPI angle reading

  • Provides quadrature-encoded equivalent output

Note

channel 1 - AB channel 2 - SPI

Type:

int

HEX_READ_ANGLE_TWO_ENC_AB_UART = 121#

Command to read angle data via AB (incremental) interface over UART.

Usage:
  • Alternative to SPI angle reading

  • Provides quadrature-encoded equivalent output

  • Faster update rate than SPI in some implementations

Type:

int

HEX_READ_ANGLE_TWO_ENC_SPI = 128#

Command to read angle data from two encoders via SPI.

Usage:
  • Continuous streaming mode for dual-encoder reading

  • Requires both encoders to be powered on

  • Returns multiple measurement frames in each response packet

Response Format:

Each 245-byte packet contains:

>>> [Header][FrameCount][Reserved][DataFrames...][Checksum]

Where:

  • Header: [0xF0, 0x00, 0x00, 0x90] (fixed pattern)

  • FrameCount: Number of valid data frames (typically 30)

  • DataFrames: 30 measurement frames (8 bytes each):

>>> [ENC1_LOW][ENC1_MID][ENC1_HIGH][ENC1_COUNTER]
>>> [ENC2_LOW][ENC2_MID][ENC2_HIGH][ENC2_COUNTER]
  • Checksum: 1 byte (sum of first 244 bytes modulo 256)

Data Interpretation:
>>> Encoder Angle = (HIGH << 16) | (MID << 8) | LOW

Counter = Single byte turn counter

Example Packet Structure:
>>> F0 00 00 90 [30 frames...] [checksum]
Type:

int

HEX_READ_CMD = 130#

Generic read command for encoder data.

Usage:
  • Followed by register address and dummy data with size equal to required read data size

  • Can read various status and configuration registers

  • Response length depends on target register

Packet Structure:
  • Request: [DUMMY_DATA_SIZE][REG_ADDR][0x82][DUMMY_DATA][CHECKSUM]

  • Response: [DATA_SIZE][REG_ADDR][0x92][DATA][CHECKSUM]

Examples

Read Example:
>>>  :01004082013C
Response:
>>>  0x10040920528

Another example writing 3 to BSEL register (changing BiSS Bank to 3):

Requests:
>>>  :0100400D03AF  Writing 3 to register 0x40
>>>  :01004082013C  Reading register 0x40
Response:
>>>  0x1004092032A  Register 0x40 keeps 0x03
Type:

int

HEX_READ_ENC2_CURRENT = 18#

Command to read current from encoder on channel 2.

Usage:
  • Single data frame

  • Requires encoder to be powered on

  • Returns one measurement frame in each response packet

  • Address in packet doesn’t matter

Packet Structure:

Request: [DUMMY_DATA_SIZE][REG_ADDR][0x12][DUMMY_DATA][CHECKSUM]

Where:

  • DUMMY_DATA_SIZE: 4 bytes

Example Request Packet Structure:
>>> 0400001200010203e4
Response Format:

Data frame contains:

>>> [Header][DataFrame][Checksum]

Where:

  • Header: [0x04, 0x00, 0x00, 0x22] (fixed pattern)

  • DataFrame: 1 measurement frame (4 bytes):

>>> [ENC2_CURRENT_HIGH][ENC2_CURRENT_MID][ENC2_CURRENT_LOW]
  • Checksum: 1 byte (sum of first 8 bytes modulo …)

Example Response Packet Structure:
>>> 04 00 00 22 [frame] [checksum]
Type:

int

HEX_READ_INSTANT_ANGLE_ENC_SPI = 16#

Command to read instant angle data from encoder via SPI.

Usage:
  • Single data frame for encoder reading

  • Requires encoder to be powered on

  • Returns one measurement frame in each response packet

Response Format:

Data frame contains:

>>> [Header][DataFrame][Checksum]

Where:

  • Header: [0x04, 0x00, 0x00, 0x20] (fixed pattern)

  • DataFrame: 1 measurement frame (8 bytes):

>>> [ENC2_LOW][ENC2_MID][ENC2_HIGH][ENC2_COUNTER]
  • Checksum: 1 byte (sum of first 12 bytes modulo …)

Data Interpretation:
>>> Encoder Angle = (HIGH << 16) | (MID << 8) | LOW

Counter = Single byte turn counter

Example Packet Structure:
>>> 04 00 00 20 [1 frame...] [checksum]
Type:

int

HEX_READ_INSTANT_ANGLE_PACKET_ENC_SPI = 19#

Command to read instant extended angle packet from encoder via SPI.

Usage:
  • Single data frame for encoder reading with extended status information

  • Requires encoder to be powered on

  • Returns one measurement packet in each response packet

  • Includes additional status flags and CRC for data integrity verification

Response Format:

Data frame contains:

>>> [Header][DataPacket][Checksum]

Where:

  • Header: [0x06, 0x00, 0x00, 0x23] (fixed pattern)

  • DataPacket: 1 measurement packet (6 bytes):

>>> [ENC2_LOW][ENC2_MID][ENC2_HIGH][ENC2_COUNTER][ENC2_STATUS][ENC2_CRC]
  • Checksum: 1 byte (sum of first 10 bytes modulo …)

Data Interpretation:
>>> Encoder Angle = (HIGH << 16) | (MID << 8) | LOW

Counter = Single byte time-of-life counter (8-bit) Status = Single byte status flags including: Bit 0: Warning flag (nW); Bit 1: Error flag (nE); Bits 2-7: Reserved/encoder-specific status bits. CRC = 6-bit CRC checksum for data validation (stored in low 6 bits)

Example Packet Structure:
>>> 06 00 00 23 [1 packet...] [checksum]

Notes

  • Extended format compared to basic angle reading

  • Provides additional diagnostic information (nW/nE flags)

  • Includes CRC for enhanced data integrity checking

  • Maintains backward compatibility with angle calculation

Type:

int

HEX_WRITE_CMD = 13#

Command to write data to encoder registers.

Usage:
  • Used for configuration and parameter setting

Packet Structure:

Request: [DATA_SIZE][REG_ADDR][0x0D][DATA_MSB][DATA_LSB][CHECKSUM] Response: None

Example

>>>  :0100400D05AD
Type:

int

PKG_INFO_LENGTH = 5#

Packet INFO constant structure length of 5 bytes

Packet Structure:

Request Packet: [DUMMY_DATA_SIZE][REG_ADDR][ CMD ][DUMMY_DATA][CHECKSUM] [ 1 byte ][2 bytes ][1 byte][———-][ 1 byte ]

Response Packet: [DUMMY_DATA_SIZE][REG_ADDR][CMD+CMD_VAL_ADD][DUMMY_DATA][CHECKSUM] [ 1 byte ][2 bytes ][ 1 byte ][———-][ 1 byte ]

Type:

int

RX_DATA_LENGTH_CURRENT = 4#

Data length for commands: HEX_READ_ENC2_CURRENT: 0x12

Type:

int

RX_DATA_LENGTH_IRS = 252#

Data length for command: HEX_IRS_ENC_WRITE_READ_CMD: 0x0F

Type:

int

UART_COMMAND_READ_DIAGNOSTIC_STATUS = 254#

Command to read comprehensive diagnostic status from FlashTool device.

Usage:
  • Retrieves complete error and fault state information from the device

  • Essential for fault detection and system health monitoring

  • Returns error type, error codes, and BiSS fault states in single response

  • Should be called periodically in critical applications or after communication errors

Response Format:

Each 3-byte response packet contains:

>>> [ErrorType][ErrorCode][FaultState]

Where:

  • ErrorType (byte 0): Type of error present (0x00=None, 0x01=BiSS, 0x02=UART)

  • ErrorCode (byte 1): Specific UART error code (detailed error identification)

  • FaultState (byte 2): BiSS interface fault state (BiSS-specific errors)

Error Type Interpretation:
>>> ERROR_TYPE_NONE = 0x00  # No errors detected
>>> ERROR_TYPE_BISS = 0x01  # BiSS communication error
>>> ERROR_TYPE_UART = 0x02  # UART protocol error
UART Error Codes:
>>> UART_ERROR_NONE = 0x00              # No error
>>> UART_ERROR_CRC = 0x01               # CRC verification failed
>>> UART_ERROR_QUEUE_FULL = 0x02        # UART queue overflow
>>> UART_ERROR_BISS = 0x03              # BiSS communication error
>>> UART_ERROR_BISS_WRITE_FAULT = 0x04  # BiSS write operation failed
>>> UART_ERROR_BISS_READ_FAULT = 0x05   # BiSS read operation failed
>>> UART_ERROR_LEN_DATA_IS_ZERO = 0x06  # Zero-length data received
>>> UART_ERROR_LEN_IS_NOT_CORRECT = 0x07 # Incorrect data length
>>> UART_ERROR_INVALID_CMD = 0x08       # Invalid command received
>>> UART_ERROR_INVALID_MODE = 0x09      # Invalid operation mode
BiSS Fault States:
>>> BISS_NO_FAULTS = 0x00       # No faults detected
>>> BISS_FAULT_IDL = 0x01       # IDLE state fault (line idle timeout)
>>> BISS_FAULT_WRITE = 0x02     # Write operation fault (data write failure)
>>> BISS_FAULT_READ_CRC = 0x03  # Read CRC verification fault
Example Response Packets:
>>> UART CRC error: [0x02, 0x01, 0x00]
>>> BiSS IDLE fault: [0x01, 0x00, 0x01]

Notes

  • Non-zero status codes in ErrorCode or FaultState fields (when ErrorType=NONE)

may indicate warning conditions requiring attention - Should be called after any communication failure to identify root cause - Response length is fixed at 3 bytes regardless of error presence - Error states are latched and persist until cleared or device reset - Some error conditions may require device reinitialization for recovery

Type:

int

lenz_flashtool.flashtool.biss_send_dif(file_path, pbar=None)#

Main function for transmitting DIF tables to BiSS device.

Parameters:
  • file_path (str) – Path to input DIF CSV file

  • pbar (Any | None) – Optional progress bar object

Return type:

None

lenz_flashtool.flashtool.biss_send_hex(file_path, nonce=None, pbar=None)#

Main function for transmitting HEX files to BiSS device.

Parameters:
  • file_path (str) – Path to input HEX file

  • nonce (int | None) – Optional security nonce value

  • pbar (Any | None) – Optional progress bar object

Return type:

None

lenz_flashtool.flashtool.calculate_checksum(hex_data)#

Calculate Intel HEX-style checksum for a hex string.

Parameters:

hex_data (str) – Hex string without leading ‘:’ or ending checksum

Return type:

int

Returns:

Checksum byte (0-255)

Example

>>> calculate_checksum("10010000214601360121470136007EFE09D21901")
64
lenz_flashtool.flashtool.connect_and_enter_fw(timeout_s=20, retry_delay=0.5)#

Waits for a COM port with a specific prefix to become available, connects to it, and sends a firmware entry command once.

The function will continuously monitor for the specified COM port until either: - The port is found and the command is successfully sent (returns True) - The timeout period is exceeded (returns False)

Parameters:
  • timeout_s (int) – Maximum time in seconds to wait for the port (default: 20)

  • retry_delay (float) – Delay in seconds between port availability checks (default: 0.5)

Returns:

True if command was successfully sent, False if timeout occurred

Return type:

bool

lenz_flashtool.flashtool.connect_and_stay_in_bl(timeout_s=20, retry_delay=0.5)#

Wait for COM port and send boot sequence to stay in bootloader mode.

Continuously scans for available COM ports matching the specified prefix and attempts to establish a bootloader connection. Implements a robust handshake protocol with configurable timeout and retry behavior.

Parameters:
  • timeout_s (int) – Maximum time in seconds to attempt connection (default: 20)

  • retry_delay (float) – Delay in seconds between port scan attempts (default: 0.5)

Returns:

True if successful handshake, False if timeout reached

Return type:

bool

Raises:
  • RuntimeError – If serial communication fails catastrophically

  • ValueError – If invalid parameters are provided

Side Effects:
  • Attempts to open and configure serial ports

  • Modifies device state if successful

  • Outputs status messages to console and log

Example

>>> # Wait up to 20 seconds for bootloader connection
>>> success = connect_and_stay_in_bl(timeout_s=30)
>>> if success:
...     # Proceed with firmware update
lenz_flashtool.flashtool.dif2hex(DifTable, filename, start_page)#

Convert a Diff table to Intel HEX format and save to a file.

This function takes a byte array representing a Diff table, converts it to Intel HEX format with proper address handling and checksums, and writes the result to the specified file. The output includes extended address records, data records, a CRC32 record, and an end-of-file record.

Parameters:
  • DifTable (bytes) – The input byte array containing the data to be converted.

  • filename (str) – The path of the output file where the HEX data will be written.

  • start_page (int) – The starting page number used to calculate the initial address offset. Each page is 2048 bytes (0x800).

Returns:

The function writes the result to a file but doesn’t return anything.

Return type:

None

The function handles: - 64KB address boundary crossing with extended address records - Proper checksum calculation for all record types - Generation of data records with 16 bytes per line (standard HEX format) - Addition of a CRC32 record (type 0x03) at the end of the file - Proper end-of-file marker

Example

>>> data = bytes([0x01, 0x02, 0x03, 0x04])
>>> dif2hex(data, "output.hex", 24)
# Creates output.hex with the converted data
lenz_flashtool.flashtool.generate_hex_line(address, command, data)#

Generate a formatted hex line for communication with a device.

Parameters:
  • address (int) – The 16-bit address field.

  • command (int) – The command byte.

  • data (list) – A list of data bytes to include in the hex line.

Returns:

The formatted hex line string, including the starting ‘:’ and checksum.

Return type:

str

lenz_flashtool.flashtool.get_nonce(filename)#

Retrieve the nonce values from a binary file.

Parameters:

filename (str) – The base filename (without extension) of the nonce file.

Returns:

A list of 32-bit unsigned integers representing the nonces.

Return type:

list

lenz_flashtool.flashtool.init_logging(logfilename=None, stdout_level=20, file_level=10, logger_name='lenz_flashtool')#

Initializes the logging system with console and optional file handlers.

This function sets up a logger with a stdout handler and, if a filename is provided, a file handler. Each handler has its own logging level and formatter.

Parameters:
  • logfilename (str | None) – The name of the file to log messages to. If None, no file logging occurs.

  • stdout_level (int) – The logging level for the stdout handler (default: INFO).

  • file_level (int) – The logging level for the file handler (default: DEBUG).

  • logger_name (str) – The name of the logger to configure (default: “lenz_flashtool”). If None, the root logger is configured.

Returns:

The configured logger instance.

Return type:

Logger

Raises:

ValueError – If logging levels are invalid.

lenz_flashtool.flashtool.prep_hex(filepath, section_id, count, desc)#

Main function to prepare HEX file for firmware update.

Parameters:
  • filepath (str) – Path to the input HEX file to be processed

  • section_id (int) – Memory section identifier (used to calculate base address)

  • count (int) – Number of bytes in the section that need hash protection

  • desc (str) – Description tag used to locate the hash file (format: lenz_hash_{desc}.bin)

Returns:

Writes the processed output to <input_filename>_op.hex

Return type:

None

Raises:
  • FileNotFoundError – If either the input HEX file or hash binary file doesn’t exist

  • IOError – If there are file access/permission issues

lenz_flashtool.flashtool.read_hex_file_irs(filepath)#

Reads an Intel HEX file and returns a list of hex record strings.

Opens the specified HEX file, reads its contents, and extracts the hex record strings (excluding the initial colon ‘:’ in each line). Each line is expected to be an Intel HEX record starting with ‘:’.

Parameters:

filepath (str) – The path to the HEX file.

Returns:

A list of hex record strings from the file.

Return type:

list[str]

Raises:

SystemExit – If the file does not exist or cannot be opened.

Example

>>> records = readhex('firmware.hex')
>>> print(records[0])
'10010000214601360121470136007EFE09D2190140'
lenz_flashtool.flashtool.send_hex_irs_enc(filename)#

Download and flash a hex file to the IRS encoder with verification.

This function handles the complete firmware update process for the IRS encoder, including bootloader entry, hex file transmission, CRC verification, and returning to normal operation mode. The process includes retry logic for robust operation.

Process Flow: 1. Establish connection with encoder in bootloader mode 2. Read and parse the hex file 3. Transmit data pages with appropriate command handling 4. Verify each page using CRC checks 5. Exit bootloader and return to firmware mode 6. Implement 3-attempt retry logic for fault tolerance

Parameters:

filename (str) – Path to the hex file to be uploaded to the encoder. The file should be in Intel HEX format.

Returns:

True if the entire upload process completes successfully,

False if any critical step fails.

Return type:

bool

Example

>>> success = send_hex_irs_enc("firmware_v1.2.hex")
>>> if success:
...     print("Firmware update completed successfully")
... else:
...     print("Firmware update failed")