Skip to content

xwr.radar

Interface implementation for generic TI demo MSS firmware.

Usage

After selecting the appropriate XWRXXXX interface:

  1. Initialization parameters can be defaults. The port may need to be changed if multiple radars are being used, or another device uses the /dev/ttyACM0 default name. The baudrate should not be changed.
  2. Setup with .setup(...) with the desired radar configuration.
  3. Start the radar with .start().
  4. Stop the radar with .stop().

Info

You may need to provide read/write permissions to access the serial port:

sudo chmod 777 /dev/ttyACM0  # or whatever port the radar is on.

Danger

If the configuration is invalid, .start() may return an error, or cause the radar to freeze. This may require the radar to be rebooted via manually disconnecting the power supply.

xwr.radar.AWR1642

Bases: XWRBase

Interface implementation for the TI AWR1642 family.

Supported devices

  • AWR1642Boost

Parameters:

Name Type Description Default
port str | None

radar control serial port; typically the lower numbered one.

None
baudrate int

baudrate of control port.

115200
name str

human-readable name.

'AWR1642'
Source code in src/xwr/radar/api.py
class AWR1642(XWRBase):
    """Interface implementation for the TI AWR1642 family.

    !!! info "Supported devices"

        - AWR1642Boost

    Args:
        port: radar control serial port; typically the lower numbered one.
        baudrate: baudrate of control port.
        name: human-readable name.
    """

    _PORT_NAME = r'XDS110'
    NUM_TX = 2
    NUM_RX = 4

    def __init__(
        self, port: str | None = None, baudrate: int = 115200,
        name: str = "AWR1642"
    ) -> None:
        super().__init__(port=port, baudrate=baudrate, name=name)

    def setup(
        self, frequency: float = 77.0, idle_time: float = 110.0,
        adc_start_time: float = 4.0, ramp_end_time: float = 56.0,
        tx_start_time: float = 1.0, freq_slope: float = 70.006,
        adc_samples: int = 256, sample_rate: int = 5000,
        frame_length: int = 64, frame_period: float = 100.0
    ) -> None:
        """Configure radar.

        Args:
            frequency: frequency band, in GHz; 77.0 or 76.0.
            idle_time: see TI chirp timing documentation; in us.
            adc_start_time: see TI chirp timing documentation; in us.
            ramp_end_time: see TI chirp timing documentation; in us.
            tx_start_time: see TI chirp timing documentation; in us.
            freq_slope: chirp frequency slope; in MHz/us.
            adc_samples: number of samples per chirp.
            sample_rate: ADC sampling rate; in ksps.
            frame_length: chirps per frame per TX antenna. Must be a power of 2.
            frame_period: time between the start of each frame; in ms.
        """
        assert frame_length & (frame_length - 1) == 0

        self.stop()
        self.flushCfg()
        self.dfeDataOutputMode(defines.DFEMode.LEGACY)
        self.adcCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
        self.adcbufCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
        self.profileCfg(
            startFreq=frequency, idleTime=idle_time,
            adcStartTime=adc_start_time, rampEndTime=ramp_end_time,
            txStartTime=tx_start_time, freqSlopeConst=freq_slope,
            numAdcSamples=adc_samples, digOutSampleRate=sample_rate)

        self._configure_channels(rx=0b1111, tx=0b011)
        self.frameCfg(
            numLoops=frame_length, chirpEndIdx=self.NUM_TX - 1,
            framePeriodicity=frame_period)
        self.compRangeBiasAndRxChanPhase(rx_phase = [(0, 1)] * 4 * 2)
        self.send("bpmCfg -1 0 0 1")
        self.lvdsStreamCfg()

        self.boilerplate_setup()
        self.log.info("Radar setup complete.")

    def lowPower(self, dontCare: int = 0, adcMode: int = 1) -> None:
        """Low power mode config.

        !!! warning

            For some reason, the AWR1642 requires `adcMode=1`. Not sure what
            this does.
        """
        cmd = "lowPower {} {}".format(dontCare, adcMode)
        self.send(cmd)

lowPower

lowPower(dontCare: int = 0, adcMode: int = 1) -> None

Low power mode config.

Warning

For some reason, the AWR1642 requires adcMode=1. Not sure what this does.

Source code in src/xwr/radar/api.py
def lowPower(self, dontCare: int = 0, adcMode: int = 1) -> None:
    """Low power mode config.

    !!! warning

        For some reason, the AWR1642 requires `adcMode=1`. Not sure what
        this does.
    """
    cmd = "lowPower {} {}".format(dontCare, adcMode)
    self.send(cmd)

setup

setup(
    frequency: float = 77.0,
    idle_time: float = 110.0,
    adc_start_time: float = 4.0,
    ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0,
    freq_slope: float = 70.006,
    adc_samples: int = 256,
    sample_rate: int = 5000,
    frame_length: int = 64,
    frame_period: float = 100.0,
) -> None

Configure radar.

Parameters:

Name Type Description Default
frequency float

frequency band, in GHz; 77.0 or 76.0.

77.0
idle_time float

see TI chirp timing documentation; in us.

110.0
adc_start_time float

see TI chirp timing documentation; in us.

4.0
ramp_end_time float

see TI chirp timing documentation; in us.

56.0
tx_start_time float

see TI chirp timing documentation; in us.

1.0
freq_slope float

chirp frequency slope; in MHz/us.

70.006
adc_samples int

number of samples per chirp.

256
sample_rate int

ADC sampling rate; in ksps.

5000
frame_length int

chirps per frame per TX antenna. Must be a power of 2.

64
frame_period float

time between the start of each frame; in ms.

100.0
Source code in src/xwr/radar/api.py
def setup(
    self, frequency: float = 77.0, idle_time: float = 110.0,
    adc_start_time: float = 4.0, ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0, freq_slope: float = 70.006,
    adc_samples: int = 256, sample_rate: int = 5000,
    frame_length: int = 64, frame_period: float = 100.0
) -> None:
    """Configure radar.

    Args:
        frequency: frequency band, in GHz; 77.0 or 76.0.
        idle_time: see TI chirp timing documentation; in us.
        adc_start_time: see TI chirp timing documentation; in us.
        ramp_end_time: see TI chirp timing documentation; in us.
        tx_start_time: see TI chirp timing documentation; in us.
        freq_slope: chirp frequency slope; in MHz/us.
        adc_samples: number of samples per chirp.
        sample_rate: ADC sampling rate; in ksps.
        frame_length: chirps per frame per TX antenna. Must be a power of 2.
        frame_period: time between the start of each frame; in ms.
    """
    assert frame_length & (frame_length - 1) == 0

    self.stop()
    self.flushCfg()
    self.dfeDataOutputMode(defines.DFEMode.LEGACY)
    self.adcCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.adcbufCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.profileCfg(
        startFreq=frequency, idleTime=idle_time,
        adcStartTime=adc_start_time, rampEndTime=ramp_end_time,
        txStartTime=tx_start_time, freqSlopeConst=freq_slope,
        numAdcSamples=adc_samples, digOutSampleRate=sample_rate)

    self._configure_channels(rx=0b1111, tx=0b011)
    self.frameCfg(
        numLoops=frame_length, chirpEndIdx=self.NUM_TX - 1,
        framePeriodicity=frame_period)
    self.compRangeBiasAndRxChanPhase(rx_phase = [(0, 1)] * 4 * 2)
    self.send("bpmCfg -1 0 0 1")
    self.lvdsStreamCfg()

    self.boilerplate_setup()
    self.log.info("Radar setup complete.")

start

start(reconfigure: bool = True) -> None

Start radar.

Parameters:

Name Type Description Default
reconfigure bool

Whether the radar needs to be configured.

True
Source code in src/xwr/radar/base.py
def start(self, reconfigure: bool = True) -> None:
    """Start radar.

    Args:
        reconfigure: Whether the radar needs to be configured.
    """
    if reconfigure:
        self.send("sensorStart")
    else:
        self.send("sensorStart 0")

    self.log.info("Radar Started.")

stop

stop() -> None

Stop radar.

Warning

The radar may be non-responsive to commands in some conditions, for example if the specified timings are fairly tight (or invalid).

Source code in src/xwr/radar/base.py
def stop(self) -> None:
    """Stop radar.

    !!! warning

        The radar may be non-responsive to commands in some conditions, for
        example if the specified timings are fairly tight (or invalid).
    """
    self.send("sensorStop")
    self.log.info("Radar Stopped.")

xwr.radar.AWR1843

Bases: XWRBase

Interface implementation for the TI AWR1843 family.

Supported devices

  • AWR1843Boost
  • AWR1843AOPEVM

Parameters:

Name Type Description Default
port str | None

radar control serial port; typically the lower numbered one.

None
baudrate int

baudrate of control port.

115200
name str

human-readable name.

'AWR1843'
Source code in src/xwr/radar/api.py
class AWR1843(XWRBase):
    """Interface implementation for the TI AWR1843 family.

    !!! info "Supported devices"

        - AWR1843Boost
        - AWR1843AOPEVM

    Args:
        port: radar control serial port; typically the lower numbered one.
        baudrate: baudrate of control port.
        name: human-readable name.
    """

    _PORT_NAME = r'(?=.*CP2105)(?=.*Enhanced)|XDS110'
    _TX_MASK = 0b111
    NUM_TX = 3
    NUM_RX = 4

    def __init__(
        self, port: str | None = None, baudrate: int = 115200,
        name: str = "AWR1843"
    ) -> None:
        super().__init__(port=port, baudrate=baudrate, name=name)

    def setup(
        self, frequency: float = 77.0, idle_time: float = 110.0,
        adc_start_time: float = 4.0, ramp_end_time: float = 56.0,
        tx_start_time: float = 1.0, freq_slope: float = 70.006,
        adc_samples: int = 256, sample_rate: int = 5000,
        frame_length: int = 64, frame_period: float = 100.0
    ) -> None:
        """Configure radar.

        Args:
            frequency: frequency band, in GHz; 77.0 or 76.0.
            idle_time: see TI chirp timing documentation; in us.
            adc_start_time: see TI chirp timing documentation; in us.
            ramp_end_time: see TI chirp timing documentation; in us.
            tx_start_time: see TI chirp timing documentation; in us.
            freq_slope: chirp frequency slope; in MHz/us.
            adc_samples: number of samples per chirp.
            sample_rate: ADC sampling rate; in ksps.
            frame_length: chirps per frame per TX antenna. Must be a power of 2.
            frame_period: time between the start of each frame; in ms.
        """
        assert frame_length & (frame_length - 1) == 0

        self.stop()
        self.flushCfg()
        self.dfeDataOutputMode(defines.DFEMode.LEGACY)
        self.adcCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
        self.adcbufCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
        self.profileCfg(
            startFreq=frequency, idleTime=idle_time,
            adcStartTime=adc_start_time, rampEndTime=ramp_end_time,
            txStartTime=tx_start_time, freqSlopeConst=freq_slope,
            numAdcSamples=adc_samples, digOutSampleRate=sample_rate)

        self._configure_channels(rx=0b1111, tx=self._TX_MASK)
        self.frameCfg(
            numLoops=frame_length, chirpEndIdx=self.NUM_TX - 1,
            framePeriodicity=frame_period)
        self.compRangeBiasAndRxChanPhase(rx_phase = [(0, 1)] * 4 * 3)
        self.lvdsStreamCfg()

        self.boilerplate_setup()
        self.log.info("Radar setup complete.")

setup

setup(
    frequency: float = 77.0,
    idle_time: float = 110.0,
    adc_start_time: float = 4.0,
    ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0,
    freq_slope: float = 70.006,
    adc_samples: int = 256,
    sample_rate: int = 5000,
    frame_length: int = 64,
    frame_period: float = 100.0,
) -> None

Configure radar.

Parameters:

Name Type Description Default
frequency float

frequency band, in GHz; 77.0 or 76.0.

77.0
idle_time float

see TI chirp timing documentation; in us.

110.0
adc_start_time float

see TI chirp timing documentation; in us.

4.0
ramp_end_time float

see TI chirp timing documentation; in us.

56.0
tx_start_time float

see TI chirp timing documentation; in us.

1.0
freq_slope float

chirp frequency slope; in MHz/us.

70.006
adc_samples int

number of samples per chirp.

256
sample_rate int

ADC sampling rate; in ksps.

5000
frame_length int

chirps per frame per TX antenna. Must be a power of 2.

64
frame_period float

time between the start of each frame; in ms.

100.0
Source code in src/xwr/radar/api.py
def setup(
    self, frequency: float = 77.0, idle_time: float = 110.0,
    adc_start_time: float = 4.0, ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0, freq_slope: float = 70.006,
    adc_samples: int = 256, sample_rate: int = 5000,
    frame_length: int = 64, frame_period: float = 100.0
) -> None:
    """Configure radar.

    Args:
        frequency: frequency band, in GHz; 77.0 or 76.0.
        idle_time: see TI chirp timing documentation; in us.
        adc_start_time: see TI chirp timing documentation; in us.
        ramp_end_time: see TI chirp timing documentation; in us.
        tx_start_time: see TI chirp timing documentation; in us.
        freq_slope: chirp frequency slope; in MHz/us.
        adc_samples: number of samples per chirp.
        sample_rate: ADC sampling rate; in ksps.
        frame_length: chirps per frame per TX antenna. Must be a power of 2.
        frame_period: time between the start of each frame; in ms.
    """
    assert frame_length & (frame_length - 1) == 0

    self.stop()
    self.flushCfg()
    self.dfeDataOutputMode(defines.DFEMode.LEGACY)
    self.adcCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.adcbufCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.profileCfg(
        startFreq=frequency, idleTime=idle_time,
        adcStartTime=adc_start_time, rampEndTime=ramp_end_time,
        txStartTime=tx_start_time, freqSlopeConst=freq_slope,
        numAdcSamples=adc_samples, digOutSampleRate=sample_rate)

    self._configure_channels(rx=0b1111, tx=self._TX_MASK)
    self.frameCfg(
        numLoops=frame_length, chirpEndIdx=self.NUM_TX - 1,
        framePeriodicity=frame_period)
    self.compRangeBiasAndRxChanPhase(rx_phase = [(0, 1)] * 4 * 3)
    self.lvdsStreamCfg()

    self.boilerplate_setup()
    self.log.info("Radar setup complete.")

start

start(reconfigure: bool = True) -> None

Start radar.

Parameters:

Name Type Description Default
reconfigure bool

Whether the radar needs to be configured.

True
Source code in src/xwr/radar/base.py
def start(self, reconfigure: bool = True) -> None:
    """Start radar.

    Args:
        reconfigure: Whether the radar needs to be configured.
    """
    if reconfigure:
        self.send("sensorStart")
    else:
        self.send("sensorStart 0")

    self.log.info("Radar Started.")

stop

stop() -> None

Stop radar.

Warning

The radar may be non-responsive to commands in some conditions, for example if the specified timings are fairly tight (or invalid).

Source code in src/xwr/radar/base.py
def stop(self) -> None:
    """Stop radar.

    !!! warning

        The radar may be non-responsive to commands in some conditions, for
        example if the specified timings are fairly tight (or invalid).
    """
    self.send("sensorStop")
    self.log.info("Radar Stopped.")

xwr.radar.AWR1843L

Bases: AWR1843

TI AWR1843Boost with its middle antenna disabled.

Supported devices

  • AWR1843Boost, with the middle TX antenna which is 1/2-wavelength above the other two disabled.

Parameters:

Name Type Description Default
port str | None

radar control serial port; typically the lower numbered one.

None
baudrate int

baudrate of control port.

115200
name str

human-readable name.

'AWR1843'
Source code in src/xwr/radar/api.py
class AWR1843L(AWR1843):
    """TI AWR1843Boost with its middle antenna disabled.

    !!! info "Supported devices"

        - AWR1843Boost, with the middle TX antenna which is 1/2-wavelength
          above the other two disabled.

    Args:
        port: radar control serial port; typically the lower numbered one.
        baudrate: baudrate of control port.
        name: human-readable name.
    """

    _TX_MASK = 0b101
    NUM_TX = 2
    NUM_RX = 4

setup

setup(
    frequency: float = 77.0,
    idle_time: float = 110.0,
    adc_start_time: float = 4.0,
    ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0,
    freq_slope: float = 70.006,
    adc_samples: int = 256,
    sample_rate: int = 5000,
    frame_length: int = 64,
    frame_period: float = 100.0,
) -> None

Configure radar.

Parameters:

Name Type Description Default
frequency float

frequency band, in GHz; 77.0 or 76.0.

77.0
idle_time float

see TI chirp timing documentation; in us.

110.0
adc_start_time float

see TI chirp timing documentation; in us.

4.0
ramp_end_time float

see TI chirp timing documentation; in us.

56.0
tx_start_time float

see TI chirp timing documentation; in us.

1.0
freq_slope float

chirp frequency slope; in MHz/us.

70.006
adc_samples int

number of samples per chirp.

256
sample_rate int

ADC sampling rate; in ksps.

5000
frame_length int

chirps per frame per TX antenna. Must be a power of 2.

64
frame_period float

time between the start of each frame; in ms.

100.0
Source code in src/xwr/radar/api.py
def setup(
    self, frequency: float = 77.0, idle_time: float = 110.0,
    adc_start_time: float = 4.0, ramp_end_time: float = 56.0,
    tx_start_time: float = 1.0, freq_slope: float = 70.006,
    adc_samples: int = 256, sample_rate: int = 5000,
    frame_length: int = 64, frame_period: float = 100.0
) -> None:
    """Configure radar.

    Args:
        frequency: frequency band, in GHz; 77.0 or 76.0.
        idle_time: see TI chirp timing documentation; in us.
        adc_start_time: see TI chirp timing documentation; in us.
        ramp_end_time: see TI chirp timing documentation; in us.
        tx_start_time: see TI chirp timing documentation; in us.
        freq_slope: chirp frequency slope; in MHz/us.
        adc_samples: number of samples per chirp.
        sample_rate: ADC sampling rate; in ksps.
        frame_length: chirps per frame per TX antenna. Must be a power of 2.
        frame_period: time between the start of each frame; in ms.
    """
    assert frame_length & (frame_length - 1) == 0

    self.stop()
    self.flushCfg()
    self.dfeDataOutputMode(defines.DFEMode.LEGACY)
    self.adcCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.adcbufCfg(adcOutputFmt=defines.ADCFormat.COMPLEX_1X)
    self.profileCfg(
        startFreq=frequency, idleTime=idle_time,
        adcStartTime=adc_start_time, rampEndTime=ramp_end_time,
        txStartTime=tx_start_time, freqSlopeConst=freq_slope,
        numAdcSamples=adc_samples, digOutSampleRate=sample_rate)

    self._configure_channels(rx=0b1111, tx=self._TX_MASK)
    self.frameCfg(
        numLoops=frame_length, chirpEndIdx=self.NUM_TX - 1,
        framePeriodicity=frame_period)
    self.compRangeBiasAndRxChanPhase(rx_phase = [(0, 1)] * 4 * 3)
    self.lvdsStreamCfg()

    self.boilerplate_setup()
    self.log.info("Radar setup complete.")

start

start(reconfigure: bool = True) -> None

Start radar.

Parameters:

Name Type Description Default
reconfigure bool

Whether the radar needs to be configured.

True
Source code in src/xwr/radar/base.py
def start(self, reconfigure: bool = True) -> None:
    """Start radar.

    Args:
        reconfigure: Whether the radar needs to be configured.
    """
    if reconfigure:
        self.send("sensorStart")
    else:
        self.send("sensorStart 0")

    self.log.info("Radar Started.")

stop

stop() -> None

Stop radar.

Warning

The radar may be non-responsive to commands in some conditions, for example if the specified timings are fairly tight (or invalid).

Source code in src/xwr/radar/base.py
def stop(self) -> None:
    """Stop radar.

    !!! warning

        The radar may be non-responsive to commands in some conditions, for
        example if the specified timings are fairly tight (or invalid).
    """
    self.send("sensorStop")
    self.log.info("Radar Stopped.")

xwr.radar.XWRBase

Bases: APIMixins, BoilerplateMixins

Generic AWR Interface for the TI demo MSS firmware.

The interface is based on a UART ASCII CLI, and is documented by the following sources:

Warning

We only implement a partial API. Non-mandatory calls which do not affect the LVDS raw I/Q stream are not implemented.

Info

If the radar serial port is not provided, we auto-detect the port by fetching the lowest-numbered one which contains "XDS110" in the USB device description (Or "CP2105 ... Enhanced" in the case of the AWR1843AOPEVM), which corresponds to the TI XDS110 JTAG debugger embedded in each radar dev board.

Parameters:

Name Type Description Default
port str | None

radar control serial port; typically the lower numbered one. If not provided (None), we attempt to auto-detect the port.

None
baudrate int

baudrate of control port.

115200
name str

human-readable name.

'AWR1843'

Attributes:

Name Type Description
NUM_TX int

number of TX antennas.

NUM_RX int

number of RX antennas.

Source code in src/xwr/radar/base.py
class XWRBase(APIMixins, BoilerplateMixins):
    """Generic AWR Interface for the TI demo MSS firmware.

    The interface is based on a UART ASCII CLI, and is documented by the
    following sources:

    - The `packages/ti/demo/xwr18xx/mmw` folder in the mmWave SDK install.
    - [mmWave SDK user guide, Table 1 (Page 19)](
        https://dr-download.ti.com/software-development/software-development-kit-sdk/MD-PIrUeCYr3X/03.06.00.00-LTS/mmwave_sdk_user_guide.pdf)
    - [mmWave Studio](https://www.ti.com/tool/MMWAVE-STUDIO)
    - [AWR1843 Data Sheet](
        https://www.ti.com/lit/ds/symlink/awr1843.pdf?ts=1708800208074)

    !!! warning

        We only implement a partial API. Non-mandatory calls which do not
        affect the LVDS raw I/Q stream are not implemented.

    !!! info

        If the radar serial port is not provided, we auto-detect the port by
        fetching the lowest-numbered one which contains "XDS110" in the USB
        device description (Or "CP2105 ... Enhanced" in the case of the
        AWR1843AOPEVM), which corresponds to the [TI XDS110 JTAG debugger](
        https://www.ti.com/tool/TMDSEMU110-U) embedded in each radar dev board.

    Args:
        port: radar control serial port; typically the lower numbered one. If
            not provided (`None`), we attempt to auto-detect the port.
        baudrate: baudrate of control port.
        name: human-readable name.

    Attributes:
        NUM_TX: number of TX antennas.
        NUM_RX: number of RX antennas.
    """

    _CMD_PROMPT = "mmwDemo:/>"
    _PORT_NAME = r"XDS110"

    NUM_TX: int = 3
    NUM_RX: int = 4

    def __init__(
        self, port: str | None = None, baudrate: int = 115200,
        name: str = "AWR1843"
    ) -> None:
        self.log: logging.Logger = logging.getLogger(name=name)

        if port is None:
            port = self.__detect_port()
            self.log.info(f"Auto-detected port: {port}")

        self.port: serial.Serial = serial.Serial(port, baudrate, timeout=None)

        # Only linux supports low latency mode.
        if hasattr(self.port, 'set_low_latency_mode'):
            self.port.set_low_latency_mode(True)
        else:
            self.log.warning(
                "Low latency mode is only supported on linux. This may cause "
                "initialization to take longer than expected.")

        self.port.reset_input_buffer()
        self.port.reset_output_buffer()

    def __detect_port(self) -> str:
        sorted_ports = sorted(list_ports.comports(), key=lambda x: x.device)
        for port in sorted_ports:
            if port.description is not None:
                if re.match(self._PORT_NAME, port.description, re.IGNORECASE):
                    return port.device

        self.log.error("Failed to auto-detect radar port.")
        raise XWRError(
            "Auto-detecting the radar port (`port=None`) failed: none of the "
            f"available ports contain '{self._PORT_NAME}' in the "
            "USB description. "
            f"Available ports: {[p.device for p in list_ports.comports()]}")

    def setup_from_config(self, path: str) -> None:
        """Run raw setup from a config file."""
        with open(path) as f:
            cmds = f.readlines()
        for c in cmds:
            self.send(c.rstrip('\n'))

    def setup(self, *args, **kwargs) -> None:
        raise NotImplementedError

    def send(self, cmd: str, timeout: float = 10.0) -> None:
        """Send message, and wait for a response.

        Args:
            cmd: command to send.
            timeout: timeout, in seconds.

        Raises:
            TimeoutError: if no response is received by the timeout.
        """
        self.log.debug("Send: {}".format(cmd))
        self.port.write((cmd + '\n').encode('ascii'))

        # Read until we get "...\rmmwDemo:/>"
        rx_buf = bytearray()
        prompt = self._CMD_PROMPT.encode('utf-8')
        start = time.time()
        while not rx_buf.endswith(prompt):
            rx_buf.extend(self.port.read(self.port.in_waiting))
            if time.time() - start > timeout:
                self.log.error("Timed out while waiting for response.")
                raise TimeoutError()

        # Remove all the cruft
        decoded = rx_buf.decode('utf-8', errors='replace')
        resp = (
            decoded
            .replace(self._CMD_PROMPT, '').replace(cmd, '')
            .rstrip(' ;\r\n\t').lstrip(' \n\t'))
        self.log.log(5, "Response: {}".format(resp))

        # Check for non-normal response
        if resp != 'Done':
            if resp.startswith("Ignored"):
                self.log.warning(resp)
            elif resp.startswith("Debug") or resp.startswith("Skipped"):
                if "Error" in resp:
                    self.log.error(resp)
            elif '*****' in resp:
                pass  # header
            else:
                self.log.error(resp)
                self.log.info(f"Raw buffer for this error was: {decoded}")
                raise XWRError(resp)

    def start(self, reconfigure: bool = True) -> None:
        """Start radar.

        Args:
            reconfigure: Whether the radar needs to be configured.
        """
        if reconfigure:
            self.send("sensorStart")
        else:
            self.send("sensorStart 0")

        self.log.info("Radar Started.")

    def stop(self) -> None:
        """Stop radar.

        !!! warning

            The radar may be non-responsive to commands in some conditions, for
            example if the specified timings are fairly tight (or invalid).
        """
        self.send("sensorStop")
        self.log.info("Radar Stopped.")

    def _configure_channels(self, rx: int = 0b1111, tx: int = 0b111) -> None:
        """Configure RX and TX channels with sequential chirps.

        Args:
            rx: RX channel mask, e.g. `0b1111` for 4 RX antennas.
            tx: TX channel mask, e.g. `0b111` for 3 TX antennas.
        """
        self.channelCfg(rxChannelEn=rx, txChannelEn=tx)
        chirp = 0
        i_tx = 0
        while tx > 0:
            if tx & 1:
                self.chirpCfg(chirpIdx=chirp, txEnable=i_tx)
                chirp += 1
            tx = tx >> 1
            i_tx += 1

send

send(cmd: str, timeout: float = 10.0) -> None

Send message, and wait for a response.

Parameters:

Name Type Description Default
cmd str

command to send.

required
timeout float

timeout, in seconds.

10.0

Raises:

Type Description
TimeoutError

if no response is received by the timeout.

Source code in src/xwr/radar/base.py
def send(self, cmd: str, timeout: float = 10.0) -> None:
    """Send message, and wait for a response.

    Args:
        cmd: command to send.
        timeout: timeout, in seconds.

    Raises:
        TimeoutError: if no response is received by the timeout.
    """
    self.log.debug("Send: {}".format(cmd))
    self.port.write((cmd + '\n').encode('ascii'))

    # Read until we get "...\rmmwDemo:/>"
    rx_buf = bytearray()
    prompt = self._CMD_PROMPT.encode('utf-8')
    start = time.time()
    while not rx_buf.endswith(prompt):
        rx_buf.extend(self.port.read(self.port.in_waiting))
        if time.time() - start > timeout:
            self.log.error("Timed out while waiting for response.")
            raise TimeoutError()

    # Remove all the cruft
    decoded = rx_buf.decode('utf-8', errors='replace')
    resp = (
        decoded
        .replace(self._CMD_PROMPT, '').replace(cmd, '')
        .rstrip(' ;\r\n\t').lstrip(' \n\t'))
    self.log.log(5, "Response: {}".format(resp))

    # Check for non-normal response
    if resp != 'Done':
        if resp.startswith("Ignored"):
            self.log.warning(resp)
        elif resp.startswith("Debug") or resp.startswith("Skipped"):
            if "Error" in resp:
                self.log.error(resp)
        elif '*****' in resp:
            pass  # header
        else:
            self.log.error(resp)
            self.log.info(f"Raw buffer for this error was: {decoded}")
            raise XWRError(resp)

setup_from_config

setup_from_config(path: str) -> None

Run raw setup from a config file.

Source code in src/xwr/radar/base.py
def setup_from_config(self, path: str) -> None:
    """Run raw setup from a config file."""
    with open(path) as f:
        cmds = f.readlines()
    for c in cmds:
        self.send(c.rstrip('\n'))

start

start(reconfigure: bool = True) -> None

Start radar.

Parameters:

Name Type Description Default
reconfigure bool

Whether the radar needs to be configured.

True
Source code in src/xwr/radar/base.py
def start(self, reconfigure: bool = True) -> None:
    """Start radar.

    Args:
        reconfigure: Whether the radar needs to be configured.
    """
    if reconfigure:
        self.send("sensorStart")
    else:
        self.send("sensorStart 0")

    self.log.info("Radar Started.")

stop

stop() -> None

Stop radar.

Warning

The radar may be non-responsive to commands in some conditions, for example if the specified timings are fairly tight (or invalid).

Source code in src/xwr/radar/base.py
def stop(self) -> None:
    """Stop radar.

    !!! warning

        The radar may be non-responsive to commands in some conditions, for
        example if the specified timings are fairly tight (or invalid).
    """
    self.send("sensorStop")
    self.log.info("Radar Stopped.")

xwr.radar.XWRError

Bases: Exception

Error raised by the Radar (via non-normal return message).

Source code in src/xwr/radar/base.py
class XWRError(Exception):
    """Error raised by the Radar (via non-normal return message)."""

    pass