EDIT:
I conclude I've failed to describe the problem.
Intro: Master-Slave Architecture
Master-Slave is a common hardware setting, in which multiple peripheral, passive components, are wired to a single active master component.
Each such slave has an address, by which the master can identify it, read from it, and write to it.
The main rule of master-slave is:
Any action on a slave can only be done by the master.
Let's assume the master can do 2 things:
- Write 1 byte to a slave address.
- Read 1 byte from a slave address.
In good old C, the master's 'API' would have been:
void Write(void* masterHandle, int slaveAddress, byte data);
byte Read(void* masterHandle, int slaveAddress);
All the slave functionality is determined by that 1 byte written to it by master.
I'm designing the API for such hardware piece. I know my slaves and their roles (which vary), but for simplicity let's assume we have 3 types of slaves:
- LightBulb - with on/off states.
- Beeper - also with on/off states, but the HW wiring is not the same so the 1-byte write command to change state is different.
- Sensor - which just exposes 256 'states'. Writing to this slave has no effect.
Now let's talk software.
Here's the thing: The user of this hardware piece does not care about 'masters' and 'slaves'. He cares about functionality. So what I want to expose is only:
TurnLightOn();
Beep();
double ReadSensor();
... and so forth.
There are (potentially) multiply slaves per type, so it makes sense to expose these operations as classes:
class Beeper
{
void Beep(int period) { ... }
}
And the user could have multiple instances of such Beepers, LightBulbs and Sensors.
I'm currently considering this IoC design, and would like to have feedback on it:
// language agnostic...
interface ISlave
{
int GetAdress();
}
interface IMaster
{
void SetState(ISlave slave, byte newState);
byte GetState(ISlave slave);
}
// common slave behavior here
class BaseSlave : ISlave
{
// implement interface
public int GetAddress() { return _address; }
// c'tor
public BaseSlave(IMaster master, int address) : _master(master), _address(address) {}
protected IMaster _master;
protected int _address;
}
// light bulb slave
class LighBulb : BaseSlave
{
static byte STATE_ON = 1;
static byte STATE_OFF = 0;
public void TurnOn() {
_master.SetState(this, STATE_ON);
}
public void TurnOff() {
_master.SetState(this, STATE_OFF);
}
public bool IsOn() { return _master.GetState(this) == STATE_ON; }
}
// beeper slave
class Beeper : BaseSlave
{
static byte STATE_ON = 0xF1;
static byte STATE_OFF = 0xA1;
public void Beep(int period) {
_master.SetState(this, STATE_ON);
// some delay here
Delay(period);
_master.SetState(this, STATE_OFF);
}
}
// sensor slave
class Sensor : BaseSlave
{
public double ReadSensor() {
return _master.GetState(this) * 100.0 / 255; // units conversion
}
}
class Master : IMaster
{
// implements that interface somehow...
public void SetState(ISlave slave, byte newState)
{
Write(this.Handle, slave.GetAddress(), newState);
}
public byte GetState(ISlave slave)
{
return Read(this.Handle, slave.GetAddress());
}
...
// creating slaves - this one also looks clumsy at best
public LightBulb AddLightBulb(int address)
{
return new LightBulb(this, address);
}
public Beeper AddBeeper(int address)
{
return new Beeper(this, address); }
}
}
So I think it's quite clear why I'm not happy with the above design. But I'm somewhat lost with finding something more suitable. Any suggestions, comments, critics are welcome.