#include <c8051f040.h>                          // SFR declarations
#include <stdio.h>					 //adding I/0 libraries
///////////////////////////////////////////////////////////////////////////
// CAN Protocol Register Index for CAN0ADR, from TABLE 18.1 of the 
// C8051F040 datasheet
///////////////////////////////////////////////////////////////////////////
#define CANCTRL            0x00               //Control Register
#define CANSTAT            0x01               //Status register
#define ERRCNT             0x02               //Error Counter Register
#define BITREG             0x03               //Bit Timing Register
#define INTREG             0x04               //Interrupt Low Byte Register
#define CANTSTR            0x05               //Test register
#define BRPEXT             0x06               //BRP Extension Register
/////////////////////////////////////////////////////////////////////////////IF1 Interface Registers
///////////////////////////////////////////////////////////////////////////
#define IF1CMDRQST         0x08              //IF1 Command Rest Register
#define IF1CMDMSK          0x09              //IF1 Command Mask Register
#define IF1MSK1            0x0A              //IF1 Mask1 Register
#define IF1MSK2            0x0B              //IF1 Mask2 Register
#define IF1ARB1            0x0C              //IF1 Arbitration 1 Register
#define IF1ARB2            0x0D              //IF1 Arbitration 2 Register
#define IF1MSGC            0x0E              //IF1 Message Control Register
#define IF1DATA1           0x0F              //IF1 Data A1 Register
#define IF1DATA2           0x10              //IF1 Data A2 Register
#define IF1DATB1           0x11              //IF1 Data B1 Register
#define IF1DATB2           0x12              //IF1 Data B2 Register
///////////////////////////////////////////////////////////////////////////
//IF2 Interface Registers
///////////////////////////////////////////////////////////////////////////
#define IF2CMDRQST         0x20              //IF2 Command Rest Register
#define IF2CMDMSK          0x21              //IF2 Command Mask Register
#define IF2MSK1            0x22              //IF2 Mask1 Register
#define IF2MSK2            0x23              //IF2 Mask2 Register
#define IF2ARB1            0x24              //IF2 Arbitration 1 Register
#define IF2ARB2            0x25              //IF2 Arbitration 2 Register
#define IF2MSGC            0x26              //IF2 Message Control Register
#define IF2DATA1           0x27              //IF2 Data A1 Register
#define IF2DATA2           0x28              //IF2 Data A2 Register
#define IF2DATB1           0x29              //IF2 Data B1 Register
#define IF2DATB2           0x2A              //IF2 Data B2 Register
///////////////////////////////////////////////////////////////////////////
//Message Handler Registers
///////////////////////////////////////////////////////////////////////////
#define TRANSREQ1          0x40              //Transmission Rest1 Register
#define TRANSREQ2          0x41              //Transmission Rest2 Register

#define NEWDAT1            0x48              //New Data 1 Register
#define NEWDAT2            0x49                 //New Data 2 Register

#define INTPEND1           0x50              //Interrupt Pending 1 Register
#define INTPEND2           0x51              //Interrupt Pending 2 Register

#define MSGVAL1            0x58               //Message Valid 1 Register
#define MSGVAL2            0x59               //Message Valid 2 Register

///////////////////////////////////////////////////////////////////////////
//ADC0 definitions
///////////////////////////////////////////////////////////////////////////
#define V_REF 3
#define BIT4 0x01 << 4
#define BIT5 0x01 << 5
#define BIT7 0x01 << 7
///////////////////////////////////////////////////////////////////////////
//TIMER Registers and definitions
///////////////////////////////////////////////////////////////////////////
#define SYSCLK // 24500000        // Internal oscillator frequency in Hz
sfr16 DP       = 0x82;               // data pointer
sfr16 RCAP2    = 0xCA;               // Timer2 reload/capture value
sfr16 RCAP3    = 0xCA;               // Timer3 reload/capture value
sfr16 RCAP4    = 0xCA;               // Timer4 reload/capture value
sfr16 TMR2     = 0xCC;               // Timer2 counter/timer
sfr16 TMR3     = 0xCC;               // Timer3 counter/timer
sfr16 TMR4     = 0xCC;               // Timer4 counter/timer
///////////////////////////////////////////////////////////////////////////
//Global Variables
///////////////////////////////////////////////////////////////////////////
char MsgNum;
char status;
int i;
int buttonstate =0x00;
sfr16 CAN0DAT = 0xD8;
int potencjometrl;
int potencjometrh;
int potencjometr;
int candacl;
int candach;
///////////////////////////////////////////////////////////////////////////
// Function PROTOTYPES
///////////////////////////////////////////////////////////////////////////

// Initialize Message Object
void clear_msg_objects (void);
void init_msg_object_TX (char MsgNum);
void init_msg_object_RX (char MsgNum);
void start_CAN (void);
void transmit_data(char MsgNum);
void receive_data (char MsgNum);
void external_osc (void);
void config_IO (void);
void ADC0(void);
void wait_ms (int ms);
void dac(void);
///////////////////////////////////////////////////////////////////////////
// MAIN Routine
///////////////////////////////////////////////////////////////////////////
void main (void) {

  // disable watchdog timer
  WDTCN = 0xde;
  WDTCN = 0xad;

  //configure Port I/O
  config_IO();

  // switch to external oscillator
  external_osc();

  // Clear CAN RAM
  clear_msg_objects();

  // Initialize message object to transmit data
  init_msg_object_TX (0x02);

  // Initialize message object to receive data
  init_msg_object_RX (0x01);

  // Enable CAN interrupts in CIP-51
  EIE2 = 0x20;

  //Function call to start CAN
  start_CAN();

  //Global enable 8051 interrupts
  EA = 1;

  //Loop and wait for interrupts
 
  while (1)
    {
	ADC0();		
 	potencjometrl=ADC0L;
	potencjometrh=ADC0H;
	wait_ms (20);
	transmit_data(0x02);
}
}


///////////////////////////////////////////////////////////////////////////
// Set up C8051F040
///////////////////////////////////////////////////////////////////////////
void wait_ms (int ms)
{
   char SFRPAGE_SAVE = SFRPAGE;        // Save Current SFR page

   SFRPAGE = TMR2_PAGE;

   TMR2CN = 0x00;                      // Stop Timer3; Clear TF3;
   TMR2CF = 0x00;                      // use SYSCLK/12 as timebase

   RCAP2 = -(SYSCLK/1000/12);          // Timer 2 overflows at 1 kHz
   TMR2 = RCAP2;

   ET2 = 0;                            // Disable Timer 2 interrupts

   TR2 = 1;                            // Start Timer 2

   while(ms){
      TF2 = 0;
      while(!TF2);                     // wait until timer overflows
      ms--;   
dac();
   }

   TR2 = 0;                            // Stop Timer 2

   SFRPAGE = SFRPAGE_SAVE;             // Restore SFRPAGE
}
// Switch to external oscillator
void dac(void)
{
REF0CN = 0x03;      // Enable DAC Bias Generator, Internal Ref Buffer  
  SFRPAGE=DAC0_PAGE;
  DAC0CN = 0x87;	//  Enable DAC 0, Update on Write to IDA0H, 2.0mA current
  DAC0L = candach;
  DAC0H = candacl;
 }
void external_osc (void)
{
  int n;                     // local variable used in delay FOR loop.
  SFRPAGE = CONFIG_PAGE;     // switch to config page to config oscillator
  OSCXCN  = 0x77;            // start external oscillator; 22.1 MHz Crystal
                                // system clock is 22.1 MHz / 2 = 11.05 MHz
  for (n=0;n<255;n++);          // delay about 1ms
  while ((OSCXCN & 0x80) == 0); // wait for oscillator to stabilize
  CLKSEL |= 0x01;               // switch to external oscillator
}

void config_IO (void)
{
  SFRPAGE  = CONFIG_PAGE;        //Port SFR's on Configuration page
  XBR3     = 0x80;     // Configure CAN TX pin (CTX) as push-pull digital   
                       // output
  P0MDOUT  = 0xFF;     // Configure P1.6 as push-pull to drive LED
  P1MDIN   = 0xFF;
  XBR2     = 0x40;     // Enable Crossbar/low ports
  buttonstate = P1;
}

void ADC0(void)
{
  SFRPAGE  = ADC0CN;
  REF0CN  = 0x03;   /* Set voltage reference to "internal"              */
  ADC0CF  = 0xF8;   /* Set analog amp gain to 1.0                       */
  ADC0CN |= BIT7;   /* Set AD1EN to activate the ADC                    */

/* Start first sample */ 
  ADC0CN &= (0xFF ^ BIT5);  /* Clear AD1INT flag                        */
  ADC0CN |= BIT4;           /* Set AD1BUSY flag, this starts conversion */
      if(ADC0CN & BIT5)
    {
		 
      ADC0CN &= (0xFF ^ BIT5);  /* Clear AD1INT flag                         */
      ADC0CN |= BIT4;           /* Set AD1BUSY flag, this starts conversion  */


  }

}
///////////////////////////////////////////////////////////////////////////
//CAN Functions
///////////////////////////////////////////////////////////////////////////

//Clear Message Objects
void clear_msg_objects (void)
{
  SFRPAGE  = CAN0_PAGE;
  CAN0ADR  = IF1CMDMSK;    // Point to Command Mask Register 1
  CAN0DATL = 0xFF;         // Set direction to WRITE all IF registers to 
                           // Msg Obj
  for (i=1;i<33;i++)
    {
      CAN0ADR = IF1CMDRQST; // Write blank (reset) IF registers to each msg 
				    //obj
      CAN0DATL = i;
    }
	    
}

//Initialize Message Object for RX
void init_msg_object_RX (char MsgNum)
{
  SFRPAGE  = CAN0_PAGE;

  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x00F8;     // Set to WRITE, and alter all Msg Obj except ID 
 // MASK
                         // and data bits
  CAN0ADR  = IF1ARB1;    // Point to arbitration1 register
  CAN0DAT  = 0x0000;     // Set arbitration1 ID to "0"
  CAN0DAT  = 0x8004;     // Arb2 high byte:Set MsgVal bit, no extended ID,
                         // Dir = RECEIVE
  CAN0DAT  = 0x0480;     // Msg Cntrl: set RXIE, remote frame function 
 // disabled
  CAN0ADR  = IF1CMDRQST; // Point to Command Request reg.
  CAN0DATL = MsgNum;     // Select Msg Obj passed into function parameter 
 // list
                         // --initiates write to Msg Obj
  // 3-6 CAN clock cycles to move IF register contents to the Msg Obj in 
  // CAN RAM
}

//Initialize Message Object for TX
void init_msg_object_TX (char MsgNum)
{
  SFRPAGE = CAN0_PAGE;
  CAN0ADR = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT = 0x00F3;     // Set to WRITE, & alter all Msg Obj except ID MASK 
// bits
  CAN0ADR = IF1ARB1;    // Point to arbitration1 register
  CAN0DAT = 0x0000;     // Set arbitration1 ID to highest priority
  CAN0DAT = 0xA055;     // Autoincrement to Arb2 high byte:
                        // Set MsgVal bit, no extended ID, Dir = WRITE
  CAN0DAT = 0x0086;     // Msg Cntrl: DLC = 3, remote frame function not 
// enabled
  CAN0ADR = IF1CMDRQST; // Point to Command Request reg.
  CAN0DAT = MsgNum;     // Select Msg Obj passed into function parameter 
// list
                        // --initiates write to Msg Obj
  // 3-6 CAN clock cycles to move IF reg contents to the Msg Obj in CAN 
  // RAM.
}

//Start CAN
void start_CAN (void)
{
  /* Calculation of the CAN bit timing :

  System clock        f_sys = 22.1184 MHz/2 = 11.0592 MHz.
  System clock period t_sys = 1/f_sys = 90.422454 ns.
  CAN time quantum       tq = t_sys (at BRP = 0)

  Desired bit rate is 1 MBit/s, desired bit time is 1000 ns.
  Actual bit time = 11 tq = 996.65ns ~ 1000 ns
  Actual bit rate is 1.005381818 MBit/s = Desired bit rate+0.5381%

  CAN bus length = 10 m, with 5 ns/m signal delay time.
  Propagation delay time : 2*(transceiver loop delay + bus line delay) = 400 ns
  (maximum loop delay between CAN nodes)

  Prop_Seg = 5 tq = 452 ns ( >= 400 ns).
  Sync_Seg = 1 tq

  Phase_seg1 + Phase_Seg2 = (11-6) tq = 5 tq
  Phase_seg1 <= Phase_Seg2,  =>  Phase_seg1 = 2 tq and Phase_Seg2 = 3 tq
  SJW = (min(Phase_Seg1, 4) tq = 2 tq

  TSEG1 = (Prop_Seg + Phase_Seg1 - 1) = 6
  TSEG2 = (Phase_Seg2 - 1)            = 2
  SJW_p = (SJW - 1)                   = 1

  Bit Timing Register = BRP + SJW_p*0x0040 = TSEG1*0x0100 + TSEG2*0x1000 = 2640

  Clock tolerance df :

  A: df < min(Phase_Seg1, Phase_Seg2) / (2 * (13*bit_time - Phase_Seg2))
  B: df < SJW / (20 * bit_time)

  A: df < 2/(2*(13*11-3)) = 1/(141-3) = 1/138 = 0.7246%
  B: df < 2/(20*11)                   = 1/110 = 0.9091%

  Actual clock tolerance is 0.7246% - 0.5381% = 0.1865% (no problem for quartz)
  */
  SFRPAGE  = CAN0_PAGE;
  CAN0CN  |= 0x41;       // Configuration Change Enable CCE and INIT
  CAN0ADR  = BITREG   ;  // Point to Bit Timing register
  CAN0DAT  = 0x2640;     // see above

  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x0087;     // Config for TX : WRITE to CAN RAM, write data 
 // bytes,
                         // set TXrqst/NewDat, clr IntPnd
  // RX-IF2 operation may interrupt TX-IF1 operation
  CAN0ADR  = IF2CMDMSK;  // Point to Command Mask 2
  CAN0DATL = 0x1F;       // Config for RX : READ CAN RAM, read data bytes,
                         // clr NewDat and IntPnd
  CAN0CN  |= 0x06;       // Global Int. Enable IE and SIE
  CAN0CN  &= ~0x41;      // Clear CCE and INIT bits, starts CAN state 
 // machine
}

//Transmit CAN frame to turn other node's LED ON
void transmit_data (char MsgNum)
{
  SFRPAGE  = CAN0_PAGE;  // IF1 already set up for TX

  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x0087;     // Config to WRITE to CAN RAM, write data bytes,
                         // set TXrqst/NewDat, Clr IntPnd
  CAN0ADR  = IF1DATA1;   // Point to 1st byte of Data Field
  CAN0DATH = P0;	 	 //Transmit:  diods state,
  CAN0DATL = P1;         // bottom state,
  CAN0DATH = potencjometrh;   // potnecjometer high bits,
  CAN0DATL = potencjometrl>>4;   // potencjometer low bits,
  CAN0DATH = potencjometrl&0x0F; 
  buttonstate = P1;
  
  CAN0ADR  = IF1CMDRQST; // Point to Command Request Reg.
  CAN0DATL = MsgNum;     // Move new data for TX to Msg Obj "MsgNum"
}

// Receive Data from the IF2 buffer
void receive_data (char MsgNum)
{
  char virtual_button;
  SFRPAGE  = CAN0_PAGE; // IF1 already set up for RX
  CAN0ADR  = IF2CMDRQST;// Point to Command Request Reg.
  CAN0DATL = MsgNum;    // Move new data for RX from Msg Obj "MsgNum"
                        // Move new data to a
  CAN0ADR  = IF2DATA1;  // Point to 1st byte of Data Field

  virtual_button = CAN0DATL;
  P0=virtual_button;          
  CAN0ADR  = IF2DATA2;  // Point to 1st byte of Data Field
  candach = CAN0DATH;
  candacl = CAN0DATL;
}

////////////////////////////////////////////////////////////////////////////////
//Interrupt Service Routine
////////////////////////////////////////////////////////////////////////////////
void ISRname (void) interrupt 19
{
  status = CAN0STA;
  if ((status&0x10) != 0)
    {                         // RxOk is set, interrupt caused by reception
      CAN0STA = (CAN0STA&0xEF)|0x07;     // Reset RxOk, set LEC to NoChange
      /* read message number from CAN INTREG */
      receive_data (0x01);       // Up to now, we have only one RX message
    }
  if ((status&0x08) != 0)
    {                       // TxOk is set, interrupt caused by transmision
      CAN0STA = (CAN0STA&0xF7)|0x07;     // Reset TxOk, set LEC to NoChange
    }
  if (((status&0x07) != 0)&&((status&0x07) != 7))
    {                           // Error interrupt, LEC changed
      /* error handling ? */
      CAN0STA = CAN0STA|0x07;              // Set LEC to NoChange
    }
}
