Come memorizzare vari valori di dimensioni in un vettore?

0

Voglio separare il protocollo di comunicazione dal mezzo di comunicazione in un progetto. Ad esempio, voglio avere una classe seriale e qualunque altra classe media e separatamente avere una classe di protocollo checksum e una classe di protocollo crc e così via. In questo modo, una classe di dispositivo può avere un puntatore di classe base membro per il mezzo e un altro per il protocollo e tramite le classi figlio del costruttore della classe di dispositivi di entrambi può essere passato.

Pseudo codice

class CDevice
{
public:
CDevice( CCommunicationDriver * drvr, CProtocol * protocol ) :
    drvr_     ( drvr ),
    protocol_ ( protocol )
{}

private:
CCommunicationDriver * drvr_;
CProtocol *            protocol_;
};

class CCrcProtcol : public CProtocol
{};

class CSerial : public CCommunicationDriver
{};

CDevice  a_device( new CSerial, new CCrcProtocol );

L'idea è che se la differenza tra 2 dispositivi è solo il mezzo e / o il protocollo, un semplice cambiamento può avere un impatto profondo. L'obiettivo è una riscrittura minima del codice per un cambiamento di questa natura.

In definitiva, immagino che il driver di comunicazione comprenda un CPacket che è un involucro sottile attorno a un vettore std ::. In questo modo l'interfaccia per il driver di comunicazione non deve cambiare in futuro. Prevedo che il vettore tenga i char non firmati (byte) poiché alla fine tutto quello che passa su un filo / mezzo è byte.

Questo porta a comandi disaccoppiati dal mezzo e protocollo anche se non completamente disaccoppiati. Quindi, un comando per accendere una luce potrebbe avere un ID 1 e un sotto-ID 2. Quello che penso che devo fare è passare i comandi figli alla funzione di trasmissione del driver [tx (CCommand *)] e far sì che questa funzione si applichi la decorazione del protocollo (non sono sicuro su come funzionerà ancora) e quindi ottenere un vettore di byte per far spingere il driver di comunicazione figlio fuori dal filo.

Quindi, ho 2 domande che potrei usare per aiutare. 1. (domanda principale) Poiché alla fine tutto finisce nello std :: vector < carattere non firmato > qual è un modo flessibile per aggiungere dati a quel vettore? Cioè un comando ha un id 2 byte lungo a causa di un protocollo ma per un altro è di 4 byte. Come faccio a passare id e 2 o 4 ad una funzione che la dividerà in singoli byte? Supponiamo che ci siano molte dimensioni (lunghezza 1, 2, 3, 4, 8, ecc.). Ho pensato a una funzione modello con cui specifichi il tipo e quindi il valore passato verrà interpretato come la dimensione di quel tipo.     modello di < typename T >     void addData (dati T)     {     // determinare il tipo di dati, analizzare in qualche modo?     }

and also
template <typename T >
void addData( T data, int size )
{
// size is known but won't I have to specialize every size?
}
  1. La classe del protocollo dovrebbe essere un membro della classe del driver o tenerli separati?

Spero che questa lunga spiegazione di ciò che sto cercando di ottenere sia più utile che fastidiosa e che qualcuno abbia un'idea brillante.

Grazie. -G -

    
posta Grasshopper 23.10.2015 - 04:52
fonte

1 risposta

1

In primo luogo, le classi di comando sono disaccoppiate dal mezzo e dal protocollo. Ciò significa che puoi progettare le classi di comando per la tua programmazione convenienza , piuttosto che doverle progettare in modo che corrispondano esattamente alle specifiche di ciascun protocollo (il che sarebbe impossibile, dal momento che protocolli diversi possono avere larghezze di bit differenti per lo stesso comando e campo).

Quando cito convenience , voglio dire che puoi utilizzare la larghezza massima di bit che ti servirà per i campi di ciascun comando.

Tuttavia, potrebbe essere comunque necessario avere un codice di convalida specifico per dispositivo o protocollo, poiché ogni dispositivo o protocollo impone i propri limiti a quali valori possono trovarsi in quei campi. A meno che tu non preveda di implementare alcuna convalida.

Quando si tratta di convalida, ci sono diverse scelte:

  • Non farlo affatto, se farai tutta la programmazione da solo, e se si tratta di un progetto per hobby in modo che gli errori non comportino danni.
  • Convalidarlo con entusiasmo, cioè nella classe di comando. Questo può essere difficile, dal momento che una classe di comando potrebbe non sapere a quale dispositivo o protocollo verrà inviato.
  • Convalida in ritardo, ovvero nella classe del protocollo in cui i valori dei comandi vengono convertiti in byte.

Ad esempio, anche se una regola di convalida dice che un determinato campo può avere solo un valore nell'intervallo 0 - 100, non ti impedisce di usare un uint32_t o int32_t per quel campo nel comando classe.

Alla seconda domanda di avere un metodo sovraccarico che accetta vari tipi di numeri incorporati e aggiunge i byte a un vettore di byte interno, nota caveat .

Secondo me, se hai solo bisogno di lavorare con i tipi interi fondamentali, non hai bisogno di modelli. Invece, si forniscono semplicemente sovraccarichi di funzione per ciascuno dei tipi e si chiamano le funzioni con un valore del tipo appropriato.

void CPacket::addData(uint32_t data) { ... }
void CPacket::addData(int32_t data) { ... }
void CPacket::addData(uint16_t data) { ... }
void CPacket::addData(int16_t data) { ... }
...

Per quanto riguarda il codice all'interno, ci sono diverse scelte:

Digitare punire con union . Ciò presuppone che il tuo codice funzionerà esclusivamente con un byte-endianness, quindi non è necessario considerare la possibilità di eseguire il porting su un diverso byte-endianness.

union
{
    uint32_t value;
    uint8_t bytes[4];
} pun = { data };
// after that, add the bytes to the vector one-by-one, according to the byte endianness of the communication.

Estrarre esplicitamente i byte con l'aritmetica bit a bit indipendente da endian: (vedi nota su casting )

// only if value is unsigned. For signed value, it must first be cast to unsigned
uint8_t byte0 = (uint8_t)value;
uint8_t byte1 = (uint8_t)(value >> 8ul);
uint8_t byte2 = (uint8_t)(value >> 16ul);
uint8_t byte3 = (uint8_t)(value >> 24ul);
    
risposta data 23.10.2015 - 09:46
fonte

Leggi altre domande sui tag