2013-02-17 15 views
5

Sto scrivendo codice incorporato per STM32F3 mc (STM32F3-Discovery). Ho bisogno di trasmettere alcuni dati su UART e sto usando DMA per questo, in quanto ciò mi consente di concentrarmi sulla lettura dei sensori e sull'elaborazione dei dati piuttosto che sull'attesa del completamento della trasmissione dei byte. Il problema però è che devo unire:Stampa formattata su buffer circolare

  1. output formattato (cioè alcuni da di printf)
  2. Un certo numero di stampe consecutive (che si verificano prima stampa precedente è terminata)

Così ho Sto pensando a un buffer circolare. Ma non penso di sapere come rendere Sprintf rispettoso della fine del buffer e continuare a scrivere all'inizio del buffer. Ovviamente posso creare un altro buffer temporaneo, stamparlo lì e copiare byte per byte, ma non mi sembra elegante.

+1

Requisito interessante, ma non credo che si possa fare molto meglio di 'formattazione in buffer temporaneo seguito da copia su buffer circolare con funzione di copia appropriata'. –

risposta

2

Una soluzione potrebbe essere quella di implementare il proprio sprintf che è in grado di funzionare con i buffer dell'anello. Sfortunatamente questo non ti aiuterà a risolvere un problema di base: cosa faresti se il tuo RingBuffer è pieno e invochi sprintf?

Se la vostra situazione memoria può permettere, io suggerirei di un'altra soluzione per questo problema:

L'idea si basa su due liste collegate di buffer (una lista dei buffer liberi, un elenco come coda di trasmissione) . I buffer sono ugualmente dimensionati in modo da poter memorizzare una stringa di lunghezza peggiore. I buffer costruiscono un semplice heap in cui allocazione/deallocazione non fa altro che dequeuing/enqueuing di un elemento sia dal libero sia dall'elenco di trasmissione.

Avere buffer di dimensioni uguali garantisce di non soffrire di effetti di frammentazione esterni come "scacchiera" mentre si assegna dinamicamente la memoria. Costruire il proprio heap per questo lavoro ti darà anche il pieno controllo sulla dimensione totale del buffer disponibile per le attività di trasmissione.

potevo immaginare questo correre come segue:

  1. di allocare un buffer dalla lista libera di rendere i dati in.
  2. Usa il render funzioni (suchas sprintf) per rendere i dati nel buffer
  3. aggiungere i dati devono essere inviati alla coda di trasmissione (e innescare una trasmissione se necessario)

Per il DMA trasferirà gestire l'IRQ di trasferimento. Qui si sposta il buffer appena trasferito alla "lista libera" e si imposta il trasferimento per il buffer successivo nella coda.

Questa soluzione non sarà la memoria più efficiente, ma l'efficienza di runtime è buona poiché si scrive una sola volta nella memoria e l'allocazione/deallocazione sta solo recuperando/memorizzando un puntatore da qualche parte. Ovviamente dovrai assicurarti di non ottenere condizioni di gara tra la tua domanda e l'IRQ per l'allocazione/deallocazione.

Forse questa idea ti dà l'ispirazione per risolvere le tue esigenze.

1

Un modo per approssimarsi è allocare il buffer di stampa come 2x della dimensione del proprio buffer, quindi utilizzare la prima metà come buffer circolare. Rileva un trabocco, copia il trabocco nella seconda metà indietro verso la parte anteriore (la parte ad anello).Qualcosa del genere:

void xprintf(const char *format, ...) 
{ 
    int written; 
    va_list args; 
    va_start(args, format); 
    written = vsnprintf(buffer, HALF_BUFFER_SIZE, format, args); 
    va_end(args); 
    if (buffer + written > bufferStart + HALF_BUFFER_SIZE) 
    { // time to wrap 
    int overflow = (buffer + written) - (bufferStart + HALF_BUFFER_SIZE); 
    memmove(bufferStart, bufferStart + HALF_BUFFER_SIZE, overflow; 
    buffer = bufferStart + overflow; 
    } 
}