C ++ 11 domande freeRTOS sull'uso della coda e sulla progettazione di oggetti

0

Sfondo

Sto scrivendo firmware C ++ con freertos su penplottingrobot. È un XYplotter di sblocco e il firmware si sta collegando al software mDraw per le istruzioni di comando tramite i driver USB. Il programma MDraw invia comandi Gcode. Se devi sapere, c'è una matita controllata da un servo di modulazione di larghezza d'onda e il plotter viene azionato con motori passo-passo a due assi.

Ai nostri intenti e quegli input mDraw sono ottenuti come std::string s e inviati a Gcodeparser::parseCommand(std::string) .

Problema

Esiste una soluzione più elegante di quanto segue ???

// quindi il codice funziona sin d'ora, ma non ha una buona interfaccia o usabilità

Sto utilizzando un parser_task , con un oggetto Gcodeparser per analizzare quei Gcodecommands . .ParseCommand() memberfunction richiede std::string come parametro e restituisce un CommandStruct in base al valore. CommandStruct contiene solo tipi di dati semplici-vecchi come int , enum e bool . Dopo che un comando legale è stato analizzato, viene quindi inviato a una coda freeRTOS per valore ( CommandStruct viene inviato alla coda). La coda è necessaria per comunicare con l'altra attività, chiamata execute_commands_task , che ovviamente sta leggendo questa coda.

Ho diverse possibilità di legale Gcode s, ma condividono solo due datamembers in comune: enum {M4, G1, G28 ... }baseType e bool isLegalCommand .

Altrimenti tutti quei "diversi tipi di basi" Gcode s possono avere una quantità differente di datamembers, di tipi diversi (in genere bool o int datamembers, ma ci sono coordinatevalue s, pencilservo valori, clockwisemotordirectionvalue s ecc ...).

Quindi, la mia soluzione corrente che era stupida (ma funziona), era quella di mettere tutti i datamembers disponibili in quel CommandStruct . In questo modo puoi utilizzare quella struttura per passare qualsiasi tipo di comando Gcode nella coda freeRTOS e ottenere comunque dati validi.

Il codice è fastidiosamente brutto perché ci sono datamembers non utilizzati per ogni comando Gcode ...

Ma devo ancora essere in grado di passare qualcosa nella coda freeRTOS che è in grado di trasmettere tutti i dati richiesti.

#pragma once

struct CommandStruct {
    enum {
        M1,
        M4,
        M10,
        G1,
        G28,
        M5,
        M11,
        M28,
        M2,
        uninitialized
    } commandWord; //any  Gcode command has commandWord (essentially a basetype)

    int commandNumber; //pencilServoParameter, or laserParameter [0,255]

    int penUp; //parameter for M2 command
    int penDown; //parameter for M2 command

    int height; //parameter for M5 command
    int width; //parameter for M5 command
    int speed;  //parameter for M5 command

    bool xMotorClockwise; //parameter for M5 command
    bool yMotorClockwise; //parameter for M5 command

    bool isLegal; //any Gcode command has legality
    int xCoord; //coords for G1command HUNDREDTHS of mm
    int yCoord; //coords for G1command HUNDREDTHS of mm

    CommandStruct() {
        commandWord = uninitialized;
        commandNumber = -1;
        penUp = -1;
        penDown = -1;
        height = -1;
        width = -1;
        speed = -1;
        xMotorClockwise = true;
        yMotorClockwise = true;
        isLegal = false;
        xCoord = -1;
        yCoord = -1;
    }
};
    
posta Late347 14.10.2018 - 22:28
fonte

1 risposta

0

La prima ottimizzazione per eliminare la maggior parte dei membri non utilizzati in CommandStruct è trasformarla in un'unione discriminata, come questa:

struct CommandStruct {
    enum {
        uninitialized,
        M1,
        M4,
        M10,
        G1,
        G28,
        M5,
        M11,
        M28,
        M2,
    } commandWord; // command discriminator

    bool isLegal; //any Gcode command has legality
    //... other members that apply to ALL commands

    union {
        struct {
            // parameters for M1 command
        } M1;
        struct {
            int penUp; //parameter for M2 command
            int penDown; //parameter for M2 command
        } M2;
        struct {
            int height; //parameter for M5 command
            int width; //parameter for M5 command
            int speed;  //parameter for M5 command

            bool xMotorClockwise; //parameter for M5 command
            bool yMotorClockwise; //parameter for M5 command
        } M5;
        //... structures with parameters for other commands
    };

    CommandStruct() {
        commandWord = uninitialized;
        isLegal = false;
    }
};

Con un'unione discriminata, i parametri di ciascun comando condividono tutti la stessa parte dell'oggetto CommandStruct e il membro commandWord indica a quale gruppo di parametri è possibile accedere in modo valido. Ciò richiede che un CommandStruct e tutti i suoi membri (sia diretti che indiretti) possano essere copiati senza un costruttore di copia.

Un'altra possibilità è creare classi separate per ogni comando. Per passare quelli attraverso la coda correttamente, dovresti passarli per riferimento (puntatore) attraverso la coda per evitare che tali informazioni vengano perse.

D'altra parte, l'utilizzo di classi separate per ciascun comando ti consente di implementare il schema di progettazione del comando e spostare l'implementazione del comando da execute_commands_task anche nelle classi di comando.

    
risposta data 15.10.2018 - 09:27
fonte

Leggi altre domande sui tag