Gadgeteer.Timer problem?

@ Gralin and all, it’s really great to see a complex .NET Gadgeteer module being built as a community effort!

I’m on the Microsoft research team that created .NET Gadgeteer. I just wanted to provide a little background into why it can sometimes be tricky to code up certain types of module, and give some suggestions.

The event model in Gadgeteer was chosen to make end users lives as easy as possible - no worrying about threading, deadlocks, etc. Unfortunately, that complexity has to go somewhere, and it goes into GadgeteerCore and into the module drivers, but we consider that a worthwhile tradeoff since it means the platform is usable by more novice end users (and hopefully the number of times you yourself are a user of your module rather than a developer is high enough to warrant it even for yourself!)

Particularly when dealing with async responses from external hardware, sometimes internally in modules a thread is the best way, making sure to call every resulting async event back on the dispatcher.

The module template http://gadgeteer.codeplex.com/releases (under Gadgeteer Builder Templates) has examples of how to use events in Gadgeteer, and these examples (the OnXXXEvent methods) work even if the caller is not on the dispatcher.

Seeed Studio’s Cellular Module (contributed by Eduardo Velloso at Lancaster Uni) is a great example of dealing with a serial external module using threads http://gadgeteer.codeplex.com/SourceControl/changeset/view/15256#157799

GHI’s camera module also uses a similar pattern though with USB not serial: http://gadgeteer.codeplex.com/SourceControl/changeset/view/15256#138365

Hope this helps

Ta
James

@ jamesscott: I don’t think you have to introduce yourself here :smiley: I’m flattered that you consider our XBee driver complex, I hope we can do even better!

I have analyzed the source code as you suggested. I will not complain about the code itself (it begs for solid refactoring to call it C# :wink: ). This example is indeed good because it has similar operations to what we have in XBee:

[ol]initalization that needs to send and receive something before letting the user play with the object
sending command and receiving responses async
async events not caused by sending a command[/ol]

First thing i don’t like is the constructor.

public CellularRadio(int socketNumber)
{
	...
	
	serialLine.Open();
	serialLine.Write("AT");
	Thread.Sleep(1000);
	String response = "";
	while (serialLine.BytesToRead > 0)
	{
		response += (char)serialLine.ReadByte();
	}
	
	...

	readerThread = new Thread(new ThreadStart(run));
	readerThread.Start();
}

I don’t like the fact it calls I/O. The new started thread could deal with it and signal ready by some flag or event. We have a similar situation in XBee where before we can let the user interact with the module we need to get some basic info from it. To do this we require that user calls a Configure() method. If he doesn’t it will be called for him before first interaction. But the main problem is the synchronous call. In this example Seed Studios use the while loop checking the BytesToRead property. We are using only DataReceived events. And here is where we found the problem. When we are on the Dispatcher thread the DataReceived event will not be called. The while loop works because it does not relay on events. This is why i think using native serial port is better than the gadgeteer version…

Another thing is the way to receive reponses. This module offers only receiving responses via events (as the gadgeteer design pattern suggests). When you send any command e.g. RetrieveClock() it will return a status enum and the actual result will be returned by ClockRetrieved event. Now my question is this. If the user is inside some gadgeteer event handler (e.g. Timer tick) and invokes RetrieveClock(), the resulting ClockRetrieved event will not be fired until he exits the event handler (so the dispatcher can call the next queued event handler). Am I correct? This way the user can’t make a synchronous call? (this question is related to the first one).

Current XBee API allows you to receive the data in a few ways. I have prepared a flow diagram that presents how we send and receive async data (there is also another way with using IAsyncResult). What i like about this design is that you can specify different handlers for different requests and it doesn’t require defining tens of events in the main class (or one event and then a switch statement). You should be even able to send concurent request as the responses include request id. Of course this may be not intuitive for a beginner so i agree some simple events are a also a good idea. However when i think about beginners I’m thinking about synchronous calls which are the most simple I think. Our API also offers them (uses the async mechanis internaly). If you have any spare time pleas check out our work. We hope for some suggestions from the community but that’s not going well so far :confused: Maybe we have to wait untill people buy more XBee hardware.

@ Gralin,

Re: cellular, I think your comments are valid; I meant it as a pattern for the module to mainboard interaction as a whole.

Re: community feedback, what we’ve tended to do is only work on modules that either we or someone else has committed to build a fun application for (some real, some more contrived examples). Then we use that app’s needs as the test of the API quality and for bug testing.

You’re right too that using asynchronous interface calls (through GTI.Serial’s events) is not always best for module internal implementation. We provided them in GTI.Serial because some modules, e.g. GPS, use fairly simple parsing on the back of newline-delimited strings to provide typed events, and such modules are made easy. With a more complex interaction, it may make sense to use synchronous calls at that layer in a thread, and only get onto the dispatcher just before the user-facing API. You can if you wish use the NETMF serial calls; I would suggest copying the appropriate code in from GTI.Serial to continue to do the socket type checking, pin reservation, etc (the core libs try to give nice end user error messages, which mean you don’t have to handle all the error cases).

In answer to your question about RetrieveClock() resulting in ClockRetrieved event - this is right, if you use an async method then the handler won’t run immediately. There’s four ways around this
[ol]you could provide both sync and async where the sync one blocks (which is inelegant)
you can provide a sync method which returns the last value (if the freshness of the value is not so important)
you can write the code using it so on timer.tick it calls retrieveclock(), then on clockreceived it does whatever you want it to do. This can end up being inelegant too since end user code ends up less readable
you can provide a module method which makes this async chaining less prevalent, e.g. ClockTick which uses a timer to call retrieveclock periodically and then when it comes back it fires a user-facing Tick event which includes the datetime of the clock. [/ol]

These options and the tradeoffs between them show why it makes sense to develop against one or more example apps - or the “best” API becomes a guessing game.