/*
 * os.h - os defines
 *
 * $Id: os.h,v 1.17 2002/08/03 17:52:57 tomdean Exp $
 */

#ifndef _OS_H_INCLUDED
#define _OS_H_INCLUDED

/*
 ********************************************************
 * structures
 */

/*
 * if DEBUG is defined, use error1 and error3 rather than lcd_row_x */
/*  #define DEBUG 1 */
/*  #define SHOW_GPS_COUNT */
#define SHOW_GPS_DATA 1

/* number of tasks */
#define NUM_TASK 8

/* trace */
typedef struct trace_t {
  unsigned char task;
  unsigned char cmd;
  unsigned char cmd_arg;
  unsigned char state[NUM_TASK+1];
  unsigned short stack[NUM_TASK+1];
} trace_t;

extern trace_t *next_trace;

/* task state */
typedef enum {
  halt,
  wait_timer,
  wait_msg,
  run,
  ready
} state_t;

/* system calls */
typedef enum {
  sys_wait_timer,
  sys_stop,
  sys_start,
  sys_send,
  sys_recv,
  sys_recv_wait,
  sys_queue,
  sys_dequeue,
  sys_done
} operation_t;

/* context */
typedef struct context_t {
  unsigned short sp;
  state_t state;
} context_t;

/* interrupt vector */
typedef struct vector_t {
  unsigned char  opcode;
  unsigned short task;
} vector_t;

#define MSG_BUF_SIZE 82
/*
 * task message queue
 * A GPS message may have 81 characters in it!
 */
#define MSG_BUF_SIZE 82
typedef struct msg_t {
  unsigned char task;         /* from task */
  unsigned char empty;        /* are we done with it? */
  struct msg_t *next;         /* linked list */
  /* XXX fix me what is the longest gps message? */
  unsigned char buf[MSG_BUF_SIZE];  /* msg body */
} msg_t;

extern msg_t *msg_queue[];

#ifndef NULL
#define NULL 0
#endif

/*
 * system call
 * status
 *  success
 *  failure unknown reason or lazy coding on my part
 *  unsupported operation
 *  illegal task number
 *  destination queue full
 */
typedef enum {
  success,
  gen_failure,
  unsupported_op,
  ill_task_num,
  dest_que_full
} sys_call_stat_t;

/* and, the structure */
typedef struct sys_call_t {
  unsigned char   operation;
  unsigned char   task_num;
  unsigned short  timer;
  sys_call_stat_t status;
  msg_t          *msg_ptr;
} sys_call_t;

/*
 * system call structures, one for each task
 * the index is task number, which is 1..8
 */
extern sys_call_t sys_call[];
/*
 * use these defines to access the system functions in swi()
 * you can manipulate the structure and do an swi() directly,
 * but, it is easier to make a mistake.  Don't blame me if strange
 * things start to happen...
 */
#define SYS_OP sys_call[cur_task].operation
#define SYS_TIMER sys_call[cur_task].timer
#define SYS_TASK sys_call[cur_task].task_num
#define SYS_MSG sys_call[cur_task].msg_ptr
#define SYS_WAIT_TIMER(n) SYS_OP=sys_wait_timer; SYS_TIMER=n; swi()
#define SYS_STOP(t) SYS_OP=sys_stop;  SYS_TASK=t; swi()
#define SYS_START(t) SYS_OP=sys_start;  SYS_TASK=t; swi()
#define SYS_SEND(t, m) SYS_OP=sys_send; SYS_TASK=t; SYS_MSG=m; swi()
#define SYS_RECV(m) SYS_OP=sys_recv; swi(); m = SYS_MSG
#define SYS_RECV_WAIT(m) SYS_OP=sys_recv_wait; swi(); m = SYS_MSG
#define SYS_QUEUE(t, m) SYS_OP=sys_send; SYS_TASK=t; SYS_MSG=m; swi()
#define SYS_DEQUEUE(m) SYS_OP=sys_dequeue; swi(); m = SYS_MSG
#define SYS_DONE() SYS_OP=sys_done; swi()

/*
 * definitions for tasks
 */
#define TASK1    1
#define TASK2    2
#define ADC_TASK 3
#define GPS_TASK 4
#define TASK5    5
#define CLI_TASK 6
#define TASK7    7
#define DIS_TASK 8

/*
 * system clock definitions
 */

typedef struct m6811_clock_t {
  unsigned char ticks;
  unsigned char seconds;
  unsigned char minutes;
  unsigned char hours;
  unsigned char days;
  unsigned char months;
  unsigned short years;
} m6811_clock_t;

extern m6811_clock_t m6811_clock;

extern unsigned long tick_count;

/*
 * interrupt vector locations.  Note: this changed after 7/23/2002.
 */
#define sci_sect_vector     (vector_t *)0x7FC4
#define spi_sect_vector	    (vector_t *)0x7FC7
#define pai_sect_vector     (vector_t *)0x7FCA
#define pao_sect_vector	    (vector_t *)0x7FCD
#define tof_sect_vector	    (vector_t *)0x7FD0
#define toc5_sect_vector    (vector_t *)0x7FD3
#define toc4_sect_vector    (vector_t *)0x7FD6
#define toc3_sect_vector    (vector_t *)0x7FD9
#define toc2_sect_vector    (vector_t *)0x7FDC
#define toc1_sect_vector    (vector_t *)0x7FDF
#define tic3_sect_vector    (vector_t *)0x7FE2
#define tic2_sect_vector    (vector_t *)0x7FE5
#define tic1_sect_vector    (vector_t *)0x7FE8
#define rti_sect_vector     (vector_t *)0x7FEB
#define irq_sect_vector	    (vector_t *)0x7FEE
#define xirq_sect_vector    (vector_t *)0x7FF1
#define swi_sect_vector	    (vector_t *)0x7FF4
#define illop_sect_vector   (vector_t *)0x7FF7
#define cop_sect_vector	    (vector_t *)0x7FFA
#define clkfail_sect_vector (vector_t *)0x7FFD

/* m68hc11 instructions */
#define RTI 0x3b
#define JMP 0x7e

/*
 * task stack size.
 * XXX fix me - change this to have a stack definition for each task
 *              to allow tuning the stack size for task requirements
 */
#define STACK_SIZE 80

/*
 * rti() decrements tocks, and, when zero, does a context switch to
 * the next ready task in a round-robin fashion.
 * Normally, there are 4 ticks per tock.  This may be changed
 * by setting TICKS_PER_TOCK
 * looks like the display task may need ~ 20 msec
 */
#define TICKS_PER_TOCK 6
extern unsigned char tocks;

/*
 * debug outputs on porta
 */
#define DEBUG_ON(n)  _io_ports[M6811_PORTA] |= n;
#define DEBUG_OFF(n) _io_ports[M6811_PORTA] &= ~n;

/*
 ********************************************************
 * prototypes
 */
typedef void(*task_t)(void);

void add_handler(vector_t *, task_t);

void clear_handler(vector_t *, task_t);
void task_init(unsigned char, task_t, unsigned char *);

/* swi functions */
void put_message(unsigned char, msg_t *);
void get_message();

/* sci functions */
void sci_init();
void sci_send(unsigned char *);

/* display functions */
void display();
void display_init();
void display_clear();

/* gps functions */
void gps();
void gps_init();
void show_gps_count();

/* short hand */
#define TRAP(x) void x() __attribute__((trap))
#define INTERRUPT(x) void x() __attribute__((interrupt))

/*
 * prototypes for trap and interrupt routines
 * Using this format allows the routine to be defined
 * as 'void xxx()' in the source file
 */
TRAP(swi);
INTERRUPT(sci);
INTERRUPT(rti);

/* short hand */
#define TASK(x) void task##x()
#define STACK(x) extern unsigned char stack##x[]

/*
 * define the tasks and the respective stack
 */
TASK(1);  STACK(1);
TASK(2);  STACK(2);
/* task 3 */
void adc();
extern unsigned char adc_stack[];
/* task 4 */
void gps();
extern unsigned char gps_stack[];
TASK(5);  STACK(5);
/* task 6 */
void cli();
extern unsigned char cli_stack[];
TASK(7);  STACK(7);
/* task 8 */
void display();
extern unsigned char display_stack[];

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

/* context pointers and definitions related to context switch */
extern context_t *context[];
#define PSH_SOFT_REG(x) asm("ldx %0"::"m"( x )); asm("pshx")
#define POP_SOFT_REG(x)  asm("pulx"); asm("stx %0":"=m"( x ))
#define SET_SP(x) asm("lds %0" ::"m" ( x ))
#define SAV_SP(x) asm("sts %0" ::"m" ( x ))
#define POP_FRAME_Y asm("puly")
#define PSH_FRAME_Y asm("pshy")

/* timers - the index is task_num, which is 1..8 */
extern unsigned short timer[];

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

/*
 * sci buffer and control
 */
#define NUM_SCI 8
extern msg_t sci_buf[];
extern msg_t *cur_sci_buf;

/*
 * convert a word bin to hex-ascii in buffer ptr
 */
void hex_to_ascii_4(unsigned short, unsigned char *);
void hex_to_ascii_2(unsigned char,  unsigned char *);

#endif
  
