OVMS3-idf/components/freertos/test/test_ringbuf.c
Piyush Shah 4f33339c1d test_ringbuf: Add tests for arbitrary length ring buffer
This will test the ring buffer for buffer length that is not
a multiple of 4

Signed-off-by: Piyush Shah <piyush@espressif.com>
2017-11-21 17:18:54 +05:30

227 lines
6.6 KiB
C

/*
Test for multicore FreeRTOS ringbuffer.
*/
#include <string.h>
#include <stdio.h>
#include "rom/ets_sys.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include "freertos/xtensa_api.h"
#include "unity.h"
#include "soc/uart_reg.h"
#include "soc/dport_reg.h"
#include "soc/io_mux_reg.h"
#include "esp_intr_alloc.h"
static RingbufHandle_t rb;
typedef enum {
TST_MOSTLYFILLED,
TST_MOSTLYEMPTY,
TST_INTTOTASK,
TST_TASKTOINT,
} testtype_t;
static volatile testtype_t testtype;
intr_handle_t s_intr_handle;
static void task1(void *arg)
{
testtype_t oldtest;
char buf[100];
int i = 0;
int x, r;
while (1) {
oldtest = testtype;
if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
for (x = 0; x < 10; x++) {
sprintf(buf, "This is test %d item %d.", (int)testtype, i++);
ets_printf("TSK w");
xRingbufferPrintInfo(rb);
r = xRingbufferSend(rb, buf, strlen(buf) + 1, 2000 / portTICK_PERIOD_MS);
if (!r) {
printf("Test %d: Timeout on send!\n", (int)testtype);
}
if (testtype == TST_MOSTLYEMPTY) {
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
//Send NULL event to stop other side.
r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
}
while (oldtest == testtype) {
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
}
static void task2(void *arg)
{
testtype_t oldtest;
char *buf;
size_t len;
while (1) {
oldtest = testtype;
if (testtype == TST_MOSTLYFILLED || testtype == TST_MOSTLYEMPTY) {
while (1) {
ets_printf("TSK r");
xRingbufferPrintInfo(rb);
buf = xRingbufferReceive(rb, &len, 2000 / portTICK_PERIOD_MS);
if (buf == NULL) {
printf("Test %d: Timeout on recv!\n", (int)testtype);
} else if (len == 0) {
printf("End packet received.\n");
vRingbufferReturnItem(rb, buf);
break;
} else {
printf("Received: %s (%d bytes, %p)\n", buf, len, buf);
vRingbufferReturnItem(rb, buf);
}
if (testtype == TST_MOSTLYFILLED) {
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
}
while (oldtest == testtype) {
vTaskDelay(300 / portTICK_PERIOD_MS);
}
}
}
static void uartIsrHdl(void *arg)
{
char c;
char buf[50];
char *item;
int r;
size_t len;
BaseType_t xHigherPriorityTaskWoken;
SET_PERI_REG_MASK(UART_INT_CLR_REG(0), UART_RXFIFO_FULL_INT_CLR);
while (READ_PERI_REG(UART_STATUS_REG(0)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) {
c = READ_PERI_REG(UART_FIFO_REG(0));
if (c == 'r') {
ets_printf("ISR r");
xRingbufferPrintInfo(rb);
item = xRingbufferReceiveFromISR(rb, &len);
if (item == NULL) {
ets_printf("ISR recv fail!\n");
} else if (len == 0) {
ets_printf("ISR recv NULL!\n");
vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
} else {
ets_printf("ISR recv '%s' (%d bytes, %p)\n", buf, len, buf);
vRingbufferReturnItemFromISR(rb, item, &xHigherPriorityTaskWoken);
}
} else {
sprintf(buf, "UART: %c", c);
ets_printf("ISR w");
xRingbufferPrintInfo(rb);
r = xRingbufferSendFromISR(rb, buf, strlen(buf) + 1, &xHigherPriorityTaskWoken);
if (!r) {
ets_printf("ISR send fail\n");
}
}
}
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
static void uartRxInit()
{
WRITE_PERI_REG(UART_CONF1_REG(0), 1 << UART_RXFIFO_FULL_THRHD_S);
CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_TXFIFO_EMPTY_INT_ENA | UART_RXFIFO_TOUT_INT_ENA);
SET_PERI_REG_MASK(UART_INT_ENA_REG(0), UART_RXFIFO_FULL_INT_ENA);
ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, &uartIsrHdl, NULL, &s_intr_handle));
}
static void uartRxDeinit()
{
esp_intr_free(s_intr_handle);
}
static void testRingbuffer(int type, bool arbitrary)
{
TaskHandle_t th[2];
int i;
/* Arbitrary Length means buffer length which is not a multiple of 4 */
if (arbitrary) {
rb = xRingbufferCreate(31 * 3, type);
} else {
rb = xRingbufferCreate(32 * 3, type);
}
testtype = TST_MOSTLYFILLED;
xTaskCreatePinnedToCore(task1, "tskone", 2048, NULL, 3, &th[0], 0);
xTaskCreatePinnedToCore(task2, "tsktwo", 2048, NULL, 3, &th[1], 0);
uartRxInit();
printf("Press 'r' to read an event in isr, any other key to write one.\n");
printf("Test: mostlyfilled; putting 10 items in ringbuff ASAP, reading 1 a second\n");
vTaskDelay(5000 / portTICK_PERIOD_MS);
printf("Test: mostlyempty; putting 10 items in ringbuff @ 1/sec, reading as fast as possible\n");
testtype = TST_MOSTLYEMPTY;
vTaskDelay(5000 / portTICK_PERIOD_MS);
//Shut down all the tasks
for (i = 0; i < 2; i++) {
vTaskDelete(th[i]);
}
vRingbufferDelete(rb);
uartRxDeinit();
}
// TODO: split this thing into separate orthogonal tests
TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]")
{
testRingbuffer(0, false);
}
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]")
{
testRingbuffer(1, false);
}
TEST_CASE("FreeRTOS ringbuffer test, no splitting items, arbitrary length buffer", "[freertos]")
{
testRingbuffer(0, true);
}
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items, arbitrary length buffer", "[freertos]")
{
testRingbuffer(1, true);
}
TEST_CASE("FreeRTOS ringbuffer test, check if zero-length items are handled correctly", "[freertos]")
{
rb = xRingbufferCreate(32, 0);
int r;
void *v;
size_t sz;
for (int x=0; x<128; x++) {
if (x!=127) {
//Send an item
r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
assert(r==pdTRUE);
}
if (x!=0) {
//Receive an item
v=xRingbufferReceive(rb, &sz, 10000 / portTICK_PERIOD_MS);
assert(sz==0);
vRingbufferReturnItem(rb, v); //actually not needed for NULL data...
}
}
vRingbufferDelete(rb);
}