O pamięć nie ma co się martwić
Zatem optowałbym za pełnoprawnym, kobylastym rozwiązaniem:
class MotorDriver {
protected:
uint8 leftMotorPin;
uint8 rightMotorPin;
public:
MotorDriver(uint8 leftMotorPin, uint8 rightMotorPin) : leftMotorPin(leftMotorPin), rightMotorPin(rightMotorPin) {
}
void enableLeftMotor() {
pinMode(this->leftMotorPin, 1);
}
void enableRightMotor() {
pinMode(this->rightMotorPin, 1);
}
}
class CameraDriver {
// srututututtu
}
typedef void (*ControllerAction)(Command);
typedef std::map<std::string, ControllerAction> ControllerActionsMap;
class AbstractController {
protected:
ControllerActionsMap controllerActions;
void registerCommand(string commandName, ControllerAction controllerAction) {
this->controllerActions[commandName] = controllerAction;
}
public:
bool handleCommand(Command command) {
// sprawdź czy dana akcja znajduje się na naszej liście obsługiwanych akcji
ControllerActionsMap::iterator fnc = this->controllerActions.find(command.commandName);
// jeśli nie - zwróć false i na tym poprzestań
if (fnc == this->controllerActions.end()) {
return false;
}
// jeśli zaś tak - przeskocz do tej metody i zwróć sukces, jako że akcja została obsłużona
(this.*(fnc->second))();
return true;
}
}
class MotorController {
protected:
MotorDriver* motorDriver;
public:
MotorController(MotorDriver* motorDriver) : motorDriver(motorDriver) {
this.registerCommand("motor.go_forward", &MotorController::cmdGoForward);
}
void cmdGoForward(Command command) {
this->motorDriver->enableLeftMotor();
this->motorDriver->enableRightMotor();
}
}
class CameraController {
protected:
OutputDriver* outputDriver;
CameraDriver* cameraDriver;
public:
CameraController(OutputDriver* outputDriver, CameraDriver* cameraDriver) : outputDriver(outputDriver), cameraDriver(cameraDriver) {
this.registerCommand("camera.take_picture", &CameraController::cmdTakePicture);
}
void cmdTakePicture(Command command) {
this->cameraDriver->picturePrepare();
char* picture;
uint32 pictureSize;
this->cameraDriver->takePicture(picture, pictureSize);
this->outputDriver->writeRaw(picture, pictureSize);
this->cameraDriver->releasePicture(picture, pictureSize);
}
}
struct Command {
string commandName;
vector<string> commandArgs;
}
class CommandManager {
protected:
string commandBuffer;
vector<AbstractController*> controllers;
Command parseCommandBuffer() {
Command command = new Command();
// uwaga, magia
return command;
}
public:
void registerController(AbstractController* controller) {
this->controllers.push_back(controller);
}
void dispatchCommand() {
Command command = this->parseCommandBuffer();
bool commandHandled = false;
for (AbstractController &controller: this->controllers) {
commandHandled |= controller->handleCommand(command);
}
if (!commandHandled) {
// wyświetl błąd czy coś
}
free(command);
this->commandBuffer.clear();
}
}
const uint8
LEFT_MOTOR_PIN = 9,
RIGHT_MOTOR_PIN = 10;
int main() {
MotorDriver* motorDriver = new MotorDriver(LEFT_MOTOR_PIN, RIGHT_MOTOR_PIN);
OutputDriver* outputDriver = new OutputDriver();
CameraDriver* cameraDriver = new CameraDriver();
MotorController* motorController = new MotorController(MotorDriver);
CameraController* cameraController = new CameraController(OutputDriver, CameraDriver);
CommandManager* commandManager = new CommandManager();
commandManager->registerController(motorController);
commandManager->registerController(cameraController);
Serial serial;
while (true) {
serial.readcośtamcośtam();
commandManager->cośtamcośtam();
}
}
uwaga: kod pisany na kolanie
Wykorzystując wzorzec DI, ładnie wydzielone zostały odpowiedzialności (przede wszystkim dodanie nowej komendy wymaga już jedynie zmiany danego kontrolera, a nie grzebania wewnątrz CommandManager
a) oraz odpowiednie stałe, wszystko tworzone jest na początku życia aplikacji, dlatego też bezproblemowo kontrolowalne ;-)
Niestety wcisnął mi się przez przypadek klawisz przez co po zapisie robot cały czas jeździ a ja na szybko szukam błędu
???
klasa która nie będzie singletonem może się bardzo rozrosnąć.
???