#include <9s12c32.h>
#include "HobbyKit.h"
#include "sci.h"

// **************************************************************************
// Each pin in PORT M can be configed as GPIO or a special purpose function
// related to the SPI and MSCAN subsystems.
//
// Port M GPIO :Each pin can be individually configured as a digital
//   input or output. Pins 0..3 will be in and 4,5 outputs.
// SPI         : The SPI module allows a duplex, synchronous, serial
//   communication between the MCU and peripheral devices. It is not
//   utilized in this kit.  See Motorolla document S12SPIV3.pdf for
//   details on how to utilize it.
// MSCAN       : The Motorola Scalable Controller Area Network (MSCAN)
//   is not utilized in this kit. See Motorolla document S12MSCANV2.pdf
//   for details on how to utilize it.
//
// **************************************************************************
// Each pin in PORT T can be configured as a GPIO, TIMER or PWM.
//
// PORT T GPIO  : Each pin can be individually configured as a digital
//   input or output.
// PORT T TIMERS: Each pin can be indiviaully configured as an
//  input capture/output compare channels or pin 7 as a pulse accumulator.
//  The input capture function is used to detect a selected transition
//  edge and record the time. The output compare function is used for
//  generating output signals or for timer software delays. The 16-bit
//  pulse accumulator is used to operate as a simple event counter or
//  a gated time accumulator. The pulse accumulator shares timer channel 7
//  when in event mode.  See Motorolla document S12TIM16B8CV1.pdf for further
//  details.
// PORT T PWM  : currently I cant get this to work
//
// **************************************************************************
// Each pin in PORT AD can be configured as GPIO or ADC
//
// PORT AD GPIO : Each pin can be individually configured as digital
//  input or output.
// PORT AD ADC  : Each pin can be individually configured as an analog
//  to digital converter with 8 or 10 bit resolution.
//


WORD ATDMax;         // Used to calculate RAW analog to voltage values
WORD MILLI;          // number of timer ticks for one millisecond to elapse

// Initialize      (work in progress XXX)
//   - Digital inputs
//   - Digital outputs
//   - Analog inputs
//   - PWM
//   - Input Timers
//   - Output Timers
int NanoCore12Init(int config){

   PLL_Init();           // switch to 24 Mhz
   SCI_Init(19200);   	// fastest baud rate  @ 4Mhz (=115200 at 24Mhz)

   //Timer_Init()
   TSCR1 = bit(7); // Enable TCNT
   TSCR2 = 0x03;  // divide by 8 -> 1 count = 333ns -> 3 counts = 1us
                  // max delay is 0xFFFF x 333ns = 21.8 ms
                  // Note : TOI is disarmed
   PACTL = 0;     // timer divide by (or prescale) is used by TCNT

   //Digital_Init()
   DDRM    = 0x00;  // enable input channels 0..5 on Port M
   DDRT    = 0xFF;  // enable output channels 0..7 on Port T
   PORTT   = 0x00;  // turn off digital outputs

   //Analog_init()
   switch (config){
      case 10:
         ATDCTL2 = 0x80;  // enable ADC (will be used in a busy wait loop)
         ATDCTL4 = 0x05;  // enable ADC 10 bit resolution
		                  // set Prescaler for clock speed 6-24 Mhz
         ATDMax = 1023;
         break;
         
      case 8:
         ATDCTL2 = 0x80;  // enable ADC (will be used in a busy wait loop)
         ATDCTL4 = 0x85;  // enable ADC 8 bit resolution
		                  // set Prescaler for clock speed 6-24 Mhz
         ATDMax = 255;
         break;
      case 0:             // do not init analog subsystem
         break;
      default:
         // Undefined config requested - ERROR
         config = -1;
   }

   // calculate number of TCNT ticks per milli second (used by wait() )
   MILLI = 40000U/pow(2,(TSCR2 & 0x07));   // @ 8Mhz
   if (CLKSEL & bit(7))      // PLL is set -> running faster than min speed
      MILLI = MILLI *(SYNR + 1) /(REFDV + 1);
   
   // return installed config to user program (
   return (config);

}

//
// Aquire and convert reading from portAD:pin(channel) to a voltage (0-5V)
//
float AnalogIn(BYTE channel){
   if (channel > 7) return ((float) (-1));
   return ((float)5.0*AnalogInRaw(channel)/ATDMax);   // return voltage
}

//
// Aquire analog signal from portAD:pin(channel)
//
WORD AnalogInRaw(BYTE channel){
   if (channel > 7) return ((WORD) (-1));
   ATDCTL5 = (unsigned char)channel;  // start ADC conversion
   while((ATDSTAT1&0x01)==0){};       // wait for  completion
   if (ATDMax== 255)
      return (ATDDR0H);
   else
      return (ATDDR0>>6);   // return voltage
}


//
// Get status of pin (channel) on Port M
//
BYTE DigitalIn(BYTE channel){
   if (channel > 5) return (-1);
   if ((PTM & bit(channel)) == 0) return (0);
   return (1);
}

//
// Set status to (value) of pin (channel) on Port T
//
BYTE DigitalOut(BYTE channel, BYTE value){
   if (channel > 7) return (-1);
   if (value == 0){
      PORTT &= ~(bit(channel));
   }else{
      PORTT |= bit(channel);
   }
}

// wait for interval millisec
// Note: interrupts will mess up this wait function - need to fix XXX
void wait(unsigned long interval){
   unsigned long int j;
   for (j=1; j< interval; j++){
      WORD end = TCNT + MILLI;
      while (TCNT != end);
   }
}

// raise n to the power e
long pow (short n, short e){
   int i;
   long answer=1;

   for (i=0; i<e; i++)
      answer = answer * n ;
   return (answer);
}


// Run PLL clock @ 24 MHz
//PLLCLK = 2 * OSCCLK * (SYNR + 1) / (REFDV + 1)
void PLL_Init(void){
  SYNR = 0x02;
  REFDV = 0x00;

  CLKSEL = 0x00;
  PLLCTL = 0xD1;

  while((CRGFLG&0x08) == 0); 	  // Wait for PLLCLK to stabilize.
  CLKSEL = bit(7);                // Switch to PLL clock
}


