This project has moved. For the latest updates, please go here.

Send methods in main XBee class

Coordinator
Mar 11, 2012 at 7:06 PM

I was thinking about easy and flexible way of allowing users to send packets. This is what i came up with:

 

// after To() is called the request is sent and asyncResult is returned

var response = xbee.Send(data).To(address).GetResponse();

var response = xbee.Send(data).ToAll().GetResponse();

var request = xbee.Send(data).To(address);
var response = request.GetResponse();

var request = xbee.Send(data).ToAll();
var response = request.GetResponse();

// After To() is called the request is sent with FrameId = 0 and null is returned

xbee.Send(data).NoResponse().To(address);

xbee.Send(data).NoResponse().ToAll();

What i like in this approach is that there will be only a few Send() methods in XBee class that accept different arguments. Right now there are too many of them in my opinion. What do you think?

 

Coordinator
Mar 11, 2012 at 7:13 PM
Edited Mar 11, 2012 at 7:14 PM

Another way

 

// you can discard the asyncResult 
// after response is received or timeout occurs the object will be disposed

xbee.Send(data).To(address);
Developer
Mar 15, 2012 at 10:33 AM
Edited Mar 15, 2012 at 10:35 AM

I like it !

You could also support:

var response = xbee.Send(data1).Send(data2).To(address).GetResponse();
// Would return the response for the first request

var responses = xbee.Send(data1).Send(data2).To(address).GetResponses();
// Would return all of the responses as an ordered list or dictionary (Where the key is a numerical index representing which send call it relates to)

// You also have to consider:
var response = xbee.Send(data).ToAll().GetResponse();
// Would return the first response

// And ... :
var response[s] = xbee.Send(data).To(address1).To(address2).GetResponse[s]();
// Would behave in the same way as ToAll()

// And ... :
var responses = xbee.Send(data).ToAll().GetResponses();
// Would return all of the responses as a dictionary (Where the key is the sender address)

// And ... ! :
var responses = xbee.Send(data1).Send(data2).ToAll().GetResponses();
// Would return all of the responses as a ordered list or dictionary inside a dictionary (Where the outer key is the sender address and the inner container is the same as the .To(Address) version)

Coordinator
Mar 15, 2012 at 11:49 AM
Edited Mar 15, 2012 at 11:50 AM

Glad you like it, me too :) This is my current version:


interface IXBee
{
	IRequest Send(string payload)
	IRequest Send(byte[] payload)
	IRequest Send(Wpan.AtCmd atCommand, params byte[] value)
	IRequest Send(Zigbee.AtCmd atCommand, params byte[] value)
	IRequest Send(XBeeRequest request)
}

interface IRequest
{
	IRequest Use(IPacketFilter filter);

	IRequest Timeout(int value);
	IRequest NoTimeout();

	IRequest To(ushort networkAddress);
	IRequest To(ulong serialNumber);
	IRequest To(XBeeAddress destination);
	IRequest To(NodeInfo destination);
	IRequest ToAll();

	AsyncSendResult Invoke();
	void NoResponse();
	XBeeResponse[] GetResponses(int timeout = -1);
	XBeeResponse GetResponse(int timeout = -1);
}

As you can see the main XBee class is down to 5 methods with even more options then before! In order to send the request one of the last four methods needs to be called. Example of usage:


xbee.Send("TEST").To(0x0013A2004086AD32).NoResponse();

var nodes = xbee.DiscoverNodes();

foreach (var node in nodes)
    xbee.Send("Hello").To(node).GetResponse();

var sendStatus = (TxStatusResponse) xbee.Send("Hello").To(node).GetResponse();

if (sendStatus.DeliveryStatus == TxStatusResponse.DeliveryResult.Success)
{
	Debug.Print("Message sent to: " + node.NetworkAddress);
}
else
{
	Debug.Print("Failed to send message to: " + node.NetworkAddress);
}

 

Regarding your suggestions:

Ad1. Sure we could add the possibility of sending multiple packets this way. It's good for next release.

Ad2. See Ad1.

Ad3. when you use ToAll() you send a broadcast packet that will return one response if this is a data packet and multiple response if this is a remote AT command. You can either wait for one or multiple packets using GetResponse() or GetResponses() and filter then with Use(Filter). 

Ad4. This is another good idea. Send one packet to multiple recipients in one call. Definitely worth implementing. Maybe another To() with array of recipients addresses?

Ad5. See Ad3.

Ad6. Combination of sending multiple packets to multiple recipients. Will remember this.

Developer
Mar 15, 2012 at 12:42 PM

 

IRequest Send(byte[] payload)

// Could be:
IRequest Send(params byte[] payload)

IRequest NoTimeout();
// I don't think this is required - When Timeout() is called with a value of 0 or less, it should behave like no time-out (Which should also be the default if it isn't called at all)

Regarding .To() with an array parameter, I'd suggest just using the params keyword for them all so that you can either specify addresses separately, just specify one address or pass in an array.

You could also have it so that you can save the request command for later use - E.g. Supposing you have a "ping" command you want to call over and over - You could do:
var pingCommand = xbee.Send("My Ping Command").ToAll().GetDeferred();

pingTimer.Tick => pingCommand.NoResponse();

In the same way, you could have more advanced deferred sending:
var reportCommand = xbee.Send((data) => "The latest temperature: " + Data.ToString() + "C").ToAll().GetDeferred();

reportTimer.Tick => reportCommand.NoResponse(temperatureSensor.GetTemperature());

Coordinator
Mar 15, 2012 at 1:26 PM
Edited Mar 15, 2012 at 1:26 PM
IRequest Send(byte[] payload)
// Could be:
IRequest Send(params byte[] payload)

Thanks, added.

When Timeout() is called with a value of 0 or less, 
it should behave like no time-out (Which should also be the default if it isn't called at all)

Right now there is a default timeout value. You can call NoTimeout() to reset it or Timeout(int) to set it (usig -1 is equal to NoTimeout). The NoTimeout method is only to make it look nice. Sometime it's better to do things this way so the user knows right away what will be te result. E.g. user might not know that no param or -1 means no timeout, but will now for sure what NoTimeout does. Of course we can change it after we do some open beta testing.

Regarding .To() with an array parameter, I'd suggest just using the params keyword

Agree! 

You could also have it so that you can save the request command for later use

Right now we are reusing the request so you cannot save it up for later use. But there is no reason why we can't do it. In fact at the beginning i was returning a new instance for each Send() call. If you imagine the GetDeferred to work as Clone() this will work as well. 

 more advanced deferred sending

How about we add Send() that accepts a delegate that returns the data. This way each time you call NoResponse the request will call this delegate to get the payload. You control what you send in that delegate. e.g. the delegate could only return local variable. 

Coordinator
Mar 15, 2012 at 2:08 PM

I have added something like this:

XBee
{
    IRequest Send(PayloadDelegate payloadDelegate);
    delegate byte[] PayloadDelegate();
}
When you provide the delegate it will be called each time you want to send the request (or once if you don't want to reuse it).

Developer
Mar 15, 2012 at 3:26 PM

I think the delegate should have a parameter (object ?) which is passed from the GetResponse / Invoke methods - This would allow you to re-use the same request for different datasources. (E.g. If you're sending temperature sensor data back from something, you could invoke it from each of the sensors passing in the temperature you want to send.)

Coordinator
Mar 15, 2012 at 8:43 PM

GetResponse now accepts an optional timeout parameter. When you add extra argument that will be used only if a delegate was provided before in the To() method doesn't sound good to me. I think at this moment having a simple delegate is enough and we should not complicat this further unless in time people start requesting this.