"""Utility functions to build the TCU command strings.

We discern between the following types of commands:
    - General commands;
    - M2MD commands (on a per-axis basis);
    - Thermal Monitoring System (TSM) commands;
    - HK commands.

Reference documents:
    - RD01: TCU User Manual (ARIEL-IEEC-PL-TN-002), v1.2
    - RD02: ARIEL TCU Data Handling (ARIEL-IEEC-PL-TN-007), v1.0
    - RD03: TCU code provided by Vladimiro Noce (priv. comm.)
    - RD04: ARIEL Telescope Control Unit Design Description Document (ARIEL-IEEC-PL-DD-001), v1.10
    - RD05: ARIEL TCU FW Architecture Design (ARIEL-IEEC-PL-DD-002), v1.5
"""

from enum import StrEnum
import crcmod

from egse.ariel.tcu import TcuMode
from egse.decorators import static_vars

TCU_LOGICAL_ADDRESS = "03"  # RD02 -> Fig. 10
DATA_LENGTH = "0004"  # Vladimiro's code


class PacketType(StrEnum):
    """Packet types (read/write)."""

    W = WRITE = "20"  # Write command (RD02 -> Sect. 4.1.1)
    R = READ = "40"  # Read command (RD02 -> Sect. 4.1.2)


class CommandAddress(StrEnum):
    """Identifiers of the components of the TCU the commands have to be sent to."""

    # Adopted from Vladimiro's code

    GENERAL = "0000"  # General TCU commands -> see `show_messageGEN`, where the command string is built
    M2MD_1 = "0001"  # M2MD axis-1 commands -> see `show_messageM2M`, where the command string is built
    M2MD_2 = "0002"  # M2MD axis-2 commands -> see `show_messageM2M`, where the command string is built
    M2MD_3 = "0003"  # M2MD axis-3 commands -> see `show_messageM2M`, where the command string is built
    TSM = "0004"  # TSM commands -> see `show_messageTSM`, where the command string is built
    HK = "0005"  # HK commands -> see `show_messageHK`, where the command string is built


#####################
# Command identifiers
#####################


class GeneralCommandIdentifier(StrEnum):
    """Identifiers for the general TCU commands."""

    # Adopted from Vladimiro's code

    TCU_FIRMWARE_ID = "0000"  # Read
    TCU_MODE = "0001"  # Read/Write
    TCU_STATUS = "0002"  # Read
    TCU_SIMULATED = "0003"  # Write
    RESTART_LINKS_PERIOD_LATCH = "0004"  # Write
    RESTART_LINKS_PERIOD = "0005"  # Read/Write


class M2MDCommandIdentifier(StrEnum):
    """Identifiers for the M2MD commands."""

    # Adopted from Vladimiro's code

    OPE_MNG_COMMAND = "0000"  # Write
    OPE_MNG_EVENT_CLEAR_PROTECT_FLAG = "0001"  # Write
    OPE_MNG_EVENT_CLEAR = "0002"  # Write
    OPE_MNG_STATUS = "0003"  # Read
    OPE_MNG_EVENT_REG = "0004"  # Read
    ACQ_CURR_OFF_CORR = "1000"  # Read/Write
    ACQ_CURR_GAIN_CORR = "1001"  # Read/Write
    ACQ_AXIS_A_CURR_READ = "1002"  # Read
    ACQ_AXIS_B_CURR_READ = "1003"  # Read
    ACQ_AVE_LPF_EN = "1004"  # Write
    ACQ_OVC_CFG_FILTER = "1005"  # Write
    ACQ_AVC_FILT_TIME = "1006"  # Write
    ACQ_AVERAGE_TYPE = "1007"  # Write
    ACQ_SPK_FILT_COUNTER_LIM = "1008"  # Write
    ACQ_SPK_FILT_INCR_THR = "1009"  # Write
    PROF_GEN_AXIS_STEP = "2000"  # Read/Write
    PROF_GEN_AXIS_SPEED = "2001"  # Read/Write
    PROF_GEN_AXIS_STATE_START = "2002"  # Read/Write
    SW_RS_XX_SW_RISE = "3001"  # Read
    # TODO Check whether this is correct:
    # This is how it is hard-coded in Vladimiro's code, but in his `show_messageM2M` function, he states that there's
    # an offset of 20 between SW_RS_XX_SW_RISE and SW_RS_XX_SW_FALL (where position must in 1,...,20).  That would mean
    # that for position 15, SW_RS_XX_SW_RISE is 3015, which clashes with the hard-coded value for
    # SW_RS_XX_SW_FALL.
    SW_RS_XX_SW_FALL = "3015"  # Read


class TSMCommandIdentifier(StrEnum):
    """Identifiers for the TSM commands."""

    TSM_LATCH = "0000"  # Write
    TSM_CURRENT_VALUE = "0001"  # Read/Write
    TSM_CURRENT_OFFSET = "0002"  # Read/Write
    TSM_ADC_REGISTER_LATCH = "1000"  # Write
    TSM_ADC_ID_REGISTER = "1001"  # Read
    TSM_ADC_CONFIGURATION_REGISTER = "1002"  # Read
    TSM_ADC_HPF_REGISTER = "1003"  # Read/Write
    TSM_ADC_OFC_REGISTER = "1004"  # Read/Write
    TSM_ADC_FSC_REGISTER = "1006"  # Read/Write
    TSM_ADC_COMMAND_LATCH = "1008"  # Write
    TSM_ADC_COMMAND = "1009"  # Write
    TSM_ADC_CALIBRATION = "100A"  # Write
    TSM_ADC_VALUE_XX_CURRENTN = "2000"  # Read
    TSM_ADC_VALUE_XX_BIASN = "2001"  # Read
    TSM_ADC_VALUE_XX_CURRENTP = "2002"  # Read
    TSM_ADC_VALUE_XX_BIASP = "2003"  # Read
    TSM_ACQ_COUNTER = "20C0"  # Read


class HKCommandIdentifier(StrEnum):
    """Identifiers for the HK commands."""

    # Adopted from Vladimiro's code

    VHK_PSU_VMOTOR = "0000"  # Read
    VHK_PSU_VHI = "0001"  # Read
    VHK_PSU_VLOW = "0002"  # Read
    VHK_PSU_VMEDP = "0003"  # Read
    VHK_PSU_VMEDN = "0004"  # Read
    IHK_PSU_VMEDN = "0005"  # Read
    IHK_PSU_VMEDP = "0006"  # Read
    IHK_PSU_VLOW = "0007"  # Read
    IHK_PSU_VHI = "0008"  # Read
    IHK_PSU_VMOTOR = "0009"  # Read
    THK_PSU_FIRST = "000A"  # Read
    THK_M2MD_FIRST = "000B"  # Read
    THK_PSU_SECOND = "000C"  # Read
    THK_M2MD_SECOND = "000D"  # Read
    THK_CTS_Q1 = "000E"  # Read
    THK_CTS_Q2 = "000F"  # Read
    THK_CTS_Q3 = "0010"  # Read
    THK_CTS_Q4 = "0011"  # Read
    THK_CTS_FPGA = "0012"  # Read
    THK_CTS_ADS1282 = "0013"  # Read
    VHK_THS_RET = "0014"  # Read
    HK_ACQ_COUNTER = "0015"  # Read


def get_tsm_adc_value_xx_currentn_cmd_id(probe: int) -> str:
    """Determines the command identifier for the TSM_ADC_VALUE_XX_CURRENTN for the given probe.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command identifier for the TSM_ADC_VALUE_XX_CURRENTN for the given probe.
    """

    return get_tsm_adc_value_xx_cmd_id(TSMCommandIdentifier.TSM_ADC_VALUE_XX_CURRENTN, probe)


def get_tsm_adc_value_xx_biasn_cmd_id(probe: int) -> str:
    """Determines the command identifier for the TSM_ADC_VALUE_XX_BIASN for the given probe.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command identifier for the TSM_ADC_VALUE_XX_BIASN for the given probe.
    """

    return get_tsm_adc_value_xx_cmd_id(TSMCommandIdentifier.TSM_ADC_VALUE_XX_BIASN, probe)


def get_tsm_adc_value_xx_currentp_cmd_id(probe: int) -> str:
    """Determines the command identifier for the TSM_ADC_VALUE_XX_CURRENTP for the given probe.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command identifier for the TSM_ADC_VALUE_XX_CURRENTP for the given probe.
    """

    return get_tsm_adc_value_xx_cmd_id(TSMCommandIdentifier.TSM_ADC_VALUE_XX_CURRENTP, probe)


def get_tsm_adc_value_xx_biasp_cmd_id(probe: int) -> str:
    """Determines the command identifier for the TSM_ADC_VALUE_XX_BIASP for the given probe.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command identifier for the TSM_ADC_VALUE_XX_BIASP for the given probe.
    """

    return get_tsm_adc_value_xx_cmd_id(TSMCommandIdentifier.TSM_ADC_VALUE_XX_BIASP, probe)


def get_tsm_adc_value_xx_cmd_id(tsm_cmd_id: TSMCommandIdentifier | str, probe: int):
    """Determines the command identifier for the given TSM_ADC_VALUE_XX for the given probe.

    Args:
        tsm_cmd_id (TSMCommandIdentifier | str): TSM command identifier.
        probe (int): Thermistor identifier.

    Returns:
        Command identifier for the
        TSM_ADC_VALUE_XX_CURRENTN/TSM_ADC_VALUE_XX_BIASN/TSM_ADC_VALUE_XX_CURRENTP/TSM_ADC_VALUE_XX_BIASP for the given
        probe.
    """

    # Adopted from Vladimiro's code
    return tsm_cmd_id.value[:2] + hex(probe * 4 + int(tsm_cmd_id.value[-1]))[2:].zfill(2)


def get_sw_rs_xx_sw_cmd_id(cmd_identifier: M2MDCommandIdentifier, position: int) -> str:
    """Determines the command identifier for the given SW_RS_XX_SW for the given probe.

    Args:
        cmd_identifier (M2MDCommandIdentifier): TSM command identifier.
        position (int):

    Returns:
        Command identifier for the SW_RS_XX_SW_RISE/SW_RS_XX_SW_FALL for the given probe.
    """

    # Adopted from Vladimiro's code
    return f"{cmd_identifier.value[:2]}{hex(position)[2:].zfill(2)}"


##############################
# Building the command strings
##############################


def format_value(value: int | str | StrEnum) -> str:
    """Formats the given value to a 4-digit hex string without leading "0x".

    Args:
        value (int | str | StrEnum): Value to format.

    Returns:
        str: Formatted value.
    """

    if isinstance(value, StrEnum):
        value = value.value
    if isinstance(value, int):
        value = f"0x{value:X}"  # Integer -> Hex string
    if value.startswith("0x"):  # Strip off leading 0x
        value = value[2:]
    return value.zfill(4)


def _create_write_cmd_string(
    cmd_address: CommandAddress | str | int,
    cmd_identifier: GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier | str,
    cargo1: int = 0,
    cargo2: int = 0,
) -> str:
    """Creates a write-command string to send to the TCU Arduino.

    Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
    attribute), as this will increase the transaction identifier without actually calling the function (merely
    importing the interface in which such a decorator call is made will increase the transaction identifier).

    Args:
        cmd_address (CommandAddress | str | int): Identifier of the commanded device.
        cmd_identifier (GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier):
                       Command identifier, internal to the commanded device.
        cargo1 (int): Reference to the first 16-bit cargo word.
        cargo2 (int): Reference to the second 16-bit cargo word.

    Returns:
        Write-command string to send to the TCU Arduino.
    """

    return _create_cmd_string(PacketType.WRITE, cmd_address, cmd_identifier, cargo1, cargo2)


def _create_read_cmd_string(
    cmd_address: CommandAddress | str | int,
    cmd_identifier: GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier | str,
    cargo1: int = 0,
    cargo2: int = 0,
) -> str:
    """Creates a read-command string to send to the TCU Arduino.

    Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
    attribute), as this will increase the transaction identifier without actually calling the function (merely
    importing the interface in which such a decorator call is made will increase the transaction identifier)>

    Args:
        cmd_address (CommandAddress | str | int): Identifier of the commanded device.
        cmd_identifier (GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier):
                       Command identifier, internal to the commanded device.
        cargo1 (int): Reference to the first 16-bit cargo word.
        cargo2 (int): Reference to the second 16-bit cargo word.

    Returns:
        Read-command string to send to the TCU Arduino.
    """

    return _create_cmd_string(PacketType.READ, cmd_address, cmd_identifier, cargo1, cargo2)


@static_vars(transaction_id=-1)
def _create_cmd_string(
    packet_type: PacketType,
    cmd_address: CommandAddress | str | int,
    cmd_identifier: GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier | str,
    cargo1: int = 0,
    cargo2: int = 0,
) -> str:
    """Creates a command string to send to the TCU Arduino.

    Packet format (text):
        "03XX TTTT 0004 AAAA BBBB CCCC DDDD CRC"
    with:
        - 03: TCU logical address;
        - XX: Indicates whether it's a read (40) or write (20) command (without reply);
        - TTTT: Transaction identifier (basically a counter that increments for each command call);
        - 0004: Data length (always 4 bytes);
        - AAAA: Identifier of the commanded device:
            - 0000: General commands;
            - 0001: M2MD axis-1 commands;
            - 0002: M2MD axis-2 commands;
            - 0003: M2MD axis-3 commands;
            - 0004: TSM commands;
            - 0005: HK commands
        - BBBB: Command identifier, internal to the commanded device;
        - CCCC: First 16-bit cargo word;
        - DDDD: Second 16-bit cargo word;
        - CRC: Cyclic Redundancy Check (CRC-16), determined from the packet string.

    Note that this function should not be called directly in the `@dynamic_command` decorator (in the `cmd_string`
    attribute), as this will increase the transaction identifier without actually calling the function (merely
    importing the interface in which such a decorator call is made will increase the transaction identifier).

    Args:
        packet_type (PacketType): Type of the packet (read or write).
        cmd_address (CommandAddress): Identifier of the commanded device.  In case of a M2MD axis, it is the reference
                                      to the axis (typically "${axis}") rather than the axis identifier enumeration.
        cmd_identifier (GeneralCommandIdentifier | TSMCommandIdentifier | M2MDCommandIdentifier | HKCommandIdentifier
                       | str): Command identifier, internal to the commanded device.
        cargo1 (int): Reference to the first 16-bit cargo word.
        cargo2 (int): Reference to the second 16-bit cargo word.

    Returns:
        Command string to send to the TCU Arduino.
    """

    _create_cmd_string.transaction_id += 1

    # Adopted from Vladimiro's code

    address = format_value(cmd_address)
    cmd_identifier = format_value(cmd_identifier)
    cargo1 = format_value(cargo1)
    cargo2 = format_value(cargo2)

    transaction_id = f"0x{_create_cmd_string.transaction_id:X}"[2:].zfill(4)

    cmd_string = (
        f"{TCU_LOGICAL_ADDRESS}{packet_type.value} {transaction_id} {DATA_LENGTH} "
        f"{address} {cmd_identifier} {cargo1} {cargo2}"
    )

    cmd_string = append_crc16(cmd_string)
    return cmd_string


def create_crc16(cmd_str: str, ln: int = 14) -> str:
    """Calculates the 16-bit Cyclic Redundancy Check (CRC) checksum for the given command string.

    The CRC-16 is an error-detecting code that generates a 16-bit checksum to verify data integrity during
    transmission.  It works by performing a polynomial division (using XOR operations) on the data, with the remainder
    becoming the CRC checksum.  The receiver performs the same division: A zero remainder indicates the data arrived
    uncorrupted, while a non-zero remainder signals a potential error.

    The leading "0x" is stripped off and the CRC is padded with leading zeros to ensure it is always 4 characters long.

    Args:
        cmd_str (str): Command string for which the CRC will be calculated.
        ln (int): Number of bytes to include in the CRC calculation.

    Returns:
        Calculated 16-bit CRC checksum.
    """

    # Adapted from Vladimiro's code

    byte_array = bytearray([int(cmd_str[2 * i : 2 * i + 2], 16) for i in range(ln)])

    crc16_func = crcmod.mkCrcFun(0x11021, 0xFFFF, False, 0x0)
    crc16 = hex(crc16_func(byte_array))

    crc16 = crc16[2:6].zfill(4)  # Crop leading "0x" + ensure 4 characters

    return crc16


def append_crc16(cmd_string: str, ln: int = 14) -> str:
    """Appends a 16-bit CRC checksum to the given command string.

    Args:
        cmd_string (str): Command string to which the CRC will be appended.
        ln (int): Number of bytes to include in the CRC calculation.

    Returns:
        Command string with the appended CRC checksum.
    """

    crc16 = create_crc16(cmd_string, ln)

    return f"{cmd_string} {crc16}"


# General commands


def tcu_firmware_id() -> str:
    """Builds the command string for the general TCU_FIRMWARE_ID read command.

    Returns:
        Command string for the general TCU_FIRMWARE_ID read command.
    """

    return _create_read_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.TCU_FIRMWARE_ID)


def get_tcu_mode() -> str:
    """Builds the command string for the general TCU_MODE read command.

    Returns:
        Command string for the general TCU_MODE read command.
    """

    return _create_read_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.TCU_MODE)


def set_tcu_mode(tcu_mode: TcuMode | int = TcuMode.IDLE):
    """Builds the command string for the general TCU_MODE write command.

    Args:
        tcu_mode (TcuMode | int): TCU mode.

    Returns:
        Command string for the general TCU_MODE write command.
    """

    return _create_write_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.TCU_MODE, cargo2=tcu_mode)


def tcu_status() -> str:
    """Builds the command string for the general TCU_STATUS read command.

    Returns:
        Command string for the general TCU_STATUS read command.
    """

    return _create_read_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.TCU_STATUS)


def tcu_simulated(cargo2: int):
    """Builds the command string for the general TCU_SIMULATED write command.

    Args:
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the general TCU_SIMULATED write command.
    """

    return _create_write_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.TCU_SIMULATED, cargo2=cargo2)


def restart_links_period_latch(cargo2: int):
    """Builds the command string for the general RESTART_LINKS_PERIOD_LATCH write command.

    Args:
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the general RESTART_LINKS_PERIOD_LATCH write command.
    """

    return _create_write_cmd_string(
        CommandAddress.GENERAL, GeneralCommandIdentifier.RESTART_LINKS_PERIOD_LATCH, cargo2=cargo2
    )


def get_restart_links_period() -> str:
    """Builds the command string for the general RESTART_LINKS_PERIOD_LATCH read command.

    Returns:
        Command string for the general RESTART_LINKS_PERIOD_LATCH read command.
    """

    return _create_read_cmd_string(CommandAddress.GENERAL, GeneralCommandIdentifier.RESTART_LINKS_PERIOD)


def set_restart_links_period(link_period: int = 0xFFFF) -> str:
    """Builds the command string for the general RESTART_LINKS_PERIOD write command.

    Args:
        link_period (int): Link period.

    Returns:
        Command string for the general RESTART_LINKS_PERIOD write command.
    """

    return _create_write_cmd_string(
        CommandAddress.GENERAL,
        GeneralCommandIdentifier.RESTART_LINKS_PERIOD,
        cargo2=link_period,
    )


# M2MD commands


def ope_mng_command(axis: CommandAddress | str | int, cargo2: int = 0x0002) -> str:
    """Builds the command string fort he M2MD OPE_MNG_COMMAND write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD OPE_MNG_COMMAND write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.OPE_MNG_COMMAND, cargo2=cargo2)


def ope_mng_event_clear_protect_flag(axis: CommandAddress | str | int, cargo2: str | int = 0xAAAA) -> str:
    """Builds the command string for the M2MD OPE_MNG_EVENT_CLEAR_PROTECT_FLAG write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD OPE_MNG_EVENT_CLEAR_PROTECT_FLAG write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.OPE_MNG_EVENT_CLEAR_PROTECT_FLAG, cargo2=cargo2)


def ope_mng_event_clear(axis: CommandAddress | str | int, cargo2: int = 0) -> str:
    """Builds the command string for the M2MD OPE_MNG_EVENT_CLEAR write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD OPE_MNG_EVENT_CLEAR write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.OPE_MNG_EVENT_CLEAR, cargo2=cargo2)


def ope_mng_status(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD OPE_MNG_STATUS read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD OPE_MNG_STATUS read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.OPE_MNG_STATUS)


def ope_mng_event_reg(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD OPE_MNG_EVENT_REG read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD OPE_MNG_EVENT_REG read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.OPE_MNG_EVENT_REG)


def get_acq_curr_off_corr(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD ACQ_CURR_OFF_CORR read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD ACQ_CURR_OFF_CORR read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.ACQ_CURR_OFF_CORR)


def set_acq_curr_off_corr(axis: CommandAddress | str | int, cargo2: int = 0x03FB) -> str:
    """Builds the command string for the M2MD ACQ_CURR_OFF_CORR write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_CURR_OFF_CORR write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_CURR_OFF_CORR, cargo2=cargo2)


def get_acq_curr_gain_corr(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD ACQ_CURR_GAIN_CORR read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD ACQ_CURR_GAIN_CORR read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.ACQ_CURR_GAIN_CORR)


def set_acq_curr_gain_corr(axis: CommandAddress | str | int, cargo2: int = 0x074C):
    """Builds the command string for the M2MD ACQ_CURR_GAIN_CORR write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_CURR_GAIN_CORR write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_CURR_GAIN_CORR, cargo2=cargo2)


def acq_axis_a_curr_read(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD ACQ_AXIS_A_CURR_READ read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD ACQ_AXIS_A_CURR_READ read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.ACQ_AXIS_A_CURR_READ)


def acq_axis_b_curr_read(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD ACQ_AXIS_B_CURR_READ read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD ACQ_AXIS_B_CURR_READ read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.ACQ_AXIS_B_CURR_READ)


def acq_ave_lpf_en(axis: CommandAddress | str | int, cargo2: int = 0) -> str:
    """Builds the command string for the M2MD ACQ_AVE_LPF_EN write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_AVE_LPF_EN write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_AVE_LPF_EN, cargo2=cargo2)


def acq_ovc_cfg_filter(axis: CommandAddress | str | int, cargo2: int = 0) -> str:
    """Builds the command string for the M2MD ACQ_OVC_CFG_FILTER write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_OVC_CFG_FILTER write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_OVC_CFG_FILTER, cargo2=cargo2)


def acq_avc_filt_time(axis: CommandAddress | str | int, cargo2: int = 0) -> str:
    """Builds the command string for the M2MD ACQ_AVC_FILT_TIME write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_AVC_FILT_TIME write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_AVC_FILT_TIME, cargo2=cargo2)


def acq_average_type(axis: CommandAddress | str | int, cargo2: int = 0x0000) -> str:
    """Builds the command string for the M2MD ACQ_AVERAGE_TYPE write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_AVERAGE_TYPE write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_AVERAGE_TYPE, cargo2=cargo2)


def acq_spk_filt_counter_lim(axis: CommandAddress | str | int, cargo2: int = 0x0001) -> str:
    """Builds the command string for the M2MD ACQ_SPK_FILT_COUNTER_LIM write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_SPK_FILT_COUNTER_LIM write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_SPK_FILT_COUNTER_LIM, cargo2=cargo2)


def acq_spk_filt_incr_thr(axis: CommandAddress | str | int, cargo2: int = 0x04C0) -> str:
    """Builds the command string for the M2MD ACQ_SPK_FILT_INCR_THR write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD ACQ_SPK_FILT_INCR_THR write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.ACQ_SPK_FILT_INCR_THR, cargo2=cargo2)


def get_prof_gen_axis_step(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_STEP read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_STEP read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_STEP)


def set_prof_gen_axis_step(axis: CommandAddress | str | int, cargo2: int = 0x0480) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_STEP write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_STEP write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_STEP, cargo2=cargo2)


def get_prof_gen_axis_speed(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_SPEED read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_SPEED read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_SPEED)


def set_prof_gen_axis_speed(axis: CommandAddress | str | int, speed: int = 0x1777) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_SPEED write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        speed (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_SPEED write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_SPEED, cargo2=speed)


def get_prof_gen_axis_state_start(axis: CommandAddress | str | int) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_STATE_START read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_STATE_START read command.
    """

    return _create_read_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_STATE_START)


def set_prof_gen_axis_state_start(axis: CommandAddress | str | int, cargo2: int = 0) -> str:
    """Builds the command string for the M2MD PROF_GEN_AXIS_STATE_START write command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the M2MD PROF_GEN_AXIS_STATE_START write command.
    """

    return _create_write_cmd_string(axis, M2MDCommandIdentifier.PROF_GEN_AXIS_STATE_START, cargo2=cargo2)


def sw_rs_xx_sw_rise(axis: CommandAddress | str | int, position: int = 1) -> str:
    """Builds the command string for the M2MD SW_RS_XX_SW_RISE read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        position (int): Position of the SW_RS_XX_SW_RISE command.

    Returns:
        Command string for the M2MD SW_RS_XX_SW_RISE read command.
    """

    # Adopted from Vladimiro's code
    m2md_cmd_id = get_sw_rs_xx_sw_cmd_id(M2MDCommandIdentifier.SW_RS_XX_SW_RISE, position)

    return _create_read_cmd_string(axis, cmd_identifier=m2md_cmd_id)


def sw_rs_xx_sw_fall(axis: CommandAddress | str | int, position: int = 1) -> str:
    """Builds the command string for the M2MD SW_RS_XX_SW_FALL read command.

    Args:
        axis (CommandAddress | str | int): Axis to which the command is sent.
        position (int): Position of the SW_RS_XX_SW_FALL command.

    Returns:
        Command string for the M2MD SW_RS_XX_SW_FALL read command.
    """

    # Adopted from Vladimiro's code
    offset_position = position + 21
    m2md_cmd_id = get_sw_rs_xx_sw_cmd_id(M2MDCommandIdentifier.SW_RS_XX_SW_FALL, offset_position)

    return _create_read_cmd_string(axis, cmd_identifier=m2md_cmd_id)


# TSM commands


def tsm_latch(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_LATCH write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_LATCH write command.
    """

    return _create_write_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_LATCH, cargo1=cargo1, cargo2=cargo2)


def get_tsm_current_value() -> str:
    """Builds the command string for the TSM TSM_CURRENT_VALUE read command.

    Returns:
        Command string for the TSM TSM_CURRENT_VALUE read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_CURRENT_VALUE)


def set_tsm_current_value(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_CURRENT_VALUE write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_CURRENT_VALUE write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_CURRENT_VALUE, cargo1=cargo1, cargo2=cargo2
    )


def get_tsm_current_offset() -> str:
    """Builds the command string for the TSM TSM_CURRENT_OFFSET read command.

    Returns:
        Command string for the TSM TSM_CURRENT_OFFSET read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_CURRENT_OFFSET)


def set_tsm_current_offset(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_CURRENT_OFFSET write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_CURRENT_OFFSET write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_CURRENT_OFFSET, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_register_latch(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_REGISTER_LATCH write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_REGISTER_LATCH write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_REGISTER_LATCH, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_id_register() -> str:
    """Builds the command string for the TSM TSM_ADC_ID_REGISTER read command.

    Returns:
        Command string for the TSM TSM_ADC_ID_REGISTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_ID_REGISTER)


def tsm_adc_configuration_register() -> str:
    """Builds the command string for the TSM TSM_ADC_CONFIGURATION_REGISTER read command.

    Returns:
        Command string for the TSM TSM_ADC_CONFIGURATION_REGISTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_CONFIGURATION_REGISTER)


def get_tsm_adc_hpf_register() -> str:
    """Builds the command string for the TSM TSM_ADC_HPF_REGISTER read command.

    Returns:
        Command string for the TSM TSM_ADC_HPF_REGISTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_HPF_REGISTER)


def set_tsm_adc_hpf_register(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_HPF_REGISTER write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_HPF_REGISTER write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_HPF_REGISTER, cargo1=cargo1, cargo2=cargo2
    )


def get_tsm_adc_ofc_register() -> str:
    """Builds the command string for the TSM TSM_ADC_OFC_REGISTER read command.

    Returns:
        Command string for the TSM TSM_ADC_OFC_REGISTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_OFC_REGISTER)


def set_tsm_adc_ofc_register(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_OFC_REGISTER write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_OFC_REGISTER write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_OFC_REGISTER, cargo1=cargo1, cargo2=cargo2
    )


def get_tsm_adc_fsc_register() -> str:
    """Builds the command string for the TSM TSM_ADC_FSC_REGISTER read command.

    Returns:
        Command string for the TSM TSM_ADC_FSC_REGISTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_FSC_REGISTER)


def set_tsm_adc_fsc_register(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_FSC_REGISTER write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_FSC_REGISTER write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_FSC_REGISTER, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_command_latch(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_COMMAND_LATCH write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_COMMAND_LATCH write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_COMMAND_LATCH, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_command(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_COMMAND write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_COMMAND write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_COMMAND, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_calibration(cargo1: int = 0, cargo2: int = 0) -> str:
    """Builds the command string for the TSM TSM_ADC_CALIBRATION write command.

    Args:
        cargo1 (int): Cargo 1 part of the command string.
        cargo2 (int): Cargo 2 part of the command string.

    Returns:
        Command string for the TSM TSM_ADC_CALIBRATION write command.
    """

    return _create_write_cmd_string(
        CommandAddress.TSM, TSMCommandIdentifier.TSM_ADC_CALIBRATION, cargo1=cargo1, cargo2=cargo2
    )


def tsm_adc_value_xx_currentn(probe: int = 1) -> str:
    """Builds the command string for the TSM TSM_ADC_VALUE_XX_CURRENTN read command.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command string for the TSM TSM_ADC_VALUE_XX_CURRENTN read command.
    """

    tsm_cmd_id = get_tsm_adc_value_xx_currentn_cmd_id(probe)

    return _create_read_cmd_string(CommandAddress.TSM, tsm_cmd_id)


def tsm_adc_value_xx_biasn(probe: int = 1):
    """Builds the command string for the TSM TSM_ADC_VALUE_XX_BIASN read command.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command string for the TSM TSM_ADC_VALUE_XX_BIASN read command.
    """

    tsm_cmd_id = get_tsm_adc_value_xx_biasn_cmd_id(probe)

    return _create_read_cmd_string(CommandAddress.TSM, tsm_cmd_id)


def tsm_adc_value_xx_currentp(probe: int = 1) -> str:
    """Builds the command string for the TSM TSM_ADC_VALUE_XX_CURRENTP read command.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command string for the TSM TSM_ADC_VALUE_XX_CURRENTP read command.
    """

    tsm_cmd_id = get_tsm_adc_value_xx_currentp_cmd_id(probe)

    return _create_read_cmd_string(CommandAddress.TSM, tsm_cmd_id)


def tsm_adc_value_xx_biasp(probe: int = 1) -> str:
    """Builds the command string for the TSM TSM_ADC_VALUE_XX_BIASP read command.

    Args:
        probe (int): Thermistor identifier.

    Returns:
        Command string for the TSM TSM_ADC_VALUE_XX_BIASP read command.
    """

    tsm_cmd_id = get_tsm_adc_value_xx_biasp_cmd_id(probe)

    return _create_read_cmd_string(CommandAddress.TSM, tsm_cmd_id)


def tsm_acq_counter() -> str:
    """Builds the command string for the TSM TSM_ACQ_COUNTER read command.

    Returns:
        Command string for the TSM TSM_ACQ_COUNTER read command.
    """

    return _create_read_cmd_string(CommandAddress.TSM, TSMCommandIdentifier.TSM_ACQ_COUNTER)


def vhk_psu_vmotor() -> str:
    """Builds the command string for the HK VHK_PSU_VMOTOR read command.

    Returns:
        Command string for the HK PSU VHK_PSU_VMOTOR read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_PSU_VMOTOR)


def vhk_psu_vhi() -> str:
    """Builds the command string for the HK VHK_PSU_VHI read command.

    Returns:
        Command string for the HK PSU VHK_PSU_VHI read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_PSU_VHI)


def vhk_psu_vlow() -> str:
    """Builds the command string for the HK VHK_PSU_VLW read command.

    Returns:
        Command string for the HK PSU VHK_PSU_VLOW read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_PSU_VLOW)


def vhk_psu_vmedp() -> str:
    """Builds the command string for the HK VHK_PSU_VMEDP read command.

    Returns:
        Command string for the HK PSU VHK_PSU_VMEDP read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_PSU_VMEDP)


def vhk_psu_vmedn() -> str:
    """Builds the command string for the HK VHK_PSU_VMEDN read command.

    Returns:
        Command string for the HK PSU VHK_PSU_VMEDN read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_PSU_VMEDN)


def ihk_psu_vmedn() -> str:
    """Builds the command string for the HK IHK_PSU_VMEDN read command.

    Returns:
        Command string for the HK PSU IHK_PSU_VMEDN read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.IHK_PSU_VMEDN)


def ihk_psu_vmedp() -> str:
    """Builds the command string for the HK IHK_PSU_VMEDP read command.

    Returns:
        Command string for the HK PSU IHK_PSU_VMEDP read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.IHK_PSU_VMEDP)


def ihk_psu_vlow() -> str:
    """Builds the command string for the HK IHK_PSU_VLOW read command.

    Returns:
        Command string for the HK PSU IHK_PSU_VLOW read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.IHK_PSU_VLOW)


def ihk_psu_vhi():
    """Builds the command string for the HK IHK_PSU_VHI read command.

    Returns:
        Command string for the HK PSU IHK_PSU_VHI read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.IHK_PSU_VHI)


def ihk_psu_vmotor() -> str:
    """Builds the command string for the HK IHK_PSU_VMOTOR read command.

    Returns:
        Command string for the HK PSU IHK_PSU_VMOTOR read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.IHK_PSU_VMOTOR)


def thk_psu_first() -> str:
    """Builds the command string for the HK THK_PSU_FIRST read command.

    Returns:
        Command string for the HK PSU THK_PSU_FIRST read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_PSU_FIRST)


def thk_m2md_first() -> str:
    """Builds the command string for the HK THK_M2MD_FIRST read command.

    Returns:
        Command string for the HK M2MD THK_M2MD_FIRST read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_M2MD_FIRST)


def thk_psu_second() -> str:
    """Builds the command string for the HK THK_PSU_SECOND read command.

    Returns:
        Command string for the HK PSU THK_PSU_SECOND read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_PSU_SECOND)


def thk_m2md_second() -> str:
    """Builds the command string for the HK THK_M2MD_SECOND read command.

    Returns:
        Command string for the HK M2MD THK_M2MD_SECOND read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_M2MD_SECOND)


def thk_cts_q1() -> str:
    """Builds the command string for the HK THK_CTS_Q1 read command.

    Returns:
        Command string for the HK CTS THK_CTS_Q1 read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_Q1)


def thk_cts_q2() -> str:
    """Builds the command string for the HK THK_CTS_Q2 read command.

    Returns:
        Command string for the HK CTS THK_CTS_Q2 read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_Q2)


def thk_cts_q3() -> str:
    """Builds the command string for the HK THK_CTS_Q3 read command.

    Returns:
        Command string for the HK CTS THK_CTS_Q3 read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_Q3)


def thk_cts_q4() -> str:
    """Builds the command string for the HK THK_CTS_Q4 read command.

    Returns:
        Command string for the HK CTS THK_CTS_Q4 read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_Q4)


def thk_cts_fpga() -> str:
    """Builds the command string for the HK THK_CTS_FPGA read command.

    Returns:
        Command string for the HK CTS THK_CTS_FPGA read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_FPGA)


def thk_cts_ads1282() -> str:
    """Builds the command string for the HK THK_CTS_ADS1282 read command.

    Returns:
        Command string for the HK CTS THK_CTS_ADS1282 read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.THK_CTS_ADS1282)


def vhk_ths_ret() -> str:
    """Builds the command string for the HK VHK_THS_RET read command.

    Returns:
        Command string for the HK VHK_THS_RET read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.VHK_THS_RET)


def hk_acq_counter() -> str:
    """Builds the command string for the HK HK_ACQ_COUNTER read command.

    Returns:
        Command string for the HK HK_ACQ_COUNTER read command.
    """

    return _create_read_cmd_string(CommandAddress.HK, HKCommandIdentifier.HK_ACQ_COUNTER)


def general_cmd():
    """Decorator for general TCU commands.

    This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
    component of the TCU that the command is for (which is necessary in the TCU UI).
    """

    def decorator(func):
        func.target_comp = "GENERAL"
        return func

    return decorator


def m2md_cmd():
    """Decorator for M2MD commands.

    This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
    component of the TCU that the command is for (which is necessary in the TCU UI).
    """

    def decorator(func):
        func.target_comp = "M2MD"
        return func

    return decorator


def tsm_cmd():
    """Decorator for TSM commands.

    This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
    component of the TCU that the command is for (which is necessary in the TCU UI).
    """

    def decorator(func):
        func.target_comp = "TSM"
        return func

    return decorator


def hk_cmd():
    """Decorator for HK commands.

    This is used to decorate these commands in the TcuInterface class, to enable an easier identification of the
    component of the TCU that the command is for (which is necessary in the TCU UI).
    """

    def decorator(func):
        func.target_comp = "HK"
        return func

    return decorator
