C Code
// MAIN.C
// in E128_Integrated Project
// Matthew Hill, Taylor Penn, Michael Wittenberg
#include <hidef.h> /* common defines and macros */
#include <mc9s12e128.h> /* derivative information */
#include <S12E128bits.h>
#include <stdio.h>
#include "S12eVec.h"
#include "XBee.h"
#include "iButton.h"
#include "helm_display.h"
#include "ADS12.H"
#include "helm_input.h"
#define REFRESH_PERIOD 37500
#define YES 1
#define NO 0
#define WAITING_FOR_IBUTTON 17
#define SEND_IBUTTON_MESSAGE 18
#define LOOKING_FOR_WATERCRAFT 19
#define PAIRED 20
#define PLAYING_GAME 21
#define ENGAGEMENT_OVER 22
#define STANDING_DOWN 23
#define IBUTTON 0x01
#define COMMAND 0x02
#define NO_ACTION_NAV 0x88
#define NO_ACTION_SPECIAL 0x00
//
#define FULL_STAND_DOWN 50
//all of these are in the special byte, the navigation byte is zero
#define ADMIRAL 0x04
#define STAND_DOWN 0x01
#define START_GAME 0x02
#define END_GAME 0x04
#define BLUE_GOAL 0x08
#define RED_GOAL 0x10
#define HARD_RESET 0x40
#define PING 0x80
#define SOFT_RESET 0x20
#define PING_RESPONSE 0x10
#define ADMIRAL_ADDRESS_MSB 0xBC
#define ADMIRAL_ADDRESS_LSB 0xFF
// incoming data HEADERS
#define ADMIRAL_HEADER 0x04
#define CRAFT_HEADER 0x08
//no action for these, but to see what we are receiving
#define IBUTTON_HELM_HEADER 0x01
#define HELM_HEADER 0x02
// completely unecessary animation flags
#define CIRCLE 1
#define FLASH_PAIRED 2
#define DOUBLE_CIRCLE 3
void Main_Init(void);
void InitializePeriodTimer(void);
// message parsing functions, defines
void Message_Machine(void);
void Handle_Admiral(void);
void Handle_iButton(void);
void Handle_Craft(void);
void Import_Message_Machine(void);
void InitializeSecondTimer(void);
void Send_If_Needed(void);
// Message_In; */
static unsigned char Message_In[12]; //array of 12 chars
static char NeedToSend = 0; //only used in returning array from a function
static unsigned char destination_MSB = 0x00;
static unsigned char destination_LSB = 0x00;
static unsigned char header_in = 0x00;
static unsigned char navigation_in = 0x00;
static unsigned char special_in = 0x00;
static unsigned char keypress_throttle = 0x00;
static unsigned char keypress_direction = 0x00;
static unsigned char incoming_address_MSB = 0x00;
static unsigned char incoming_address_LSB = 0x00;
// pairing stuff
static unsigned char paired_Address_LSB = 0x00;
static unsigned char paired_Address_MSB = 0x00;
static unsigned char iButton_LSB = 0x00;
static unsigned char iButton_MSB = 0x00;
static unsigned char game_state = WAITING_FOR_IBUTTON;
// **********************************************************
// test code #defines
// **********************************************************
//#define _TRANSMIT_TEST
//#define _SEGMENT_DISPLAY_TEST
//#define _INPUTS_TEST
//#define _LEDS_TEST
#define _GAME_CODE
// _GAME_CODE IS THE MAIN CODE
// IT PLAYS THE GAME
#ifdef _GAME_CODE
// static char game_state = WAITING_FOR_IBUTTON; < -- now a module level variable
// initialize variables
// Module variables
static unsigned int next_time = 0;
static int counter_test = 0;
static int i;
static char key_press;
static unsigned char iButton_last_msb;
static unsigned char iButton_last_lsb;
static long int stand_down_counter = FULL_STAND_DOWN; // to time the standown
static char animateFlag = 0; // to animate
static int animate_counter = 0; // "
void main()
{
// Initializes the variables we need
int voice = 17;
int roll = 17;
int FSR = 17;
int pitch = 17;
unsigned char speedout = 17;
unsigned char directionout = 17;
unsigned char pumpspeedout = 17;
unsigned char reverseout = 17;
unsigned char special1 = 0;
unsigned char special2 = 0;
// Initialize the timer that does our stand-down count
// and our animation:
InitializeSecondTimer();
// initialize the XBee module, the helm input ports, and the helm output ports
XBee_Init();
InitDisplayPorts();
InitInputPorts();
PTT = 0xFF; // clear the display
Set_XBee_Address(0x00, 0x00); // set to an invalid address
// so we can't spam by accident
EnableInterrupts;
// do the following forever
while(1) // GAME LOOOOP
{
switch(game_state) // based on the state we're in, we want to act differently
{
case WAITING_FOR_IBUTTON: // if we don't have an ibutton
printf("1 \r\n");
animateFlag = DOUBLE_CIRCLE;// animate the "double circle
Message_Machine(); // check for received messages
printf("WAITING_FOR_IBUTTON state \r\n");
InitiButtonModule(); //needs to be called each time, since it resets prescalers
printf("2 \r\n");
// see if there's an iButton present
// this thing is blocking, but not very long at all
// but we don't want to interrupt it...
// we'll never get anywhere if we do
//DisableInterrupts;
if(PollForiButton()) { //returns true if ibutton found
ReadiButton();
iButton_last_msb = GetiButtonMSB();
iButton_last_lsb = GetiButtonLSB();
ReadiButton();
if((GetiButtonMSB() == iButton_last_msb)
&& (GetiButtonLSB() == iButton_last_lsb)
&& (iButton_last_msb != 0xFF)
&& (iButton_last_msb != 0x00)) //two concurrent reads the same, and not 0x0000 or 0xFFFF
{
iButton_LSB = iButton_last_lsb; // store values
iButton_MSB = iButton_last_msb;
} else printf("Second iButton read doesn't match \r\n");
}
printf("3 \r\n");
if ((iButton_LSB)&&(iButton_MSB))
{
// we're out of the iButton code, we can get interrupted
printf("iButton read as %x %x \r\n",iButton_MSB,iButton_LSB);
// START THE SENDING EVER 200ms
Set_XBee_Address(0xFF, 0xFF);
InitializePeriodTimer();
game_state = SEND_IBUTTON_MESSAGE; // only change state if we've found an iButton
break;
}
printf("4 \r\n");
break;
case SEND_IBUTTON_MESSAGE:
Message_Machine();
puts("SEND_IBUTTON_MESSAGE state \r\n");
// set which data we're going to send
//header = IBUTTON;
//navigation = GetiButtonMSB();
//special = GetiButtonLSB();
Set_XBee_Bytes(IBUTTON, GetiButtonMSB(), GetiButtonLSB());
printf("iButton LSB: %x, iButton MSB: %x \r\n", GetiButtonLSB(),GetiButtonMSB());
// enable interrupts, so we transmit every 200 ms
EnableInterrupts;
// change our game state
animateFlag = 0;
PTT = middle; // turn on only the middle dash
// to show we have an ibutton, are searching
game_state = LOOKING_FOR_WATERCRAFT;
puts("changed state to LOOKING_FOR_WATERCRAFT \r\n");
break;
case LOOKING_FOR_WATERCRAFT:
Message_Machine();
break;
case PAIRED:
//printf("paired case");
Set_XBee_Address(0xDD, 0xAA); // <-- junk address
Message_Machine();
// break;
// game_state = PLAYING_GAME;
break;
case PLAYING_GAME:
Set_Standdown_LED(PLAYING_GAME);
Set_XBee_Address(paired_Address_MSB, paired_Address_LSB);
Message_Machine();
// poll for inputs
special1 = 0;
special2 = 0;
speedout = Set_Speed();
directionout = Set_Direction();
pumpspeedout = Set_PumpSpeed();
reverseout = Check_Reverse();
if(Report_Special1())
{
special1 = BIT4HI;
}
if(Report_Special2())
{
special2 = BIT5HI;
}
// assemble the Xbee output byte
printf("%x, %x, %x\r\n", COMMAND, ((directionout*16)+speedout), (pumpspeedout + special1 + special2));
Set_XBee_Bytes(COMMAND, ((directionout*16)+speedout), (pumpspeedout + special1 + special2));
break;
case STANDING_DOWN:
Message_Machine();
Set_XBee_Address(paired_Address_MSB, paired_Address_LSB);
Set_XBee_Bytes(COMMAND,0x88,0x00);
break;
case ENGAGEMENT_OVER:
Message_Machine();
special1 = 0;
special2 = 0;
speedout = Set_Speed();
directionout = Set_Direction();
pumpspeedout = Set_PumpSpeed();
reverseout = Check_Reverse();
if(Report_Special1())
{
special1 = BIT4HI;
}
if(Report_Special2())
{
special2 = BIT5HI;
}
// assemble the Xbee output byte
printf("%x, %x, %x\r\n", COMMAND, ((directionout*16)+speedout), (pumpspeedout + special1 + special2));
Set_XBee_Bytes(COMMAND, ((directionout*16)+speedout), (special1+special2 + 0x00));
break;
break;
}
}
}
//}//end main
#endif
// **********************************************************************************
// ************************* INITIALIZATIONS
// **********************************************************************************
void Main_Init(void)
{
TIM0_TSCR1 |= _S12_TEN; //start timer0
TIM0_TSCR2 |= (_S12_PR2 | _S12_PR1 | _S12_PR0); //set timer0 prescaler to 128
DDRP |= BIT5HI; //set P5 as an output (used to test)
PTP = 0xFF;
}
void InitializePeriodTimer(void)
// initializes timer on channel 4
{
TIM0_TSCR1 |= _S12_TEN; // turns timer on
TIM0_TSCR2 |= (_S12_PR2 | _S12_PR1 | _S12_PR0); //set timer0 prescaler to 128
TIM0_TIOS |= _S12_IOS4; // OUTPUT CAPTURE
TIM0_TIE |= _S12_C4I; // ENABLE THIS INTERRUPT!!!!!!
TIM0_TCTL1 |= TIM0_TCTL1 & ~(_S12_OL4 | _S12_OM4); // no pin associated with this one
TIM0_TC4 = TIM0_TCNT + REFRESH_PERIOD; // schedule first event
TIM0_TFLG1 |= _S12_C4F; // clear OC4 flag;
puts("Period Timer Initialized\r\n");
DDRP |= BIT5HI; // P5 is now an output
PTP = 0xFF; // initialize to HI
printf("DEBUG: Pin P5 enabled as an output\r\n");
}
void InitializeSecondTimer(void)
// initializes timer on channel 5
{
TIM2_TSCR1 |= _S12_TEN; // turns timer on
TIM2_TSCR2 |= (_S12_PR2 | _S12_PR1 | _S12_PR0); //set timer0 prescaler to 128
TIM2_TIOS |= _S12_IOS7; // OUTPUT CAPTURE
TIM2_TIE |= _S12_C7I; // ENABLE THIS INTERRUPT!!!!!!
TIM2_TCTL1 |= TIM2_TCTL1 & ~(_S12_OL7 | _S12_OM7); // no pin associated with this one
TIM2_TC7 = TIM0_TCNT + REFRESH_PERIOD; // schedule first event
TIM2_TFLG1 |= _S12_C5F; // clear OC4 flag;
puts("Second Timer Initialized\r\n");
//DDRP |= BIT5HI; // P5 is now an output
//PTP = 0xFF; // initialize to HI
//printf("DEBUG: Pin P5 enabled as an output\r\n");
}
// **********************************************************************************
// ************************* INTERRUPT SERVICE ROUTINES
// **********************************************************************************
void interrupt _Vec_tim0ch4 Periodic_ISR (void)
{
TIM0_TFLG1 = _S12_C4F; // clear dem flags
TIM0_TC4 += REFRESH_PERIOD; // set next event
// TEST CODE:
// blip pin P5 (assuming P5 is already an output, configured above)
// PTP ^= BIT5HI;
// printf("____________INTERRUPT!\r\n");
NeedToSend = YES; // set send flag...this means we need to send
// Set_Xbee_Out based on whatever the helm says
//DisableInterrupts;
//Send_XBee_Data(header,navigation,special); // sets module level variables needed to send
//EnableInterrupts;
//this next code is blocking. We did this so that other parts of our main
//loop won't cause us to transmit slower (i.e. 5 printfs between calls to
//SendingFSM would put ~5ms between bytes sent to the XBee . We weren't
//sure how long we would have between bytes sent before the XBee would reset.
//if(header_out&BIT0HI | header_out&BIT1HI) //only send 0x02 or 0x01 (message or ibutton)
//{
while(1) // end of Autosend
{
if(SendingFSM() ) break;
}
}
// this is our Second Timer
// it does the stand down
// and the animation
void interrupt _Vec_tim2ch7 Periodic_ISR_copy (void)
{
TIM2_TFLG2 = _S12_C7F; // clear dem flags
TIM2_TFLG1 = _S12_C7F;
TIM2_TC7 += REFRESH_PERIOD; // set next event
// printf("Second interrupt machine \r\n");
if (game_state == STANDING_DOWN) // if we're standing down
{
stand_down_counter--;
if(stand_down_counter==0)
{
stand_down_counter = FULL_STAND_DOWN;
Set_Standdown_LED(PLAYING_GAME);
animateFlag = 0;
DisplayBoatNumber(paired_Address_LSB);
game_state = PLAYING_GAME;
}
}
// the following segment controls the 7-segment display animation
// based on which animation flag is set
if (animateFlag) // if we're supposed to animate
{
/* Figure 8
switch(animate_counter%8)
{
case 0:
PTT = bottom_center;
break;
case 1:
PTT = bottom_right;
break;
case 2:
PTT = middle;
break;
case 3:
PTT = top_left;
break;
case 4:
PTT = top_center;
break;
case 5:
PTT = top_right;
break;
case 6:
PTT = middle;
break;
case 7:
PTT = bottom_left;
break;
}
*/
/* circle
switch(animate_counter%6)
{
case 0:
PTT = bottom_center;
break;
case 1:
PTT = bottom_right;
break;
case 2:
PTT = top_right;
break;
case 3:
PTT = top_center;
break;
case 4:
PTT = top_left;
break;
case 5:
PTT = bottom_left;
}
*/
// double circle
if(animateFlag == DOUBLE_CIRCLE)
{
switch(animate_counter%3)
{
case 0:
PTT = (bottom_center&top_center);
break;
case 1:
PTT = (bottom_right&top_left);
break;
case 2:
PTT = (top_right&bottom_left);
break;
}
animate_counter++;
}
if(animateFlag == CIRCLE)
{
// build / debuild a circle
switch(animate_counter%11)
{
case 0:
PTT = bottom_center;
break;
case 1:
PTT = (bottom_center&bottom_right);
break;
case 2:
PTT = (bottom_center&bottom_right&top_right);
break;
case 3:
PTT = (bottom_center&bottom_right&top_right&top_center);
break;
case 4:
PTT = (bottom_center&bottom_right&top_right&top_center&top_left);
break;
case 5:
PTT = (bottom_center&bottom_right&top_right&top_center&top_left&bottom_left);
break;
case 6:
PTT = (bottom_right&top_right&top_center&top_left&bottom_left);
break;
case 7:
PTT = (top_right&top_center&top_left&bottom_left);
break;
case 8:
PTT = (top_center&top_left&bottom_left);
break;
case 9:
PTT = (top_left&bottom_left);
break;
case 10:
PTT = (bottom_left);
}
animate_counter++;
}
if (animateFlag == FLASH_PAIRED)
{
switch(animate_counter%2)
{
case 0:
PTT = 0xFF;
break;
case 1:
DisplayBoatNumber(paired_Address_LSB);
break;
}
animate_counter++;
}
}
}
void interrupt _Vec_sci1 SCI_Interrupt_Machine(void)
{
// static char dummy = 0;
DisableInterrupts; //disable global interrupts. We don't want
//to be interrupted while receiving data.
ReceivingFSM();
/* while(ReceivingFSM())
{
dummy++;
} */
//printf("In SCI interrupt \r\n");
EnableInterrupts; //re-enable interrupts
}
// **********************************************************************************
// ******************************** MESSAGE_MACHINE *******************************
// ******************************** *******************************
// **********************************************************************************
// message machine checks if we've received a new message
// if so, it reads in all the values (Import_Message_Machine)
// and deals with them appropriately
// based on incoming message header
void Message_Machine(void) {
if(Check_Message_Flag())
{
Clear_Message_Flag();
Import_Message_Machine();
// puts("Message received.....");
switch(header_in)
{
case ADMIRAL_HEADER:
Handle_Admiral();
break;
case CRAFT_HEADER:
Handle_Craft();
break;
case HELM_HEADER:
printf("from helm %x %x \r\n",incoming_address_MSB,incoming_address_LSB);
break;
case IBUTTON_HELM_HEADER:
printf("from helm %x %x (iButton) \r\n",incoming_address_MSB,incoming_address_LSB);
break;
default:
// printf("...with no recognizable header (%x) \r\n",header_in);
break;
} //end header_in switch
} //end if(Check_Message_Flag())
} //end message machine
// **********************************************************************************
// ************************* message handling helper function
// **********************************************************************************
void Handle_Admiral(void)
// handles messages with the "Admiral" header
// first tests for proper admiral address
// then deals with the commands
// based on content
{
// check for address...if admirals, deal with the message
if ((incoming_address_MSB == ADMIRAL_ADDRESS_MSB)
&&(incoming_address_LSB == ADMIRAL_ADDRESS_LSB))
{
printf ("...from Admiralty, with an Admiral header\r\n");
// navigation in should be zero, just check the special
switch (special_in)
{
case START_GAME:
// printf("ADM: Start Game received\r\n");
//make sure we're paired
if(game_state == PAIRED)
{
// ack
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(0x80, 0x00, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
// end ack
Set_Standdown_LED(PLAYING_GAME);
game_state = PLAYING_GAME;
} /*else
{
//send waiting for ibutton
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x01, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
}*/
break;
case END_GAME:
// printf("ADM: End Game received\r\n");
// ack
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(0x80, 0x00, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
// end ack
PTU = 0xFF;
game_state = ENGAGEMENT_OVER;
break;
case BLUE_GOAL:
// printf("ADM: Blue Goal Active\r\n");
Set_Base(BLUE);
break;
case RED_GOAL:
// printf("ADM: Red Goal Active\r\n");
Set_Base(RED);
break;
case HARD_RESET:
// printf("ADM: Hard Reset received\r\n");
// reset our saved values
// revert to start game state
paired_Address_LSB = 0;
paired_Address_MSB = 0;
iButton_LSB = 0;
iButton_MSB = 0;
game_state = WAITING_FOR_IBUTTON;
PTU = 0x00; // clear all LEDs v
TIM0_TIE &= ~(_S12_C4I); // turn off the 2nd timer interrupt
break;
case PING:
printf("ADM: Ping received\r\n");
// we ping back to the amdiral
// respond to ping appropriately
switch (game_state)
{
case WAITING_FOR_IBUTTON:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x01, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
case SEND_IBUTTON_MESSAGE:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x02, iButton_LSB);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
case LOOKING_FOR_WATERCRAFT:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x02, iButton_LSB);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
case PLAYING_GAME:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x04, paired_Address_LSB);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
case PAIRED:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(PING_RESPONSE, 0x04, paired_Address_LSB);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
default:
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB);
Set_XBee_Bytes(0x80, 0x00, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(0xDD, 0xEE);
break;
}//end switch (game_state)
break;
default:
printf("ADM: Invalid Admiral Command\r\n");
break;
} // end switch special byte
} // end IF check of admiral address
} // end handle admiral
// Handle Craft messages *********************************************************************************
void Handle_Craft(void)
{
switch (game_state)
{
case LOOKING_FOR_WATERCRAFT:
if (special_in == 0x01) // if we get a matched command
{
paired_Address_MSB = incoming_address_MSB;
paired_Address_LSB = incoming_address_LSB;
puts("successfully paired\r\n");
// show which boat we've got
DisplayBoatNumber(paired_Address_LSB);
printf("paired to team %x\r\n", paired_Address_LSB);
// show our team affiliation
if (iButton_LSB & BIT0HI) // if odd
{
printf("RED TEAM\r\n");
Set_Affiliation(RED);
} else
{
printf("BLUE TEAM\r\n");
Set_Affiliation(BLUE);
}
// state transition
game_state = PAIRED;
}
break;
case PLAYING_GAME:
// check for address
if( (incoming_address_MSB!=paired_Address_MSB)||(incoming_address_LSB!=paired_Address_LSB))
{
puts("we're getting messages from the wrong boat\r\n");
break;
}
if (special_in == 0x02) // if this is a stand down
{
// send our ACK
Set_XBee_Address(paired_Address_MSB, paired_Address_LSB); // we want to send back to the boat
Set_XBee_Bytes(0x80, 0x00, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
Set_XBee_Address(ADMIRAL_ADDRESS_MSB, ADMIRAL_ADDRESS_LSB); // we want to send back to the boat
Set_XBee_Bytes(0x80, 0x00, 0x00);
while(1) // send one byte
{
if(SendingFSM() ) break;
}
// start TIMER // <-----------------------------------------------------# # # # # #
Set_XBee_Address(0xDD, 0xEE);
animateFlag = FLASH_PAIRED;
game_state = STANDING_DOWN;
}
break;
default:
printf("Craft is sending us messages when we don't want them\r\n");
break;
}
}
void Import_Message_Machine(void)
{
static int i = 0;
for(i=0;i<12;i++)
{
Message_In[i] = Get_XBee_Byte(i); //Put entire XBee message int Message_In
}
header_in = Message_In[8];
navigation_in = Message_In[9];
special_in = Message_In[10];
// printf("header in is %x, navigation in is %x, special in is %x\r\n",header_in,navigation_in,special_in);
incoming_address_MSB = Message_In[4];
incoming_address_LSB = Message_In[5];
}