jefffhaynes / XBee

A .NET library for XBee wireless controllers
MIT License
40 stars 17 forks source link

TxRequestExtFrame with 16-bit address #28

Closed MeijinGandalf closed 7 years ago

MeijinGandalf commented 7 years ago

I was reading through the Xbee documentaion and came across this.

Address Table

The XBee modules can store up to ten address table entries. For applications where a single device (for example coordinator) may send unicast transmissions to more than ten devices, the application should implement an address table to store the 16-bit and 64-bit addresses for each remote device. Any XBee that will send data to more than ten remotes should also use API firmware. The application can then send both the 16-bit and 64-bit addresses to the XBee in the API transmit frames which will significantly reduce the number of 16-bit address discoveries and greatly improve data throughput.

If an application will support an address table, the size should ideally be larger than the maximum number of destination addresses the device will communicate with. Each entry in the address table should contain a 64-bit destination address and its last known 16-bit address.

When sending a transmission to a destination 64-bit address, the application should search the address table for a matching 64-bit address. If a match is found, the 16-bit address should be populated into the 16-bit address field of the API frame. If a match is not found, the 16-bit address should be set to 0xFFFE (unknown) in the API transmit frame.

Could you add the ability to to send a TxRequestExtFrame with the 16-bit address? I looked at it and it just uses 0xFFFE since we don't know it. It would also be cool if the library added the 16-bit address to the node when data is received from the node so I would have an easy way of getting the 16-bit address of the node and when I used the alternate frame that uses the 16-bit address it could just pull it from the node itself so I wouldn't need to keep a separate table of 64-bit and 16-bit pairs.

Also at the moment I can only use Visual Studio 2013 so I can't install Xbee 5.0. I don't know what it would take to add it to the version 4 branch. I am going to try and get at least Visual Studio 2015, but I don't know if I will be able to get it or not.

jefffhaynes commented 7 years ago

Sure, I can take a look. You can get Visual Studio 2017 Community Edition for free unless there is some other issue preventing you from using it.


From: MeijinGandalf notifications@github.com Sent: Wednesday, June 21, 2017 10:59:15 AM To: jefffhaynes/XBee Cc: Subscribed Subject: [jefffhaynes/XBee] TxRequestExtFrame with 16-bit address (#28)

I was reading through the Xbee documentaion and came across this.

Address Table

The XBee modules can store up to ten address table entries. For applications where a single device (for example coordinator) may send unicast transmissions to more than ten devices, the application should implement an address table to store the 16-bit and 64-bit addresses for each remote device. Any XBee that will send data to more than ten remotes should also use API firmware. The application can then send both the 16-bit and 64-bit addresses to the XBee in the API transmit frames which will significantly reduce the number of 16-bit address discoveries and greatly improve data throughput.

If an application will support an address table, the size should ideally be larger than the maximum number of destination addresses the device will communicate with. Each entry in the address table should contain a 64-bit destination address and its last known 16-bit address.

When sending a transmission to a destination 64-bit address, the application should search the address table for a matching 64-bit address. If a match is found, the 16-bit address should be populated into the 16-bit address field of the API frame. If a match is not found, the 16-bit address should be set to 0xFFFE (unknown) in the API transmit frame.

Could you add the ability to to send a TxRequestExtFrame with the 16-bit address? I looked at it and it just uses 0xFFFE since we don't know it. It would also be cool if the library added the 16-bit address to the node when data is received from the node so I would have an easy way of getting the 16-bit address of the node and when I used the alternate frame that uses the 16-bit address it could just pull it from the node itself so I wouldn't need to keep a separate table of 64-bit and 16-bit pairs.

Also at the moment I can only use Visual Studio 2013 so I can't install Xbee 5.0. I don't know what it would take to add it to the version 4 branch. I am going to try and get at least Visual Studio 2015, but I don't know if I will be able to get it or not.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/XBee/issues/28, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKR9OpUnfQrOaotHcBKPfNHJV412Zfks5sGS_DgaJpZM4OBF1N.

MeijinGandalf commented 7 years ago

I am working on this project at work so I can't use the community addition unfortunately. The only option I have available to me is 2015 and I may not even be able to get that. Its frustrating for sure!

jefffhaynes commented 7 years ago

Gotcha. I'll look at updating the 4.x as well.


From: MeijinGandalf notifications@github.com Sent: Wednesday, June 21, 2017 11:24:44 AM To: jefffhaynes/XBee Cc: Jeff Haynes; Comment Subject: Re: [jefffhaynes/XBee] TxRequestExtFrame with 16-bit address (#28)

I am working on this project at work so I can't use the community addition unfortunately. The only option I have available to me is 2015 and I may not even be able to get that. Its frustrating for sure!

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/XBee/issues/28#issuecomment-310114443, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKR0o4iNwJGmI9CExQwj9HXj5fNhF3ks5sGTW8gaJpZM4OBF1N.

MeijinGandalf commented 7 years ago

Thanks!

jefffhaynes commented 7 years ago

So just to clarify this - if I simply pass the short address from the node in TransmitDataAsync, will that be sufficient? For example,

var transmitRequest = new TxRequestExtFrame(Address.LongAddress, Address.ShortAddress, data);
jefffhaynes commented 7 years ago

Also, as to the DataReceived event including the address, I'm not opposed to it but the address is already available from the sender (the emitting node). Are you saying you also would like it in the event itself?

MeijinGandalf commented 7 years ago

Yes I think that frame will work. I would just need a way to use it and disable enableAck and I see that TransmitDataAsync only uses.

var transmitRequest = new TxRequestExtFrame(Address.LongAddress, data);

When it comes to the address I saw that I can get to the short address from the sender, but as the code currently stands it only returns 0xFFFE, but I guess with this new constructor you would change that.

jefffhaynes commented 7 years ago

Deleted previous erroneous replies for clarity -

I'm seeing the short address get returned if the node has a short address configured. Are you seeing something different?

jefffhaynes commented 7 years ago

ok, not sure if I got what you wanted or not but I pushed 4.3.2. Give it a shot and let me know if it's missing anything.

MeijinGandalf commented 7 years ago

For some reason I am still getting FFFE for the short address. I am am looking at it in the NodeDiscovered event.

jefffhaynes commented 7 years ago

What short address is specified if you use x-ctu?


From: MeijinGandalf notifications@github.com Sent: Wednesday, July 5, 2017 11:29:09 AM To: jefffhaynes/XBee Cc: Jeff Haynes; Comment Subject: Re: [jefffhaynes/XBee] TxRequestExtFrame with 16-bit address (#28)

For some reason I am still getting FFFE for the short address. I am am looking at it in the NodeDiscovered event.

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/XBee/issues/28#issuecomment-313138253, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKR_QAaSBXnmKuMRykk0GtP7isOZvaks5sK6vFgaJpZM4OBF1N.

MeijinGandalf commented 7 years ago

Right now it is DC6B

jefffhaynes commented 7 years ago

How weird...can you send the exact code you're using?


From: MeijinGandalf notifications@github.com Sent: Wednesday, July 5, 2017 12:01:15 PM To: jefffhaynes/XBee Cc: Jeff Haynes; Comment Subject: Re: [jefffhaynes/XBee] TxRequestExtFrame with 16-bit address (#28)

Right now it is DC6B

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/XBee/issues/28#issuecomment-313147866, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKRzGwfqWv0i7TY_LBvI83zrQD4hsiks5sK7NLgaJpZM4OBF1N.

MeijinGandalf commented 7 years ago

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using XBee; using System.Diagnostics; using log4net;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]

namespace XBee_Test {

public partial class Form1 : Form
{
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    const string terminator = "\n";
    bool stop = false;

    Stopwatch totalTime = new Stopwatch();
    XBeeController controller = new XBeeController("COM9", 9600);
    Dictionary<LongAddress,RemoteDevice> remoteDevices = new Dictionary<LongAddress,RemoteDevice>();
    //LongAddress currentAddress;
    List<XBeeNode> nodes = new List<XBeeNode>();
    //BackgroundWorker pollWorkerTest1 = new BackgroundWorker();
    System.Timers.Timer timer = new System.Timers.Timer(100);

    string sendString = "Stardusthurtstheeye!";
    int nodeCount = 0;
    int currentDevice = 0;

    public Form1()
    {
        InitializeComponent();
        timer.AutoReset = true;
        timer.Elapsed += timer_Elapsed;
        //pollWorkerTest1.WorkerSupportsCancellation = true;
        //pollWorkerTest1.DoWork += pollWorkerTest1_DoWork;
        //pollWorkerTest1.ProgressChanged += pollWorkerTest1_ProgressChanged;
        //pollWorkerTest1.RunWorkerCompleted += pollWorkerTest1_RunWorkerCompleted;
    }

    private async void btnConnectCoordinator_Click(object sender, EventArgs e)
    {
        await controller.OpenAsync();
        controller.NodeDiscovered += controller_NodeDiscovered;
        lblHost.Text = "Host: Connected";
        lblHost.ForeColor = Color.Green;
        btnDiscoverNetwork.Visible = true;
        btnConnectCoordinator.Visible = false;
        log.Debug("Connect to Coordinator button pressed.");
    }

    void controller_NodeDiscovered(object sender, NodeDiscoveredEventArgs e)
    {
        remoteDevices.Add(e.Node.Address.LongAddress, new RemoteDevice(e.Node, e.Name));
        nodes.Add(e.Node);
        e.Node.DataReceived += Node_DataReceived;
        nodeCount += 1;
        this.Invoke((MethodInvoker) delegate() {
            lblNumNodes.Text = "Nodes: " + nodeCount.ToString();
            nodeGridView.Rows.Add(e.Name, String.Format("{0:X}", e.Node.Address.LongAddress) ,String.Format("{0:X}",e.Node.Address.ShortAddress), 0, 0, 0, 0, 0);
        });
        log.Debug(e.Name + " Discovered! - Address: " + e.Node.Address.LongAddress.Low);
    }

    async void Node_DataReceived(object sender, XBee.DataReceivedEventArgs e)
    {
        timer.Stop();
        log.Debug("Timer Stopped");

        XBeeNode node = (XBeeNode)sender;
        RemoteDevice device;
        string receivedText = Encoding.ASCII.GetString(e.Data); 

        remoteDevices.TryGetValue(node.Address.LongAddress, out device);

        nodeGridView["Received", currentDevice].Value = ++device.NumRec;

        if (!receivedText.Equals(sendString))
            nodeGridView["FailedMatch", currentDevice].Value = ++device.NoMatch;

        currentDevice++;
        if (currentDevice > nodes.Count - 1)
            currentDevice = 0;

        log.Debug("Data Received: " + node.Address.LongAddress.Low);
        if (!stop)
        {
            nodeGridView["Sent", currentDevice].Value = ++remoteDevices[nodes[currentDevice].Address.LongAddress].NumSent;
            try
            {
               log.Debug("Data Sent: " + nodes[currentDevice].Address.LongAddress.Low);
               await nodes[currentDevice].TransmitDataAsync(Encoding.UTF8.GetBytes(sendString + terminator), false);
            }
            catch
            {

            }
            timer.Start();
            log.Debug("Timer Started");
        }
    }

    private async void btnDiscoverNetwork_Click(object sender, EventArgs e)
    {
        log.Debug("Discover Network button pressed");
        btnDiscoverNetwork.Visible = false;
        await controller.DiscoverNetworkAsync();
        btnStartTest1.Visible = true;
    }

    async void btnStartTest1_Click(object sender, EventArgs e)
    {
        log.Debug("Test1 button pressed");
        btnStartTest1.Visible = false;
        btnStopTest1.Visible = true;
        totalTime.Start();
        nodeGridView["Sent", currentDevice].Value = ++remoteDevices[nodes[0].Address.LongAddress].NumSent;

        log.Debug("Data Sent: " + nodes[currentDevice].Address.LongAddress.Low);
        await nodes[currentDevice].TransmitDataAsync(Encoding.UTF8.GetBytes(sendString + terminator), false);
        timer.Start();
        log.Debug("Timer Started");

    }

    private void btnStopTest1_Click(object sender, EventArgs e)
    {
        log.Debug("Stop Test1 button pressed");
        int totalNoMatch = 0, totalSent = 0, totalReceived = 0, totalRadioFaults = 0, totalNoReplies = 0;

        stop = true;
        totalTime.Stop();
        timer.Stop();
        TimeSpan eT = totalTime.Elapsed;
        lblElapsedTime.Text = String.Format("Total Time: {0:00}:{1:00}:{2:00}:{3:00}", eT.Hours, eT.Minutes, eT.Seconds, eT.Milliseconds / 10);
        lblElapsedTime.Visible = true;
        lblMS.Text = String.Format("{0:00}ms", eT.TotalMilliseconds);
        lblMS.Visible = true;
        btnReset.Visible = true;
        btnStopTest1.Visible = false;

        foreach (RemoteDevice device in remoteDevices.Values)
        {
            totalNoMatch += device.NoMatch;
            totalNoReplies += device.NoReply;
            totalReceived += device.NumRec;
            totalSent += device.NumSent;
            totalRadioFaults += device.RadioFaults;
        }
        lblTestResults.Text = String.Format("Sent: {0}  Received: {1}  Radio Faults: {2}  No Replies: {3}  No Match: {4}", totalSent, totalReceived, totalRadioFaults, totalNoReplies, totalNoMatch);
        lblTestResults.Visible = true;
    }

    async void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        RemoteDevice device;
        log.Debug("Timer tick event started");

        remoteDevices.TryGetValue(nodes[currentDevice].Address.LongAddress, out device);

        nodeGridView["NoReply", currentDevice].Value = ++device.NoReply;
        device.ThreeNoReply++;
        if (device.ThreeNoReply == 3)
        {
            timer.Stop();
            log.Debug("Timer Stopped");
            device.ThreeNoReply = 0;
            nodeGridView["RadioFaults", currentDevice].Value = ++device.RadioFaults;

            currentDevice++;
            if (currentDevice > nodes.Count - 1)
                currentDevice = 0;
            log.Debug("Data Sent: " + nodes[currentDevice].Address.LongAddress.Low);
            await nodes[currentDevice].TransmitDataAsync(Encoding.UTF8.GetBytes(sendString + terminator), false);
            timer.Start();
            log.Debug("Timer Started");
        }
    }

    private void btnReset_Click(object sender, EventArgs e)
    {
        log.Debug("Reset button pressed");
        lblTestResults.Visible = false;
        btnReset.Visible = false;
        lblElapsedTime.Visible = false;
        lblMS.Visible = false;
        btnStopTest1.Visible = false;
        btnStartTest1.Visible = true;
        totalTime.Reset();
        stop = false;
        currentDevice = 0;

        foreach (RemoteDevice device in remoteDevices.Values)
        {
            device.NoMatch = 0;
            device.NoReply = 0;
            device.NumRec = 0;
            device.NumSent = 0;
            device.RadioFaults = 0;
            device.ThreeNoReply = 0;
        }

        foreach (DataGridViewRow row in nodeGridView.Rows)
        {
            for (int i = 1; i < 6; i++)
            {
                row.Cells[i].Value = 0;
            }
        }

    }

    async void btnStartTest2_Click(object sender, EventArgs e)
    {

    }
}

}

jefffhaynes commented 7 years ago

You're right! Sorry about that, it was a pretty insidious bug. Fixed in 4.3.3.

MeijinGandalf commented 7 years ago

Glad you were able to find the bug! It is working well on my end.

One thing in relation to this that could be a problem is if the transmission fails because the 16-bit address changed for some reason. This is what the manual has to say about it.

The API provides indication of a remote device's 16-bit address in the following frames: • All receive data frames Rx Data (0x90) Rx Explicit Data (0x91) IO Sample Data (0x92) Node Identification Indicator (0x95) Route Record Indicator (0xA1) and so forth • Transmit status frame (0x8B) The application should always update the 16-bit address in the address table when one of these frames is received to ensure the table has the most recently known 16-bit address. If a transmission failure occurs, the application should set the 16-bit address in the table to 0xFFFE (unknown).

I don't really know how often or likely the 16-bit address is to change, but you may want to do as this suggests. I can keep track of whether I am getting responses from my nodes and change the 16-bit address manually, but others may not realize that this can happen. What do you think?

jefffhaynes commented 7 years ago

Sounds good, I'll add it. Thanks


From: MeijinGandalf notifications@github.com Sent: Monday, July 10, 2017 2:19:50 PM To: jefffhaynes/XBee Cc: Jeff Haynes; Comment Subject: Re: [jefffhaynes/XBee] TxRequestExtFrame with 16-bit address (#28)

Glad you were able to find the bug! It is working well on my end.

One thing in relation to this that could be a problem is if the transmission fails because the 16-bit address changed for some reason. This is what the manual has to say about it.

The API provides indication of a remote device's 16-bit address in the following frames: • All receive data frames Rx Data (0x90) Rx Explicit Data (0x91) IO Sample Data (0x92) Node Identification Indicator (0x95) Route Record Indicator (0xA1) and so forth • Transmit status frame (0x8B) The application should always update the 16-bit address in the address table when one of these frames is received to ensure the table has the most recently known 16-bit address. If a transmission failure occurs, the application should set the 16-bit address in the table to 0xFFFE (unknown).

I don't really know how often or likely the 16-bit address is to change, but you may want to do as this suggests. I can keep track of whether I am getting responses from my nodes and change the 16-bit address manually, but others may not realize that this can happen. What do you think?

— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/jefffhaynes/XBee/issues/28#issuecomment-314191235, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AJSKR5JAuZ5SxE8IZQaMpk-jQABl8UFCks5sMmtFgaJpZM4OBF1N.

MeijinGandalf commented 7 years ago

Cool thanks!

jefffhaynes commented 7 years ago

Added in 5.3.3/1.4.3 Core