blob: 7c3c6a3d939b7b940bf99ee1faee5102b58ef8c0 [file] [log] [blame]
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* @file
* @brief Test nanokernel stack APIs
*
* This module tests three basic scenarios with the usage of the following
* STACK routines:
*
* nano_fiber_stack_pop, nano_fiber_stack_push
* nano_task_stack_pop, nano_task_stack_push
* nano_isr_stack_pop, nano_isr_stack_push
*
* 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. Fiber2 pops an item from queue1 in ISR context.
* It then enters four items into the queue and finishes execution. Control
* is returned back to function testTaskStackPopW which also finished it's
* execution and returned to main. Finally function testIsrStackFromTask is
* run and it popped all data from queue1, push and pop one last item to the
* queue. All these are run in ISR context.
*/
#include <tc_util.h>
#include <arch/cpu.h>
#include <irq_offload.h>
#include <util_test_common.h>
#define STACKSIZE 2048
#define NUM_STACK_ELEMENT 4
#define STARTNUM 1 /* Used to compute data to put in the stack */
#define MULTIPLIER 100 /* Used to compute data to put in the stack */
#define MYNUMBER 50 /* Used to compute data to put in the stack */
#define INVALID_DATA 0 /* Invalid data on stack */
#define TCERR1(count) TC_ERROR("Didn't get back correct data, count %d\n", count)
#define TCERR2 TC_ERROR("Didn't get back correct data\n")
#define TCERR3 TC_ERROR("The stack should be empty!\n")
typedef struct {
struct nano_stack *stack_ptr; /* STACK */
uint32_t data; /* data to add */
} ISR_STACK_INFO;
char __stack fiberStack1[STACKSIZE];
char __stack fiberStack2[STACKSIZE];
char __stack fiberStack3[STACKSIZE];
struct nano_timer timer;
struct nano_stack nanoStackObj;
struct nano_stack nanoStackObj2;
struct nano_sem nanoSemObj; /* Used for transferring control between
* main and fiber1
*/
uint32_t myData[NUM_STACK_ELEMENT];
uint32_t myIsrData[NUM_STACK_ELEMENT]; /* Data used for testing
* nano_isr_stack_push and
* nanoIsrStatckPop interfaces
*/
uint32_t stack1[NUM_STACK_ELEMENT];
uint32_t stack2[NUM_STACK_ELEMENT];
void *timerData[1];
int retCode = TC_PASS;
static ISR_STACK_INFO isrStackInfo = {&nanoStackObj, 0};
void initData(void);
void fiber1(void);
void fiber2(void);
void initNanoObjects(void);
void testFiberStackPopW(void);
void testTaskStackPopW(void);
/* Isr related functions */
void isr_stack_push(void *parameter);
void isr_stack_pop(void *parameter);
void testIsrStackFromFiber(void);
void testIsrStackFromTask(void);
/**
*
* initData
*
* Initialize myData and myIsrData arrays.
*
* @return none
*/
void initData(void)
{
for (int i=0; i< NUM_STACK_ELEMENT; i++) {
myData[i] = (STARTNUM + i) * MULTIPLIER;
myIsrData[i] = myData[i] + MYNUMBER;
}
} /* initData */
/**
*
* @brief Add an item to a STACK
*
* This routine is the ISR handler for _trigger_nano_isr_stack_push(). It adds
* an item to the STACK in the context of an ISR.
*
* @param parameter pointer to ISR handler parameter
*
* @return N/A
*/
void isr_stack_push(void *parameter)
{
ISR_STACK_INFO *pInfo = (ISR_STACK_INFO *) parameter;
nano_isr_stack_push(pInfo->stack_ptr, pInfo->data);
} /* isr_stack_push */
static void _trigger_nano_isr_stack_push(void)
{
irq_offload(isr_stack_push, &isrStackInfo);
}
/**
*
* @brief Get an item from a STACK
*
* This routine is the ISR handler for _trigger_nano_isr_stack_pop(). It gets
* an item from the STACK in the context of an ISR. If the queue is empty,
* it sets data to INVALID_DATA.
*
* @param parameter pointer to ISR handler parameter
*
* @return N/A
*/
void isr_stack_pop(void *parameter)
{
ISR_STACK_INFO *pInfo = (ISR_STACK_INFO *) parameter;
if (nano_isr_stack_pop(pInfo->stack_ptr, &(pInfo->data), TICKS_NONE) == 0) {
/* the stack is empty, set data to INVALID_DATA */
pInfo->data = INVALID_DATA;
}
} /* isr_stack_pop */
static void _trigger_nano_isr_stack_pop(void)
{
irq_offload(isr_stack_pop, &isrStackInfo);
}
/**
*
* fiber1
*
* This is the fiber started from the main task. Gets all items from
* the STACK queue and puts four items back to the STACK queue. Control is
* transferred back to the main task.
*
* @return N/A
*/
void fiber1(void)
{
uint32_t data; /* data used to put and get from the stack queue */
int count = 0; /* counter */
TC_PRINT("Test Fiber STACK Pop\n\n");
/* Get all data */
while (nano_fiber_stack_pop(&nanoStackObj, &data, TICKS_NONE) != 0) {
TC_PRINT("FIBER STACK Pop: count = %d, data is %d\n", count, data);
if ((count >= NUM_STACK_ELEMENT) || (data != myData[NUM_STACK_ELEMENT - 1 - count])) {
TCERR1(count);
retCode = TC_FAIL;
return;
}
count++;
}
TC_END_RESULT(retCode);
PRINT_LINE;
/* Put data */
TC_PRINT("Test Fiber STACK Push\n");
TC_PRINT("\nFIBER STACK Put Order: ");
for (int i=NUM_STACK_ELEMENT; i>0; i--) {
nano_fiber_stack_push(&nanoStackObj, myData[i-1]);
TC_PRINT(" %d,", myData[i-1]);
}
TC_PRINT("\n");
PRINT_LINE;
/* Give semaphore to allow the main task to run */
nano_fiber_sem_give(&nanoSemObj);
} /* fiber1 */
/**
*
* testFiberStackPopW
*
* This function tests the stack push and pop wait interfaces in a fiber.
* It gets data from nanoStackObj2 queue and puts data to nanoStackObj queue.
*
* @return N/A
*/
void testFiberStackPopW(void)
{
uint32_t data; /* data used to put and get from the stack queue */
int rc;
TC_PRINT("Test Fiber STACK Pop Wait Interfaces\n\n");
rc = nano_fiber_stack_pop(&nanoStackObj2, &data, TICKS_UNLIMITED);
TC_PRINT("FIBER STACK Pop from queue2: %d\n", data);
/* Verify results */
if ((rc == 0) || (data != myData[0])) {
retCode = TC_FAIL;
TCERR2;
return;
}
data = myData[1];
TC_PRINT("FIBER STACK Push to queue1: %d\n", data);
nano_fiber_stack_push(&nanoStackObj, data);
rc = nano_fiber_stack_pop(&nanoStackObj2, &data, TICKS_UNLIMITED);
TC_PRINT("FIBER STACK Pop from queue2: %d\n", data);
/* Verify results */
if ((rc == 0) || (data != myData[2])) {
retCode = TC_FAIL;
TCERR2;
return;
}
data = myData[3];
TC_PRINT("FIBER STACK Push to queue1: %d\n", data);
nano_fiber_stack_push(&nanoStackObj, data);
TC_END_RESULT(retCode);
} /* testFiberStackPopW */
/**
*
* testIsrStackFromFiber
*
* This function tests the stack push and pop interfaces in the ISR context.
* It is invoked from a fiber.
*
* We use nanoStackObj queue to push and pop data.
*
* @return N/A
*/
void testIsrStackFromFiber(void)
{
uint32_t result = INVALID_DATA; /* data used to put and get from the stack queue */
TC_PRINT("Test ISR STACK (invoked from Fiber)\n\n");
/* This is data pushed by function testFiberStackPopW */
_trigger_nano_isr_stack_pop();
result = isrStackInfo.data;
if (result != INVALID_DATA) {
TC_PRINT("ISR STACK (running in fiber) Pop from queue1: %d\n", result);
if (result != myData[3]) {
retCode = TC_FAIL;
TCERR2;
return;
}
}
/* Verify that the STACK is empty */
_trigger_nano_isr_stack_pop();
result = isrStackInfo.data;
if (result != INVALID_DATA) {
TC_PRINT("Pop from queue1: %d\n", result);
retCode = TC_FAIL;
TCERR3;
return;
}
/* Put more data into STACK */
TC_PRINT("ISR STACK (running in fiber) Push to queue1:\n");
for (int i=0; i<NUM_STACK_ELEMENT; i++) {
isrStackInfo.data = myIsrData[i];
TC_PRINT(" %d, ", myIsrData[i]);
_trigger_nano_isr_stack_push();
}
TC_PRINT("\n");
/* Set variable to INVALID_DATA to ensure [data] changes */
isrStackInfo.data = INVALID_DATA;
TC_END_RESULT(retCode);
} /* testIsrStackFromFiber */
/**
*
* testIsrStackFromTask
*
* This function tests the stack push and pop interfaces in the ISR context.
* It is invoked from a task.
*
* We use nanoStackObj queue to push and pop data.
*
* @return N/A
*/
void testIsrStackFromTask(void)
{
uint32_t result = INVALID_DATA; /* data used to put and get from the stack queue */
int count = 0;
TC_PRINT("Test ISR STACK (invoked from Task)\n\n");
/* Get all data */
_trigger_nano_isr_stack_pop();
result = isrStackInfo.data;
while (result != INVALID_DATA) {
TC_PRINT(" Pop from queue1: count = %d, data is %d\n", count, result);
if ((count >= NUM_STACK_ELEMENT) || (result != myIsrData[NUM_STACK_ELEMENT - count - 1])) {
TCERR1(count);
retCode = TC_FAIL;
return;
} /* if */
/* Get the next element */
_trigger_nano_isr_stack_pop();
result = isrStackInfo.data;
count++;
} /* while */
/* Put data into stack and get it again */
isrStackInfo.data = myIsrData[3];
_trigger_nano_isr_stack_push();
isrStackInfo.data = INVALID_DATA; /* force variable to a new value */
/* Get data from stack */
_trigger_nano_isr_stack_pop();
result = isrStackInfo.data;
/* Verify data */
if (result != myIsrData[3]) {
TCERR2;
retCode = TC_FAIL;
return;
} else {
TC_PRINT("\nTest ISR STACK (invoked from Task) - push %d and pop back %d\n",
myIsrData[3], result);
}
TC_END_RESULT(retCode);
}
/**
*
* fiber2
*
* This is the fiber started from the testTaskStackPopW function.
*
* @return N/A
*/
void fiber2(void)
{
testFiberStackPopW();
PRINT_LINE;
testIsrStackFromFiber();
TC_END_RESULT(retCode);
}
/**
*
* testTaskStackPopW
*
* This is in the task. It puts data to nanoStackObj2 queue and gets
* data from nanoStackObj queue.
*
* @return N/A
*/
void testTaskStackPopW(void)
{
uint32_t data; /* data used to put and get from the stack queue */
int rc;
PRINT_LINE;
TC_PRINT("Test STACK Pop Wait Interfaces\n\n");
data = myData[0];
TC_PRINT("TASK STACK Push to queue2: %d\n", data);
nano_task_stack_push(&nanoStackObj2, data);
/* Start fiber */
task_fiber_start(&fiberStack2[0], STACKSIZE,
(nano_fiber_entry_t) fiber2, 0, 0, 7, 0);
rc = nano_task_stack_pop(&nanoStackObj, &data, TICKS_UNLIMITED);
TC_PRINT("TASK STACK Pop from queue1: %d\n", data);
/* Verify results */
if ((rc == 0) || (data != myData[1])) {
retCode = TC_FAIL;
TCERR2;
return;
}
data = myData[2];
TC_PRINT("TASK STACK Push to queue2: %d\n", data);
nano_task_stack_push(&nanoStackObj2, data);
TC_END_RESULT(retCode);
} /* testTaskStackPopW */
/**
*
* @brief A fiber to help test nano_task_stack_pop(TICKS_UNLIMITED)
*
* This fiber blocks for one second before pushing an item onto the stack.
* The main task, which was waiting for item from the stack then unblocks.
*
* @return N/A
*/
void fiber3(void)
{
nano_fiber_timer_start(&timer, SECONDS(1));
nano_fiber_timer_test(&timer, TICKS_UNLIMITED);
nano_fiber_stack_push(&nanoStackObj, myData[0]);
}
/**
*
* @brief Initialize nanokernel objects
*
* This routine initializes the nanokernel objects used in the STACK tests.
*
* @return N/A
*/
void initNanoObjects(void)
{
nano_stack_init(&nanoStackObj, stack1);
nano_stack_init(&nanoStackObj2, stack2);
nano_sem_init(&nanoSemObj);
nano_timer_init(&timer, timerData);
} /* initNanoObjects */
/**
*
* @brief Entry point to STACK tests
*
* This is the entry point to the STACK tests.
*
* @return N/A
*/
void main(void)
{
int count = 0; /* counter */
uint32_t data; /* data used to put and get from the stack queue */
int rc; /* return code */
TC_START("Test Nanokernel STACK");
/* Initialize data */
initData();
/* Initialize the queues and semaphore */
initNanoObjects();
/* Start fiber3 */
task_fiber_start(&fiberStack3[0], STACKSIZE, (nano_fiber_entry_t) fiber3,
0, 0, 7, 0);
/*
* While fiber3 blocks (for one second), wait for an item to be pushed
* onto the stack so that it can be popped. This will put the nanokernel
* into an idle state.
*/
rc = nano_task_stack_pop(&nanoStackObj, &data, TICKS_UNLIMITED);
if ((rc == 0) || (data != myData[0])) {
TC_ERROR("nano_task_stack_pop(TICKS_UNLIMITED) expected 0x%x, but got 0x%x\n",
myData[0], data);
retCode = TC_FAIL;
goto exit;
}
/* Put data */
TC_PRINT("Test Task STACK Push\n");
TC_PRINT("\nTASK STACK Put Order: ");
for (int i=0; i<NUM_STACK_ELEMENT; i++) {
nano_task_stack_push(&nanoStackObj, myData[i]);
TC_PRINT(" %d,", myData[i]);
}
TC_PRINT("\n");
PRINT_LINE;
/* Start fiber */
task_fiber_start(&fiberStack1[0], STACKSIZE,
(nano_fiber_entry_t) fiber1, 0, 0, 7, 0);
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(&nanoSemObj, TICKS_UNLIMITED);
TC_PRINT("Test Task STACK Pop\n");
/* Get all data */
while (nano_task_stack_pop(&nanoStackObj, &data, TICKS_NONE) != 0) {
TC_PRINT("TASK STACK Pop: count = %d, data is %d\n", count, data);
if ((count >= NUM_STACK_ELEMENT) || (data != myData[count])) {
TCERR1(count);
retCode = TC_FAIL;
goto exit;
}
count++;
}
/* Test Task Stack Pop Wait interfaces*/
testTaskStackPopW();
if (retCode == TC_FAIL) {
goto exit;
}
PRINT_LINE;
/* Test ISR interfaces */
testIsrStackFromTask();
PRINT_LINE;
exit:
TC_END_RESULT(retCode);
TC_END_REPORT(retCode);
}