The NEDMO, or the controller for the watercraft, consists of the NAVCON, or the handheld controller responsible for driving the boat, and the FUELCON, which houses all components related to wireless communication and refueling.
The NAVCON and FUELCON share a single power distribution board and PIC32 microcontroller, and are tethered via wired connection. They function collectively under a single state machine - the NEDMO FSM, which receives events from peripherals and posts events to an XBee service, which is responsible for all packet transmission to the 0ILUS (boat). The state machine block diagram for the NEDMO state machine is shown below:
Module Variables:
CurrentState: NEDMOState_t
// Tracks the current state of the NEDMO_FSM
MyPriority: uint8_t
// Priority level of the NEDMO_FSM service
PAIRED_ONCE: uint8_t
// Flag indicating whether the system has been paired at least once
// 1 indicates paired at least once, 0 indicates not paired yet
DRUM_TIMEOUT: uint8_t
// Flag indicating whether the drum timeout has occurred
// 1 indicates drum timeout occurred, 0 indicates not occurred
MISSED_FUEL_ACKS: uint8_t
// Counter for the number of missed fuel acknowledgment packets
// Represents the number of times fuel acknowledgment was not received
// Range: 0 to 5
FUEL_ACK_RECEIVED: uint8_t
// Flag indicating whether a fuel acknowledgment packet was received
// 1 indicates fuel acknowledgment received, 0 indicates not received
BOAT_ADDRS: uint16_t[6]
// Array holding the addresses of the six boats
// Each boat address is represented by a 16-bit value
Initialize state machine and set priority:
Define the initial state as BoatChoosing.
Post the initial event (ES_INIT) to the event queue.
Return true if the event was posted successfully, otherwise return false.
Post an event to the state machine:
Post the given event to the event queue.
Return true if the event was posted successfully, otherwise return false.
Run the state machine:
Depending on the current state, process the given event as follows:
If the current state is BoatChoosing:
If the event is ES_BOAT (Boat button pressed):
Post ES_UPDATE_BOAT_ADDR event to the XBee service with the target boat address.
Transition to the Unpaired state.
Post ES_REQUEST_PAIR event to the XBee service to request pairing, if not paired before.
Start a timer for 200ms.
If the current state is Unpaired:
If the event is ES_TIMEOUT (timer expired):
Post ES_REQUEST_PAIR event to the XBee service to request pairing again.
Start a timer for 200ms.
If the event is ES_BOAT (Boat button pressed):
If paired before, post ES_REQUEST_PAIR event to the XBee service to request pairing.
Start a timer for 200ms.
If the event is ES_ACK_RECEIVED (acknowledgment received):
Set PAIRED_ONCE to 1.
Transition to the Paired state.
Post ES_BOAT event to the BoatDisplayFSM.
Start a timer for 4000ms.
If the current state is Paired:
If the event is ES_TIMEOUT (timer expired):
If the timer is COMMAND_TIMER, post ES_CONTROL_TIMEOUT event to the BoatDisplayFSM.
Transition to the Unpaired state.
If the event is ES_FUELLVL (fuel level update received):
Post ES_UPDATE_FUEL_SERVO event to the Fuel Servo Service with the new fuel level.
If control commands (ES_MOVE, ES_SHOOT, ES_INC, ES_DEC) are received:
Post the event to the XBee service.
If the event is ES_REFUEL (refuel request received):
Transition to the Refueling state.
If not in a drum timeout, post ES_REFUEL event to the XBee service.
Start a timer for 500ms for drum timeout.
If the event is ES_FUEL_ACK_RECEIVED (fuel acknowledgment received):
Start a timer for 4000ms.
If the event is ES_ACK_RECEIVED (acknowledgment received):
Start a timer for 4000ms.
If the current state is Refueling:
If the event is ES_TIMEOUT (timer expired):
If the timer is COMMAND_TIMER, post ES_CONTROL_TIMEOUT event to the BoatDisplayFSM.
Transition to the Unpaired state.
Reset drum timeout.
If the timer is REFUEL_TIMER and acknowledgment was not received:
Increment the missed fuel acknowledgment counter.
Transition to the Paired state and reset drum timeout.
If the event is ES_FUEL_ACK_RECEIVED (fuel acknowledgment received):
Set FUEL_ACK_RECEIVED to 1.
Reset the missed fuel acknowledgment counter.
Start a timer for 4000ms.
Query the current state of the state machine:
Return the current state.
Get the number of missed fuel packets:
Return 1 plus the number of missed fuel acknowledgments.
Module Variables:
CurrentState: BoatDisplayState_t
// Tracks the current state of the BoatDisplayFSM
MyPriority: uint8_t
// Priority level of the BoatDisplayFSM service
DeferralQueue: ES_Event_t[4]
// Queue for deferring events in case of full queue
joycon_enable: uint8_t
// Flag to control whether joystick inputs are enabled
boat_idx: uint8_t
// Current index of the selected boat for display
Initialize BoatDisplayFSM with Priority
Clear Screen
Set CurrentState to Init_State
Post ES_INIT event
Function PostBoatDisplayFSM(Event)
Post Event to BoatDisplayFSM queue
Function RunBoatDisplayFSM(Event)
If CurrentState is Init_State
If Event is ES_INIT
Set boat_idx to initial value
Update display with boat_idx
Transition to Selecting
Else If CurrentState is Selecting
If Event is ES_LEFT_BOAT
Decrease boat_idx, wrap around if necessary
Update display with boat_idx
If Event is ES_RIGHT_BOAT
Increase boat_idx, wrap around if necessary
Update display with boat_idx
If Event is ES_BOAT
Display selected boat_idx
Transition to Displaying
If Event is ES_NEW_KEY
If key is 'L'
Decrease boat_idx, wrap around if necessary
Update display with boat_idx
If key is 'R'
Increase boat_idx, wrap around if necessary
Update display with boat_idx
If key is 'B'
Display selected boat_idx
Transition to Displaying
Else If CurrentState is Displaying
If Event is ES_NEW_KEY and key is 'T'
Update display with boat_idx
Transition to Selecting
If Event is ES_CONTROL_TIMEOUT
Log timeout
Update display with boat_idx
Transition to Selecting
Function QueryBoatDisplayFSM()
Return CurrentState
Function GetBoatIdx()
Return boat_idx
Variables:
- NumModules: Integer = 4 // Number of modules in the LED display
- NumLEDDisplays: Integer = 1 // Number of LED displays
- NUM_ROWS: Integer = 8 // Number of rows in the LED display
- NUM_ROWS_IN_FONT: Integer = 5 // Number of rows for each character in the font
- DM_START_SHUTDOWN: Integer = 0x0C00 // Command to start shutdown
- DM_END_SHUTDOWN: Integer = 0x0C01 // Command to end shutdown
- DM_DISABLE_CODEB: Integer = 0x0900 // Command to disable Code B decoding
- DM_ENABLE_SCAN: Integer = 0x0B07 // Command to enable scanning
- DM_SET_BRIGHT: Integer = 0x0A0A // Command to set brightness
- NUM_BOATS: Integer = 6 // Number of boats
- ClawWalls: Integer = 0b11000000000000000000000000000011 // Initial value for claw walls
- NumMask[NUM_ROWS]: Array of Integers // Masks for numbers
- LED_Display_Modes[NUM_BOATS][NUM_ROWS * NumLEDDisplays]: 2D Array of Integers // LED display modes for each boat
- Number_Masks[NUM_BOATS][NUM_ROWS * NumLEDDisplays]: 2D Array of Integers // Masks for numbers for each boat
- Invert_Mask[NUM_ROWS]: Array of Integers // Inversion mask
- BitReverseTable256: Array of Bytes // Bit reversal table
- CurrentInitStep: Enum (DM_StepStartShutdown, DM_StepFillBufferZeros, DM_StepDisableCodeB, DM_StepEnableScanAll, DM_StepSetBrighness, DM_StepCopyBuffer2Display, DM_StepEndShutdown) // State variable for tracking initialization steps
// Define constants for the number of modules, LED displays, rows, and various commands
Constants:
NumModules = 4
NumLEDDisplays = 1
NUM_ROWS = 8
NUM_ROWS_IN_FONT = 5
DM_START_SHUTDOWN = 0x0C00
DM_END_SHUTDOWN = 0x0C01
DM_DISABLE_CODEB = 0x0900
DM_ENABLE_SCAN = 0x0B07
DM_SET_BRIGHT = 0x0A0A
NUM_BOATS = 6
// Define types for row data and initialization steps
Types:
DM_Row_t:
Union
FullRow: uint32_t
ByBytes[NumModules]: uint8_t
InitStep_t:
Enum
DM_StepStartShutdown
DM_StepFillBufferZeros
DM_StepDisableCodeB
DM_StepEnableScanAll
DM_StepSetBrighness
DM_StepCopyBuffer2Display
DM_StepEndShutdown
// Declare private functions for sending commands and rows
Private Functions:
sendCmd(uint16_t Cmd2Send)
sendRow(uint8_t RowNum, DM_Row_t* RowData)
// Define module-level variables
Variables:
DM_Display[NUM_ROWS][NumLEDDisplays]: DM_Row_t array
CurrentInitStep: InitStep_t
BitReverseTable256: uint8_t array
ClawWalls: uint32_t
NumMask[NUM_ROWS]: uint32_t
LED_Display_Modes[NUM_BOATS][NUM_ROWS * NumLEDDisplays]: uint32_t array
Number_Masks[NUM_BOATS][NUM_ROWS * NumLEDDisplays]: uint32_t array
Invert_Mask[NUM_ROWS]: uint32_t array
// Function to take initialization steps for the display
Function: DM_TakeInitDisplayStep
Loop:
Switch(CurrentInitStep):
Case DM_StepStartShutdown:
Send command to start shutdown
Increment CurrentInitStep
Case DM_StepFillBufferZeros:
Clear display buffer
Increment CurrentInitStep
Case DM_StepDisableCodeB:
Send command to disable Code B decoding
Increment CurrentInitStep
Case DM_StepEnableScanAll:
Send command to enable scanning for all digits
Increment CurrentInitStep
Case DM_StepSetBrighness:
Send command to set brightness to minimum
Increment CurrentInitStep
Case DM_StepCopyBuffer2Display:
If DM_TakeDisplayUpdateStep returns true:
Increment CurrentInitStep
Else:
Continue loop
Case DM_StepEndShutdown:
Send command to end shutdown
Set ReturnVal to true
Reset CurrentInitStep to DM_StepStartShutdown
End Switch
Return ReturnVal
// Function to update the display buffer row by row
Function: DM_TakeDisplayUpdateStep
If WhichRow < 8:
Send row data for WhichRow
Increment WhichRow
Else:
Set ReturnVal to true
Reset WhichRow to 0
Return ReturnVal
// Function to scroll the display buffer
Function: DM_ScrollDisplayBuffer(NumCols2Scroll, WhichLED)
For Each Row in DM_Display:
Shift data in the row left by NumCols2Scroll bits
// Function to add a character to the display buffer
Function: DM_AddChar2DisplayBuffer(Char2Display, WhichLED)
For Each Row in NUM_ROWS_IN_FONT:
OR font line data with corresponding row in display buffer
// Function to clear the display buffer
Function: DM_ClearDisplayBuffer
For Each Row in DM_Display:
Set row data to all zeros
// Function to put data into a specific row of the display buffer
Function: DM_PutDataIntoBufferRow(Data2Insert, WhichRow, WhichLED)
If WhichRow and WhichLED are within valid range:
Set row data in DM_Display to Data2Insert
Set ReturnVal to true
Else:
Set ReturnVal to false
Return ReturnVal
// Function to query row data from the display buffer
Function: DM_QueryRowData(WhichLED, RowToQuery, pReturnValue)
If WhichRow and WhichLED are within valid range:
Get row data from DM_Display and store in pReturnValue
Set ReturnVal to true
Else:
Set ReturnVal to false
Return ReturnVal
// Function to update display buffer with template for a specific boat
Function: UpdateBufferWithTemplate(BoatNum)
If BoatNum is within valid range:
For Each Row in DM_Display:
Set row data to corresponding template data for BoatNum
// Define constants for fuel levels
#define EMPTY 4600
#define FULL 1300
#define ONE_FIFTH EMPTY+(FULL-EMPTY)/5
#define TWO_FIFTHS EMPTY+(FULL-EMPTY)*2/5
#define THREE_FIFTHS EMPTY+(FULL-EMPTY)*3/5
#define FOUR_FIFTHS EMPTY+(FULL-EMPTY)*4/5
// Declare module-level variables
static uint8_t MyPriority;
// Initialize Fuel Servo Service
bool InitFuelServoService(uint8_t Priority) {
ES_Event_t ThisEvent;
MyPriority = Priority;
// Configure the OC pin
// Set pin B2 as output
// Disable analog input for pin B2
// Route pin B2 to OC4 output
// Configure Timer 3 for OC
// Disable Timer 3
// Select internal clock source for Timer 3
// Set Timer 3 prescaler to 1:2
// Initialize Timer 3 count value to 0
// Set Timer 3 period to achieve a frequency of 4608 Hz
// Clear Timer 3 interrupt flag
// Disable Timer 3 interrupts
// Enable Timer 3
// Configure OC4 for left motor
// Disable OC4
// Specify 16-bit timer for OC4
// Specify Timer 3 as the timer source for OC4
// Configure OC4 for PWM mode with no fault pin
// Initialize OC4 duty cycle to EMPTY (initially motionless)
// Enable OC4
// Post initial transition event ES_INIT
// Return true if event posted successfully, false otherwise
}
// Post an event to the queue
bool PostFuelServoService(ES_Event_t ThisEvent) {
// Post ThisEvent to the service queue with priority MyPriority
// Return true if enqueue operation succeeded, false otherwise
}
// Process an event
ES_Event_t RunFuelServoService(ES_Event_t ThisEvent) {
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // Assume no errors
if (ThisEvent.EventType == ES_UPDATE_FUEL_SERVO) {
// Adjust fuel servo based on fuel level
// If fuel level is above 60, set OC4 duty cycle to FULL
// If fuel level is above 45, set OC4 duty cycle to FOUR_FIFTHS
// If fuel level is above 30, set OC4 duty cycle to THREE_FIFTHS
// If fuel level is above 15, set OC4 duty cycle to TWO_FIFTHS
// If fuel level is above 0, set OC4 duty cycle to ONE_FIFTH
// If fuel level is 0 or below, set OC4 duty cycle to EMPTY
}
// Return no event
}
/****************************************************************************
Module
LEDService.c
Revision
0.0
Description
LED Service that accepts an alphanumeric character and displays it to
the MAX7219 Dot Matrix Controller.
Notes
****************************************************************************/
// Include necessary header files
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "DM_Display.h"
#include "PIC32_SPI_HAL.h"
#include "LEDFSM.h"
#include "dbprintf.h"
// Declare module-level variables
static LEDState_t CurrentState;
static uint8_t MyPriority;
static ES_Event_t DeferralQueue[3 + 1];
static uint8_t joycon_enable = 1;
static uint8_t boat_idx = 1;
// Initialize LED Service
bool InitLEDFSM(uint8_t Priority) {
// Initialize GPIO pins for LED control
// Set pins A0, A1, and B14 as outputs
// Disable analog input for pins A0, A1, and B14
// Setup SPI communication
// Initialize MAX7219 display
// Initialize deferral queue
// Post initial transition event ES_INIT
// Return true if event posted successfully, false otherwise
}
// Post an event to the queue
bool PostLEDFSM(ES_Event_t ThisEvent) {
// Post ThisEvent to the service queue with priority MyPriority
// Return true if enqueue operation succeeded, false otherwise
}
// Process an event
ES_Event_t RunLEDFSM(ES_Event_t ThisEvent) {
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // Assume no errors
switch (CurrentState) {
case Init_LEDState:
{
// Transition to Idle state upon initialization
}
break;
case Idle:
{
// If in Idle state, handle ES_CHAR_PRESS event to transition to Writing state
}
break;
case Writing:
{
// If in Writing state, handle ES_UPDATING event to update LED display
// Transition back to Idle state once display update is complete
}
break;
}
return ReturnEvent;
}
// Query current state of the LED Service
LEDState_t QueryLEDFSM(void) {
// Return the current state of the LED Service
}
/****************************************************************************
Function
InitJoystickStatus
Description
Initializes joystick status by configuring pins and ADC channels.
****************************************************************************/
void InitJoystickStatus(void) {
// Configure pins as analog inputs
// Set ANSELB bit for RB3, RB12, and RB13
// Set TRISB bit for RB12, RB13, and RB3
// Configure ADC for auto-scan on specified channels
// Read initial ADC values
// Print initial ADC values for debugging
}
/****************************************************************************
Function
CheckMoveEvents
Description
Checks for changes in joystick states related to movement.
Returns
bool: true if the joystick has changes
****************************************************************************/
bool CheckMoveEvents(void)
{
// Initialize local variables
// Read current ADC values for all channels
// Compare current ADC values with last recorded values
// For each channel, if the absolute difference exceeds a threshold or is greater than half of the ADC range
// Set ReturnVal to true indicating a change in joystick state
// If the boat is paired:
// Construct an ES_MOVE event with the thrust and turn values calculated from ADC readings
// Post the event to the NEDMO FSM
// Update last ADC values for future comparison
}
/****************************************************************************
Function
CheckMovingEvents
Description
Checks for changes in joystick states related to forward/backward movement.
Returns
bool: true if the joystick has changes
****************************************************************************/
bool CheckMovingEvents(void)
{
// Initialize local variables
// Read current ADC values for all channels
// Compare current ADC values with last recorded values
// If the absolute difference in the second channel (thrust) exceeds a threshold or is greater than half of the ADC range
// Set ReturnVal to true indicating a change in joystick state
// If changes detected:
// Calculate the thrust level from the ADC reading
// Construct appropriate event based on thrust level (ES_FORWARD, ES_BACKWARD, or ES_STOP)
// Post event to communication service
// Update last ADC values for future comparison
}
/****************************************************************************
Function
CheckChoosingEvents
Description
Checks for changes in joystick states related to boat selection.
Returns
bool: true if the joystick has changes
****************************************************************************/
bool CheckChoosingEvents(void)
{
// Initialize local variables
// Read current ADC values for all channels
// Compare current ADC values with last recorded values
// If the absolute difference in the first channel (choosing) exceeds a threshold or is greater than half of the ADC range
// Or if the boat is unpaired:
// Check if enough time has elapsed since last action
// If elapsed time is sufficient:
// Determine boat selection based on joystick input
// Construct appropriate event (ES_LEFT_BOAT or ES_RIGHT_BOAT)
// Post event to boat display FSM
// Update last action time and last ADC values for future comparison
}
/****************************************************************************
Module
PumpButtonCheckers.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
****************************************************************************/
// Include necessary header files
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_Events.h"
#include "ES_PostList.h"
#include "ES_ServiceHeaders.h"
#include "ES_Port.h"
#include "PumpButtonsCheckers.h"
#include "BoatDisplayFSM.h"
#include "NEDMO_FSM.h"
#include "dbprintf.h"
// Define pin states for buttons
#define ShootPinState PORTAbits.RA2
#define IncAnglePin PORTBbits.RB5
#define DecAnglePin PORTBbits.RB8
#define DrumButton PORTAbits.RA3
#define BoatButton PORTBbits.RB4
// Initialize static variables for button states
static uint8_t lastShootState;
static uint8_t lastIncAnglePinState;
static uint8_t lastDecAnglePinState;
static uint8_t lastDrumState;
static uint8_t lastBoatButtonState;
/****************************************************************************
Function
InitButtonsStatus
Description
Initializes button status by configuring pins and saving initial states.
****************************************************************************/
void InitButtonsStatus(void) {
// Configure pins as inputs
// Save initial pin states
DB_printf("Initial pin state: shoot - %u\n", lastShootState);
DB_printf("Initial pin state: IncAnglePin - %u\n", lastIncAnglePinState);
DB_printf("Initial pin state: DecAnglePin - %u\n", lastDecAnglePinState);
DB_printf("Initial pin state: DrumButton - %u\n", lastDrumState);
}
/****************************************************************************
Function
Check4Shoot
Description
Checks for changes in shoot button state.
Returns
bool: true if shoot button state has changed
****************************************************************************/
bool Check4Shoot(void)
{
// Initialize local variables
// Read current shoot button state
// Check for transition from low to high
// If transition detected:
// Construct ES_SHOOT event and post to NEDMO FSM
// Update last shoot button state for future comparison
}
/****************************************************************************
Function
Check4Inc
Description
Checks for changes in angle increment button state.
Returns
bool: true if increment button state has changed
****************************************************************************/
bool Check4Inc(void)
{
// Initialize local variables
// Read current increment button state
// Check for transition from low to high
// If transition detected:
// Construct ES_INC event and post to NEDMO FSM
// Update last increment button state for future comparison
}
/****************************************************************************
Function
Check4Dec
Description
Checks for changes in angle decrement button state.
Returns
bool: true if decrement button state has changed
****************************************************************************/
bool Check4Dec(void)
{
// Initialize local variables
// Read current decrement button state
// Check for transition from low to high
// If transition detected:
// Construct ES_DEC event and post to NEDMO FSM
// Update last decrement button state for future comparison
}
/****************************************************************************
Function
Check4Drum
Description
Checks for changes in drum button state.
Returns
bool: true if drum button state has changed
****************************************************************************/
bool Check4Drum(void)
{
// Initialize local variables
// Read current drum button state
// Check for transition from high to low
// If transition detected and sufficient time has elapsed since last action:
// Construct ES_REFUEL event and post to NEDMO FSM
// Update last drum button state and action time for future comparison
}
/****************************************************************************
Function
Check4Boat
Description
Checks for changes in boat button state.
Returns
bool: true if boat button state has changed
****************************************************************************/
bool Check4Boat(void)
{
// Initialize local variables
// Read current boat button state
// Check for transition from high to low
// If transition detected:
// Construct ES_BOAT event and post to NEDMO FSM
// Update last boat button state for future comparison
}