Closed mundya closed 10 years ago
(Note, apparently PySerial is thread safe: http://stackoverflow.com/questions/8796800/pyserial-possible-to-write-to-serial-port-from-thread-a-do-blocking-reads-fro)
Using __getitem__
and __setitem__
to get and set Node input/output seemed nice when I thought of it, but now I'm not so sure. It seems weird that
a = nodes[node]
nodes[node] = b
# a != b
nodes[node] == a
Maybe explicit get_node_input(node)
and set_node_output(node, value)
would be better?
Hmm... I'm a bit worried about this being an implicit parameter based on imports. That makes it difficult to do things like:
import nengo
import nengo_spinnaker
...
sim1 = nengo_spinnaker(model, use_serial=True)
sim2 = nengo_spinnaker(model, use_serial=False)
But the approach for the internals of the code seems pretty reasonable to me... my first instinct is still to implement the Ethernet in/out and then figure out what the refactored nice version would be, but we are pretty close to having the Ethernet version done, so I guess we've already got a pretty good sense of how it'll end up looking.
That makes it difficult to do things like:
import nengo import nengo_spinnaker ... sim1 = nengo_spinnaker(model, use_serial=True) sim2 = nengo_spinnaker(model, use_serial=False)
An excellent point... how would something like:
sim1 = nengo_spinnaker.Simulator(model, io=nengo_spinnaker.io.Serial(...))
sim2 = nengo_spinnaker.Simulator(model, io=nengo_spinnaker.io.Pixiedust(...))
Suit you?
I'm torn between "there'll likely only ever be two IO forms, so we should/could just stick everything in and have booleans to enable/disable" and "we should factorise nicely"... I can see the pragmatism of the former, but would sincerely prefer the latter...
I made a start with 2104674395e853a55ef89197dc48dc04c1451eb6.
When we don't specify a
spinnaker_build
function for a Node, the Builder currently looks through some flags before constructing either the connectivity required for SpiNNlink/UART IO or SDP/Ethernet IO. It would be nice if providing the "default" action for a Node were pluggable in the same way that we provide pluggable Connection building. I'm thinking then that when the Builder encounters a Node without aspinnaker_build
function it passes the building of this Node off to some external function which may be one registered by a different module.This different module/code/... can also provide code for interfacing with Nodes being computed on the host. This code needs to provide complete inputs from the network on SpiNNaker and accept input from Nodes for the network. The Simulator then cares just about this interface.
From the user side this could be as simple as:
The Builder will need changing to have pluggable handles for building Nodes, x -> Node and Node -> x connections - but to an extent this is already done. The Simulator will need some interface for receiving/querying inputs from Nodes (these may be cached by the IO interface) and some interface for sending from Nodes.
The
nengo_spinnaker.io.xyz
modules cancall a class method on the Buildercontain decorated functions which register themselves as the default functions for constructing Nodes and connecting to/from Nodes. The SpiNNlink/UART module might look like:This isn't too far from the kind of stuff we already do... We should "require" that any IO method defines all the required functions because that would mean that
cleanly uses SpiNNlink/UART rather than entangled pairs or some mix-match of both.
For the Simulator, IO modules need to provide a class which can be instantiated to generate key/Node/whatever mappings (all IO will likely need this), and provides functions for getting the input and setting the output of a Node. We may also need a start/stop function which sets up serial links/starts IO handling threads/... Continuing with the SpiNNlink IO module:
The Simulator can then do something like:
This doesn't include anything for Node <-> Node connections, but that should be relatively trivial to do.
Is this over engineered? Thoughts?