SCI.c

//#define TEST
/****************************************************************************
 Module
     SCI.c
 
 Description
     Contains functions for using the SCI subsystem on the E128. 

 Notes
 
 
 History
 When           Who     What/Why
 -------------- ---     --------
 April 2010     NRM     Started Coding
****************************************************************************/
 
/*----------------------------- Include Files -----------------------------*/
#include <hidef.h>      /* common defines and macros */
#include <mc9s12e128.h>     /* derivative information */
#include <stdio.h>
#include <stdlib.h>
#include <S12E128bits.h> /* E128 bit definitions  */
#include <bitdefs.h> /* BIT0HI, BIT0LO....definitions */
#include "S12eVec.h"
#include "S12Vec.h"
#include "HC_Controller.h"
#include "SCI.h"
#include "servo.h"
 
#pragma LINK_INFO DERIVATIVE "SampleS12"
 
/*----------------------------- Module Defines ----------------------------*/
#define Number_of_Bytes_In_Message 15
#define START_BYTE 0x7E
#define LENGTH_MSB 0x00
#define LENGTH_LSB 11
#define API_TRANSMIT 0x01
#define FRAME_ID 0x08
#define OPTIONS 0x00
#define CRAFT_MSB 0x21
#define CRAFT_LSB 0x83
#define NEPTUNE_MSB 0x77
#define NEPTUNE_LSB 0x77
#define _BOADCAST_ 0x02
#define _PERSONAL_ 0x00
#define _TEAM_MESSAGE_ 0x01
#define _CIPHER_MESSAGE_ 0x02
#define _CRAB_MESSAGE_ 0x03
 
/*------------------------------ Module Types -----------------------------*/
// struct for messages
typedef struct {
  unsigned char Contents[Number_of_Bytes_In_Message];  // Contents of Messege
  int Index_Counter;  // Index
  int Length;         // total length of packet
} _MESSAGE_;
 
// struct to hold user inputs
typedef struct {
  unsigned char Left_Prop;   // Duty Cycle for Left Propeller
  unsigned char Right_Prop;  // Duty Cycle for Right Propeller
  unsigned char Pump;        // Duty Cycle for Pump
  unsigned char Left_Aim_Gun;// Duty Cycle for Left Gun Aim
  unsigned char Right_Aim_Gun;// Duty Cycle for Right Gun Aim
  unsigned char Turbo_Prop;   // Duty Cycle for Turbo Prop
} _INPUTS_;
 
/*---------------------------- Module Functions ---------------------------*/
void SCI_Init(void);
unsigned char SCI_Receive(void);
void Process_Message();
void Compile_Message(unsigned char[]);
void Send_Message(void);
char Query_Received_Cipher_Flag(void);
char Query_GO_Flag(void);
char Query_New_Message_Flag(void);
char Query_In_Flag(void);
 
/*---------------------------- Module Variables ---------------------------*/
_MESSAGE_ OutgoingMessage; // _MESSAGE_ struct for outgoing message
_MESSAGE_ IncomingMessage; // _MESSAGE_ struct for incoming message
_MESSAGE_ IncMessageBuffer; // _MESSAGE_ for incoming message buffer
_INPUTS_ UserInputs; // _INPUTS_ struct for user inputs
 
unsigned char CIPHER = 0xAA; // initialize cipher to 0xAA (same as boat)
unsigned char MyTeam = 0x44; // initialize to white team
char New_Message_Flag = 0;   // initialize flag for new message
char Received_Cipher_Flag = 0; // initalize flag for cipher received
char GO_Flag = 0; // initialize flag for neptune GO received
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     SCI_Init()
 
 Parameters
 
 
 Returns
     None.
 
 Description
     Initializes SCI system on E128
 
 Notes
 
 
 Author
     Nick Musser
****************************************************************************/
void SCI_Init(void)
{
   unsigned char dummy;   // Create dummy variable for clearing interrupt flag
 
   OutgoingMessage.Index_Counter = 0;
   OutgoingMessage.Length = Number_of_Bytes_In_Message;
   IncomingMessage.Index_Counter = 0;
   IncomingMessage.Length = Number_of_Bytes_In_Message;
 
   // Configure Baud Rate Registers (SCI1BDH, SCI1BDL)
   // Set baud rate to 9600
   SCI1BDH = 0x00;
   SCI1BDL = 0x9C;
 
   // Configure SCI Control Register 1 (SCI1CR1)
   // Leave defaults: 8 data bits and Idle line wakeup
 
   // Configure SCI Control Register 2 (SCI1CR2)
   SCI1CR2 |= (_S12_TE | _S12_RE);   // Enable Transmitter and Reciever
 
   dummy = SCI_Receive(); //clears receiver interrupt flag
 
   EnableInterrupts;      // Enable Interrupts globally
}
 
/****************************************************************************
 Function
     SCI_Receive()
 
 Parameters
     None
 
 Returns
     Returns the byte of data from the SCI Receive Register in the form
     of a char
 
 Description
     Clears the receive interrupt flag and returns the byte of data.
 
 Notes
     This will most likely be called in the interrupt response routine
     following a receive.
 
 Author
     Nick Musser
****************************************************************************/
unsigned char SCI_Receive(void)
{
  static unsigned char Message_Byte;
  if(SCI1SR1 & _S12_RDRF)  // If the recieve flag has been set
      {
        // Read SCI1SR1 and SCIDRL to clear the flag
            Message_Byte = SCI1DRL;       // Read SCI Data Register Low
            return Message_Byte;      // Return the byte of data
      }
}
 
/****************************************************************************
 Function
     Compile_Message()
 
 Parameters
 
 
 Returns
     None.
 
 Description
     Stuffs the user inputs into the outgoing message stuct
 
 Notes
 
 
 Author
     Nick Musser
****************************************************************************/
void Compile_Message(unsigned char User_Inputs[6])
{
    unsigned char checksum;
    checksum = API_TRANSMIT + FRAME_ID + CRAFT_MSB + CRAFT_LSB + OPTIONS + User_Inputs[0] + User_Inputs[1] + User_Inputs[2] + User_Inputs[3] + User_Inputs[4] + User_Inputs[5];
    checksum = 0xFF - checksum;
 
    OutgoingMessage.Contents[0] = START_BYTE;
    OutgoingMessage.Contents[1] = LENGTH_MSB;
    OutgoingMessage.Contents[2] = LENGTH_LSB;
    OutgoingMessage.Contents[3] = API_TRANSMIT;
    OutgoingMessage.Contents[4] = FRAME_ID;
    OutgoingMessage.Contents[5] = CRAFT_MSB;
    OutgoingMessage.Contents[6] = CRAFT_LSB;
    OutgoingMessage.Contents[7] = OPTIONS;
    OutgoingMessage.Contents[8] = User_Inputs[0]; //Left_Prop;
    OutgoingMessage.Contents[9] = User_Inputs[1]; //Right_Prop;
    OutgoingMessage.Contents[10] = User_Inputs[2]; //Pump;
    OutgoingMessage.Contents[11] = User_Inputs[3]; //Left_Aim_Gun;
    OutgoingMessage.Contents[12] = User_Inputs[4]; //Right_Aim_Gun;
    OutgoingMessage.Contents[13] = User_Inputs[5]; //Turbo_Prop;
    OutgoingMessage.Contents[14] = checksum;
} // end of function
 
/****************************************************************************
 Function
     Send_Message()
 
 Parameters
     None
 
 Returns
     None
 
 Description
     Resets the OutgoingMessage Index Counter to zero.  Enables the Transmission buffer
     empty interrupt.  This flag defaults to set, so immediately after it is turned on
     the interrupt will fire and send the first byte of the OutgoingMessage.Contents[].
     The interrupt gets turned off again after the last byte has been sent.
 
 Notes
 
 
 Author
     Nick Musser
****************************************************************************/
void Send_Message(void)
{
  OutgoingMessage.Index_Counter = 0;  // reset outgoing index counter to zero
  SCI1CR2 |= _S12_TCIE;     // Enable Transmitssion Complete Interrupt.  Interrupt will fire immediately after
} // end of function

/****************************************************************************
 Function
     Process_Message()
 
 Parameters
     None
 
 Returns
 
 
 Description
     Takes in the message and determines if it is of interest.  Depending on what type
     of message it is, different things will happen. Can also print out the incoming    message
 Notes
 
 
 Author
     Nick Musser
****************************************************************************/
void Process_Message(void)
{
  unsigned char SourceAddressMSB = IncMessageBuffer.Contents[4]; // take out the source address MSB
  unsigned char SourceAddressLSB = IncMessageBuffer.Contents[5]; // take out the source address LSB
  unsigned char Message_Intention = IncMessageBuffer.Contents[7]; // take out the message intention
  unsigned char Team_Indicator = IncMessageBuffer.Contents[8]; // take out the team indicator
  unsigned char Message_Type = IncMessageBuffer.Contents[9]; // take out message type

  static unsigned char Crab_Pot_Number; // create variable for crab pot number
  static unsigned char Crab_Accum_Rate; // create variable for cab accum rate
 
  /*printf("\r\n%x\r\n",IncMessageBuffer.Contents[0]);
  printf("%x\r\n",IncMessageBuffer.Contents[1]);
  printf("%x\r\n",IncMessageBuffer.Contents[2]);
  printf("%x\r\n",IncMessageBuffer.Contents[3]);
  printf("%x\r\n",IncMessageBuffer.Contents[4]);
  printf("%x\r\n",IncMessageBuffer.Contents[5]);
  printf("%x\r\n",IncMessageBuffer.Contents[6]);
  printf("%x\r\n",IncMessageBuffer.Contents[7]);
  printf("%x\r\n",IncMessageBuffer.Contents[8]);
  printf("%x\r\n",IncMessageBuffer.Contents[9]);
  printf("%x\r\n",IncMessageBuffer.Contents[10]);
  printf("%x\r\n",IncMessageBuffer.Contents[11]);
  printf("%x\r\n",IncMessageBuffer.Contents[12]);  */
 
  switch(IncMessageBuffer.Contents[3])
  {
    case 0x89:  // case: reply back from your XBee
        if(IncMessageBuffer.Contents[5] == 0)
          printf("Success\r\n");
        if(IncMessageBuffer.Contents[5] == 1)
          printf("No ACK\r\n");
        if(IncMessageBuffer.Contents[5] == 3)
          printf("CCA Failure\r\n");
        if(IncMessageBuffer.Contents[5] == 4)
          printf("Purged\r\n");
        break;
    case 0x81:  // case: message from other XBee
        if((SourceAddressMSB == NEPTUNE_MSB) && (SourceAddressLSB == NEPTUNE_LSB) && (IncMessageBuffer.Contents[8] == 0x47) && (IncMessageBuffer.Contents[9] == 0x6F) && (IncMessageBuffer.Contents[10] == 0x21)) // If broadcast GO message from Neptune
        {
            GO_Flag = 1; // Set GO_Flag
            return;  // return
        } // end if
        if((SourceAddressMSB == CRAFT_MSB) && (SourceAddressLSB == CRAFT_LSB) && (Message_Intention == _PERSONAL_) && (Message_Type == _CIPHER_MESSAGE_))// If personal message from Boat (Cypher)
        {
            MyTeam = Team_Indicator; // assign the team to local team variable
            CIPHER = IncMessageBuffer.Contents[10];  // Take cypher and store it
            Received_Cipher_Flag = 1;  // Set Recevied Cipher Flag
            return;
        } // end if
        if((Message_Intention == _BOADCAST_) && (Team_Indicator == MyTeam) && (Message_Type == _CRAB_MESSAGE_)) // If broadcast message and its from your fleet then its a crab update. save crab data
        {
            Crab_Pot_Number = (CIPHER ^ IncMessageBuffer.Contents[10]) - 0xA0; // Take crab pot # and decode it with XOR
            Crab_Accum_Rate = CIPHER ^ IncMessageBuffer.Contents[11]; // Take crab pot accum rate and decode it with XOR
            printf(" Crab Pot ID is %x\r\n", Crab_Pot_Number);
            printf(" Crab Pot Accum is %x\r\n", Crab_Accum_Rate);
            Update_Indicators(Crab_Pot_Number,Crab_Accum_Rate);  // update indicators
            return;
        } // end if
        break;
    default:
        break;
  } // end of switch
} // end of function

/****************************************************************************
 Function
     Query_Received_Cipher_Flag()
 
 Parameters
     None.
 
 Returns
     1 or 0
 
 Description
      Queries the Receive Cipher Flag.  Returns 1 if set, 0 otherwise
 
 Notes
     None.
 
 Author
     Nick Musser
****************************************************************************/
char Query_Received_Cipher_Flag(void)
{
  if(Received_Cipher_Flag == 1)
  {
    Received_Cipher_Flag = 0;  // clear flag
    return 1;
  }
  else
    return 0;
}
 
/****************************************************************************
 Function
     Query_GO_Flag()
 
 Parameters
     None.
 
 Returns
     1 or 0
 
 Description
     Queries the Neptune GO Flag.  Returns 1 if set, 0 otherwise
 
 Notes
     None.
 
 Author
     Nick Musser
****************************************************************************/
char Query_GO_Flag(void)
{
  if(GO_Flag == 1)
  {
    GO_Flag = 0;  // clear flag
    return 1;
  }
  else
    return 0;
}
 
/****************************************************************************
 Function
     Query_New_Message_Flag()
 
 Parameters
     None.
 
 Returns
     1 or 0
 
 Description
     Queries the New Message Flag.  Returns 1 if set, 0 otherwise
 
 
 Notes
     None.
 
 Author
     Nick Musser
****************************************************************************/
char Query_New_Message_Flag(void)
{
  if(New_Message_Flag == 1)
  {
    New_Message_Flag = 0;  // clear flag
    return 1;
  }
  else
    return 0;
}
 
/****************************************************************************
 Function
     SCI_Resp
 
 Parameters
     None.
 
 Returns
     None.
 
 Description
     This is the interrupt response associated with the Receiver Data Register Full flagand the Transmit Data Register Empty Flag.  We must see which one caused the interrupt.

 Notes
     None.
 
 Author
     Nick Musser
****************************************************************************/
void interrupt _Vec_sci1 SCI_Resp(void)
{
  In_Flag = 1;
  if(SCI1SR1 & _S12_RDRF)     // Is it Receive Interrupt?
  {
        //Read SCI1SR1 and SCIDRL to clear the flag
        if((IncomingMessage.Index_Counter == 0) && (SCI1DRL != 0x7E))  // if this is the first index and the first byte
        {                                                              // isnt 0x7E, we know something is wrong - dont
          return;                                                      // do anything.
        }
            IncomingMessage.Contents[IncomingMessage.Index_Counter] = SCI1DRL;          // Read SCI Data Register Low
            if(IncomingMessage.Index_Counter == 2)  // if we are at the LSB length byte of the packet
            {
              IncomingMessage.Length = 4 + IncomingMessage.Contents[2];  // This would be the length of the packet
            }
 
            if(IncomingMessage.Index_Counter > IncomingMessage.Length-2)       // we are at the end of the message
            {
              IncomingMessage.Index_Counter = 0;  // reset index for next message
              IncMessageBuffer = IncomingMessage;   // store away complete incoming message
              New_Message_Flag = 1; // Set Message  Flag
            }
            else           // we are not at the end of the message
              IncomingMessage.Index_Counter++;  // Increment index
        return;
      }
 
  if(SCI1SR1 & _S12_TDRE)       // Is it transmit interrupt?
  {
 
    if(OutgoingMessage.Index_Counter >= OutgoingMessage.Length)  // If Message is done
    {
        OutgoingMessage.Index_Counter = 0;     // Reset Index counter and dont send anything.  This leaves the flag set
        SCI1CR2 &= (~_S12_TCIE);     // Disable Transmit Interrupt
        return;
    }
    else  // else Message is not done.  Send the next byte in the sequence
    {
        SCI1DRL = OutgoingMessage.Contents[OutgoingMessage.Index_Counter];  // write next byte to Transmit data register
        OutgoingMessage.Index_Counter++;   // Increment Index Counter
    }
    return;
  }
}
 
/*------------------------------- Footnotes -------------------------------*/
#ifdef TEST
 
void main(void){
  int KeyStroke;
  SCI_Init();
  //Compile_Message(2,2,2,2,2,2);
  //Send_Message();
  (void)printf("Press a,b,c,d,e,f\r\n");
 
  while(1){
    if(kbhit() != 0)
    {
      KeyStroke = getchar();
      if(KeyStroke == 'a')  // If button B was pressed
      {
        Compile_Message(0,0,0,0,0,0);
        //Compile_Message(1);
        (void)printf("000\r\n");
      }
      if(KeyStroke == 'b')  // If button B was pressed
      {
        Compile_Message(0,0,1,0,0,1);
        //Compile_Message(2);
        (void)printf("001\r\n");
      }
      if(KeyStroke == 'c')  // If button B was pressed
      {
        Compile_Message(0,1,1,0,1,1);
        //Compile_Message(1);
        (void)printf("011\r\n");
      }
      if(KeyStroke == 'd')  // If button B was pressed
      {
        Compile_Message(1,0,1,1,0,1);
        //Compile_Message(2);
        (void)printf("101\r\n");
      }
      if(KeyStroke == 'e')  // If button B was pressed
      {
        Compile_Message(1,1,0,1,1,0);
        //Compile_Message(1);
        (void)printf("110\r\n");
      }
      if(KeyStroke == 'f')  // If button B was pressed
      {
        Compile_Message(0,1,0,0,1,0);
        //Compile_Message(2);
        (void)printf("010\r\n");
      }
      Send_Message();
    }
    if( New_Message_Flag == 1)
    {
      Process_Message();  // Process Message
      New_Message_Flag  = 0;  // Reset Message_Done Flag
    }
 
 
    /*printf("interrupt_in counter = %i\n\r", p);
    printf("interrupt_out counter = %i\n\r", m);
    printf("first = %x\n\r",IncomingMessage.Contents[0]);
    printf("second = %x\n\r",IncomingMessage.Contents[1]);
    printf("third = %x\n\r",IncomingMessage.Contents[2]);
    printf("fourth  = %x\n\r",IncomingMessage.Contents[3]);
    printf("fifth = %x\n\r",IncomingMessage.Contents[4]);
    printf("sixth  = %x\n\r",IncomingMessage.Contents[5]);
    printf("seventh  = %x\n\r",IncomingMessage.Contents[6]);
    printf("eighth  = %x\n\r",IncomingMessage.Contents[7]);
    printf("ninth  = %x\n\r",IncomingMessage.Contents[8]);
    printf("tenth  = %x\n\r",IncomingMessage.Contents[9]);
    printf("eleventh  = %x\n\r",IncomingMessage.Contents[10]);
    printf("twelve  = %x\n\r",IncomingMessage.Contents[11]);
    printf("thirteen  = %x\n\r",IncomingMessage.Contents[12]);
    printf("fourteenth  = %x\n\r",IncomingMessage.Contents[13]);
    printf("fifteenth  = %x\n\r",IncomingMessage.Contents[14]);
    printf("process message flag = %i\n\r", Message_Done); */
    //printf("outgoing message counter = %i\n\r", OutgoingMessage.Index_Counter);
  }
}
 
 
#endif
/*------------------------------ End of file ------------------------------*/