Advanced Embedded Programming: Completely Solving Data Loss Caused by Communication Data Overwrite – Ring Buffer

Advanced Embedded Programming: Completely Solving Data Loss Caused by Communication Data Overwrite - Ring Buffer

Advanced Embedded Programming: Completely Solving Data Loss Caused by Communication Data Overwrite - Ring Buffer

01Introduction

The Ring Buffer (also known as Circular Buffer) is a data structure used to efficiently store and manage data within a fixed-size array. It is particularly suitable for scenarios that require continuous reading and writing of data, such as audio processing, network communication, and real-time data stream processing. Below are the basic concepts, implementation methods, and application scenarios of the ring buffer.

02Basic Concepts of Ring Buffer

The ring buffer is a cyclically used buffer where data is stored in order, and when the end of the array is reached, it automatically wraps around to the beginning of the array to continue storing. This structure avoids frequent memory allocation and deallocation, improving data processing efficiency.

03Key Components of Ring Buffer

  • Buffer: A fixed-size array used to store data.

  • Head Pointer: A pointer that points to the current write position.

  • Tail Pointer: A pointer that points to the current read position.

  • Buffer Size: The fixed size of the buffer, usually a fixed integer.

04Operations of Ring Buffer

4.1 Writing Data

  • Write data to the position pointed to by the head pointer.

  • Update the head pointer to point to the next position.

  • If the head pointer reaches the end of the buffer, reset it to the starting position of the buffer.

4.2 Reading Data

  • Read data from the position pointed to by the tail pointer.

  • Update the tail pointer to point to the next position.

  • If the tail pointer reaches the end of the buffer, reset it to the starting position of the buffer.

05Implementation of Ring Buffer

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *buffer;
    int head;
    int tail;
    int size;
    int count; // Current number of elements in the buffer
} CircularBuffer;

// Initialize the circular buffer
void initCircularBuffer(CircularBuffer *cb, int size) {
    cb->buffer = (int *)malloc(size * sizeof(int));
    cb->head = 0;
    cb->tail = 0;
    cb->size = size;
    cb->count = 0;
}

// Destroy the circular buffer
void destroyCircularBuffer(CircularBuffer *cb) {
    free(cb->buffer); 
}
// Write data
int writeCircularBuffer(CircularBuffer *cb, int data) {
    if (cb->count == cb->size) {
        return 0; // Buffer is full
    }
    cb->buffer[cb->head] = data;
    cb->head = (cb->head + 1) % cb->size;
    cb->count++;
    return 1; 
}
// Read data
int readCircularBuffer(CircularBuffer *cb, int *data) {
    if (cb->count == 0) {
        return 0; // Buffer is empty
    }
    *data = cb->buffer[cb->tail];
    cb->tail = (cb->tail + 1) % cb->size;
    cb->count--;
    return 1;
}
// Check if the buffer is empty
int isCircularBufferEmpty(CircularBuffer *cb) {
    return cb->count == 0;
}
// Check if the buffer is full
int isCircularBufferFull(CircularBuffer *cb) {
    return cb->count == cb->size;
}
// Main function
int main() {
    CircularBuffer cb;
    initCircularBuffer(&cb, 5);

    writeCircularBuffer(&cb, 1);
    writeCircularBuffer(&cb, 2);
    writeCircularBuffer(&cb, 3);

    int data;
    while (!isCircularBufferEmpty(&cb)) {
        readCircularBuffer(&cb, &data);
        printf("Read: %d\n", data);
    }

    destroyCircularBuffer(&cb);
    return 0;
}

06Conclusion

Application Scenarios:

  • Audio Processing: Used for real-time processing and buffering of audio data.

  • Network Communication: Used for receiving and sending network packets, ensuring data continuity and integrity.

  • Real-time Data Stream Processing: Used for processing sensor data, log data, and other real-time data streams.

  • Embedded Systems: Used for data buffering and processing in embedded devices, improving system response speed and efficiency.

  • Advantages of Storage

  • Efficiency: Avoids frequent memory allocation and deallocation, improving data processing efficiency.

  • Simplicity: Simple to implement, easy to understand and maintain.

  • Cyclic Usage: Makes full use of limited memory resources, avoiding memory waste.

Leave a Comment