kerneltest/e32test/personality/example/main.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test\personality\example\main.cpp
// Test code for example RTOS personality.
// 
//

#include <kernel/kern_priv.h>
#include <personality/example/personality.h>

#ifdef __cplusplus
extern "C" {
#endif

#define	OC_TASK				0
#define	L2_TASK				1
#define	RR_TASK				2
#define NONEXISTENT_TASK	3
#define TM_TASK				4
#define	TASK1				6
#define	TASK2				7
#define	TASK3				8
#define	TASK4				9
#define	L1_TASK				10

void oo_overall_control(void);
void l1_task_entry(void);
void l2_task_entry(void);
void rr_task_entry(void);
void tm_task_entry(void);
void task1_entry(void);
void task2_entry(void);
void task3_entry(void);
void task4_entry(void);

typedef void (*isr_entry)(unsigned);

extern int start_random_isr(isr_entry vector);
extern void stop_random_isr(void);

const taskinfo task_list[] =
	{

	/*		entry_pt,			priority, stack_size,	task_id, auto_start	*/

		{	&oo_overall_control,	120,	1024,		OC_TASK,	1	},
		{	&l2_task_entry,			236,	1024,		L2_TASK,	0	},
		{	&rr_task_entry,			224,	1024,		RR_TASK,	0	},
		{	&tm_task_entry,			240,	1024,		TM_TASK,	0	},
		{	&task1_entry,			112,	1024,		TASK1,		0	},
		{	&task2_entry,			112,	1024,		TASK2,		0	},
		{	&task3_entry,			112,	1024,		TASK3,		0	},
		{	&task4_entry,			112,	1024,		TASK4,		0	},
		{	&l1_task_entry,			244,	1024,		L1_TASK,	0	},
	/* terminator */
		{	0,						0,		0,			0,			0	}
	};

const poolinfo pool_list[] =
	{
	/*	block size,		block count	*/
		{	32,			256		},
		{	64,			256		},
		{	128,		128		},
		{	256,		64		},
		{	512,		32		},
	/* terminator */
		{	0,			0		}
	};

const int timer_count = 8;
const int semaphore_count = 2;

#define TM_TIMER		0

#define TM_INIT_DELAY	1000
#define TM_PERIOD		2

volatile unsigned next_random_id = 0;
volatile unsigned random_sem_signal_interval = 0;
volatile unsigned random_sem_signal_count = 0;
volatile unsigned random_send_interval = 0;
volatile unsigned random_send_count = 0;
volatile unsigned tmcount = 0;
volatile int t1func = 0;
volatile int t2func = 0;
volatile int t3func = 0;
volatile int t4func = 0;

#define TEST_SEM		0
#define	ISR_SEM			1

#define MSG_ID_INIT		1
#define MSG_ID_RUN		2
#define MSG_ID_RUN_P	3
#define	MSG_ID_RND_ISR	4
#define MSG_ID_DONE		5
#define	MSG_ID_DATA		6
#define	MSG_ID_FLUSH	7
#define MSG_ID_SEM_RPT	8
#define MSG_ID_RCV_RPT	9
#define MSG_ID_TM_RPT	10

typedef struct _run_msg
	{
	msghdr			header;
	int				task_id;
	unsigned		tmcount;
	int				parameter;
	} run_msg;

typedef struct _random_isr_msg
	{
	msghdr			header;
	unsigned		random_isr_number;
	unsigned		extra;
	} random_isr_msg;

typedef struct _data_msg
	{
	msghdr			header;
	int				length;
	unsigned char	checksum;
	unsigned char	data[1];
	} data_msg;

typedef struct _report_msg
	{
	msghdr			header;
	int				pad;
	unsigned		count;
	unsigned		ok_count;
	unsigned		bad_count;
	} report_msg;

void busy_wait(unsigned ticks)
	{
	unsigned t0 = tmcount;
	while ((tmcount - t0) < ticks)
		{}
	}

void send_run_signal()
	{
	run_msg* m = (run_msg*)alloc_mem_block(sizeof(run_msg));
	assert(m);
	m->header.msg_id = MSG_ID_RUN;
	m->task_id = current_task_id();
	m->tmcount = tmcount;
	int r = send_msg(OC_TASK, &m->header);
	assert(r == OK);
	}

void send_run_signal_p(int parameter)
	{
	run_msg* m = (run_msg*)alloc_mem_block(sizeof(run_msg));
	assert(m);
	m->header.msg_id = MSG_ID_RUN_P;
	m->task_id = current_task_id();
	m->tmcount = tmcount;
	m->parameter = parameter;
	int r = send_msg(OC_TASK, &m->header);
	assert(r == OK);
	}

void tsend_run_signal_p(int task_id, int parameter)
	{
	run_msg* m = (run_msg*)alloc_mem_block(sizeof(run_msg));
	assert(m);
	m->header.msg_id = MSG_ID_RUN_P;
	m->task_id = current_task_id();
	m->tmcount = tmcount;
	m->parameter = parameter;
	int r = send_msg(task_id, &m->header);
	assert(r == OK);
	}

void check_no_signal()
	{
	msghdr* m = NULL;
	int r = recv_msg(&m, NO_WAIT);
	assert(r == TIMED_OUT);
	}

unsigned check_for_signal(int task_id)
	{
	msghdr* m = NULL;
	int r = recv_msg(&m, NO_WAIT);
	assert(r == OK);
	assert(m->msg_id == MSG_ID_RUN);
	run_msg* rm = (run_msg*)m;
	assert(rm->task_id == task_id);
	unsigned tmc = rm->tmcount;
	free_mem_block(m);
	return tmc;
	}

int check_for_signal_p(int task_id, int task_id2, unsigned* pt)
	{
	msghdr* m = NULL;
	int r = recv_msg(&m, NO_WAIT);
	assert(r == OK);
	assert(m->msg_id == MSG_ID_RUN_P);
	run_msg* rm = (run_msg*)m;
	assert(rm->task_id == task_id);
	assert(m->sending_task_id == task_id2);
	r = rm->parameter;
	if (pt)
		*pt = rm->tmcount;
	free_mem_block(m);
	return r;
	}

int wait_for_signal_p(int task_id, unsigned* pt)
	{
	msghdr* m = NULL;
	int r = recv_msg(&m, WAIT_FOREVER);
	assert(r == OK);
	assert(m->msg_id == MSG_ID_RUN_P);
	run_msg* rm = (run_msg*)m;
	assert(rm->task_id == task_id);
	r = rm->parameter;
	if (pt)
		*pt = rm->tmcount;
	free_mem_block(m);
	return r;
	}

void resume_4(int t1, int t2, int t3, int t4)
	{
	if (t1>=0)
		assert(resume_task(t1)==OK);
	if (t2>=0)
		assert(resume_task(t2)==OK);
	if (t3>=0)
		assert(resume_task(t3)==OK);
	if (t4>=0)
		assert(resume_task(t4)==OK);
	}

void check_signal_4(int t1, int t2, int t3, int t4)
	{
	if (t1>=0)
		check_for_signal(t1);
	else
		check_no_signal();
	if (t2>=0)
		check_for_signal(t2);
	else
		check_no_signal();
	if (t3>=0)
		check_for_signal(t3);
	else
		check_no_signal();
	if (t4>=0)
		check_for_signal(t4);
	else
		check_no_signal();
	}

void check_for_multiple_signals(int task_id, int count)
	{
	unsigned t = check_for_signal(task_id);
	while (--count)
		{
		unsigned t2 = check_for_signal(task_id);
		assert(t2 - t >= 1);
		t = t2;
		}
	}

int flush_signals(void)
	{
	int c = 0;
	for (;;)
		{
		msghdr* m = NULL;
		int r = recv_msg(&m, NO_WAIT);
		if (r == TIMED_OUT)
			break;
		assert(r == OK);
		assert(m->msg_id == MSG_ID_RUN);
		free_mem_block(m);
		++c;
		}
	return c;
	}

void test_mem_pool(size_t size, int count, void** chain)
	{
	int i, fill;
	void *b, *bb, *c;
	c = *chain;
	for (i=0; i<count; ++i)
		{
		b = alloc_mem_block(size);
		assert(b != NULL);
		fill = (int)(size>>5);
		fill += 29;
		fill *= fill;
		fill &= 0xff;
		memset(b, fill, size);
		*(void**)b = c;
		((int*)b)[1] = (int)size;
		c = b;
		}
	bb = alloc_mem_block(size);
	assert(bb == NULL);
	*chain = c;
	}

void check_blocks(void* chain)
	{
	void* p = chain;
	while (p)
		{
		unsigned char *q, *qq;
		int size, fill, x;
		size = ((int*)p)[1];
		fill = (size>>5)+29;
		fill = (fill*fill)&0xff;
		q = (unsigned char*)p + sizeof(void*) + sizeof(int);
		qq = (unsigned char*)p + size;
		x = 0;
		while (q<qq)
			x |= (*q++ ^ fill);
		assert(x==0);
		p = *(void**)p;
		}
	}

int free_blocks(void* chain)
	{
	void* p = chain;
	int c = 0;
	while (p)
		{
		void* n = *(void**)p;
		free_mem_block(p);
		p = n;
		++c;
		}
	return c;
	}

void test_mem_mgr(void)
	{
	void* chain = NULL;
	const poolinfo* pi = pool_list;
	int nblocks = 0;
	int nfreed = 0;
	for (; pi->block_size; ++pi)
		{
		nblocks += pi->block_count;
		test_mem_pool(pi->block_size, pi->block_count, &chain);
		}
	check_blocks(chain);
	nfreed = free_blocks(chain);
	assert(nfreed == nblocks);
	chain = NULL;
	for (--pi; pi >= pool_list; --pi)
		test_mem_pool(pi->block_size, pi->block_count, &chain);
	check_blocks(chain);
	nfreed = free_blocks(chain);
	assert(nfreed == nblocks);
	chain = NULL;
	kprintf("Memory Manager Test OK");
	}

void test_suspend_1(void)
	{
	unsigned t1, t2, t3;
	int r;
	t1 = tmcount;
	delay(5*TM_PERIOD);
	t2 = tmcount;
	assert( ((int)t2)-((int)t1) >= 5 );
	r = suspend_task(TM_TASK);
	assert(r == OK);
	t1 = tmcount;
	delay(5*TM_PERIOD);
	t2 = tmcount;
	assert(t2==t1);
	r = resume_task(TM_TASK);
	assert(r == OK);
	t3 = tmcount;
	assert( ((int)t3)-((int)t2) >= 5 );

	r = suspend_task(TM_TASK);
	assert(r == OK);
	r = suspend_task(TM_TASK);
	assert(r == OK);
	t1 = tmcount;
	delay(5*TM_PERIOD);
	t2 = tmcount;
	assert(t2==t1);
	r = resume_task(TM_TASK);
	assert(r == OK);
	t3 = tmcount;
	assert(t3==t2);
	r = resume_task(TM_TASK);
	assert(r == OK);
	t3 = tmcount;
	assert( ((int)t3)-((int)t2) >= 5 );

	r = suspend_task(-1);
	assert(r == BAD_TASK_ID);
	r = suspend_task(300);
	assert(r == BAD_TASK_ID);
	r = suspend_task(NONEXISTENT_TASK);
	assert(r == BAD_TASK_ID);
	r = resume_task(-1);
	assert(r == BAD_TASK_ID);
	r = resume_task(300);
	assert(r == BAD_TASK_ID);
	r = resume_task(NONEXISTENT_TASK);
	assert(r == BAD_TASK_ID);

	kprintf("test_suspend_1 OK");
	}

void test_priority_scheduling(void)
	{
	int init_pri = get_task_priority(current_task_id());
	resume_4(TASK1, TASK2, TASK3, TASK4);
	delay(80*TM_PERIOD);
	check_for_multiple_signals(TASK1, 50);	// check no timeslicing
	assert(flush_signals()<=31);
	suspend_task(TASK1);
	delay(80*TM_PERIOD);
	check_for_multiple_signals(TASK2, 50);	// check no timeslicing
	assert(flush_signals()<=31);
	suspend_task(TASK2);
	delay(80*TM_PERIOD);
	check_for_multiple_signals(TASK3, 50);	// check no timeslicing
	assert(flush_signals()<=31);
	suspend_task(TASK3);
	delay(1);
	check_for_signal(TASK4);
	assert(flush_signals()<=1);

	t1func = 1;
	t2func = 1;
	t3func = 1;
	t4func = 1;

	resume_4(TASK1, TASK2, TASK3, TASK4);
	delay(10);
	flush_signals();

	resume_4(TASK3, TASK2, TASK4, TASK1);
	delay(10);
	check_signal_4(TASK3, TASK2, TASK4, TASK1);
	check_no_signal();
	resume_4(TASK1, TASK2, TASK3, TASK4);
	check_no_signal();	// all lower priority so don't run
	set_task_priority(TASK2, 255);		// higher than current task so run immediately
	check_for_signal(TASK2);
	set_task_priority(TASK4, 116);
	check_no_signal();	// all lower priority so don't run
	delay(10);
	check_for_signal(TASK4);
	check_for_signal(TASK1);
	check_for_signal(TASK3);
	set_task_priority(TASK1, 116);
	set_task_priority(TASK2, 116);
	set_task_priority(TASK3, 116);
	set_task_priority(TASK4, 116);
	resume_4(TASK1, TASK2, TASK3, TASK4);
	set_task_priority(current_task_id(), 112);	// drop current task priority
	assert(get_task_priority(current_task_id())==112);
	check_signal_4(TASK1, TASK2, TASK3, TASK4);
	set_task_priority(current_task_id(), init_pri);
	assert(get_task_priority(current_task_id())==init_pri);
	
	kprintf("test_priority_scheduling OK");
	}

unsigned sem_test(int task_id)
	{
	int r = semaphore_signal(TEST_SEM);
	assert(r==OK);
	return check_for_signal(task_id);
	}

unsigned sem_test_p(int task_id, int parameter)
	{
	unsigned t;
	int r = semaphore_signal(TEST_SEM);
	assert(r==OK);
	r = check_for_signal_p(task_id, task_id, &t);
	assert(r == parameter);
	return t;
	}

unsigned sem_test_pt(int task_id, int parameter)
	{
	unsigned t;
	int r = semaphore_signal(TEST_SEM);
	assert(r==OK);
	r = check_for_signal_p(task_id, task_id, &t);
	assert(r == parameter);
	return t;
	}

void test_semaphore(void)
	{
	unsigned t1, t2, t3;
	int r;
	int init_pri = get_task_priority(current_task_id());
	set_task_priority(TASK1, 128);
	set_task_priority(TASK2, 128);
	set_task_priority(TASK3, 128);
	set_task_priority(TASK4, 128);
	t1func = 2;
	t2func = 2;
	t3func = 2;
	t4func = 2;
	resume_4(TASK1, TASK2, TASK3, TASK4);
	delay(10);		// let tasks wait on semaphore
	check_no_signal();
	sem_test(TASK1);	// test they are released in same order
	sem_test(TASK2);
	sem_test(TASK3);
	sem_test(TASK4);
	check_no_signal();
	set_task_priority(TASK3, 132);	// test highest priority is released first
	sem_test(TASK3);
	sem_test(TASK3);
	suspend_task(TASK3);		// test suspended task doesn't contend for semaphore
	sem_test(TASK1);
	sem_test(TASK2);
	sem_test(TASK4);
	sem_test(TASK1);
	suspend_task(TASK2);
	sem_test(TASK4);
	sem_test(TASK1);
	sem_test(TASK4);
	set_task_priority(TASK2, 136);	// change priority while suspended
	sem_test(TASK1);
	sem_test(TASK4);
	sem_test(TASK1);
	resume_task(TASK2);
	sem_test(TASK2);
	sem_test(TASK2);	// test new highest priority task acquires semaphore first
	delay(100*TM_PERIOD);
	check_no_signal();	// check waits don't time out

	t2func = 3;			// switch over to timed waits for task 2
	t1 = sem_test(TASK2);			// get one last message of previous type
	delay(5*TM_PERIOD);
	t2 = sem_test_p(TASK2, OK);		// signal after half the timeout and check OK
	delay(11*TM_PERIOD);			// wait for > timeout
	r = check_for_signal_p(TASK2, TASK2, &t3);
	assert(r == TIMED_OUT);
	kprintf("t2-t1=%d t3-t2=%d", t2-t1, t3-t2);
	assert(t2-t1 >= 5);
	assert(t3-t2 >= 10);
	sem_test_p(TASK2, OK);
	resume_task(TASK3);

	set_task_priority(current_task_id(), 176);	// raise current task priority
	semaphore_signal(TEST_SEM);		// signal semaphore 4 times - should release all 4 waiting threads
	semaphore_signal(TEST_SEM);
	semaphore_signal(TEST_SEM);
	semaphore_signal(TEST_SEM);
	set_task_priority(current_task_id(), init_pri);	// let tasks run
	r = check_for_signal_p(TASK2, TASK2, NULL);
	assert(r == OK);
	check_for_signal(TASK3);
	check_for_signal(TASK4);
	check_for_signal(TASK1);
	set_task_priority(current_task_id(), 176);	// raise current task priority
	busy_wait(11);					// let semaphore wait time out
	t1func = 4;						// switch all threads over
	t2func = 4;						//
	t3func = 4;						//
	t4func = 4;						//
	semaphore_signal(TEST_SEM);		// signal semaphore 3 times - should release other 3 waiting threads
	semaphore_signal(TEST_SEM);
	semaphore_signal(TEST_SEM);
	set_task_priority(current_task_id(), init_pri);	// let tasks run
	r = check_for_signal_p(TASK2, TASK2, NULL);
	assert(r == TIMED_OUT);
	check_for_signal(TASK3);
	check_for_signal(TASK4);
	check_for_signal(TASK1);

	kprintf("test_semaphore OK");
	}

void test_message_queue(void)
	{
	unsigned t1, t2, t3, t4;
	int tid, p, r;
	int init_pri = get_task_priority(current_task_id());
	p = 0;
	t1 = 0;
	for (tid = TASK1; tid <= TASK4; ++tid)
		{
		for (p = 1; p; p<<=1)
			{
			tsend_run_signal_p(tid, p);
			r = check_for_signal_p(OC_TASK, tid, NULL);
			assert(r == p);
			}
		}
	check_no_signal();
	set_task_priority(current_task_id(), 176);	// raise current task priority
	set_task_priority(TASK4, 144);	// change task priorities while they are waiting
	set_task_priority(TASK3, 140);
	set_task_priority(TASK2, 136);
	set_task_priority(TASK1, 132);
	t1func = 5;	// switch task 1 to timed waits
	for (tid = TASK1; tid <= TASK4; ++tid)
		{
		for (p = 0; p<0x40000000; p+=(0x413b9cb+tid))
			{
			tsend_run_signal_p(tid, p);	// let multiple messages accumulate on the queues
			}
		}
	check_no_signal();
	set_task_priority(current_task_id(), init_pri);	// let tasks run
	kprintf("init_pri=%d",init_pri);
	for (tid = TASK4; tid >= TASK1; --tid)
		{
		for (p = 0; p<0x40000000; p+=(0x413b9cb+tid))
			{
			r = check_for_signal_p(OC_TASK, tid, &t1);
			assert(r == p);
			}
		}

	delay(5*TM_PERIOD);
	tsend_run_signal_p(TASK1, p);		// send after half timeout
	r = check_for_signal_p(OC_TASK, TASK1, &t2);
	assert(r == p);
	delay(11*TM_PERIOD);				// wait for > timeout
	tsend_run_signal_p(TASK1, ~p);		// send after timeout
	r = check_for_signal_p(TASK1, TASK1, &t3);
	assert(r == TIMED_OUT);
	kprintf("t2-t1=%d t3-t2=%d", t2-t1, t3-t2);
	assert(t2-t1 >= 5);
	assert(t3-t2 >= 10);
	r = check_for_signal_p(OC_TASK, TASK1, &t4);
	assert(r == ~p);
	assert(t4-t3 <= 1);
	t1func = 6;						// switch task 1 to timed semaphore wait
	t2func = 7;						// switch task 2 to timed queue wait
	t3func = 8;						//
	t4func = 8;						//
	for (tid = TASK1; tid <= TASK4; ++tid)
		{
		tsend_run_signal_p(tid, 0);
		r = check_for_signal_p(OC_TASK, tid, NULL);
		assert(r == 0);
		}
	check_no_signal();

	kprintf("test_message_queue OK");
	}

void random_isr(unsigned n)
	{
	random_isr_msg* m;
	unsigned extra = 1;
	unsigned count = 1;
	int r;
	if (!(n%11))
		++count;
	if (!(n%13))
		++count;
	while (count--)
		{
		m = (random_isr_msg*)alloc_mem_block(sizeof(random_isr_msg));
		m->header.msg_id = MSG_ID_RND_ISR;
		m->random_isr_number = n;
		extra *= n;
		m->extra = extra;
		r = send_msg(L1_TASK, &m->header);
		}
	if (random_sem_signal_count && !--random_sem_signal_count)
		{
		random_sem_signal_count = random_sem_signal_interval;
		semaphore_signal(ISR_SEM);
		}
	}

void flush_queue(msghdr** f, msghdr** l, msghdr* tm)
	{
	msghdr* m = *f;
	*f = NULL;
	*l = NULL;
	send_to_epoc(tm);
	while (m)
		{
		msghdr* n = m->next;
		send_to_epoc(m);
		m = n;
		}
	}

void l1_task_entry(void)
	{
	msghdr* first = NULL;
	msghdr* last = NULL;
	unsigned state = 0;
	unsigned extra_count = 0;
	unsigned extra_value = 0;
	assert(current_task_id() == L1_TASK);
	kprintf("L1_TASK running");
	for (;;)
		{
		msghdr* m = NULL;
		int r = recv_msg(&m, WAIT_FOREVER);
		assert(r == OK);
		switch (m->msg_id)
			{
			case MSG_ID_RND_ISR:
				{
				random_isr_msg* rm = (random_isr_msg*)m;
				assert(m->sending_task_id == TASK_ID_ISR);
				assert(rm->random_isr_number == next_random_id);
				if (state == 0)
					{
					extra_count = 0;
					if (!(next_random_id % 11))
						++extra_count;
					if (!(next_random_id % 13))
						++extra_count;
					extra_value = next_random_id;
					}
				else if (state > 0)
					{
					extra_value *= next_random_id;
					}
				assert(rm->extra == extra_value);
				if (++state > extra_count)
					state = 0;
				if (state == 0)
					++next_random_id;
				if (rm->random_isr_number == 0)
					send_msg(OC_TASK, m), m=NULL;
				if (state == 1 && extra_count == 2 && m)
					{
					flush_queue(&first, &last, m);
					m = NULL;
					}
				if (random_send_count && !--random_send_count)
					{
					random_send_count = random_send_interval;
					if (m)
						send_msg(TASK2, m), m=NULL;
					}
				break;
				}
			case MSG_ID_DATA:
				m->next = NULL;
				if (last)
					last->next = m;
				else
					first = m;
				last = m;
				m = NULL;
				break;
			case MSG_ID_FLUSH:
				flush_queue(&first, &last, m);
				m = NULL;
				break;
			default:
				kprintf("L1<-%08x",m->msg_id);
				break;
			}
		if (m)
			free_mem_block(m);
		}
	}

void l2_task_entry(void)
	{
	assert(current_task_id() == L2_TASK);
	kprintf("L2_TASK running");
	for (;;)
		{
		msghdr* m = NULL;
		int r = recv_msg(&m, WAIT_FOREVER);
		assert(r == OK);
		switch (m->msg_id)
			{
			case MSG_ID_DATA:
				{
				data_msg* dm = (data_msg*)m;
				int i;
				unsigned char cs = 0;
				for (i=0; i<dm->length; ++i)
					cs = (unsigned char)(cs + dm->data[i]);
				dm->checksum = cs;
				send_msg(L1_TASK, m);
				m=NULL;
				break;
				}
			default:
				kprintf("L2<-%08x",m->msg_id);
				break;
			}
		if (m)
			free_mem_block(m);
		}
	}

void rr_task_entry(void)
	{
	assert(current_task_id() == RR_TASK);
	kprintf("RR_TASK running");
	for (;;)
		{
		msghdr* m = NULL;
		int r = recv_msg(&m, WAIT_FOREVER);
		assert(r == OK);
		switch (m->msg_id)
			{
			case MSG_ID_DATA:
				send_msg(L2_TASK, m);
				m=NULL;
				break;
			default:
				kprintf("RR<-%08x",m->msg_id);
				break;
			}
		if (m)
			free_mem_block(m);
		}
	}

void tm_task_entry(void)
	{
	assert(current_task_id() == TM_TASK);
	kprintf("TM_TASK running");
	for (;;)
		{
		msghdr* m = NULL;
		int r = recv_msg(&m, WAIT_FOREVER);
		assert(r == OK);
		switch (m->msg_id)
			{
			case MSG_ID_TIMEOUT:
				tmcount = ((timer_msg*)m)->count;
				assert(m->sending_task_id == TASK_ID_ISR);
				if (!(tmcount & 255))
					{
					report_msg* rpt = (report_msg*)alloc_mem_block(sizeof(report_msg));
					rpt->header.msg_id = MSG_ID_TM_RPT;
					rpt->count = tmcount;
					rpt->ok_count = 0;
					rpt->bad_count = 0;
					send_to_epoc(&rpt->header);
					}
				break;
			default:
				kprintf("TM<-%08x",m->msg_id);
				break;
			}
		free_mem_block(m);
		}
	}

void generic_task(volatile int* f)
	{
	int r;
	msghdr* m;
	unsigned t1, t2;
	unsigned count = 0;
	unsigned ok_count = 0;
	unsigned bad_count = 0;
	while (*f==0)
		{
		send_run_signal();
		busy_wait(1);
		}
	while (*f==1)
		{
		send_run_signal();
		suspend_task(current_task_id());
		}
	while (*f==2)
		{
		r = semaphore_wait(TEST_SEM, WAIT_FOREVER);
		assert(r == OK);
		send_run_signal();
		}
	while (*f==3)
		{
		r = semaphore_wait(TEST_SEM, 10*TM_PERIOD);
		assert(r==OK || r==TIMED_OUT);
		send_run_signal_p(r);
		}
	while (*f==4)
		{
		r = recv_msg(&m, WAIT_FOREVER);
		assert(r==OK);
		assert(m->sending_task_id == OC_TASK);
		r = send_msg(OC_TASK, m);
		assert(r == OK);
		}
	while (*f==5)
		{
		r = recv_msg(&m, 10*TM_PERIOD);
		assert(r==OK || r==TIMED_OUT);
		if (r == OK)
			{
			assert(m->sending_task_id == OC_TASK);
			r = send_msg(OC_TASK, m);
			assert(r == OK);
			}
		else
			send_run_signal_p(r);
		}
	while (*f==6)
		{
		t1 = tick_count();
		r = semaphore_wait(ISR_SEM, 5);
		t2 = tick_count() - t1;
		if (r == TIMED_OUT && t2<5)
			{
			kprintf("SEM timed out too soon: %d", t2);
			++bad_count;
			}
		if (r == OK)
			++ok_count;
		++count;
		if (!(count & 0xff))
			{
			report_msg* rpt = (report_msg*)alloc_mem_block(sizeof(report_msg));
			rpt->header.msg_id = MSG_ID_SEM_RPT;
			rpt->count = count;
			rpt->ok_count = ok_count;
			rpt->bad_count = bad_count;
			send_to_epoc(&rpt->header);
			}
		}
	while (*f==7)
		{
		t1 = tick_count();
		r = recv_msg(&m, 5);
		t2 = tick_count() - t1;
		if (r == TIMED_OUT && t2<5)
			{
			kprintf("RECV timed out too soon: %d", t2);
			++bad_count;
			}
		if (r==OK)
			++ok_count, free_mem_block(m);
		++count;
		if (!(count & 0xff))
			{
			report_msg* rpt = (report_msg*)alloc_mem_block(sizeof(report_msg));
			rpt->header.msg_id = MSG_ID_RCV_RPT;
			rpt->count = count;
			rpt->ok_count = ok_count;
			rpt->bad_count = bad_count;
			send_to_epoc(&rpt->header);
			}
		}
	kprintf("Task %d finished", current_task_id());
	for(;;)
		suspend_task(current_task_id());
	}

void task1_entry(void)
	{
	assert(current_task_id() == TASK1);
	generic_task(&t1func);
	}

void task2_entry(void)
	{
	assert(current_task_id() == TASK2);
	generic_task(&t2func);
	}

void task3_entry(void)
	{
	assert(current_task_id() == TASK3);
	generic_task(&t3func);
	}

void task4_entry(void)
	{
	assert(current_task_id() == TASK4);
	generic_task(&t4func);
	}



void oo_overall_control(void)
	{
	int r;
	msghdr* m;
	random_isr_msg* rm;
	unsigned t1, t2, rss_interval;
	kprintf("OC_TASK running");
	assert(current_task_id() == OC_TASK);
	resume_task(L2_TASK);
	resume_task(RR_TASK);
	resume_task(TM_TASK);
	test_mem_mgr();

	kprintf("Wait for init msg");
	r = recv_msg(&m, WAIT_FOREVER);
	assert(r == OK);
	assert(m->msg_id == MSG_ID_INIT);
	assert(m->sending_task_id == TASK_ID_UNKNOWN);
	free_mem_block(m);
	kprintf("Received init msg");

	r = start_periodic_timer(TM_TIMER, TM_TASK, TM_INIT_DELAY, TM_PERIOD, NULL);
	assert(r == OK);
	delay(TM_INIT_DELAY-10);
	assert(tmcount == 0);
	delay(10*TM_PERIOD+20);
	assert(tmcount > 0);
	test_suspend_1();
	test_priority_scheduling();
	test_semaphore();
	test_message_queue();

	resume_task(L1_TASK);
	r = start_random_isr(&random_isr);
	if (r != OK)
		goto no_random_isr;

	r = recv_msg(&m, WAIT_FOREVER);
	assert(r == OK);
	assert(m->msg_id == MSG_ID_RND_ISR);
	assert(m->sending_task_id == L1_TASK);
	rm = (random_isr_msg*)m;
	assert(rm->random_isr_number == 0);
	free_mem_block(m);
	t1 = next_random_id;
	delay(1024);
	t2 = next_random_id;
	kprintf("%d random ISRs in 1024 ticks", t2-t1);
	rss_interval = (5*(t2-t1)+512)/1024;
	set_task_priority(TASK1, 196);	// needs to be higher than DfcThread1
	set_task_priority(TASK2, 196);
	random_sem_signal_interval = rss_interval;
	random_sem_signal_count = rss_interval;
	random_send_interval = rss_interval;
	random_send_count = rss_interval;

no_random_isr:
	m = (msghdr*)alloc_mem_block(sizeof(msghdr));
	m->msg_id = MSG_ID_DONE;
	send_to_epoc(m);
	kprintf("All tests completed OK");
	for (;;)
		{
		int r = recv_msg(&m, WAIT_FOREVER);
		assert(r == OK);
		switch (m->msg_id)
			{
			case MSG_ID_DATA:
				send_msg(RR_TASK, m);
				m=NULL;
				break;
			case MSG_ID_FLUSH:
				send_msg(L1_TASK, m);
				m=NULL;
				break;
			case MSG_ID_DONE:
				stop_random_isr();
				stop_timer(TM_TIMER);
				suspend_task(L1_TASK);
				suspend_task(L2_TASK);
				suspend_task(RR_TASK);
				suspend_task(TM_TASK);
				suspend_task(TASK1);
				suspend_task(TASK2);
				suspend_task(TASK3);
				suspend_task(TASK4);
				break;
			default:
				kprintf("OC<-%08x",m->msg_id);
				break;
			}
		if (m)
			free_mem_block(m);
		}
	}

#ifdef __cplusplus
}
#endif