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

// This program reads from the serial port and acts as a slave to perform:
// 1) an n-point read from any analog input  (PORT AD 0..7)
// 2) an n-point read from all digital input (PORT M 0..5)
// 3) a signle write to all digital outputs (PORT T 0..7)
//
//
// If the requested action is a digital write then the next byte is written
//
// If the requested action is a digial read or an analog read then the
// the following 4 additional inputs are required.
//   1) channel 0..7
//   2) mantissa of delay
//   3) abs(exponent) of delay (a negative number is assumed)
//   4) number of points to aquire
//
// The analog output is a list 8 bit resolution numbers. A ":" preceeds the list
// The digital output is a list of 5 bit digital values encoded as the lower
// bits in a BYTE. (i.e. PORT M bit 4 status  = > bit 4 status
//
// The delay time between points = mantissa * 10^(-1 * exponent) seconds
//
// Note: It takes 7us to measure the analog signal.
//
//
// Using the predefined (Timer Counter) = (BUS CLOCK) / 8 from NanoCore12Init()
// we find that the max delay in 0xFFFF counts in 21ms. To increase this max
// delay a loop over TCNT timer counts was added. A loop being 0xFFFF
// timer counts. The total delay is seperated into how many loops and
// then TCNT counts.
//
//       Min delay  : 10 us (mantissa=10, exponent=5
//       Max delay  : (0xFFFF +1) * .021s = 1376s (roughly 23 min)
//
// note :BYTE is unsigned  8 bits
//      :WORD is unsigned 16 bits
//
//

#define GET_ANALOG    0
#define GET_DIGITAL   1
#define SET_DIGITAL   2

void main (void){
   // init NanoCore12 with 8 bit analog->digital resolution
   NanoCore12Init(8);

   for (;;){
      BYTE data[1000];  // array to hold the measured data
      WORD i;           // counter in loops
      BYTE channel;     // the channel to perfrom ATD on
      WORD mantissa;    // mantissa of the delay between samples
      BYTE exponent;    // neg exponent of the delay between samples
      WORD numPoints;   // number of points to record
      BYTE action;      // 0=measure Analog, 1=measure Digital, 2=set Digital

      //
      // Get requested action
      //
      action   = SCI_InUDec();
      
      // if requested action is to set digital outputs
      if (action == SET_DIGITAL) {
         DigitalOutAll = SCI_InUDec();
         continue;         // request processed - go get another
      }
      
      // otherwise continue for digital or analog inputs
      channel  = SCI_InUDec();
      mantissa = SCI_InUDec();
      exponent = SCI_InUDec();
      numPoints= SCI_InUDec();


       
      // Calculate the delay to wait between sample.
      // Note: It takes 7us to perform ATD conversion on 10 bits but I cant
      // find a reference for 8 bits.
     long full_delay = pow(10, 6-exponent) * mantissa * 3;
     WORD loops = (full_delay / 0xFFFF);
     WORD delay =  (full_delay % 0xFFFF);

     // record data at periodic intervals
      for (i=0; i<numPoints; i++){
         // * IMPORTANT * Calculate end of delay settings before aquiring data
         WORD j;                   // counter for loop over # of datapoints
         WORD start= TCNT;         // start timer count
         WORD end = start + delay; // end   timer count

         //
         // Gather Data
         //
         if (action == GET_ANALOG)                 // if request is analog
            data[i] =(BYTE)AnalogInRaw(channel);   // measure and store channel
         else                                      // if request is digital
            data[i] = DigitalInAll;                // measure and store channels

         // we dont need to perform the last wait because there is no
         // more data to collect
         if (i==numPoints-1) break;
         
         //
         // Wait is a two step game:
         //
         // Step 1: (big) Wait for one loop = 0xFFFF timer counts
         //
         for (j=0; j< loops; j++){
            while(TCNT != start-1);      // wait for TCNT to return to start
            while(TCNT != start);        // ...
         }
         //
         //Step 2: (small) Wait for TCNT to get to end
         //
         while(TCNT != end);
      }

      //
      // Send data over serial port to PC
      //
      print (":");                           //start of data indicator
      for (i=0; i<numPoints; i++){
         SCI_OutChar(data[i]);               // send data to PC
      }
   }
}
