Mechanical Components

BARNACOAL

Complete Assembly

The BARNACOAL’s main purposes are to: maneuver through the water; to carry and dispense COAL; and to house all onboard electronics while protecting critical components from water. To start, we laser cut a clear acrylic sheet to create a base place. Our initial prototype featured a Duron base plate and foam, and while the Duron was overall functional, acrylic was more aesthetic and still more water-resistant. The acrylic was cheap, could withstand water, and readily available. To the bottom side of the base plate, we first attached two pieces of custom cut foam to provide buoyancy. Beneath the foam, we affixed two 3D printed pieces that mainly served as propeller mounts. As seen in the image to the right, the propellers are attached to DC brushed motors encased in a waterproof housing. Using a flexible U-ring and two #6-screws, we were able to mount the motor propeller unit to the bottom of the chassis to ensure that the propellers were fully submerged in the water.

BARNACOAL Assembly CAD DesignFoam

CAD Drawings of Chassis

BARNACOAL

Dumping Mechanism

The COAL dump mechanism and anchor both sit towards the front of the BARNACOAL. The dump mechanism was created using a combination of laser cut acrylic and 3D printed parts and features a top-hinged flat, activated by an HS-322HD motor. At the start of the game, the hinged door stays closed, holding in the COAL until we are ready to dispense everything into the RECEPTACOAL. The funnel at the top facilitates COAL reloading, since we were not allowed to get into the pool while reloading.

CAD Design of Dumping Mechanism

CAD Drawings of Dumping Mechanism

BARNACOAL

Anchoring Mechanism

Lastly, the 3D-printed anchor proved to be useful for latching onto the RECEPTACOAL while dumping COAL. Momentum as well as passive waves both tend to drive the BARNACOAL backwards in the water, away from the RECEPTACOAL, while dispensing COAL. The servo was also activated by an HS-322HD motor. 

Anchor CAD Design

CAD Drawings of Cascade Lift

BARNACOAL

PCB Mount

As for the onboard components, we mounted a watertight food container upside down near the nearside of the boat. Inside the tupperware, the battery pack sits on the bottom and the PCB mount rests on top of the battery packs. This design was simple but ensured that 1) none of the critical electronics were exposed to water and 2) in the midst of all the jostling and motion in water, the PCBs would not come into contact with each other and cause any unintentional shorts. 

PCB mount Design

CAD Drawings of Electronics Mount

BARNACOAL

Battery Holders

In order to reduce battery interference and to best organize the electrical components of the robot, we 3-D printed holders to house the 12V batteries as well as the portable battery that was connected to the power distribution board.

Battery Packs Image

CAD Drawings of Battery Holders

 BARNACOAL

Team Pairing Indicator

We cut through-holes in the tupperware, the Duron base plate, and the foam to allow motor wires to pass through. On top of the tupperware, a servo motor with a large “2” is attached, and the “2” is upside-down by default. When the BARNACOAL has successfully paired to another SPECTACOAL, the “2” rotates right side up. 

Team Pairing Indicator CAD Design

CAD Drawing of Team Pairing Indicator

Team Pairing Indicator CAD Drawing
SPECTACOAL

Carrying Case

The main housing of the SPECTACOAL was created using 3D-printed parts and a laser-cut acrylic front panel to house the 3 buttons, 2 joysticks, and 3 state-indicator LEDs of varying colors. Following the overarching airplane theme, the SPECTACOAL resembles a suitcase inside a TSA tray-box and houses an XBee module and a PIC32 chip. As it is not coming into intentional contact with the water, the SPECTACOAL’s main requirement was to provide easy access to the various tactile BARNACOAL controllers (joysticks, buttons, potentiometer, etc.) and withstand the motions of an occasional human celebration. 

SPECTACOAL CASE CAD

CAD Drawings of SPECTACOAL Case

Electrical Components

The KiCAD Schematic of the entire electrical system is as follows. Note that the electrical design of this project is divided into two subsystems–the BARNACOAL (the watercraft) and the SPECTACOAL (the controller). The BARNACOAL is connected to most of the servos and motors, whereas the SPECTACOAL is mainly connected to indicators and buttons to control an action and provide feedback on the completion of the action. Each of the subsystems is comprised of a PIC32 microcontroller wired up to various different components, listed below.

BARNACOAL KICADSPECTACOAL KICAD

SPECTACOAL COMPONENTS

Electrical Components

SPECTACOAL

This subsystem is in charge of sending commands from the SPECTACOAL to the BARNACOAL via the XBee radio module and the class-wide communications protocol. Considering that the BARNACOAL is not entirely autonomous, the SPECTACOAL is able to send constant messages to focus on the control-aspect of the tasks accomplished by the BARNACOAL.

SPECTACOAL KICAD

PIC32MX170F256B

  • The PIC is programmed with the communication software to transmit and receive messages via interrupts.
  • The PIC on the SPECTACOAL communicates with the PIC on the BARNACOAL, dictating which state the BARNACOAL should exist in.
  • The PIC on the SPECTACOAL controls the battery indication servo as well as the LEDs that dictate the visual feedback regarding the state of the BARNACOAL.
  • Microcontroller

Single-Axis Thumb Joystick Module

  • There are two joystick modules on the SPECTACOAL. Both are configured to operate on a single axis, with the left joystick operating on the Y-axis and the right joystick operating on the X-axis.
  • The left joystick controls the thrust of both of the motors, and the right joystick controls the direction of each of the motors, especially regarding turns.
  • Joystick Module

LED Diode

  • This LED Diode Indicates that the SPECTACOAL is unpaired.
  • Yellow LED
  • This LED Diode Indicates that the SPECTACOAL is paired.
  • Green LED
  • This LED Diode Indicates that the SPECTACOAL is recharging. If this LED is blinking, this indicates that the SPECTACOAL needs recharging
  • Red LED

Push Button

  • This is the button that would be used to pair the SPECTACOAL with a BARNACOAL.
  • Push Button
  • This is the button that would be used to actuate the anchor on the BARNACOAL that could be used to latch onto the RECEPTACOAL.
  • Push Button
  • The same type of button would be used to actuate the dump mechanism on the BARNACOAL to release the COAL into the RECEPTACOAL.
  • Push Button

XBee Radio Module

  • The SPDL-provided XBee module communicates with the SPDL-provided XBee module on the BARNACOAL. The address of the XBee on the SPECTACOAL is 2182.
  • XBee Radio Module

Game Indicator Servo Motor (FM90)

  • This servo shows the battery level of the BARNACOAL that is communicated back to the SPECTACOAL.

  • a game indicator Servo

BARNACOAL COMPONENTS

Electrical Components

BARNACOAL

The BARNACOAL is the watercraft itself, and the electronics on the BARNACOAL is primarily action-focused. Any components in this subsystem are geared towards driving the motor propellers, or driving the servo motors for the anchor or the dump mechanism. Any action that the BARNACOAL completes is as a result of a command provided by the SPECTACOAL, and the BARNACOAL sends the SPECTACOAL a pairing indicator message or a battery level message as a confirmation that the two devices are successfully paired. Most of the communication between the devices occurs via the XBee radio module.

BARNACOAL KICAD

PIC32MX170F256B

  • The PIC is programmed with the communication software to transmit and receive messages via interrupts.
  • The PIC on the BARNACOAL communicates with the PIC on the SPECTACOAL, receiving commands and sending back messages with battery levels or a pairing confirmation.
  • Microcontroller

Drive Motors (33GN2732) 

  • The drive motors were used to drive the wheels of the bot. We elected not to incorporate encoders into these motors because all feedback was included in the line following algorithm. The Drive Motors were driven with the Output Compare modules of the PIC 32 and included motor drivers with an H-Bridge and flyback diodes to protect against current surges.
  • A Drive Motor

HS-322HD Standard Heavy Duty Servo

  • Three identical servo motors are used on the BARNACOAL, for different purposes. The first servo is used as the pairing indicator on the BARNACOAL, flipping the team number 2 right-side up to indicate that the BARNACOAL has successfully paired. The second servo is used as the anchor, responding to commands from the SPECTACOAL. The third servo is used as the actuator for the dump mechanism, responding to commands from the SPECTACOAL.
  • Servo Motors

XBee Radio Module

  • The SPDL-provided XBee module communicates with the SPDL-provided XBee module on the SPECTACOAL. The address of the XBee on the BARNACOAL is 2082.
  • XBee Radio Module

Software Components

SoftWare Components – State Machine
ME218C State Diagram

The software is designed to be consistent with the class-wide Communication Protocol, designed by the Communications Committee, comprised of one delegate of each team. Check out the document below:

2025 ME218C Communications Protocol

The software for both the BARNACOAL and SPECTACOAL are each written in the format of a state machine that flows between a waiting state and a paired state. The state diagram for the BARNACOAL is a bit simpler than that of the SPECTACOAL. The SPECTACOAL involves additional states as it waits for the BARNACOAL to pair and additionally has a separate state when recharging.

The way that the software works for both the SPECTACOAL and BARNACOAL is that they both configure the UART2 Module to transmit and receive data via interrupts. However, the data can only be transmitted or received when the two devices are in a pairing or paired state–when in an unpaired state, the two devices should not be sending messages to one another.

Furthermore, the way that the message transmission works is that the messages are constructed via a helper function, according to the API framework. The way that message reception works is that the messages are stored in the Receive buffer and evaluated to ensure that the messages are properly packaged (with the start delimiter, the proper address, the frame ID, message length, and the checksum) then the data is parsed and the corresponding commands are carried out.

Click below to view pseudocode, source code, and header files.

SoftWare Components – SPECTACOAL FSM PSEUDOCODE
bool InitSPECXBeeService(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;
    // post the initial transition event
    // Configure the pins

    //First Byte, since there is nothing set to false
    DelimiterFound = false;
    
    // avoid any issues in the ISR regarding buffer size
        
    /* Set up UART2 Module */
    // Enable Interrupts and Configure Interrupts to transmit and receive
    
    // Enable input capture and global interrupts;  
    
    ThisEvent.EventType = ES_INIT;

    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}


ES_Event_t RunSPECXBeeService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

    if (ThisEvent.EventType == ES_INIT) {
        // Start the timer for 200 ms first so we stay on 5Hz schedule
        ES_Timer_InitTimer (MESSAGE_TIMER, 200);
    } 
    else if (ThisEvent.EventType == ES_PAIRING_REQ) {
        // Basically the mumbo jumbo to pair with the boats 
        // Update the address to transmit data to based on the boat address
    }
    else if (ThisEvent.EventType == ES_TIMEOUT) {
        // if the Message Timer timed out, then check if it is paired with the right barnacoal
        // if paired, then make the packet of data to send 
    }
    
    // Also need to handle issue with recharging
    else if (ThisEvent.EventType == ES_RECHARGE ) {
        // 
    }
 
    return ReturnEvent;
}


// Helper function to also package data into transmit buffer


void __ISR(_UART_2_VECTOR,IPL7SOFT)UART2_ISR(void) {
    __builtin_disable_interrupts();
    // Handle the Rx Buffer first ! 
    if (If the Receive Interrupt Flag is set) {
        Write the Receive register into received;
       
        Post a new event with the receive messages;
        Clear the Receive Interrupt Flag;
        
        // Do more with understanding if the bytes are correct
        // Check the start delimiter and all the bytes to follow
        // Index through the receive buffer and make sure the data is valid
        
    } 
    // handle the Tx buffer now
    else if (If Transmit Interrupts are enabled and the transmit interrupt flag is set) {
        // do some fancy stuff with the interrupt handling to make sure the
        // data is transmitted over nicely
        
        // Make sure not to clear the transmit interrupt enable mask until
        // the entire message is transmitted over
        Clear Transmit Interrupt Flag;
    }
    __builtin_enable_interrupts();
}


SoftWare Components –  SPECTACOAL FSM Source Code
/****************************************************************************
 Module
   SPECXBeeService.c

 Revision
   1.0.1

 Description
   This is a template file for implementing a simple service under the
   Gen2 Events and Services Framework.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 01/16/12 09:58 jec      began conversion from TemplateFSM.c
****************************************************************************/
/*----------------------------- 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 "SPECXBeeService.h"
#include <sys/attribs.h>
#include "ADPotService.h"
#include "dbprintf.h"
#include <xc.h>
#include "PWM_PIC32.h"

/*----------------------------- Module Defines ----------------------------*/
#define MAX_MESSAGE_SIZE 4
#define MAX_TX_BUF_SIZE MAX_MESSAGE_SIZE + 9
#define MAX_RX_BUF_SIZE MAX_MESSAGE_SIZE + 5
/*---------------------------- 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 TemplateState_t CurrentState;
    // buffers for Tx and Rx data
    static uint8_t TX_BUF[13];
    volatile static uint8_t RX_BUF[9];

    // Tx and Rx ISR index counters to make sure the bytes being sent/received are correct
    volatile static uint8_t idx_TX;
    volatile static uint8_t idx_RX;

    // Size that a current Tx / Rx will be
    static uint8_t TxBufferSize = 13;
    volatile static uint8_t RxBufferSize;

    // Checksums sum of bytes in a Tx Message
    static uint8_t TxByteSum;
    volatile static uint8_t RxByteSum;

    // Frame ID
    static uint8_t FrameID = 0x00;

    // Boolean to track transmission of start delimiter
    volatile static bool DelimiterFound;
    
    // Union for access of bytes within the addresses
    typedef union {
        uint16_t Whole16;
        uint8_t Byte[2];
    }TwoBytes_t;
    
    static TwoBytes_t TxAddress;
    

    static TwoBytes_t RxAddress;
    
    static TwoBytes_t RxMessage;

    // Boat Addresses
    static uint16_t ADDRESSES[6] = {0x2081, 0x2082, 0x2083, 0x2084, 0x2095, 0x2086};

    // Variables determined by Comms Committee
    // Joystick 1
    static uint32_t FORWARD = 0;
    // Joystick 2
    static uint32_t TURN = 0;
    static uint8_t STATUS = 0;
    static uint8_t Buttons = 0;
    static uint8_t Charge = 0;
    
    bool IsAnchor = false;
    bool IsDump = false;
    
    uint32_t potValue = 0;
    uint32_t adjPotValue = 0;
    uint32_t JoystickX = 0;
    uint32_t JoystickY = 0;
    
    static uint8_t onesCount = 0;
    static uint8_t zerosCount = 0;
    static uint8_t readCount = 0;


/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitSPECXBeeService

 Parameters
     uint8_t : the priorty of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, and does any
     other required initialization for this service
 Notes

 Author
     J. Edward Carryer, 01/16/12, 10:00
****************************************************************************/
bool InitSPECXBeeService(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;
    /* Pin Configurations */
    TRISBbits.TRISB11 = 1; // --> Configure pin for inputs Rx
    U2RXR = 0b0011;

    TRISAbits.TRISA3 = 0; //--> Configure pin for outputs Tx
    RPA3R = 0b0010;
    
    TRISAbits.TRISA0 = 1; //--> Configure pin for input for joystick
    ANSELAbits.ANSA0 = 1; // Analog
    
    TRISAbits.TRISA1 = 1; //--> Configure pin for input for joystick
    ANSELAbits.ANSA1 = 1; // Analog
    
    TRISBbits.TRISB14 = 1; //--> Configure pin for input for potentiometer
    ANSELBbits.ANSB14 = 1; // Analog
    
    TRISBbits.TRISB13 = 1; //--> Configure pin for input for potentiometer button
    ANSELBbits.ANSB13 = 0; // Digital
    
    TRISBbits.TRISB8 = 1; //--> Configure pin for input for Recharge mode button
    
    TRISAbits.TRISA0 = 1; //--> Configure pin for input for joystick
    ANSELAbits.ANSA0 = 1; // Analog
    
    TRISAbits.TRISA1 = 1; //--> Configure pin for input for joystick
    ANSELAbits.ANSA1 = 1; // Analog
    
    TRISAbits.TRISA4 = 1; //--> Configure pin for input for anchor button
    TRISBbits.TRISB5 = 1; //--> Configure pin for input for dump button
    
    TRISBbits.TRISB3 = 0; //--> Configure pin for output for battery indicator servo
    
    TRISBbits.TRISB12 = 0; //--> Configure pin for output for pairing mode indicator // RED LED
    TRISBbits.TRISB4 = 0; //--> Configure pin for output for drive mode indicator // GREEN LED
    TRISAbits.TRISA2 = 0; //--> Configure pin for output for recharge mode indicator // YELLOW LED
    ANSELBbits.ANSB12 = 0;
    LATBbits.LATB12 = 0;
    LATBbits.LATB4 = 0;
    LATAbits.LATA2 = 1;
    
    TRISBbits.TRISB10 = 1; //--> Configure pin for input for barcode scanner

    
    PWMSetup_BasicConfig(1);
    PWMSetup_AssignChannelToTimer(1, _Timer2_ );
    PWMSetup_SetPeriodOnTimer(50000, _Timer2_);
    PWMSetup_MapChannelToOutputPin(1, PWM_RPB3);
    PWMOperate_SetPulseWidthOnChannel(5000, 1);
    
    //Find the Address of the Boat that you want to send to
    // TxAddress.Whole = ADDRESSES[GET BOAT ID];
    
    //First Byte, since there is nothing set to false
    DelimiterFound = false;
    
    // avoid any issues in the ISR regarding buffer size
    
    RxBufferSize = MAX_RX_BUF_SIZE;
    
    // Hard code address
    TxAddress.Whole16 = (0x20 << 8) | 0x82;    
    /* Set up UART2 Module */
    // Disable UART2
    U2MODEbits.ON = 0;
    
    // Configure the UXMODE register to clear the SIDL, IREN, RTSMD, 
    // UEN, WAKE, LPBACK, ABAUD, RXINV
    U2MODEbits.SIDL = 0;
    U2MODEbits.IREN = 0;
    U2MODEbits.RTSMD = 1;
    U2MODEbits.WAKE = 0;
    U2MODEbits.LPBACK = 0;
    U2MODEbits.ABAUD = 0;
    U2MODEbits.UEN = 0b00;
    U2MODEbits.RXINV = 0;
    
    // Configure the UXMODE register to choose high speed or low speed baud clock
    U2MODEbits.BRGH = 0;
    
    // Configure the UXMODE register to choose the number of data bits, stop bits, and parity
    // 8 bit data, no parity
    U2MODEbits.PDSEL = 0b00;
    // one stop bit
    U2MODEbits.STSEL = 0;
    
    // Configure the UXSTA register to clear the UXINTV, UTXBRK and ADDEN bits
    U2STAbits.UTXINV = 0;
    U2STAbits.UTXBRK = 0;
    U2STAbits.ADDEN = 0;
    U2STAbits.ADM_EN = 0;
    
    U2STAbits.URXISEL = 0b00;
    U2STAbits.UTXISEL = 0b00;
    

    // Enable the receiver
    U2STAbits.URXEN = 1;
    // Enable the transmitter
    U2STAbits.UTXEN = 1;
    
    // Baud Rate of 9600
    U2BRG = 129;
    
    U2TXREG;
    U2RXREG;
    
    IFS1CLR = _IFS1_U2RXIF_MASK;
    IFS1CLR = _IFS1_U2TXIF_MASK;
    IEC1bits.U2RXIE = 1;  // Enable UART2 RX interrupt
    IEC1bits.U2TXIE = 1;
    IPC9bits.U2IP = 7;    // Set priority
    
    U2MODEbits.ON = 1;
    
    // Enable input capture and global interrupts;
    __builtin_enable_interrupts();    
    CurrentState = InitPState;
    ThisEvent.EventType = ES_INIT;

    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/****************************************************************************
 Function
     PostSPECXBeeService

 Parameters
     EF_Event_t ThisEvent ,the event to post to the queue

 Returns
     bool false if the Enqueue operation failed, true otherwise

 Description
     Posts an event to this state machine's queue
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostSPECXBeeService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunSPECXBeeService

 Parameters
   ES_Event_t : the event to process

 Returns
   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise

 Description
   add your description here
 Notes

 Author
   J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunSPECXBeeService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
    
    switch (CurrentState)
    {
        case InitPState: // Unpaired
        {
            if (ThisEvent.EventType == ES_INIT) {
                DB_printf("IN INIT STATE \n");
                LATBbits.LATB4 = 0;
                LATBbits.LATB12 = 1;
                LATAbits.LATA2 = 0;
                // Start the timer here once when pairing begins
                ES_Timer_InitTimer(POT_TIMER, 50);
                
            }
            else if (ThisEvent.EventType == ES_TIMEOUT) {
                // Read the potentiometer value and then print to Tera Term for debugging
                potValue = readADC();
                adjPotValue = (potValue * 100.0 / 1023);
                ES_Timer_InitTimer(POT_TIMER, 50);
                DB_printf("READING POT VALUE, %d \n", adjPotValue);
            }
            else if (ThisEvent.EventType == ES_POT_BUTTON) {
                // math to find which boat to pair with :)
                if (adjPotValue < 17) {
                    TxAddress.Whole16 = (0x20 << 8) | 0x81;   
                }
                else if (adjPotValue < 34) {
                    TxAddress.Whole16 = (0x20 << 8) | 0x82;   
                }
                else if (adjPotValue < 51) {
                    TxAddress.Whole16 = (0x20 << 8) | 0x83;   
                }
                else if (adjPotValue < 68) {
                    TxAddress.Whole16 = (0x20 << 8) | 0x84;   
                }
                else if (adjPotValue < 85) {
                    TxAddress.Whole16 = (0x20 << 8) | 0x85;   
                }
                else {
                    TxAddress.Whole16 = (0x20 << 8) | 0x86;   
                }
                DB_printf("NO LONGER READING POT VALUE, address 0x%x\n", TxAddress.Whole16);
                CurrentState = Pairing;
                ES_Timer_InitTimer(MESSAGE_TIMER, 200);
            }
        }
        break;
         
        case Pairing:
        {
            DB_printf("STATE: PAIRING\n");
            if (ThisEvent.EventType == ES_TIMEOUT) {
                // if the Message Timer timed out, then check if it is paired with the right barnacoal
                STATUS = 2;
                ConstructTx(STATUS);

                idx_TX = 0;
                IFS1SET = _IFS1_U2TXIF_MASK;
                IEC1SET = _IEC1_U2TXIE_MASK;

                // DB_printf("Sent API frame to boat at address 0x%x\n", TxAddress.Whole16);

                ES_Timer_InitTimer(MESSAGE_TIMER, 200);
            }
            
            else if (ThisEvent.EventType == ES_RX_SUCCESS) {
                // Receive buffer but not the first three bytes, so its  8-3
                if (RX_BUF[5] == 0xFF) {
                    DB_printf("Pairing Success!\n");
                    CurrentState = Paired;
                    LATAbits.LATA2 = 0;
                    LATBbits.LATB4 = 1;
                    
                    // Servo shit yurrrrrr motor go burrrrrrrr
                }
                
            }
        }
        break;
        
        case Paired:
        {
            DB_printf("STATE: PAIRED\n");
            LATBbits.LATB4 = 1;
            LATBbits.LATB12 = 0;
            LATAbits.LATA2 = 0;
//            DB_printf("This is the amount of recharge left %u\n", Charge);
            STATUS = 0;
            if (ThisEvent.EventType == ES_TIMEOUT) {
                if (ThisEvent.EventParam == MESSAGE_TIMER) {
                    // if the Message Timer timed out, then check if it is paired with the right barnacoal
                    if (Charge > 0) {
                        JoystickX = GetJoystickXValue();
                        JoystickY = GetJoystickYValue();
                        uint32_t AdjJoystickX = (uint32_t)((JoystickX * 255.0) / 1023.0 + 0.5);
                        uint32_t AdjJoystickY = (uint32_t)((JoystickY * 255.0) / 1023.0 + 0.5);
                        TURN = 255 - AdjJoystickX;
                        FORWARD = AdjJoystickY;
                        DB_printf("This is TURN %u and FORWARD %u\n", TURN, FORWARD);
//                        // ADDING A DEAD BAND ON THE SPECTACOAL
                        if ((AdjJoystickX >= 117.0) && (AdjJoystickX <= 137.0)) {
                            TURN = 127;
                        }
                        
                        if ((AdjJoystickY >= 117.0) && (AdjJoystickY <= 137.0)) {
                            FORWARD = 127;
                        }   
                    }
                    else {
                        TURN = 127;
                        FORWARD = 127;
                    }

                    ConstructTx(STATUS);
                    
                    if (IsAnchor == true || IsDump == true) {
                        Buttons = 0;
                        IsAnchor = false;
                        IsDump = false;
                    }
                    
                    idx_TX = 0;
                    IFS1SET = _IFS1_U2TXIF_MASK;
                    IEC1SET = _IEC1_U2TXIE_MASK;

                    // DB_printf("Sent API frame to boat at address 0x%x\n", TxAddress.Whole16);
                    ES_Timer_InitTimer(MESSAGE_TIMER, 200);
                }
                else if (ThisEvent.EventParam == TIMEOUT_TIMER) {
                    CurrentState = InitPState;
                    LATBbits.LATB4 = 0;
                    LATBbits.LATB12 = 1;
                    LATAbits.LATA2 = 0;
                    PWMOperate_SetPulseWidthOnChannel(5000, 1);
                }
                
                else if (ThisEvent.EventParam == BLINK_TIMER) {
                    uint8_t RedLED = PORTAbits.RA2;
                    LATAbits.LATA2 = !RedLED;
                    DB_printf("THIS SHOULD BE BLINKING\n");
                }
            }

            else if (ThisEvent.EventType == ES_RECHARGE) {
                DB_printf("This is Recharge mode\n");
                CurrentState = Recharge;
                
                // Construct recharge message or change state
            }
            
            else if (ThisEvent.EventType == ES_ANCHOR) {
                DB_printf("Anchor is being deployed\n");
                // check if the anchor is deployed first
                // bit for anchor is bit 1
                Buttons ^= (1 << 1); 
                // toggle state of isAnchor
                IsAnchor = !IsAnchor;     
                
            }
            
            else if (ThisEvent.EventType == ES_DUMP) {
                DB_printf("Dumping Coal\n");
                // check if the dump mechanism is deployed first
                // bit for dump mechanism is bit 0
                Buttons ^= (1 << 0);
                IsDump = !IsDump;
            }
            
            else if (ThisEvent.EventType == ES_RX_SUCCESS) {
                // byte 9 from BARNACOAL is the charge value
                Charge = RX_BUF[5];
                DB_printf("This is the amount of charge left %u\n", Charge);
                // Adjust the value for the LEDs to indicate charge
                // Four Second Timer for Timeout
                
                if (Charge == 0) {
                    LATAbits.LATA2 = 1;
                    ES_Timer_InitTimer(BLINK_TIMER, 2500);
                }
                PWMOperate_SetPulseWidthOnChannel(5000 - (Charge * 50 / 3) , 1);
                
                ES_Timer_InitTimer(TIMEOUT_TIMER, 4000);
            }

        }
        break;
        
        case Recharge:
        {
            
            STATUS = 1;
            LATBbits.LATB4 = 0;
            LATBbits.LATB12 = 0;
            LATAbits.LATA2 = 1;
            if (ThisEvent.EventType == ES_TIMEOUT) {
                if (ThisEvent.EventParam == MESSAGE_TIMER) {
                    // if the Message Timer timed out, then check if it is paired with the right barnacoal
                    ConstructTx(STATUS);

                    idx_TX = 0;
                    IFS1SET = _IFS1_U2TXIF_MASK;
                    IEC1SET = _IEC1_U2TXIE_MASK;

                    // DB_printf("Sent API frame to boat at address 0x%x\n", TxAddress.Whole16);

                    ES_Timer_InitTimer(MESSAGE_TIMER, 200);
                }
            }
            
            else if (ThisEvent.EventType == ES_DRIVE) {
                DB_printf("Exiting Recharge Mode\n");
                CurrentState = Paired;
                ES_Timer_InitTimer(MESSAGE_TIMER, 200);
            }
            
            else if (ThisEvent.EventType == ES_RX_SUCCESS) {
                // byte 9 from BARNACOAL is the charge value
                Charge = RX_BUF[5];
                DB_printf("STATE: RECHARGE %u \n", Charge);
                
                // PWMOperate_SetDutyOnChannel((5 + (Charge / 20)) , 1);
                PWMOperate_SetPulseWidthOnChannel(5000 - (Charge * 50 / 3) , 1);
            }

        }
        break;
    }
 
    return ReturnEvent;
}
/****************************************************************************
 Function
     QuerySPECXBeeService

 Parameters
     None

 Returns
     TemplateState_t The current state of the Template state machine

 Description
     returns the current state of the Template state machine
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:21
****************************************************************************/
TemplateState_t QuerySPECXBeeService(void)
{
  return CurrentState;
}


/***************************************************************************
 private functions
 ***************************************************************************/
bool ConstructTx (uint8_t status) {
    __builtin_disable_interrupts();
    bool returnVal = true;
    
    TX_BUF[0] = 0x7E; // Start Delimiter
    TX_BUF[1] = 0x00; // Length MSB
    TX_BUF[2] = 0x09; // Length LSB
    TX_BUF[3] = 0x01; // API identifier
    TX_BUF[4] = FrameID;
    TX_BUF[5] = TxAddress.Byte[1]; // Address MSB
    TX_BUF[6] = TxAddress.Byte[0]; // Address LSB
    TX_BUF[7] = 0x01; // Disable ACK
    TX_BUF[8] = status;
    
    // handle pairing state
    if (status == 0x02) {
        TX_BUF[9] = 0x00;
        TX_BUF[10] = 0x00;
        TX_BUF[11] = 0x00;
    }
    
    // handle driving state
    else if (status == 0x00) {
        TX_BUF[9] = FORWARD;
        TX_BUF[10] = TURN;
        TX_BUF[11] = Buttons; // This is for the button pressing, need to do logical operations
    }

    // handle Recharge state
    else if (status == 0x01) {
        TX_BUF[9] = 0x00;
        TX_BUF[10] = 0x00;
        TX_BUF[11] = 0x00;
    }
    else {
        // mishandling of data
        returnVal = false;
    }
    TxByteSum = 0;
    
    // add all the values together for checksum math
    for (int idx = 3; idx < TxBufferSize - 1; idx++) {
        TxByteSum += TX_BUF[idx];
    }
    TX_BUF[TxBufferSize - 1] = 0xFF - TxByteSum;

    __builtin_enable_interrupts();
    
    
    return returnVal;
}

void __ISR(_UART_2_VECTOR,IPL7SOFT)UART2_ISR(void) {
    __builtin_disable_interrupts();
    // Handle the Rx Buffer first ! 
    if (IFS1bits.U2RXIF) {
        uint8_t Received = U2RXREG;
        IFS1CLR = _IFS1_U2RXIF_MASK;
        if (!DelimiterFound && Received == 0x7E) {
            DelimiterFound = true;
            idx_RX = 0;
            RxByteSum = 0;
        }
        if (DelimiterFound) {
            if (idx_RX == 0) {
                // This is the start delimiter, just need to make sure it is 0x7E
            } 
            else if (idx_RX == 1) {
                RxMessage.Byte[1] = Received;
            }
            else if (idx_RX == 2) {
                RxMessage.Byte[0] = Received;
                        
                // Make sure that the length of the message is 5 bytes
                if (RxMessage.Whole16 == 0 || RxMessage.Whole16 > MAX_RX_BUF_SIZE) {
                    DelimiterFound = false;
                    idx_RX = 0;
                    RxByteSum = 0;
                }
                else {
                    RxBufferSize = RxMessage.Whole16;
                }
            }
           
            // This is the message now, so add to the Rx Byte Sum for checksum
            else if (idx_RX < (RxBufferSize + 3)) {
                RX_BUF[idx_RX - 3] = Received;
                RxByteSum += Received;
            }
            else {
                uint8_t ChecksumVal = RxByteSum + Received;
                if (ChecksumVal == 0xFF) {
                    ES_Event_t RX_EVENT;
                    RX_EVENT.EventType = ES_RX_SUCCESS;
                    RX_EVENT.EventParam = RX_BUF[0];
                    PostSPECXBeeService(RX_EVENT); 
                }
                DelimiterFound = false;
                idx_RX = 0;
                RxByteSum = 0;
            }
            idx_RX ++;
        }
    } 
    // handle the Tx buffer now
    else if (IFS1bits.U2TXIF && IEC1bits.U2TXIE) {
        U2TXREG = TX_BUF[idx_TX];  // Send next byte
            // Done sending
        idx_TX ++;
        IFS1CLR = _IFS1_U2TXIF_MASK;       // Clear TX interrupt flag
        if (TxBufferSize == idx_TX) {
            IEC1CLR = _IEC1_U2TXIE_MASK;
        }
    }   
    __builtin_enable_interrupts();
}
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/

SoftWare Components –  DRIVE Service Header File
#ifndef DriveService2_H
#define DriveService2_H

#include <stdint.h>
#include <stdbool.h>

#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
// Public Function Prototypes

typedef enum {
    WaitingForCommand,
    AligningWithBeacon,
    MovingToNode,
    MovingForwardTimed,
    TurningLeft,
    TurningRight,
    TurningFull,
    LookingForBlock,
    DroppingBlock,
    TurningLeftBeacon,
    TimedReverse
} DriveServiceState_t;

bool InitDriveService2(uint8_t Priority);
bool PostDriveService2(ES_Event_t ThisEvent);
ES_Event_t RunDriveService2(ES_Event_t ThisEvent);

#endif /* ServTemplate_H */
SoftWare Components –  SPECTACOAL EVENT Checker Pseudocode
bool Check4PairButton (void) {
	// Rising Edge Detection
	if the button is being pressed and it was not previously being pressed {
		Post an event to indicate that the SPECTACOAL should pair with BARNACOAL;
		PreviousState = CurrentState;
		return true;
	}
	PreviousState = CurrentState;
	return false;
}

bool Check4RechargeButton (void)  {

	if the Recharge button is being pressed and a rising edge is detected {
		// Reading the difference between tape and not tape
        	if the IR sensor is reading a change in signal in the barcode {
            	Post an event to indicate that the recharge requirement is being met;
            	RechargePosted = true;
                }
   	} else if the falling edge is detected {
    		Post an event to return the BARNACOAL back to drive mode;
        	Reset the onesCount, zerosCount, and readCount;
        	RechargePosted = false;
	}
PreviousButtonState = CurrentButtonState;
return false;
}

bool Check4AnchorButton (void) {
	If the button is being pressed and it was not previously being pressed {
		if it has not been milliseconds after the previous rising edge {
			LastStableState = CurrentState;
			Post an event to indicate the anchor should be deployed;
			PreviousState = CurrentState;
			return true;
		}
	}
	PreviousState = CurrentState;
	return false;
}

bool Check4DumpButton (void) {
	// Implement Debouncer
	uint32_t Now = ES_Get_Time();

	If the button is being pressed and it was not previously being pressed {
		if it has not been milliseconds after the previous rising edge {
			LastStableState = CurrentState;
			Post an event to indicate the dump mechanism should be deployed;
			PreviousState = CurrentState;
			return true;
		}
	}
	PreviousState = CurrentState;
	return false;
}
SoftWare Components – SPECTACOAL Event Checker Source Code
/****************************************************************************
 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 gets us the prototype for ES_PostAll
#include "ES_Framework.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 "dbprintf.h"
#include "ES_Timers.h" 

// This is the event checking function sample. It is not intended to be
// included in the module. It is only here as a sample to guide you in writing
// your own event checkers
#if 0
/****************************************************************************
 Function
   Check4Lock
 Parameters
   None
 Returns
   bool: true if a new event was detected
 Description
   Sample event checker grabbed from the simple lock state machine example
 Notes
   will not compile, sample only
 Author
   J. Edward Carryer, 08/06/13, 13:48
****************************************************************************/
bool Check4Lock(void)
{
  static uint8_t  LastPinState = 0;
  uint8_t         CurrentPinState;
  bool            ReturnVal = false;

  CurrentPinState = LOCK_PIN;
  // check for pin high AND different from last time
  // do the check for difference first so that you don't bother with a test
  // of a port/variable that is not going to matter, since it hasn't changed
  if ((CurrentPinState != LastPinState) &&
      (CurrentPinState == LOCK_PIN_HI)) // event detected, so post detected event
  {
    ES_Event ThisEvent;
    ThisEvent.EventType   = ES_LOCK;
    ThisEvent.EventParam  = 1;
    // this could be any of the service post functions, ES_PostListx or
    // ES_PostAll functions
    ES_PostAll(ThisEvent);
    ReturnVal = true;
  }
  LastPinState = CurrentPinState; // update the state for next time

  return ReturnVal;
}

#endif

/****************************************************************************
 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_t ThisEvent;
    ThisEvent.EventType   = ES_NEW_KEY;
    ThisEvent.EventParam  = GetNewKey();
    ES_PostAll(ThisEvent);
    return true;
  }
  return false;
}


bool Check4PairButton(void)
{
    static uint8_t PreviousState = 0;
    uint8_t CurrentState = PORTBbits.RB13;
    if ((CurrentState == 1) && (CurrentState != PreviousState)) {
        // DB_printf("Button is being pressed\n");
        // Rising edge detected
        ES_Event_t NewEvent;
        NewEvent.EventType = ES_POT_BUTTON;
        ES_PostAll(NewEvent);
        PreviousState = CurrentState; // Always update PreviousState
        return true;
    }
    
    PreviousState = CurrentState; // Always update PreviousState
    return false;
}

static uint8_t onesCount = 0;
static uint8_t zerosCount = 0;
static uint8_t readCount = 0;

bool Check4RechargeButton(void)
{
    static uint8_t PreviousButtonState = 0;
    uint8_t CurrentButtonState = PORTBbits.RB8;
    static bool RechargePosted = false;
    uint8_t BarcodeState = PORTBbits.RB10;
    
    if (CurrentButtonState == 1) {
        if (BarcodeState == 1) {
            onesCount++;
        } else {
            zerosCount++;
        }
        if (!RechargePosted && (onesCount > 30) && (onesCount <= (zerosCount + 4))) {
            DB_printf("Recharging Action\n");
            ES_Event_t NewEvent;
            NewEvent.EventType = ES_RECHARGE;
            ES_PostAll(NewEvent);
            RechargePosted = true;
        }
    }
    // Right now the issue is that even if you're holding down the button,
    // if you started the barcode scan successfully, even if you don't continue the scan it continues to recharge
    else if (CurrentButtonState == 0 && PreviousButtonState == 1) {
        ES_Event_t NewEvent;
        NewEvent.EventType = ES_DRIVE;
        ES_PostAll(NewEvent);

        onesCount = 0;
        zerosCount = 0;
        readCount = 0;
        RechargePosted = false;
    }
    
    PreviousButtonState = CurrentButtonState; // Always update PreviousState
    return false;
}

bool Check4AnchorButton(void)
{
    uint8_t CurrentState = PORTAbits.RA4;
    // Implement Debouncer
    static uint8_t LastStableState = 0;
    static uint8_t LastReadState = 0;
    static uint32_t LastDebounceTime = 0;
    uint32_t Now = ES_Timer_GetTime();
    
    if (CurrentState != LastReadState) {
        LastDebounceTime = Now;
        LastReadState = CurrentState;
    }
    if ((Now - LastDebounceTime) > 50) {
        if (LastStableState != CurrentState) {
            LastStableState = CurrentState;
            // Rising edge
            if (CurrentState == 1) {
                ES_Event_t NewEvent;
                NewEvent.EventType = ES_ANCHOR;
                ES_PostAll(NewEvent);
                return true;
            }
        }
    }
    return false;
}

bool Check4DumpButton(void)
{
    uint8_t CurrentState = PORTBbits.RB5;
    // Implement Debouncer
    static uint8_t LastStableState = 0;
    static uint8_t LastReadState = 0;
    static uint32_t LastDebounceTime = 0;
    uint32_t Now = ES_Timer_GetTime();
    
    if (CurrentState != LastReadState) {
        LastDebounceTime = Now;
        LastReadState = CurrentState;
    }
    
    if ((Now - LastDebounceTime) > 50) {
        if (LastStableState != CurrentState) {
            LastStableState = CurrentState;
        // Rising edge
            if (CurrentState == 1) {
                ES_Event_t NewEvent;
                NewEvent.EventType = ES_DUMP;
                ES_PostAll(NewEvent);
                return true;
            }
        }
    }
    return false;
}
SoftWare Components – Follower SPI Service Header file
#ifndef FollowerSPIService_H
#define FollowerSPIService_H

#include <stdint.h>
#include <stdbool.h>

#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
// Public Function Prototypes

typedef enum
{
    WaitingCommand,
    CompletingAction,
    WaitingBeaconAlign,
} FollowerSPIState_t;


bool InitFollowerSPIService(uint8_t Priority);
bool PostFollowerSPIService(ES_Event_t ThisEvent);
ES_Event_t RunFollowerSPIService(ES_Event_t ThisEvent);

#endif /* ServTemplate_H */
SoftWare Components – SPECTACOAL AD SERVICE PseudoCode
Based on the pins mapped to be inputs for the analog settings:

Read one input pin value for the horizontal-axis joystick -- adcResults[0]
Read one input pin value for the vertical-axis joystick -- adcResults[1]
Read one input pin value for the potentiometer -- adcResults[2]


Create a helper function for reading JoystickX

Create a helper function for reading JoystickY

Create a helper function for reading Potentiometer
SoftWare Components – SPECTACOAL AD SERVICE Source Code
/****************************************************************************
 Module
   AD_PotService.c

 Revision
   1.0.1

 Description
 * Create a simple service (ADService) to handle the reading of the A/D and 
 * updating of the interval between steps. The initializer for this service 
 * would init the A/D system and start a timer (ADTimer) running to trigger 
 * speed updates. The speed updates don?t need to happen all that often. I?d 
 * suggest 50Hz (20ms interval) would be plenty fast enough. Before leaving 
 * the init function, start the timer associated with the other state machine 
 * (StepTimer, below). When the ADTimer expires, you would read the A/D and 
 * do the scaling to create the time interval to wait between steps. This A/D
 *  service ought to be implemented inside its own module, so you?ll also need
 *  an ?access function? to query the value of the scaled interval.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 01/16/12 09:58 jec      began conversion from TemplateFSM.c
****************************************************************************/
/*----------------------------- 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 "ADPotService.h"
#include "PIC32_AD_Lib.h"

/*----------------------------- Module Defines ----------------------------*/

/*---------------------------- 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;
uint32_t PotValue = 100;
uint32_t JoystickXValue = 0;  // AN0
uint32_t JoystickYValue = 0;  // AN1
uint32_t adcResults[3];



/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitTemplateService

 Parameters
     uint8_t : the priorty of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, and does any
     other required initialization for this service
 Notes

 Author
     J. Edward Carryer, 01/16/12, 10:00
****************************************************************************/
bool InitADService(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;
 
    ThisEvent.EventType = ES_INIT;
  
    ANSELBbits.ANSB14 = 1;
    TRISBbits.TRISB14 = 1;
    
    ANSELAbits.ANSA0 = 1;
    TRISAbits.TRISA0 = 1;
    
    ANSELAbits.ANSA1 = 1;
    TRISAbits.TRISA1 = 1;
    
    ES_Timer_InitTimer(AD_TIMER, 20);
    // From PIC32 Datasheet, want to set the pin to be reading ADC here
    ADC_ConfigAutoScan(BIT10HI | BIT0HI | BIT1HI);

    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/****************************************************************************
 Function
     PostTemplateService

 Parameters
     EF_Event_t ThisEvent ,the event to post to the queue

 Returns
     bool false if the Enqueue operation failed, true otherwise

 Description
     Posts an event to this state machine's queue
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostADService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunTemplateService

 Parameters
   ES_Event_t : the event to process

 Returns
   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise

 Description
   add your description here
 Notes

 Author
   J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunADService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
  
    switch (ThisEvent.EventType) {
        case ES_TIMEOUT:
            ADC_MultiRead(adcResults);
            
            JoystickXValue = adcResults[0];  // AN0 (RA0)
            JoystickYValue = adcResults[1];  // AN1 (RA1)
            PotValue = adcResults[2];
            ES_Timer_InitTimer(AD_TIMER, 20);
            break;
            
        default:
            break;
    }
    return ReturnEvent;
}

uint32_t readADC () {
    return PotValue;
}

uint32_t GetJoystickXValue(void) {
    return JoystickXValue;
}

uint32_t GetJoystickYValue(void) {
    return JoystickYValue;
}

/*------------------------------ End of file ------------------------------*/

SoftWare Components – BARNACOAL XBEE PseudoCode
bool InitBARNXBeeService(uint8_t Priority)
{
    ES_Event_t ThisEvent;
    MyPriority = Priority;
	Configure Input and Output pins;
    Set up UART2 module with receive and transmit interrupts;
    
    ThisEvent.EventType = ES_INIT;
    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

ES_Event_t RunBARNXBeeService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

    switch(ThisEvent.EventType){
        case ES_INIT:
            
        case ES_TIMEOUT:
            if (MESSAGE_TIMER times out) {
                // Everytime the message timer times out, send a message (every 200 ms)
                Construct a message according to API framework;
                Trigger the interrupts;
            }
            
            else if (TIMEOUT_TIMER times out) {
                // if the 4 second timer runs out, there has not been a message for 4 seconds
               	Reset to unpaired state;
            }

            break;

        case MSG_RECV:
          {
            // Always start the 4 second time just in case
            if (RX_BUF[0] == 0x81) {
            	// this means that message received is formatted properly
                
                if (Status Byte is 2 (Pairing)) {
                    // Send 255 as a pairing confirmation
                    Store the Address of the received SPECTACOAL to send messages to;
                    
                    Construct a message with 0xFF (255) as the data to send;
                    Trigger the interrupt to send the message with the constructed data package

                }
                if (Status Byte is 1 (Recharging)) {
                    if (The Address is the initial address that was initially paired with) {
                        Send a package with charge status;
                        Post the Recharge Event;
                    }
                }
                if (Status Byte is 0 (Driving)) {
                    if (The Address is the initial address that was initially paired with) {
                        // drive the motors
                        Store the Joystick values;
                        Store the button values into a single byte to decode

                        Post the Driving Event
                        
                        if (The buttons have changed since the last message ) {
                    // if Buttons is 0, no anchor and no dump mechanism
                    // if Buttons is 1, deploy anchor
                    // if Buttons is 2, open dump mechanism
                    // if Buttons is 3, open dump mechanism and deploy anchor
                            Post a Button Change Event;
                        }
                    }
                }
            }
        }
          break;



        case TX_REQUESTED:
        // the barnacoal wants to send data to the spectacoal. 
        // check what kind of data it wants to send, then package it and send it over
        {
            Construct a Data Package using a helper function;
            Send the message via interrupts;
        }
        break;
        
        default:
        break;
    }
    return ReturnEvent;
}

/***************************************************************************
 private functions
 ***************************************************************************/

/////// RX and TX INTERRUPT ///////
void __ISR(_UART_2_VECTOR, IPL7SOFT) BarnISR(void)
{
    __builtin_disable_interrupts();
    
    // if we've received data, and are processing received data:
    void __ISR(_UART_2_VECTOR,IPL7SOFT)UART2_ISR(void) {
    __builtin_disable_interrupts();
    // Handle the Rx Buffer first ! 
    if (If the Receive Interrupt Flag is set) {
        Write the Receive register into received;
       
        Post a new event with the receive messages;
        Clear the Receive Interrupt Flag;
        
        // Do more with understanding if the bytes are correct
        // Check the start delimiter and all the bytes to follow
        // Index through the receive buffer and make sure the data is valid
        
    } 
    // handle the Tx buffer now
    else if (If Transmit Interrupts are enabled and the transmit interrupt flag is set) {
        // do some fancy stuff with the interrupt handling to make sure the
        // data is transmitted over nicely
        
        // Make sure not to clear the transmit interrupt enable mask until
        // the entire message is transmitted over
        Clear Transmit Interrupt Flag;
    }
    __builtin_enable_interrupts();
}

bool ConstructTx (uint8_t DataToSend) {
    bool returnVal = true;
    
    First Byte is Start Delimiter;
    Second and third Bytes are Length of Message;
    Fourth Byte is the API Identifier;
    Fifth Byte is Frame ID;
    Sixth and Seventh Bytes are Address of Device to receive message;
    Eighth Byte is set to 0x01;
    Ninth Byte is Data;
    Initialize Byte for CheckSum;
    
    Calculate the value of the Checksum so that the data values sum to 0xFF;
    
    return returnVal;
}
SoftWare Components – BARNACOAL XBEE Source Code
/****************************************************************************
 Module
   BARNXBeeService.c

 Revision
   1.0.1

 Description
   This is a template file for implementing a simple service under the
   Gen2 Events and Services Framework.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 01/16/12 09:58 jec      began conversion from TemplateFSM.c
****************************************************************************/
/*----------------------------- 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 "TemplateService.h"
#include "BARNXBeeService.h"
#include "DriveService.h"
#include "BarnacoalFSM.h"

#include <sys/attribs.h>
#include "dbprintf.h"
#include <xc.h>

/*----------------------------- Module Defines ----------------------------*/
#define MAX_MESSAGE_SIZE 4
#define MAX_TX_BUF_SIZE MAX_MESSAGE_SIZE + 5
#define MAX_RX_BUF_SIZE MAX_MESSAGE_SIZE + 9

/*---------------------------- 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;


// Setup for UART transmission between XBees
    // buffers for Tx and Rx data
    static uint8_t TX_BUF[13];
    volatile static uint8_t RX_BUF[9];
    volatile static uint8_t RxData;

    // Tx and Rx ISR index counters to make sure the bytes being sent/received are correct
    volatile static uint8_t idx_TX;
    volatile static uint8_t idx_RX;

    // Size that a current Tx / Rx will be
    static uint8_t TxBufferSize = 10;
    static uint8_t RxBufferSize = 13;

    // Checksums sum of bytes in a Tx Message
    static uint8_t TxByteSum;
    volatile static uint8_t RxByteSum;

    // Frame ID
    static uint8_t FrameID;

    // Boolean to track transmission of start delimiter
    volatile static bool DelimiterFound = false;
    
    // Union for access of bytes within the addresses
    typedef union {
        uint16_t Whole16;
        uint8_t Byte[2];
    }TwoBytes_t;
    
    typedef union {
        struct {
        uint8_t Left;
        uint8_t Right;
        };
        uint16_t Whole16;
    } JoystickVals;
    
    static TwoBytes_t TxAddress;
    static TwoBytes_t RxAddress;
    static TwoBytes_t RxMessage;
    uint8_t PreviousButtons = 0;
    uint8_t Buttons = 0;
    // Boat Addresses
    static uint16_t BARN_address = 0x2082;
    
    uint8_t DataToSend = 0x00;
    uint8_t Charge = 150;


/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitBARNXBeeService

 Parameters
     uint8_t : the priorty of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, and does any
     other required initialization for this service
 Notes

 Author
     J. Edward Carryer, 01/16/12, 10:00
****************************************************************************/
bool InitBARNXBeeService(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;

    PreviousButtons = 0;
    // post the initial transition event
    TRISBbits.TRISB11 = 1; // --> Configure pin B11/22 for inputs Rx, using UART2 module
    U2RXR = 0b0011; 

    TRISAbits.TRISA3 = 0; //--> Configure pin A3/10 for outputs Tx
    RPA3R = 0b0010;

    DelimiterFound = false;
    RxBufferSize = MAX_RX_BUF_SIZE;

    TRISBbits.TRISB15 = 0;    // initialize pin to drive LED when Rx buffer fills
    ANSELBbits.ANSB15 = 0;    // set B15, pin 26, to digital output
    LATBbits.LATB15 = 0;      // set it LOW

     /* Set up UART2 Module */
    // Disable UART2
    U2MODEbits.ON = 0;

    // Configure the UXMODE register to clear the SIDL, IREN, RTSMD, 
    // UEN, WAKE, LPBACK, ABAUD, RXINV
    U2MODEbits.SIDL = 0;
    U2MODEbits.IREN = 0;
    U2MODEbits.RTSMD = 1;
    U2MODEbits.WAKE = 0;
    U2MODEbits.LPBACK = 0;
    U2MODEbits.ABAUD = 0;
    U2MODEbits.UEN = 0b00;
    U2MODEbits.RXINV = 0;

    // Configure the UXMODE register to choose high speed or low speed baud clock
    U2MODEbits.BRGH = 0;

    // Configure the UXMODE register to choose the number of data bits, stop bits, and parity
    // 8 bit data, no parity
    U2MODEbits.PDSEL = 0b00;
    // one stop bit
    U2MODEbits.STSEL = 0;

    // Configure the UXSTA register to clear the UXINTV, UTXBRK and ADDEN bits
    U2STAbits.UTXINV = 0;
    U2STAbits.UTXBRK = 0;
    U2STAbits.ADDEN = 0;
    U2STAbits.ADM_EN = 0;

    U2STAbits.URXISEL = 0b00;
    U2STAbits.UTXISEL = 0b00;


    // Enable the receiver
    U2STAbits.URXEN = 1;
    // Enable the transmitter
    U2STAbits.UTXEN = 1;

    // Baud Rate of 9600
    U2BRG = 129;

    U2TXREG;
    U2RXREG;

    IFS1CLR = _IFS1_U2RXIF_MASK;
    IFS1CLR = _IFS1_U2TXIF_MASK;
    IEC1bits.U2RXIE = 1;  // Enable UART2 RX interrupt
    IEC1bits.U2TXIE = 0;  
    IPC9bits.U2IP = 7;    // Set priority

    U2MODEbits.ON = 1;

    // Enable input capture and global interrupts;
    __builtin_enable_interrupts(); 

    ThisEvent.EventType = ES_INIT;
    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/****************************************************************************
 Function
     PostBARNXBeeService

 Parameters
     EF_Event_t ThisEvent ,the event to post to the queue

 Returns
     bool false if the Enqueue operation failed, true otherwise

 Description
     Posts an event to this state machine's queue
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostBARNXBeeService(ES_Event_t ThisEvent)
{
  return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunBARNXBeeService

 Parameters
   ES_Event_t : the event to process

 Returns
   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise

 Description
   add your description here
 Notes

 Author
   J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunBARNXBeeService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

    switch(ThisEvent.EventType){
        case ES_INIT:
            LATBbits.LATB15 = 0;
            break;
        case ES_TIMEOUT:
            if (ThisEvent.EventParam == MESSAGE_TIMER) {
                DB_printf("Data To Send %u\n", DataToSend);
                ConstructTx(DataToSend);
                idx_TX = 0;
                IFS1SET = _IFS1_U2TXIF_MASK;
                IEC1SET = _IEC1_U2TXIE_MASK;

            }
            else if (ThisEvent.EventParam == TIMEOUT_TIMER) {
                ES_Event_t NewEvent;
                NewEvent.EventType = ES_ENDOFTIME;
                PostBarnacoalFSM(NewEvent);
            }

            break;

        case MSG_RECV:
          {
            DB_printf("Message Received\n");
            ES_Timer_InitTimer(TIMEOUT_TIMER, 4000);
            if (RX_BUF[0] == 0x81) {


                // Status Byte == 2, this means that it is pairing
                if (RX_BUF[5] == 0x02) {
                    // Send 255 as a pairing confirmation
                    RxAddress.Byte[1] = RX_BUF[1];
                    RxAddress.Byte[0] = RX_BUF[2];
                    TxAddress.Whole16 = RxAddress.Whole16;
                    DB_printf("This is the Receive Address 0x%x\n", TxAddress.Whole16);

                    DataToSend = 0xFF;
                    ConstructTx(DataToSend);
                    idx_TX = 0;
                    IFS1SET = _IFS1_U2TXIF_MASK;
                    IEC1SET = _IEC1_U2TXIE_MASK;

                    ES_Event_t NewEvent;
                    NewEvent.EventType = PAIR_REQUEST;
                    ES_PostAll(NewEvent);

                }
                // Status Byte == 1, this means that it is recharging
                if (RX_BUF[5] == 0x01) {
                    if (RxAddress.Byte[1] == RX_BUF[1] && RxAddress.Byte[0] == RX_BUF[2]) {
                        // send a package with charge status
                        ES_Event_t RechargeEvent;
                        RechargeEvent.EventType = ES_RECHARGE;
                        ES_PostAll(RechargeEvent);
                    }
                }
                if (RX_BUF[5] == 0x00) {
                    if (RxAddress.Byte[1] == RX_BUF[1] && RxAddress.Byte[0] == RX_BUF[2]) {
                        // drive the motors
                        JoystickVals joystick;
                        // Left is vertical / Thrust
                        joystick.Left = RX_BUF[7];
                        // Right is Horizontal / Direction
                        joystick.Right = RX_BUF[6];
                        Buttons = RX_BUF[8];

                        ES_Event_t DriveEvent;
                        DriveEvent.EventType = ES_DRIVE;
                        DriveEvent.EventParam = joystick.Whole16;
                        ES_PostAll(DriveEvent);
                        
                        if (PreviousButtons != Buttons) {
                    // if Buttons is 0, no anchor and no dump mechanism
                    // if Buttons is 1, deploy anchor
                    // if Buttons is 2, open dump mechanism
                    // if Buttons is 3, open dump mechanism and deploy anchor
                            DB_printf("Button is being pressed\n");
                            ES_Event_t ButtonEvent;
                            ButtonEvent.EventType = ES_BUTTONCHANGE;
                            ButtonEvent.EventParam = Buttons;
                            ES_PostAll(ButtonEvent);
                            PreviousButtons = Buttons;
                        }
                    }
                }
            }
        }
          break;



        case TX_REQUESTED:
        // the barnacoal wants to send data to the spectacoal. 
        // check what kind of data it wants to send, then package it and send it over
        {
            DataToSend = ThisEvent.EventParam;
            ConstructTx(DataToSend);
            idx_TX = 0;
            IFS1SET = _IFS1_U2TXIF_MASK;
            IEC1SET = _IEC1_U2TXIE_MASK;          
//            for (int i = 0; i < TxBufferSize; i++) {
//                while (U2STAbits.UTXBF == 1);
//                DB_printf("#%d Tx_Bug %x\n",i,TX_BUF[i]);
//                U2TXREG = TX_BUF[i];
////                ES_Timer_InitTimer(MESSAGE_TIMER, 200);
//            }
        }
        break;
        
        default:
        break;
    }
    return ReturnEvent;
}

/***************************************************************************
 private functions
 ***************************************************************************/

/////// RX and TX INTERRUPT ///////
void __ISR(_UART_2_VECTOR, IPL7SOFT) BarnISR(void)
{
    __builtin_disable_interrupts();
    
    // if we've received data, and are processing received data:
    if (IFS1bits.U2RXIF && IEC1bits.U2RXIE)       // if interrupt flag has been raised
    {
        LATBbits.LATB15 = 1;         // turn on the LED for 0.5s 
        ES_Timer_InitTimer(LED_PULSE, 500);
        
        RxData = U2RXREG;             // read from Rx buffer and put into RxData
        IFS1CLR = _IFS1_U2RXIF_MASK;
        
        if (!DelimiterFound && RxData == 0x7E) {
            DelimiterFound = true;
            idx_RX = 0;
            RxByteSum = 0;
        }
        
        if (DelimiterFound) {
            if (idx_RX == 0) {
                // This is just to check that the first byte is the start delimiter
            }
            else if (idx_RX == 1) {
                RxMessage.Byte[1] = RxData;
            } 
            else if (idx_RX == 2) {
                RxMessage.Byte[0] = RxData;
                if (RxMessage.Whole16 == 0 || RxMessage.Whole16 > MAX_TX_BUF_SIZE) {
                    DelimiterFound = false;
                    idx_RX = 0;
                    RxByteSum = 0;
                } 
                else {
                    RxBufferSize = RxMessage.Whole16;
                }
            }
            
            else if (idx_RX < (RxBufferSize + 3)) {
                RX_BUF[idx_RX - 3] = RxData;
                RxByteSum += RxData;
            }
            else {
                uint8_t CheckSumVal = RxByteSum + RxData;
                if (CheckSumVal == 0xFF) {
                    ES_Event_t DataToRX;
                    DataToRX.EventType = MSG_RECV;
                    DataToRX.EventParam = RX_BUF[0];
                    PostBARNXBeeService(DataToRX);
                    
                }
                DelimiterFound = false;
                idx_RX = 0;
                RxByteSum = 0;
            }
            idx_RX ++;
        }   
    }
    
    else if (IFS1bits.U2TXIF && IEC1bits.U2TXIE) {
        
        if (idx_TX < TxBufferSize) {
            U2TXREG = TX_BUF[idx_TX];
            idx_TX ++;
            IFS1CLR = _IFS1_U2TXIF_MASK;
        }
        else {
            IEC1CLR = _IEC1_U2TXIE_MASK;
            idx_TX = 0;
        }
    }
    __builtin_enable_interrupts();
}

bool ConstructTx (uint8_t DataToSend) {
    __builtin_disable_interrupts();
    bool returnVal = true;
    
    TX_BUF[0] = 0x7E;
    TX_BUF[1] = 0x00;
    TX_BUF[2] = 0x06;
    TX_BUF[3] = 0x01;
    TX_BUF[4] = FrameID;
    TX_BUF[5] = TxAddress.Byte[1]; // Address MSB
    TX_BUF[6] = TxAddress.Byte[0]; // Address LSB
    TX_BUF[7] = 0x01;
    TX_BUF[8] = DataToSend;
    TxByteSum = 0;
    
    for (int idx = 3; idx < TxBufferSize - 1; idx++) {
        TxByteSum += TX_BUF[idx];
    }
    TX_BUF[TxBufferSize - 1] = 0xFF - TxByteSum;
    
    __builtin_enable_interrupts();
    
    return returnVal;
}

/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
SoftWare Components – TOP HSM Header File
/****************************************************************************
 Template header file for Hierarchical Sate Machines AKA StateCharts

 ****************************************************************************/

#ifndef TopHSMTemplate_H
#define TopHSMTemplate_H

// State definitions for use with the query function
typedef enum { INIT_STATE, STATE_ONE, STATE_TWO, STATE_THREE, END_GAME } MasterState_t ;

// Public Function Prototypes

ES_Event_t RunMasterSM( ES_Event_t CurrentEvent );
void StartMasterSM ( ES_Event_t CurrentEvent );
bool PostMasterSM( ES_Event_t ThisEvent );
bool InitMasterSM ( uint8_t Priority );

#endif /*TopHSMTemplate_H */
SoftWare Components – BARNACOAL FSM pseudoCode

bool InitBarnacoalFSM(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;
    
    Configure Input and Output pins;
    Configure Pins for PWM;
    
    // LEFT MOTOR

    // RIGHT MOTOR

    // DUMP MOTOR

    // ANCHOR MOTOR
    
    // TEAM NUMBER ROTATION MOTOR

    // Timer2 setup

    // Timer3 setup

    // OC2 (Left motor)

    // OC3 (Right motor)

    // OC1 setup (dump motor)

    // OC4 setup (anchor motor)

    // OC5 setup (team number rotation motor)

    CurrentState = InitPState;
    // post the initial transition event
    ThisEvent.EventType = ES_INIT;
    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}


ES_Event_t RunBarnacoalFSM(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; 

    switch (CurrentState)
    {
        case InitPState:
        {
            if (Init Event)  
            {
                Reset the Battery Charge Value;
                Initialize the initial servo motor positions
            }
        }
        break;

        case Pairing:        
        {
            switch (ThisEvent.EventType)
            {
                case PAIR_REQUEST:
                // When Paired
                { 
                    CurrentState = Paired;
                    Set the servo motor for pairing to be right side up;
                }
                break;

                default:
                  ;
            }
        }
        break;
    
        case Paired: // we are in the driving state
        {        
            switch (ThisEvent.EventType){
                case ES_TIMEOUT:
                {
                
                }
                break;
                case ES_DRIVE:
                {
                    if (Battery is Dead ) {
                        // make motor not go burrrrr
                        Turn Everything OFF;
                        
                    }
                    else if (the Battery != dead and the joystick is not in neutral state +- dead zone) {
                        if (Battery has Charge) {
                            Decrement the battery value;
                            // Make motor go burrrrr
                            Left Jostick is Thrust/Speed;
                            Right Joystick is Direction/Turning;
                            
                            // Calculations to adjust the motor values depending on how it should turn
                            double LeftDC = ThrustDC + DirectDC;
                            double RightDC = ThrustDC - DirectDC;
                            
                            Make sure the joystick values maximize at 1 or -1;
                            
                            Set direction and absolute value for PWM based on sign of value;
                            
                            Drive the motors;
                            
                    } else if (joystick is in dead zone) {
                        Turn Motors off;
                    }
                    Post an Event to send message to SPECTACOAL with battery level;

                }
                break;
                
                case ES_BUTTONCHANGE: // posted from XBeeService
                {
                    // Anchor and Dump Mechanism activated
                    ButtonVals is "Buttons" on BARNXBeeService;
                    if (BARNACOAL is not dead) {
                        switch(ButtonVals){
                        // if Button is 0, no anchor and no dump mechanism
                        // if Button is 1, deploy coal
                        // if Button is 2, deploy anchor     
                        }
                    }
                    if (there is battery charge) {
                        Deplete the battery;
                    }
                }
                break;
                
                case ES_RECHARGE:
                // Recharge mode
                {
                    if (If the battery is not full) {
                        if (BatteryCharge > 144) {
                            Battery cannot be greater than 150;
                        }
                        else {
                            Increment battery level by 6 every 200ms
                        }
                    }
                    else {
                    	Battery is now full;
                    }
                    
                    DO NOT DRIVE MOTORS;
                    Send a message to the SPECTACOAL that the battery is charging;
                }
                break;
                
                case ES_ENDOFTIME:
                {
                    If the timeout timer runs out, it resets to unpaired state;
                }
                break;
                
                default:
                    break;
            }
        }
        break;
    }                                   // end switch on Current State
    return ReturnEvent;
}
SoftWare Components – BARNACOAL FSM source Code
/****************************************************************************
 Module
   BarnacoalFSM.c

 Revision
   1.0.1

 Description
   This is a file for implementing the BARNACOAL FSM under the
   Gen2 Events and Services Framework.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 01/15/12 11:12 jec      revisions for Gen2 framework
 11/07/11 11:26 jec      made the queue static
 10/30/11 17:59 jec      fixed references to CurrentEvent in RunTemplateSM()
 10/23/11 18:20 jec      began conversion from SMTemplate.c (02/20/07 rev)
****************************************************************************/
/*----------------------------- 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 "BarnacoalFSM.h"
#include "BARNXBeeService.h"
#include "dbprintf.h"

/*----------------------------- Module Defines ----------------------------*/
#define PR_VAL 24999 // this is TIMER2 only!
#define UP 1
#define DOWN 0
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this machine.They should be functions
   relevant to the behavior of this state machine
*/

/*---------------------------- Module Variables ---------------------------*/
// everybody needs a state variable, you may need others as well.
// type of state variable should match htat of enum in header file
static BarnState_t CurrentState;

// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
typedef union {
    struct {
        uint8_t Left;
        uint8_t Right;
    };
    uint16_t Whole16;
} JoystickVals;

static uint8_t LeftJoystick = 127;
static uint8_t RightJoystick = 127;
static double ThrustDC = 0.0;
static double DirectDC = 0.0;
static double LeftDC = 0.0;
static double RightDC = 0.0;

uint8_t BatteryCharge = 150;
uint8_t ButtonVals = 0;

static uint8_t CoalIs = DOWN;
static uint8_t AnchorIs = DOWN;
static uint8_t TeamNumberIs = DOWN;


/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitBarnacoalFSM

 Parameters
     uint8_t : the priorty of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, sets up the initial transition and does any
     other required initialization for this state machine
 Notes

 Author
     J. Edward Carryer, 10/23/11, 18:55
****************************************************************************/
bool InitBarnacoalFSM(uint8_t Priority)
{
    ES_Event_t ThisEvent;

    MyPriority = Priority;
  // put us into the Initial PseudoState
    
  /****************************************************************************
   * motor control initialization
   * ****************************************************************************/
    TRISBbits.TRISB8 = 0;  // Left polarity
    TRISBbits.TRISB10 = 0; // Right polarity

    // Set direction to default (LOW)
    LATBbits.LATB8 = 0;
    LATBbits.LATB10 = 0;

    // Configure PWM output pins
    
    // LEFT MOTOR
    TRISBbits.TRISB5 = 0; // OC2 -> Left motor
    RPB5R = 0b0101;       // Map OC2 to RB5

    // RIGHT MOTOR
    TRISBbits.TRISB9 = 0; // OC3 -> Right motor
    RPB9R = 0b0101;       // Map OC3 to RB9
    
    // DUMP MOTOR
    TRISAbits.TRISA0 = 0; // set A0, pin 2 to output
    ANSELAbits.ANSA0 = 1; // analog
    RPA0R = 0b0101;       // OC1 -> anchor motor
    
    // ANCHOR MOTOR
    TRISBbits.TRISB2 = 0; // set B2, pin 6 to output
    ANSELBbits.ANSB2 = 1; // analog
    RPB2R = 0b0101;       // OC4 -> anchor servo motor
    
    // TEAM NUMBER ROTATION MOTOR
    TRISBbits.TRISB13 = 0; // set B13, pin 24 to output
    ANSELBbits.ANSB13 = 1; // analog
    RPB13R = 0b0110;        // OC5 -> team number servo

    // Timer2 setup
    T2CONbits.ON = 0;
    T2CONbits.TCS = 0;
    T2CONbits.TCKPS = 0b010; // 1:4 prescaler
    T2CONbits.TGATE = 0;
    TMR2 = 0;
    PR2 = PR_VAL;
    T2CONbits.ON = 1;
    
    // Timer3 setup
    T3CONbits.ON = 0;
    T3CONbits.TCS = 0;
    T3CONbits.TCKPS = 0b011; // 1:8 prescaler
    T3CONbits.TGATE = 0;
    TMR3 = 0;
    PR3 = 49999;
    T3CONbits.ON = 1;
    

    // OC2 (Left motor)
    OC2CONbits.ON = 0;
    OC2CONbits.OCM = 0b110;
    OC2CONbits.OCTSEL = 0;
    OC2R = 0;
    OC2RS = 0;
    OC2CONbits.ON = 1;

    // OC3 (Right motor)
    OC3CONbits.ON = 0;
    OC3CONbits.OCM = 0b110;
    OC3CONbits.OCTSEL = 0;
    OC3R = 0;
    OC3RS = 0;
    OC3CONbits.ON = 1;
    clrScrn();
    
    // OC1 setup (dump motor)
    OC1CONbits.ON = 0;
    OC1CONbits.OCM = 0b110;
    OC1CONbits.OCTSEL = 1; // assign OC1 to timer3
    OC1R = 0;
    OC1RS = 3500; // hold position when turned on
    OC1CONbits.ON = 1;
    
    // OC4 setup (anchor motor)
    OC4CONbits.ON = 0;
    OC4CONbits.OCM = 0b110;
    OC4CONbits.OCTSEL = 1; // assign OC4 to timer3
    OC4R = 0;
    OC4RS = 0;
    OC4CONbits.ON = 1;
    
    // OC5 setup (team number rotation motor)
    OC5CONbits.ON = 0;
    OC5CONbits.OCM = 0b110;
    OC5CONbits.OCTSEL = 1; // assign OC5 to timer3
    OC5R = 0;
    OC5RS = 0;
    OC5CONbits.ON = 1;
    

    CurrentState = InitPState;
    // post the initial transition event
    ThisEvent.EventType = ES_INIT;
    if (ES_PostToService(MyPriority, ThisEvent) == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/****************************************************************************
 Function
     PostBarnacoalFSM

 Parameters
     EF_Event_t ThisEvent , the event to post to the queue

 Returns
     boolean False if the Enqueue operation failed, True otherwise

 Description
     Posts an event to this state machine's queue
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostBarnacoalFSM(ES_Event_t ThisEvent)
{
  return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunBarnacoalFSM

 Parameters
   ES_Event_t : the event to process

 Returns
   ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise

 Description
   add your description here
 Notes
   uses nested switch/case to implement the machine.
 Author
   J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunBarnacoalFSM(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent;
    ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

    switch (CurrentState)
    {
        case InitPState:        // If current state is initial Psedudo State
        {
            if (ThisEvent.EventType == ES_INIT)    // only respond to ES_Init
            {
                // nothing much to do here
                // now put the machine into the actual initial state
                BatteryCharge = 150;
                CurrentState = Pairing;
                OC2RS = 0;
                OC5RS = 1400; // keep team number upside down
            }
        }
        break;

        case Pairing:        
        {
            switch (ThisEvent.EventType)
            {
                case PAIR_REQUEST:
                { 
                    CurrentState = Paired;
                    DB_printf("paired");
                    OC5RS = 6000; // right side up!
                }
                break;

                // repeat cases as required for relevant events
                default:
                  ;
            }
        }
        break;
    
        case Paired: // we are in the driving state
        {        
            switch (ThisEvent.EventType){
                case ES_TIMEOUT:
                {
                
                }
                break;
                case ES_DRIVE:
                {
                    JoystickVals joystick;
                    joystick.Whole16 = ThisEvent.EventParam;
                    // DB_printf("This is the JoystickVals %u %u\n", joystick.Left, joystick.Right);
                    if (BatteryCharge == 0) {
                        // no more battery left
                        // make motor not go burrrrr
                        DB_printf("THE MOTOR IS DEAD \n");
                        OC2RS = 0;
                        OC3RS = 0;
                        LATBbits.LATB8 = 0;  // Left polarity
                        LATBbits.LATB10 = 0; // Right polarity
                        
                    }
                    else if ((joystick.Left < 125) || (joystick.Left > 129) || (joystick.Right < 125) || (joystick.Right > 129)) {
                        if (BatteryCharge > 0) {
                            BatteryCharge -= 1;
                            DB_printf("DRIVE MODE: %u\n", BatteryCharge);
                            // Make motor go burrrrr
                            LeftJoystick = joystick.Left;
                            RightJoystick = joystick.Right;
                            DB_printf("This is the Pot Value: %u%% %u%%\n", LeftJoystick, RightJoystick);
                            ThrustDC = (((double)LeftJoystick - 127.0)) / 128.0;
                            DirectDC = ((double)RightJoystick - 127.0) / 128.0; 
                            double LeftDC = ThrustDC + DirectDC;
                            double RightDC = ThrustDC - DirectDC;
                            if (LeftDC > 1) {
                                LeftDC = 1;
                            }
                            if (RightDC > 1) {
                                RightDC = 1;
                            }
                            else if (LeftDC < -1) {
                                LeftDC = -1;
                            } else if (RightDC < -1) {
                                RightDC = -1;
                            }
                            
                            // Set direction and absolute value for PWM
                            if (LeftDC >= 0) {
                                LATBbits.LATB8 = 0;
                            } else {
                                LATBbits.LATB8 = 1;
                                LeftDC = 1 + LeftDC;
                            }

                            if (RightDC >= 0) {
                                LATBbits.LATB10 = 0;
                            } else {
                                LATBbits.LATB10 = 1;
                                RightDC = 1 + RightDC;
                            }
                            uint16_t LeftThrustPercent = (uint16_t)(LeftDC * 100.0);
                            uint16_t RightThrustPercent = (uint16_t)(RightDC * 100.0);
                            DB_printf("This is the Thrust Value: %u%% %u%%\n", LeftThrustPercent, RightThrustPercent);

                            OC2RS = ((LeftDC) * (double)PR_VAL);    
                            OC3RS = ((RightDC) * (double)PR_VAL);
                        } else {
                            OC2RS = 0;
                            OC3RS = 0;
                        }
                    } else if ((joystick.Left > 125) && (joystick.Left < 129) && (joystick.Right > 125) && (joystick.Right < 129)) {
                        OC2RS = 0; // right motor
                        OC3RS = 0; // left motor
                        LATBbits.LATB8 = 0;  // Left polarity
                        LATBbits.LATB10 = 0; // Right polarity
                    }
                    ES_Event_t NewEvent;
                    NewEvent.EventType = TX_REQUESTED;
                    NewEvent.EventParam = BatteryCharge;
                    ES_PostAll(NewEvent);

                }
                break;
                
                case ES_BUTTONCHANGE: // posted from XBeeService
                {
                    // Anchor and Dump Mechanism activated
                    ButtonVals = ThisEvent.EventParam; // aka "Buttons" on BARNXBeeService
                    DB_printf("The button is changed: Button %u\n", ButtonVals);
                    if (BatteryCharge > 0) {
                        switch(ButtonVals){
                        // if Button is 0, no anchor and no dump mechanism
                            case 0:{

                            }
                            break;
                        // if Button is 1, deploy coal
                            case 1:{
                                if(CoalIs == UP){
                                    // bring it up
                                    OC1RS = 3500; //2400
                                    CoalIs = DOWN;
                                    DB_printf("down\n");
                                } else
                                {
                                    // bring it down/deploy
                                    OC1RS = 5550; //5550
                                    CoalIs = UP;
                                }
                            }
                            break;
                        // if Button is 2, deploy anchor     
                            case 2:{
                                if(AnchorIs == UP){
                                    // bring it up
                                    OC4RS = 2000;
                                    AnchorIs = DOWN;
                                    DB_printf("down\n");
                                } else
                                {
                                    // bring it down/deploy
                                    OC4RS = 4500;
                                    AnchorIs = UP;
                                }

                            }
                            break;
                        // if Button is 3, open dump mechanism and deploy anchor
                        // but this should not happen so we will ignore it
                        }
                    }
                    if (BatteryCharge > 0) {
                        BatteryCharge -= 1;
                    }
                }
                break;
                
                case ES_RECHARGE:
                {
                    if (BatteryCharge < 150) {
                        if (BatteryCharge > 144) {
                            BatteryCharge = 150;
                        }
                        else {
                            BatteryCharge += 6;
                        }
                        DB_printf("Battery Charge: %u\n", BatteryCharge);
                    }
                    else {
                        DB_printf("Battery Full \n");
                    }
                    
                    OC2RS = 0;
                    OC3RS = 0;
                    LATBbits.LATB8 = 0;  // Left polarity
                    LATBbits.LATB10 = 0; // Right polarity
                    ES_Event_t NewEvent;
                    NewEvent.EventType = TX_REQUESTED;
                    NewEvent.EventParam = BatteryCharge;
                    ES_PostAll(NewEvent);
                }
                break;
                
                case ES_ENDOFTIME:
                {
                    DB_printf("TIMEOUT\n");
                    ES_Event_t NewEvent;
                    NewEvent.EventType = ES_INIT;
                    PostBarnacoalFSM(NewEvent);
                    CurrentState = InitPState;
                }
                break;
                
                default:
                    break;
            }
        }
        break;
    }                                   // end switch on Current State
    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryBarnacoalSM

 Parameters
     None

 Returns
     BarnState_t The current state of the BARNACOAL state machine

 Description
     returns the current state of the BARNACOAL state machine
 Notes

 Author
     J. Edward Carryer, 10/23/11, 19:21
****************************************************************************/
BarnState_t QueryBarnacoalFSM(void)
{
  return CurrentState;
}

/***************************************************************************
 private functions
 ***************************************************************************/
SoftWare Components – Communication Service Header file
#ifndef CommunicationService_H
#define CommunicationService_H

#include <stdint.h>
#include <stdbool.h>

#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
// Public Function Prototypes

typedef enum
{
    AwaitingGameCommand,
    SendingCommand,
    AwaitingActionCompletion,
    AligningBeacon,
} CommunicationServiceState_t;

bool InitCommunicationService(uint8_t Priority);
bool PostCommunicationService(ES_Event_t ThisEvent);
ES_Event_t RunCommunicationService(ES_Event_t ThisEvent);

#endif /* ServTemplate_H */