ringbuffer, helper, HAL_Driver (LL)

This commit is contained in:
2022-07-15 12:44:08 +02:00
parent 32162a2ec4
commit cf43818890
21 changed files with 36069 additions and 0 deletions

15
Core/Inc/helper.h Normal file
View File

@ -0,0 +1,15 @@
/*
* helper.h
*
* Created on: Jul 14, 2022
* Author: tom
*/
#ifndef INC_HELPER_H_
#define INC_HELPER_H_
char *ltrim(char *s);
char *rtrim(char *s);
char *trim(char *s);
#endif /* INC_HELPER_H_ */

63
Core/Inc/ringbuf.h Normal file
View File

@ -0,0 +1,63 @@
/*
* ringbuf.h
*
* Created on: Jul 12, 2022
* Author: tom
*/
#ifndef _INC_RINGBUF_H_
#define _INC_RINGBUF_H_
#define RING_STATISTICS_ENABLED 1
#define RINGBUF_MAX_READ_LEN 20
typedef enum {
RINGBUF_PARAM_NONE = 0x00,
RINGBUF_ALLOWOVERWRITE= 0x01,
} ringbuf_param_t;
#if !defined _SYS_ERRNO_H_ && !defined __ERRNO_H__ && !defined _STM32_SI5351_H_
typedef enum {
EPERM = 1, /*!< Operation not permitted */
EIO = 5, /*!< I/O error */
ENOMEM = 12, /*!< Out of memory */
EFAULT = 14, /*!< Bad address */
EBUSY = 16, /*!< Device or resource busy */
ENODEV = 19, /*!< No such device */
EINVAL = 22, /*!< Invalid argument */
EADDRINUSE = 98,/*!< Address already in use */
ETIMEDOUT = 116,/*!< Connection timed out */
} ringbuf_errno_t;
#endif
//extern ringbuf;
#define hring struct ringbuf *
//receive callback typedef definition
typedef void (*ringbuf_rcv_cb_t)(uint16_t delimiterfound, void* cb_data);
#if !defined min
#define min(a,b) ((a < b)? a : b)
#endif
hring ringbuf_create(size_t size, ringbuf_param_t param);
void ringbuf_destroy(hring);
int ringbuf_push(hring, const uint8_t *data, size_t size);
int ringbuf_pull(hring, uint8_t *data, size_t maxsize);
int ringbuf_clear(hring);
int ringbuf_free(hring);
int ringbuf_read(hring, char *str);
int ringbuf_write(hring, char *str);
int ringbuf_callback_register(hring, ringbuf_rcv_cb_t cb_func, void *cb_data);
int ringbuf_set_max_read_len(hring, int max_read_len);
int ringbuf_get_max_read_len(hring);
int ringbuf_is_empty(hring);
int ringbuf_dump(hring);
#if RING_STATISTICS_ENABLED
int ringbuf_statistics(hring);
int ringbuf_stat_writes(hring);
int ringbuf_stat_reads(hring);
int ringbuf_stat_overflow(hring);
#endif
#endif /* _INC_RINGBUF_H_ */

15
Core/Inc/ringbuf_test.h Normal file
View File

@ -0,0 +1,15 @@
/*
* ringbuf_test.h
*
* Created on: Jul 14, 2022
* Author: tom
*/
#ifndef INC_RINGBUF_TEST_H_
#define INC_RINGBUF_TEST_H_
void ringbuf_test(void);
#endif /* INC_RINGBUF_TEST_H_ */

27
Core/Src/helper.c Normal file
View File

@ -0,0 +1,27 @@
/*
* helper.c
*
* Created on: Jul 14, 2022
* Author: tom
*/
#include <string.h>
#include <ctype.h>
char *ltrim(char *s)
{
while(isspace((int)*s)) s++;
return s;
}
char *rtrim(char *s)
{
char* back = s + strlen(s);
while(isspace((int)*--back));
*(back+1) = '\0';
return s;
}
char *trim(char *s)
{
return rtrim(ltrim(s));
}

311
Core/Src/ringbuf.c Normal file
View File

@ -0,0 +1,311 @@
/**
******************************************************************************
* @file ringbuf.c
* @brief driver for a ring buffer used for UART RX
******************************************************************************
* @author: Thomas Kuschel KW4NZ
* created 2022-07-12
*
* A description can be found in the header file ringbuf.h
******************************************************************************/
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <stdlib.h> /* malloc */
#include <stdio.h> /* printf */
#include <string.h> /* memcpy */
#include "ringbuf.h"
/* macros */
#define MEM_USED(b) ((b->size + b->head - b->tail) % b->size)
#define MEM_FREE(b) ((b->size + b->tail - b->head - 1) % b->size + 1)
#if RING_STATISTICS_ENABLED
typedef struct stat {
uint32_t overflows;
uint32_t reads;
uint32_t writes;
} stat_t;
#endif
typedef struct ringbuf {
#if RING_STATISTICS_ENABLED
stat_t statistics;
#endif
ringbuf_rcv_cb_t rcv_callback;
void *rcv_cb_data;
uint8_t *buf;
uint16_t size;
uint16_t head;
uint16_t tail;
uint16_t delimiterfound;
uint16_t max_read_len;
unsigned full :1; // not implemented yet
unsigned halffull:1; // not implemented yet
unsigned overflow:1;
unsigned allowoverwrite:1;
} ringbuf_t;
struct ringbuf * ringbuf_create(size_t size, ringbuf_param_t param) {
struct ringbuf * rb;
if (size == 0 || size > USHRT_MAX)
return NULL;
// rb = malloc(sizeof(ringbuf_t) + size * sizeof(uint8_t));
rb = calloc(1, sizeof(ringbuf_t) + size * sizeof(uint8_t));
if (rb == NULL) {
puts("Memory not allocated.\n");
exit(0);
} else {
puts("Memory successfully allocated.\n");
// the data area is connected to the structure
rb->buf = (uint8_t *)rb + sizeof(ringbuf_t);
rb->size = (uint16_t)size;
// rb->head = rb->tail = rb->halffull = rb->overflow 0;
if (param & RINGBUF_ALLOWOVERWRITE)
rb->allowoverwrite = 1;
rb->max_read_len = RINGBUF_MAX_READ_LEN;
}
return rb;
}
void ringbuf_destroy(struct ringbuf *ring) {
if (ring != 0)
free(ring);
}
int ringbuf_dump(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
printf("Buffer: 0x%08x\n", (unsigned int) ring);
printf("Start: 0x%08x\n", (unsigned int) ring->buf);
printf("Size: total: %d used: %d free: %d\n", ring->size, MEM_USED(ring), MEM_FREE(ring));
printf("Head: %d\n", ring->head);
printf("Tail: %d\n", ring->tail);
printf("Empty: %s\n", (ring->head == ring->tail) ? "yes" : "no");
printf("Max read length: %d\n", ring->max_read_len);
for (size_t i = 0; i < ring->size; i += 16 ) {
for (size_t j = 0; j < 16 && (j + i) < ring->size; j++) {
//printf("%02x%s", *(ring->buf +i), ((i%4)==3)?(((i%16)==15)?"\n":" "):"");
printf("%02x%s", *(ring->buf + i + j), ((j%4)==3)?" ":"");
}
putchar(' ');
for (size_t j = 0; j < 16 && (j + i) < ring->size; j++) {
uint8_t b = *(ring->buf + i + j);
printf("%c", ((b >= ' ') && (b < 127))? b: '.');
}
puts("");
}
return 0;
}
int ringbuf_push(struct ringbuf *ring, const uint8_t *data, size_t size) {
size_t delimiterpos;
size_t delimiterfound = 0;
uint16_t head;
uint8_t *ptr;
if (ring == NULL || size == 0 || data == NULL || size > USHRT_MAX)
return -EINVAL;
if (size >= ring->size)
return -ENOMEM;
if (size >= (size_t)MEM_FREE(ring)) { // no free space available, but overwrite ?
#if RING_STATISTICS_ENABLED
ring->statistics.overflows++;
#endif
if (ring->allowoverwrite)
ring->overflow = 1;
else
return -ENOMEM;
}
head = ring->head;
if (head + size > ring->size) {
uint16_t remaining = ring->size - head;
memcpy(ring->buf + head, data, remaining);
ring->head = (uint16_t)(size - remaining);
memcpy(ring->buf, data + remaining, ring->head);
} else {
memcpy(ring->buf + head, data, size);
ring->head += (uint16_t)size;
}
for (delimiterpos = 0; delimiterpos < size; delimiterpos++) {
if (data[delimiterpos] == '\n' || data[delimiterpos] == 0 ) {
delimiterfound++;
ptr = ring->buf + ((head + delimiterpos) % ring->size);
*ptr = 0;
}
}
ring->head %= ring->size;
#if RING_STATISTICS_ENABLED
ring->statistics.writes +=size;
#endif
ring->delimiterfound = (uint16_t)delimiterfound;
//call registered callback function
if (ring->delimiterfound && ring->rcv_callback != NULL)
ring->rcv_callback(ring->delimiterfound, ring->rcv_cb_data);
return (int)size;
}
int ringbuf_clear(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
ring->tail = ring->head;
ring->full = ring->halffull = ring->overflow = 0;
return 0;
}
int ringbuf_is_empty(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
return (ring->tail == ring->head);
}
int ringbuf_pull(struct ringbuf *ring, uint8_t *data, size_t maxsize) {
size_t datasize;
if (ring == NULL || maxsize == 0 || data == NULL || maxsize > USHRT_MAX)
return -EINVAL;
datasize = min(maxsize, (size_t)MEM_USED(ring));
if (datasize > ring->size)
return -ENOMEM;
if ((ring->head > ring->tail) /*|| ring->full*/) {
memcpy(data, ring->buf + ring->tail, datasize);
ring->tail += (uint16_t)datasize;
} else {
if (ring->head < ring->tail) {
size_t remaining = ring->size -ring->tail;
if (datasize < remaining) {
memcpy(data, ring->buf + ring->tail, datasize);
ring->tail += (uint16_t)datasize;
} else {
memcpy(data, ring->buf + ring->tail, remaining);
ring->tail = (uint16_t)(datasize - remaining);
memcpy(data + remaining, ring->buf, ring->tail);
}
}
}
#if RING_STATISTICS_ENABLED
ring->statistics.reads += datasize;
#endif
ring->overflow = 0;
return (int)datasize;
}
int ringbuf_read(struct ringbuf *ring, char *str) {
int len = 0;
uint16_t tail = 0;
if (ring == NULL || str == NULL)
return -EINVAL;
*str = '\0';
if (ring->head == ring->tail){
return 0;
}
tail = ring->tail;
if (ring->head > ring->tail) {
if (ring->max_read_len < 2)
return -ENOMEM;
strncpy(str, (char *)(ring->buf + ring->tail), ring->max_read_len);
str[ring->max_read_len] = '\0';
for (int i = ring->tail; i < ring->head; i++) {
if (*(ring->buf + i) == 0) {
ring->tail = (uint16_t)i + 1;
break;
}
}
if (ring->tail == tail) {
// no \0 found
return 0;
}
} else {
int continu = 1;
int tail = 0;
strncpy(str, (char *)(ring->buf + ring->tail),(size_t)min(ring->size - ring->tail, ring->max_read_len));
str[ring->max_read_len] = '\0';
len = (int)strlen(str);
for (int i = ring->tail; i < ring->size; i++) {
if (*(ring->buf + i) == 0) {
tail = i + 1;
continu = 0;
break;
}
}
if (continu) {
strncpy(str + ring->size - ring->tail, (char *)ring->buf, (size_t)(ring->max_read_len - ring->size + ring->tail));
str[ring->max_read_len] = '\0';
continu = 1;
for (int i = 0; i < ring->head; i++) {
if (*(ring->buf + i) == 0) {
tail = i + 1;
continu = 0;
break;
}
}
if (continu)
return -EINVAL;
}
ring->tail = (uint16_t)tail;
}
len = (int)strlen(str);
ring->tail = ring->tail % ring->size;
#if RING_STATISTICS_ENABLED
ring->statistics.reads += (uint32_t)len + 1;
#endif
return len;
}
int ringbuf_write(struct ringbuf *ring, char *str) {
size_t len = 0;
len = (size_t)strlen(str);
if (len > 0)
return ringbuf_push(ring, (uint8_t *)str, len + 1);
else
return -EINVAL;
}
#if RING_STATISTICS_ENABLED
int ringbuf_statistics(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
puts("Ring Buffer Statistics:");
printf(" Bytes written: %ld\n", ring->statistics.writes);
printf(" Bytes read: %ld\n", ring->statistics.reads);
printf("# of overflows: %ld\n", ring->statistics.overflows);
return 0;
}
int ringbuf_stat_writes(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
return (int)ring->statistics.writes;
}
int ringbuf_stat_reads(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
return (int)ring->statistics.reads;
}
int ringbuf_stat_overflow(struct ringbuf *ring) {
if (ring == NULL)
return -EINVAL;
return (int)ring->statistics.overflows;
}
#endif
int ringbuf_callback_register(struct ringbuf *ring, ringbuf_rcv_cb_t cb_func, void *cb_data) {
if (ring == NULL)
return -EINVAL;
ring->rcv_callback = cb_func;
ring->rcv_cb_data = cb_data;
return 0;
}

144
Core/Src/ringbuf_test.c Normal file
View File

@ -0,0 +1,144 @@
/*
* ringbuf_test.c
*
* Created on: Jul 14, 2022
* Author: tom
*/
#include <assert.h>
#include <stdio.h>
#include "ringbuf.h"
#include <malloc.h>
void ringbuf_test(void) {
size_t usable_size = 0;
fprintf(stderr, "\n");
malloc_stats();
assert(1);
// assert(0); // ... assertion "0" failed: ...blabla bla
//1. Test Initialization
hring rb1 = ringbuf_create(512, RINGBUF_PARAM_NONE);
usable_size = malloc_usable_size(rb1);
fprintf(stdout, "Malloc Usable Size: %d\n", usable_size);
hring rb2 = ringbuf_create(512, RINGBUF_ALLOWOVERWRITE);
assert(rb1 != NULL);
assert(rb2 != NULL);
hring rb3 = ringbuf_create(512, RINGBUF_ALLOWOVERWRITE);
hring rb4 = ringbuf_create(512, RINGBUF_ALLOWOVERWRITE);
printf("Malloc Usable Size of rb1: %d\n", malloc_usable_size(rb1));
printf("Malloc Usable Size of rb2: %d\n", malloc_usable_size(rb2));
printf("Malloc Usable Size of rb3: %d\n", malloc_usable_size(rb3));
printf("Malloc Usable Size of rb4: %d\n", malloc_usable_size(rb4));
ringbuf_destroy(rb4);
malloc_stats();
ringbuf_destroy(rb3);
malloc_stats();
malloc_stats();
ringbuf_destroy(rb2);
malloc_stats();
ringbuf_destroy(rb1);
malloc_stats();
printf("rb1 after destroy is: 0x%08X\n", rb1);
}
#if 0
volatile int ret = 0;
ring = ringbuf_create(64,RINGBUF_ALLOWOVERWRITE);
if (ring == NULL)
printf("we have some problems ...\n");
uint8_t data[1024];
char str[1024]={0};
strcpy(str, "KW4NZ");
ret = ringbuf_dump(ring);
ret = ringbuf_write(ring, str);
printf("Writing string: %s\n", str);
ret = ringbuf_dump(ring);
ret = ringbuf_push(ring, (uint8_t *)"Ich gehe spazieren.", sizeof("Ich gehe spazieren."));
ret = ringbuf_dump(ring);
ret = ringbuf_push(ring, (uint8_t *)"NOCHMALS GEHE ICH RAUS.", sizeof("NOCHMALS GEHE ICH RAUS."));
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("STRING: %s\n", str);
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("STRING: %s\n", str);
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("STRING: %s\n", str);
ret = ringbuf_dump(ring);
strcpy(str, "OE3TKT,OE1TKT,OE7TKT");
ret = ringbuf_write(ring, str);
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("STRING: %s\n", str);
ret = ringbuf_dump(ring);
strcpy(str, "OE1TKT,OE3TKT,OE7TKT");
ret = ringbuf_write(ring, str);
strcpy(str, "KW4NZ");
ret = ringbuf_write(ring, str);
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("STRING: %s (OE1TKT,OE3TKT,OE7TKT)\n", str);
ret = ringbuf_read(ring, str);
printf("STRING: %s (KW4NZ)\n", str);
ret = ringbuf_pull(ring, data, 1024);
printf("Read %d bytes...\n", ret);
for (int i = 0; i < ret; i++)
putchar(data[i]);
puts("");
ringbuf_dump(ring);
ret = ringbuf_push(ring, (uint8_t *)"Eine 128-tägige Reise ist zu gewinnen!", sizeof("Eine 128-tägige Reise ist zu gewinnen!"));
ringbuf_dump(ring);
// ret = ringbuf_push(ring, (uint8_t *)"Eine 100-tägige Reise ist zu gewinnen!", sizeof("Eine 128-tägige Reise ist zu gewinnen!"));
// ret = ringbuf_push(ring, (uint8_t *)"Eine 90-tägige Reise ist zu gewinnen!", sizeof("Eine 90-tägige Reise ist zu gewinnen!"));
ret = ringbuf_push(ring, (uint8_t *)"ENDENDENDENDEND", sizeof("ENDENDENDENDEND"));
ringbuf_dump(ring);
ret = ringbuf_push(ring, (uint8_t *)"Vereinbarungen treffen zu.", sizeof("Vereinbarungen treffen zu."));
ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("String: %s (length: %d)\n", str, ret);
ret = ringbuf_dump(ring);
ret = ringbuf_read(ring, str);
printf("String: %s (length: %d)\n", str, ret);
ret = ringbuf_read(ring, str);
printf("String: %s (length: %d)\n", str, ret);
ret = ringbuf_pull(ring, data, 1024);
printf("Read %d bytes...\n", ret);
for (int i = 0; i < ret; i++)
putchar(data[i]);
puts("");
ringbuf_dump(ring);
ringbuf_clear(ring);
ringbuf_dump(ring);
#if RING_STATISTICS_ENABLED
ringbuf_statistics(ring);
#endif
#endif