This state machine was created by the communications committee for all the hovercrafts to implement to facilitate bug-free interoperability.
It handles the decision making structure for incoming data packets and actuates the hovercraft's peripherals accordingly.
LobbyistReceive receives data for the hovercraft (LOBBYIST) that was sent by the controller (PAC) via UART.
LOBBYISTTransmit handles sending data to the PAC via UART.
This state machine was created by the communications committee for all the controllers to implement to facilitate bug-free interoperability.
PACReceive receives data for controller (PAC) that was sent by the hovercraft (LOBBYIST) via UART.
PACTransmit handles the data transmission to the hovercraft via UART.
PACService uses the I/O and received data to carry out actions for the controller.
LobbyistReceive receives data for the hovercraft (Lobbyist) that was sent by the controller (PAC) via UART
#ifndef LOBBYISTRECEIVE_H
#define LOBBYISTRECEIVE_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
#define ALL_BITS (0xff<<2)
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { WaitingFor0x7e, WaitingForMSB, WaitingForLSB, GettingDataPacket} LobbyistReceiveState_t;
//Public function prototypes
bool InitializeLobbyistReceive (uint8_t Priority);
bool PostLobbyistReceive( ES_Event ThisEvent );
ES_Event RunLobbyistReceive (ES_Event ThisEvent);
void ReceiveISR(void);
uint8_t GetNextRxByte(uint8_t);
#endif ///LOBBYISTRECEIVE_H
/****************************************************************************
Module
LobbyistReceive.c
Receives data for the hovercraft from the controller via UART
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistReceive.h"
#include "Initializations.h"
#include "MainLobbyist.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
#define DoubleCharTime 17
#define LARGEST_FRAME_DATA 38 //max number of bytes stored in RxPacket[] and DataForMain[]
#define FRAME_DATA_OVERHEAD 5 //number of bytes in the array before the RF data starts
//Number of RF data bytes in a certain packet
#define REQ_PAIR_LENGTH 2 //number of RF data bytes in a request to pair packet
#define ENCR_KEY_LENGTH 33 //number of RF data bytes in an encryption key packet
#define CONTROL_LENGTH 5 //number of RF data bytes in a control packet
#define STATUS_LENGTH 3 //number of RF data bytes in a status packet
//Packet types used as event parameters (hex values match those found in communications protocol)
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CONTROL 0x02
#define STATUS 0x03
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static void ClearRxPacket(void);
static void ReinitializeAllVariables(void);
static void InitializeRxInterrupt(void);
static void WriteRxToDataArray(void);
static uint8_t GetPacketType(void);
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static LobbyistReceiveState_t CurrentState;
static uint8_t index = 0; //this is the index into RxPacket[]
static uint8_t MyRxSum = 0; //this is the sum you add to each time you read in a new decrypted data byte. It adds everything from the API identifier though the last byte of RF data
static uint8_t MyRxChecksum = 0; //this is the checksum that's produced from MyRxSum: MyRxChecksum = FF - MyRxSum
static uint8_t RxChecksum = 0; //this is the checksum that was sent to you over Xbee at the highest level of the data packet
static uint8_t BytesLeftRx = 0; //this is the number of bytes you're still expecting to receive
static uint8_t NewByte; //NewByte is the byte that's read in from the UART during the ISR and then sent as an event parameter from the ISR attached to ES_GOT_7E and ES_GOT_NEW_BYTE
uint8_t PacketType = 0; //specifies if packet is a control packet, encryption key, etc...
uint8_t PacketLSB = 0; //the number of bytes that the frame data will hold
//The RxPacket array stores the incoming data, starting with the API Identifier (index 0) and ending with the RF Data.
//It is statically allocated and is large enough to hold the largest-anticipated data transmission, which is the encryption key data
static uint8_t RxPacket[LARGEST_FRAME_DATA];
//The DataForMain array stores the information we want to send to send to MainLobbyist.
static uint8_t DataForMain[LARGEST_FRAME_DATA];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeLobbyistReceive
Does all the initiializations needed to make the UART receive work so
the hovercraft (Lobbyist) can receive data from the controller (PAC)
****************************************************************************/
bool InitializeLobbyistReceive (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//Because the Lobbyist will receive data before sending any, initialize the UART here
InitializeUART();
//Make sure all arrays are initialized to 0, and not filled with leftover junk from the data registers
ClearRxPacket();
//Set CurrentState of state machine
CurrentState = WaitingFor0x7e;
//Initialize interrupts
InitializeRxInterrupt();
//Kick the state machine off by posting an initialization event
ThisEvent.EventType = ES_INIT;
PostLobbyistReceive(ThisEvent);
return true;
}//End of InitializeLobbyistReceive (return True)
/****************************************************************************
Function
PostLobbyistReceive
Function the framework uses to post events to the LobbyistReceive
state machine.
****************************************************************************/
bool PostLobbyistReceive( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/****************************************************************************
Function
RunLobbyistReceive
State machine that handles the events coming in for the LobbyistRecieve module
****************************************************************************/
ES_Event RunLobbyistReceive (ES_Event ThisEvent){
//Set up local varaibles
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
//Set NextState to CurrentState
LobbyistReceiveState_t NextState = CurrentState;
switch(CurrentState)
{
case WaitingFor0x7e:
if(ThisEvent.EventType == ES_GOT_7E){
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
//Go to next state
NextState = WaitingForMSB;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables(); //this also sets the DecryptFlag back to false
NextState = WaitingFor0x7e;
}
break; //End of WaitingFor0x7e
case WaitingForMSB:
if(ThisEvent.EventType == ES_GOT_NEW_BYTE){
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
//If new byte == 00, go to WaitingForLSB (read UART register). Else, go back to WaitingFor0x7e
if(NewByte == 0x00){
NextState = WaitingForLSB;
} else{
NextState = WaitingFor0x7e;
}
}
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DOUBLE_CHAR_TIMER_RX)
|| (ThisEvent.EventType == ES_LOST_CONNECTION)
|| (ThisEvent.EventType == ES_BAD_DECRYPTION)){
//re-initialize all variables to prep for next data packet
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables();
NextState = WaitingFor0x7e;
}
break; //End of WaitingForMSB
case WaitingForLSB:
if(ThisEvent.EventType == ES_GOT_NEW_BYTE){
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
PacketLSB = NewByte;
//Set BytesLeftRx to the value of this new data byte
BytesLeftRx = NewByte;
//Go to GettingDataPacket
NextState = GettingDataPacket;
}
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DOUBLE_CHAR_TIMER_RX)
|| (ThisEvent.EventType == ES_LOST_CONNECTION)
|| (ThisEvent.EventType == ES_BAD_DECRYPTION)){
//Clear RxPacket[] and EncryptionKey[] and re-initialize all variables to prep for next data packet
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables(); //this also sets the DecryptFlag back to false
NextState = WaitingFor0x7e;
}
break; //End of WaitingForLSB
case GettingDataPacket:
if((ThisEvent.EventType == ES_GOT_NEW_BYTE) && (BytesLeftRx > 0)){
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
//Add data value to running sum MyRxSum
MyRxSum += NewByte;
//Store data in RxPacket[index]
RxPacket[index] = NewByte;
//Increment index variable (index into RxPacket)
index++;
//Decrement BytesLeftRx
BytesLeftRx--;
} else if((ThisEvent.EventType == ES_GOT_NEW_BYTE) && (BytesLeftRx == 0)){
NewByte = ThisEvent.EventParam;
//Store data in RxChecksum
RxChecksum = NewByte;
//Compare MyRxChecksum against RxChecksum
MyRxChecksum = 0xFF - MyRxSum;
//If you get a good checksum compare AND the data had an API of 81, then decide what to do with the data
if(MyRxChecksum == RxChecksum && RxPacket[0]==0x81){
//Send the new data up to MainLobbyist
WriteRxToDataArray();
PacketType = GetPacketType();
//Post ES_NEW_DATA_RECEIVED to MainLobbyist
ThisEvent.EventType = ES_NEW_DATA_RECEIVED;
ThisEvent.EventParam = PacketType;
PostMainLobbyist(ThisEvent);
} else{
//ignore the data because you got a bad checksum compare
//Re-initialize all variables to prep for next data packet (DON'T CLEAR RxPacket[] here. If you do, it will delete the data before MainLobbyist can use it. The clear is handled elsewhere
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
} // end of if/else statement for ES_GOT_NEW_BYTE
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DOUBLE_CHAR_TIMER_RX)
|| (ThisEvent.EventType == ES_LOST_CONNECTION)
|| (ThisEvent.EventType == ES_BAD_DECRYPTION)){
//Clear RxPacket[] and EncryptionKey[] and re-initialize all variables to prep for next data packet
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables(); //this also sets the DecryptFlag back to false
NextState = WaitingFor0x7e;
}
break; //end of GettingDataPacket
}//End switch statement
CurrentState = NextState;
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunLobbyistReceive
void ClearRxPacket(void){
//Go through each index of the RxPacket array and clear the data
for(uint8_t i=0; i < LARGEST_FRAME_DATA; i++){
RxPacket[i] = 0;
}
}
void ReinitializeAllVariables(void){
//reinitialize all variables in preparation for the next round
index = 0;
MyRxSum = 0;
MyRxChecksum = 0;
RxChecksum = 0;
BytesLeftRx = 0;
NewByte = 0;
//Make sure the data packet from the last transmission is cleared away so you don't mistake the old data for new data
ClearRxPacket();
}
void InitializeRxInterrupt(void){
//Locally enable the interrupt in NVIC.
//It is interrupt #6, so it appears in EN0 at bit 6
HWREG(NVIC_EN0) |= BIT6HI;
//Enable the receive interrupt in UARTIM (UART Interrupt Mask register)
HWREG(UART1_BASE + UART_O_IM) |= UART_IM_RXIM;
//Globally enable interrupts
__enable_irq();
}
void ReceiveISR(void){
//This interrupt service routine is used in conjunction with interrupts from the UART
ES_Event ThisEvent;
//Read the masked interrupt status (UARTMIS)
uint8_t RxInterruptBit = HWREG(UART1_BASE + (UART_O_MIS)) & (UART_MIS_RXMIS);
//If RXMIS is set(interrupt caused by receive byte)
if(RxInterruptBit > 0){ //true > 0
//Clear the receive interrupt source in the UARTICR (UART Masked Interrpt Clear Register)
HWREG(UART1_BASE + UART_O_ICR) |= UART_ICR_RXIC;
//Read the data register (UARTDR) and store in "RxUartByte"
uint8_t RxUartByte = HWREG(UART1_BASE + (UART_O_DR));
//Figure out the states of the error flags
uint8_t OverrunErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_OE);
uint8_t BreakErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_BE);
uint8_t ParityErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_PE);
uint8_t FramingErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_FE);
//If no error flags are set
if((OverrunErrorFlag==0) && (BreakErrorFlag==0) && (ParityErrorFlag==0) && (FramingErrorFlag==0)){
//Determine if byte was 0x7e or something else and post ES_GOT_7E or E_GOT_NEW_BYTE to LobbyistReceive.c with RxUartByte set as the optional event parameter
if(RxUartByte == 0x7e && CurrentState == WaitingFor0x7e){
ThisEvent.EventType = ES_GOT_7E;
PostLobbyistReceive(ThisEvent);
} else{
ThisEvent.EventType = ES_GOT_NEW_BYTE;
ThisEvent.EventParam = RxUartByte;
PostLobbyistReceive(ThisEvent);
}
} else{//Else, respond to the error
ThisEvent.EventType = ES_LOST_CONNECTION;
PostLobbyistReceive(ThisEvent);
//clear the UARTRSR register flags by writing any value of the UARTECR register
HWREG(UART1_BASE + UART_O_ECR) |= (UART_ECR_DATA_M);
}//end of if/else dealing with error flags
} else{
//Else, you are done (not an RX interrupt)
} //end of if/else that determines if the interrupt was caused by a UART receive
}
void WriteRxToDataArray(void){
//Use to transfer information from buffer array RxPacket to the array you're sending to MainLobbyist, DataForMain
for(uint8_t i=0; i < LARGEST_FRAME_DATA; i++){
DataForMain[i] = RxPacket[i];
}
}
uint8_t GetNextRxByte(uint8_t ThisIndex){
//Getter function MainLobbyist uses to read in the information from DataForMain array
return DataForMain[ThisIndex];
}
uint8_t GetPacketType(void){
uint8_t RfDataLength = PacketLSB - FRAME_DATA_OVERHEAD;
if(RfDataLength == REQ_PAIR_LENGTH){
return REQ_PAIR;
} else if(RfDataLength == ENCR_KEY_LENGTH){
return ENCR_KEY;
} else if(RfDataLength == CONTROL_LENGTH){
return CONTROL;
} else if(RfDataLength == STATUS_LENGTH){
return STATUS;
}
return 7; // This value is used for debugging to let us know something went wrong
}
LobbyistUARTISR routes the main UART ISR to the transmit and receive sub-ISRs
#ifndef LobbyistUARTISR_H
#define LobbyistUARTISR_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
//Public function prototypes
void LobbyistUARTISR ( void );
#endif ///LobbyistUARTISR_H
/****************************************************************************
Module
LobbyistUARTISR.c
Routes the main UART ISR to the Tx and Rx sub-ISRs
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistUARTISR.h"
// include header files for LOBBYISTTransmit & LOBBYISTReceive
#include "LobbyistTransmit.h"
#include "LobbyistReceive.h"
/****************************************************************************
Function
LobbyistUARTISR
****************************************************************************/
void LobbyistUARTISR ( void ){
// Call LobbyistTransmitISR
LobbyistTransmitISR();
// Call LobbyistRecieveISR
ReceiveISR();
}
MainLobbyist is the main control code for the hovercraft (Lobbyist). It handles the decision making structure for incoming data packets and actuates the hovercraft's peripherals accordingly.
#ifndef MAINLOBBYIST_H
#define MAINLOBBYIST_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h"
#define ALL_BITS (0xff<<2)
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { WaitingForPair, WaitingForEncryption, WaitingForControl} MainLobbyistState_t;
//Public function prototypes
bool InitializeMainLobbyist (uint8_t Priority);
bool PostMainLobbyist( ES_Event ThisEvent );
ES_Event RunMainLobbyist (ES_Event ThisEvent);
bool GetPairStatus(void); //returns true if pair status should be set, false if clear
bool GetDecryptError(void); //returns true if decrypt error should be set, false if clear
uint8_t GetPACAddressMSB(void);
uint8_t GetPACAddressLSB(void);
uint8_t GetMyNum(void);
uint8_t GetEncryptionByte(uint8_t);
uint8_t GetACKDATA(void);
#endif ///MAINLOBBYIST_H
/****************************************************************************
Module
MainLobbyist.c
MainLobbyist is the main control code for the hovercraft. It handles all
of the decision making for incoming data packets and actuates the
hovercraft's peripherals accordingly.
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistReceive.h"
#include "Initializations.h"
#include "MainLobbyist.h"
#include "Fan_Control.h"
#include "Flipper_Control.h"
#include "ParseControl.h"
#include "ID_Badge.h"
#include "FlipperSweep.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
#define LARGEST_FRAME_DATA 38 //max number of bytes stored in DataPacket
//The following are indexes into the DataPacket[] array
#define API_IDENT_INDEX 0 //all packets
#define FRAME_ID_INDEX 1 //all packets
#define STATUS_INDEX 2 //all packets
#define SOURCE_MSB_INDEX 1 //all packets
#define SOURCE_LSB_INDEX 2 //all packets
#define RSSI_INDEX 3 //all packets
#define OPTIONS_INDEX 4 //all packets
#define RF_DATA_START_INDEX 5 //all packets
#define HEADER_INDEX 5 //all packets
#define COLOR_INDEX 6 //pair request packet
#define BROADCAST_NUM_INDEX 6 //pair request packet
#define CTRL0_INDEX 6 //control packet
#define CTRL1_INDEX 7 //control packet
#define CTRL2_INDEX 8 //control packet
#define CTRL_CHKSM_INDEX 9 //control packet
#define ENCR_START_INDEX 6 //encryption packet
//The following are the header values for the various data packets
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CONTROL 0x02
#define STATUS 0x03
#define RESEND 0x04
//Constants used for operating the timers
#define TIME_45_SEC 45000
#define TIME_1_SEC 1000
//Masks used for parsing control data packets
#define BROADCAST_NUM_MASK (BIT0HI | BIT1HI | BIT2HI | BIT3HI | BIT4HI | BIT5HI | BIT6HI)
#define COLOR_MASK BIT7HI
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static void GetDataPacketFromRx(void);
static void DoUnpairActions(void);
static bool IsSameSource(void);
static bool DecryptControlData(void);
static void ExecuteControlCommands(void);
void IncrementEncrIndex(void);
/*---------------------------- Module Variables ---------------------------*/
static uint8_t MyPriority;
static uint8_t MyNum = 0; //the lobbyist's badge number
static MainLobbyistState_t CurrentState; //current state in the state machine
static uint8_t StoredSourceAddressMSB = 0x00; //stored MSB source address you compare incoming addresses against
static uint8_t StoredSourceAddressLSB = 0x00; //stored LSB source address you comare incoming addresses aginst
static uint8_t TrySendingCount = 0; //store the number of times you've tried sending a status byte to the PAC (only increments if a transmission failed)
static bool PairingBit = false; //Set to true so Tx function knows the pairing bit should be set; false for clear
static bool DecryptErrorBit = false; //Set to true so Tx function knows there was a decrypt error; false if there wasn't an error
static uint8_t LastSourceAddressMSB = 0x00; //Stores the MSB address of the last PAC you were paired with
static uint8_t LastSourceAddressLSB = 0x00; //Stores the LSB address of the last PAC you were paired with
static uint8_t BroadcastNumber = 0; //the badge number any given PAC broadcasts to this Lobbyist
static bool FirstControlPacketFlag = false; //flag that determines whether we are on the first control packet or not
static uint8_t LastEncCtrlCksm = 0; //last encryption control checksum value
static uint8_t NewEncCtrlCksm = 0; //current encyption control checksum value
static uint8_t eIndex = 0; //index into encryption key
static uint8_t DataPacket[LARGEST_FRAME_DATA]; //array that stores the incoming data sent from the PAC
static uint8_t EncryptionKey[32]; //array that stores the encryption key
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeMainLobbyist
Initializes the hovercraft's peripherals
****************************************************************************/
bool InitializeMainLobbyist (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//Do initializations on all GPIO pins that correspond to peripherals
InitializeDMCPins();
Fan_Control_Init();
Flipper_Control_Init();
//Set CurrentState to WaitingForPair
CurrentState = WaitingForPair;
//Read the resistor badge to determine the lobbyist's credential nubmer
InitializeBadge();
MyNum = GetBadgeNumber();
//Kick off the state machine by posting an initialization event
ThisEvent.EventType = ES_INIT;
PostMainLobbyist(ThisEvent);
return true;
}//End of InitializeMainLobbyist
/****************************************************************************
Function
PostMainLobbyist
Function used by the framework to post events the MainLobbyist's
state machine
****************************************************************************/
bool PostMainLobbyist( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunMainLobbyist
This is the state machine that is used to control the hovercraft's
logic and operation
****************************************************************************/
ES_Event RunMainLobbyist (ES_Event ThisEvent){
//set up local variables
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
MainLobbyistState_t NextState = CurrentState;
switch(CurrentState)
{
//If CurrentState is WaitingForPair///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
case WaitingForPair:
//If you receive an ES_NEW_DATA_RECEIVED event
//Guard: AND it's a request to pair event (check header in RF DATA)
//Guard: AND the request comes from a PAC different than last 45 sec time
if(ThisEvent.EventType == ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == REQ_PAIR){
//Read in data from LobbyistReceive.c and store locally in DataPacket
GetDataPacketFromRx();
//Figure out the broadcast number
BroadcastNumber = DataPacket[BROADCAST_NUM_INDEX] & BROADCAST_NUM_MASK;
//Determine if broadcast was meant for me
if(MyNum == BroadcastNumber){
//Figure out the PAC source address MSB and LSB
uint8_t DataSourceMSB = DataPacket[SOURCE_MSB_INDEX];
uint8_t DataSourceLSB = DataPacket[SOURCE_LSB_INDEX];
//Concatenate both source addresses (new and old) into uint16's to make them easier (and more robust) to compare
uint16_t DataSourceAddress16 = DataSourceMSB;
DataSourceAddress16 = DataSourceAddress16 << 8;
DataSourceAddress16 += DataSourceLSB;
uint16_t LastSourceAddress16 = LastSourceAddressMSB;
LastSourceAddress16 = LastSourceAddress16 << 8;
LastSourceAddress16 += LastSourceAddressLSB;
//figure out if this was the same or different PAC from the last 45 sec time period
if(DataSourceAddress16 != LastSourceAddress16){
//Then store the PAC source address in 2 modular level variables (MSB & LSB)
StoredSourceAddressMSB = DataSourceMSB;
StoredSourceAddressLSB = DataSourceLSB;
//Start 45s pairing timer
ES_Timer_InitTimer(LOBBYIST_45SEC_TIMER, TIME_45_SEC);
//Start 1s transmit timeout timer
ES_Timer_InitTimer(LOBBYIST_1SEC_TIMER, TIME_1_SEC);
//Activate lift fan
Fan_Lift_On();
//Update DMC pairing status
HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_3);
//Update DMC team color
uint8_t TeamColor = DataPacket[COLOR_INDEX] & COLOR_MASK;
if(TeamColor == 0){ //if the team color is red
HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_4);
} else { //if the team color is blue
HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_4);
} //end of sending team color to DMC
//Transmit Status byte with pairing bit set by posting to LobbyistTransmit.c
//Make sure you send all 0s for the return checksum
NewEncCtrlCksm = 0;
PairingBit = true;
DecryptErrorBit = false;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
//Set NextState to WaitingForEncryption
NextState = WaitingForEncryption;
} else{
} //end of new/old data source address comparison if/else statement
} else{
//Do nothing. This wasn't a broadcast meant for me
}// end of BroadcastNumber comparison if/else
} //end of ES_NEW_DATA_RECEIVED if statment
break; //break out of WaitingForPair
//If CurrentState is WaitingForEncryption /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
case WaitingForEncryption:
//If you get an ES_NEW_DATA_RECEIVED event
//Guard: AND it's an Encryption Key data packet
if(ThisEvent.EventType == ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == ENCR_KEY){
//Read in data from LobbyistReceive.c and store locally
GetDataPacketFromRx();
//if the source address matches the one you expected to see, then store the data as the encryption key
if(IsSameSource()){
//save encryption key locally
for(uint8_t i=(ENCR_START_INDEX); i <= LARGEST_FRAME_DATA; i++){
EncryptionKey[i-ENCR_START_INDEX] = DataPacket[i];
}
//Restart 1s transmit timeout timer
ES_Timer_InitTimer(LOBBYIST_1SEC_TIMER, TIME_1_SEC);
//Set FirstControlPacketFlag to true
FirstControlPacketFlag = true;
//Transmit Status byte with pairing bit set by posting to LobbyistTransmit.c
PairingBit = true;
NewEncCtrlCksm = 0;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
//Resent the index into the encryption key to 0 (this is the only time this should ever happen...when you get a completely new encryption key)
eIndex = 0;
//Set NextState to WaitingForEncryption
NextState = WaitingForControl;
} else{
//the sources were different, so don't use the data
} //end of source match if/else check
}//end of ES_NEW_DATA_RECEIVED if statement
//If you get an ES_TIMEOUT[1sec timer]
if(ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == LOBBYIST_1SEC_TIMER){
DoUnpairActions();
//Transmit status byte with pairing bit CLEARED by posting to LobbyistTransmit
PairingBit = false;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
//Set NextState to WaitingForPair
NextState = WaitingForPair;
}//end of ES_TIMEOUT if statement
break;//break out of WaitingForPair
//If CurrentState is WaitingForControl/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
case WaitingForControl:
//If you get an ES_NEW_DATA_RECEIVED event
//Guard:AND it's a Control data packet
//Guard:AND the source address matches the ones you have stored
//Guard: AND FirstControlPacketFlag = true
if(ThisEvent.EventType == ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == CONTROL && FirstControlPacketFlag){
//Read in data from LobbyistReceive.c and store locally
GetDataPacketFromRx();
if(IsSameSource()){
//Restart 1s transmit timeout timer
ES_Timer_InitTimer(LOBBYIST_1SEC_TIMER, TIME_1_SEC);
//save the control packet encrypted checksum value into LastEncCtrlCksm
LastEncCtrlCksm = DataPacket[CTRL_CHKSM_INDEX];
//decrypt packet
if(DecryptControlData()) { // DecryptControlData returns true for good decryption
DecryptErrorBit = false;
} else {
DecryptErrorBit = true;
}
//set FirstControlPacketFlag to false
FirstControlPacketFlag = false;
//execute control commands
ExecuteControlCommands();
//Transmit STATUS to LobbyistTransmit with pairing bit SET and
PairingBit = true;
NewEncCtrlCksm = LastEncCtrlCksm;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
} else{
//the sources were different, so don't use the data
} //end of source match if/else check
}//end of ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == CONTROL && FirstControlPacketFlag if statement
//If you get an ES_NEW_DATA_RECEIVED event
//Guard:AND it's a Control data packet
//Guard:AND the source address matches the ones you have stored
//Guard: AND FirstControlPacketFlag = false
else if(ThisEvent.EventType == ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == CONTROL && FirstControlPacketFlag == false){
//Read in data from LobbyistReceive.c and store locally
GetDataPacketFromRx();
if(IsSameSource()){
NewEncCtrlCksm = DataPacket[CTRL_CHKSM_INDEX];
if(NewEncCtrlCksm == LastEncCtrlCksm){ //we got the exact same command packet as last time
//we got the exact same control packet as last time (i.e. a transmission error occurred as some point)
//Restart 1s transmit timeout timer
ES_Timer_InitTimer(LOBBYIST_1SEC_TIMER, TIME_1_SEC);
//post an ES_BEGIN_TRANSMIT with a RESEND parameter
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = RESEND;
PostLobbyistTransmit(ThisEvent);
} else{ //we got a completely new command packet
//Restart 1s transmit timeout timer
ES_Timer_InitTimer(LOBBYIST_1SEC_TIMER, TIME_1_SEC);
//save the control packet encrypted checksum value into LastEncCtrlCksm
LastEncCtrlCksm = DataPacket[CTRL_CHKSM_INDEX];
//decrypt packet
if(DecryptControlData()) { // DecryptControlData returns true for good decryption
DecryptErrorBit = false; //good decryption
} else {
DecryptErrorBit = true; //bad decryption
}
//execute control commands
ExecuteControlCommands();
//Transmit STATUS to LobbyistTransmit with pairing bit SET and
if((DataPacket[CTRL2_INDEX] & BIT1HI) == 0){
PairingBit = true;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
}
}// end of EncCtrlCksm compare if/else
} else{ //the sources were different
//the sources were different, so don't use the data
}//end of IsSameSource check if statement
}//end of ES_NEW_DATA_RECEIVED && ThisEvent.EventParam == CONTROL && FirstControlPacketFlag == false statement
//If you get an ES_TIMEOUT[45s timer] or ES_TIMEOUT[1s timer] or ES_PAC_MANUAL_UNPAIR event
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == LOBBYIST_45SEC_TIMER)
|| (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == LOBBYIST_1SEC_TIMER)
|| (ThisEvent.EventType == ES_PAC_MANUAL_UNPAIR)){
if(ThisEvent.EventParam == LOBBYIST_45SEC_TIMER){
} else if(ThisEvent.EventParam == LOBBYIST_1SEC_TIMER){
} else {
}
ExecuteControlCommands();
DoUnpairActions();
//Transmit Status wiht pairing bit CLEARED by posting to LobbyistTransmit
PairingBit = false;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
//Set NextState to WaitingForPair
NextState = WaitingForPair;
}
//If you get an ES_BAD_DECRYPTION event,
if(ThisEvent.EventType == ES_BAD_DECRYPTION){
DoUnpairActions();
//Transmit Status with pairing bit CLEARED and 'decrypt failed' bit Set
PairingBit = false;
DecryptErrorBit = true;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = STATUS;
PostLobbyistTransmit(ThisEvent);
//Set NextState to WaitingForPair
NextState = WaitingForPair;
}//end of ES_BAD_DECRYPTION if statement
break;//break out of WaitingForControl
}//End switch statement
CurrentState = NextState;
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunMainLobbyist
bool GetPairStatus(void){
//returns true if pair status should be set, false if clear
return PairingBit;
}
bool GetDecryptError(void){
//returns true if decrypt error should be set, false if clear
return DecryptErrorBit;
}
uint8_t GetPACAddressMSB(void){
//returns the SourceAddressMSB so the LobbyistTransmit can use it
return StoredSourceAddressMSB;
}
uint8_t GetPACAddressLSB(void){
//returns the SourceAddressLSB so the LobbyistTransmit can use it
return StoredSourceAddressLSB;
}
uint8_t GetMyNum(void){
//returns the lobbyist's badge credential number
return MyNum;
}
void DoUnpairActions(void){
//post an unpair event to LobbyistReceive so it can set its decrypt flag back to false from whatever state it's in and go back to WiatingFor0x7e
ES_Event ThisEvent;
ThisEvent.EventType = ES_FAILURE_UNPAIR;
PostLobbyistReceive(ThisEvent);
//reinitialize other variables
PairingBit = false;
DecryptErrorBit = false;
//Set values of LastSourceAddress MSB and LSB (so main lobbyist can check if the PAC it's pairing to is the same as the last PAC it paired to)
LastSourceAddressMSB = StoredSourceAddressMSB;
LastSourceAddressLSB = StoredSourceAddressLSB;
//Deactivate the lift fan
Fan_All_Off();
//Indicate 'available for pairing' on DMC
HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_3);
//Reset flippers to nominal position
WritePulseWidthLeft(1500);
WritePulseWidthRight(1500);
Reset_Flippers();
}
void GetDataPacketFromRx(void){
//clear the data packet in preparation for receiving new data
for(uint8_t i=0; i < LARGEST_FRAME_DATA; i++){
DataPacket[i] = 0;
}
//access LobbyistReceive.c and read in the stored data packet that was received through UART
for(uint8_t i=0; i < LARGEST_FRAME_DATA; i++){
DataPacket[i] = GetNextRxByte(i);
}
}
uint8_t GetEncryptionByte(uint8_t ThisIndex){
//this getter function allows LobbyistRecieve.c to store the encryption key that was found
return EncryptionKey[ThisIndex];
}
bool IsSameSource(){
//tests to see if the new data is coming from the same PAC source as last time
uint8_t NewDataAddressMSB = DataPacket[SOURCE_MSB_INDEX];
uint8_t NewDataAddressLSB = DataPacket[SOURCE_LSB_INDEX];
if(StoredSourceAddressMSB == NewDataAddressMSB && StoredSourceAddressLSB == NewDataAddressLSB){
return true;
} else{
return false;
}
}
bool DecryptControlData(void){
//Decrypts the control data that was read in from LobbyistReceive
DataPacket[HEADER_INDEX] = DataPacket[HEADER_INDEX]^EncryptionKey[eIndex];
IncrementEncrIndex();
DataPacket[CTRL0_INDEX] = DataPacket[CTRL0_INDEX]^EncryptionKey[eIndex];
IncrementEncrIndex();
DataPacket[CTRL1_INDEX] = DataPacket[CTRL1_INDEX]^EncryptionKey[eIndex];
IncrementEncrIndex();
DataPacket[CTRL2_INDEX] = DataPacket[CTRL2_INDEX]^EncryptionKey[eIndex];
IncrementEncrIndex();
DataPacket[CTRL_CHKSM_INDEX] = DataPacket[CTRL_CHKSM_INDEX]^EncryptionKey[eIndex];
//the last thing we should do in this function is increment the control function
IncrementEncrIndex();
// add up ctrl bytes 0-3
uint8_t CtrlSum = DataPacket[HEADER_INDEX] + DataPacket[CTRL0_INDEX] + DataPacket[CTRL1_INDEX] + DataPacket[CTRL2_INDEX];
// check if decrypted bytes 0-3 add up to decrypted ctrl_cksum byte 4
if (CtrlSum == DataPacket[CTRL_CHKSM_INDEX]){
return true;
} else {
return false;
}
}
void IncrementEncrIndex(void){
//increment the index into the encryption key
eIndex = (eIndex + 1) % 32;
}
uint8_t GetACKDATA(void){
//access the encryption checksum
return NewEncCtrlCksm;
}
void ExecuteControlCommands(void){
//parse the data that was sent to you as part of a control packet
uint8_t UnpairCommand = DataPacket[CTRL2_INDEX] & BIT1HI; //this should be an UNSIGNED integer
uint8_t Brake = DataPacket[CTRL2_INDEX] & BIT0HI; //this should be an UNSIGNED integer
int8_t FBSpeed = DataPacket[CTRL0_INDEX]; //this should be a SIGNED integer
int8_t LRControl = DataPacket[CTRL1_INDEX]; //this should be a SIGNED integer
//Call function in ParseControl.c to decide how to handle this control information
DecideControl(UnpairCommand, Brake, FBSpeed, LRControl);
}
Fan_Control is responsible for initializing and controlling the lift fan and the PWM signals that drive the propellers
/****************************************************************************
Header
Fan_Control.h
Module Revision
1.0.1
****************************************************************************/
#ifndef Fan_Control_H
#define Fan_Control_H
#include
#include
#include
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
void Fan_Control_Init(void);
void Fan_Lift_On(void);
void Fan_Lift_Off(void);
void Fan_SetDuty_Left(int);
void Fan_SetDuty_Right(int);
void Fan_All_Off(void);
//***************************************************************************
#endif /* Fan_Control_H */
/****************************************************************************
Module
Fan_Control.c
Revision
1.0.1
Description
Module for initializing and controlling PWM for left & right DC motors & lift fan
Notes
History
When Who What/Why
-------------- --- --------
02/01/16 17:50 lxw revised for lab 8 - team 4
11/10/15 20:50 lxw completed placeholder service template
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for the framework and this service
*/
#include "Fan_Control.h"
#include "BITDEFS.h"
#include
#include
#include
#include
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_pwm.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
/*----------------------------- Module Defines ----------------------------*/
// Readability defines:
#define ALL_BITS (0xff<<2)
#define BitsPerNibble 4
#define LMOT_REVERSE BIT5HI
#define RMOT_REVERSE BIT4HI
#define LMOT_PWM BIT4HI
#define RMOT_PWM BIT5HI
/*---------------------------- Module Variables ---------------------------*/
// Data private to the module
static uint16_t PeriodInMSx10 = 1; //drive frequency of 10kHz
static uint16_t PWMTicksPerMS = 1250;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
Fan_Control_Init
Initializes the control structure for the propellers
****************************************************************************/
void Fan_Control_Init(void){
//initialization for PWM on PB4 & PB5 (PWM0_1;genA/B;PWM2/3)
//enable clock to the PWM Module
HWREG(SYSCTL_RCGCPWM) |= SYSCTL_RCGCPWM_R0;
//enable the clock to Port A, B, & E
HWREG(SYSCTL_RCGCGPIO) |= (SYSCTL_RCGCGPIO_R0 | SYSCTL_RCGCGPIO_R1 | SYSCTL_RCGCGPIO_R4);
//select the PWM clock as System Clock/32
HWREG(SYSCTL_RCC) = (HWREG(SYSCTL_RCC) & ~SYSCTL_RCC_PWMDIV_M) | (SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_32);
//make sure that the PWM module clock has gotten going
while ((HWREG(SYSCTL_PRPWM) & SYSCTL_PRPWM_R0) != SYSCTL_PRPWM_R0);
//disable the PWM while initializing
HWREG(PWM0_BASE+PWM_O_1_CTL) = 0;
//program generator A/B to go to 1 at rising compare A/B, 0 on falling compare A/B
HWREG( PWM0_BASE+PWM_O_1_GENA) = (PWM_1_GENA_ACTCMPAU_ONE | PWM_1_GENA_ACTCMPAD_ZERO);
HWREG( PWM0_BASE+PWM_O_1_GENB) = (PWM_1_GENB_ACTCMPBU_ONE | PWM_1_GENB_ACTCMPBD_ZERO);
//set the PWM period. Since we are counting both up & down, we initialize
//the load register to 1/2 the desired total period. We will also program
//the match compare registers to 1/2 the desired high time
HWREG( PWM0_BASE+PWM_O_1_LOAD) = ((PeriodInMSx10 * PWMTicksPerMS)/10-1)>>1;
//set the initial Duty cycle on generators A & B to 0%
//enable the PWM outputs (2 & 3)
HWREG( PWM0_BASE+PWM_O_ENABLE) |= (PWM_ENABLE_PWM2EN | PWM_ENABLE_PWM3EN);
//now configure the Port B pins 4 & 5 to be PWM output
//start by selecting the alternate function for PB4 & PB5
HWREG(GPIO_PORTB_BASE+GPIO_O_AFSEL) |= (LMOT_PWM | RMOT_PWM);
//now choose to map PWM to those pins, this is a max value of 4 that we
//want to use for specifying the function on bits 0 & 1
HWREG(GPIO_PORTB_BASE+GPIO_O_PCTL) = (HWREG(GPIO_PORTB_BASE+GPIO_O_PCTL) & 0xff00ffff) + (4<<(4*BitsPerNibble)) + (4<<(5*BitsPerNibble));
//enable required pins on Port B for digital I/O
HWREG(GPIO_PORTB_BASE+GPIO_O_DEN) |= (LMOT_PWM | RMOT_PWM);
//make required pins on Port B into output
HWREG(GPIO_PORTB_BASE+GPIO_O_DIR) |= (LMOT_PWM | RMOT_PWM);
//enable required pins on Port E for digital I/O
HWREG(GPIO_PORTE_BASE+GPIO_O_DEN) |= (LMOT_REVERSE | RMOT_REVERSE);
//make required pins on Port E into output
HWREG(GPIO_PORTE_BASE+GPIO_O_DIR) |= (LMOT_REVERSE | RMOT_REVERSE);
//set both reverse lines LOW initially
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= (~LMOT_REVERSE & ~RMOT_REVERSE);
//enable lift fan pin on Port A for digital I/O
HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= (GPIO_PIN_5);
//make lift fan pin into output
HWREG(GPIO_PORTA_BASE + GPIO_O_DIR) |= (GPIO_PIN_5);
//leave lift fan pin low initially
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ALL_BITS)) &= (BIT5LO);
//set the up/down count mode, enable the PWM generator and make
//the generator updates locally synchronized to zero count
HWREG(PWM0_BASE+ PWM_O_1_CTL) = (PWM_1_CTL_MODE | PWM_1_CTL_ENABLE | PWM_1_CTL_GENAUPD_LS | PWM_1_CTL_GENBUPD_LS);
}
/****************************************************************************
Function
Fan_Lift_On
Turns the lift fan on
****************************************************************************/
void Fan_Lift_On(void){
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ALL_BITS)) |= (BIT5HI); //lift fan on
}
/****************************************************************************
Function
Fan_Lift_Off
Turns the lift fan off
****************************************************************************/
void Fan_Lift_Off(void){
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ALL_BITS)) &= (BIT5LO); //lift fan off
}
/****************************************************************************
Function
Fan_All_Off
Turns the lift fan and both of the propellers off
****************************************************************************/
void Fan_All_Off(void){
HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA + ALL_BITS)) &= (BIT5LO); //lift fan off
Fan_SetDuty_Left(0); //left thrust off
Fan_SetDuty_Right(0); //left thrust off
}
/****************************************************************************
Function
Fan_SetDuty_Left
Sets PWM duty cycle for left motor
****************************************************************************/
void Fan_SetDuty_Left(int newDuty){
//if newDuty is negative
if(newDuty < 0){
//set LMOT_REVERSE pin HI
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) |= (LMOT_REVERSE);
//set newDuty to positive
newDuty = abs(newDuty);
//calculate the inverted duty from newDuty
newDuty = 100 - newDuty;
}
//else if newDuty is positive or 0
else{
//set LMOT_REVERSE pin LO
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= (~LMOT_REVERSE);
}
//if newDuty is greater than 0 or less than 100
if(newDuty > 0 && newDuty < 100){
//set duty cycle to newDuty
HWREG(PWM0_BASE+PWM_O_1_CMPA) = (((HWREG(PWM0_BASE+PWM_O_1_LOAD) << 1) + 1) * (100 - (uint8_t)newDuty) / 100) >> 1;
//restore normal functionality (for returning from 0 or 100 duty cycle)
HWREG(PWM0_BASE+PWM_O_1_GENA) = (PWM_1_GENA_ACTCMPAU_ONE | PWM_1_GENA_ACTCMPAD_ZERO);
}
//else if newDuty is 0
else if(newDuty == 0){
//set duty cycle to 0
HWREG(PWM0_BASE+PWM_O_1_CMPA) = 0;
//set generator A constant LO
HWREG(PWM0_BASE+PWM_O_1_GENA) = PWM_0_GENA_ACTZERO_ZERO;
}
//else if newDuty is 100
else if(newDuty >= 100){
//set duty cycle to 0
HWREG(PWM0_BASE+PWM_O_1_CMPA) = 0;
//set generator A constant HI
HWREG(PWM0_BASE+PWM_O_1_GENA) = PWM_0_GENA_ACTZERO_ONE;
}
}
/****************************************************************************
Function
Fan_SetDuty_Right
Sets PWM duty cycle for ri-ght motor
****************************************************************************/
void Fan_SetDuty_Right(int newDuty){
//if newDuty is negative
if(newDuty < 0){
//set RMOT_REVERSE pin HI
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) |= (RMOT_REVERSE);
//set newDuty to positive
newDuty = abs(newDuty);
//calculate the inverted duty from newDuty
newDuty = 100 - newDuty;
}
//else if newDuty is positive or 0
else{
//set RMOT_REVERSE pin LO
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= (~RMOT_REVERSE);
}
//if newDuty is greater than 0 or less than 100
if(newDuty > 0 && newDuty < 100){
//set duty cycle to newDuty
HWREG(PWM0_BASE+PWM_O_1_CMPB) = (((HWREG(PWM0_BASE+PWM_O_1_LOAD) << 1) + 1) * (100 - (uint8_t)newDuty) / 100) >> 1;
//restore normal functionality (for returning from 0 or 100 duty cycle)
HWREG(PWM0_BASE+PWM_O_1_GENB) = (PWM_1_GENB_ACTCMPBU_ONE | PWM_1_GENB_ACTCMPBD_ZERO);
}
//else if newDuty is 0
else if(newDuty == 0){
//set duty cycle to 0
HWREG(PWM0_BASE+PWM_O_1_CMPB) = 0;
//set generator B constant LO
HWREG(PWM0_BASE+PWM_O_1_GENB) = PWM_0_GENB_ACTZERO_ZERO;
}
//else if newDuty is 100
else if(newDuty >= 100){
//set duty cycle to 0
HWREG(PWM0_BASE+PWM_O_1_CMPB) = 0;
//set generator B constant HI
HWREG(PWM0_BASE+PWM_O_1_GENB) = PWM_0_GENB_ACTZERO_ONE;
}
}
LobbyistTransmit is responsible for transmitting information via UART from the hovercraft (Lobbyist) back to the controller (PAC)
#ifndef LobbyistTransmit_H
#define LobbyistTransmit_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { WaitingToSendByteOne, SendingPacket} LobbyistTransmitState_t;
//Public function prototypes
bool InitializeLobbyistTransmit ( uint8_t Priority );
bool PostLobbyistTransmit ( ES_Event ThisEvent );
ES_Event RunLobbyistTransmit ( ES_Event ThisEvent );
void LobbyistTransmitISR ( void );
uint8_t GetLastEncryptedCTRLChecksum ( void );
#endif ///LobbyistTransmit_H
/****************************************************************************
Module:
LobbyistTransmit.c
LobbyistTransmit is responsible for transmitting information via UART
from the hovercraft (Lobbyist) back to the controller (PAC)
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistTransmit.h"
#include "Initializations.h"
// include uart, interrupt lib
#include "inc/hw_uart.h"
#include "driverlib/interrupt.h"
#include "inc/hw_nvic.h"
// include lobbyist main service,UI service header
#include "MainLobbyist.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
// Types of packets
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CTRL 0x02
#define STATUS 0x03
#define RESEND 0x04
// Packet size overhead (everything besides
#define PACKET_SIZE_OVERHEAD 9
// Frame data overhead
#define FRAME_DATA_OVERHEAD 5
// Frame data bytes start position
#define FRAME_DATA_START 3
// RF Data bytes start position
#define RF_DATA_START 8
// RF Data Length
#define REQ_PAIR_SIZE 2
#define ENCR_KEY_SIZE 33
#define CTRL_SIZE 5
#define STATUS_SIZE 3
// Packet Pieces
#define START_DELIMTER 0x7e
#define LENGTH_MSB 0x00
#define API_ID 0x01
#define FRAME_ID 0x00
#define OPTIONS 0x00
// REQ_PAIR Bit Positions
#define TEAM_COLOR BIT7HI
// Status Bit Positions
#define DEC_ERR BIT1HI
#define PAIR BIT0HI
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static bool ConstructTxPacket ( uint8_t );
static void CreateXBeeHeader ( void );
static void SetXBeeChecksum ( void );
static bool BeginLobbyistTransmit ( void );
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// States defined in the header file (LobbyistTransmit.h)
static LobbyistTransmitState_t CurrentState;
// Encryption Variables
static uint8_t EncryptKey[32] = { 0 }; // Encrypt key for Lobbyist is zero (does nothing)
static uint8_t EncryptIndex = 0; // Tells us how far into the key we've rotated
// Packet Variables
static uint8_t PacketType;
static uint8_t index = 0;
static uint8_t PacketSize = 0;
static uint8_t FrameDataSize; // Equivalent to length LSB in XBee Tx Packet
static uint8_t RFDataSize;
static uint8_t DestAddressMSB = 0;
static uint8_t DestAddressLSB = 0;
static uint8_t StatusData = 0;
static uint8_t ACKDATA = 0;
//The TxPacket array stores the outgoing data, starting with the API Identifier (index 0) and ending with the RF Data.
//It is statically allocated and is large enough to hold the largest-anticipated data transmission, which is the encryption key data
static uint8_t TxPacket[41];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeLobbyistTransmit
Initializes everything relating to transmitting information via the UART
from the Lobbyist back to the PAC
****************************************************************************/
bool InitializeLobbyistTransmit (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//The UART for the Lobbyist is not initialized here, because the
// lobbyist will receive data before sending any.
//Set CurrentState of state machine
CurrentState = WaitingToSendByteOne;
// Post Event ES_Init to this queue (this service)
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true) {
// End of initialization (return True)
return true;
} else {
return false;
}
}//End of InitializeLobbyistTransmit (return True)
/****************************************************************************
Function
PostLobbyistTransmit
Function used by the framework to post events to the LobbyistTransmit
state machine
****************************************************************************/
bool PostLobbyistTransmit( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/****************************************************************************
Function
RunLobbyistTransmit
State machine that decides what to do with events posted to LobbyistTransmit
****************************************************************************/
ES_Event RunLobbyistTransmit (ES_Event ThisEvent){
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
switch(CurrentState) {
/***** If CurrentState is WaitingToSendByteOne *****/
case WaitingToSendByteOne:
if (ThisEvent.EventType == ES_BEGIN_TRANSMIT) { // ADD EVENT TYPE TO ES_CONFIGURE
// Save away event param that has packet type
PacketType = ThisEvent.EventParam;
// Construct Packet (this function also sets PacketSize)
if (ConstructTxPacket( PacketType )) { // Packet was created successfully
// Reset index (index indexes into TxPacket)
index = 0;
// Move Current State to sending byte
CurrentState = SendingPacket;
// Begin the transmit
BeginLobbyistTransmit();
} else {
// Do nothing, exit transmit
} // END IF constructed packet success/failure
} // END IF EVENT TYPE
break; // END CASE WaitingToSendByteOne
/***** If CurrentState is SendingPacket *****/
case SendingPacket:
if ( ThisEvent.EventType == ES_ALL_BYTES_SENT ) {
// Change state to WaitingToSendByteOne (we reset on ES_BEGIN_TRANSMIT event)
CurrentState = WaitingToSendByteOne;
} else if ( ThisEvent.EventType == ES_LOST_CONNECTION ) {
// Only switch current state to wait2sendbyte1
CurrentState = WaitingToSendByteOne;
} // END IF Event Types
break; // END CASE SendingByte
}//END SWITCH STATEMENT
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunLobbyistTransmit
/****************************************************************************
Function
LobbyistTransmitISR
Handles the UART TX Interrupt
****************************************************************************/
void LobbyistTransmitISR ( void ) {
// If TXMIS is set (TX byte finished sending interrupt)
if (HWREG(UART1_BASE + UART_O_MIS) & UART_MIS_TXMIS) {
// (Writing to the TX FIFO should technically clear the int. but let's make sure)
// Clear TXIC in UARTICR (interrupt clear register)
HWREG(UART1_BASE + UART_O_ICR) |= UART_ICR_TXIC;
// If we've sent all bytes of the packet
if (index == PacketSize) {
// Disable UART TX interrupts
// Clear Interrupt Mask bit in UART Mask Reg
HWREG(UART1_BASE + UART_O_IM) &= ~UART_IM_TXIM;
// Post ES_ALL_BYTES_SENT to this service
ES_Event ThisEvent;
ThisEvent.EventType = ES_ALL_BYTES_SENT;
ThisEvent.EventParam = 0; // Don't really need this
PostLobbyistTransmit( ThisEvent );
} else if (index == (PacketSize - 1)) {
// We send the last byte
// Write new data to register (UARTDR: UART data register)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Increment index to let us know that the last byte of the packet was sent
index++;
} else {
// We still have more bytes to send
// Write new data to register (UARTDR: UART data register)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Increment index
index++;
}
} else {
// Not a TX interrupt, do nothing
}
}
/***************************************************************************
private functions
***************************************************************************/
/****************************************************************************
Function
ConstructPacket
Notes
Constructs the packet to send.
Takes in type of packet
****************************************************************************/
static bool ConstructTxPacket ( uint8_t TypeOfPacket ) {
// Get info for packet construction
if (TypeOfPacket == STATUS) {
// If TypeOfPacket is STATUS
// Set PacketSize
PacketSize = PACKET_SIZE_OVERHEAD + STATUS_SIZE;
// Set FrameDataSize
FrameDataSize = FRAME_DATA_OVERHEAD + STATUS_SIZE;
// Set RFDataSize
RFDataSize = STATUS_SIZE;
// Get Dest Address from RX service
DestAddressMSB = GetPACAddressMSB();
DestAddressLSB = GetPACAddressLSB();
// Create XBee Header: (XBee bytes up to RF Data)
CreateXBeeHeader();
// Get decryption error status from RX service
if (GetDecryptError()) {
StatusData |= DEC_ERR;
} else {
StatusData &= ~DEC_ERR;
}
// Get pair status from main state machine
if (GetPairStatus()) {
StatusData |= PAIR;
} else {
StatusData &= ~PAIR;
}
ACKDATA = GetACKDATA();
// Fill Out RF Data of TXPacket (Don't Encrypt)
TxPacket[RF_DATA_START] = TypeOfPacket;
TxPacket[RF_DATA_START+1] = StatusData;
TxPacket[RF_DATA_START+2] = ACKDATA;
// Set XBee Checksum
SetXBeeChecksum();
// Return true: packet successfully created
return true;
} else if (TypeOfPacket == RESEND) {
// If TypeOfPacket is RESEND (0x04)
// Packet stays the same, do not modify the packet
return true;
} else {
// Do Nothing (bad packet type)
// Return false: packet not created
return false;
}
// Finish and go back to SM
}
/****************************************************************************
Function
CreateXBeeHeader
Makes the XBee Header up to the RF Data
****************************************************************************/
static void CreateXBeeHeader ( void ) {
// Build XBee Header
TxPacket[0] = START_DELIMTER;
TxPacket[1] = LENGTH_MSB;
TxPacket[2] = FrameDataSize; // Update in ContructTx before calling me
TxPacket[3] = API_ID;
TxPacket[4] = FRAME_ID;
TxPacket[5] = DestAddressMSB; // Update in ContructTx before calling me
TxPacket[6] = DestAddressLSB; // Update in ContructTx before calling me
TxPacket[7] = OPTIONS;
}
/****************************************************************************
Function
SetXBeeChecksum
Calculates then sets the checksum for the frame data
****************************************************************************/
static void SetXBeeChecksum ( void ) {
// Function variables
uint8_t i;
uint8_t RollingSum;
uint8_t XBeeChecksum;
// Set RollingSum to zero
RollingSum = 0;
// Calculate by looping through bytes in frame data
for ( i = FRAME_DATA_START; i < FRAME_DATA_START + FrameDataSize ; i++ ) {
// Add current TxPacket byte to rolling sum
RollingSum += TxPacket[i];
}
// Subtract rolling sum from 0xff to get actual checksum
XBeeChecksum = 0xff - RollingSum;
// Set XBeeChecksum as last byte in XBee packet
TxPacket[FRAME_DATA_START + FrameDataSize] = XBeeChecksum;
}
/****************************************************************************
Function
BeginLobbyistTransmit
This code is called when we want to transmit a packet,
and this function will cause a UART Tx Interrupt.
****************************************************************************/
static bool BeginLobbyistTransmit ( void ) {
// Non-Interrupt TX Code
// If TXFE is set (there is room to transfer a byte)
if ( HWREG(UART1_BASE + UART_O_FR) & UART_FR_TXFE ) {
// Write the new byte to the single-stack FIFO (full FIFO is diasbled)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Initialize UART TX Interrupt:
// Set Interrupt Mask bit in UART Mask Reg
// (This will fire an interrupt when the byte finishes sending)
HWREG(UART1_BASE + UART_O_IM) |= UART_IM_TXIM;
// Increment index
index++;
// Return true
return true; // First byte transmission successful
} else {
return false; // TX failed
}
}
ParseControl decides how to control the hovercraft's lift fan and propellers for a given control packet
/****************************************************************************
Header
ParseControl.h
Module Revision
1.0.1
****************************************************************************/
#ifndef PARSE_CONTROL_H
#define PARSE_CONTROL_H
#include
#include
#include
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
void DecideControl(uint8_t UnpairCommand, uint8_t Brake, int8_t FBSpeed, int8_t LRControl);
//***************************************************************************
#endif /* PARSE_CONTROL_H */
/****************************************************************************
Module
ParseControl.c
Module for deciding how to control the prop and lift fans given a set of control bytes
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for the framework and this service
*/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistReceive.h"
#include "Initializations.h"
#include "MainLobbyist.h"
#include "Fan_Control.h"
#include "FlipperSweep.h"
/*----------------------------- Module Defines ----------------------------*/
// Readability defines:
#define ALL_BITS (0xff<<2)
//NOTE! Only use LEFT_PROP_OFFSET and RIGHT_PROP_OFFSET to SLOW DOWN whichever motor is running faster
//For whichever motor is running slower, just leave its offset at 0
#define LEFT_PROP_OFFSET 0
#define RIGHT_PROP_OFFSET 0
#define START_DUTY_OFFSET 20 //prop motors don't start turning until duty cycle hits this value
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
void CombineControls(int8_t FBSpeed, int8_t LRControl);
void ExecuteControl(int8_t FBSpeed, int8_t LRControl);
int8_t GetDuty(int8_t input);
int8_t ClampLeftDuty(int8_t Duty);
int8_t ClampRightDuty(int8_t Duty);
/*---------------------------- Module Variables ---------------------------*/
// Data private to the module
static bool BrakeOn = false;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: DecideControl
Decides if Lobbyist should unpair, brake, or execute control commands
****************************************************************************/
void DecideControl(uint8_t UnpairCommand, uint8_t Brake, int8_t FBSpeed, int8_t LRControl){
ES_Event ThisEvent;
ES_Event FlipperEvent;
//Note: LRControl and FBSpeed are SIGNED integers
//Handle all the cases when the PAC unpairs, brakes, and unbrakes
if(UnpairCommand == BIT1HI){ //if an unpair command is received, turn the lift fan off
Fan_All_Off();
ThisEvent.EventType = ES_PAC_MANUAL_UNPAIR;
PostMainLobbyist(ThisEvent);
FlipperEvent.EventType = ES_FLIPPERS_OFF;
PostFlipperSweep(FlipperEvent);
return;
} else if(Brake == 1){ //if a brake command is received, turn all the fans off. Else, make sure the lift fan is on
Fan_All_Off();
BrakeOn = true;
FlipperEvent.EventType = ES_FLIPPERS_OFF;
PostFlipperSweep(FlipperEvent);
return;
} else if(Brake ==0) { //Make sure the lift fan is on because you're paired and the brake is off
Fan_Lift_On();
BrakeOn = false;
} else {
//do nothing more here
}
ExecuteControl(FBSpeed, LRControl);
}
/****************************************************************************
Function: ExecuteControl
Decides speeds for the props
****************************************************************************/
void ExecuteControl(int8_t FBSpeed, int8_t LRControl){
ES_Event FlipperEvent;
if(BrakeOn == false){ //You're only allowed to drive the hovercraft props if the brake is off.
int8_t Duty;
int8_t LeftDuty;
int8_t RightDuty;
//Handle all the combinations of LRControl and FBSpeed
if(LRControl == 0 && FBSpeed == 0){ //If LRControl and FBSpeed are both 0, stop both propellers
Fan_SetDuty_Left(0);
Fan_SetDuty_Right(0);
FlipperEvent.EventType = ES_FLIPPERS_OFF;
PostFlipperSweep(FlipperEvent);
} else if(LRControl == 0 && FBSpeed != 0){ //If LRControl is 0, just go forward/backward
//Use FBSpeed value to go forward/backward
Duty = GetDuty(FBSpeed); //Duty will always be returned from the function as a positive value
FlipperEvent.EventType = ES_FLIPPERS_ON;
FlipperEvent.EventParam = (uint16_t)Duty;
PostFlipperSweep(FlipperEvent);
LeftDuty = ClampLeftDuty(Duty);
RightDuty = ClampRightDuty(Duty);
if(FBSpeed < 0){
Fan_SetDuty_Left(-LeftDuty);
Fan_SetDuty_Right(-RightDuty);
} else { //if FBSpeed > 0
Fan_SetDuty_Left(LeftDuty);
Fan_SetDuty_Right(RightDuty);
}
} else if(FBSpeed == 0 && LRControl != 0){ //If FBSpeed is 0, just go left/right
//Use LRControl to turn left/right
Duty = GetDuty(LRControl); //returns a positive duty cycle
LeftDuty = ClampLeftDuty(Duty);
RightDuty = ClampRightDuty(Duty);
FlipperEvent.EventType = ES_FLIPPERS_ON;
FlipperEvent.EventParam = (uint16_t)Duty;
PostFlipperSweep(FlipperEvent);
if(LRControl < 0){ //turn left
Fan_SetDuty_Left(-LeftDuty);
Fan_SetDuty_Right(RightDuty);
} else { //turn right
Fan_SetDuty_Left(LeftDuty);
Fan_SetDuty_Right(-RightDuty);
}
} else if(FBSpeed < 0){ //If you're reversing (and LRControl != 0), you're not allowed to turn left or right until you start driving forward again
Duty = GetDuty(FBSpeed); //returns a positive duty cycle
LeftDuty = ClampLeftDuty(Duty);
RightDuty = ClampRightDuty(Duty);
FlipperEvent.EventType = ES_FLIPPERS_ON;
FlipperEvent.EventParam = (uint16_t)Duty;
PostFlipperSweep(FlipperEvent);
Fan_SetDuty_Left(-LeftDuty);
Fan_SetDuty_Right(-RightDuty);
} else if(FBSpeed > 0) { //If you're driving forward and FBSpeed!=0 and LRControl!=0, combine FBSpeed with LRControl
CombineControls(FBSpeed, LRControl);
} else{
//do nothing
}
}
}
/****************************************************************************
Function: CombineControls
Decides the prop speeds when FBSpeed and LRControl variables are both nonzero
****************************************************************************/
void CombineControls(int8_t FBSpeed, int8_t LRControl){
ES_Event FlipperEvent;
//convert forward speed into a fraction (note, it's inherent in getting into this function that FBSpeed > 0)
double FractionForward = ((double)FBSpeed/127.0); //always positive value
//convert LRControl into a percent turn (e.g. 0% right turn is pi/2 on unit circle, 100% right turn is 0pi on unit circle, 100% left turn is pi on unit circle)
double PercentTurn = ((double)LRControl/127.0) * 100; //can be negative or positive value
//apply fraction to amount of turn you want to accomplish (based off of LRControl)
double TurnAmt = FractionForward * PercentTurn; //this is a double percent value
//make sure TurnAmt is always positive
if(TurnAmt < 0){
TurnAmt = -TurnAmt;
}
//Cast TurnAmt into an int8_t
int8_t TurnDuty = (int8_t)TurnAmt;
int8_t LeftDuty = ClampLeftDuty(TurnDuty);
int8_t RightDuty = ClampRightDuty(TurnDuty);
FlipperEvent.EventType = ES_FLIPPERS_ON;
FlipperEvent.EventParam = (uint16_t)TurnDuty;
PostFlipperSweep(FlipperEvent);
//To turn, we need a positive int version of TurnDuty and a backward int version of Turn duty. Fan_SetDuty functions will accept anything from -100 to +100
if(LRControl > 0){ //if you want to make a right turn (TurnDuty will be positive)
Fan_SetDuty_Left(LeftDuty);
Fan_SetDuty_Right(-RightDuty);
} else { //if you want to make a left turn (TurnDuty will be positive)
Fan_SetDuty_Left(-LeftDuty);
Fan_SetDuty_Right(RightDuty);
}
}
/****************************************************************************
Function: GetDuty
Converts the input (either FBSpeed or LRControl) into a positive duty cycle
and that accounts for the START_DUTY_OFFSET constant, which is the minimum
duty cycle at which the prop fans will turn on
****************************************************************************/
int8_t GetDuty(int8_t input){
//convert the input (either FBSpeed or LRControl) into a positive duty cycle
double fraction = ((double)input)/127.0;
double percent = fraction * 100.0;
int8_t NewDuty = (int8_t)percent;
//Always return a positive duty cycle
if(NewDuty < 0){
NewDuty = -NewDuty;
}
NewDuty += START_DUTY_OFFSET; //map the duty cycle so when the user inputs a 1% duty cycle, the props still turn on (the props usually don't turn on until they hit a duty cycle of about 20%)
return NewDuty;
}
/****************************************************************************
Function: ClampLeftDuty
If the left prop's duty cycle is decremented due to an offset, make sure it never goes below 0
****************************************************************************/
int8_t ClampLeftDuty(int8_t Duty){
int8_t OffsetDuty = Duty - LEFT_PROP_OFFSET;
if(OffsetDuty < 0){
return 0;
} else if(OffsetDuty > 100){
return 100;
} else {
return OffsetDuty;
}
}
/****************************************************************************
Function: ClampRightDuty
If the right prop's duty cycle is decremented due to an offset, make sure it never goes below 0
****************************************************************************/
int8_t ClampRightDuty(int8_t Duty){
int8_t OffsetDuty = Duty - RIGHT_PROP_OFFSET;
if(OffsetDuty < 0){
return 0;
} else if(OffsetDuty > 100){
return 100;
} else {
return OffsetDuty;
}
}
ID_Badge provides functions that enable the hovercraft (Lobbyist) to read the credential badge
/****************************************************************************
Header
ID_Badge.h
Module Revision
1.0.1
****************************************************************************/
#ifndef ID_BADGE_H
#define ID_BADGE_H
#include
#include
#include
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
void InitializeBadge(void);
uint8_t GetBadgeNumber(void);
//***************************************************************************
#endif /* ID_BADGE_H */
/****************************************************************************
Module
ID_Badge.c
Description
Functions that enable the hovercraft (Lobbyist) to read the credential badge
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for the framework and this service
*/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistReceive.h"
#include "Initializations.h"
#include "MainLobbyist.h"
#include "Fan_Control.h"
#include
/*----------------------------- Module Defines ----------------------------*/
// Readability defines:
#define ALL_BITS (0xff<<2)
//The badge boundary defines come from the output voltage on the voltage divider with a 2.2k resistor and the badge resistor.
//The boundary values correspond to a 12 bit scaling of the output voltage from that voltage divider for badge resistors of
//1k, 2k, 3k, and 4k
#define FIRST_BADGE_BOUNDARY 1614
#define SECOND_BADGE_BOUNDARY 2157
#define THIRD_BADGE_BOUNDARY 2502
/*---------------------------- Module Variables ---------------------------*/
// Data private to the module
static uint32_t AnalogInput[1];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: InitializeBadge
Initializes the analog input from the badge into the Tiva
****************************************************************************/
void InitializeBadge(void){
ADC_MultiInit(1); //will give us PE0 as an analog input
}
/****************************************************************************
Function: GetBadgeNumber
Returns the badge number based off the resistor on the credential badge
****************************************************************************/
uint8_t GetBadgeNumber(void){
//read analog input
ADC_MultiRead(AnalogInput);
uint32_t BadgeInput = AnalogInput[0];
uint8_t ReturnedBadgeNumber = 0;
//determine if the resistor is 1k, 2k, 3k, or 4k
if(BadgeInput < FIRST_BADGE_BOUNDARY){
ReturnedBadgeNumber = 0;
return ReturnedBadgeNumber;
} else if((BadgeInput >= FIRST_BADGE_BOUNDARY) && (BadgeInput < SECOND_BADGE_BOUNDARY)){
ReturnedBadgeNumber = 1;
return ReturnedBadgeNumber;
} else if((BadgeInput >= SECOND_BADGE_BOUNDARY) && (BadgeInput < THIRD_BADGE_BOUNDARY)){
ReturnedBadgeNumber = 2;
return ReturnedBadgeNumber;
} else if(BadgeInput > THIRD_BADGE_BOUNDARY){
ReturnedBadgeNumber = 3;
return ReturnedBadgeNumber;
} else {
ReturnedBadgeNumber = 99;
return ReturnedBadgeNumber;
}
}
Flipper_Control handles the flipper servo PWM signals and limit switch interrupt
/****************************************************************************
Header
Flipper_Control.h
****************************************************************************/
#ifndef Flipper_Control_H
#define Flipper_Control_H
#include
#include
#include
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
void Flipper_Control_Init(void);
void Reset_Flippers(void);
void Left_Flipper_On(void);
void Left_Flipper_Off(void);
void Right_Flipper_On(void);
void Right_Flipper_Off(void);
void WritePulseWidthLeft(uint16_t newDuty);
void WritePulseWidthRight(uint16_t newDuty);
//***************************************************************************
#endif /* Flipper_Control_H */
/****************************************************************************
Module
Flipper_Control.c
Revision
1.0.1
Description
Module for servo PWM and limit switch interrupt handling
Notes
****************************************************************************/
//#define Analog_Test
// the common headers for C99 types
#include
#include
// the headers to access the GPIO subsystem
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_pwm.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "inc/hw_timer.h"
#include "inc/hw_nvic.h"
// the headers to access the TivaWare Library
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_Port.h"
#include "termio.h"
#include "Flipper_Control.h"
#include "BITDEFS.H"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
/*---------------------------- Module Variables ---------------------------*/
static uint16_t PWMTicksPerMS = 1250;
static uint8_t DEFAULT_PERIOD = 20;
static uint8_t BitsPerNibble = 4;
static uint16_t DEFAULT_POSITION = 1500;
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static void Flipper_PWM_Init(void);
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: Flipper_Control_Init
Calls relevant intitialization functions to initialize the turtle's flippers
****************************************************************************/
void Flipper_Control_Init(void){
//initialize PWM to servos
Flipper_PWM_Init();
//reset flippers
Reset_Flippers();
}
/****************************************************************************
Function: Reset_Flippers
Resets flippers to their center positions
****************************************************************************/
void Reset_Flippers(void){
//set servos to default position
WritePulseWidthLeft(DEFAULT_POSITION);
WritePulseWidthRight(DEFAULT_POSITION);
}
/****************************************************************************
Function: WritePulseWidthLeft
Writes new pulse width value to the left flipper
****************************************************************************/
void WritePulseWidthLeft(uint16_t newWidth){
HWREG(PWM0_BASE+PWM_O_0_CMPA) = (newWidth*5/4)>>1;
}
/****************************************************************************
Function: WritePulseWidthRight
Writes new pulse width value to the right flipper
****************************************************************************/
void WritePulseWidthRight(uint16_t newWidth){
HWREG(PWM0_BASE+PWM_O_0_CMPB) = (newWidth*5/4)>>1;
}
/****************************************************************************
Function: Flipper_PWM_Init
Initializes everything necessary to use a PWM signal with the flippers
****************************************************************************/
static void Flipper_PWM_Init(void){
//start by initializing the pwm drive pins as outputs
// init the pins associated with the Tiva pins we are using
// set up port B by enabling the peripheral clock
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R1;
//wait a few cycles for modifications to take effect
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R1) != SYSCTL_PRGPIO_R1);
volatile uint32_t Dummy; // use volatile to avoid over-optimization
// start by enabling the clock to the PWM Module (PWM0)
HWREG(SYSCTL_RCGCPWM) |= SYSCTL_RCGCPWM_R0;
// Select the PWM clock as System Clock/32
HWREG(SYSCTL_RCC) = (HWREG(SYSCTL_RCC) & ~SYSCTL_RCC_PWMDIV_M) |
(SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_32);
// make sure that the PWM module clock has gotten going
while ((HWREG(SYSCTL_PRPWM) & SYSCTL_PRPWM_R0) != SYSCTL_PRPWM_R0);
// disable the PWM while initializing
HWREG( PWM0_BASE+PWM_O_0_CTL ) = 0;
// program generator A to go to 0 at rising compare A, 1 on falling compare A
HWREG( PWM0_BASE+PWM_O_0_GENA) = (PWM_0_GENA_ACTCMPAU_ZERO | PWM_0_GENA_ACTCMPAD_ONE );
// program generator B to go to 0 at rising compare B, 1 on falling compare B
HWREG( PWM0_BASE+PWM_O_0_GENB) = (PWM_0_GENB_ACTCMPBU_ZERO | PWM_0_GENB_ACTCMPBD_ONE );
// Set the PWM period. Since we are counting both up & down, we initialize
// the load register to 1/2 the desired total period. We will also program
// the match compare registers to 1/2 the desired high time
HWREG( PWM0_BASE+PWM_O_0_LOAD) = ((DEFAULT_PERIOD * PWMTicksPerMS)-1)>>1;
// Set the initial CMPA & CMPB values to the DEFAULT_POSITION
HWREG( PWM0_BASE+PWM_O_0_CMPA) = (DEFAULT_POSITION*5/4)>>1;
HWREG( PWM0_BASE+PWM_O_0_CMPB) = (DEFAULT_POSITION*5/4)>>1;
// enable the PWM outputs
HWREG( PWM0_BASE+PWM_O_ENABLE) |= (PWM_ENABLE_PWM0EN | PWM_ENABLE_PWM1EN);
// now configure the Port B pins to be PWM outputs
// start by selecting the alternate function for PB6 & 7
HWREG(GPIO_PORTB_BASE+GPIO_O_AFSEL) |= (BIT6HI | BIT7HI);
// now choose to map PWM to those pins, this is a mux value of 4 that we
// want to use for specifying the function on bits 6 & 7
HWREG(GPIO_PORTB_BASE+GPIO_O_PCTL) =
(HWREG(GPIO_PORTB_BASE+GPIO_O_PCTL) & 0x00ffffff) + (4<<(7*BitsPerNibble)) + (4<<(6*BitsPerNibble));
// Enable pins 6 & 7 on Port B for digital I/O
HWREG(GPIO_PORTB_BASE+GPIO_O_DEN) |= (BIT7HI | BIT6HI);
// make pins 6 & 7 on Port B into outputs
HWREG(GPIO_PORTB_BASE+GPIO_O_DIR) |= (BIT7HI |BIT6HI);
// set the up/down count mode, enable the PWM generator and make
// both generator updates locally synchronized to zero count
HWREG(PWM0_BASE+ PWM_O_0_CTL) = (PWM_0_CTL_MODE | PWM_0_CTL_ENABLE |
PWM_0_CTL_GENAUPD_LS | PWM_0_CTL_GENBUPD_LS);
}
FlipperSweep is responsible for moving the turtle's flippers when the hovercraft is moving
/****************************************************************************
Header
FlipperSweep.h
Module Revision
1.0.1
****************************************************************************/
#ifndef FLIPPER_SWEEP_H
#define FLIPPER_SWEEP_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum {FlippersOff, FlippersOn} FlipperState_t;
//Function prototypes
bool InitializeFlipperSweep(uint8_t Priority);
bool PostFlipperSweep( ES_Event ThisEvent );
ES_Event RunFlipperSweep (ES_Event ThisEvent);
#endif /* FLIPPER_SWEEP_H */
/****************************************************************************
Module
FlipperSweep.c
Sweeps the turtle's flippers when the hovercraft is being driven
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "LobbyistReceive.h"
#include "Initializations.h"
#include "MainLobbyist.h"
#include "Fan_Control.h"
#include "Flipper_Control.h"
#include "ParseControl.h"
#include "ID_Badge.h"
#include "FlipperSweep.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
#define SWEEP_TIME 30 //timer used to create a smoooth sweep of the turtle's flippers
#define MIN_SERVO 1000 //minimum servo location
#define CENTER_SERVO 1500 //center servo location
#define MAX_SERVO 2000 //maximum servo location
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
uint16_t ConvertDutyToStep(void);
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static FlipperState_t CurrentState;
static bool Direction = true; //sets direction the flippers are moving in (true is forward; false is backward)
static uint16_t Step = 10; //servo step size
static int8_t Duty = 0;
static uint16_t PulseWidthForward = 1500; //pulse width for one flipper
static uint16_t PulseWidthBackward = 1500; //pulse width for the other flipper
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeFlipperSweep
Initializes the hovercraft turtle's swimming action
****************************************************************************/
bool InitializeFlipperSweep (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//Set CurrentState to FlippersOff and set flippers to their nominal position
CurrentState = FlippersOff;
Reset_Flippers();
//Transition into the state machine
ThisEvent.EventType = ES_INIT;
PostFlipperSweep(ThisEvent);
return true;
}//End of InitializeFlipperSweep(return true)
/****************************************************************************
Function
PostFlipperSweep
Function used by the framework to post events to the FlipperSweep state
machine
****************************************************************************/
bool PostFlipperSweep( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunFlipperSweep
State machine that decides how to control the turtle's flippers based
off of posted events
****************************************************************************/
ES_Event RunFlipperSweep(ES_Event ThisEvent){
//set up local variables
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
FlipperState_t NextState = CurrentState;
switch(CurrentState)
{
case FlippersOff:
//If you get an ES_FLIPPERS_ON event
if(ThisEvent.EventType == ES_FLIPPERS_ON){
//get the duty cycle of the props associated with this event (this will be used to create a proportional flipper speed)
uint16_t DutyFromParseControl = ThisEvent.EventParam; //this number will always be positive
Duty = (int8_t)DutyFromParseControl;
//start sweep timer
ES_Timer_InitTimer(FLIPPER_TIMER, SWEEP_TIME);
//go to FlippersOn state
NextState = FlippersOn;
}
break; //end of FlippersOff case
case FlippersOn:
//If you get an ES_TIMEOUT [sweep timer] event
if(ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == FLIPPER_TIMER){
//reset sweep timer
ES_Timer_InitTimer(FLIPPER_TIMER, SWEEP_TIME);
//Convert that duty cycle (duty of 0 = still flippers, 100 = fast) into a proportional flipper speed by changing the duty you send to the flippers (var name= STEP)
Step = ConvertDutyToStep();
//If Direction == true
if(Direction == true){
PulseWidthForward += Step;
PulseWidthBackward -= Step;
//check if you've reach the final forward sweep destination
if(PulseWidthForward <= MAX_SERVO){
//If you haven't, increment pwm to sweep flippers forward by "step" amount
WritePulseWidthLeft(PulseWidthForward);
WritePulseWidthRight(PulseWidthBackward);
} else {
//If you have, set Direction = false
Direction = false;
} //end of PulseWidthForward <= MAX_SERVO
} else { //if Direction == false
PulseWidthForward -= Step;
PulseWidthBackward += Step;
//check if you've reached the final backward sweep destination
if(PulseWidthForward >= MIN_SERVO){
//If you haven't, decrement pwm to sweep flippers backward by "step" amount
WritePulseWidthLeft(PulseWidthForward);
WritePulseWidthRight(PulseWidthBackward);
} else {
//If you have, set Direction = true
Direction = true;
}
}//end of Direction == true if/else statement
} //end of ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == FLIPPER_TIMER event
//If you get an ES_FLIPPERS_OFF event
if(ThisEvent.EventType == ES_FLIPPERS_OFF){
//turn servos off where they are
//go to FlippersOff state
NextState = FlippersOff;
}
break; //end of FlippersOn case
}//End switch statement
CurrentState = NextState;
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunFlipperSweep
uint16_t ConvertDutyToStep(void){
//converts positive int8_t Duty to uint16_t Step that will be used to increment the flippers
//Duty goes 0-100; Step goes __ to ___
uint16_t NewStep = 0;
if(Duty < 25){
NewStep = 5;
} else if(Duty >= 25 && Duty < 50){
NewStep = 10;
} else if(Duty >= 50 && Duty < 75){
NewStep = 20;
} else if(Duty >= 75){
NewStep = 30;
} else {
//do nothing
}
return NewStep;
}
SevSegW is a low level interface to a common cathode 7 segment display using a shift register
/****************************************************************************
Header
SevSegW.h
Module Revision
1.0.2
****************************************************************************/
#ifndef SevSegW_H
#define SevSegW_H
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
/*
Function: SevSeg_HWInit
Arguments: void
Returns: void
Operation: Initializes the port hardware necessary to write to the 7
segment display
*/
void SevSeg_HWInit(void);
/*
Function: SevSeg_WriteData8
Arguments: uint8_t NewData
Returns: void
Operation: Sets the register select bit to select the data register then
writes all 8 bits of data, using 2 4-bit writes
*/
void SevSeg_Write(uint8_t NewData);
//***************************************************************************
#endif /* SevSegW_H */
/****************************************************************************
Module
SevSegW.c
Revision
1.0.2
Description
Low level interface to a common cathode 7 segment display using a shift register
Notes
History
When Who What/Why
-------------- --- --------
10/19/15 22:00 lxw revised for ES framework
10/18/15 16:30 lxw first pass
****************************************************************************/
// C99 headers:
#include
#include
#include
// GPIO subsystem headers:
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
// TivaWare library headers:
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "ES_Port.h"
#include "BITDEFS.h"
// Module headers:
#include "SevSegW.h"
#include "ShiftRegW.h"
// Readability defines:
#define LSB_MASK 0x0f
#define NUM_DIGITS 10
// array of segment combinations for various digits (0's are lit)
static const uint16_t DigitValues[NUM_DIGITS] = {
0x11, //0
0x7D, //1
0x89, //2
0x29, //3
0x65, //4
0x23, //5
0x03, //6
0x79, //7
0x01, //8
0x61 //9
};
// Misc. defines:
//#define TEST
/****************************************************************************
FUNCTION IMPLEMENTATION
****************************************************************************/
//PUBLIC FUNCTIONS:
/* SevSeg_HWInit
Operation: Initializes the port hardware necessary to write to the LCD
*/
void SevSeg_HWInit(void){
//init the Shift Register module
SR_Init();
}
/* SevSeg_Write
Operation: Writes the digit to the display
*/
void SevSeg_Write(uint8_t Digit){
// write the segment combination to the shift register
SR_Write(DigitValues[Digit]);
}
Low level write-only shift register interface
/****************************************************************************
Header
ShiftRegW.h
****************************************************************************/
#ifndef ShiftRegW_H
#define ShiftRegW_H
/****************************************************************************
FUNCTION PROTOTYPES
****************************************************************************/
/*
Function: SR_Init
Operation: enable Port B & intialize PB0, PB1, & PB0 as the DATA, SCLK, & RCLK, respectively
*/
void SR_Init(void);
/*
Function: SR_GetCurrentRegister
Operation: return the last uint8_t written to the shift register
*/
uint8_t SR_GetCurrentRegister(void);
/*
Function: SR_Write
Operation: push NewValue onto shift register & write it to external device(s)
*/
void SR_Write(uint8_t NewValue);
//***************************************************************************
#endif /* ShiftRegW_H */
/****************************************************************************
Module
ShiftRegW.c
Revision
1.0.1
Description
Low level write-only shift register interface
Notes
History
When Who What/Why
-------------- --- --------
10/17/15 22:00 lxw first pass
****************************************************************************/
// C99 headers:
#include
#include
#include
// GPIO subsystem headers:
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
// TivaWare library headers:
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "BITDEFS.h"
// Module headers
#include "ShiftRegW.h"
// Readability defines:
#define DATA GPIO_PIN_4
#define DATA_HI BIT0HI
#define DATA_LO BIT0LO
#define SCLK GPIO_PIN_6
#define SCLK_HI BIT6HI
#define SCLK_LO BIT6LO
#define RCLK GPIO_PIN_5
#define RCLK_LO BIT5LO
#define RCLK_HI BIT5HI
#define ALL_BITS (0xff<<2)
// Static variable initializations:
//image of the last 8 bits written to the shift register
static uint8_t LocalRegisterImage = 0;
// Misc.:
//#define TEST
/****************************************************************************
FUNCTION IMPLEMENTATION
****************************************************************************/
/* SR_Init
Operation: enable Port C & intialize PC4, PC5, & PC6 as the DATA, SCLK, & RCLK, respectively
*/
void SR_Init(void){
//enable peripheral clock into port C & wait for Port C to be recorded as enabled
HWREG(SYSCTL_RCGCGPIO) |= BIT2HI;
while((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R2) != SYSCTL_PRGPIO_R2);
//set bit 4,5,6 on port C as digital I/O & set their direction as outputs
HWREG(GPIO_PORTC_BASE + GPIO_O_DEN) |= (DATA | SCLK | RCLK);
HWREG(GPIO_PORTC_BASE + GPIO_O_DIR) |= (DATA | SCLK | RCLK);
// start with the DATA & SCLK lines low and the RCLK line high
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) &= (DATA_LO & SCLK_LO);
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) |= (RCLK_HI);
}
/* SR_GetCurrentRegister
Operation: return the last uint8_t written to the shift register
*/
uint8_t SR_GetCurrentRegister(void){
return LocalRegisterImage;
}
/* SR_Write
Operation: push NewValue onto shift register & write it to external device(s)
*/
void SR_Write(uint8_t NewValue){
//save a local copy of NewValue
LocalRegisterImage = NewValue;
//set RCLK low
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) &= (RCLK_LO);
uint8_t MSB = 0;
//loop 8 times
for(int i=0;i<8;i++){
//push ith MSB of NewValue onto DATA
MSB = NewValue>>(7-i);
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) = (MSB & BIT0HI)<<4;
//test harness portion to monitor shift register output
#ifdef TEST
if(MSB & BIT0HI) putchar('1');
else putchar('0');
#endif
//pulse SCLK to shift data
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) |= (SCLK_HI);
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) &= (SCLK_LO);
}
//set RCLK hi to write out of the register (latch data)
HWREG(GPIO_PORTC_BASE + (GPIO_O_DATA + ALL_BITS)) |= (RCLK_HI);
}
/****************************************************************************
TEST HARNESS
****************************************************************************/
#ifdef TEST
#include "termio.h"
int main(void)
{
TERMIO_Init();
SR_Init();
puts("\r\nTESTING ShiftRegW.c\r\n");
while(true){
getchar(); //BLOCKING
SR_Write(rand()%256);
printf(": %i\r\n",SR_GetCurrentRegister());
}
}
#endif
The DMC is an 8-pin PIC (PIC12F752) programmed in assembly which controlled the team select LEDs inside the turbines as well as the sunglasses to indicate paired status and servo inside the fuel gauge which was a signal of how much time there was left in the paired state. It used three timers to generate a PWM frequency for both servos at 50Hz and two other timers to control the pulse width of each one. The step size for the fuel gauge servo was controlled using a counter based on the instruction clock.
;Project code for DMC
;Note: FOSC is set to 32KHz for a 50Hz servo PWM freq
errorlevel -302 ;Ignore banksel macro error reminder
list P=PIC12F752
#include "p12F752.inc"
__config (_CP_OFF & _WDTE_OFF & _MCLRE_OFF & _PWRTE_ON & _FOSC0_INT)
;
; Variable definitions
;
index equ 42h ;Index for moving through tables
WREG_TEMP equ 43h ;Save WREG for ISR
STATUS_TEMP equ 44h ;Save STATUS for ISR
PCLATH_TEMP equ 45h ;Save PCLATH for ISR
SHRT_VAL equ d'30'
SHRTN_RANGE equ 72h
PAIR_WIDTH equ 74h
PAIR_FLAG equ 73h ;Used to sweep servo in 45 sec
UNPAIR_FLAG equ 70h ;Set the flag if unpaired for servo reset
SWEEP_TIME equ d'110'
SWEEP_CNTR equ 71h
WIDTH_RESET equ d'9' ;Match value for setting the pulse width of servo 2
PULSE_WIDTH equ 75h
SERVO_FREQ equ d'19' ;Will set HWLTMR1 to 50 Hz freq for servo PWM
org 0
goto Main
org 4
goto ISR ;Goto ISR from org 4
org 5
Main: ;Initialize PIC clock, interrupts, timers, and GPIO
;Use 1MHz clock default from reset
call InitGPIO ;Set pins 0:2, 5 as outputs, 3:4 as inputs
call InitHLTimer1;Sets timer for fuel servo PWM
call InitTimer2 ;Initialize timer 2 for servo sweep
call InitTimer0 ;Initialize timer 0 for pair servo
Run: ;Check pin states and do paired/unpaired actions
banksel PORTA
btfsc PORTA,4 ;Check paired status
call doPaired ;Change servo to paired position
btfss PORTA,4
call doUnpaired ;Change servo to unpaired position
goto Run ;Wait for interrupts
;************************ Interrupt Service Routine ********************
;
ISR: ;Begin interrupt service routine
Push movwf WREG_TEMP ;Save WREG
movf STATUS,w ;Store STATUS in WREG
clrf STATUS ;Change to file register bank0
movwf STATUS_TEMP ;Save STATUS value
movf PCLATH,w ;Store PCLATH in WREG
movwf PCLATH_TEMP ;Save PCLATH value
clrf PCLATH ;Change to program memory page0
ISR_Body:
banksel PIR1 ;Switch to Bank0 to write to PORTA
btfsc PIR1,TMR2IF ;If this interrupt is due to Timer2
call Timer2Int ;Call the Timer 2 Int
banksel INTCON
btfsc INTCON,T0IF ;Check if Timer0 interrupt flag is set
call Timer0Int
btfsc PIR1,HLTMR1IF;Check if HLTimer1 interrupt flag is set
call Timer1Int ;Set servo pulse width
Pop:
clrf STATUS ;Select bank0
movf PCLATH_TEMP,w;Store saved PCLATH value in WREG
movwf PCLATH ;Restore PSLATH
movf STATUS_TEMP,w;Store saved STATUS value in WREG
movwf STATUS ;Restore STATUS
swapf WREG_TEMP,f ;Prepare WREG to be restored
swapf WREG_TEMP,w ;Restore WREG keeping STATUS bits
banksel PORTA ;Go back to PORTA bank, 0
retfie ;Return from interrupts & re-enable
;
;************************ Interrupt Subroutines ************************
;
Timer0Int: ;Timer used for setting the pulse width of the pair servo
banksel INTCON
bcf INTCON,T0IF ;Clear the Timer0 interrupt flag
decfsz UNPAIR_FLAG,f
goto PairWidth
goto UnpairWidth
PairWidth decfsz PAIR_WIDTH
goto Pop
banksel LATA
bcf LATA,2
movlw d'2' ;reset the pair width counter
movwf PAIR_WIDTH
goto Pop
Timer1Int: ;Timer one sets on time for pulse width
banksel PIR1
bcf PIR1,HLTMR1IF;Clear HLMT1 match interrupt
banksel LATA
bsf LATA,5 ;Set sweep servo pin HI
bsf LATA,2 ;Set paired servo pin HI
;Write zero to TMR2 before turning on**
banksel TMR2
movlw d'0'
movwf TMR2
;Reset the TMR0 counter
banksel INTCON
bcf INTCON,T0IF ;Clear the Timer0 interrupt flag
banksel TMR0 ;Reset the TMR0 overflow count
movlw d'0'
movwf TMR0
movlw d'2' ;reset the pair width counter
movwf PAIR_WIDTH
banksel T2CON
bsf T2CON,TMR2ON;Turn Timer2 ON
return ;in order to set the pulse width
Timer2Int: ;Timer that sets the duty cycle for the sweep servo
banksel T2CON
bcf T2CON,TMR2ON;Turn Timer2 back OFF
banksel PIR1
bcf PIR1,TMR2IF ;Clear source of Timer 2 interrupt
banksel LATA
bcf LATA, 5
decfsz SWEEP_CNTR,f;If 3 sec pass, change the servo pos
goto Pop
banksel PR2 ;Load PR2 register with period value
incf PR2,f ;Increment the servo pulse width
movlw SWEEP_TIME ;Reset the 3 second sweep counter
movwf SWEEP_CNTR
goto Pop
;************************ Helper Subroutines ************************
;
;
UnpairWidth:
decfsz SHRTN_RANGE
goto UnpairWidth
movlw SHRT_VAL
movwf SHRTN_RANGE
banksel LATA
bcf LATA,2
movlw d'2' ;reset the pair width counter
movwf PAIR_WIDTH
goto Pop
doUnpaired: ;Moves paired/sunglass servo to unpaired position
banksel LATA
bcf LATA, 0 ;Turn OFF pair status LED
bcf LATA, 1 ;Set R/B color pin low
;Reset sweep servo with initial pulse width
banksel PR2 ;Load PR2 register with period value
movlw WIDTH_RESET ;Load PR2 with initial pulse width for sweep servo
movwf PR2 ;Write to register
movlw SWEEP_TIME ;Sets a 3 second increment counter sweep for servo
movwf SWEEP_CNTR
;Set unpair flag to count 1
movlw d'1' ;Set the unpair flag
movwf UNPAIR_FLAG
return
doPaired: ;Moves paired/sunglass servo to paired position
banksel PORTA
btfsc PORTA,3 ;Check the R/B color pin and set output
call setLED1
btfss PORTA,3
call setLED2
;Set pair flag
movlw d'200'
movwf UNPAIR_FLAG ;Clear the unpair flag
return
setLED1: ;sets RA0 low and RA1 high
banksel LATA
bsf LATA, 1
banksel PORTA
bcf PORTA, 0
return
setLED2: ;sets RA0 high and RA1 low
banksel LATA
bsf LATA, 0
banksel PORTA
bcf PORTA, 1
return
;;
;************************ Initialization Subroutines ************************
;
InitTimer0: ;In order to have a 1:1 prescaler, the value for Timer0 module
;must be assigned to WDT module
; banksel TMR0 ;Changing prescaler (Timer0 -> WDT)
; clrwdt ;Clear WDT
; clrf TMR0 ;Clear TMR0 and prescaler
; banksel OPTION_REG
; bsf OPTION_REG,PSA ;select WDT
; clrwdt
; movlw b'11111000' ;Mask prescaler
; andwf OPTION_REG,w
; iorlw b'00000101' ;Set WDT prescaler to 1:32
; movwf OPTION_REG
banksel INTCON
bsf INTCON,T0IE ;Enable Timer0 interrupt
banksel OPTION_REG
bsf OPTION_REG,PSA ;Assign prescaler to WDT to get prescaler of 1:1
bcf OPTION_REG,T0CS ;Use FOSC/4 as the Timer0 clock source
banksel TMR0 ;Reset the TMR0 overflow count
movlw d'0'
movwf TMR0
movlw d'2' ;Reset paired pulse width counter
movwf PAIR_WIDTH
movlw SHRT_VAL
movwf SHRTN_RANGE
return
InitTimer2:; Timer 2 setup - TMR2 = 0, PR2 = FF on reset;
;banksel INTCON ;Switch to bank 0 for INTCON register
;bsf INTCON,PEIE ;Enable PEIE unmasked peripheral interrupts
banksel PIE1 ;Switch to bank 1 for PIE1 register
bsf PIE1,TMR2IE ;Enable TMR2IE interrupt enable bit on PIE1
banksel T2CON ;Switch to T2CON register bank
movlw b'01111000' ;Set 1:1 prescaler and 1:16 postcaler, & Timer 2 OFF
movwf T2CON ;Write to T2CON register; PR2 defaults to 255
banksel PR2 ;Load PR2 register with period value
movlw WIDTH_RESET ;Load PR2 with initial pulse width for sweep servo
movwf PR2 ;Write to register
movlw SWEEP_TIME ;Sets a 3 second increment counter sweep for servo
movwf SWEEP_CNTR
return
InitHLTimer1:;Timer 1 setup for asynchronous communication
banksel INTCON ;Switch to bank 0 for INTCON bank
bsf INTCON,GIE ;Enable GIE, global interrupts
banksel INTCON ;Switch to bank 0 for INTCON register
bsf INTCON,PEIE ;Enable PEIE unmasked peripheral interrupts
banksel PIE1
bsf PIE1,HLTMR1IE;Enable HWLMT interrupt
banksel HLTPR1
movlw SERVO_FREQ ;Set HLTimer to value for 50 Hz
movwf HLTPR1
banksel HLT1CON0
movlw b'01111111' ;Set prescalar to 16, postcaler to 16, timer ON
movwf HLT1CON0
return
InitGPIO: ; GPIO set up
banksel PORTA ;Switch to bank 0 for PORT A bank
clrf PORTA ;Initialize PORTA
banksel LATA ;Switch to data Latch A bank, 2
clrf LATA ;Initialize LATA
banksel ANSELA ;Switch to ANSELA bank, 3
clrf ANSELA ;Use digital I/O
banksel TRISA ;Switch to TRISA bank, 1
movlw b'00011000' ;Set RA<0:2,5> as outputs, and //Reqd for PWM
movwf TRISA ;RA<4:3> as input, using TRISA
banksel PORTA ;Switch to Bank0 to write to PORTA
movlw b'00000000' ;Set pin 0, 1, 2 to LO - Start with LEDs OFF
movwf PORTA ;Write to port output pins
return
;
end
PACService is the main code for the controller (PAC). This service handles when to send certain types of data packets, or when to unpair. Additionally, this service controls the pair status LED on the controller.
#ifndef PACService_H
#define PACService_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { Unpaired, Paired} PACServiceState_t;
//Public function prototypes
bool InitializePACService ( uint8_t Priority );
bool PostPACService ( ES_Event ThisEvent );
ES_Event RunPACService( ES_Event ThisEvent );
//Public Getter Functions necessary for PACTransmit.c
uint8_t GetLobbyistAddressMSB( void );
uint8_t GetLobbyistAddressLSB( void );
#endif //PACService_H
/****************************************************************************
Module
PACService.c
Notes
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "PACService.h"
#include "PACTransmit.h"
#include "PACReceive.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
// Pair LED is BIT0 on port e
#define PAIR_LED BIT0HI
// Types of packets
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CTRL 0x02
#define STATUS 0x03
#define RESEND 0x04
// Timeout Lengths
#define RESENDINTERVAL 100 // 100ms
#define FIFTHSECOND 200 // 200ms
#define ONESECOND 1000 // 1s
// Packet Bit Definitions
#define PAIR_BIT BIT8HI
#define ACKDATA 0xff
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static bool DoesACKDATAMatch( uint16_t );
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// States defined in the header file (PACService.h)
static PACServiceState_t CurrentState;
// 200ms timer flag
static bool FifthSecondTimerActive = false;
// ACKFlag
static bool ACKFlag = false;
// Keeps track of the last packet type sent
static uint8_t LastTxPacketType;
// Address of the currently paired lobbyist
static uint8_t LobbyistAddressMSB;
static uint8_t LobbyistAddressLSB;
// Allow the user to use the pair button to unpair after 1 sec of pairing
bool CanUnpair;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializePACService
****************************************************************************/
bool InitializePACService (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
// Do Initialization Stuff
// 1. Intialize pair LED to be off
// Initialize the port E line to display pair status
// Enable peripheral clock to Port E (R4)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R4;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R4) != SYSCTL_PRGPIO_R4)
; // (wait for port to be ready)
// Enable bit 0 on Port E as digital I/O line
HWREG(GPIO_PORTE_BASE+GPIO_O_DEN) |= PAIR_LED;
// Set data direction for bit 0 on Port E to be an output
HWREG(GPIO_PORTE_BASE+GPIO_O_DIR) |= PAIR_LED;
// Start with LED off
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= ~PAIR_LED;
// 2. Go to Unpaired state out of reset
CurrentState = Unpaired;
// Prints
puts("\r\nInitializePACService Complete");
// Post Event ES_Init to this queue (this service)
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true) {
// End of initialization (return True)
return true;
} else {
return false;
}
}//End of InitializePACService (return True)
/****************************************************************************
Function
PostPACService
****************************************************************************/
bool PostPACService( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
RunPACService
****************************************************************************/
ES_Event RunPACService (ES_Event ThisEvent){
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
switch(CurrentState) {
/***** If CurrentState is Unpaired *****/
case Unpaired:
if (ThisEvent.EventType == ES_USER_PAIR_PRESS && !(FifthSecondTimerActive)) {
// Prints
printf("\r\n\n\nGot ES_USER_PAIR_PRESS event & 200ms timer inactive.");
printf("\r\nSending ES_BEGIN_TRANSMIT: REQ_PAIR event to PACTransmit.");
// Transmit REQ_PAIR (lobbyist number and team color set separately in this module)
ES_Event ThisEvent;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = REQ_PAIR;
PostPACTransmit(ThisEvent);
// Start 200ms Timer
ES_Timer_InitTimer( FIFTHSECONDTIMER, FIFTHSECOND);
// Set timer active flag
FifthSecondTimerActive = true;
// LastTxPacketType sent
LastTxPacketType = REQ_PAIR;
// Set ACKFlag to false
ACKFlag = false;
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == FIFTHSECONDTIMER) {
// Check if we've heard back from the lobbyist
if (ACKFlag) { // We heard back from the lobbyist in the past 200ms
// Transmit ENCR_KEY
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = ENCR_KEY;
PostPACTransmit(ThisEvent);
// LastTxPacketType sent
LastTxPacketType = ENCR_KEY;
// Restart resend timer and 200ms timer
ES_Timer_InitTimer( RESENDTIMER, RESENDINTERVAL);
ES_Timer_InitTimer( FIFTHSECONDTIMER, FIFTHSECOND);
// Set timer active flag
FifthSecondTimerActive = true;
// Clear ACKFlag
ACKFlag = false;
// Move state to PAIRED
CurrentState = Paired;
} else { // We haven't heard back from the lobbyist in the past 200ms
// Clear timer active flag
FifthSecondTimerActive = false;
}
} else if ( ThisEvent.EventType == ES_STATUS_RECEIVED && ((ThisEvent.EventParam & PAIR_BIT) == PAIR_BIT) && LastTxPacketType == REQ_PAIR) { // ES_STATUS_RECEIVED event param is STATUS Pair Byte
// Prints
printf("\r\n\n\nGot ES_STATUS_RECEIVED event. The request to pair was accepted.");
// Get the paired lobbyist address
LobbyistAddressMSB = GetSourceAddressMSB();
LobbyistAddressLSB = GetSourceAddressLSB();
// Turn on pair LED
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) |= PAIR_LED;
// Start Pair Guarding Timer & set CanUnpair to false
ES_Timer_InitTimer( PAIRGUARDTIMER, ONESECOND);
CanUnpair = false;
// Post ES_PAIR_REQUEST_ACCEPTED to UIService
ES_Event ThisEvent;
ThisEvent.EventType = ES_PAIR_REQUEST_ACCEPTED;
ThisEvent.EventParam = 0x00; // Doesn't matter, but let's just clear it
PostUIService(ThisEvent);
// Restart 1s TX timeout timer
ES_Timer_InitTimer( ONESECONDTIMER, ONESECOND);
// Check if we've already sent a packet in the last 200ms
if (FifthSecondTimerActive == true) {
// Set ACKFlag
ACKFlag = true;
} else { // FifthSecondTimer is not active
// Transmit ENCR_KEY
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = ENCR_KEY;
PostPACTransmit(ThisEvent);
// LastTxPacketType sent
LastTxPacketType = ENCR_KEY;
// Restart resend timer and 200ms timer
ES_Timer_InitTimer( RESENDTIMER, RESENDINTERVAL);
ES_Timer_InitTimer( FIFTHSECONDTIMER, FIFTHSECOND);
// Set timer active flag
FifthSecondTimerActive = true;
// Clear ACKFlag
ACKFlag = false;
// Move state to PAIRED
CurrentState = Paired;
}
} else {
// Do nothing (the event doesn't apply to this state)
} // END IF
break; // END CASE State: Unpaired
/***** If CurrentState is Paired *****/
case Paired:
if ( ThisEvent.EventType == ES_STATUS_RECEIVED && ((ThisEvent.EventParam & PAIR_BIT) == PAIR_BIT) ) { // ES_STATUS_RECEIVED event param is STATUS Pair Byte
// Restart 1s TX timeout timer
ES_Timer_InitTimer( ONESECONDTIMER, ONESECOND);
// Check if the ACKDATA byte matches
if ( DoesACKDATAMatch(ThisEvent.EventParam & ACKDATA) || LastTxPacketType == ENCR_KEY ) { // Might want to allow LastTxPacketType == ENCR_KEY if other lobbyists dont send ACKDATA=0 in response to E-Key
// Prints
// printf("\r\n\n\nGot ES_STATUS_RECEIVED event with matching ACKDATA. The last control packet was received by the lobbyist.");
if (FifthSecondTimerActive) { // We already sent a packet less than 200ms ago
// Set ACKFlag
ACKFlag = true;
} else { // FifthSecondTimer = false
// Transmit new CTRL packet
ES_Event ThisEvent;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = CTRL;
PostPACTransmit(ThisEvent);
// LastTxPacketType sent
LastTxPacketType = CTRL;
// Restart resend timer & 200ms timer
ES_Timer_InitTimer( RESENDTIMER, RESENDINTERVAL);
ES_Timer_InitTimer( FIFTHSECONDTIMER, FIFTHSECOND);
// Set 200ms timer active flag
FifthSecondTimerActive = true;
// Clear ACKFlag (must be false to get to this block, but clear it for consistency)
ACKFlag = false;
}
} else {
// Prints
printf("\r\n\n\nGot ES_STATUS_RECEIVED event with NON_MATCHING ACKDATA.");
}
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == FIFTHSECONDTIMER) {
// Prints
// printf("\r\n\n\nGot 200ms timeout event.");
if (ACKFlag) {
// Transmit new CTRL packet
ES_Event ThisEvent;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = CTRL;
PostPACTransmit(ThisEvent);
// LastTxPacketType sent
LastTxPacketType = CTRL;
// Restart resend timer and 200ms timer
ES_Timer_InitTimer( RESENDTIMER, RESENDINTERVAL);
ES_Timer_InitTimer( FIFTHSECONDTIMER, FIFTHSECOND);
// Set 200ms timer active flag
FifthSecondTimerActive = true; // Already true, but set to true for consistency
// Clear ACKFlag
ACKFlag = false;
} else { // 200ms have elapsed, good to send
// Clear 200ms timer active flag
FifthSecondTimerActive = false;
}
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == RESENDTIMER && ACKFlag == false) {
// Prints
// printf("\r\n\n\nGot 100ms timeout event and ACKFlag = false.");
// Retransmit last CTRL packet
ES_Event ThisEvent;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = RESEND;
PostPACTransmit(ThisEvent);
// Restart resend timer
ES_Timer_InitTimer( RESENDTIMER, RESENDINTERVAL);
} else if ( ThisEvent.EventType == ES_STATUS_RECEIVED && ((ThisEvent.EventParam & PAIR_BIT) == 0) ) { // ES_STATUS_RECEIVED event param is STATUS Pair Byte cleared
// Prints
printf("\r\n\n\nGot ES_STATUS_RECEIVED event. The lobbyist unpaired.");
// Need to Post ES_FAILURE_UNPAIR to PACReceive
ES_Event ThisEvent;
ThisEvent.EventType = ES_FAILURE_UNPAIR;
ThisEvent.EventParam = 0x00; // doesn't matter but clear it anyways
PostPACReceive(ThisEvent);
// Turn off LED
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= ~PAIR_LED;
// Clear ACKFlag
ACKFlag = false;
// Move state to unpaired
CurrentState = Unpaired;
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == ONESECONDTIMER) {
// Prints
printf("\r\n\n\nGot 1s timeout event. Unpairing.");
// Need to Post ES_FAILURE_UNPAIR to PACReceive
ES_Event ThisEvent;
ThisEvent.EventType = ES_FAILURE_UNPAIR;
ThisEvent.EventParam = 0x00; // doesn't matter but clear it anyways
PostPACReceive(ThisEvent);
// Turn off LED
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= ~PAIR_LED;
// Clear ACKFlag
ACKFlag = false;
// Move state to unpaired
CurrentState = Unpaired;
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == PAIRGUARDTIMER) {
// Prints
printf("\r\nUser can now unpair.");
// Set CanUnpair
CanUnpair = true;
} else if (ThisEvent.EventType == ES_USER_PAIR_PRESS && CanUnpair == true) {
// Prints
printf("\r\nUser has requested to unpair.");
// Send unpair command to UIService
ES_Event ThisEvent;
ThisEvent.EventType = ES_UNPAIR;
ThisEvent.EventParam = 0x00; // Doesn't matter, but let's just clear it
PostUIService(ThisEvent);
// Clear CanUnpair
CanUnpair = false;
} else {
// Do nothing (the event doesn't apply to this state)
} // END IF Event Types
break; // END CASE State: Paired
}//END SWITCH STATEMENT
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunPACService
/****************************************************************************
Function
GetLobbyistAddressMSB
Notes
Gives PACTransmit the LobbyistAddressMSB
****************************************************************************/
uint8_t GetLobbyistAddressMSB( void ) {
return LobbyistAddressMSB;
}
/****************************************************************************
Function
GetLobbyistAddressLSB
Notes
Gives PACTransmit the LobbyistAddressLSB
****************************************************************************/
uint8_t GetLobbyistAddressLSB( void ) {
return LobbyistAddressLSB;
}
/***************************************************************************
private functions
***************************************************************************/
/****************************************************************************
Function
DoesACKDATAMatch
Notes
This code is called to check if the received ACKDATA matches
the most previously sent CONTROL_CHECKSUM
****************************************************************************/
bool DoesACKDATAMatch( uint16_t Current_ACKDATA ) {
uint8_t CastedACKDATA = (uint8_t) Current_ACKDATA;
return (GetLastEncryptedCTRLChecksum() == CastedACKDATA);
}
Initializations does the necessary steps to initialize the UART for transmitting and receiving data through the XBee.
#ifndef INITIALIZATIONS_H
#define INITIALIZATIONS_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
#define ALL_BITS (0xff<<2)
//Public function prototypes
bool InitializeUART (void);
#endif //INITIALIZATIONS_H
/****************************************************************************
Module
Initializations.c
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_uart.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
#include "Initializations.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeUART
Purpose:
Configure the UART on the Tiva for UART1, full-duplex (send and receive
data at the same time), 8-bit data, 1 stop bit, asynchronous communication
at 9600 baud)
****************************************************************************/
bool InitializeUART (void){
//1. Enable the clock to the UART1 module using the RCGCUART (run time gating clock control) register
HWREG(SYSCTL_RCGCUART) |= SYSCTL_RCGCUART_R1; //Specifies we're using UART1
//2. Wait for the UART to be ready using the PRUART (peripheral ready register)
//Wait for PR bit to get set for that particular UART so you know it's ready
while ((HWREG(SYSCTL_PRUART) & SYSCTL_PRUART_R1) != SYSCTL_PRUART_R1)
;
//3. Enable the clock to the appropriate GPIO module via the RCGCGPIO
//We're using Port B because UART 1 is on PB0 and PB1
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R1; //Enable GPIO Port B
//4. Wait for the GPIO module to be ready (PRGPIO)
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R1) != SYSCTL_PRGPIO_R1)
;
//5. Configure the GPIO pins for in/out/drive-level/drive-type
//PB0 is an input...PB1 is an output
HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) |= (GPIO_PIN_0 | GPIO_PIN_1); //Assign digital ports
HWREG(GPIO_PORTB_BASE + GPIO_O_DIR) &= ~(GPIO_PIN_0); //Set data inputs
HWREG(GPIO_PORTB_BASE + GPIO_O_DIR) |= (GPIO_PIN_1); //Set data outputs
//6. Select the Alternate function for the UART pins (AFSEL)
//Set bits 0 and 1 on Port B to indicate you're going to use an alternate function with them
HWREG(GPIO_PORTB_BASE + GPIO_O_AFSEL) |= (GPIO_PIN_0 | GPIO_PIN_1);
//7. Configure the PMCn fields in the GPIOPCTL register to assign the UART pins
//Write 11 to get alternate function 4 (this chooses UART as the alternate function) see pg 1351 for alternate function table. Check???????????????????????????????????????????????????????????????????????????????????????????????????????????????????
HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) = (HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) & 0xfffffff0) + (1); //write 1 to PB0 to select U1Rx as the alternate function
HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) = (HWREG(GPIO_PORTB_BASE + GPIO_O_PCTL) & 0xffffff0f) + (1<<4); //write 1 to PB1 to select U1Tx as the alternate function
//8. Disable the UART by clearing the UARTEN bit in the UARTCTL register
//Do nothing because the UARTEN bit is already disabled upon reset
//9. Write the integer portion of the BRD to the UARTIBRD register (part 1/3 of setting the baud rate to 9600...value to write is decimal 260 or hex 0x104)
HWREG(UART1_BASE + UART_O_IBRD) = HWREG(UART1_BASE + UART_O_IBRD) + 0x104;//????????????????????????????????????????????????????????????????????????????????
//10. Write the factional portion of the BRD to the UARTFBRD register (part 2/3 of setting the baud rate to 9600...value to write is decimal 27 or hex 0x1B)
HWREG(UART1_BASE + UART_O_FBRD) = HWREG(UART1_BASE + UART_O_FBRD) + 0x1B; //??????????????????????????????????
//11. Write the desired serial parameters to the UARTLCRH register (part 3/3 of setting the baud rate to 9600
//One stop bit is the default for this register, so we don't need to do anything to configure the stop bits
//Set the word length to 8 bits by writing 0x3 to bits <6:5> to set WLEN to 0x3
HWREG(UART1_BASE + UART_O_LCRH) = HWREG(UART1_BASE + UART_O_LCRH) + UART_LCRH_WLEN_8; //??????????????????????????????????????????????????
//12. Configure the UART operation using the UARTCTL register
//Do nothing because RXE and TXE are already enabled, and HSE comes out of reset as 0, which is what you want
//13. Enable the UART by setting the UARTEN bit in the UARTCTL register
HWREG(UART1_BASE + UART_O_CTL) |= (UART_CTL_UARTEN);
puts("\r\nInitializeUART Complete");
return true;
}//End of InitializeUART (return True)
PACUARTISR routes the main UART ISR to the transmit and receive sub-ISRs
#ifndef PACUARTISR_H
#define PACUARTISR_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
//Public function prototypes
void PACUARTISR ( void );
#endif ///PACUARTISR_H
/****************************************************************************
Module
PACUARTISR.c
Notes
Routes the main UART ISR to the Tx and Rx sub-ISRs
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "PACUARTISR.h"
// include header files for PACTransmit & PACReceive
#include "PACTransmit.h"
#include "PACReceive.h"
/****************************************************************************
Function
PACUARTISR
****************************************************************************/
void PACUARTISR ( void ){
// Call PACTransmitISR
PACTransmitISR();
// Call PACRecieveISR
ReceiveISR();
}
PACTransmit transmits data packets from the controller (PAC) to the hovercrafts (Lobbyists) via UART.
#ifndef PACTransmit_H
#define PACTransmit_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { WaitingToSendByteOne, SendingPacket} PACTransmitState_t;
//Public function prototypes
bool InitializePACTransmit ( uint8_t Priority );
bool PostPACTransmit ( ES_Event ThisEvent );
ES_Event RunPACTransmit ( ES_Event ThisEvent );
void PACTransmitISR ( void );
uint8_t GetLastEncryptedCTRLChecksum ( void );
#endif ///PACTransmit_H
/****************************************************************************
Module:
PACTransmit.c
Notes:
External Functions Required:
Initializations.c:
void InitializeUART( void );
PACService.c:
uint8_t GetLobbyistAddressMSB( void );
uint8_t GetLobbyistAddressLSB( void );
UIService:
uint8_t GetLobbyistNumber( void ); // [0-3] from lobbyist selector switch
bool GetTeamColor( void ); // [true,false] from PAC team color switch
int8_t GetThrottle( void ); // [-127,127] throttle from PAC
int8_t GetTurn( void ); // [-127,127] turn from PAC
uint8_t GetSpecialAction( void ); // [8bits] from PAC special
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "PACTransmit.h"
#include "Initializations.h"
// include uart, interrupt lib
#include "inc/hw_uart.h"
#include "driverlib/interrupt.h"
#include "inc/hw_nvic.h"
// include PAC main service,UI service header
#include "PACService.h"
#include "UIService.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
// Types of packets
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CTRL 0x02
#define STATUS 0x03
#define RESEND 0x04
// Packet size overhead (everything besides
#define PACKET_SIZE_OVERHEAD 9
// Frame data overhead
#define FRAME_DATA_OVERHEAD 5
// Frame data bytes start position
#define FRAME_DATA_START 3
// RF Data bytes start position
#define RF_DATA_START 8
// RF Data Length
#define REQ_PAIR_SIZE 2
#define ENCR_KEY_SIZE 33
#define CTRL_SIZE 5
#define STATUS_SIZE 2
// Packet Pieces
#define START_DELIMTER 0x7e
#define LENGTH_MSB 0x00
#define API_ID 0x01
#define FRAME_ID 0x00
#define OPTIONS 0x00
// REQ_PAIR Bit Positions
#define TEAM_COLOR BIT7HI
// Status Bit Positions
#define DEC_ERR BIT1HI
#define PAIR BIT0HI
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static bool ConstructTxPacket ( uint8_t );
static void CreateXBeeHeader ( void );
static void SetXBeeChecksum ( void );
static void CreateEncryptKey ( void );
static void IncrementEncryptIndex (void );
static bool BeginPACTransmit ( void );
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// States defined in the header file (PACTransmit.h)
static PACTransmitState_t CurrentState;
// Encryption Variables
static uint8_t EncryptKey[32] = { 0 }; // Encrypt key for Lobbyist is zero (does nothing)
static uint8_t EncryptIndex = 0; // Tells us how far into the key we've rotated
// Packet Variables
static uint8_t PacketType;
static uint8_t index = 0;
static uint8_t PacketSize = 0;
static uint8_t FrameDataSize; // Equivalent to length LSB in XBee Tx Packet
static uint8_t RFDataSize;
static uint8_t CTRL0;
static uint8_t CTRL1;
static uint8_t CTRL2;
static uint8_t CTRLChecksum;
static uint8_t DestAddressMSB = 0;
static uint8_t DestAddressLSB = 0;
static uint8_t PairData = 0x87; // For reference, this is a test setting
static uint8_t LastEncryptedCTRLChecksum = 0;
//The TxPacket array stores the outgoing data, starting with the API Identifier (index 0) and ending with the RF Data.
//It is statically allocated and is large enough to hold the largest-anticipated data transmission, which is the encryption key data
static uint8_t TxPacket[41];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializePACTransmit
****************************************************************************/
bool InitializePACTransmit (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//The UART for the PAC is initialized here, because the
// PAC will transmit data before receiving any.
InitializeUART();
// Enable NVIC and Global Interrupts
HWREG(NVIC_EN0) |= BIT6HI;
__enable_irq();
//Set CurrentState of state machine
CurrentState = WaitingToSendByteOne;
puts("\r\nInitializePACTransmit Complete");
// Post Event ES_Init to this queue (this service)
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true) {
// End of initialization (return True)
return true;
} else {
return false;
}
}//End of InitializePACTransmit (return True)
/****************************************************************************
Function
PostPACTransmit
****************************************************************************/
bool PostPACTransmit( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
RunPACTransmit
****************************************************************************/
ES_Event RunPACTransmit (ES_Event ThisEvent){
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
switch(CurrentState) {
/***** If CurrentState is WaitingToSendByteOne *****/
case WaitingToSendByteOne:
if (ThisEvent.EventType == ES_BEGIN_TRANSMIT) { // ADD EVENT TYPE TO ES_CONFIGURE
// Prints
// printf("\r\n\n\nGot ES_BEGIN_TRANSMIT event.");
// Save away event param that has packet type
PacketType = ThisEvent.EventParam;
// Construct Packet (this function also sets PacketSize)
// printf("\r\n\nStarting ConstructPacket with PacketType = %d", PacketType);
if (ConstructTxPacket( PacketType )) { // Packet was created successfully
// Reset index (index indexes into TxPacket)
index = 0;
// Move Current State to sending byte
CurrentState = SendingPacket;
// Prints
// printf("\r\nCreated packet.");
// Begin the transmit
BeginPACTransmit();
} else {
// Do nothing, exit transmit
// Prints
printf("\r\nExiting transmit.");
} // END IF constructed packet success/failure
} // END IF EVENT TYPE
break; // END CASE WaitingToSendByteOne
/***** If CurrentState is SendingPacket *****/
case SendingPacket:
if ( ThisEvent.EventType == ES_ALL_BYTES_SENT ) {
// Prints
// printf("\r\nFull packet sent.");
// printf("\r\nNumber of bytes sent = %d.", index);
// Change state to WaitingToSendByteOne (we reset on ES_BEGIN_TRANSMIT event)
CurrentState = WaitingToSendByteOne;
} else if ( ThisEvent.EventType == ES_LOST_CONNECTION ) {
// Only switch current state to wait2sendbyte1
CurrentState = WaitingToSendByteOne;
} // END IF Event Types
break; // END CASE SendingByte
}//END SWITCH STATEMENT
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunPACTransmit
/****************************************************************************
Function
PACTransmitISR
Notes
Handles the UART TX Interrupt
****************************************************************************/
void PACTransmitISR ( void ) {
// TX ISR Code
// If TXMIS is set (TX byte finished sending interrupt)
if (HWREG(UART1_BASE + UART_O_MIS) & UART_MIS_TXMIS) {
// (Writing to the TX FIFO should technically clear the int. but let's make sure)
// Clear TXIC in UARTICR (interrupt clear register)
HWREG(UART1_BASE + UART_O_ICR) |= UART_ICR_TXIC;
// If we've sent all bytes of the packet
if (index == PacketSize) {
// Disable UART TX interrupts
// Clear Interrupt Mask bit in UART Mask Reg
HWREG(UART1_BASE + UART_O_IM) &= ~UART_IM_TXIM;
// Post ES_ALL_BYTES_SENT to this service
ES_Event ThisEvent;
ThisEvent.EventType = ES_ALL_BYTES_SENT;
ThisEvent.EventParam = 0; // Don't really need this
PostPACTransmit( ThisEvent );
} else if (index == (PacketSize - 1)) {
// We send the last byte
// Write new data to register (UARTDR: UART data register)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Increment index to let us know that the last byte of the packet was sent
index++;
} else {
// We still have more bytes to send
// Write new data to register (UARTDR: UART data register)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Increment index
index++;
}
} else {
// Not a TX interrupt, do nothing
}
}
/****************************************************************************
Function
GetLastEncryptedCTRLChecksum
Notes
Handles the UART TX Interrupt
****************************************************************************/
uint8_t GetLastEncryptedCTRLChecksum ( void ) {
// Give PACService the encrypted CTRL checksum of the last packet sent
return LastEncryptedCTRLChecksum;
}
/***************************************************************************
private functions
***************************************************************************/
/****************************************************************************
Function
ConstructPacket
Notes
Constructs the packet to send.
Takes in type of packet
****************************************************************************/
static bool ConstructTxPacket ( uint8_t TypeOfPacket ) {
// Function variables
uint8_t i;
// Get info for packet construction
if (TypeOfPacket == REQ_PAIR) {
printf("\r\nREQ_PAIR packet type request.");
// If TypeOfPacket is REQ_PAIR
// Set PacketSize
PacketSize = PACKET_SIZE_OVERHEAD + REQ_PAIR_SIZE;
// Set FrameDataSize
FrameDataSize = FRAME_DATA_OVERHEAD + REQ_PAIR_SIZE;
// Set RFDataSize
RFDataSize = REQ_PAIR_SIZE;
// Set Destination Adress to Broadcast
DestAddressMSB = 0xff;
DestAddressLSB = 0xff;
// Create XBee Header: (XBee bytes up to RF Data)
CreateXBeeHeader();
// Get 0-3 number from the PAC's lobbyist pair selector switch
PairData = GetLobbyistNumber();
// Get color from the PAC's color switch
if (GetTeamColor()) {
PairData |= TEAM_COLOR; // If true, set bit 7 hi for blue team
} else {
PairData &= ~TEAM_COLOR; // If false, set bit 7 lo for red team
}
// Fill Out RF Data of TXPacket (Don't Encrypt)
TxPacket[RF_DATA_START] = TypeOfPacket;
TxPacket[RF_DATA_START+1] = PairData; // Use default for debugging
// Set XBee Checksum
SetXBeeChecksum();
// Reset last enc ctrl checksum to zero
LastEncryptedCTRLChecksum = 0x00;
// Return true: packet successfully created
return true;
} else if (TypeOfPacket == ENCR_KEY) {
printf("\r\nENCR_KEY packet type request.");
// If TypeOfPacket is ENCR_KEY (0x03 Header)
// Set PacketSize
PacketSize = PACKET_SIZE_OVERHEAD + ENCR_KEY_SIZE;
// Set FrameDataSize
FrameDataSize = FRAME_DATA_OVERHEAD + ENCR_KEY_SIZE;
// Set RFDataSize
RFDataSize = ENCR_KEY_SIZE;
// Get Dest Address from RX service
DestAddressMSB = GetLobbyistAddressMSB();
DestAddressLSB = GetLobbyistAddressLSB();
// Create XBee Header: (XBee bytes up to RF Data)
CreateXBeeHeader();
// Create EncryptKey
CreateEncryptKey();
// Reset EncryptIndex (new pair)
EncryptIndex = 0;
// Fill Out RF Data of TXPacket (Don't Encrypt)
TxPacket[RF_DATA_START] = TypeOfPacket;
for ( i = RF_DATA_START + 1 ; i < RF_DATA_START + RFDataSize ; i++ ) {
TxPacket[i] = EncryptKey[(i-RF_DATA_START-1)];
}
// Set XBee Checksum
SetXBeeChecksum();
// Reset last enc ctrl checksum to zero
LastEncryptedCTRLChecksum = 0x00;
// Return true: packet successfully created
return true;
} else if (TypeOfPacket == CTRL) {
// printf("\r\nCTRL packet type request.");
// If TypeOfPacket is CTRL
// Set PacketSize
PacketSize = PACKET_SIZE_OVERHEAD + CTRL_SIZE;
// Set FrameDataSize
FrameDataSize = FRAME_DATA_OVERHEAD + CTRL_SIZE;
// Set RFDataSize
RFDataSize = CTRL_SIZE;
// Get Dest Address from RX service
DestAddressMSB = GetLobbyistAddressMSB();
DestAddressLSB = GetLobbyistAddressLSB();
// Create XBee Header: (XBee bytes up to RF Data)
CreateXBeeHeader();
// Get forward/back
CTRL0 = (uint8_t) GetThrottle(); // Make sure lobbyist uncasts these
// Get direction
CTRL1 = (uint8_t) GetTurn(); // Make sure lobbyist uncasts these
// Get special actions
CTRL2 = GetSpecialAction();
// Calculate CTRLChecksum
CTRLChecksum = TypeOfPacket + CTRL0 + CTRL1 + CTRL2;
// Fill out RF Data of TXPacket (Encrypt)
TxPacket[RF_DATA_START] = TypeOfPacket ^ EncryptKey[EncryptIndex];
IncrementEncryptIndex();
TxPacket[RF_DATA_START+1] = CTRL0 ^ EncryptKey[EncryptIndex];
IncrementEncryptIndex();
TxPacket[RF_DATA_START+2] = CTRL1 ^ EncryptKey[EncryptIndex];
IncrementEncryptIndex();
TxPacket[RF_DATA_START+3] = CTRL2 ^ EncryptKey[EncryptIndex];
IncrementEncryptIndex();
TxPacket[RF_DATA_START+4] = CTRLChecksum ^ EncryptKey[EncryptIndex];
IncrementEncryptIndex();
// Save away the encrypted checksum
LastEncryptedCTRLChecksum = TxPacket[RF_DATA_START+4];
// Set XBee Checksum
SetXBeeChecksum();
// Return true: packet successfully created
return true;
} else if (TypeOfPacket == RESEND) {
printf("\r\nRESEND packet type request.");
// If TypeOfPacket is RESEND (0x04)
// Packet stays the same, do not modify the packet
return true;
} else {
// Do Nothing (bad packet type)
printf("\r\nBad packet type request.");
// Return false: packet not created
return false;
}
// Finish and go back to SM
}
/****************************************************************************
Function
CreateXBeeHeader
Notes
Makes the XBee Header up to the RF Data
****************************************************************************/
static void CreateXBeeHeader ( void ) {
// Build XBee Header
TxPacket[0] = START_DELIMTER;
TxPacket[1] = LENGTH_MSB;
TxPacket[2] = FrameDataSize; // Update in ContructTx before calling me
TxPacket[3] = API_ID;
TxPacket[4] = FRAME_ID;
TxPacket[5] = DestAddressMSB; // Update in ContructTx before calling me
TxPacket[6] = DestAddressLSB; // Update in ContructTx before calling me
TxPacket[7] = OPTIONS;
}
/****************************************************************************
Function
SetXBeeChecksum
Notes
Calculates then sets the checksum for the frame data
****************************************************************************/
static void SetXBeeChecksum ( void ) {
// Function variables
uint8_t i;
uint8_t RollingSum;
uint8_t XBeeChecksum;
// Set RollingSum to zero
RollingSum = 0;
// Calculate by looping through bytes in frame data
for ( i = FRAME_DATA_START; i < FRAME_DATA_START + FrameDataSize ; i++ ) {
// Add current TxPacket byte to rolling sum
RollingSum += TxPacket[i];
}
// Subtract rolling sum from 0xff to get actual checksum
XBeeChecksum = 0xff - RollingSum;
// Set XBeeChecksum as last byte in XBee packet
TxPacket[FRAME_DATA_START + FrameDataSize] = XBeeChecksum;
}
/****************************************************************************
Function
CreateEncryptKey
Notes
Makes a 32 byte encryption key randomly
****************************************************************************/
static void CreateEncryptKey ( void ) {
// Function variables
uint8_t i;
uint8_t n = 32; // Encrypt Key length
for ( i = 0 ; i < n ; i++ )
{
// Random number between 0 and 255
EncryptKey[i] = rand() % 256;
}
}
/****************************************************************************
Function
IncrementEncryptIndex
Notes
increments the EncryptIndex so that it satys within [0,31]
****************************************************************************/
static void IncrementEncryptIndex ( void ) {
EncryptIndex = (EncryptIndex + 1) % 32;
}
/****************************************************************************
Function
BeginPACTransmit
Notes
This code is called when we want to transmit a packet,
then this function wil cause a UART Tx Interrupt.
****************************************************************************/
static bool BeginPACTransmit ( void ) {
// printf("\r\n\nStarting BeginPACTransmit. index = %d.", index);
// Non-Interrupt TX Code
// If TXFE is set (there is room to transfer a byte)
if ( HWREG(UART1_BASE + UART_O_FR) & UART_FR_TXFE ) {
// Write the new byte to the single-stack FIFO (full FIFO is diasbled)
HWREG(UART1_BASE + UART_O_DR) = (HWREG(UART1_BASE + UART_O_DR) & 0xffffff00) + TxPacket[index];
// Initialize UART TX Interrupt:
// Set Interrupt Mask bit in UART Mask Reg
// (This will fire an interrupt when the byte finishes sending)
HWREG(UART1_BASE + UART_O_IM) |= UART_IM_TXIM;
// Increment index
index++;
// Return true
return true; // First byte transmission successful
} else {
return false; // TX failed
}
}
PACReceive receives status packets that are sent by the hovercrafts (Lobbyists) via UART.
#ifndef PACReceive_H
#define PACReceive_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
#define ALL_BITS (0xff<<2)
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { WaitingFor0x7e, WaitingForMSB, WaitingForLSB, GettingDataPacket} PACReceiveState_t;
//Public function prototypes
bool InitializePACReceive (uint8_t Priority);
bool PostPACReceive( ES_Event ThisEvent );
ES_Event RunPACReceive (ES_Event ThisEvent);
void ReceiveISR(void);
uint8_t GetNextRxByte(uint8_t);
uint8_t GetSourceAddressMSB( void );
uint8_t GetSourceAddressLSB( void );
#endif ///PACReceive_H
/****************************************************************************
Module
PACReceive.c
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_nvic.h"
#include "inc/hw_uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "PACReceive.h"
#include "PACService.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
#define DoubleCharTime 17 //1.67ms is the time for 16 bits, aka 2 bytes, at 9600 baud!!!!!!!!!!!!!!!!Rounded to 2ms!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define LARGEST_FRAME_DATA 38 //max number of bytes stored in RxPacket[] and DataForMani[]
#define FRAME_DATA_OVERHEAD 5
//Number of RF data bytes in a certain packet
#define REQ_PAIR_LENGTH 2 //number of Rf data bytes in a request to pair
#define ENCR_KEY_LENGTH 33
#define CONTROL_LENGTH 5
#define STATUS_LENGTH 3
//Packet types used as event parameters
#define REQ_PAIR 0x00
#define ENCR_KEY 0x01
#define CONTROL 0x02
#define STATUS 0x03
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static void ClearRxPacket(void);
static void ReinitializeAllVariables(void);
static void InitializeRxInterrupt(void);
static void WriteRxToDataArray(void);
static uint8_t GetPacketType(void);//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static PACReceiveState_t CurrentState;
static uint8_t index = 0; //this is the index into RxPacket[]
static uint8_t MyRxSum = 0; //this is the sum you add to each time you read in a new decrypted data byte. It adds everything from the API identifier though the last byte of RF data
static uint8_t MyRxChecksum = 0; //this is the checksum that's produced from MyRxSum: MyRxChecksum = FF - MyRxSum
static uint8_t RxChecksum = 0; //this is the checksum that was sent to you over Xbee at the highest level of the data packet
static uint8_t BytesLeftRx = 0; //this is the number of bytes you're still expecting to receive
static uint8_t NewByte; //NewByte is the byte that's read in from the UART during the ISR and then sent as an event parameter from the ISR attached to ES_GOT_7E and ES_GOT_NEW_BYTE
uint8_t PacketType = 0; //specifies if packet is a control packet, encryption key, etc...
uint8_t PacketLSB = 0; //the number of bytes that the frame data will hold
uint8_t SourceAddressMSB;
uint8_t SourceAddressLSB;
//The RxPacket array stores the incoming data, starting with the API Identifier (index 0) and ending with the RF Data.
//It is statically allocated and is large enough to hold the largest-anticipated data transmission, which is the encryption key data
static uint8_t RxPacket[LARGEST_FRAME_DATA];
//The DataForMain array stores the information we want to send to send to MainLobbyist.
static uint8_t DataForMain[LARGEST_FRAME_DATA];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializePACReceive
****************************************************************************/
bool InitializePACReceive (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
//Because the PAC will send data before recieving any, do not initialize the UART here
//Make sure all arrays are initialized to 0, and not filled with leftover junk from the data registers
ClearRxPacket();
//Set CurrentState of state machine
CurrentState = WaitingFor0x7e;
//Initialize interrupts
InitializeRxInterrupt();
// Prints
puts("\r\nInitializePACReceive Complete");
// Post Event ES_Init to this queue (this service)
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true) {
// End of initialization (return True)
return true;
} else {
return false;
}
}//End of InitializeLobbyistReceive (return True)
/****************************************************************************
Function
PostPACReceive
****************************************************************************/
bool PostPACReceive( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
RunPACReceive
****************************************************************************/
ES_Event RunPACReceive (ES_Event ThisEvent){
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
//Set NextState to CurrentState
PACReceiveState_t NextState = CurrentState;
switch(CurrentState)
{
case WaitingFor0x7e:
// puts("Inside WaitingFor0x7e \r\n");
if(ThisEvent.EventType == ES_GOT_7E){
//puts("ES_GOT_7E \r\n");
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
//Go to next state
NextState = WaitingForMSB;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables(); //this also sets the DecryptFlag back to false
NextState = WaitingFor0x7e;
}
break; //End of WaitingFor0x7e
case WaitingForMSB:
// puts("Inside WaitingForMSB \r\n");
if(ThisEvent.EventType == ES_GOT_NEW_BYTE){
//puts("Got ES_GOT_NEW_BYTE inside WaitingForMSB\r\n");
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
//If new byte == 00, go to WaitingForLSB (read UART register). Else, go back to WaitingFor0x7e
if(NewByte == 0x00){
NextState = WaitingForLSB;
} else{
NextState = WaitingFor0x7e;
}
}
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DOUBLE_CHAR_TIMER_RX)
|| (ThisEvent.EventType == ES_LOST_CONNECTION)
|| (ThisEvent.EventType == ES_BAD_DECRYPTION)){
puts("Bad event occurred inside WaitingForMSB \r\n");
//re-initialize all variables to prep for next data packet
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables();
NextState = WaitingFor0x7e;
}
break; //End of WaitingForMSB
case WaitingForLSB:
// puts("Inside WaitingForLSB \r\n");
if(ThisEvent.EventType == ES_GOT_NEW_BYTE){
// puts("Got ES_GOT_NEW_BYTE inside WaitingForLSB \r\n");
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
PacketLSB = NewByte;
//Set BytesLeftRx to the value of this new data byte
BytesLeftRx = NewByte;
//Go to GettingDataPacket
NextState = GettingDataPacket;
}
if((ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DOUBLE_CHAR_TIMER_RX)
|| (ThisEvent.EventType == ES_LOST_CONNECTION)
|| (ThisEvent.EventType == ES_BAD_DECRYPTION)){
puts("Bad event occurred inside WaitingForLSB \r\n");
//Clear RxPacket[] and EncryptionKey[] and re-initialize all variables to prep for next data packet
ReinitializeAllVariables();
//Go back to WaitingFor0x7e
NextState = WaitingFor0x7e;
}
if(ThisEvent.EventType == ES_FAILURE_UNPAIR){
//Go back to the full initial unpaired state
ReinitializeAllVariables(); //this also sets the DecryptFlag back to false
NextState = WaitingFor0x7e;
}
break; //End of WaitingForLSB
case GettingDataPacket:
// puts("Inside GettingDataPacket \r\n");
if((ThisEvent.EventType == ES_GOT_NEW_BYTE) && (BytesLeftRx > 0)){
// puts("Got ES_GOT_NEW_BYTE inside GettingDataPacket1 \r\n");
//Start DoubleCharTimer
ES_Timer_InitTimer(DOUBLE_CHAR_TIMER_RX, DoubleCharTime);
NewByte = ThisEvent.EventParam;
//Add data value to running sum MyRxSum
MyRxSum += NewByte;
// printf("The next number being added to the rolling sum is %x \r\n",NewByte);
// printf("The rolling decrypted checksum is: %x\r\n",MyRxSum);
//Store data in RxPacket[index]
RxPacket[index] = NewByte;
//Increment index variable (index into RxPacket)
index++;
//Decrement BytesLeftRx
BytesLeftRx--;
} else if((ThisEvent.EventType == ES_GOT_NEW_BYTE) && (BytesLeftRx == 0)){
// puts("Got ES_GOT_NEW_BYTE inside GettingDataPacket2 \r\n");
NewByte = ThisEvent.EventParam;
//Store data in RxChecksum
RxChecksum = NewByte;
// printf("The checksum that was sent to me (in hex) was %x\r\n",RxChecksum);
//Compare MyRxChecksum against RxChecksum
MyRxChecksum = 0xFF - MyRxSum;
// printf("The checksum I calculated (inhex) was %x\r\n",MyRxChecksum);
//If you get a good checksum compare, then decide what to do with the data
if(MyRxChecksum == RxChecksum && RxPacket[0] == 0x81){
// printf("The checksum matches.\r\n");
//Send the new data up to MainLobbyist
WriteRxToDataArray();
PacketType = GetPacketType();
// printf("Packet type: %x\r\n", PacketType);
if (PacketType == STATUS) {
//Post ES_STATUS_RECEIVED to PACService
ThisEvent.EventType = ES_STATUS_RECEIVED;
ThisEvent.EventParam = (RxPacket[index-2]<<8);
ThisEvent.EventParam &= ~0xff;
ThisEvent.EventParam |= RxPacket[index-1];
PostPACService(ThisEvent);
SourceAddressMSB = RxPacket[1];
SourceAddressLSB = RxPacket[2];
} else {
// Not a status packet, do nothing, dont send it up
}
} else{
//ignore the data because you got a bad checksum compare
}
//FOR DEBUGGING/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// for(int i=0; i 0){ //true > 0
//Clear the receive interrupt source in the UARTICR (UART Masked Interrpt Clear Register)
HWREG(UART1_BASE + UART_O_ICR) |= UART_ICR_RXIC;
//Read the data register (UARTDR) and store in "RxUartByte"
uint8_t RxUartByte = HWREG(UART1_BASE + (UART_O_DR));
//Figure out the states of the error flags
uint8_t OverrunErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_OE);
uint8_t BreakErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_BE);
uint8_t ParityErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_PE);
uint8_t FramingErrorFlag = HWREG(UART1_BASE + (UART_O_RSR)) & (UART_RSR_FE);
//If no error flags are set
if((OverrunErrorFlag==0) && (BreakErrorFlag==0) && (ParityErrorFlag==0) && (FramingErrorFlag==0)){
//Determine if byte was 0x7e or something else and post ES_GOT_7E or E_GOT_NEW_BYTE to LobbyistReceive.c with RxUartByte set as the optional event parameter
if(RxUartByte == 0x7e && CurrentState == WaitingFor0x7e){
ThisEvent.EventType = ES_GOT_7E;
PostPACReceive(ThisEvent);
} else{
ThisEvent.EventType = ES_GOT_NEW_BYTE;
ThisEvent.EventParam = RxUartByte;
PostPACReceive(ThisEvent);
}
} else{//Else, respond to the error
//respond to all errors!!!!!!!Fix This!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ThisEvent.EventType = ES_LOST_CONNECTION;
PostPACReceive(ThisEvent);
//clear the UARTRSR register flags by writing any value of the UARTECR register
HWREG(UART1_BASE + UART_O_ECR) |= (UART_ECR_DATA_M);
}//end of if/else dealing with error flags
} else{
//Else, you are done (not an RX interrupt)
} //end of if/else that determines if the interrupt was caused by a UART receive
}
void WriteRxToDataArray(void){
//Use to transfer information from buffer array RxPacket to the array you're sending to MainLobbyist, DataForMain
for(uint8_t i=0; i < LARGEST_FRAME_DATA; i++){
DataForMain[i] = RxPacket[i];
}
}
uint8_t GetNextRxByte(uint8_t ThisIndex){
//Getter function MainLobbyist uses to read in the information from DataForMain array
return DataForMain[ThisIndex];
}
uint8_t GetPacketType(void){
uint8_t RfDataLength = PacketLSB - FRAME_DATA_OVERHEAD;
if(RfDataLength == REQ_PAIR_LENGTH){
return REQ_PAIR;
} else if(RfDataLength == ENCR_KEY_LENGTH){
return ENCR_KEY;
} else if(RfDataLength == CONTROL_LENGTH){
return CONTROL;
} else if(RfDataLength == STATUS_LENGTH){
return STATUS;
}
printf("Bad LSB received.\r\n");
return 0;
}
uint8_t GetSourceAddressMSB( void ){
//Getter function PACService uses to get the address of the sender XBee
return SourceAddressMSB;
}
uint8_t GetSourceAddressLSB( void ){
//Getter function PACService uses to get the address of the sender XBee
return SourceAddressLSB;
}
UIService interprets the input signals from the shake sensors and FSRs by converting them into throttle and turn values. This service gives PACTransmit the user’s commands whenever a control packet is transmitted. Additionally, this service interprets the lobbyist select and team color switch positions.
#ifndef UIService_H
#define UIService_H
// the common headers for C99 types
#include
#include
#include "ES_Configure.h"
#include "ES_Events.h"
#include "ES_Types.h" /* gets bool type for returns */
// typedefs for the states in the state machine
// State definitions for use with the query function
typedef enum { State1, State2} UIServiceState_t;
//Public function prototypes
bool InitializeUIService ( uint8_t Priority );
bool PostUIService ( ES_Event ThisEvent );
ES_Event RunUIService( ES_Event ThisEvent );
//Interrupt Service Routines
void PaddleRightISR( void );
void PaddleLeftISR( void );
void FSRRightISR( void );
void FSRLeftISR( void );
//Public Getter Functions necessary for PACTransmit.c
uint8_t GetLobbyistNumber( void ); // [0-3] from lobbyist selector switch
bool GetTeamColor( void ); // [true,false] from PAC team color switch
int8_t GetThrottle( void ); // [-127,127] throttle from PAC
int8_t GetTurn( void ); // [-127,127] turn from PAC
uint8_t GetSpecialAction( void ); // [8bits] from PAC special
#endif //UIService_H
/****************************************************************************
Module
UIService.c
Notes
Pair button press event is NOT handled here. See PairButtonService.
****************************************************************************/
//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h" // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"
#include
#include
#include
#include "termio.h"
#include
// include our own prototypes to insure consistency between header &
// actual functions definition
#include "UIService.h"
// include timer,interrupt,nvic lib
#include "inc/hw_timer.h"
#include "driverlib/interrupt.h"
#include "inc/hw_nvic.h"
/*----------------------------- Module Defines ----------------------------*/
#define ALL_BITS (0xff<<2)
// Control Interval Time Length
#define CONTROL_INTERVAL 200 // How often the control commands are updated
// Reverse-to-forward delay
#define R2F_INTERVAL 800 // Sets the delay between the last reverse command and when the user can begin applying throttle or turning
// Clamp values
#define THROTTLE_GAIN 3 // Scaling amount for throttle magnitude
#define TURN_GAIN 1 // Scaling amount for turn magnitude
#define REVERSE_THROTTLE -100 // Sets the reverse speed, can be anything in [-128,-1]
#define PADDLE_OFF_LIMIT 10 // Limit which defines a paddle as still or moving ( < PADDLE_OFF_LIMIT is treated as still)
#define TURN_PROPORTION 50
// Input Port Pin Definitions
#define BRAKE_BUTTON BIT3HI // Defined so that we can enter the testing mode
#define LOBBYIST_PINS (BIT0HI|BIT1HI|BIT2HI|BIT3HI) // All the Lobbyist Pins
#define L1 (~BIT0HI & LOBBYIST_PINS) // Select Lobbyist 1
#define L2 (~BIT1HI & LOBBYIST_PINS) // Select Lobbyist 2
#define L3 (~BIT2HI & LOBBYIST_PINS) // Select Lobbyist 3
#define L4 (~BIT3HI & LOBBYIST_PINS) // Select Lobbyist 4
#define TEAM_COLOR BIT2HI // Team Color
#define PADDLE_RIGHT BIT4HI // Right paddle
#define PADDLE_LEFT BIT5HI // Left paddle
#define FSR_RIGHT BIT6HI // Right FSR
#define FSR_LEFT BIT7HI // Left FSR
#define BRAKE_BIT BIT0HI // Brake bit in special action
#define PAIR_BIT BIT1HI // Unpair bit in special action
#define STATUS_PAIR_BIT BIT8HI // Pair bit in status packet
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
static void InitializeLobbyistNumber( void );
static void InitializeTeamColor( void );
static void InitializePaddlesAndForceSensors( void );
static void SetThrottleAndTurn( uint16_t, uint16_t, uint8_t, uint8_t);
static uint8_t ClampToInt8( uint16_t );
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// States defined in the header file (PACService.h)
static UIServiceState_t CurrentState;
// Control Bytes
static int8_t Throttle;
static int8_t Turn;
static uint8_t SpecialAction;
// Counters for capture inputs
static uint16_t PaddleRightCount;
static uint16_t PaddleLeftCount;
static uint8_t FSRRightCount;
static uint8_t FSRLeftCount;
static bool IsR2FActive; // Flag for reverse-to-forward delay timer
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeUIService
****************************************************************************/
bool InitializeUIService (uint8_t Priority){
ES_Event ThisEvent;
//Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
// Do Initialization Stuff
// Initialize UI Pins
InitializeLobbyistNumber();
InitializeTeamColor();
InitializePaddlesAndForceSensors();
// Go to (X) state out of reset
CurrentState = State1;
// Reset control bytes
Throttle = 0;
Turn = 0;
SpecialAction = 0;
// Start CONTROL_TIMER with zero holders
ES_Timer_InitTimer(CONTROL_TIMER, CONTROL_INTERVAL);
IsR2FActive = false;
PaddleRightCount = 0;
PaddleLeftCount = 0;
FSRRightCount = 0;
FSRLeftCount = 0;
// Prints
puts("\r\nInitializeUIService Complete");
// Post Event ES_Init to this queue (this service)
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true) {
// End of initialization (return True)
return true;
} else {
return false;
}
}//End of InitializePACService (return True)
/****************************************************************************
Function
PostUIService
****************************************************************************/
bool PostUIService( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************/
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
RunUIService
****************************************************************************/
ES_Event RunUIService (ES_Event ThisEvent){
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
switch(CurrentState) {
/***** If CurrentState is State1 *****/
case State1:
// Control Timer timeout
if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == CONTROL_TIMER) {
// Save counts to local variables so they dont change due to interrupts
uint16_t Local_PaddleRightCount = PaddleRightCount; // Frac allows us to tune imbalances between left and right paddles !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
uint16_t Local_PaddleLeftCount = PaddleLeftCount;
uint8_t Local_FSRRightCount = FSRRightCount;
uint8_t Local_FSRLeftCount = FSRLeftCount;
// Calculate throttle/turn values
SetThrottleAndTurn( Local_PaddleRightCount, Local_PaddleLeftCount, Local_FSRRightCount, Local_FSRLeftCount);
// Prints
// printf("\r\nRight = %d", Local_PaddleRightCount);
// printf(" Left = %d", Local_PaddleLeftCount);
// printf(" DIFF = %d", Local_PaddleRightCount-Local_PaddleLeftCount);
printf("\r\nThrottle = %d", Throttle);
printf(" Turn = %d", Turn);
// Reset modular-level counters
PaddleRightCount = 0;
PaddleLeftCount = 0;
FSRRightCount = 0;
FSRLeftCount = 0;
// Restart CONTROL_TIMER
ES_Timer_InitTimer(CONTROL_TIMER, CONTROL_INTERVAL);
// Reverse-to-forward Timer timeout
} else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == R2F_TIMER) {
// clear flag, false allows the user to apply throttle and turn commands
IsR2FActive = false;
// Pair Request Accepted from PACService (resets control packet values)
} else if (ThisEvent.EventType == ES_PAIR_REQUEST_ACCEPTED) {
// Clear Special
SpecialAction = 0;
// Brake Commands from BrakeButtonService (next to event types)
} else if (ThisEvent.EventType == ES_BRAKE && ThisEvent.EventParam == true) {
printf("\r\nBraking.");
// Set brake bit
SpecialAction |= BRAKE_BIT;
} else if (ThisEvent.EventType == ES_BRAKE && ThisEvent.EventParam == false) {
printf("\r\nReleasing Brake.");
// Clear brake bit
SpecialAction &= ~BRAKE_BIT;
// Unpair button press command
} else if (ThisEvent.EventType == ES_UNPAIR) {
printf("\r\nSending unpair command.");
// Send control packet with unpair command (set pair)
SpecialAction |= PAIR_BIT;
// ~~~~~~~~~~~~~~~ KEYBOARD TESTING EVENTS BELOW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Keyboard Test Event
} else if (ThisEvent.EventType == ES_TEST) {
Throttle = ThisEvent.EventParam;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x02;
PostPACTransmit( ThisEvent );
// Keyboard Brake Command (toggles)
} else if (ThisEvent.EventType == ES_SPECIAL_ACTION && ThisEvent.EventParam == BRAKE_BIT) {
printf("\r\nSending brake command.");
SpecialAction = SpecialAction ^ ThisEvent.EventParam;
// Keyboard Unpair Command
} else if (ThisEvent.EventType == ES_SPECIAL_ACTION && ThisEvent.EventParam == PAIR_BIT) {
printf("\r\nSending unpair command.");
// Send control packet with unpair command
SpecialAction |= PAIR_BIT;
} else {
// Event not applicable to this state.
// Do nothing.
}
break; // END CASE State: Unpaired
/***** If CurrentState is State2 *****/
case State2:
break; // END CASE State: Paired
}//END SWITCH STATEMENT
//Return ES_NO_EVENT
return ReturnEvent;
}//End of RunUIService
/****************************************************************************
Function
GetLobbyistNumber
Notes
Allows PACTransmit to get the lobbyist number
****************************************************************************/
uint8_t GetLobbyistNumber( void ) {
// Prints
// printf("\r\nFor testing, sending Lobbyist Number 0x07.");
// return 0x07;
// Test mode: hold down the brake button when pairing
if ( (HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & BRAKE_BUTTON) == BRAKE_BUTTON ) {
// Prints
printf("\r\n\nTest Mode: Sending Lobbyist Number 0x07.");
// Return Lobbyist 0x07 (our team)
return 0x07;
}
// Sample Port D: [0-3]
if ((HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS)) & LOBBYIST_PINS) == L1) {
// Prints
printf("\r\n\nLobbyist: 1.");
// Return Lobbyist 1
return 0x00;
} else if ((HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS)) & LOBBYIST_PINS) == L2) {
// Prints
printf("\r\n\nLobbyist: 2.");
// Return Lobbyist 2
return 0x01;
} else if ((HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS)) & LOBBYIST_PINS) == L3) {
// Prints
printf("\r\n\nLobbyist: 3.");
// Return Lobbyist 3
return 0x02;
} else if ((HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS)) & LOBBYIST_PINS) == L4) {
// Prints
printf("\r\n\nLobbyist: 4.");
// Return Lobbyist 4
return 0x03;
} else { // Physically impossible situation, unless switch broken
// Prints
printf("\r\n\nLobbyist Switch Broken. Gave PACTransmit 0xFF.");
// Return nonsense Lobbyist number
return 0xFF;
}
}
/****************************************************************************
Function
GetTeamColor
Notes
Allows PACTransmit to get the PAC's team color (PE2)
****************************************************************************/
bool GetTeamColor( void ) {
// Return the state of the pin
if ( (HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & TEAM_COLOR) == TEAM_COLOR) {
printf("\r\nPlaying for BLUE team.");
return true;
} else {
printf("\r\nPlaying for RED team.");
return false;
}
}
/****************************************************************************
Function
GetThrottle
Notes
Allows PACTransmit to get the throttle value
****************************************************************************/
int8_t GetThrottle( void ) {
// Print out throttle command
printf("\r\nThrottle = %d", Throttle);
return Throttle;
}
/****************************************************************************
Function
GetTurn
Notes
Allows PACTransmit to get the turn amount
****************************************************************************/
int8_t GetTurn( void ) {
// Print out turn command
printf(" Turn = %d", Turn);
return Turn;
}
/****************************************************************************
Function
GetSpecialAction
Notes
Allows PACTransmit to get the special action
****************************************************************************/
uint8_t GetSpecialAction( void ) {
// This PAC has no special action functionality
// Return blank special action byte
return SpecialAction;
}
/****************************************************************************
Function
PaddleRightISR
Notes
Handles WT2A input capture events (paddles)
****************************************************************************/
void PaddleRightISR( void ) {
// Clear interrupt
HWREG(WTIMER0_BASE+TIMER_O_ICR) = TIMER_ICR_CAECINT;
// Increment right paddle counter
PaddleRightCount++;
}
/****************************************************************************
Function
PaddleLeftISR
Notes
Handles WT2B input capture events (paddles)
****************************************************************************/
void PaddleLeftISR( void ) {
// Clear interrupt
HWREG(WTIMER0_BASE+TIMER_O_ICR) = TIMER_ICR_CBECINT;
// Increment left paddle counter
PaddleLeftCount++;
}
/****************************************************************************
Function
FSRRightISR
Notes
Handles WT3A input capture events (FSRs)
****************************************************************************/
void FSRRightISR( void ) {
// Clear interrupt
HWREG(WTIMER1_BASE+TIMER_O_ICR) = TIMER_ICR_CAECINT;
// Increment right FSR counter
FSRRightCount++;
}
/****************************************************************************
Function
FSRLeftISR
Notes
Handles WT3B input capture events (FSRs)
****************************************************************************/
void FSRLeftISR( void ) {
// Clear interrupt
HWREG(WTIMER1_BASE+TIMER_O_ICR) = TIMER_ICR_CBECINT;
// Increment left FSR counter
FSRLeftCount++;
}
/***************************************************************************
private functions
***************************************************************************/
/****************************************************************************
Function
InitializeLobbyistNumber
Notes
Initializes pins for lobbyist selector switch (PD0,PD1,PD2,PD3)
****************************************************************************/
static void InitializeLobbyistNumber( void ) {
// Initialize the port D line to receive Lobbyist select switch signals
// Enable peripheral clock to Port D (R3)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R3;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R3) != SYSCTL_PRGPIO_R3)
; // (wait for port to be ready)
// Enable bits 0,1,2,3 on Port D as digital I/O line
HWREG(GPIO_PORTD_BASE+GPIO_O_DEN) |= (L1 | L2 | L3 | L4);
// Set data direction for bit 0,1 on Port D to be an input
HWREG(GPIO_PORTD_BASE+GPIO_O_DIR) &= ~(L1 | L2 | L3 | L4);
}
/****************************************************************************
Function
InitializeTeamColor
Notes
Initializes pin for team color switch (PE2)
****************************************************************************/
static void InitializeTeamColor( void ) {
// Initialize the port E line to receive team color switch signal
// Enable peripheral clock to Port E (R4)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R4;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R4) != SYSCTL_PRGPIO_R4)
; // (wait for port to be ready)
// Enable bit 2 on Port E as digital I/O line
HWREG(GPIO_PORTE_BASE+GPIO_O_DEN) |= TEAM_COLOR;
// Set data direction for bit 2 on Port E to be an input
HWREG(GPIO_PORTE_BASE+GPIO_O_DIR) &= ~TEAM_COLOR;
}
/****************************************************************************
Function
InitializePaddlesAndForceSensors
Notes
Initializes input capture interrupts for the paddles (shake sensors)
and force sensors
Port C(4,5,6,7)
****************************************************************************/
static void InitializePaddlesAndForceSensors( void ) {
///////////////////////////////////////////////////
// Follow steps on page 724 of the Tiva Datsheet://
///////////////////////////////////////////////////
// start by enabling the clock to the timer (Wide Timer 0 & 1)
HWREG(SYSCTL_RCGCWTIMER) |= (SYSCTL_RCGCWTIMER_R0 | SYSCTL_RCGCWTIMER_R1);
// enable the clock to Port C
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R2;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R2) != SYSCTL_PRGPIO_R2)
; // (wait for port to be ready)
// 1.
// make sure that WT0 & WT1 (Timer A&B on both) are disabled before configuring
HWREG(WTIMER0_BASE+TIMER_O_CTL) &= ~(TIMER_CTL_TAEN | TIMER_CTL_TBEN);
HWREG(WTIMER1_BASE+TIMER_O_CTL) &= ~(TIMER_CTL_TAEN | TIMER_CTL_TBEN);
// 2.
// set it up in 32bit wide (individual, not concatenated) mode
// the constant name derives from the 16/32 bit timer, but this is a 32/64
// bit timer so we are setting the 32bit mode
HWREG(WTIMER0_BASE+TIMER_O_CFG) = TIMER_CFG_16_BIT;
HWREG(WTIMER1_BASE+TIMER_O_CFG) = TIMER_CFG_16_BIT;
// 3.
// set up WT0,A
HWREG(WTIMER0_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TACDIR; //Up counting
HWREG(WTIMER0_BASE+TIMER_O_TAMR) &= ~TIMER_TAMR_TAAMS; //Up counting
HWREG(WTIMER0_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TACMR; //Edge-time mode
HWREG(WTIMER0_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TAMR_CAP; //Capture mode
// repeat for (WT0,B)
HWREG(WTIMER0_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBCDIR; //Up counting
HWREG(WTIMER0_BASE+TIMER_O_TBMR) &= ~TIMER_TBMR_TBAMS; //Up counting
HWREG(WTIMER0_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBCMR; //Edge-time mode
HWREG(WTIMER0_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBMR_CAP; //Capture mode
// repeat for (WT1,A)
HWREG(WTIMER1_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TACDIR; //Up counting
HWREG(WTIMER1_BASE+TIMER_O_TAMR) &= ~TIMER_TAMR_TAAMS; //Up counting
HWREG(WTIMER1_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TACMR; //Edge-time mode
HWREG(WTIMER1_BASE+TIMER_O_TAMR) |= TIMER_TAMR_TAMR_CAP; //Capture mode
// repeat for (WT1,B)
HWREG(WTIMER1_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBCDIR; //Up counting
HWREG(WTIMER1_BASE+TIMER_O_TBMR) &= ~TIMER_TBMR_TBAMS; //Up counting
HWREG(WTIMER1_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBCMR; //Edge-time mode
HWREG(WTIMER1_BASE+TIMER_O_TBMR) |= TIMER_TBMR_TBMR_CAP; //Capture mode
// 4.
// To set the event to rising edge, we need to modify the TAEVENT bits
// in GPTMCTL. Rising edge = 00, so we clear the 2 TAEVENT bits
HWREG(WTIMER0_BASE+TIMER_O_CTL) &= ~TIMER_CTL_TAEVENT_BOTH;
HWREG(WTIMER0_BASE+TIMER_O_CTL) &= ~TIMER_CTL_TBEVENT_BOTH;
HWREG(WTIMER1_BASE+TIMER_O_CTL) &= ~TIMER_CTL_TAEVENT_BOTH;
HWREG(WTIMER1_BASE+TIMER_O_CTL) &= ~TIMER_CTL_TBEVENT_BOTH;
// 5. Do not prescale the timers
// Do nothing
// 6.
// we want to use the full 32 bit count, so initialize the Interval Load
// register to 0xffff.ffff (its default value)
HWREG(WTIMER0_BASE+TIMER_O_TAILR) = 0xffffffff;
HWREG(WTIMER0_BASE+TIMER_O_TBILR) = 0xffffffff;
HWREG(WTIMER1_BASE+TIMER_O_TAILR) = 0xffffffff;
HWREG(WTIMER1_BASE+TIMER_O_TBILR) = 0xffffffff;
// 7.
// back to the timer to enable a local capture interrupt
HWREG(WTIMER0_BASE+TIMER_O_IMR) |= TIMER_IMR_CAEIM; //Event interrupt mask on
HWREG(WTIMER0_BASE+TIMER_O_IMR) |= TIMER_IMR_CBEIM; //Event interrupt mask on
HWREG(WTIMER1_BASE+TIMER_O_IMR) |= TIMER_IMR_CAEIM; //Event interrupt mask on
HWREG(WTIMER1_BASE+TIMER_O_IMR) |= TIMER_IMR_CBEIM; //Event interrupt mask on
// X.
// Other steps not in data sheet init. steps (instead, these are under signal description on p.706):
// Set up the port pins to do the capture (clock was enabled earlier)
// Start by setting the alternate function for Port C bits 4,5,6,7
HWREG(GPIO_PORTC_BASE+GPIO_O_AFSEL) |= (PADDLE_RIGHT | PADDLE_LEFT | FSR_RIGHT | FSR_LEFT);
// Map Port C bits 4,5,6,7 alternate functions to WTnCCPm
// 7 is the mux value to select WTnCCPm
// Pin 4
HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) = (HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) & 0xfff0ffff) + (7<<16);
// Pin 5
HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) = (HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) & 0xff0fffff) + (7<<20);
// Pin 6
HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) = (HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) & 0xf0ffffff) + (7<<24);
// Pin 7
HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) = (HWREG(GPIO_PORTC_BASE+GPIO_O_PCTL) & 0x0fffffff) + (7<<28);
// Enable pins 4,5,6,7 on Port C for digital I/O
HWREG(GPIO_PORTC_BASE+GPIO_O_DEN) |= (PADDLE_RIGHT | PADDLE_LEFT | FSR_RIGHT | FSR_LEFT);
// Make pins 4,5,6,7 on Port C into inputs
HWREG(GPIO_PORTC_BASE+GPIO_O_DIR) &= ~(PADDLE_RIGHT | PADDLE_LEFT | FSR_RIGHT | FSR_LEFT);
// Enable the Timer WT0A/B & WT1A/B interrupt in the NVIC
// Interrupt numbers 94,95,96,97 (datasheet p.105)
// How to program on p.142
HWREG(NVIC_EN2) |= BIT30HI; // Interrupt 94, WT0A
HWREG(NVIC_EN2) |= BIT31HI; // Interrupt 95, WT0B
HWREG(NVIC_EN3) |= BIT0HI; // Interrupt 96, WT1A
HWREG(NVIC_EN3) |= BIT1HI; // Interrupt 97, WT1B
// Make sure interrupts are enabled globally
__enable_irq();
// 8. Kick off the timers
HWREG(WTIMER0_BASE+TIMER_O_CTL) |= (TIMER_CTL_TAEN | TIMER_CTL_TASTALL); // Turn on WT0,A
HWREG(WTIMER0_BASE+TIMER_O_CTL) |= (TIMER_CTL_TBEN | TIMER_CTL_TBSTALL); // Turn on WT0,B
HWREG(WTIMER1_BASE+TIMER_O_CTL) |= (TIMER_CTL_TAEN | TIMER_CTL_TASTALL); // Turn on WT1,A
HWREG(WTIMER1_BASE+TIMER_O_CTL) |= (TIMER_CTL_TBEN | TIMER_CTL_TBSTALL); // Turn on WT1,B
// 9. Just for reference:
// Clear int by writing 1 to CnECINT of GPTMICR register
// Read time by reading GPTMTnR register
}
/****************************************************************************
Function
SetThrottleAndTurn
Notes
****************************************************************************/
static void SetThrottleAndTurn( uint16_t RightPaddle, uint16_t LeftPaddle, uint8_t RightFSR, uint8_t LeftFSR) {
// Function variables
int8_t LocalThrottle;
int8_t LocalTurn;
// Individual side gains
uint16_t LocalRightPaddle = (RightPaddle*2)+1;
uint16_t LocalLeftPaddle = LeftPaddle+1;
// Calculate throttle & turn
if ((LocalRightPaddle/LocalLeftPaddle) > TURN_PROPORTION) { // Left turn
// Set Throttle to zero
LocalThrottle = 0;
// Turn is based on right paddle
LocalTurn = -127; // -1*ClampToInt8(LocalRightPaddle*TURN_GAIN);
printf("\r\nLEFT TURN");
} else if ((LocalLeftPaddle/LocalRightPaddle) > TURN_PROPORTION) { // Right turn
// Set Throttle to zero
LocalThrottle = 0;
// Turn is based on right paddle
LocalTurn = 127; // ClampToInt8(LocalLeftPaddle*TURN_GAIN);
printf("\r\nRIGHT TURN");
} else if ((LocalRightPaddle > PADDLE_OFF_LIMIT) && (LocalLeftPaddle > PADDLE_OFF_LIMIT)) { // Forward
// Set Throttle based on average
LocalThrottle = ClampToInt8(LocalRightPaddle*THROTTLE_GAIN);
// Turn is zero
LocalTurn = 0;
printf("\r\nNO TURN");
} else if ((LocalRightPaddle < PADDLE_OFF_LIMIT) && (LocalLeftPaddle < PADDLE_OFF_LIMIT)) { // No accel
// Set Throttle to zero
LocalThrottle = 0;
// Turn is zero
LocalTurn = 0;
printf("\r\nNOTHING");
} else {
// Set Throttle to zero
LocalThrottle = 0;
// Turn is zero
LocalTurn = 0;
printf("\r\nELSE");
}
// Set throttle based on PaddleCount if no reverse requested
if ( RightFSR || LeftFSR ) { // user requested reverse
// Do full reverse
LocalThrottle = REVERSE_THROTTLE;
// No turn
LocalTurn = 0;
// Reset reverse-to-forward delay timer
ES_Timer_InitTimer(R2F_TIMER, R2F_INTERVAL);
// Set Timer active
IsR2FActive = true;
} else if ( !IsR2FActive ) { // user requested throttle and reverse-to-forward delay has expired
// Set Throttle
LocalThrottle = LocalThrottle;
} else { // No reverse requested and R2F timer active
// Set throttle to zero
LocalThrottle = 0;
// Turn is zero
LocalTurn = 0;
}
// Set modular level throttle & turn
Throttle = LocalThrottle;
Turn = LocalTurn;
}
/****************************************************************************
Function
ClampToInt8
Notes
****************************************************************************/
static uint8_t ClampToInt8( uint16_t Param ) {
// Clamp PaddleCount
if (Param > 127) {
return 127;
} else {
return Param;
}
}
PairButtonService debounces the pair/unpair button on the controller (PAC) and posts the pair button state to PACService.
/****************************************************************************
Header file for PairButtonService module
based on the Gen 2 Events and Services Framework
****************************************************************************/
#ifndef PairButtonService_H
#define PairButtonService_H
// Event Definitions
#include "ES_Configure.h" /* gets us event definitions */
#include "ES_Types.h" /* gets bool type for returns */
#include "ES_Framework.h"
// typedefs for the states
// State definitions for use with the query function
typedef enum { PowerCycleDelay, Debouncing, WaitingForButtonChange
} ButtonState_t ;
// Public Function Prototypes
bool InitializePairButtonService ( uint8_t Priority );
bool PostPairButtonService( ES_Event ThisEvent );
ES_Event RunPairButtonService( ES_Event ThisEvent );
bool CheckPairButtonEvents(void);
#endif /* PairButtonService_H */
/****************************************************************************
Module
PairButtonService.c
Revision
1.0.1
Description
This is the pair button service for the PAC
Notes
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "PairButtonService.h"
#include "PACService.h"
// the common headers for C99 types
#include
#include
// the headers to access the GPIO subsystem
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
// the headers to access the TivaWare Library
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "ES_Port.h"
#include "BITDEFS.H"
// these times assume a 1.000mS/tick timing
#define ONE_SEC 976
#define HALF_SEC (ONE_SEC/2)
#define TWO_SEC (ONE_SEC*2)
#define FIVE_SEC (ONE_SEC*5)
/*----------------------------- Module Defines ----------------------------*/
// mask for the number of active bits in the array of messages
#define CHOOSE_MSG_MASK 0x01
// Create macro to access all 8 bits at a time
#define ALL_BITS (0xff<<2)
// Define button down to be high
#define PAIR_BUTTON BIT1HI
// 30 ms debounce time
#define DEBOUNCE_INTERVAL 30
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static bool LastButtonState;
static bool CurrentButtonState;
// States for state machine
static ButtonState_t CurrentState;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializePairButtonService
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
Initializes the pins necessary to interface the pair
button with the PAC's Tiva
Saves away the priority, and does any
other required initialization for this service
Notes
Author
Nam Cuong, 10/23/15, 09:30
****************************************************************************/
bool InitializePairButtonService ( uint8_t Priority )
{
ES_Event ThisEvent;
// Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
// Initialize the port E line to receive team color switch signal
// Enable peripheral clock to Port E (R4)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R4;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R4) != SYSCTL_PRGPIO_R4)
; // (wait for port to be ready)
// Enable bit 1 on Port E as digital I/O line
HWREG(GPIO_PORTE_BASE+GPIO_O_DEN) |= PAIR_BUTTON;
// Set data direction for bit 1 on Port E to be an input
HWREG(GPIO_PORTE_BASE+GPIO_O_DIR) &= ~PAIR_BUTTON;
// Sample the button port pin (bit 1) and use it to initialize LastButtonState
LastButtonState = HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & PAIR_BUTTON;
// Set CurrentState to be PowerCycleDelay
CurrentState = PowerCycleDelay;
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(DEBOUNCE_TIMER, DEBOUNCE_INTERVAL);
// Prints
puts("\r\nInitializePairButtonService Complete");
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true)
{
// End of initialization (return True)
return true;
}else
{
return false;
}
}
/****************************************************************************
Function
PostPairButtonService
Parameters
EF_Event ThisEvent ,the event to post to the queue
Returns
bool false if the Enqueue operation failed, true otherwise
Description
Posts an event to the PairButtonService state machine's queue
Notes
Author
Nam Cuong, 10/25/15, 08:10
****************************************************************************/
bool PostPairButtonService( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunPairButtonService
Parameters
ES_Event : the event to process
Returns
ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
Description
Implements a 2-state state machine for debouncing timing (+1 state for power cycle delay timer)
Notes
Author
Nam Cuong
****************************************************************************/
ES_Event RunPairButtonService( ES_Event ThisEvent )
{
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
switch (CurrentState){
// If CurrentState is PowerCycleDelay
case PowerCycleDelay :
if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DEBOUNCE_TIMER){
// Set CurrentState to WaitingForButtonChange
CurrentState = WaitingForButtonChange;
}
break;
// If CurrentState is Debouncing
case Debouncing :
if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DEBOUNCE_TIMER){
// Set CurrentState to WaitingForButtonChange
CurrentState = WaitingForButtonChange;
}
break;
// Else if CurrentState is WaitingForButtonChange
case WaitingForButtonChange :
// If EventType is ES_BUTTON_RELEASE,
if(ThisEvent.EventType == ES_BUTTON_RELEASE){
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(DEBOUNCE_TIMER, DEBOUNCE_INTERVAL);
// Set CurrentState to Debouncing
CurrentState = Debouncing;
} else if (ThisEvent.EventType == ES_BUTTON_PRESS){
// Prints
printf("\r\n\n\nSending ES_USER_PAIR_PRESS event to PACService.");
// Post ES_USER_PAIR_PRESS event to PACService
ES_Event ThisEvent;
ThisEvent.EventType = ES_USER_PAIR_PRESS;
ThisEvent.EventParam = 0x00; // param doesnt matter
PostPACService(ThisEvent);
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(DEBOUNCE_TIMER, DEBOUNCE_INTERVAL);
// Set CurrentState to Debouncing
CurrentState = Debouncing;
}
break;
}
return ReturnEvent;
}
/****************************************************************************
Function
CheckPairButtonEvents
Parameters
None
Returns
bool: true if an event was detected & posted
Description
checks to see if the recalibration button is pressed and, if so,
posts to ButtonService that the button was pressed.
Notes
Author
Nam Cuong
****************************************************************************/
bool CheckPairButtonEvents(void)
{
//Local ReturnVal = False
bool ReturnVal = false;
// Set CurrentButtonState to state read from port pin
CurrentButtonState = HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & PAIR_BUTTON;
// If the CurrentButtonState is different from the LastButtonState
if (CurrentButtonState != LastButtonState) {// button state has been changed
if (CurrentButtonState) {
ES_Event ThisEvent;
ThisEvent.EventType = ES_BUTTON_PRESS;
ThisEvent.EventParam = 0; // don't really need this
PostPairButtonService(ThisEvent);
// Set return val
ReturnVal = true;
} else {
ES_Event ThisEvent;
ThisEvent.EventType = ES_BUTTON_RELEASE;
ThisEvent.EventParam = 0; // don't really need this
PostPairButtonService(ThisEvent);
// Set return val
ReturnVal = true;
}
}
// Set LastButtonState to the CurrentButtonState
LastButtonState = CurrentButtonState;
return ReturnVal;
}
/***************************************************************************
private functions
***************************************************************************/
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
BrakeButtonService debounces the brake button on the controller (PAC) and posts the brake button state to UIService.
/****************************************************************************
Header file for BrakeButtonService module
based on the Gen 2 Events and Services Framework
****************************************************************************/
#ifndef BrakeButtonService_H
#define BrakeButtonService_H
// Event Definitions
#include "ES_Configure.h" /* gets us event definitions */
#include "ES_Types.h" /* gets bool type for returns */
#include "ES_Framework.h"
// typedefs for the states
// State definitions for use with the query function
typedef enum { BrakePowerCycleDelay, BrakeDebouncing, BrakeWaitingForButtonChange
} BrakeButtonState_t ;
// Public Function Prototypes
bool InitializeBrakeButtonService ( uint8_t Priority );
bool PostBrakeButtonService( ES_Event ThisEvent );
ES_Event RunBrakeButtonService( ES_Event ThisEvent );
bool CheckBrakeButtonEvents(void);
#endif /* BrakeButtonService_H */
/****************************************************************************
Module
BrakeButtonService.c
Revision
1.0.1
Description
This is the brake button service for the PAC
Notes
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "BrakeButtonService.h"
#include "UIService.h"
// the common headers for C99 types
#include
#include
// the headers to access the GPIO subsystem
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
// the headers to access the TivaWare Library
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "ES_Port.h"
#include "BITDEFS.H"
// these times assume a 1.000mS/tick timing
#define ONE_SEC 976
#define HALF_SEC (ONE_SEC/2)
#define TWO_SEC (ONE_SEC*2)
#define FIVE_SEC (ONE_SEC*5)
/*----------------------------- Module Defines ----------------------------*/
// mask for the number of active bits in the array of messages
#define CHOOSE_MSG_MASK 0x01
// Create macro to access all 8 bits at a time
#define ALL_BITS (0xff<<2)
// Define button down to be high
#define BRAKE_BUTTON BIT3HI
// 30 ms debounce time
#define BRAKE_DEBOUNCE_INTERVAL 20
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static bool LastButtonState;
static bool CurrentButtonState;
// States for state machine
static BrakeButtonState_t CurrentState;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitializeBrakeButtonService
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
Initializes the pins necessary to interface the pair
button with the PAC's Tiva
Saves away the priority, and does any
other required initialization for this service
Notes
Author
Nam Cuong, 10/23/15, 09:30
****************************************************************************/
bool InitializeBrakeButtonService ( uint8_t Priority )
{
ES_Event ThisEvent;
// Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
// Initialize the port E line to receive team color switch signal
// Enable peripheral clock to Port E (R4)
HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R4;
while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R4) != SYSCTL_PRGPIO_R4)
; // (wait for port to be ready)
// Enable bit 3 on Port E as digital I/O line
HWREG(GPIO_PORTE_BASE+GPIO_O_DEN) |= BRAKE_BUTTON;
// Set data direction for bit 3 on Port E to be an input
HWREG(GPIO_PORTE_BASE+GPIO_O_DIR) &= ~BRAKE_BUTTON;
// Sample the button port pin (bit 3) and use it to initialize LastButtonState
LastButtonState = HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & BRAKE_BUTTON;
// Set CurrentState to be PowerCycleDelay
CurrentState = BrakePowerCycleDelay;
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(BRAKE_DEBOUNCE_TIMER, BRAKE_DEBOUNCE_INTERVAL);
// Prints
puts("\r\nInitializeBrakeButtonService Complete");
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService( MyPriority, ThisEvent) == true)
{
// End of initialization (return True)
return true;
}else
{
return false;
}
}
/****************************************************************************
Function
PostBrakeButtonService
Parameters
EF_Event ThisEvent ,the event to post to the queue
Returns
bool false if the Enqueue operation failed, true otherwise
Description
Posts an event to the BrakeButtonService state machine's queue
Notes
Author
Nam Cuong, 10/25/15, 08:10
****************************************************************************/
bool PostBrakeButtonService( ES_Event ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunBrakeButtonService
Parameters
ES_Event : the event to process
Returns
ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
Description
Implements a 2-state state machine for debouncing timing (+1 state for power cycle delay timer)
Notes
Author
Nam Cuong
****************************************************************************/
ES_Event RunBrakeButtonService( ES_Event ThisEvent )
{
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
switch (CurrentState){
// If CurrentState is PowerCycleDelay
case BrakePowerCycleDelay :
if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == BRAKE_DEBOUNCE_TIMER){
// Set CurrentState to WaitingForButtonChange
CurrentState = BrakeWaitingForButtonChange;
}
break;
// If CurrentState is Debouncing
case BrakeDebouncing :
if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == BRAKE_DEBOUNCE_TIMER){
// Set CurrentState to WaitingForButtonChange
CurrentState = BrakeWaitingForButtonChange;
}
break;
// Else if CurrentState is WaitingForButtonChange
case BrakeWaitingForButtonChange :
// If EventType is ES_BUTTON_RELEASE,
if(ThisEvent.EventType == ES_BUTTON_RELEASE){
// Prints
printf("\r\n\n\nSending ES_USER_BRAKE_PRESS event to UIService.");
// Post ES_USER_PAIR_PRESS event to UIService
ES_Event ThisEvent;
ThisEvent.EventType = ES_BRAKE;
ThisEvent.EventParam = 0; // brake off
PostUIService(ThisEvent);
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(BRAKE_DEBOUNCE_TIMER, BRAKE_DEBOUNCE_INTERVAL);
// Set CurrentState to Debouncing
CurrentState = BrakeDebouncing;
} else if (ThisEvent.EventType == ES_BUTTON_PRESS){
// Prints
printf("\r\n\n\nSending ES_USER_BRAKE_PRESS event to UIService.");
// Post ES_USER_PAIR_PRESS event to UIService
ES_Event ThisEvent;
ThisEvent.EventType = ES_BRAKE;
ThisEvent.EventParam = 1; // brake on
PostUIService(ThisEvent);
// Start debounce timer (timer posts to this service)
ES_Timer_InitTimer(BRAKE_DEBOUNCE_TIMER, BRAKE_DEBOUNCE_INTERVAL);
// Set CurrentState to Debouncing
CurrentState = BrakeDebouncing;
}
break;
}
return ReturnEvent;
}
/****************************************************************************
Function
CheckBrakeButtonEvents
Parameters
None
Returns
bool: true if an event was detected & posted
Description
checks to see if the recalibration button is pressed and, if so,
posts to ButtonService that the button was pressed.
Notes
Author
Nam Cuong
****************************************************************************/
bool CheckBrakeButtonEvents(void)
{
//Local ReturnVal = False
bool ReturnVal = false;
// Set CurrentButtonState to state read from port pin
CurrentButtonState = HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) & BRAKE_BUTTON;
// If the CurrentButtonState is different from the LastButtonState
if (CurrentButtonState != LastButtonState) {// button state has been changed
if (CurrentButtonState) {
ES_Event ThisEvent;
ThisEvent.EventType = ES_BUTTON_PRESS;
ThisEvent.EventParam = 0; // don't really need this
PostBrakeButtonService(ThisEvent);
// Set return val
ReturnVal = true;
} else {
ES_Event ThisEvent;
ThisEvent.EventType = ES_BUTTON_RELEASE;
ThisEvent.EventParam = 0; // don't really need this
PostBrakeButtonService(ThisEvent);
// Set return val
ReturnVal = true;
}
}
// Set LastButtonState to the CurrentButtonState
LastButtonState = CurrentButtonState;
return ReturnVal;
}
/***************************************************************************
private functions
***************************************************************************/
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
EventCheckers provides the opportunity to use keyboard presses to simulate events when plugged into a computer.
/****************************************************************************
Module
EventCheckers.h
Description
header file for the event checking functions
Notes
History
When Who What/Why
-------------- --- --------
10/18/15 11:50 jec added #include for stdint & stdbool
08/06/13 14:37 jec started coding
*****************************************************************************/
#ifndef EventCheckers_H
#define EventCheckers_H
// the common headers for C99 types
#include
#include
// prototypes for event checkers
bool Check4Keystroke(void);
bool CheckPairButtonEvents(void);
bool CheckBrakeButtonEvents(void);
#endif /* EventCheckers_H */
/****************************************************************************
Module
EventCheckers.c
Revision
1.0.1
Description
This is the sample for writing event checkers along with the event
checkers used in the basic framework test harness.
Notes
Note the use of static variables in sample event checker to detect
ONLY transitions.
History
When Who What/Why
-------------- --- --------
08/06/13 13:36 jec initial version
****************************************************************************/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"
// include our own prototypes to insure consistency between header &
// actual functionsdefinition
#include "EventCheckers.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h" /* gets bool type for returns */
#define BRAKE_BIT BIT0HI
#define PAIR_BIT BIT1HI
/****************************************************************************
Function
Check4Keystroke
Parameters
None
Returns
bool: true if a new key was detected & posted
Description
checks to see if a new key from the keyboard is detected and, if so,
retrieves the key and posts an ES_NewKey event to TestHarnessService0
Notes
The functions that actually check the serial hardware for characters
and retrieve them are assumed to be in ES_Port.c
Since we always retrieve the keystroke when we detect it, thus clearing the
hardware flag that indicates that a new key is ready this event checker
will only generate events on the arrival of new characters, even though we
do not internally keep track of the last keystroke that we retrieved.
Author
J. Edward Carryer, 08/06/13, 13:48
****************************************************************************/
bool Check4Keystroke(void) {
if ( IsNewKeyReady() ) // new key waiting?
{
ES_Event ThisEvent;
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
switch(GetNewKey()) {
case 'y':
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x00;
PostPACTransmit( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_BEGIN_TRANSMIT: REQ_PAIR event.");
break;
case 'e':
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x01;
PostPACTransmit( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_BEGIN_TRANSMIT: ENCR_KEY event.");
break;
case 'c':
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x02;
PostPACTransmit( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_BEGIN_TRANSMIT: CTRL event.");
break;
case 't':
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x03;
PostPACTransmit( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_BEGIN_TRANSMIT: STATUS event.");
break;
case 'z':
ThisEvent.EventType = ES_BEGIN_TRANSMIT;
ThisEvent.EventParam = 0x04;
PostPACTransmit( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_BEGIN_TRANSMIT: RESEND event.");
break;
case 'p':
ThisEvent.EventType = ES_USER_PAIR_PRESS;
ThisEvent.EventParam = 0x00; // Param doesn't matter
PostPACService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_USER_PAIR_REQUEST event.");
break;
case 'l':
ThisEvent.EventType = ES_STATUS_RECEIVED;
ThisEvent.EventParam = (BIT0HI); // Paired
PostPACService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_STATUS_RECEIVED: Paired event.");
break;
case '0':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x00; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x00 event.");
break;
case '1':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x01; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x01 event.");
break;
case '2':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x02; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x02 event.");
break;
case '3':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x03; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x03 event.");
break;
case '4':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x04; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x04 event.");
break;
case '5':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x05; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x05 event.");
break;
case '6':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x06; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x06 event.");
break;
case 'w':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x01; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x01 event.");
break;
case 'a':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x03; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x03 event.");
break;
case 's':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x02; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x02 event.");
break;
case 'd':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x04; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x04 event.");
break;
case 'f':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x00; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x00 event.");
break;
case 'g':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x06; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x06 event.");
break;
case 'r':
ThisEvent.EventType = ES_TEST;
ThisEvent.EventParam = 0x05; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_TEST: 0x05 event.");
break;
case ' ':
ThisEvent.EventType = ES_SPACEBAR;
ThisEvent.EventParam = 0x00; // Doesn't matter
PostUIService( ThisEvent );
//printf("\r\n\n\n\n\n\nSent ES_SPACEBAR event.");
break;
case 'b':
ThisEvent.EventType = ES_SPECIAL_ACTION;
ThisEvent.EventParam = BRAKE_BIT; // Doesn't matter
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_SPECIAL_ACTION: Brake event.");
break;
case 'u':
ThisEvent.EventType = ES_SPECIAL_ACTION;
ThisEvent.EventParam = PAIR_BIT; // Unpaired
PostUIService( ThisEvent );
printf("\r\n\n\n\n\n\nSent ES_SPECIAL_ACTION: Unpair event.");
break;
}
return true;
}
return false;
}