blob: d1f86e2056c66a592f3f3c4e26a1ffa552464168 [file] [log] [blame]
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @file
* @brief Test nanokernel FIFO APIs
*
* This module tests four basic scenarios with the usage of the following FIFO
* routines:
*
* nano_fiber_fifo_get, nano_fiber_fifo_put
* nano_task_fifo_get, nano_task_fifo_put
* nano_isr_fifo_get, nano_isr_fifo_put
*
* Scenario #1
* Task enters items into a queue, starts the fiber and waits for a semaphore.
* Fiber extracts all items from the queue and enters some items back into
* the queue. Fiber gives the semaphore for task to continue. Once the control
* is returned back to task, task extracts all items from the queue.
* Scenario #2
* Task enters an item into queue2, starts a fiber and extract an item from
* queue1 once the item is there. The fiber will extract an item from queue2
* once the item is there and and enter an item to queue1. The flow of control
* goes from task to fiber and so forth.
* Scenario #3
* Tests the ISR interfaces. Function testIsrFifoFromFiber gets an item from
* the fifo queue in ISR context. It then enters four items into the queue
* and finishes execution. Control is returned back to function
* testTaskFifoGetW which also finished it's execution and returned to main.
* Finally function testIsrFifoFromTask is run and it gets all data from
* the queue and puts and gets one last item to the queue. All these are run
* in ISR context.
*
* Scenario #4:
* Timeout scenarios with multiple FIFOs and fibers.
*/
#include <zephyr.h>
#include <tc_util.h>
#include <misc/__assert.h>
#include <misc/util.h>
#include <irq_offload.h>
#include <util_test_common.h>
#define FIBER_STACKSIZE 256
#define NUM_FIFO_ELEMENT 4
#define INVALID_DATA NULL
#define TCERR1(count) TC_ERROR("Didn't get back correct FIFO, count %d\n", count)
#define TCERR2 TC_ERROR("Didn't get back correct FIFO\n")
#define TCERR3 TC_ERROR("The queue should be empty!\n")
struct isr_fifo_info {
struct nano_fifo *fifo_ptr; /* FIFO */
void *data; /* pointer to data to add */
};
char __stack fiberStack1[FIBER_STACKSIZE];
char __stack fiberStack2[FIBER_STACKSIZE];
char __stack fiberStack3[FIBER_STACKSIZE];
struct nano_fifo nanoFifoObj;
struct nano_fifo nanoFifoObj2;
struct nano_sem nanoSemObj1; /* Used to block/wake-up fiber1 */
struct nano_sem nanoSemObj2; /* Used to block/wake-up fiber2 */
struct nano_sem nanoSemObj3; /* Used to block/wake-up fiber3 */
struct nano_sem nanoSemObjTask; /* Used to block/wake-up task */
struct nano_timer timer;
void *timerData[1];
int myFifoData1[4];
int myFifoData2[2];
int myFifoData3[4];
int myFifoData4[2];
void * const pMyFifoData1 = (void *)myFifoData1;
void * const pMyFifoData2 = (void *)myFifoData2;
void * const pMyFifoData3 = (void *)myFifoData3;
void * const pMyFifoData4 = (void *)myFifoData4;
void * const pPutList1[NUM_FIFO_ELEMENT] = {
(void *)myFifoData1,
(void *)myFifoData2,
(void *)myFifoData3,
(void *)myFifoData4
};
void * const pPutList2[NUM_FIFO_ELEMENT] = {
(void *)myFifoData4,
(void *)myFifoData3,
(void *)myFifoData2,
(void *)myFifoData1
};
int retCode = TC_PASS;
static struct isr_fifo_info isrFifoInfo = {&nanoFifoObj, NULL};
void fiber1(void);
void fiber2(void);
void fiber3(void);
void initNanoObjects(void);
void testTaskFifoGetW(void);
extern int test_fifo_timeout(void);
/**
*
* @brief Add an item to a FIFO
*
* This routine is the ISR handler for _trigger_nano_isr_fifo_put(). It adds
* an item to the FIFO in the context of an ISR.
*
* @param parameter pointer to ISR handler parameter
*
* @return N/A
*/
void isr_fifo_put(void *parameter)
{
struct isr_fifo_info *pInfo = (struct isr_fifo_info *) parameter;
nano_isr_fifo_put(pInfo->fifo_ptr, pInfo->data);
}
static void _trigger_nano_isr_fifo_put(void)
{
irq_offload(isr_fifo_put, &isrFifoInfo);
}
/**
*
* @brief Get an item from a FIFO
*
* This routine is the ISR handler for _trigger_nano_isr_fifo_get(). It gets
* an item from the FIFO in the context of an ISR.
*
* @param parameter pointer to ISR handler parameter
*
* @return N/A
*/
void isr_fifo_get(void *parameter)
{
struct isr_fifo_info *pInfo = (struct isr_fifo_info *) parameter;
pInfo->data = nano_isr_fifo_get(pInfo->fifo_ptr, TICKS_NONE);
}
static void _trigger_nano_isr_fifo_get(void)
{
irq_offload(isr_fifo_get, &isrFifoInfo);
}
/**
*
* @brief Entry point for the first fiber
*
* @return N/A
*/
void fiber1(void)
{
void *pData; /* pointer to FIFO object get from the queue */
int count = 0; /* counter */
/* Wait for fiber1 to be activated. */
nano_fiber_sem_take(&nanoSemObj1, TICKS_UNLIMITED);
/* Wait for data to be added to <nanoFifoObj> by task */
pData = nano_fiber_fifo_get(&nanoFifoObj, TICKS_UNLIMITED);
if (pData != pPutList1[0]) {
TC_ERROR("fiber1 (1) - expected 0x%x, got 0x%x\n",
pPutList1[0], pData);
retCode = TC_FAIL;
return;
}
/* Wait for data to be added to <nanoFifoObj2> by fiber3 */
pData = nano_fiber_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
if (pData != pPutList2[0]) {
TC_ERROR("fiber1 (2) - expected 0x%x, got 0x%x\n",
pPutList2[0], pData);
retCode = TC_FAIL;
return;
}
/* Wait for fiber1 to be reactivated */
nano_fiber_sem_take(&nanoSemObj1, TICKS_UNLIMITED);
TC_PRINT("Test Fiber FIFO Get\n\n");
/* Get all FIFOs */
while ((pData = nano_fiber_fifo_get(&nanoFifoObj, TICKS_NONE)) != NULL) {
TC_PRINT("FIBER FIFO Get: count = %d, ptr is %p\n", count, pData);
if ((count >= NUM_FIFO_ELEMENT) || (pData != pPutList1[count])) {
TCERR1(count);
retCode = TC_FAIL;
return;
}
count++;
}
TC_END_RESULT(retCode);
PRINT_LINE;
/*
* Entries in the FIFO queue have to be unique.
* Put data.
*/
TC_PRINT("Test Fiber FIFO Put\n");
TC_PRINT("\nFIBER FIFO Put Order: ");
for (int i = 0; i < NUM_FIFO_ELEMENT; i++) {
nano_fiber_fifo_put(&nanoFifoObj, pPutList2[i]);
TC_PRINT(" %p,", pPutList2[i]);
}
TC_PRINT("\n");
PRINT_LINE;
/* Give semaphore to allow the main task to run */
nano_fiber_sem_give(&nanoSemObjTask);
} /* fiber1 */
/**
*
* @brief Test the nano_fiber_fifo_get(TICKS_UNLIMITED) interface
*
* This function tests the fifo put and get wait interfaces in a fiber.
* It gets data from nanoFifoObj2 queue and puts data to nanoFifoObj queue.
*
* @return N/A
*/
void testFiberFifoGetW(void)
{
void *pGetData; /* pointer to FIFO object get from the queue */
void *pPutData; /* pointer to FIFO object to put to the queue */
TC_PRINT("Test Fiber FIFO Get Wait Interfaces\n\n");
pGetData = nano_fiber_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
TC_PRINT("FIBER FIFO Get from queue2: %p\n", pGetData);
/* Verify results */
if (pGetData != pMyFifoData1) {
retCode = TC_FAIL;
TCERR2;
return;
}
pPutData = pMyFifoData2;
TC_PRINT("FIBER FIFO Put to queue1: %p\n", pPutData);
nano_fiber_fifo_put(&nanoFifoObj, pPutData);
pGetData = nano_fiber_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
TC_PRINT("FIBER FIFO Get from queue2: %p\n", pGetData);
/* Verify results */
if (pGetData != pMyFifoData3) {
retCode = TC_FAIL;
TCERR2;
return;
}
pPutData = pMyFifoData4;
TC_PRINT("FIBER FIFO Put to queue1: %p\n", pPutData);
nano_fiber_fifo_put(&nanoFifoObj, pPutData);
TC_END_RESULT(retCode);
} /* testFiberFifoGetW */
/**
*
* @brief Test ISR FIFO routines (triggered from fiber)
*
* This function tests the fifo put and get interfaces in the ISR context.
* It is invoked from a fiber.
*
* We use nanoFifoObj queue to put and get data.
*
* @return N/A
*/
void testIsrFifoFromFiber(void)
{
void *pGetData; /* pointer to FIFO object get from the queue */
TC_PRINT("Test ISR FIFO (invoked from Fiber)\n\n");
/* This is data pushed by function testFiberFifoGetW */
_trigger_nano_isr_fifo_get();
pGetData = isrFifoInfo.data;
TC_PRINT("ISR FIFO Get from queue1: %p\n", pGetData);
if (isrFifoInfo.data != pMyFifoData4) {
retCode = TC_FAIL;
TCERR2;
return;
}
/* Verify that the queue is empty */
_trigger_nano_isr_fifo_get();
pGetData = isrFifoInfo.data;
if (pGetData != NULL) {
TC_PRINT("Get from queue1: %p\n", pGetData);
retCode = TC_FAIL;
TCERR3;
return;
}
/* Put more item into queue */
TC_PRINT("\nISR FIFO (running in fiber) Put Order:\n");
for (int i = 0; i < NUM_FIFO_ELEMENT; i++) {
isrFifoInfo.data = pPutList1[i];
TC_PRINT(" %p,", pPutList1[i]);
_trigger_nano_isr_fifo_put();
}
TC_PRINT("\n");
TC_END_RESULT(retCode);
} /* testIsrFifoFromFiber */
/**
*
* @brief Test ISR FIFO routines (triggered from task)
*
* This function tests the fifo put and get interfaces in the ISR context.
* It is invoked from a task.
*
* We use nanoFifoObj queue to put and get data.
*
* @return N/A
*/
void testIsrFifoFromTask(void)
{
void *pGetData; /* pointer to FIFO object get from the queue */
void *pPutData; /* pointer to FIFO object put to queue */
int count = 0; /* counter */
TC_PRINT("Test ISR FIFO (invoked from Task)\n\n");
/* This is data pushed by function testIsrFifoFromFiber
* Get all FIFOs
*/
_trigger_nano_isr_fifo_get();
pGetData = isrFifoInfo.data;
while (pGetData != NULL) {
TC_PRINT("Get from queue1: count = %d, ptr is %p\n", count, pGetData);
if ((count >= NUM_FIFO_ELEMENT) || (pGetData != pPutList1[count])) {
TCERR1(count);
retCode = TC_FAIL;
return;
}
/* Get the next element */
_trigger_nano_isr_fifo_get();
pGetData = isrFifoInfo.data;
count++;
} /* while */
/* Put data into queue and get it again */
pPutData = pPutList2[3];
isrFifoInfo.data = pPutData;
_trigger_nano_isr_fifo_put();
isrFifoInfo.data = NULL; /* force data to a new value */
/* Get data from queue */
_trigger_nano_isr_fifo_get();
pGetData = isrFifoInfo.data;
/* Verify data */
if (pGetData != pPutData) {
retCode = TC_FAIL;
TCERR2;
return;
}
TC_PRINT("\nTest ISR FIFO (invoked from Task) - put %p and get back %p\n",
pPutData, pGetData);
TC_END_RESULT(retCode);
} /* testIsrFifoFromTask */
/**
*
* @brief Entry point for the second fiber
*
* @return N/A
*/
void fiber2(void)
{
void *pData; /* pointer to FIFO object from the queue */
/* Wait for fiber2 to be activated */
nano_fiber_sem_take(&nanoSemObj2, TICKS_UNLIMITED);
/* Wait for data to be added to <nanoFifoObj> */
pData = nano_fiber_fifo_get(&nanoFifoObj, TICKS_UNLIMITED);
if (pData != pPutList1[1]) {
TC_ERROR("fiber2 (1) - expected 0x%x, got 0x%x\n",
pPutList1[1], pData);
retCode = TC_FAIL;
return;
}
/* Wait for data to be added to <nanoFifoObj2> by fiber3 */
pData = nano_fiber_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
if (pData != pPutList2[1]) {
TC_ERROR("fiber2 (2) - expected 0x%x, got 0x%x\n",
pPutList2[1], pData);
retCode = TC_FAIL;
return;
}
/* Wait for fiber2 to be reactivated */
nano_fiber_sem_take(&nanoSemObj2, TICKS_UNLIMITED);
/* Fiber #2 has been reactivated by main task */
for (int i = 0; i < 4; i++) {
pData = nano_fiber_fifo_get(&nanoFifoObj, TICKS_UNLIMITED);
if (pData != pPutList1[i]) {
TC_ERROR("fiber2 (3) - iteration %d expected 0x%x, got 0x%x\n",
i, pPutList1[i], pData);
retCode = TC_FAIL;
return;
}
}
nano_fiber_sem_give(&nanoSemObjTask); /* Wake main task */
/* Wait for fiber2 to be reactivated */
nano_fiber_sem_take(&nanoSemObj2, TICKS_UNLIMITED);
testFiberFifoGetW();
PRINT_LINE;
testIsrFifoFromFiber();
TC_END_RESULT(retCode);
} /* fiber2 */
/**
*
* @brief Entry point for the third fiber
*
* @return N/A
*/
void fiber3(void)
{
void *pData;
/* Wait for fiber3 to be activated */
nano_fiber_sem_take(&nanoSemObj3, TICKS_UNLIMITED);
/* Put two items onto <nanoFifoObj2> to unblock fibers #1 and #2. */
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[0]); /* Wake fiber1 */
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[1]); /* Wake fiber2 */
/* Wait for fiber3 to be re-activated */
nano_fiber_sem_take(&nanoSemObj3, TICKS_UNLIMITED);
/* Immediately get the data from <nanoFifoObj2>. */
pData = nano_fiber_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
if (pData != pPutList2[0]) {
retCode = TC_FAIL;
TC_ERROR("fiber3 (1) - got 0x%x from <nanoFifoObj2>, expected 0x%x\n",
pData, pPutList2[0]);
}
/* Put three items onto the FIFO for the task to get */
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[0]);
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[1]);
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[2]);
/* Sleep for 2 seconds */
nano_fiber_timer_start(&timer, SECONDS(2));
nano_fiber_timer_test(&timer, TICKS_UNLIMITED);
/* Put final item onto the FIFO for the task to get */
nano_fiber_fifo_put(&nanoFifoObj2, pPutList2[3]);
/* Wait for fiber3 to be re-activated (not expected to occur) */
nano_fiber_sem_take(&nanoSemObj3, TICKS_UNLIMITED);
}
/**
*
* @brief Test the nano_task_fifo_get(TICKS_UNLIMITED) interface
*
* This is in a task. It puts data to nanoFifoObj2 queue and gets
* data from nanoFifoObj queue.
*
* @return N/A
*/
void testTaskFifoGetW(void)
{
void *pGetData; /* pointer to FIFO object get from the queue */
void *pPutData; /* pointer to FIFO object to put to the queue */
PRINT_LINE;
TC_PRINT("Test Task FIFO Get Wait Interfaces\n\n");
pPutData = pMyFifoData1;
TC_PRINT("TASK FIFO Put to queue2: %p\n", pPutData);
nano_task_fifo_put(&nanoFifoObj2, pPutData);
/* Activate fiber2 */
nano_task_sem_give(&nanoSemObj2);
pGetData = nano_task_fifo_get(&nanoFifoObj, TICKS_UNLIMITED);
TC_PRINT("TASK FIFO Get from queue1: %p\n", pGetData);
/* Verify results */
if (pGetData != pMyFifoData2) {
retCode = TC_FAIL;
TCERR2;
return;
}
pPutData = pMyFifoData3;
TC_PRINT("TASK FIFO Put to queue2: %p\n", pPutData);
nano_task_fifo_put(&nanoFifoObj2, pPutData);
TC_END_RESULT(retCode);
} /* testTaskFifoGetW */
/**
*
* @brief Initialize nanokernel objects
*
* This routine initializes the nanokernel objects used in the FIFO tests.
*
* @return N/A
*/
void initNanoObjects(void)
{
nano_fifo_init(&nanoFifoObj);
nano_fifo_init(&nanoFifoObj2);
nano_sem_init(&nanoSemObj1);
nano_sem_init(&nanoSemObj2);
nano_sem_init(&nanoSemObj3);
nano_sem_init(&nanoSemObjTask);
nano_timer_init(&timer, timerData);
} /* initNanoObjects */
/**
*
* @brief Entry point to FIFO tests
*
* This is the entry point to the FIFO tests.
*
* @return N/A
*/
void main(void)
{
void *pData; /* pointer to FIFO object get from the queue */
int count = 0; /* counter */
TC_START("Test Nanokernel FIFO");
/* Initialize the FIFO queues and semaphore */
initNanoObjects();
/* Create and start the three (3) fibers. */
task_fiber_start(&fiberStack1[0], FIBER_STACKSIZE, (nano_fiber_entry_t) fiber1,
0, 0, 7, 0);
task_fiber_start(&fiberStack2[0], FIBER_STACKSIZE, (nano_fiber_entry_t) fiber2,
0, 0, 7, 0);
task_fiber_start(&fiberStack3[0], FIBER_STACKSIZE, (nano_fiber_entry_t) fiber3,
0, 0, 7, 0);
/*
* The three fibers have each blocked on a different semaphore. Giving
* the semaphore nanoSemObjX will unblock fiberX (where X = {1, 2, 3}).
*
* Activate fibers #1 and #2. They will each block on nanoFifoObj.
*/
nano_task_sem_give(&nanoSemObj1);
nano_task_sem_give(&nanoSemObj2);
/* Put two items into <nanoFifoObj> to unblock fibers #1 and #2. */
nano_task_fifo_put(&nanoFifoObj, pPutList1[0]); /* Wake fiber1 */
nano_task_fifo_put(&nanoFifoObj, pPutList1[1]); /* Wake fiber2 */
/* Activate fiber #3 */
nano_task_sem_give(&nanoSemObj3);
/*
* All three fibers should be blocked on their semaphores. Put data into
* <nanoFifoObj2>. Fiber #3 will read it after it is reactivated.
*/
nano_task_fifo_put(&nanoFifoObj2, pPutList2[0]);
nano_task_sem_give(&nanoSemObj3); /* Reactivate fiber #3 */
for (int i = 0; i < 4; i++) {
pData = nano_task_fifo_get(&nanoFifoObj2, TICKS_UNLIMITED);
if (pData != pPutList2[i]) {
TC_ERROR("nano_task_fifo_get() expected 0x%x, got 0x%x\n",
pPutList2[i], pData);
goto exit;
}
}
/* Add items to <nanoFifoObj> for fiber #2 */
for (int i = 0; i < 4; i++) {
nano_task_fifo_put(&nanoFifoObj, pPutList1[i]);
}
nano_task_sem_give(&nanoSemObj2); /* Activate fiber #2 */
/* Wait for fibers to finish */
nano_task_sem_take(&nanoSemObjTask, TICKS_UNLIMITED);
if (retCode == TC_FAIL) {
goto exit;
}
/*
* Entries in the FIFO queue have to be unique.
* Put data to queue.
*/
TC_PRINT("Test Task FIFO Put\n");
TC_PRINT("\nTASK FIFO Put Order: ");
for (int i = 0; i < NUM_FIFO_ELEMENT; i++) {
nano_task_fifo_put(&nanoFifoObj, pPutList1[i]);
TC_PRINT(" %p,", pPutList1[i]);
}
TC_PRINT("\n");
PRINT_LINE;
nano_task_sem_give(&nanoSemObj1); /* Activate fiber1 */
if (retCode == TC_FAIL) {
goto exit;
}
/*
* Wait for fiber1 to complete execution. (Using a semaphore gives
* the fiber the freedom to do blocking-type operations if it wants to.)
*/
nano_task_sem_take(&nanoSemObjTask, TICKS_UNLIMITED);
TC_PRINT("Test Task FIFO Get\n");
/* Get all FIFOs */
while ((pData = nano_task_fifo_get(&nanoFifoObj, TICKS_NONE)) != NULL) {
TC_PRINT("TASK FIFO Get: count = %d, ptr is %p\n", count, pData);
if ((count >= NUM_FIFO_ELEMENT) || (pData != pPutList2[count])) {
TCERR1(count);
retCode = TC_FAIL;
goto exit;
}
count++;
}
/* Test FIFO Get Wait interfaces*/
testTaskFifoGetW();
PRINT_LINE;
testIsrFifoFromTask();
PRINT_LINE;
/* test timeouts */
if (test_fifo_timeout() != TC_PASS) {
retCode = TC_FAIL;
goto exit;
}
PRINT_LINE;
exit:
TC_END_RESULT(retCode);
TC_END_REPORT(retCode);
}