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.

CC2640: Disconnection between Aoa master and Aoa slave via Python code

Part Number: CC2640

Hello, 

We get raw data by using below python code. However we want to disconnect the slave from the master and connect to another slave. So therefore we need to update the python code. I have shared the python code below.

slave_addr = '54:6C:0E:9F:11:3E' (first connection)
slave_addr = '54:6C:0E:A3:22:9F' (second connection)
1.) Can you help us update the Python code?
2.)Are there any updates to the rtls_master, rtls_slave or rtls_passive codes?
3.)We're getting raw data. But there are 511 examples, not 512 samples. What is the reason of this? I have shared the sample raw data below.
Thanks for helps.
import queue
import time
import csv
from collections import namedtuple

from rtls.rtlsmanager import RTLSManager
from rtls.rtlsnode import RTLSNode, Subscriber


# Uncomment the below to get raw serial transaction logs

# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG,
#                     format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s')


if __name__ == '__main__':
    # Initialize, but don't start RTLS Nodes to give to the RTLSManager
    my_nodes = [RTLSNode('COM32', 115200), RTLSNode('COM20', 115200)]

    # prepare csv file to save data
    filename = 'sla_rtls_raw_IQ_toggles.csv'
    outfile = open(filename, 'w', newline='')

    csv_fieldnames = ['pkt', 'sample_idx', 'rssi', 'ant_array', 'channel', 'i', 'q']
    csv_writer = csv.DictWriter(outfile, fieldnames=csv_fieldnames)
    SampleRow = namedtuple('CsvRow', csv_fieldnames)
    dump_rows = []

    csv_writer.writeheader()

    # Initialize references to the connected devices
    masterNode = None
    address = None
    addressType = None
    passiveNodes = []
    slave_addr = '54:6C:0E:9F:11:3E'  # Slave addr should be set here or set to 'None'
    pkt_limit = 10  # Or None

    # Running packet counter
    pkt_cnt = 0

    # Initialize manager reference, because on Exception we need to stop the manager to stop all the threads.
    manager = None
    try:
        # Start an RTLSManager instance without WebSocket server enabled
        manager = RTLSManager(my_nodes, wssport=None)
        # Create a subscriber object for RTLSManager messages
        managerSub = Subscriber(queue=queue.PriorityQueue(), interest=None, transient=False, eventloop=None)
        # Attach subscriber to manager
        manager.add_subscriber(managerSub)
        # Start RTLS Node threads, Serial threads, and manager thread
        manager.start()

        # Wait until nodes have responded to automatic identify command, and assign nodes to application references
        timeout = time.time() + 5
        while time.time() < timeout:
            if all([node.identifier is not None for node in manager.nodes]):
                try:
                    masterNode = next((n for n in manager.nodes if n.capabilities.get('RTLS_MASTER', False)))
                except StopIteration:
                    pass
                passiveNodes = [n for n in manager.nodes if not n.capabilities.get('RTLS_MASTER', False)]
                break
            time.sleep(0.1)

        # Exit if no master node exists
        if not masterNode:
            raise RuntimeError("No RTLS Master node connected")

        #
        # At this point the connected devices are initialized and ready
        #

        # Display list of connected devices
        print(f"{masterNode.identifier} {', '.join([str(c) for c, e in masterNode.capabilities.items() if e])}")
        for pn in passiveNodes:
            print(f"{pn.identifier} {', '.join([str(c) for c, e in pn.capabilities.items() if e])}")

        print("\nSending example command RTLS_CMD_IDENTIFY; responses below\n")

        # Send an example command to each of them, from commands listed at the bottom of rtls/ss_rtls.py
        for n in passiveNodes + [masterNode]:
            n.rtls.identify()

        while True:
            # Get messages from manager
            try:
                node_msg = managerSub.pend(True, 0.5)
                from_node = node_msg.identifier
                msg = node_msg.message.item
                print(node_msg.as_json())

                # After example identify is received, we start scanning
                if msg.command == 'RTLS_CMD_IDENTIFY':
                    masterNode.rtls.scan()

                # Once we start scanning, we will save the address of the
                # last scan response
                if msg.command == 'RTLS_CMD_SCAN' and msg.type == 'AsyncReq':
                    address = msg.payload.addr
                    addressType = msg.payload.addrType

                # Once the scan has stopped and we have a valid address, then connect
                if msg.command == 'RTLS_CMD_SCAN_STOP':
                    if address is not None and addressType is not None and (slave_addr is None or slave_addr == address):
                        masterNode.rtls.connect(addressType, address)
                    else:
                        # If we didn't find the device, keep scanning.
                        masterNode.rtls.scan()

                # Forwarding the connection parameters to the passives
                if msg.command == 'RTLS_CMD_CONN_PARAMS' and msg.type == 'AsyncReq' and msg.payload.accessAddress is not 0:
                    if node_msg.identifier == masterNode.identifier:
                        for node in passiveNodes:
                            node.rtls.set_ble_conn_info(msg.payload.accessAddress, msg.payload.connInterval,
                                                        msg.payload.hopValue, msg.payload.mSCA, msg.payload.currChan,
                                                        msg.payload.chanMap)

                # Once we are connected and slave setup is completed, we can enable AoA
                if msg.command == 'RTLS_CMD_CONNECT' and msg.type == 'AsyncReq':
                    if msg.payload.status == 'RTLS_SUCCESS':
                        if node_msg.identifier == masterNode.identifier:
                            masterNode.rtls.aoa_set_params('AOA_MASTER', 'AOA_MODE_RAW', 4, 4, 20)
                            masterNode.rtls.aoa_start(1)
                        else:
                            # Iterate over all passive nodes, send ToF params
                            for node in passiveNodes:
                                node.rtls.aoa_set_params('AOA_PASSIVE', 'AOA_MODE_RAW', 4, 4, 20)
                                node.rtls.aoa_start(1)
                    else:
                        # The connection failed, keep scanning.
                        masterNode.rtls.scan()

                # Saving I/Q samples into csv file
                if msg.command == 'RTLS_CMD_AOA_RESULT_RAW':
                    payload = msg.payload
                    # Extract first sample index in this payload
                    offset = payload.offset

                    # If we have data, and offset is 0, we are done with one dump
                    if offset == 0 and len(dump_rows):
                        pkt_cnt += 1

                        # Make sure the samples are in order
                        dump_rows = sorted(dump_rows, key=lambda s: s.sample_idx)

                        # Write to file
                        for sample_row in dump_rows:
                            csv_writer.writerow(sample_row._asdict())

                        # Reset payload storage
                        dump_rows = []

                        # Stop script now if there was a limit configured
                        if pkt_limit is not None and pkt_cnt > pkt_limit:
                            break

                    # Save samples for writing when dump is complete
                    for sub_idx, sample in enumerate(payload.samples):
                        sample = SampleRow(pkt=pkt_cnt, sample_idx=offset + sub_idx, rssi=payload.rssi, ant_array=payload.antenna, channel=payload.channel, i=sample.i, q=sample.q)
                        dump_rows.append(sample)

            except queue.Empty:
                pass

    finally:
        outfile.flush()
        outfile.close()

        if manager:            manager.stop()

  • Hi Elehab,
    I have assigned one of the experts to provide some fruitful comments.
  • Hi Elehab,

    1)
    I can't give you a complete solution here, but you can call masterNode.rtls.terminate_link() to disconnect. You will, or should at least, then get a message RTLS_CONNECT/AsyncReq with status RTLS_LINK_TERMINATED. At this point you can connect to your other slave.

    if msg.command == 'RTLS_CONNECT' and msg.type == 'AsyncReq' and msg.payload.status == 'RTLS_LINK_TERMINATED':
    # connect to next

    2)
    What kind of updates?

    3)
    511 is expected I think, although I'm not sure why. I'll get a colleague to get back to you.

    Best regards,
    Aslak
  • We are modifying the python code to adapt our purpose. Below are the changes we have made:


                                masterNode.rtls.terminate_link()

                                time.sleep(10)

                                masterNode.rtls.reset_device()

                                time.sleep(10)


    We could terminate link and reset master by using these updates. But it doesn't work for the passive (rtls_passive). 


    These commands are supposed to be host messages so it should come into HOST_MSG_EVENT. However, nothing comes to this event. Also it continuously receives RTLS_RUN_EVENT messages in RTLSCtrl_processMessage() function , as if the connection is still valid and getting the IQ samples although there is no connection and IQ samples.


    How can we reset the rtls_passive?


    Thanks.
  • We are modifying the python code to adapt our purpose. Below are the changes we have made:


    masterNode.rtls.terminate_link()

    time.sleep(10)

    masterNode.rtls.reset_device()

    time.sleep(10)


    We could terminate link and reset master by using these updates. But it doesn't work for the passive (rtls_passive).


    These commands are supposed to be host messages so it should come into HOST_MSG_EVENT. However, nothing comes to this event. Also it continuously receives RTLS_RUN_EVENT messages in RTLSCtrl_processMessage() function , as if the connection is still valid and getting the IQ samples although there is no connection and IQ samples.


    How can we reset the rtls_passive?


    Thanks.
  • You should be able to reset passive by using things like:

    if msg.command == 'RTLS_CONNECT' and msg.type == 'AsyncReq' and msg.payload.status == 'RTLS_LINK_TERMINATED':
    for node in passiveNodes:
    node. rtls_reset_device()