2016-11-17 08:36:10 +00:00
|
|
|
/*
|
|
|
|
Test for multicore FreeRTOS ringbuffer.
|
|
|
|
*/
|
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
#include <string.h>
|
2016-11-17 08:36:10 +00:00
|
|
|
#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"
|
2017-10-18 13:09:53 +00:00
|
|
|
#include "esp_intr_alloc.h"
|
2016-11-17 08:36:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
static RingbufHandle_t rb;
|
|
|
|
typedef enum {
|
|
|
|
TST_MOSTLYFILLED,
|
|
|
|
TST_MOSTLYEMPTY,
|
|
|
|
TST_INTTOTASK,
|
|
|
|
TST_TASKTOINT,
|
|
|
|
} testtype_t;
|
|
|
|
|
|
|
|
static volatile testtype_t testtype;
|
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
intr_handle_t s_intr_handle;
|
|
|
|
|
2016-11-17 08:36:10 +00:00
|
|
|
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) {
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(300 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
//Send NULL event to stop other side.
|
|
|
|
r = xRingbufferSend(rb, NULL, 0, 10000 / portTICK_PERIOD_MS);
|
|
|
|
}
|
|
|
|
while (oldtest == testtype) {
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(300 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(300 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (oldtest == testtype) {
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(300 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2017-10-18 13:09:53 +00:00
|
|
|
WRITE_PERI_REG(UART_CONF1_REG(0), 1 << UART_RXFIFO_FULL_THRHD_S);
|
2016-11-17 08:36:10 +00:00
|
|
|
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);
|
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
ESP_ERROR_CHECK(esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, &uartIsrHdl, NULL, &s_intr_handle));
|
|
|
|
}
|
2016-11-17 08:36:10 +00:00
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
static void uartRxDeinit()
|
|
|
|
{
|
|
|
|
esp_intr_free(s_intr_handle);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
|
2017-11-17 11:53:43 +00:00
|
|
|
static void testRingbuffer(int type, bool arbitrary)
|
2016-11-17 08:36:10 +00:00
|
|
|
{
|
|
|
|
TaskHandle_t th[2];
|
|
|
|
int i;
|
2017-11-17 11:53:43 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
2016-11-17 08:36:10 +00:00
|
|
|
|
|
|
|
testtype = TST_MOSTLYFILLED;
|
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
xTaskCreatePinnedToCore(task1, "tskone", 2048, NULL, 3, &th[0], 0);
|
|
|
|
xTaskCreatePinnedToCore(task2, "tsktwo", 2048, NULL, 3, &th[1], 0);
|
2016-11-17 08:36:10 +00:00
|
|
|
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");
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
printf("Test: mostlyempty; putting 10 items in ringbuff @ 1/sec, reading as fast as possible\n");
|
|
|
|
testtype = TST_MOSTLYEMPTY;
|
2017-10-18 13:09:53 +00:00
|
|
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
2016-11-17 08:36:10 +00:00
|
|
|
|
|
|
|
//Shut down all the tasks
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
vTaskDelete(th[i]);
|
|
|
|
}
|
2017-10-18 13:09:53 +00:00
|
|
|
vRingbufferDelete(rb);
|
|
|
|
uartRxDeinit();
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: split this thing into separate orthogonal tests
|
2017-10-18 13:09:53 +00:00
|
|
|
TEST_CASE("FreeRTOS ringbuffer test, no splitting items", "[freertos]")
|
2016-11-17 08:36:10 +00:00
|
|
|
{
|
2017-11-17 11:53:43 +00:00
|
|
|
testRingbuffer(0, false);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
|
2017-10-18 13:09:53 +00:00
|
|
|
TEST_CASE("FreeRTOS ringbuffer test, w/ splitting items", "[freertos]")
|
2016-11-17 08:36:10 +00:00
|
|
|
{
|
2017-11-17 11:53:43 +00:00
|
|
|
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);
|
2016-11-17 08:36:10 +00:00
|
|
|
}
|
|
|
|
|
2017-08-28 11:31:26 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|