⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmx_init.c

📁 CMEX source code RTOS for atmel atmega128
💻 C
字号:
/*********************************************************

Copyright (c) CMX Company. 1999. All rights reserved

*********************************************************/
/* version 5.30, adds the following:
1. counting semaphores
2. priority inversion on resources
3. highest priority task waiting on resource, is the one
   that will get resource when it is released.
4. New pipe routine 
*/

#define CMX_INIT_MODULE
#define CMXMODULE

#include <cxfuncs.h>		/* get cmx include header file */
#include "cxconfig.h"	/* get user configuration file */
#include <iom103.h>		/* The chip to be used */

#if CMXTRACKER_ENABLE > 0
#include <cmxtrack.h>	/* get cmx include header file */
#endif

#if C_PIPE_SIZE < 1 || C_PIPE_SIZE > 255
#error PIPE_SIZE MUST BE between 1 and 255 
#endif 

#if C_MAX_MESSAGES > 0
#define CMX_MAX_MESSAGES C_MAX_MESSAGES + 2
#endif


#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0
#define CC_TASK_STK_SIZE (C_TASK_STK_SIZE + 128)
#define CC_TASK_SYSTEM_STK_SIZE (C_TASK_SYSTEM_STK_SIZE + 48)
#else
#define CC_TASK_STK_SIZE C_TASK_STK_SIZE
#define CC_TASK_SYSTEM_STK_SIZE C_TASK_SYSTEM_STK_SIZE
#endif

#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0
#define CC_MAX_TASKS (C_MAX_TASKS + 1)
#else
#define CC_MAX_TASKS C_MAX_TASKS
#endif

/***********************************************************
 WARNING: these are assumed to be initailized by the "C" compiler
 start up code. Also all non-initialized CMX variables are assumed
 to be zeroed out by the "C" compiler startup code. This is normally
 done. If NOT, then the user must set the CMX_RAM_INIT define to 1. 
 See cxconfig.h (or equivalent file).  
***********************************************************/

byte MAX_TASKS = CC_MAX_TASKS;	
byte MAX_RESOURCES = C_MAX_RESOURCES;
byte MAX_CYCLIC_TIMERS = C_MAX_CYCLIC_TIMERS;
byte MAX_MAILBOXES = C_MAX_MAILBOXES;
byte MAX_QUEUES = C_MAX_QUEUES;
byte RTC_SCALE = C_RTC_SCALE;
byte MAX_SEMAPHORES = C_MAX_SEMAPHORES;
byte TSLICE_SCALE = C_TSLICE_SCALE;

/*******************************************************
 The following sets up the necessary memory needed by CMX
*******************************************************/ 

/******************************************************
 The cxvendor.h header file will actually add additional
 CMX variables to ONLY this file. See that header file.
********************************************************/

struct _tcb cmx_tcb[CC_MAX_TASKS+1];

#if C_MAX_CYCLIC_TIMERS > 0

CYCLIC_TIMERS tcproc[C_MAX_CYCLIC_TIMERS];

#else

byte tcproc[1];

#endif


#if C_MAX_RESOURCES > 0

RESHDR res_que[C_MAX_RESOURCES];

#else

byte res_que[1];

#endif

#if C_MAX_MAILBOXES > 0

MAILBOX mail_box[C_MAX_MAILBOXES];

#else

byte mail_box[1];

#endif

#if C_MAX_MESSAGES > 0

MSG message_box[CMX_MAX_MESSAGES];

#else

byte message_box[1];

#endif


#if C_MAX_QUEUES > 0

QUEHDR queue[C_MAX_QUEUES];

#else

byte queue[1];

#endif

#if C_MAX_SEMAPHORES > 0

SEM sem_array[C_MAX_SEMAPHORES];

#else

byte sem_array[1];

#endif

struct {
	word16 stack_space[CC_TASK_STK_SIZE / 2];
	word16 dummy;
	} stack_storage;
word16 *stack_blk;

struct {
	word16 system_stack_space[CC_TASK_SYSTEM_STK_SIZE / 2];
	word16 dummy;
	} system_stack_storage;
word16 *system_stack_blk;


struct {
	word16 interrupt_bytes[C_INTERRUPT_SIZE / 2];
	word16 dummy;
	} int_storage;
word16 *interrupt_stack;

struct {
	word16 interrupt_bytes[C_SYSTEM_INTERRUPT_SIZE / 2];
	word16 dummy;
	} system_int_storage;
word16 *system_interrupt_stack;

word16 *stack_holder;

CYCLIC_LNK cyclic_buf;
CYCLIC_LNK *cyclic_lnk;
TSK_TIMER_LNK *tsk_timer_lnk;
TSK_TIMER_LNK tsk_timer_buf;
MSG *message_ptr;
word16 message_free;

/* Note the following are held in NEAR data space */
byte tslice_count;
byte SLICE_ON;
tcbpointer activetcb;
byte active_priority;
/* end of NEAR data space variables */

tcbpointer timertask;
byte rtc_count;

PIPE_STRUC *out_ptr;

PIPE_STRUC pipe[C_PIPE_SIZE];


#if CMX_RAM_INIT > 0
static void clear_ram(void *,word16);
static void init_cmx_variables(void);
#endif

#if CMXTRACKER_ENABLE > 0
byte CMXTRACKER_ACTIVE;
byte CMXTRACKER_ON;
tcbpointer previoustcb;
extern byte cmxtracker_slot;
extern void cmxtracker(void);
extern void cmxtracker_mode(byte,word16);
extern word16 cmxtracker_ctr;
extern byte *cmxtracker_in_ptr;
extern word16 num_records;
void init_cmxtracker(void);
byte cmxtracker_array[CMXTRACKER_SIZE];
#define LOG_DISPLAY_LEN 18
word16 rec_cnt[((sizeof (cmxtracker_array) / 4) / LOG_DISPLAY_LEN) + 2];
#endif

#if CMXBUG_ENABLE > 0 
extern byte cmxbug_slot;
extern void cmxbug(void);
byte CMXBUG_ACTIVE;
#endif

#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0
long stat_array[CC_MAX_TASKS+1];
char *task_name[CC_MAX_TASKS + 1];
byte BUG_WAIT_TICKS;
void setup_bug(void);
byte K_Bug_Getchr(byte *ptr);
void K_Bug_Putchr(char);
#else
char *task_name[1];
#endif

word32 cmx_tick_count;	/* total number of CMX system ticks accumulated */

void K_OS_Init(void)
{
	MSG *link;		/* scratch pointer */

	locked_out = 1;	/* set lock so it will never goto K_I_Scheduler */
	cmx_tick_count = 0;	/* reset CMX long counter */

#if CMX_RAM_INIT > 0		/* Should we initialize CMX variables */
	init_cmx_variables();
#endif

#if C_MAX_MESSAGES > 0
	link = message_box; /* address of 1st block */
	message_free = CMX_MAX_MESSAGES;	/* use pipe_max to hold count */
	while (message_free--)
		{
		message_ptr = link;	/* point head at 1st block */
		link++;					/* compute addr of next block */
		message_ptr->env_link = link;	/* create link to it */
		}
	message_ptr->env_link = message_box;	/* last link in chain is null */
	message_ptr = message_box;	/* point head at 1st block */
	message_free = CMX_MAX_MESSAGES-2;
#endif

	in_ctr = out_ctr = cmx_flag1 = 0;
	pipe_slots_avail = C_PIPE_SIZE;

	cyclic_lnk = &cyclic_buf;	/* set up cyclic timers time link. */
	cyclic_lnk->ftlink = cyclic_lnk->btlink = (struct _tcproc *)cyclic_lnk;
	tsk_timer_lnk = &tsk_timer_buf;	/* set up task timer link. */
	tsk_timer_lnk->ftlink = tsk_timer_lnk->btlink = (tcbpointer)tsk_timer_lnk;

	/* now set up stack block to release memory to task's stacks as
		they are created. Also interrupt stack if used. */
	stack_blk = &stack_storage.dummy;
	interrupt_stack = &int_storage.dummy;
	system_stack_blk = &system_stack_storage.dummy;
	system_interrupt_stack = &system_int_storage.dummy;
	activetcb = timertask = cmx_tcb;  /* dummy tcb */
	timertask->nxttcb = cmx_tcb;		/* set up link. */

#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0
	setup_bug();
	BUG_WAIT_TICKS = 10;		/* Number of system ticks to wait, before checking
										to see if the + (plus key) has been received
										by UART. */
#endif

	rtc_count = C_RTC_SCALE;			/* number of timer ticks, before running
												CMX task timer if needed. */
}	/* K_OS_Init */

#if CMX_RAM_INIT > 0
static void init_cmx_variables(void)
{
	MAX_TASKS = CC_MAX_TASKS;	
	MAX_RESOURCES = C_MAX_RESOURCES;
	MAX_CYCLIC_TIMERS = C_MAX_CYCLIC_TIMERS;
	MAX_MAILBOXES = C_MAX_MAILBOXES;
	MAX_QUEUES = C_MAX_QUEUES;
	MAX_SEMAPHORES = C_MAX_SEMAPHORES;
	RTC_SCALE = C_RTC_SCALE;
	TSLICE_SCALE = C_TSLICE_SCALE;
	clear_ram(cmx_tcb,sizeof cmx_tcb);
	clear_ram(&stack_storage.stack_space[0],sizeof stack_storage);

#if C_MAX_CYCLIC_TIMERS > 0
	clear_ram(tcproc,sizeof tcproc);
#endif

#if C_MAX_RESOURCES > 0
	clear_ram(res_que,sizeof res_que);
#endif

#if C_MAX_MAILBOXES > 0
	clear_ram(mail_box,sizeof mail_box);
#endif

#if C_MAX_MESSAGES > 0
	clear_ram(message_box,sizeof message_box);
#endif

#if C_MAX_QUEUES > 0
	clear_ram(queue,sizeof queue);
#endif

#if C_MAX_SEMAPHORES > 0
	clear_ram(sem_array,sizeof sem_array);
#endif

}
static void clear_ram(void *addr_ptr,word16 size)
{
	byte *crap_ptr;
	crap_ptr = addr_ptr;
	while(size--)
		{
		*crap_ptr++ = 0;
		}
}
#endif

#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0

void setup_bug(void)
{
	/* Do NOT change the "cmxbug_slot" or "cmxbug", for
		CMXBug expects these names. You could change the priority
		or stack size if need be, but we highly suggest you do not. */

#if CMXBUG_ENABLE > 0 
	K_Task_Create(1,&cmxbug_slot,cmxbug,128,32);	/* create CMXBug task */
	K_Task_Name(cmxbug_slot,"CMXBug");		/* Name for task */
	K_Task_Start(cmxbug_slot);					/* start CMXBug task */
#else
	K_Task_Create(1,&cmxtracker_slot,cmxtracker,128,32);	/* create CMXTracker task */
	K_Task_Name(cmxtracker_slot,"CMXTracker");		/* Name for task */
	K_Task_Start(cmxtracker_slot);					/* start CMXBug task */
	init_cmxtracker();
#endif

		/* The following is for serial channel */
		UBRR  = 6;		/* Bad tolerance - 9600 Baud using 1 MHz	*/
/*		UBRR  = 12;		*/ /* 4800 Baud using 1 MHz	*/
		UBRR  = 50;		/* 1200 Baud using 1 MHz	*/
		UCR = 0x18;			/* enable transmitter/receiver */
}

#if CMXTRACKER_ENABLE > 0
void init_cmxtracker(void)
{
	num_records = 0;
	cmxtracker_in_ptr = cmxtracker_array;
	cmxtracker_ctr = sizeof (cmxtracker_array);
}
#endif

byte K_Bug_Getchr(byte *ptr)
{
	if ( USR & 0x80 )
		{
		*ptr = UDR & 0x7F;
		return(1);
		}
	else
		return(0);
}

void K_Bug_Putchr(char c)
{
	while ( ! (USR & 0x20) ) 
		;
	UDR = c;
}
#endif

byte K_I_Intrp_Pipe_In(byte a, byte b, byte c, word16 d, void *mesg)
{
	PIPE_STRUC *in_ptr;

#if CMXTRACKER_ENABLE > 0
	if ((!(TEST_CMX_ACTIVE)) || (CMXTRACKER_ACTIVE))
		return(K_ERROR);
#else
	if (!(TEST_CMX_ACTIVE))
		return(K_ERROR);
#endif
	PROC_SAVE_INT;	/* disable interrupts */
	if (pipe_slots_avail)
		{
		in_ptr = &pipe[in_ctr];
		--pipe_slots_avail;
		if (++in_ctr == C_PIPE_SIZE)
			in_ctr = 0;
		PROC_RESTORE_INT;	/* enable interrupts */
		DO_INT_PIPE;		/*	Set the do interrupt pipe flag. */
		in_ptr->identifier = a;
		in_ptr->p1 = b;
		switch(a) {
			case 5:
			case 6:
				in_ptr->pipe_u.p3 = d;
				break;
			case 7:
				in_ptr->pipe_u.p4 = mesg;
				break;
			case 8:
				in_ptr->p2 = c;
				in_ptr->pipe_u.p3 = d;
				break;
			}
		return(K_OK);
		}
	else
		{
		PROC_RESTORE_INT;	/* enable interrupts */
		return(K_ERROR);
		}
}

/*********************************************************************
 The following function executes the functions that the interrupts
 place into the interrupt pipe. called only by CMX K_I_Scheduler.
*********************************************************************/
void K_I_Intrp_Pipe_Out(void)
{
	byte parm1;
	byte parm2;

	while(1)
		{
#if CMXTRACKER_ENABLE
		if (!CMXTRACKER_ACTIVE)
			{
			cmxtracker_in1(INT_ACTION);
			}
#endif
		out_ptr = &pipe[out_ctr];
		switch (out_ptr->identifier) {
			case 0:
				K_Task_Wake(out_ptr->p1);
				break;
			case 1:
				K_Task_Wake_Force(out_ptr->p1);
				break;
			case 2:
				K_Task_Start(out_ptr->p1);
				break;
			case 3:
				K_Timer_Stop(out_ptr->p1);
				break;
			case 4:
				K_Timer_Restart(out_ptr->p1);
				break;
			case 5:
				parm1 = out_ptr->p1;
				K_Timer_Initial(parm1,out_ptr->pipe_u.p3);
				break;
			case 6:
				parm1 = out_ptr->p1;
				K_Timer_Cyclic(parm1,out_ptr->pipe_u.p3);
				break;
			case 7:
				parm1 = out_ptr->p1;
				K_Mesg_Send(parm1,out_ptr->pipe_u.p4);
				break;
			case 8:
				parm1 = out_ptr->p1;
				parm2 = out_ptr->p2;
				K_Event_Signal(parm1,parm2,out_ptr->pipe_u.p3);
				break;
			case 9:
				K_Semaphore_Post(out_ptr->p1);
				break;
			default:
				/* What should we do here, possibly reset pipe ? to be beginning */
				break;
			}
		PROC_DISABLE_INT;	/* disable interrupts */
		pipe_slots_avail++;
		if (++out_ctr == C_PIPE_SIZE)
			out_ctr = 0;
		if (out_ctr == in_ctr)
			{
			CLR_DO_INT_PIPE;	/* no, reset do interrupt pipe flag. */
			break;		/* exit. */
			}
		PROC_ENABLE_INT;	/* re-enable interrupts and process more. */
		}
	PROC_ENABLE_INT;	/* re-enable interrupts and exit. */
}

byte K_Task_Name(byte task_slot,char *name)
{
	tcbpointer tcbptr;

	if(K_I_Get_Ptr(task_slot,&tcbptr))	/* send address of pointer */
		return(K_ERROR);
#if CMXBUG_ENABLE > 0 || CMXTRACKER_ENABLE > 0
	task_name[task_slot] = name;
#else
	task_name[0] = name;
#endif 
	return(K_OK);
}

byte K_OS_Task_Slot_Get(void)
{
	return ((struct _tcb *)activetcb - cmx_tcb);
}

word32 K_OS_Tick_Get_Ctr(void)
{
	return(cmx_tick_count);
}

/******************************************************************
	K_OS_Tick_Update:  Called from timer interrupt routine to signal that
	the CMX task timer should execute if need be.
	THIS CODE EXECUTES ONLY AT INTERRUPT LEVEL.
**********************************************************************/
 
void K_OS_Tick_Update(void)
{
	if (TEST_CMX_ACTIVE)	/* see if CMX OS has been entered. */
		{
#if CMXBUG_ENABLE > 0
		if (!CMXBUG_ACTIVE)
			{
			if (activetcb->tcbstate & RUNNING)
				stat_array[activetcb - cmx_tcb] += 1;
			else
				stat_array[0] += 1;
			}
#endif
			cmx_tick_count++;	/* increment long counter */

#if CMXTRACKER_ENABLE
		if (!CMXTRACKER_ACTIVE)
			{
#endif
			if (!(--rtc_count))	/* converts hardware tics to CMX delay tics */
				{
#if CMXTRACKER_ENABLE
				cmxtracker_in1(CMX_TIC_CALL);
#endif

				rtc_count = RTC_SCALE;	/* reset counter with rtc prescaler */
			/* the following will see if a task timer needs servicing or
				a cyclic timer needs servicing. */
			if ((tsk_timer_lnk->ftlink != (tcbpointer)tsk_timer_lnk) ||
				(cyclic_lnk->ftlink != (struct _tcproc *)cyclic_lnk))
				{
				DO_TIMER_TSK;	/* yes, set flag to indicate that CMX timer
									task should execute. */
				}
  			}
#if CMXTRACKER_ENABLE
		}
#endif

		if (TEST_SLICE_ENABLE)	/* see if time slicing active. */
			{
			if (!(--tslice_count))	/* if so, decrement and test time slice
											counter. */
				{
				DO_TIME_SLICE;		/* set flag indicating time count expired. */
				SLICE_DISABLE;		/* disable time slicing. */
				}
			}
		}
}	/* K_OS_Tick_Update */

void K_I_Func_Return(void)
{
	/* this function will decrement the task block (lock) counter.
		Also see if the interrupt count is 0 and if so, will
		test to see any of the CMX 5 flags are set, which will then call
		the K_I_Scheduler to invoke possibly a task switch */

	K_I_Enable_Sched();
}

/*****************************************************************
 The following is the CPU reduced power function. The user
 MUST write their own and they must ensure that the proceesor
 returns to the caller, without modifying the stack.

 NOTE: the CMX K_I_Scheduler calls this function which is in the assembly
 module supplied. The user may find it necessary to modify the
 assembly file, so every thing is correct when the CPU
 comes out of the reduced power state. ALSO the CPU must let
 the interrupts wake it up, out of the reduced power state
 so as the task's timers and cyclic timers may have their
 time counters decremented if need be.
*****************************************************************/
void K_OS_Low_Power_Func(void)
{
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -