Hi Oliver,

Just a heads up that I've been working on something similar for the past 
six months or so. I'm fortunate enough to be starting a new project where I 
have no legacy code and the freedom to play around a bit. I think we have 
similar ideas: properties are abstract / singleton types in my code as 
well. I really like your idea of using `getindex` and `setindex!` but I 
didn't think of that initially (sigh...) and at present have defined 
methods like:

configure(ins::Instrument,::Type{DeviceFeature}, value, channel::Integer=1)
inspect(ins::Instrument, ::Type{DeviceFeature})

My approach would have the same scaling issues you worry about. I hope it 
won't be such an issue and it would be kind of a shame to resort to 
separate functions for each instrument property in Julia, so I'm just going 
full speed ahead.

My code is not yet ready for public use and is not stable, but the source 
is in my repo <https://github.com/ajkeller34/PainterQB.jl> if you're 
curious. I should caution that its a bit of a mess right now and the 
documentation is not up-to-date, so some of it reflects things that are not 
be true anymore, or ideas I have abandoned / improved upon. Seeing as how I 
need to do some real science soon I hope the source code will stabilize 
within a few weeks. I would welcome discussion if you want to combine 
efforts on this. I'm not sure if I want to invite PRs yet until I have the 
project in a more stable state but discussion is always good.

As I've been working on this since I started learning Julia, there are a 
number of things I did early on that I regret and am now fixing. One thing 
you'll find becomes annoying quickly is namespace issues: if you want to 
put different instruments in different modules, shared properties or 
functions may require a lot of careful imports/exports that tend to break 
easily. I'd suggest that rather than hard coding properties in source 
files, you store what you need in some standard external format. I'm now 
storing my SCPI codes, Julia property names, argument types, etc. in a JSON 
file that Julia parses to generate code with metaprogramming. With this 
approach I believe I'll be able to write code to scrape instrument manuals, 
and thereby generate code for new instruments semiautomatically. You'd 
still need to decide on property names and such, and write regular 
expressions to scrape the manuals, but that's not so bad.

Finally, I think some really great things could be done with this sort of 
code if Julia had better native support for physical units. For instance, 
on a vector network analyzer you could write something like:

vna[Frequency] = 4GHz:1MHz:10GHz

and thereby set frequency start, stop, and step at once. I have a units 
package for Julia v0.5 that I'm also developing when I have the time (
Unitful.jl <https://github.com/ajkeller34/Unitful.jl>), but there are some 
tweaks to Base that would help the package play nicely. If that sounds 
appealing, it'd be great if you could voice your support for that, e.g. 
here: https://github.com/JuliaLang/julia/pull/15394

Best wishes,
Andrew Keller

On Sunday, March 27, 2016 at 5:34:31 AM UTC-7, Oliver Schulz wrote:
>
> Hello,
>
> I'm designing a scheme to control and read out hardware devices (mostly 
> lab instruments) via Julia. The basic idea is that each device type is 
> characterized by a set of features/properties that have a value type and 
> dimensionality and that can be read-only or read/write (a bit like SCPI or 
> VISA, conceptually).
>
> Features/properties would be things like "InputVoltage" for a multimeter, 
> "Waveform", "TriggerLevel", etc. for an oscilloscope, and so on. They would 
> be represented by (abstract or singleton) types. Obviously, certain 
> features would be supported by many different device classes.
>
> For the API, I was thinking of an interface like this:
>
> current_feature_value = mydevice[SomeDeviceFeature]
> mydev[SomeDeviceFeature] = new_feature_value
>
> resp. things like
>
> mydev[SomeMultiChannelFeature, channel]
>
> for feature with multiple instances (e.g. in muli-channel devices). The 
> implementation would, of course, be
>
> getindex(dev::SomeDeviceType, ::Type{SomeDeviceFeature}) = ...
> setindex!(dev::SomeDeviceType, value, ::Type{SomeDeviceFeature}) = ...
>
> etc. This would mean having a large number of classes for all features 
> (let's say around 200), and an even larger number of methods ( 
> O(number_of_device_classes * typical_number_of_features_per_device), let's 
> say around 5000) for getindex and setindex!. Can Julia handle this, or 
> would this result in long compile times and/or bad performance?
>
> An alternative would be, of course, to represent each feature by a 
> specific set of methods like "trigger_level_set, "trigger_level_get", etc. 
> However, I like the idea of representing a device feature as something that 
> can be passed around (possibly between hosts). Also, there may be other 
> feature operations beyond a simple set and get, which would many several 
> functions for each feature.
>
> Any insights?
>
>
> Cheers,
>
> Oliver
>

Reply via email to