Biljana Tanceska
Biljana Tanceska

Reputation: 21

How to make a FIFO buffer with can_frame structure inside?

In the moment I am working on a project on which a few processors are communication between then using can bus. The main controler (beagle bone) controls the other device using a can bus. Using a socket can linux framework I wrote a proccess that reads the can messages send from the other devices, and now I want to put the messages I get into a FIFO bufer, and then to obrabotam the messages. So I need to write the FIFO buffer with can_frame structure inside.

For example:

struct can_buffer {
    struct can_frame *frames;
    int head;
    int tail;
    int size;
};

can_buffer new_can_buffer (size_t capacity)
{
    can_buffer rb = malloc(sizeof(struct can_buffer));
    if (rb) {

        /* One byte is used for detecting the full condition. */
        rb->size = capacity + 1;
        rb->frames = malloc(rb->size * sizeof(struct can_frame));
        if (rb->frames)
            can_buffer_reset(rb);
        else {
            free(rb);
            return 0;
        }
    }
    return rb;
}

size_t can_buffer_size(const struct can_buffer *rb)
{
    return rb->size;
}

size_t can_buffer_capacity(const struct can_buffer *rb)
{
    return can_buffer_buffer_size(rb) - 1;
}

size_t can_buffer_free(const struct can_buffer *rb)
{
    if (rb->head >= rb->tail)
        return can_buffer_capacity(rb) - (rb->head - rb->tail);
    else
        return rb->tail - rb->head - 1;
}

int can_buffer_is_full(const struct can_buffer *rb)
{
    return can_buffer_free(rb) == 0;
}

int can_buffer_is_empty(const struct can_buffer *rb)
{
    return can_buffer_free(rb) ==can_buffer_capacity(rb);
}

void can_buffer_reset(can_buffer rb)
{
    rb->head = rb->tail = 0;
}

......... ........

/* Add message to the end of the queue. */

void can_buffer_push(struct can_buffer *cb, struct can_frame *frame)
{
    memcpy(&cb->frames[cb->tail], frame, sizeof(struct can_frame));
    cb->tail = (cb->tail + 1) % cb->size;
}

/* Retrieve message from the start of the queue. */
can_frame *can_buffer_pop(struct can_buffer *cb)
{
    struct can_frame *frame;
    memcpy(frame, &cb->frames[cb->head], sizeof(struct can_frame));
    cb->head = (cb->head + 1) % cb->size;
    return frame;
}

But I canoot do it successfully. I think the problem is that every can_frame structure inside is a structure again,that is the problem (for example int, char etc), but I do not know how to solve this issue.

How can I make a FIFO buffer that can store the can_frame structure inside?

I need to write this in C lagnuage

in main i call

can_buffer can_buff;

can_buff = new_can_buffer(100);

can_buffer_push(can_buff,frame);

frame = can_frame i received

can_buff = fifo buffer

Upvotes: 1

Views: 831

Answers (1)

Seth
Seth

Reputation: 2647

Well, you have incompletely modified the ringbuf routines. Specifically, you don't allocate enough space for the structures here:

if (rb) {

    /* One byte is used for detecting the full condition. */
    rb->size = capacity + 1;
    rb->frames = malloc(rb->size);
    if (rb->frames)
        ringbuf_reset(rb);
    else {
        free(rb);
        return 0;
    }
}

The malloc needs to be

rb->frames = malloc(rb->size * sizeof(struct can_frame));

And the you should update the ringbuf_reset() call on the next line to your renamed can_buffer_reset()


Addendum:

I just noticed that you also need to update your ringbuf_reset() function to rb->head = rb->tail = 0


Addendum 2:

Referencing the newly added code, can_buffer_pop() will not work correctly as it doesn't check for the message existing and it doesn't allocate memory for the popped message.

There is also a typo in can_buffer_capacity().

Editorial: I would strongly suggest writing a simple test program that executes these functions. It's frustrating but will catch a number of these small gotchas.

Upvotes: 1

Related Questions