//kernel.c

#include <912d60.h>
#include <stdio.h>
#include "kernel.h"


// GLOBAL VARIABLE DEFINITIONS
unsigned int current;		   	 		    // current task id number
unsigned long int system_tick;


// task control block
typedef struct task_block {
	 	unsigned char id; 			  		// ID of task
		enum task_state state;				// State
		unsigned char priority;				// Priority
		unsigned long int period_tick;		// for determining if deadline is up
		unsigned int interrupt_msg_box;		// flags for pending interrupts
		enum message_box message;			// misc flags
		unsigned char message_data[8];		// data for misc_msg_box flags
	 	unsigned char *heap_ptr;			// heap addr while not current task
		unsigned int heap_size;				// heap size
		unsigned char *frame_ptr;			// CCR pointer
		};


// resource control block
typedef struct resource_block {
		unsigned char id;	   				// ID of resource
		enum resource_state state;			// State (busy, free...)
		unsigned char user;					// Current resource user/owner
		signed char queue[3];				// Tasks waiting on resource
		unsigned char queue_pos;			// Next free spot in queue
		};

		
struct task_block task[numtasks];
struct resource_block resource[numresources];


// error massages
char error_msg[6][25] = {"unimplimented function",	// error 0 
	 				  	"syntax error",				// error 1 
						"illegal task ID",			// error 2 
						"illegal task state",		// error 3 
						"illegal task priority",	// error 4 
						"out of memory"				// error 5 
						};
char error_src[4][18] = {"kernel error:",			// source 0
	 				  	"kernel.c error:",			// source 1
						"kernel RTI error:",		// source 2
						"shell error:"				// source 3
						};



// FUNCTIONS

char get_task_id() { 
		 return task[current].id; 
}



int get_task_state(unsigned char id) { 

		 if (id < numtasks) {
		 	return task[id].state;
			}
		 else {
		 	  #ifdef KERNEL_ERROR_MSG
	 	 	  puts(error_src[1]); puts(error_msg[3]);
			  #endif
			return -1;
		 	}
		  
}



int get_task_messages(unsigned char id) {

	if (id < numtasks) {
	   return task[id].message;
	   }
	else {
		 #ifdef KERNEL_ERROR_MSG
	 	 puts(error_src[1]); puts(error_msg[3]);
		 #endif
		 return -1;
		 }

}



int get_task_priority(unsigned char id) { 

		 INTR_OFF();
		 
		 if (id < numtasks) {
		 	INTR_ON();
		 	return task[id].priority;
			}
		 else {
	 	 	#ifdef KERNEL_ERROR_MSG
	 	 	puts(error_src[1]); puts(error_msg[4]);
			#endif
			INTR_ON();
			return -1;
		 	}

}



int set_task_state(unsigned char id, unsigned char state) {
	
	
	INTR_OFF();
	
	
	// check id validity
	if (id < numtasks) {

	   // check state validity
	   if ((state == running) || 
	   	  (state == waiting)  ||
	   	  (state > finished)) { 
	      		 #ifdef KERNEL_ERROR_MSG
	 	 	  	 puts(error_src[1]); puts(error_msg[3]);
			  	 #endif
				 INTR_ON();
	 	  		 return -1;
	   			 }
	 
	   		switch (task[id].state) {
		   	  	   case idle:
				   		if (state == idle) {	   // no change
						   INTR_ON();
				 		   return 0;
						   }
				 		else if (state == pending) {
				 		   // pass msg to task[id].msgbox;
						   #ifdef KERNEL_ERROR_MSG
	 	 	  			   puts(error_src[1]); puts(error_msg[0]);
			  			   #endif
						   INTR_ON();
						   return -1;
				 		   }
						else if (state == finished) {
							 // pass msg to task[id].msgbox;
						     #ifdef KERNEL_ERROR_MSG
	 	 	  			     puts(error_src[1]); puts(error_msg[0]);
			  			     #endif
							 INTR_ON();
						     return -1; 
						    }
				 		else {	  // nothing else is legalox;
						   	 #ifdef KERNEL_ERROR_MSG
	 	 	  			   	 puts(error_src[1]); puts(error_msg[3]);
			  			   	 #endif
							 INTR_ON();
					  		 return -1;
				 			 }
				 		break;
		   			case pending:
						 if (state == pending) {	// no change
						 	INTR_ON();
				 		 	return 0;
							}
						 else if (state == idle) {
				   		 	  // pass msg to task[id].msgbox;
						   	  #ifdef KERNEL_ERROR_MSG
	 	 	  			   	  puts(error_src[1]); puts(error_msg[0]);
			  			   	  #endif
							  INTR_ON();
					  		  return -1;
							  }
						 else if (state == finished) {
				   		 	  // pass msg to task[id].msgbox;
						   	  #ifdef KERNEL_ERROR_MSG
	 	 	  			   	  puts(error_src[1]); puts(error_msg[0]);
			  			   	  #endif
							  INTR_ON();
					  		  return -1;
						 	  }	
						 else {
				   		 	  #ifdef KERNEL_ERROR_MSG
							  puts(error_src[1]); puts(error_msg[3]);
							  #endif
							  INTR_ON();
							  return -1;
						 	  }
						 break;

		   			case finished:
		   				 if (state == finished)	{ 	// no change
				   		 	INTR_ON();
							return 0;
							}
						 else if (state == pending) {
				   		 	  // pass msg to task[id].msgbox;
						   	  #ifdef KERNEL_ERROR_MSG
	 	 	  			   	  puts(error_src[1]); puts(error_msg[0]);
			  			   	  #endif
							  INTR_ON();
					  		  return -1;
							  }
						 else {
					 	 	  #ifdef KERNEL_ERROR_MSG
							  puts(error_src[1]); puts(error_msg[3]);
							  #endif
							  INTR_ON();
							  return -1;
							  }
						 break;
		   			default:
		   		   			#ifdef KERNEL_ERROR_MSG
							puts(error_src[1]); puts(error_msg[3]);
							#endif
							INTR_ON();
							return -1;
				   			break;
							
	 				}	// end switch (task[id].state)
					
	 		}		// if 
			
		   else {
		   		#ifdef KERNEL_ERROR_MSG
				puts(error_src[1]); puts(error_msg[2]);
				#endif
				INTR_ON();
				return -1;
				}

	 INTR_ON();

}



int set_task_priority(unsigned char id, unsigned char priority) {

	 if (priority == 0) 			 // priority 0 is reserved for the shell
	 	priority = 1;
		
	 if (id >= (numtasks)) {
	 	#ifdef KERNEL_ERROR_MSG
		puts(error_src[1]); puts(error_msg[4]);
		#endif
		return -1;
		}
	 else if ((priority > 255) || (priority < 0)) {
	 	#ifdef KERNEL_ERROR_MSG
		puts(error_src[1]); puts(error_msg[4]);
		#endif
		return -1;
		}
	 else {
	 	 task[id].priority=priority;
		 return 0;
		 }
}

