-
-
Save glopesdev/13a08b8854a73124ffa98a8d32243bda to your computer and use it in GitHub Desktop.
| using Bonsai.Expressions; | |
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Linq.Expressions; | |
| using System.Reactive.Linq; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| namespace Bonsai.Dynamic | |
| { | |
| public enum DynamicDevice | |
| { | |
| String, | |
| Int32, | |
| Double | |
| } | |
| [WorkflowElementCategory(ElementCategory.Source)] | |
| public class DynamicSource : ZeroArgumentExpressionBuilder | |
| { | |
| public DynamicDevice Device { get; set; } | |
| public override Expression Build(IEnumerable<Expression> arguments) | |
| { | |
| switch (Device) | |
| { | |
| case DynamicDevice.String: | |
| return Expression.Call(typeof(DynamicSource), "GenerateString", null); | |
| case DynamicDevice.Int32: | |
| return Expression.Call(typeof(DynamicSource), "GenerateInt32", null); | |
| case DynamicDevice.Double: | |
| return Expression.Call(typeof(DynamicSource), "GenerateDouble", null); | |
| default: | |
| throw new InvalidOperationException("Unsupported source"); | |
| } | |
| } | |
| static IObservable<string> GenerateString() | |
| { | |
| return Observable.Return("hello"); | |
| } | |
| static IObservable<int> GenerateInt32() | |
| { | |
| return Observable.Return(42); | |
| } | |
| static IObservable<double> GenerateDouble() | |
| { | |
| return Observable.Return(Math.PI); | |
| } | |
| } | |
| } |
@jonnew I would say the Build method can probably do this handshaking. It can be as complicated as you want. Also, the output can be a list, or sequence, of devices. I can also extend the example to do the discovery and handshaking of devices within a drop-down dialog that is shown on the property pages, so the user can pick which device(s) should be activated.
Sometimes I also setup hardware manager classes that can be accessed more globally and take care of discovering/configuring connected devices. This is the way the Arduino serial port works (see here), for example, which allows you to have per-device configuration settings (i.e. for baud rates, etc).
Ultimately, Build is just the entry point, but you can exploit it to setup your own complicated infrastructure that controls the runtime code generation in detail. In fact, I often find myself doing this for exactly the same reasons you pointed out 😄
Cool. As far as I understand it, this is nice for dynamically configuring the outputs of the node to support different hardware configurations. But what about about the case where the hardware capabilities are discovered during the construction of the source? In our case there is some handshaking between the host software and the FPGA that enumerates a list devices that will be supplying data to the host. These devices come with read offsets that tell where in a data frame their raw data resides and some type conversion information. Let say there is a device that produces
Strings and on that producesInts. Referring to the above example, could theDynamicSourceconstructor somehow call Build 2x, on for theStringdevice if found and the other for theIntdevice?