This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TICSPRO-SW: A few TICS Pro issues

Part Number: TICSPRO-SW
Other Parts Discussed in Thread: USB2ANY, LMK05318B, LMK5B12204

Tool/software:

TICS Pro v1.7.9.0

* When TICS Pro starts with a USB2ANY connected, it writes registers R68, R202, R203, R204, R205, R206, R207 to the device.  Should it really be writing registers to a device before it's even loaded a tcs file? And why those registers specifically?
Welcome to TICS Pro. Version -> 1.7.9.0, 27-May-25
Loading Device LMK05318B...
Detected 1 USB2ANY interfaces
Wrote Register R68 (0x44) as 0x00 4408
Wrote Register R68 (0x44) as 0x00 4408
Wrote Register R202 (0xCA) as 0x00 CA00
Wrote Register R203 (0xCB) as 0x00 CB00
Wrote Register R204 (0xCC) as 0x00 CC38
Wrote Register R68 (0x44) as 0x00 4408
Wrote Register R68 (0x44) as 0x00 4408
Wrote Register R205 (0xCD) as 0x00 CD00
Wrote Register R206 (0xCE) as 0x00 CE00
Wrote Register R207 (0xCF) as 0x00 CF38
Completed loading Device LMK05318B. Version = 2025-05-06, v0.12.8

* TICS Pro doesn't seem to save the  AutoUpdate option.

* When TICS Pro loads a tcs file with a USB2ANY connected it automatically writes all registers it to the device which I don't think is a good idea, especially if AutoUpdate is off.  It also writes it even if the device in the tcs file doesn't match the device connected.  I.E if you have a LMK05318B connected and load a LMK5B12204 tcs file to use as a base, TICS Pro still writes all the registers.  Also not a good idea.

* It also writes all registers if you select one of the default configurations even if AutoUpdate is off.  This really isn't a good idea.

* On the Wizard Set Reference page, If you change the value of PRIREF frequency it often resets the interface type to AC, hysteresis = 200mv

  • Should it really be writing registers to a device before it's even loaded a tcs file? And why those registers specifically?

    No, it really shouldn't be writing registers during that initialization phase. I'm not exactly in a position to divulge the entire story behind these initial writes, but it boils down to ten years of feature expansion in the software greatly exceeding the initial implementation of the core event handling code. Somewhere in our event handlers for the controls, we have a conditional check that is supposed to suppress initial register writes until after the profile loads, but there are cases where certain initialization actions don't get handled in-order, and the conditional check is deasserted before all writes are properly suppressed. The multiple years spent unsuccessfully chasing down every root cause of this specific bug are a major reason why we are in the process of writing a new implementation of the software in TICS Pro 2, with plans to port over several devices including LMK05318B. The TICS Pro 2 event handling has been greatly simplified, such that we can always be certain that register I/O is suppressed until profile initialization completes.

    TICS Pro doesn't seem to save the  AutoUpdate option.

    This was a conscious choice on our part, that may be worth revisiting. We commonly have multiple instances of TICS Pro running on the same PC, controlling different boards. Until very recently, we didn't even have a way to specify startup options to the program - this only became possible starting in December 2023, with the ability to set a settings.ini config file with some startup options. Until two months ago, only one such file could exist, making it very clunky to work with more than one instance of TICS Pro open at a time. Now that there is a way to specify a custom settings INI path on startup, we should refer the AutoUpdate setting back to the settings INI.

    When TICS Pro loads a tcs file with a USB2ANY connected it automatically writes all registers it to the device which I don't think is a good idea, especially if AutoUpdate is off.  It also writes it even if the device in the tcs file doesn't match the device connected.  I.E if you have a LMK05318B connected and load a LMK5B12204 tcs file to use as a base, TICS Pro still writes all the registers.  Also not a good idea.

    I mostly agree. In TICS Pro 2, config files include information about the profile that generated them, and when loading a config file the default behavior is to first check if the generating profile matches the current profile before loading any settings, before simply loading the settings into the GUI without writing them out to the device. Unfortunately in TP1.x changing this behavior now would break many existing workflows (including some we rely on internally), and at this point with many thousands of tcs files across hundreds of customers over a decade of use (some of which contain undocumented format changes that were never handled well in the first place), it's too late for TP1.x to add any kind of meaningful attempt to validate that a TCS file matches the expected device. A setting to choose whether we write all registers on config load, combined with a way to configure this setting through the UI and settings INI, would be a valuable addition for both TP1.x and TP2 (we just flip the default between 1.x and 2).

    It also writes all registers if you select one of the default configurations even if AutoUpdate is off.  This really isn't a good idea.

    In fairness to the AutoUpdate feature, it was originally envisioned as a mechanism to prevent register I/O as a side-effect of changing fields or variables in the UI through their checkbox/combobox/etc. To the extent that we were thinking about the AutoUpdate feature (which I assure you was close to never), we were internally thinking of a very narrow set of side-effect register I/O, to introduce a VERY specific workaround from a long time ago. That said, in the absence of a clear name or any documentation of the behavior controlled by the setting, and with only the black box behavioral observation that toggling the setting appears to prevent some comboboxes from writing registers, I think it's a perfectly reasonable assumption to make that the feature flag called "AutoUpdate" would have some impact on the notably automatic side effect of writing all registers on configuration load. In any case, my key takeaway is that the AutoUpdate option is not well-named or well-documented, and the behavior feels inconsistent in frustrating ways; and we'd do well to clean this up in the future. I think we're more likely to tackle this in TICS Pro 2 than in TP1.x

    On the Wizard Set Reference page, If you change the value of PRIREF frequency it often resets the interface type to AC, hysteresis = 200mv

    This is intentional (sort of). Per the profile maintainer, and per the instructions just below the DPLL reference selection, "AC or DC buffer is auto-selected based on reference frequency" - but no attempt was made to distinguish between the different hysteresis levels within the AC or DC buffer types, so the code ends up overwriting one hysteresis choice with another when the reference frequency is set.

    It's fair to say that the LMK05318B wizard does not have a spectacular implementation, for a variety of reasons. The poor LMK05318B wizard experience on TP1.x is another significant motivation for the new TICS Pro 2 implementation. As we transition to TICS Pro 2, I have been advising profile maintainers responsible for porting over devices to recreate wizard-like flows such that they follow a more sensible set of rules:

    • Offer a way to automatically select sensible values when possible, which documents the value choice made and why - this must be opt-in only through some explicit action, such that only on request (such as through a button) do any settings change.
    • Manual changes should always be permitted. Sub-optimal settings should trigger a visually-distinct warning indicator with a clear explanation for why a given setting might be sub-optimal. Incorrect settings should trigger a visually-distinct error indicator with a clear explanation for why a given setting is invalid.
    • Warnings and errors should be aggregated somewhere for review, such that the user does not have to hunt down individual settings across a half dozen pages looking for hard-to-spot visual indicators tied to controls that may be off-page. Aggregate warning/error information should offer a way to quickly jump to the source of the error.
    • GUI controls used to capture wizard-style design intent should be internally distinct from GUI controls used to trigger register I/O. Wizards should ideally never need to be connected to a device to construct a design or prepare register settings / programming sequence. Changing something in the wizard should not change any behaviors in a connected device until the user explicitly requests the wizard configuration to be loaded to the device for testing/debugging.

    At some point very soon, the LMK05318B will have a better implementation in TICS Pro 2. We appreciate you taking the time to point out the stuff that doesn't make sense or that makes working with the GUI needlessly difficult, and we're keeping that in mind as we put together a superior experience in TICS Pro 2. If there's other problems, we'd like to hear about them, as now's the perfect time to avoid repeating any prior mistakes. Right now, in TP1.x, if there's specific issues that are blocking you from getting work done, and you have no usable workaround, let us know - I'm trying to give our profile maintainers time to focus on improvements in TP2, but we can still make hotfixes in TP1.x on an as-needed basis.

    ---

    For now, I don't think it's exactly the solution you were looking for, but you could use the AUTOCONNECT boolean option in the [USB] section of the settings INI on startup to prevent TICS Pro from automatically connecting to a USB2ANY. The register I/O would still be logged until the USB2ANY was connected, but only as a simulation.

    From the 1.7.9.0 release notes, regarding the startup settings:

    When running TICS Pro.exe, optional --settings flag takes an absolute path to an INI file with startup settings. Customizable startup behaviors are documented more extensively in the dataclass objects in the newly included ti_ticspro python package.

  • Wow!  Thanks for the detailed response!

    but it boils down to ten years of feature expansion in the software greatly exceeding the initial implementation

    Been there many times. Slight smile

    None of the issues are critical and TBH, I only use the USB2ANY when I need to do some quick individual parameter testing.  This is a Linux shop so there's only 1 Windows machine that we RDP into to run Windows-only things that simply won't run under Linux/Wine.  Normally I run TICS Pro via RDP from my Linux desktop and save the files to a shared drive, then use python scripts and an I2C adapter to to load them.

    I'm pleased to hear that TICS Pro 2 is in the works.  If it's not too late, can I make a plea for a multi-platform version and if you have any sway with the USB2ANY SDK devs, a multi-platform version of that would be welcomed as well.  Also, if you need beta testers, I'm available. Slight smile

    Thanks again!

  • Oh, on the whole "multi-platform" thing...  I ran across an old post of yours with a Python example for the USB2ANY SDK...
    LMX2594EVM: Serial control through python 

    If you install TICS Pro with Wine in Linux, the Python script does actually work using the bundled Windows Python build even though the TICS Pro UI itself doesn't.  It's not ideal for many reasons though among them it's slow and hard to add modules to.  This is why I'd like to see a multi-platform implementation or just multiple builds for different platforms.  

    In the short term, is there any info about the USB2ANY HID-level protocol that can be shared with the public?

    Thanks...george

  • the USB2ANY SDK devs

    USB2ANY hasn't been in active development since 2017, and the individual product groups are responsible for their own forks at this point. I've thought about how best to manage cross-platform support for USB2ANY, and there are big challenges because the current library is deeply platform-specific (in particular the firmware loader). If we could sort out the firmware loader process, the remaining HID packet communication is straightforward.

    If you install TICS Pro with Wine in Linux, the Python script does actually work using the bundled Windows Python build even though the TICS Pro UI itself doesn't.

    Interesting. I had tried TICS Pro through Wine previously and I ran into problems. Were there any specific tweaks you made to get the binary to run? Or maybe Wine just got better, it's been a few years...

    It's not ideal for many reasons though among them it's slow and hard to add modules to. 

    Thinking aloud, the decision to invest most of our software development time and energy into a windows-only GUI application, onto which automation gets bolted, is inconvenient for more than just the Linux shop workflow - the GUI is very resource-intensive as an automation utility, both from a computational perspective (lots of user memory and overhead from logging/UI/server/etc) and from a development perspective (we spend time tweaking and debugging UI nuisances instead of abstracting device handling; improvements to the GUI sometimes result in better end-user understanding of the underlying dependencies, but rarely improve understanding of any register sequences required to program the device).

    I personally think power users can be better served with simpler, open-source libraries to manage register I/O and device control. Something like the following, as pure python code (or as close as possible), is where I'd like to go long-term for cross-platform support:

    • Code to communicate with USB2ANY, FTDI, etc
    • Some hardware abstraction layer to present a unified I/O interface, with standard GPIO and protocol configure/read/write functions
    • Device register model - keeps track of register map structure and caching, manages read/write/get/set functions at a register level by breaking it down into instructions for the HAL
    • Device field model - maps fields to the register map, manages read/write/get/set by breaking it down into register-level requests to the device register model
    • Device "driver" or API - higher level functions to perform specific actions, generate programming sequences, check dependencies by writing and reading specific fields in the correct order

    TICS Pro GUI already implements the first four layers of this model, but the fifth is tangled up in GUI-specific code, which makes abstracting library capabilities difficult. If TICS Pro instead becomes another layer on top of the device "driver", the GUI can focus on its primary objectives (graphical debugging and configuration development) while everything below it can be decoupled and used standalone or as a library integrated into a larger automation and testing system.

    Practically, implementing the whole GUI as a cross-platform application is feasible, but I don't know that we're equipped to support cross-platform GUI applications well. I think providing all the underlying functionality, but no GUI, is a better bet - we're much more likely to be able to diagnose and fix issues that emerge with python libraries on linux than with e.g. MESA driver issues, arcane window manager interactions, etc.

    So, if we gave you a python library as described above, and functions to import/export registers and maybe certain config variables back and forth between the GUI, but the GUI remained windows-only, would this be a suitable compromise? 

    In the short term, is there any info about the USB2ANY HID-level protocol that can be shared with the public?

    Sure! The impediments to sharing the source code for USB2ANY are mostly the internal effort required, so I can't share the whole project, but I can definitely share the HID stuff. In fact, I have a pure python implementation of the CRC computation and the packet communication from a previous experiment:

    crc8_table = [
        0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
        0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,
        0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
        0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,
        0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5,
        0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
        0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85,
        0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,
        0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
        0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,
        0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2,
        0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
        0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32,
        0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,
        0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
        0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,
        0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c,
        0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
        0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec,
        0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,
        0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
        0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,
        0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c,
        0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
        0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b,
        0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,
        0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
        0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,
        0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb,
        0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
        0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb,
        0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
    ]
    
    def calc_crc8(buf):
        crc = 0
        for value in buf:
            crc = crc8_table[(value ^ crc) & 0xff]
        return crc
    
    def write_packet(device, seq, command, *params):
        """
        HEADER
        ---
        byte    report_id       - always 0x3F for USB2ANY
        byte    packet_len      - always len(params) + 8
        byte    packet_id       - always 0x54 (unclear why)
        byte    pec             - CRC8 of all subsequent bytes (4:63, 0-based)
        byte    payload_len     - len(params)
        byte    packet_type     - packet type (see below)
        byte    packet_flags    - packet flags (see below)
        byte    seq_num         - sequence number (see below)
        char    status          - return status as per API manual
        byte    command         - command code for the desired API
        ---
        PAYLOAD
        byte*   payload         - payload of up to 54 bytes, includes packed API arguments
        
        
        """
        pl = len(params)
        buf = [0x3f, 8+pl, 0x54, 0x00, pl, 1, 0, seq, 0, command]
        buf.extend(params)
        buf[3] = calc_crc8(buf[4:])
        device.write(buf)
    
    	
    def read_packet(device):
        device.read(64, 25)
    
    def read_firmware(device):
        payload = [0] * 5
        write_packet(device, 1, 0x0a, *payload)
        res = read_packet(device)
        return f"{res[10]}.{res[11]}.{res[12]}.{res[13]}"
    
    """
    status codes (copied from USB2ANY firmware)
    typedef enum
    {
        ERR_OK                      =  0,
        ERR_COM_RX_OVERFLOW         = -1,
        ERR_COM_RX_BUF_EMPTY        = -2,
        ERR_COM_TX_BUF_FULL         = -3,
        ERR_COM_TX_STALLED          = -4,
        ERR_COM_TX_FAILED           = -5,
        ERR_COM_OPEN_FAILED         = -6,
        ERR_COM_PORT_NOT_OPEN       = -7,
        ERR_COM_PORT_IS_OPEN        = -8,
        ERR_COM_READ_TIMEOUT        = -9,
        ERR_COM_READ_ERROR          = -10,
        ERR_COM_WRITE_ERROR         = -11,
        ERR_DEVICE_NOT_FOUND        = -12,
        ERR_COM_CRC_FAILED          = -13,
    
        ERR_INVALID_PORT            = -20,
        ERR_ADDRESS_OUT_OF_RANGE    = -21,
        ERR_INVALID_FUNCTION_CODE   = -22,
        ERR_BAD_PACKET_SIZE         = -23,
        ERR_INVALID_HANDLE          = -24,
        ERR_OPERATION_FAILED        = -25,
        ERR_PARAM_OUT_OF_RANGE      = -26,
        ERR_PACKET_OUT_OF_SEQUENCE  = -27,
        ERR_INVALID_PACKET_HEADER   = -28,
        ERR_UNIMPLEMENTED_FUNCTION  = -29,
        ERR_TOO_MUCH_DATA           = -30,
        ERR_INVALID_DEVICE          = -31,
        ERR_UNSUPPORTED_FIRMWARE    = -32,
        ERR_BUFFER_TOO_SMALL        = -33,
        ERR_NO_DATA                 = -34,
        ERR_RESOURCE_CONFLICT       = -35,
        ERR_NO_EVM                  = -36,
        ERR_COMMAND_BUSY            = -37,
        ERR_ADJ_POWER_FAIL          = -38,
        ERR_NOT_ENABLED             = -39,
    
        ERR_I2C_INIT_ERROR          = -40,
        ERR_I2C_READ_ERROR          = -41,
        ERR_I2C_WRITE_ERROR         = -42,
        ERR_I2C_BUSY                = -43,
        ERR_I2C_ADDR_NAK            = -44,
        ERR_I2C_DATA_NAK            = -45,
        ERR_I2C_READ_TIMEOUT        = -46,
        ERR_I2C_READ_DATA_TIMEOUT   = -47,
        ERR_I2C_READ_COMP_TIMEOUT   = -48,
        ERR_I2C_WRITE_TIMEOUT       = -49,
        ERR_I2C_WRITE_DATA_TIMEOUT  = -50,
        ERR_I2C_WRITE_COMP_TIMEOUT  = -51,
        ERR_I2C_NOT_MASTER          = -52,
        ERR_I2C_ARBITRATION_LOST    = -53,
        ERR_I2C_NO_PULLUP_POWER     = -54,
    
        ERR_SPI_INIT_ERROR          = -60,
        ERR_SPI_WRITE_READ_ERROR    = -61,
    
        ERR_DATA_WRITE_ERROR        = -70,
        ERR_DATA_READ_ERROR         = -71,
        ERR_TIMEOUT                 = -72,
        ERR_DATA_CRC_FAILED         = -73,
        ERR_INVALID_PARAMETER       = -74,
        ERR_NOT_INITIALIZED         = -75
    
    } ERROR_CODE;
    
    Packet types (copied from USB2ANY firmware, some explanation included below)
    #define COMMAND_PACKET      1
    #define REPLY_PACKET        2
    #define ERROR_PACKET        3
    #define PAYLOAD_PACKET      4
    #define INTERRUPT_PACKET    5
    
    - COMMAND_PACKET is the standard packet type for API commands.
    - REPLY_PACKET is the type returned by USB2ANY for any non-error reply.
    - ERROR_PACKET is the type returned by USB2ANY for any has-error reply.
    - PAYLOAD_PACKET is the type returned by USB2ANY for asynchronous readback (ADCs, UART)
      where a REPLY_PACKET was already sent. There's some special handling related to this in 
      the code, but it doesn't appear to be relevant for SPI/I2C/GPIO.
    - INTERRUPT_PACKET is used for immediate interrupt functions (GPIO, user-defined 
      callbacks)
    
    Packet flags (copied from USB2ANY firmware, descriptions added)
    #define FLAG_MOREDATA       1
    - seems to be used for FIFO-related commands (ADCs, UART) - I think it's always 0
      unless it's ADCs, UART, etc
    
    seq_num appears to be used for debug - and needs to be set > 0 because 0 is reserved for 
    asynchronous packets. I set it to 1 everywhere for SPI/I2C/GPIO.
    
    Command definitions (note that a bunch appear to be unused, even the defined ones):
    typedef enum Command
    {
        Cmd_LoopPacket = 0,                 // 0x00
        Cmd_I2C_Control = 1,                // 0x01
        Cmd_I2C_Write = 2,                  // 0x02
        Cmd_I2C_Read = 3,                   // 0x03
        Cmd_I2CRead_WithAddress = 4,        // 0x04
        Cmd_GPIO_Write_Control = 5,         // 0x05
        Cmd_GPIO_Write_States = 6,          // 0x06
        Cmd_GPIO_Read_States = 7,           // 0x07
        Cmd_SPI_Control = 8,                // 0x08
        Cmd_SPI_WriteAndRead = 9,           // 0x09
        Cmd_FirmwareVersion_Read = 10,      // 0x0A
        Cmd_MSP430_WordWrite = 11,          // 0x0B
        Cmd_MSP430_WordRead = 12,           // 0x0C
        Cmd_MSP430_ByteWrite = 13,          // 0x0D
        Cmd_MSP430_ByteRead = 14,           // 0x0E
        Cmd_UART_Control = 15,              // 0x0F
        Cmd_MSP430_MemoryWrite = 16,        // 0x10
        Cmd_MSP430_MemoryRead = 17,         // 0x11
        Cmd_UART_Write = 18,                // 0x12
        Cmd_UART_SetMode = 19,              // 0x13
        Cmd_UART_Read = 20,                 // 0x14
        Cmd_Local_I2C_Write = 21,           // 0x15
        Cmd_PWM_Write_Control = 22,         // 0x16
        Cmd_Power_WriteControl = 23,        // 0x17
        Cmd_Power_ReadStatus = 24,          // 0x18
        Cmd_ADC_Control = 25,               // 0x19
        Cmd_ADC_ConvertAndRead = 26,        // 0x1A
        Cmd_LED_Control = 27,               // 0x1B
        Cmd_Clock_Control = 28,             // 0x1C
        Cmd_FEC_Control = 29,               // 0x1D
        Cmd_FEC_CountAndRead = 30,          // 0x1E
        Cmd_Interrupt_Control = 31,         // 0x1F
        Cmd_Interrupt_Received = 32,        // 0x20
        Cmd_EasyScale_Control = 33,         // 0x21
        Cmd_EasyScale_Write = 34,           // 0x22
        Cmd_EasyScale_Read = 35,            // 0x23
        Cmd_EasyScale_ACK_Received = 36,    // 0x24
        Cmd_GPIO_SetPort = 37,              // 0x25
        Cmd_GPIO_WritePort = 38,            // 0x26
        Cmd_GPIO_ReadPort = 39,             // 0x27
        Cmd_Reserved_40 = 40,               // 0x28 Reserved for end-user command **
        Cmd_Reserved_41 = 41,               // 0x29 Reserved for end-user command **
        Cmd_Reserved_42 = 42,               // 0x2A Reserved for end-user command **
        Cmd_Reserved_43 = 43,               // 0x2B Reserved for end-user command **
        Cmd_Reserved_44 = 44,               // 0x2C Reserved for end-user command **
        Cmd_Reserved_45 = 45,               // 0x2D Reserved for end-user command **
        Cmd_Reserved_46 = 46,               // 0x2E Reserved for end-user command **
        Cmd_Reserved_47 = 47,               // 0x2F Reserved for end-user command **
        Cmd_Reserved_48 = 48,               // 0x30 Reserved for end-user command **
        Cmd_Reserved_49 = 49,               // 0x31 Reserved for end-user command **
        Cmd_SMBUS_SendByte = 50,            // 0x32
        Cmd_SMBUS_WriteByte = 51,           // 0x33
        Cmd_SMBUS_WriteWord = 52,           // 0x34
        Cmd_SMBUS_WriteBlock = 53,          // 0x35
        Cmd_SMBUS_ReceiveByte = 54,         // 0x36
        Cmd_SMBUS_ReadByte = 55,            // 0x37
        Cmd_SMBUS_ReadWord = 56,            // 0x38
        Cmd_SMBUS_ReadBlock = 57,           // 0x39
        Cmd_SMBUS_ProcessCall = 58,         // 0x3A
        Cmd_SMBUS_BWBRProcessCall = 59,     // 0x3B
        Cmd_SMBUS_Control = 60,             // 0x3C
        Cmd_SMBUS_GetEchoBuffer = 61,       // 0x3D
        Cmd_RFFE_RegZeroWrite = 62,         // 0x3E 
        Cmd_RFFE_RegWrite = 63,             // 0x3F 
        Cmd_RFFE_ExtRegWrite  = 64,         // 0x40 
        Cmd_RFFE_ExtRegWriteLong = 65,      // 0x41 
        Cmd_RFFE_RegRead  = 66,             // 0x42 
        Cmd_RFFE_ExtRegRead = 67,           // 0x43 
        Cmd_RFFE_ExtRegReadLong = 68,       // 0x44 
        Cmd_OneWire_SetMode = 69,           // 0x45
        Cmd_OneWire_PulseSetup = 70,        // 0x46
        Cmd_OneWire_PulseWrite = 71,        // 0x47
        Cmd_OneWire_SetState = 72,          // 0x48
        Cmd_Reserved_73 = 73,               // 0x49 **
        Cmd_Reserved_74 = 74,               // 0x4A **
        Cmd_Reserved_75 = 75,               // 0x4B **
        Cmd_Reserved_76 = 76,               // 0x4C **
        Cmd_Reserved_77 = 77,               // 0x4D **
        Cmd_Reserved_78 = 78,               // 0x4E **
        Cmd_Reserved_79 = 79,               // 0x4F **
        Cmd_Reserved_80 = 80,               // 0x50 **
        Cmd_Reserved_81 = 81,               // 0x51 **
        Cmd_Reserved_82 = 82,               // 0x52 **
        Cmd_Reserved_83 = 83,               // 0x53 **
        Cmd_Packet = 84,                    // 0x54
        Cmd_GPIO_SetCustomPort = 85,        // 0x55
        Cmd_GPIO_WriteCustomPort = 86,      // 0x56
        Cmd_GPIO_ReadCustomPort = 87,       // 0x57
        Cmd_GPIO_WritePulse = 88,           // 0x58
        Cmd_Reserved_89 = 89,               // 0x59 **
        Cmd_Reserved_90 = 90,               // 0x5A **
        Cmd_Reserved_91 = 91,               // 0x5B **
        Cmd_Reserved_92 = 92,               // 0x5C **
        Cmd_Reserved_93 = 93,               // 0x5D **
        Cmd_Reserved_94 = 94,               // 0x5E **
        Cmd_Reserved_95 = 95,               // 0x5F **
        Cmd_I2C_BlkWriteBlkRead = 96,       // 0x60
        Cmd_InvokeBSL = 97,                 // 0x61
        Cmd_FirmwareDebugMode = 98,         // 0x62
        Cmd_Restart = 99,                   // 0x63
        Cmd_I2C_ReadWithAddress = 100,      // 0x64
        Cmd_I2C_ReadInternal = 101,         // 0x65
        Cmd_I2C_WriteInternal = 102,        // 0x66
        Cmd_GetErrorList = 103,             // 0x67
        Cmd_LED_SetState = 104,             // 0x68
        Cmd_Power_SetVoltageRef = 105,	    // 0x69
        Cmd_Status_GetControllerType = 106, // 0x6A
        Cmd_Power_Enable = 107,             // 0x6B
        Cmd_ADC_Enable = 108,               // 0x6C
        Cmd_ADC_Acquire = 109,              // 0x6D
        Cmd_ADC_GetData = 110,              // 0x6E
        Cmd_ADC_GetStatus = 111,            // 0x6F
        Cmd_ADC_SetReference = 112,         // 0x70
        Cmd_Status_GetBoardRevision = 113,  // 0x71
        Cmd_Status_EVMDetect = 114,         // 0x72
        Cmd_ADC_AcquireTriggered = 115,     // 0x73
        Cmd_Power_Notify = 116,             // 0x74
        Cmd_Digital_Capture = 117,          // 0x75
        Cmd_Digital_GetData = 118,          // 0x76
        Cmd_Digital_GetStatus = 119,        // 0x77
        Cmd_EasyScale_WriteAndRead = 120,   // 0x78
        Cmd_DisplayScale_Set = 121,         // 0x79
        Cmd_DisplayScale_WriteReg = 122,    // 0x7A
        Cmd_DisplayScale_ReadReg = 123,     // 0x7B
        Cmd_DisplayScale_WriteAndRead = 124,// 0x7C
        Cmd_Reserved_125 = 125,             // 0x7D **
        Cmd_Reserved_126 = 126,             // 0x7E **
        Cmd_Invalid = 127,                  // 0x7F
        Cmd_Stream_Start = 128,             // 0x80
        Cmd_Stream_Stop = 129,              // 0x81
        Cmd_Stream_Status = 130,            // 0x82
        Cmd_Stream_GetData = 131,           // 0x83
        Cmd_Stream_Execute = 132,           // 0x84 
        Cmd_SPI_StreamOut = 133,            // 0x85
        Cmd_SPI_StreamStop = 134,           // 0x86
        Cmd_SPI_WriteAndReadEx = 135,       // 0x87
        Cmd_Reserved_136 = 136,             // 0x88 **
        Cmd_Reserved_137 = 137,             // 0x89 **
        Cmd_Pegasus_Test = 138,             // 0x8A
        Cmd_Reserved_139 = 139,             // 0x8B **
        Cmd_Port_Setup = 140,               // 0x8C
        Cmd_Port_Read = 141,                // 0x8D
        Cmd_Port_Write = 142,               // 0x8E
        Cmd_Port_WritePulse = 143,          // 0x8F
        Cmd_END                             // 0x90
        
    //  ** = UNUSED COMMAND
    };
    """

  • Interesting. I had tried TICS Pro through Wine previously and I ran into problems. Were there any specific tweaks you made to get the binary to run? Or maybe Wine just got better, it's been a few years...

    Well, the TICS Pro UI doesn't draw well enough to be usable under Wine but the USB2ANY explorer from the SDK does work although it's stuck at firmware 2.8.x.x so even on Windows going back and forth between TICS Pro and the Explorer triggers firmware switches 2.9.2.1 and back again.   The USB2ANY.dll in the TICS Pro distro does work fine in Wine as long as you use the Windows version of Python distributed with TICS Pro.

    So, if we gave you a python library as described above, and functions to import/export registers and maybe certain config variables back and forth between the GUI, but the GUI remained windows-only, would this be a suitable compromise?

    You've made my day!  I think you're exactly on the right track.  The TICS Pro wizards do a lot of work that we wouldn't be able to do easily ourselves but if that were pushed down into a cross-platform library that would work well.  

    You've also made my day with the sample Python.  I actually have a basic version working but a lot of it is just hard-coded to what I was able to learn from the USB packet captures.  The CRC turned out to be absurdly simple with the "crc" package "crc.Calculator(Crc8.CCITT, optimized=True).checksum(buffer[4:]". Slight smile

    Thanks again Derek!  I really appreciate the detailed responses and insight!