/*
 * os.c - os
 *
 * Global variable definitions.
 * Some os related functions.  These could be elsewhere.
 * 
 * interrupt vectors
 *   Since we are working with eeprom, normally write protected,
 *   the interrupt vectors are each pointed to a 3-byte block
 *   at the top of RAM.  Each block consists of an opcode, a
 *   task pointer, and an rti instruction.
 *   There are 20 interrupt vectors,
 *
 * sci_sect     ORIGIN = 0x7FC4
 * spi_sect	    ORIGIN = 0x7FC7
 * pai_sect     ORIGIN = 0x7FCA
 * pao_sect	    ORIGIN = 0x7FCD
 * tof_sect	    ORIGIN = 0x7FD0
 * toc5_sect    ORIGIN = 0x7FD3
 * toc4_sect    ORIGIN = 0x7FD6
 * toc3_sect    ORIGIN = 0x7FD9
 * toc2_sect    ORIGIN = 0x7FDC
 * toc1_sect    ORIGIN = 0x7FDF
 * tic3_sect    ORIGIN = 0x7FE2
 * tic2_sect    ORIGIN = 0x7FE5
 * tic1_sect    ORIGIN = 0x7FE8
 * rti_sect     ORIGIN = 0x7FEB
 * irq_sect	    ORIGIN = 0x7FEE
 * xirq_sect    ORIGIN = 0x7FF1
 * swi_sect	    ORIGIN = 0x7EF4
 * illop_sect   ORIGIN = 0x7EF7
 * cop_sect	    ORIGIN = 0x7FFA
 * clkfail_sect	ORIGIN = 0x7FFD
 *
 * $Id: os.c,v 1.11 2002/08/02 20:05:07 tomdean Exp $
 *
 */

#include <os.h>
#include <sys/regs.h>

/*
 * trace.  use like:
 *
 * trace_t *trace;
 * trace = (trace_t *)*next_trace;
 * trace->task = cur_task;
 * trace->cmd = cmd;
 * trace->cmd_arg = 0;
 * for (i=0; i<NUM_TASK+1; i++) {
 *   trace->state[i] = context[i].state;
 *   trace->stack[i] = context[i].sp;
 * }
 * *next_trace = (unsigned short)++trace;
 */
trace_t *next_trace;

/*
 * number of the current running task
 */
unsigned char cur_task;

/*
 * for task switch - initial value set in main.c
 */
unsigned char tocks __attribute__((section((".page0"))));

/*
 * for counting ticks...
 */
unsigned long tick_count;

/*
 * context structures, one for each task plus the null task
 */
context_t *context[NUM_TASK+1];

/*
 * control for swi()
 */
sys_call_t sys_call[NUM_TASK+1] __attribute__((section((".page0"))));

/*
 * timers - the index is the task number, which is 1..8
 * The value of timer[n] is in rti's, decremented each rti.
 */
unsigned short timer[NUM_TASK+1];

/*
 * message queue, one for each task
 * the index is task number, which is 1..8
 */
msg_t *msg_queue[NUM_TASK+1];

/*
 * sci buffer and control
 */
msg_t sci_buf[NUM_SCI];  /* how many do we need? */
msg_t *cur_sci_buf;

/*
 * gps message variables
 */
unsigned short gpbod_count;
unsigned short gpgga_count;
unsigned short gpgll_count;
unsigned short gpgsa_count;
unsigned short gpgsv_count;
unsigned short gprmb_count;
unsigned short gprmc_count;
unsigned short gprte_count;
unsigned short gpwpl_count;
unsigned short pgrme_count;
unsigned short pgrmm_count;
unsigned short pgrmz_count;
unsigned short ignore_count;

/*
 * lcd display buffers
 */
unsigned char lcd_row_1[41]; /* need room for null termination */
unsigned char lcd_row_2[41]; /* need room for null termination */
unsigned char lcd_row_3[41]; /* need room for null termination */
unsigned char lcd_row_4[41]; /* need room for null termination */
unsigned char error1[41];    /* put in row 1 if DEBUG */
unsigned char error3[41];    /* put in row 3 if DEBUG */
unsigned char error3_in_use; /* change the use or error3 */
/*
 * set the requested interrupt vector to point to the specified task
 */
void add_handler(vector_t *vector, task_t task) {
  vector->opcode = JMP; /* jmp */
  vector->task   = (unsigned short)task;
  return;
}

/*
 * set the specified interrupt vector to dismiss
 */
void clear_handler(vector_t *vector, task_t task) {
  vector->opcode = RTI; 
  vector->task   = 0;
  return;
}

/*
 * task init - initialize a task for future activation
 *
 *  +-------+
 *  | pc    |
 *  +-------+
 *  | y     |
 *  +-------+
 *  | x     |
 *  +-------+
 *  | d     |
 *  +-------+
 *  | ccr   |
 *  +-------+
 *  | _.tmp |
 *  +-------+
 *  | _.z   |
 *  +-------+
 *  | _.xy  |
 *  +-------+
 *  |  prev |  main's _.frame
 *  |_.frame|
 *  +-------+
 *  | _.d1  |
 *  +-------+
 *  | _.d2  |
 *  +-------+
 *  | _.d3  |
 *  +-------+
 *  | _.d4  |
 *  +-------+
 *  | _.d5  |
 *  +-------+
 *  | _.d6  |
 *  +-------+
 *  | _.d7  |
 *  +-------+
 *  | _.d8  |
 *  +-------+
 *  |       |<-- sp
 */

void task_init(unsigned char task_num, task_t task, unsigned char *stack) {
  context_t *ptr = context[task_num];
  ptr->sp = (unsigned short)stack+STACK_SIZE-34;
  ptr->state = ready;
  /* set pc */
  *(unsigned short *)&stack[STACK_SIZE-2 ] = (unsigned short)task;
  /* ccr */
  *(unsigned short *)&stack[STACK_SIZE-9 ] = 0;
  /* prev _.frame */
  *(unsigned short *)&stack[STACK_SIZE-17] = __frame;  /* main's frame */
}

/*
 * convert a word bin to hex-ascii in buffer ptr
 * this looks long, but, the compiler will fix it
 */
void hex_to_ascii_4(unsigned short value, unsigned char *ptr) {
  register unsigned char n;
  
  n = (unsigned char)((value >> 12)&0x0f);
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
  
  n = (unsigned char)((value >> 8)&0x0f);
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
  
  n = (unsigned char)((value >> 4)&0x0f);
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
   
  n = (unsigned char)value&0x0f;
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
 
  return;
}

/*
 * convert a byte bin to hex-ascii in buffer ptr
 */
void hex_to_ascii_2(unsigned char value, unsigned char *ptr) {
  register unsigned char n;
  
  n = ((value >> 4)&0x0f);
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
   
  n = value&0x0f;
  if (n < 10) *ptr++ = n + '0';
  else        *ptr++ = n + '7';
 
  return;
}

/*
 * convert 4 ascii bytes to a short
 */
unsigned short ascii_to_hex_4(unsigned char *ptr) {
  register unsigned short value;
  register unsigned char ch;
  register unsigned short idx;

  value = 0;
  for (idx=0; idx<4; idx++) {
	value <<= 4;
	ch = *ptr++;
	if (ch > 'Z') ch -= 0x20; /* fold it all into 0x00..0x */
	if (ch > '9') value += ch - '7';
	else          value += ch - '0';
  }
  
  return value;
}

/*
 * convert 2 ascii bytes to a short
 */
unsigned short ascii_to_hex_2(unsigned char *ptr) {
  register unsigned char value;
  register unsigned char ch;
  register unsigned short idx;

  value = 0;
  for (idx=0; idx<2; idx++) {
	value <<= 4;
	ch = *ptr++;
	if (ch > 'Z') ch -= 0x20; /* fold it all into 0x00..0x */
	if (ch > '9') value += ch - '7';
	else          value += ch - '0';
  }
  
  return value;
}
