Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

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();