I’m writing a piece of software in python that will communicate with a bunch of devices via an I2C bus. Each of these devices are going to need some sort of a module or class to handle the communication and data conversion in some sensible way. The operations that each of the device modules perform are drastically different.
My main concern is the I2C bus control. I fear that sharing the bus, by for example having each of the device modules instantiate a new I2C bus control object results in code that is hard to follow and I’m not sure how these objects would communicate if the there’s an interrupt in the bus. However, not sharing it, I fear I’ll end up with a huge control class that is hard to maintain and extend.
If I lean towards the control class, each of the device modules would hold a map of operations, like an OrderedDict
or a list of tuples of functions with expected result values or ranges. The I2C control object could then iterate that dictionary, write and read the results from the bus and move to the next function if the result is in the expected range. This sounds like a state machine design, but I’m not sure if I can really generalize all operations enough.
I suppose my question boils down to does anyone have a good suggestion for a design pattern?
Not as pythonic as you want it, but I think you just want to have the i2c control object only be a bus arbiter, not a device controller; each different device object can instantiate its own copy of the i2c bus object and communicate to the bus as if it has exclusive access to the bus. This greatly simplifies the device object programming. I don’t see how this results in code that is hard to follow. Think of this as just the device driver logic. The layer one level up from this will be your system logic layer, which instantiates devices and communicates to the devices via their object interfaces.
Your i2c bus object can have class methods and class attributes (such as mutexes, read queues, write queues, etc) that the users of the class don’t need to know about. The users of the class , which are instances of the device objects, simply call read and write methods of the i2c class.
Your device objects would then present an attribute and method interface that makes sense for the underlying physical device on the bus. For example, only your device object for the left arm of your robot knows that the method of its class “setPowerLevel(x)” results in any particular i2c bus operation. Data conversion to or from a BCD value as needed by the device on the i2c bus would be done by your device object, perhaps with the help of helper functions on the i2c bus object.
I wasn’t sure where you were headed with the OrderedDict
. It seems like you wanted to somehow give all the devices’s possible operations and data values/expected data into some iterable
object, and have some uber-controller iterate and send/receive data that way. To be honest I think that just makes the code harder to read, actually. I think devices are devices, you can create an object model for devices but you shouldn’t try to objectify them so much to squeeze them into a one-size-fits all interface. You can still have classes (in the conceptual way) of different objects grouped together under several different base classes, where each base class represents similar types of devices (i.e. memory, motor control, displays, etc)…
2