Skip to content

Instantly share code, notes, and snippets.

@glopesdev
Created October 4, 2017 09:11
Show Gist options
  • Select an option

  • Save glopesdev/13a08b8854a73124ffa98a8d32243bda to your computer and use it in GitHub Desktop.

Select an option

Save glopesdev/13a08b8854a73124ffa98a8d32243bda to your computer and use it in GitHub Desktop.
Minimalist example of a dynamically typed source in Bonsai
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

jonnew commented Oct 6, 2017

Copy link
Copy Markdown

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 produces Ints. Referring to the above example, could the DynamicSource constructor somehow call Build 2x, on for the String device if found and the other for the Int device?

@glopesdev

Copy link
Copy Markdown
Author

@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 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment