nirfmxbluetooth 26.0.0
Python APIs for interacting with NI RFmx Bluetooth(R) Test Product
License: MIT
Requires Python: <4.0,>=3.9
Keywords: rfmx, nirfmx, nirfmxbluetooth

| **Info**      | Contains Python APIs for interacting with NI RFmx Bluetooth® Test Product. |
| :------------ | :------------------------------------------------------------------- |
| **Author**    | National Instruments                                                 |

# Table of Contents

- [Table of Contents](#table-of-contents)
- [About](#about)
  - [Documentation](#documentation)
  - [Operating System Support](#operating-system-support)
- [Installation](#installation)
- [License](#license)
- [Support and Feedback](#support-and-feedback)
- [Example](#example)


# About

The **nirfmx-python** repository generates Python bindings (Application Programming Interface)
for interacting with the NI RFmx Products.

**nirfmx-python** follows [Python Software Foundation](https://devguide.python.org/#status-of-python-branches)
support policy for different versions.


## RFmx Instr Python API Status

| Item                         | Details                      |
|------------------------------|-------------------------------|
| **Driver Version Tested**    | [2026 Q1](http://www.ni.com/downloads/)                      |
| **PyPI Package Version**     | v19.1                        |
| **Supported Python Versions**| Python 3.9+ (64-bit)    |
| **Documentation**            | [RFmx Instr Docs](https://nirfmx-python-nirfmxinstr.readthedocs-hosted.com/en/latest/) |


## RFmx Bluetooth® Test Python API Status

| Item                         | Details                      |
|------------------------------|-------------------------------|
| **Driver Version Tested**    | [2026 Q1](http://www.ni.com/downloads/)                      |
| **PyPI Package Version**     | v19.1                        |
| **Supported Python Versions**| Python 3.9+ (64-bit)    |
| **Documentation**            | [RFmx Bluetooth® Test Docs](https://nirfmx-python-nirfmxbluetooth.readthedocs-hosted.com/en/latest/) |


## Documentation

You can find the latest API documentation for the **nirfmx-python** package
on [Read the Docs](https://nirfmx-python-nirfmxinstr.readthedocs-hosted.com/en/latest/)

Refer to the [NI RFmx User Manual](https://www.ni.com/docs/en-US/bundle/rfmx/page/user-manual-welcome.html)
for an overview of NI RFmx, system requirements, troubleshooting, key concepts, etc.


## Operating System Support

**nirfmx-python** supports Windows systems where the supported drivers are 
installed. Refer to [NI Hardware and Operating System Compatibility](https://www.ni.com/r/hw-support) for 
which versions of the driver support your hardware on a given operating system.


## Installation

You can use [pip](http://pypi.python.org/pypi/pip) to download [nirfmxbluetooth](https://pypi.org/project/nirfmxbluetooth/) and install it.
    
    $ python -m pip install nirfmxbluetooth

## Upgrade

You can use [pip](http://pypi.python.org/pypi/pip) to upgrade [nirfmxbluetooth](https://pypi.org/project/nirfmxbluetooth/) package using following command:

    $ python -m pip install nirfmxbluetooth --upgrade

## License

This project is licensed under the MIT License. While the source code is not publicly released,
the license permits binary distribution with attribution.

**Note:** This Python driver depends on several third-party components that are subject to separate
commercial licenses. Users are responsible for ensuring they have the appropriate rights and licenses
to use those dependencies in their environments.


# gRPC Features

For driver APIs that support it, passing a GrpcSessionOptions instance as a parameter to nirfmxinstr.Session.__init__() is subject to the NI General Purpose EULA.


# SSL/TLS Support

The server supports both server-side TLS and mutual TLS. Security configuration is accomplished by setting the `server_cert`, `server_key` and `root_cert` values in the server's configuration file. The server expects the certificate files specified in the configuration file to exist in a `certs` folder that is located in the same directory as the configuration file being used by the server. For more detailed information on SSL/TLS support refer to the [Server Security Support wiki page](https://github.com/ni/grpc-device/wiki/Server-Security-Support).


## Support and Feedback

For support with Python API, hardware, the driver runtime or any other questions,
please visit [NI Community Forums](https://forums.ni.com/).

## RFmxBluetooth Example

```python
import nirfmxinstr
import nirfmxbluetooth
import numpy

instr_session = None
bluetooth_signal = None

try:
    # Create a new RFmx Session
    instr_session = nirfmxinstr.Session(resource_name="RFSA", option_string="")

    # Get Bluetooth signal configuration
    bluetooth_signal = instr_session.get_bluetooth_signal_configuration()

    # Configure frequency reference
    instr_session.configure_frequency_reference(selector_string="",
      frequency_reference_source="OnboardClock", frequency_reference_frequency=10e6)

    # Configure RF settings
    bluetooth_signal.configure_rf(selector_string="", center_frequency=2.402e9,
      reference_level=0.00, external_attenuation=0.0)

    # Configure trigger
    bluetooth_signal.configure_iq_power_edge_trigger(
        selector_string="",
        iq_power_edge_trigger_source="0",
        iq_power_edge_trigger_slope=nirfmxbluetooth.IQPowerEdgeTriggerSlope.RISING,
        iq_power_edge_trigger_level=-20.0,
        trigger_delay=0.0,
        trigger_minimum_quiet_time_mode=nirfmxbluetooth.TriggerMinimumQuietTimeMode.AUTO,
        trigger_minimum_quiet_time_duration=100e-6,
        iq_power_edge_trigger_level_type=nirfmxbluetooth.IQPowerEdgeTriggerLevelType.RELATIVE,
        enable_trigger=True
    )

    # Configure packet settings
    bluetooth_signal.configure_packet_type(selector_string="",
      packet_type=nirfmxbluetooth.PacketType.PACKET_TYPE_DH1)
    bluetooth_signal.configure_data_rate(selector_string="", data_rate=1000000)
    bluetooth_signal.configure_payload_length(selector_string="",
      payload_length_mode=nirfmxbluetooth.PayloadLengthMode.AUTO, payload_length=10)

    # Select measurements
    bluetooth_signal.select_measurements(selector_string="",
      measurements=nirfmxbluetooth.MeasurementTypes.ACP, enable_all_traces=True)

    # Configure ACP measurement
    bluetooth_signal.acp.configuration.configure_burst_synchronization_type(selector_string="",
      burst_synchronization_type=nirfmxbluetooth.AcpBurstSynchronizationType.PREAMBLE)
    bluetooth_signal.acp.configuration.configure_averaging(selector_string="",
      averaging_enabled=nirfmxbluetooth.AcpAveragingEnabled.FALSE, averaging_count=10)
    bluetooth_signal.acp.configuration.configure_offset_channel_mode(selector_string="",
      offset_channel_mode=nirfmxbluetooth.AcpOffsetChannelMode.SYMMETRIC)

    number_of_offsets = 5
    channel_number = 0
    offset_channel_mode = nirfmxbluetooth.AcpOffsetChannelMode.SYMMETRIC

    if offset_channel_mode == nirfmxbluetooth.AcpOffsetChannelMode.SYMMETRIC:
        bluetooth_signal.acp.configuration.configure_number_of_offsets(selector_string="",
          number_of_offsets)
    elif offset_channel_mode == nirfmxbluetooth.AcpOffsetChannelMode.INBAND:
        bluetooth_signal.configure_channel_number(selector_string="", channel_number)

    # Initiate measurement
    error_code = bluetooth_signal.initiate(selector_string="", result_name="")

    # Retrieve results
    measurement_status, error_code = bluetooth_signal.acp.results.fetch_measurement_status(
      selector_string="", timeout=10.0)
    print(f"Measurement Status: {measurement_status}")

    reference_channel_power, error_code = bluetooth_signal.acp.results.fetch_reference_channel_power
      (selector_string="", timeout=10.0)
    print(f"Reference Channel Power (dBm): {reference_channel_power}")

    (
        lower_absolute_power,
        upper_absolute_power,
        lower_relative_power,
        upper_relative_power,
        lower_margin,
        upper_margin,
        error_code
    ) = bluetooth_signal.acp.results.fetch_offset_measurement_array(selector_string="", timeout=10.0)

    # Fetch traces
    limit_with_exception_mask = numpy.empty(0, dtype=numpy.float32)
    limit_without_exception_mask = numpy.empty(0, dtype=numpy.float32)
    x0_mask, dx_mask, error_code = bluetooth_signal.acp.results.fetch_mask_trace(
        selector_string="", 
        timeout=10.0, 
        limit_with_exception_mask=limit_with_exception_mask, 
        limit_without_exception_mask=limit_without_exception_mask
    )

    absolute_power_trace = numpy.empty(0, dtype=numpy.float32)
    x0_abs, dx_abs, error_code = bluetooth_signal.acp.results.fetch_absolute_power_trace(
        selector_string="", 
        timeout=10.0, 
        absolute_power=absolute_power_trace
    )

    spectrum = numpy.empty(0, dtype=numpy.float32)
    x0_spec, dx_spec, error_code = bluetooth_signal.acp.results.fetch_spectrum(
        selector_string="", timeout=10.0, spectrum=spectrum
    )

    # Print Results
    print("------------------ACP------------------")
    print(f"Measurement Status                 : {measurement_status}")
    print(f"Reference Channel Power (dBm)      : {reference_channel_power}")
    print()

    print("------------------Offset Measurements------------------")
    for i in range(len(lower_absolute_power)):
        print(f"Offset {i}")
        print(f"Lower Absolute Powers (dBm)        : {lower_absolute_power[i]}")
        print(f"Upper Absolute Powers (dBm)        : {upper_absolute_power[i]}")
        print(f"Lower Relative Powers (dB)         : {lower_relative_power[i]}")
        print(f"Upper Relative Powers (dB)         : {upper_relative_power[i]}")
        print(f"Lower Margin (dB)                  : {lower_margin[i]}")
        print(f"Upper Margin (dB)                  : {upper_margin[i]}")
        print()

except Exception as e:
    print("ERROR: " + str(e))

finally:
    # Close Session
    if bluetooth_signal is not None:
        bluetooth_signal.dispose()
        bluetooth_signal = None
    if instr_session is not None:
        instr_session.close()
        instr_session = None
```