My work is mostly in embedded systems programming in C, and the proper class str
ID: 643213 • Letter: M
Question
My work is mostly in embedded systems programming in C, and the proper class structure to pull this off eludes me. Currently we communicate via C# and Visual Basic with a large collection of servos, pumps, and sensors via a USB-to-CAN hid device.
Right now, it is quite cumbersome to communicate with the devices. To read the firmware version of controller number 1 you would use:
SendCan(Controller,1,ReadFirmwareVersion) or
SendCan(8,1,71)
This sends three bytes on the CAN bus: (8,1,71)
Connected to controllers are various sensors.
SendCan(Controller,1,PassThroughCommand,O2Sensor,2,ReadO2)
would tell Controller number 1 to pass a command to O2 Sensor number 2 to read O2 by sending the bytes 8,1,200,16,2,0
I would like to develop a domain-specific language for this setup. Instead of commands issued like they are currently, commands would be written like this:
Controller1.SendCommand.O2Sensor2.ReadO2
to send the bytes 8,1,200,16,0
What's the best way to do this? Some machines have 20 O2 Sensors, others have 5 controllers, so the numbers and types of controllers and sensors, pumps, etc. aren't static.
Explanation / Answer
I would prefer to write
machine1.Controllers[1].O2Sensors[2].ReadO2();
There is no need to have a SendCommand in there.
UPDATE
Here is my suggestion for a controller class
public class Controller
{
private const int ReadFirmwareVersionCmd = 71;
private const int PassThroughCommandCmd = 200;
private int _controllerNumber;
public Controller(int controllerNumber)
{
_controllerNumber = controllerNumber;
O2Sensors = new List<O2Sensor>();
}
public List<O2Sensor> O2Sensors { get; private set; }
private void SendControllerCommand(int controllerCommand)
{
Controller.SendCan(8, _controllerNumber, controllerCommand);
}
public void SendSensorCommand(int sensorType, int sensorNo, int sensorCommand)
{
Controller.SendCan(8, _controllerNumber, PassThroughCommandCmd, sensorType, sensorNo, sensorCommand);
}
private static void SendCan(int deviceType, int deviceNo, int commandNo)
{
// ...
}
private static void SendCan(int deviceType, int deviceNo, int commandNo,
int sensorType, int sensorNo, int sensorCommand)
{
// ...
}
public void ReadFirmwareVersion( )
{
SendControllerCommand(ReadFirmwareVersionCmd);
}
}
I would derive all the sensor types from a common base
public abstract class SensorBase
{
protected Controller _controller;
protected int _sensorNo;
public SensorBase(Controller controller, int sensorNo)
{
_controller = controller;
_sensorNo = sensorNo;
}
public abstract void Read();
}
An O2-sensor as an example for a sensor
public class O2Sensor : SensorBase
{
public O2Sensor(Controller controller, int sensorNo)
: base(controller, sensorNo)
{
}
public override void Read()
{
_controller.SendSensorCommand(16, _sensorNo, 0);
}
}
You can initialize a controller like this
var controller1 = new Controller(1);
controller1.O2Sensors.Add(new O2Sensor(controller1, 1));
controller1.O2Sensors.Add(new O2Sensor(controller1, 2));
Now you can read information like this
controller1.ReadFirmwareVersion();
controller1.O2Sensors[1].Read();
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.