//PIC Stuff/Cerebot_32MX7_LED_Cube/CONTROLLERS.c |
---|
3,12 → 3,10 |
#include "I2C1.h" |
static CONTROLLER_DATA *ctrl_data_p; |
static BOARD_STATE *board_state_p; |
void Controller_Init(CONTROLLER_DATA *data, BOARD_STATE *state, |
void Controller_Init(CONTROLLER_DATA *data, |
void (*btn_change_callback)(uint8_t, uint8_t)) { |
ctrl_data_p = data; |
board_state_p = state; |
ctrl_data_p->btn_change_callback = btn_change_callback; |
105,23 → 103,20 |
} |
// If board is in an idle state and a controller is connected, switch modes |
if (board_state_p->cube_mode == BOARD_MODE_IDLE) { |
if (Get_Board_State() == BOARD_MODE_IDLE) { |
// If both controllers are active, go into game TRON mode |
if (ctrl_data_p->ctrl_1_active && ctrl_data_p->ctrl_2_active) { |
board_state_p->cube_mode = BOARD_MODE_TRON; |
Reset_Board(); |
Reset_Board(BOARD_MODE_TRON); |
} |
// Otherwise if only one controller is active, go into game SNAKE mode |
if (ctrl_data_p->ctrl_1_active || ctrl_data_p->ctrl_2_active) { |
board_state_p->cube_mode = BOARD_MODE_SNAKE; |
Reset_Board(); |
Reset_Board(BOARD_MODE_SNAKE); |
} |
} |
if (board_state_p->cube_mode == BOARD_MODE_SNAKE) { |
if (Get_Board_State() == BOARD_MODE_SNAKE) { |
// If both controllers are active, go into game TRON mode |
if (ctrl_data_p->ctrl_1_active && ctrl_data_p->ctrl_2_active) { |
board_state_p->cube_mode = BOARD_MODE_TRON; |
Reset_Board(); |
Reset_Board(BOARD_MODE_TRON); |
} |
} |
136,4 → 131,15 |
void Controller_Set_Leds(uint8_t ctrl_1, uint8_t ctrl_2) { |
ctrl_data_p->ctrl_1_leds = ctrl_1; |
ctrl_data_p->ctrl_2_leds = ctrl_2; |
} |
uint8_t Controller_Query(void) { |
// Returns the active status of attached controllers |
if (ctrl_data_p->ctrl_1_active && ctrl_data_p->ctrl_2_active) |
return 0x3; |
else if (ctrl_data_p->ctrl_1_active) |
return 0x1; |
else if (ctrl_data_p->ctrl_2_active) |
return 0x2; |
return 0; |
} |
//PIC Stuff/Cerebot_32MX7_LED_Cube/CONTROLLERS.h |
---|
24,11 → 24,12 |
uint8_t ctrl_2_active; |
} CONTROLLER_DATA; |
void Controller_Init(CONTROLLER_DATA *data, BOARD_STATE *state, |
void Controller_Init(CONTROLLER_DATA *data, |
void (*btn_change_callback)(uint8_t, uint8_t)); |
void Controller_Update(void); |
void Controller_Set_Leds(uint8_t ctrl_1, uint8_t ctrl_2); |
void Controller_Btn_Change(void (*callback)(uint8_t, uint8_t)); |
uint8_t Controller_Query(void); |
#endif /* CONTROLLERS_H */ |
//PIC Stuff/Cerebot_32MX7_LED_Cube/SNAKE.c |
---|
0,0 → 1,177 |
#include "defines.h" |
#include "CONTROLLERS.h" |
#include "SNAKE.h" |
static SNAKE_DATA *data_p; |
void Snake_Init(SNAKE_DATA *data) { |
data_p = data; |
// Disable watchdog timer |
WDTCON = 0x00000000; |
// Set starting point |
data_p->body[0].x = 0; |
data_p->body[0].y = 0; |
data_p->body[0].z = 0; |
data_p->pos_head = 0; |
data_p->pos_tail = 0; |
data_p->length = 1; |
data_p->level = 1; |
data_p->delay = 800; |
// Generate a starting location for the candy |
data_p->candy_loc = Snake_Generate_Candy(); |
// Draw the snake (head) |
Cube_Clear(); |
uint32_t index = data_p->pos_head; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR); |
while (index != data_p->pos_tail) { |
if (data_p->length > 1) { |
index = (index == 0) ? CUBE_PIXELS - 1 : index - 1; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR); |
} |
} |
} |
void Snake_Main(void) { |
Delay_MS(2000); |
while (1) { |
Snake_Update_Frame(); |
Delay_MS(data_p->delay); |
} |
} |
void Snake_Update_Direction(uint8_t p1, uint8_t p2) { |
// Determine the next direction for the snake based off the last button press |
SNAKE_DIRECTION dir; |
dir.value = p1 | p2; |
data_p->last_direction = dir.value; |
SNAKE_POINT point = data_p->body[data_p->pos_head]; |
if (dir.up) { |
point.z = (point.z == CUBE_LAYER_COUNT - 1) ? 0 : point.z + 1; |
} else if (dir.down) { |
point.z = (point.z == 0) ? CUBE_LAYER_COUNT - 1 : point.z - 1; |
} else if (dir.forward) { |
point.x = (point.x == CUBE_ROW_COUNT - 1) ? 0 : point.x + 1; |
} else if (dir.right) { |
point.y = (point.y == CUBE_COLUMN_COUNT - 1) ? 0 : point.y + 1; |
} else if (dir.backward) { |
point.x = (point.x == 0) ? CUBE_ROW_COUNT - 1 : point.x - 1; |
} else if (dir.left) { |
point.y = (point.y== 0) ? CUBE_COLUMN_COUNT - 1 : point.y - 1; |
} |
data_p->direction = point; |
// Update the overlay with the candy location |
Cube_Overlay_Clear(); |
Cube_Overlay_Set_Pixel(data_p->candy_loc.z, data_p->candy_loc.x, data_p->candy_loc.y, SNAKE_CANDY_COLOR); |
} |
void Snake_Update_Frame(void) { |
uint8_t om_nom_nom = 0; |
// Check if we are moving onto a candy, if so extend body |
if (data_p->direction.x == data_p->candy_loc.x && |
data_p->direction.y == data_p->candy_loc.y && |
data_p->direction.z == data_p->candy_loc.z) { |
data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1; |
data_p->body[data_p->pos_head] = data_p->direction; |
data_p->length++; |
data_p->candy_loc = Snake_Generate_Candy(); |
om_nom_nom = 1; |
} |
// Check if the location that we are moving to is overlapping the body |
uint32_t pos = data_p->pos_tail; |
while (pos != data_p->pos_head) { |
if (data_p->direction.x == data_p->body[pos].x && |
data_p->direction.y == data_p->body[pos].y && |
data_p->direction.z == data_p->body[pos].z) { |
Cube_Overlay_Set_Pixel(data_p->direction.z, data_p->direction.x, data_p->direction.y, SNAKE_HEAD_COLOR); |
Delay_MS(3000); |
Reset_Board(BOARD_MODE_IDLE); |
} |
pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1; |
} |
// If we didnt eat a candy, increment the frame to move the body along |
if (!om_nom_nom) { |
data_p->pos_head = (data_p->pos_head == CUBE_PIXELS - 1) ? 0 : data_p->pos_head + 1; |
data_p->pos_tail = (data_p->pos_tail == CUBE_PIXELS - 1) ? 0 : data_p->pos_tail + 1; |
data_p->body[data_p->pos_head] = data_p->direction; |
} |
// Draw updated snake location |
Cube_Clear(); |
uint32_t index = data_p->pos_head; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_HEAD_COLOR); |
while (index != data_p->pos_tail) { |
if (data_p->length > 1) { |
index = (index == 0) ? CUBE_PIXELS - 1 : index - 1; |
Cube_Set_Pixel(data_p->body[index].z, data_p->body[index].x, data_p->body[index].y, SNAKE_BODY_COLOR); |
} |
} |
// Determine the next direction to take |
Snake_Update_Direction(data_p->last_direction, 0x0); |
// If we ate a candy, delay for a bit to rest |
if (om_nom_nom) { |
data_p->level += 1; // Increase the level by one |
if (data_p->level % SNAKE_LEVEL_STEP == 0) { |
uint8_t tier = data_p->level / SNAKE_LEVEL_STEP; |
Controller_Set_Leds(tier, tier); |
} |
data_p->delay -= 5; // Decrease the delay between frame updates by 5ms |
} |
} |
SNAKE_POINT Snake_Generate_Candy(void) { |
// Generates a random position within the cube that doesnt overlap anything |
SNAKE_POINT ret; |
uint32_t x, y, z, brk = 0; |
while(1) { |
x = rand() % 8; |
y = rand() % 8; |
z = rand() % 8; |
if (data_p->length != 1) { |
uint32_t pos = data_p->pos_tail; |
uint32_t overlap = 0; |
// Iterate through the frame till we finish or find an overlap |
while (pos != data_p->pos_head) { |
if (data_p->body[pos].x == x && |
data_p->body[pos].y == y && |
data_p->body[pos].z == z) { |
overlap = 1; |
break; |
} else { |
pos = (pos == CUBE_PIXELS - 1) ? 0 : pos + 1; |
} |
} |
if (!overlap) |
brk = 1; |
} else { |
uint32_t pos = data_p->pos_tail; |
if (data_p->body[pos].x != x && |
data_p->body[pos].y != y && |
data_p->body[pos].z != z) { |
brk = 1; |
} |
} |
if (brk) |
break; |
} |
ret.x = x; |
ret.y = y; |
ret.z = z; |
return ret; |
} |
//PIC Stuff/Cerebot_32MX7_LED_Cube/SNAKE.h |
---|
0,0 → 1,51 |
#ifndef SNAKE_H |
#define SNAKE_H |
#include "CUBE.h" |
#define SNAKE_BODY_COLOR BLUE |
#define SNAKE_HEAD_COLOR RED |
#define SNAKE_CANDY_COLOR GREEN |
#define SNAKE_LEVEL_STEP 10 |
typedef struct { |
unsigned x :8; |
unsigned y :8; |
unsigned z :8; |
unsigned :8; |
} SNAKE_POINT; |
typedef union { |
struct { |
unsigned up :1; |
unsigned down :1; |
unsigned left :1; |
unsigned backward :1; |
unsigned right :1; |
unsigned forward :1; |
unsigned :2; |
}; |
uint8_t value; |
} SNAKE_DIRECTION; |
typedef struct { |
SNAKE_POINT body[CUBE_PIXELS]; |
SNAKE_POINT direction; |
SNAKE_POINT candy_loc; |
uint8_t last_direction; |
uint32_t pos_head; |
uint32_t pos_tail; |
uint32_t length; |
uint32_t level; |
uint32_t delay; |
} SNAKE_DATA; |
void Snake_Init(SNAKE_DATA *data); |
void Snake_Main(void); |
void Snake_Update_Direction(uint8_t p1, uint8_t p2); |
void Snake_Update_Frame(void); |
SNAKE_POINT Snake_Generate_Candy(void); |
#endif /* SNAKE_H */ |
//PIC Stuff/Cerebot_32MX7_LED_Cube/defines.h |
---|
53,7 → 53,8 |
void Delay_MS(uint32_t delay_ms); |
void Delay_US(uint32_t delay_us); |
uint8_t Get_Reset_Condition(void); |
void Reset_Board(void); |
uint8_t Get_Board_State(void); |
void Reset_Board(uint8_t next_state); |
void Idle_Animation_Sequence(void); |
#endif /* DEFINES_H */ |
//PIC Stuff/Cerebot_32MX7_LED_Cube/main.c |
---|
87,7 → 87,16 |
return ret; |
} |
void Reset_Board(void) { |
// Initialize a persistent operational state machine |
static BOARD_STATE op_state __attribute__((persistent)); |
uint8_t Get_Board_State(void) { |
return op_state.cube_mode; |
} |
void Reset_Board(uint8_t next_state) { |
op_state.cube_mode = next_state; |
// Executes a software reset |
INTDisableInterrupts(); |
SYSKEY = 0x00000000; // Write invalid key to force lock |
132,9 → 141,6 |
LED3_LAT = 0; |
LED4_LAT = 0; |
// Initialize a persistent operational state machine |
BOARD_STATE op_state __attribute__((persistent)); |
// Initialize the SPI1 module |
SPI1_DATA spi_1_data; |
SPI1_Init(&spi_1_data, NULL); |
171,8 → 177,11 |
BTN_DATA btn_data; |
BTN_Init(&btn_data, &BTN1_Interrupt, &BTN2_Interrupt, NULL); |
// Initialize controllers |
CONTROLLER_DATA ctrl_data; |
Controller_Init(&ctrl_data, &op_state, &Controller_Set_Leds); |
Controller_Init(&ctrl_data, &Snake_Update_Direction); |
SNAKE_DATA snake_data; |
// Determine what to do at this point. We either choose to idle (on POR) |
// or go into a mode specified prior to the software reset event |
197,15 → 206,10 |
switch (op_state.cube_mode) { |
case BOARD_MODE_SNAKE: |
LED3_LAT = 1; |
LED4_LAT = 0; |
SNAKE_DATA snake_data; |
Snake_Init(&snake_data); |
while(1); |
Snake_Main(); |
break; |
case BOARD_MODE_TRON: |
LED3_LAT = 0; |
LED4_LAT = 1; |
while(1); |
break; |
case BOARD_MODE_IDLE: |
217,6 → 221,7 |
} |
void Idle_Animation_Sequence(void) { |
Delay_MS(250); |
// Cube_Set_All(RED); |
// Delay_MS(2000); |
224,12 → 229,12 |
// Delay_MS(2000); |
// Cube_Set_All(BLUE); |
// Delay_MS(2000); |
Animation_Pseudo_Random_Colors(200); |
Animation_Pseudo_Random_Colors(200); |
Animation_Pseudo_Random_Colors(200); |
Animation_Pseudo_Random_Colors(200); |
Animation_Pseudo_Random_Colors(200); |
Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Animation_Pseudo_Random_Colors(200); |
// Start the scrolling text |
TIMER4_Stop(); |
//PIC Stuff/Cerebot_32MX7_LED_Cube/nbproject/private/private.xml |
---|
1,3 → 1,10 |
<?xml version="1.0" encoding="UTF-8"?><project-private xmlns="http://www.netbeans.org/ns/project-private/1"> |
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/> |
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/1"> |
<file>file:/C:/Users/Kevin/Documents/Code/Cerebot_32MX7_LED_Cube/main.c</file> |
<file>file:/C:/Users/Kevin/Documents/Code/Cerebot_32MX7_LED_Cube/SNAKE.c</file> |
<file>file:/C:/Users/Kevin/Documents/Code/Cerebot_32MX7_LED_Cube/defines.h</file> |
<file>file:/C:/Users/Kevin/Documents/Code/Cerebot_32MX7_LED_Cube/README.txt</file> |
<file>file:/C:/Users/Kevin/Documents/Code/Cerebot_32MX7_LED_Cube/SNAKE.h</file> |
</open-files> |
</project-private> |