Generate callgraph

This commit is contained in:
Michael Hayes
2011-08-27 01:46:08 +00:00
commit 513810e138
233 changed files with 22993 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
# File: Makefile
# Author: M. P. Hayes, UCECE
# Date: 12 Sep 2010
# Descr: Makefile for space10
# Definitions.
CC = avr-gcc
CFLAGS = -mmcu=atmega32u2 -Os -Wall -Wstrict-prototypes -Wextra -g -I. -I../../utils -I../../fonts -I../../drivers -I../../drivers/avr
OBJCOPY = avr-objcopy
SIZE = avr-size
DEL = rm
# Default target.
all: space10.out
# Compile: create object files from C source files.
space10.o: space10.c ../../drivers/avr/eeprom.h ../../drivers/avr/system.h ../../drivers/display.h ../../drivers/ir.h ../../drivers/ir_serial.h ../../fonts/font3x5_1.h ../../utils/font.h ../../utils/pacer.h ../../utils/tinygl.h ../../utils/uint8toa.h flasher.h spacey.h
$(CC) -c $(CFLAGS) $< -o $@
flasher.o: flasher.c ../../drivers/avr/system.h flasher.h
$(CC) -c $(CFLAGS) $< -o $@
spacey.o: spacey.c ../../drivers/avr/system.h spacey.h
$(CC) -c $(CFLAGS) $< -o $@
eeprom.o: ../../drivers/avr/eeprom.c ../../drivers/avr/eeprom.h ../../drivers/avr/system.h
$(CC) -c $(CFLAGS) $< -o $@
pio.o: ../../drivers/avr/pio.c ../../drivers/avr/pio.h ../../drivers/avr/system.h
$(CC) -c $(CFLAGS) $< -o $@
system.o: ../../drivers/avr/system.c ../../drivers/avr/system.h
$(CC) -c $(CFLAGS) $< -o $@
timer.o: ../../drivers/avr/timer.c ../../drivers/avr/system.h ../../drivers/avr/timer.h
$(CC) -c $(CFLAGS) $< -o $@
display.o: ../../drivers/display.c ../../drivers/avr/system.h ../../drivers/display.h ../../drivers/ledmat.h
$(CC) -c $(CFLAGS) $< -o $@
ir.o: ../../drivers/ir.c ../../drivers/avr/delay.h ../../drivers/avr/pio.h ../../drivers/avr/system.h ../../drivers/ir.h
$(CC) -c $(CFLAGS) $< -o $@
ir_serial.o: ../../drivers/ir_serial.c ../../drivers/avr/delay.h ../../drivers/avr/system.h ../../drivers/ir.h ../../drivers/ir_serial.h
$(CC) -c $(CFLAGS) $< -o $@
ledmat.o: ../../drivers/ledmat.c ../../drivers/avr/pio.h ../../drivers/avr/system.h ../../drivers/ledmat.h
$(CC) -c $(CFLAGS) $< -o $@
pacer.o: ../../utils/pacer.c ../../drivers/avr/system.h ../../drivers/avr/timer.h ../../utils/pacer.h
$(CC) -c $(CFLAGS) $< -o $@
tinygl.o: ../../utils/tinygl.c ../../drivers/avr/system.h ../../drivers/display.h ../../utils/font.h ../../utils/tinygl.h
$(CC) -c $(CFLAGS) $< -o $@
uint8toa.o: ../../utils/uint8toa.c ../../drivers/avr/system.h
$(CC) -c $(CFLAGS) $< -o $@
# Link: create ELF output file from object files.
space10.out: display.o eeprom.o flasher.o ir.o ir_serial.o ledmat.o pacer.o pio.o space10.o spacey.o system.o timer.o tinygl.o uint8toa.o
$(CC) $(CFLAGS) $^ -o $@ -lm
$(SIZE) $@
# Target: clean project.
.PHONY: clean
clean:
-$(DEL) *.o *.out *.hex
# Target: program project.
.PHONY: program
program: space10.out
$(OBJCOPY) -O ihex space10.out space10.hex
dfu-programmer atmega32u2 erase; dfu-programmer atmega32u2 flash space10.hex; dfu-programmer atmega32u2 start
+75
View File
@@ -0,0 +1,75 @@
# File: Makefile
# Author: M. P. Hayes, UCECE
# Date: 11 Sep 2010
# Descr: Makefile for space10
CC = gcc
CFLAGS = -Wall -Wstrict-prototypes -Wextra -g -I. -I../../utils -I../../drivers -I../../drivers/test
DEL = rm
# Default target.
all: space10
# Compile: create object files from C source files.
space10-test.o: space10.c ../../utils/font.h ../../drivers/ir_serial.h ../../drivers/test/system.h ../../drivers/test/eeprom.h ../../fonts/font3x5_1.h flasher.h ../../utils/tinygl.h spacey.h ../../utils/pacer.h ../../drivers/display.h ../../drivers/ir.h ../../utils/uint8toa.h
$(CC) -c $(CFLAGS) $< -o $@
timer-test.o: ../../drivers/test/timer.c ../../drivers/test/timer.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
display-test.o: ../../drivers/display.c ../../drivers/ledmat.h ../../drivers/display.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
spacey-test.o: spacey.c spacey.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
pio-test.o: ../../drivers/test/pio.c
$(CC) -c $(CFLAGS) $< -o $@
ir_serial-test.o: ../../drivers/ir_serial.c ../../drivers/ir.h ../../drivers/ir_serial.h ../../drivers/test/delay.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
pacer-test.o: ../../utils/pacer.c ../../drivers/test/timer.h ../../utils/pacer.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
flasher-test.o: flasher.c flasher.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
tinygl-test.o: ../../utils/tinygl.c ../../drivers/display.h ../../utils/font.h ../../utils/tinygl.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
uint8toa-test.o: ../../utils/uint8toa.c ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
ledmat-test.o: ../../drivers/ledmat.c ../../drivers/test/avrtest.h ../../drivers/test/pio.h ../../drivers/ledmat.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
eeprom-test.o: ../../drivers/test/eeprom.c ../../drivers/test/eeprom.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
system-test.o: ../../drivers/test/system.c ../../drivers/test/pio.h ../../drivers/test/avrtest.h ../../drivers/test/mgetkey.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
ir-test.o: ../../drivers/ir.c ../../drivers/test/pio.h ../../drivers/ir.h ../../drivers/test/avrtest.h ../../drivers/test/delay.h ../../drivers/test/system.h
$(CC) -c $(CFLAGS) $< -o $@
mgetkey-test.o: ../../drivers/test/mgetkey.c ../../drivers/test/mgetkey.h
$(CC) -c $(CFLAGS) $< -o $@
# Link: create executable file from object files.
space10: space10-test.o timer-test.o display-test.o spacey-test.o pio-test.o ir_serial-test.o pacer-test.o flasher-test.o tinygl-test.o uint8toa-test.o ledmat-test.o eeprom-test.o system-test.o ir-test.o mgetkey-test.o
$(CC) $(CFLAGS) $^ -o $@ -lrt
# Clean: delete derived files.
.PHONY: clean
clean:
-$(DEL) space10 space10-test.o timer-test.o display-test.o spacey-test.o pio-test.o ir_serial-test.o pacer-test.o flasher-test.o tinygl-test.o uint8toa-test.o ledmat-test.o eeprom-test.o system-test.o ir-test.o mgetkey-test.o
+100
View File
@@ -0,0 +1,100 @@
/** @file flasher.c
@author M. P. Hayes, UCECE
@date 13 March 2005
@brief
*/
#include "flasher.h"
/* These routines are for flashing a LED or beeping a piezo tweeter.
Perhaps they should be separated into software PWM and flash
pattern sequencing. */
int8_t
flasher_pattern_set (flasher_t flasher, flasher_pattern_t *pattern)
{
flasher->pattern = pattern;
flasher->mod_count = 0;
flasher->flasher_count = 0;
flasher->flashes_count = 0;
flasher->flasher_prescale = 0;
return 1;
}
flasher_pattern_t *
flasher_pattern_get (flasher_t flasher)
{
return flasher->pattern;
}
/* FIXME. */
int8_t
flasher_phase_set (flasher_t flasher, uint8_t phase)
{
flasher->mod_count = 0;
flasher->flasher_count = 0;
flasher->flashes_count = phase;
return 1;
}
/* Return the next state for the associated device. For example,
to control the flashing of a LED use:
led_set (led, flasher_update (flasher)); */
bool
flasher_update (flasher_t flasher)
{
if (!flasher->pattern)
return 0;
flasher->mod_count++;
if (flasher->mod_count >= flasher->pattern->mod_period)
{
flasher->mod_count = 0;
flasher->flasher_prescale++;
if (flasher->flasher_prescale >= FLASHER_PRESCALE)
{
flasher->flasher_prescale = 0;
flasher->flasher_count++;
if (flasher->flasher_count >= flasher->pattern->flasher_period)
{
flasher->flasher_count = 0;
flasher->flashes_count++;
if (!flasher->pattern->period)
{
/* One shot mode. */
if (flasher->flashes_count >= flasher->pattern->flashes)
{
/* Disable pattern. */
flasher->pattern = 0;
return 1;
}
}
else if (flasher->flashes_count >= flasher->pattern->period)
{
flasher->flashes_count = 0;
}
}
}
}
return flasher->mod_count < flasher->pattern->mod_duty
&& flasher->flasher_count < flasher->pattern->flasher_duty
&& flasher->flashes_count < flasher->pattern->flashes;
}
/* Create a new flasher device. */
flasher_t
flasher_init (flasher_obj_t *flasher)
{
flasher_pattern_set (flasher, 0);
return flasher;
}
+97
View File
@@ -0,0 +1,97 @@
/** @file flasher.h
@author M. P. Hayes, UCECE
@date 13 March 2005
@brief Combined software PWM and flashing module. Use at your peril!
*/
#ifndef FLASHER_H
#define FLASHER_H
#include "system.h"
/* This parameter is for internal use only. It's purpose is to
reduce the chances of flasher_period and flasher_duty overflow.
It could possibly be made an additional parameter for flasher_pattern_t
and calculated by FLASHER_PATTERN. */
#define FLASHER_PRESCALE 8
/* POLL_RATE (Hz)
MOD_FREQ (Hz)
MOD_DUTY (percent)
FLASHER_PERIOD (s) - period between flashes
FLASHER_DUTY (percent) - proportion of flash period that is lit
FLASHES (integer) - how many flashes per flash pattern
PERIOD (s) - how often the flash pattern repeats
*/
#define FLASHER_PATTERN(POLL_RATE, MOD_FREQ, MOD_DUTY, FLASHER_PERIOD, \
FLASHER_DUTY, FLASHES, PERIOD) \
(POLL_RATE) / (double)(MOD_FREQ) + 0.5, \
(POLL_RATE) * (double)(MOD_DUTY) / (MOD_FREQ) / 100.0 + 0.5, \
(MOD_FREQ) * (FLASHER_PERIOD) / (double)FLASHER_PRESCALE + 0.5, \
(MOD_FREQ) * (FLASHER_PERIOD) * (FLASHER_DUTY) / 100.0 / FLASHER_PRESCALE + 0.5, \
(FLASHES), \
(PERIOD) / (double)(FLASHER_PERIOD) + 0.5
typedef struct
{
/* This is the modulation period. It determines the frequency
of a tone or flicker rate of a LED. */
uint8_t mod_period;
/* This is the modulation duty. It determines the luminance of a LED. */
uint8_t mod_duty;
/* This is the period between the start of two flashes in a sequence. */
uint8_t flasher_period;
/* This is the flash period. */
uint8_t flasher_duty;
/* This is the number of flashes in the sequence. */
uint8_t flashes;
/* This is the number of flasher periods before the sequence repeats. */
uint8_t period;
} flasher_pattern_t;
#define FLASHER_ACTIVE_P(FLASHER) \
(((flasher_obj_t *)(FLASHER))->pattern != 0)
#define FLASHER_PATTERN_FLASHES_SET(PATTERN, FLASHES) \
(PATTERN)->flashes = (FLASHES)
/* This structure is defined here so the compiler can allocate enough
memory for it. However, its fields should be treated as
private. */
typedef struct
{
flasher_pattern_t *pattern;
uint8_t mod_count;
uint8_t flasher_count;
uint8_t flashes_count;
uint8_t flasher_prescale;
} flasher_private_t;
typedef flasher_private_t flasher_obj_t;
typedef flasher_obj_t *flasher_t;
extern int8_t
flasher_pattern_set (flasher_t flasher, flasher_pattern_t *pattern);
extern flasher_pattern_t *
flasher_pattern_get (flasher_t flasher);
extern int8_t
flasher_phase_set (flasher_t flasher, uint8_t phase);
extern bool
flasher_update (flasher_t);
/* INFO is a pointer into RAM that stores the state of the FLASH.
CFG is a pointer into ROM to define the port the FLASH is connected to.
The returned handle is passed to the other flasher_xxx routines to denote
the FLASH to operate on. */
extern flasher_t
flasher_init (flasher_obj_t *info);
#endif
+363
View File
@@ -0,0 +1,363 @@
/** @file space10.c
@author M. P. Hayes, UCECE
@date 20 April 2007
@brief A simple space invaders game with different difficulty levels
and IR remote control.
@defgroup space10 A simple space invaders game controlled by the @ref spacey_remote1 "spacey_remote1" application.
*/
#include <string.h>
#include "system.h"
#include "display.h"
#include "tinygl.h"
#include "pacer.h"
#include "ir_serial.h"
#include "flasher.h"
#include "spacey.h"
#include "eeprom.h"
#include "uint8toa.h"
#include "../fonts/font3x5_1.h"
#define VERSION "1.6"
/** Define polling rates in Hz. */
enum {LOOP_RATE = 500};
enum {FLASHER_UPDATE_RATE = LOOP_RATE};
enum {GAME_UPDATE_RATE = 100};
enum {GAME_OVER_PERIOD = 2};
/** Define flasher modes. */
static flasher_pattern_t flasher_patterns[] =
{
/** POLL_RATE, MOD_FREQ, MOD_DUTY, FLASHER_PERIOD,
FLASHER_DUTY, FLASHES, PERIOD. */
{FLASHER_PATTERN (FLASHER_UPDATE_RATE, 100, 100, 0.4, 100, 1, 0.4)},
{FLASHER_PATTERN (FLASHER_UPDATE_RATE, 100, 100, 0.4, 100, 1, 0.4)},
{FLASHER_PATTERN (FLASHER_UPDATE_RATE, 200, 100, 0.1, 50, 1, 0.1)},
};
typedef enum {FLASH_MODE_GUN, FLASH_MODE_SHELL,
FLASH_MODE_ALIEN, FLASH_MODE_NUM} flash_mode_t;
typedef enum {STATE_DUMMY, STATE_INIT, STATE_START,
STATE_PLAYING, STATE_OVER,
STATE_READY, STATE_MENU_LEVEL} state_t;
enum {GAME_LEVEL_MAX = 5};
typedef struct
{
uint8_t level;
uint8_t games;
} game_data_t;
/** Draw pixel on display. */
static void
display_handler (void *data, uint8_t col, uint8_t row, spacey_pix_t type)
{
uint8_t *display = data;
uint8_t pixel;
pixel = row * TINYGL_WIDTH + col;
display[pixel] = type;
}
/** Display the game over message. */
static void
game_over_display (char *buffer)
{
char *str = buffer;
strcpy (str, "GAME OVER ");
while (*str)
str++;
*str++ = 'K';
uint8toa (spacey_aliens_killed_get (), str, 0);
while (*str)
str++;
*str++ = 'F';
uint8toa (spacey_shells_fired_get (), str, 0);
tinygl_clear ();
tinygl_text (buffer);
}
static void
game_text_display (uint8_t num, char *buffer, char *msg)
{
char *str = buffer;
while (*msg)
*str++ = *msg++;
uint8toa (num, str, 0);
tinygl_clear ();
tinygl_text (buffer);
}
/** Display the game level of difficulty. */
static void
game_level_display (uint8_t level, char *buffer)
{
game_text_display (level, buffer, "LEVEL");
}
/** Set the game level of difficulty. */
static void
game_level_set (uint8_t level)
{
spacey_options_t options;
uint8_t alien_num = 3;
uint8_t alien_steps = 4;
switch (level)
{
default:
case 0:
options.aliens_wrap = 0;
options.aliens_evasive = 0;
break;
case 1:
options.aliens_wrap = 0;
options.aliens_evasive = 1;
alien_steps = 3;
break;
case 2:
options.aliens_wrap = 1;
options.aliens_evasive = 0;
alien_steps = 3;
break;
case 3:
options.aliens_wrap = 1;
options.aliens_evasive = 1;
alien_steps = 3;
break;
case 4:
options.aliens_wrap = 1;
options.aliens_evasive = 1;
alien_steps = 3;
alien_num = 4;
break;
case 5:
options.aliens_wrap = 1;
options.aliens_evasive = 1;
alien_steps = 2;
alien_num = 4;
break;
}
spacey_alien_num_set (alien_num);
spacey_alien_create_steps_set (alien_steps);
spacey_options_set (options);
}
static void
game_start (game_data_t *data)
{
tinygl_clear ();
data->games++;
game_level_set (data->level);
spacey_start ();
eeprom_write (0, data, sizeof (*data));
}
void game_event (__unused__ void *data, spacey_event_t event)
{
ir_serial_transmit (event);
}
int
main (void)
{
uint8_t game_ticks;
uint8_t game_over_ticks;
state_t state = STATE_INIT;
flasher_t flashers[SPACEY_PIX_TYPE_NUM];
uint8_t flasher_state[SPACEY_PIX_TYPE_NUM];
flasher_obj_t flashers_info[SPACEY_PIX_TYPE_NUM];
uint8_t display[TINYGL_WIDTH * TINYGL_HEIGHT];
uint8_t i;
uint8_t j;
game_data_t data;
char message[44];
ir_serial_ret_t ret;
uint8_t ir_data;
system_init ();
/* The first time EEPROM is read all the bytes are 0xFF so set to
sensible defaults. */
eeprom_read (0, &data, sizeof (data));
if (data.level == 0xff)
{
data.level = 0;
data.games = 0;
}
for (i = 0; i < ARRAY_SIZE (flashers); i++)
{
flashers[i] = flasher_init (&flashers_info[i]);
flasher_state[i] = 0;
}
for (i = 0; i < ARRAY_SIZE (display); i++)
display[i] = 0;
/* Set up flash patterns for different pixel types. */
flasher_pattern_set (flashers[SPACEY_PIX_GUN],
&flasher_patterns[FLASH_MODE_GUN]);
flasher_pattern_set (flashers[SPACEY_PIX_SHELL],
&flasher_patterns[FLASH_MODE_SHELL]);
flasher_pattern_set (flashers[SPACEY_PIX_ALIEN],
&flasher_patterns[FLASH_MODE_ALIEN]);
tinygl_init (LOOP_RATE);
tinygl_font_set (&font3x5_1);
tinygl_text_mode_set (TINYGL_TEXT_MODE_SCROLL_LEFT);
tinygl_text_mode_set (TINYGL_TEXT_MODE_ROTATE_SCROLL_DOWN);
tinygl_text_speed_set (10);
spacey_init (GAME_UPDATE_RATE, TINYGL_WIDTH, TINYGL_HEIGHT,
display_handler, display);
spacey_event_handler_set (game_event, 0);
game_ticks = 0;
game_over_ticks = 0;
pacer_init (LOOP_RATE);
while (1)
{
pacer_wait ();
if (state == STATE_PLAYING)
{
uint8_t *src;
/* Update flasher states. NB, the first flasher is always off. */
for (i = 1; i < ARRAY_SIZE (flashers); i++)
flasher_state[i] = flasher_update (flashers[i]);
/* Update display. */
src = display;
for (j = 0; j < TINYGL_HEIGHT; j++)
for (i = 0; i < TINYGL_WIDTH; i++)
{
tinygl_point_t point = {i, j};
tinygl_draw_point (point, flasher_state[*src++]);
}
}
/* Advance messages and refresh display. */
tinygl_update ();
game_ticks++;
if (game_ticks >= LOOP_RATE / GAME_UPDATE_RATE)
{
game_ticks = 0;
switch (state)
{
case STATE_PLAYING:
if (! spacey_update ())
{
game_over_display (message);
game_over_ticks = 0;
state = STATE_OVER;
}
break;
case STATE_INIT:
tinygl_text ("SPACEY READY V" VERSION " BY MPH ");
state = STATE_READY;
break;
case STATE_OVER:
game_over_ticks ++;
if (game_over_ticks >= GAME_UPDATE_RATE * GAME_OVER_PERIOD)
state = STATE_READY;
/* Fall through. */
case STATE_READY:
case STATE_MENU_LEVEL:
default:
break;
case STATE_START:
/* Turn that bloody blimey space invader off... */
game_start (&data);
state = STATE_PLAYING;
break;
}
}
ret = ir_serial_receive (&ir_data);
if (ret == IR_SERIAL_OK)
{
if (ir_data == 1)
{
switch (state)
{
case STATE_READY:
state = STATE_MENU_LEVEL;
game_level_display (data.level, message);
break;
case STATE_MENU_LEVEL:
state = STATE_INIT;
break;
case STATE_PLAYING:
spacey_gun_move_right ();
break;
default:
break;
}
}
if (ir_data == 2)
{
switch (state)
{
case STATE_READY:
state = STATE_START;
break;
case STATE_PLAYING:
spacey_gun_fire ();
break;
case STATE_MENU_LEVEL:
data.level++;
if (data.level > GAME_LEVEL_MAX)
data.level = 0;
game_level_display (data.level, message);
break;
default:
break;
}
}
}
}
}
+578
View File
@@ -0,0 +1,578 @@
/** @file spacey.c
@author M. P. Hayes, UCECE
@date 13 March 2007
@brief This implements a simple space invaders game.
*/
#include <stdlib.h>
#include "spacey.h"
/* This function implements a simple space invades program. Aliens
randomly appear on the top row of the display and work their way
randomly down the display. The game ends when 5 aliens have
reached the bottom of the display. To kill the aliens, shells can
be fired at them from a gun on the bottom of the display. The gun
can only move across the bottom and when it gets to the side it
wraps around to the other side.
The aliens could move at different speeds but currently they are
set at the same speed to keep things simple.
*/
#ifndef DISPLAY_INTERLACE
#define DISPLAY_INTERLACE 0
#endif
#if DISPLAY_INTERLACE
/* With an interlaced display we do not have odd numbered rows and
columns. */
enum {SPACEY_SHELL_INC = 2, SPACEY_GUN_INC = 2};
#else
enum {SPACEY_SHELL_INC = 1, SPACEY_GUN_INC = 1};
#endif
enum {SPACEY_LIVES_DEFAULT = 5};
enum {SPACEY_SHELL_SPEED_DEFAULT = 16};
enum {SPACEY_ALIEN_SPEED_DEFAULT = 2};
enum {SPACEY_ALIEN_CREATE_STEPS_DEFAULT = 4};
enum {SPACEY_ALIEN_NUM_DEFAULT = 3};
enum {SPACEY_SHELL_NUM_DEFAULT = 2};
#define min(x, y) ((x) < (y) ? (x) : (y))
static spacey_t spacey_data;
static spacey_t * const spacey = &spacey_data;
void
spacey_lives_set (uint8_t lives)
{
spacey->lives = lives;
}
void
spacey_alien_speed_set (uint8_t alien_speed)
{
spacey->aliens.move_period = spacey->poll_rate / alien_speed;
}
void
spacey_shell_speed_set (uint8_t shell_speed)
{
spacey->shells.move_period = spacey->poll_rate / shell_speed;
}
void
spacey_alien_create_steps_set (uint8_t alien_create_steps)
{
spacey->alien_create_steps = alien_create_steps;
}
void
spacey_alien_num_set (uint8_t aliens_num)
{
spacey->aliens.num = min (aliens_num, SPACEY_ALIENS_MAX);
}
void
spacey_shell_num_set (uint8_t shells_num)
{
spacey->shells.num = min (shells_num, SPACEY_SHELLS_MAX);
}
void
spacey_options_set (spacey_options_t options)
{
spacey->options = options;
}
void
spacey_init (uint16_t poll_rate,
uint8_t x_size, uint8_t y_size,
void (*display_handler) (void *data, uint8_t row, uint8_t col,
spacey_pix_t type),
void *display_data)
{
spacey->size.x = x_size;
spacey->size.y = y_size;
spacey->display_hook = display_handler;
spacey->display_data = display_data;
spacey->active = 0;
spacey->poll_rate = poll_rate;
spacey->event_hook = NULL;
spacey->options.aliens_wrap = 0;
spacey->options.aliens_evasive = 0;
spacey_alien_num_set (SPACEY_ALIEN_NUM_DEFAULT);
spacey_shell_num_set (SPACEY_SHELL_NUM_DEFAULT);
spacey_shell_speed_set (SPACEY_SHELL_SPEED_DEFAULT);
spacey_alien_speed_set (SPACEY_ALIEN_SPEED_DEFAULT);
spacey_alien_create_steps_set (SPACEY_ALIEN_CREATE_STEPS_DEFAULT);
spacey->lives = SPACEY_LIVES_DEFAULT;
}
void
spacey_event_handler_set (void (*event_handler) (void *, spacey_event_t),
void *event_data)
{
spacey->event_hook = event_handler;
spacey->event_data = event_data;
}
static void
spacey_pixel_set (spacey_pos_t *pos,
spacey_pix_t type)
{
spacey->display_hook (spacey->display_data, pos->x, pos->y, type);
}
/* Return if obj is at the same point as another alien. */
static spacey_obj_t *
spacey_alien_conflict_p (spacey_obj_t *obj)
{
int8_t i;
for (i = 0; i < spacey->aliens.num; i++)
{
spacey_obj_t *alien = &spacey->aliens.array[i];
if (!alien->active || alien == obj)
continue;
if (alien->pos.x == obj->pos.x
&& alien->pos.y == obj->pos.y)
return alien;
}
return 0;
}
/* Return if obj is at the same point as another shell. */
static spacey_obj_t *
spacey_shell_conflict_p (spacey_obj_t *obj)
{
int8_t i;
for (i = 0; i < spacey->shells.num; i++)
{
spacey_obj_t *shell = &spacey->shells.array[i];
if (!shell->active || shell == obj)
continue;
if (shell->pos.x == obj->pos.x
&& shell->pos.y == obj->pos.y)
return shell;
}
return 0;
}
static void
spacey_gun_move (int8_t inc)
{
int8_t gun_x;
spacey_pixel_set (&spacey->gun, SPACEY_PIX_OFF);
gun_x = spacey->gun.x + inc;
if (gun_x >= spacey->size.x)
gun_x = 0;
else if (gun_x < 0)
gun_x = spacey->size.x - 1;
spacey->gun.x = gun_x;
spacey_pixel_set (&spacey->gun, SPACEY_PIX_GUN);
}
/* Return true if move off display. */
static bool
spacey_shell_move (spacey_obj_t *shell)
{
/* Erase the previous position of the shell except if still
at gun. */
if (shell->pos.x != spacey->gun.x
|| shell->pos.y != spacey->gun.y)
spacey_pixel_set (&shell->pos, SPACEY_PIX_OFF);
/* Shells only go straight up. */
shell->pos.y -= SPACEY_SHELL_INC;
if (shell->pos.y < 0)
return 1;
spacey_pixel_set (&shell->pos, SPACEY_PIX_SHELL);
return 0;
}
static void
spacey_alien_erase (spacey_obj_t *alien)
{
spacey_pixel_set (&alien->pos, SPACEY_PIX_OFF);
}
/* Return true if move off display or get to the bottom. */
static bool
spacey_alien_move (spacey_obj_t *alien)
{
int8_t x_jump;
/* Aliens move down randomly zig zagging. */
alien->pos.y++;
/* Randomly move left or right. */
x_jump = 2 * (rand () & 1) - 1;
/* Don't move into line of gun if being evasive. */
if (spacey->options.aliens_evasive &&
spacey->gun.x == alien->pos.x + x_jump)
x_jump = -x_jump;
alien->pos.x += x_jump;
/* Keep the alien within bounds. */
if (alien->pos.x < 0 || alien->pos.x >= spacey->size.x)
{
if (spacey->options.aliens_wrap)
alien->pos.x = spacey->size.x - abs (alien->pos.x);
else
alien->pos.x -= 2 * x_jump;
}
if (alien->pos.y < spacey->size.y)
spacey_pixel_set (&alien->pos, SPACEY_PIX_ALIEN);
if (alien->pos.y >= (spacey->size.y - 1))
return 1;
return 0;
}
static void
spacey_alien_create (void)
{
int8_t i;
for (i = 0; i < spacey->aliens.num; i++)
{
spacey_obj_t *alien = &spacey->aliens.array[i];
if (alien->active)
continue;
/* Aliens start at the top. */
alien->pos.y = 0;
while (1)
{
/* Choose random x position. */
alien->pos.x = rand () % spacey->size.x;
#if DISPLAY_INTERLACE
/* Ensure x position is even. */
alien->pos.x &= ~1;
#endif
alien->active = 1;
/* Ensure aliens start at different spots to be fair! */
if (!spacey_alien_conflict_p (alien))
break;
}
spacey->stats.aliens_live++;
spacey_pixel_set (&alien->pos, SPACEY_PIX_ALIEN);
return;
}
/* If we get to here then we already have too many aliens. */
}
static void
spacey_shell_create (void)
{
int8_t i;
for (i = 0; i < spacey->shells.num; i++)
{
spacey_obj_t *shell = &spacey->shells.array[i];
if (shell->active)
continue;
shell->pos = spacey->gun;
shell->active = 1;
spacey->stats.shells_fired++;
/* Don't turn shell on initially since it will erase the gun. */
return;
}
/* If we get to here then we already have too many shells. */
}
static void
spacey_alien_kill (spacey_obj_t *alien)
{
alien->active = 0;
spacey->stats.aliens_live--;
}
static void
spacey_shell_kill (spacey_obj_t *shell)
{
shell->active = 0;
}
static void
spacey_event (spacey_event_t event)
{
if (spacey->event_hook)
spacey->event_hook (spacey->event_data, event);
}
static void
spacey_alien_hit (spacey_obj_t *alien, spacey_obj_t *shell)
{
spacey_alien_kill (alien);
spacey->stats.aliens_killed++;
spacey_shell_kill (shell);
spacey_pixel_set (&shell->pos, SPACEY_PIX_OFF);
spacey_event (SPACEY_EVENT_ALIEN_HIT);
}
static void
spacey_alien_landed (void)
{
spacey->stats.aliens_landed++;
if (spacey->stats.aliens_landed >= spacey->lives)
spacey->active = 0;
spacey_event (SPACEY_EVENT_ALIEN_LANDED);
}
static void
spacey_shells_move (void)
{
int8_t i;
spacey->shells.move_clock++;
if (spacey->shells.move_clock < spacey->shells.move_period)
return;
spacey->shells.move_clock = 0;
/* Shells move until they hit an alien or move off the display. */
for (i = 0; i < spacey->shells.num; i++)
{
spacey_obj_t *shell = &spacey->shells.array[i];
if (!shell->active)
continue;
if (spacey_shell_move (shell))
spacey_shell_kill (shell);
else
{
spacey_obj_t *alien;
/* Check if we've hit an alien. */
while ((alien = spacey_alien_conflict_p (shell)))
{
/* We've hit an alien so kill it and the shell. */
spacey_alien_hit (alien, shell);
}
}
}
}
static void
spacey_aliens_move (void)
{
int8_t i;
uint8_t steps;
spacey->aliens.move_clock++;
if (spacey->aliens.move_clock < spacey->aliens.move_period)
return;
spacey->aliens.move_clock = 0;
/* Erase all aliens before moving them. */
for (i = 0; i < spacey->aliens.num; i++)
{
spacey_obj_t *alien = &spacey->aliens.array[i];
if (!alien->active)
continue;
spacey_alien_erase (alien);
}
/* Now move and redraw aliens. */
for (i = 0; i < spacey->aliens.num; i++)
{
spacey_obj_t *alien = &spacey->aliens.array[i];
if (!alien->active)
continue;
if (spacey_alien_move (alien))
{
if (alien->pos.y == spacey->gun.y)
{
/* The alien has reached Earth. */
spacey_alien_landed ();
}
else
{
/* The alien has moved off the display so disable it. */
spacey_alien_kill (alien);
/* Redraw the gun in case it got hit by the alien. */
spacey_pixel_set (&spacey->gun, SPACEY_PIX_GUN);
}
}
else
{
spacey_obj_t *shell;
while ((shell = spacey_shell_conflict_p (alien)))
{
/* The alien hit a shell so kill it and the shell. */
spacey_alien_hit (alien, shell);
}
}
}
/* Randomly create an alien. If there are no aliens create a new
one more rapidly. */
if (!spacey->stats.aliens_live)
steps = 2;
else
steps = spacey->alien_create_steps;
if ((rand () % steps) == 0)
spacey_alien_create ();
}
/* Update the state of the game. */
bool
spacey_update (void)
{
/* Allow playing with the gun even if game inactive. */
spacey_shells_move ();
if (!spacey->active)
return 0;
spacey_aliens_move ();
return 1;
}
/* Move the gun position to the right wrapping back around on left. */
void
spacey_gun_move_right (void)
{
spacey_gun_move (SPACEY_GUN_INC);
}
/* Move the gun position to the left wrapping back around on right. */
void
spacey_gun_move_left (void)
{
spacey_gun_move (-SPACEY_GUN_INC);
}
/* Fire the gun. */
void
spacey_gun_fire (void)
{
spacey_shell_create ();
}
/* Start a new game. */
void
spacey_start (void)
{
int8_t i;
int8_t j;
spacey->shells.move_clock = 0;
spacey->aliens.move_clock = 0;
for (i = 0; i < spacey->shells.num; i++)
{
spacey_obj_t *shell = &spacey->shells.array[i];
shell->active = 0;
}
for (i = 0; i < spacey->aliens.num; i++)
{
spacey_obj_t *alien = &spacey->aliens.array[i];
alien->active = 0;
}
/* Turn all pixels off. */
for (i = 0; i < spacey->size.x; i++)
for (j = 0; j < spacey->size.y; j++)
{
spacey_pos_t pos = {i, j};
spacey_pixel_set (&pos, SPACEY_PIX_OFF);
}
/* Display gun in centre of display. */
spacey->gun.x = (spacey->size.x / 2) & ~1;
spacey->gun.y = spacey->size.y - 1;
spacey_pixel_set (&spacey->gun, SPACEY_PIX_GUN);
spacey->stats.aliens_live = 0;
spacey->stats.aliens_killed = 0;
spacey->stats.aliens_landed = 0;
spacey->stats.shells_fired = 0;
spacey->active = 1;
}
uint8_t
spacey_aliens_killed_get (void)
{
return spacey->stats.aliens_killed;
}
uint8_t
spacey_shells_fired_get (void)
{
return spacey->stats.shells_fired;
}
+152
View File
@@ -0,0 +1,152 @@
/** @file spacey.h
@author M. P. Hayes, UCECE
@date 13 March 2007
@brief This is the interface for a simple space invaders game.
*/
#ifndef SPACEY_H
#define SPACEY_H
#include "system.h"
enum {SPACEY_ALIENS_MAX = 4, SPACEY_SHELLS_MAX = 4};
typedef enum {SPACEY_PIX_OFF, SPACEY_PIX_GUN, SPACEY_PIX_ALIEN,
SPACEY_PIX_SHELL, SPACEY_PIX_TYPE_NUM} spacey_pix_t;
typedef enum {SPACEY_EVENT_ALIEN_HIT, SPACEY_EVENT_ALIEN_LANDED} spacey_event_t;
typedef enum {SPACEY_ALIEN, SPACEY_SHELL} spacey_type_t;
/* Positions must be signed. */
typedef struct
{
int8_t x;
int8_t y;
} spacey_pos_t;
typedef struct
{
spacey_pos_t pos;
bool active;
} spacey_obj_t;
typedef struct
{
spacey_obj_t array[SPACEY_ALIENS_MAX];
uint8_t num;
uint16_t move_period;
uint16_t move_clock;
} spacey_objs_t;
typedef struct
{
uint8_t aliens_killed;
uint8_t aliens_landed;
uint8_t shells_fired;
uint8_t aliens_live;
} spacey_stats_t;
typedef struct
{
int aliens_wrap:1;
int aliens_evasive:1;
} spacey_options_t;
typedef struct
{
/* If we have lots of objects then a linked list would be more
efficient for the aliens and shells. */
spacey_objs_t aliens;
spacey_objs_t shells;
spacey_pos_t gun;
spacey_pos_t size;
spacey_stats_t stats;
uint16_t poll_rate; /* Hz */
uint8_t alien_create_steps;
uint8_t lives;
void (*display_hook) (void *data, uint8_t row, uint8_t col, spacey_pix_t type);
void *display_data;
void (*event_hook) (void *data, spacey_event_t event);
void *event_data;
spacey_options_t options;
bool active;
} spacey_t;
void
spacey_event_handler_set (void (*event_handler) (void *, spacey_event_t),
void *event_data);
void
spacey_init (uint16_t poll_rate,
uint8_t x_size, uint8_t y_size,
void (*display_handler) (void *data, uint8_t row, uint8_t col,
spacey_pix_t type),
void *display_data);
/** Start a new game. */
void
spacey_start (void);
/** Update state of game. */
bool
spacey_update (void);
/** Specify number of lives we have before we die. */
void
spacey_lives_set (uint8_t lives);
/** Set alien speed in Hz. */
void
spacey_alien_speed_set (uint8_t alien_speed);
/** Set shell speed in Hz. */
void
spacey_shell_speed_set (uint8_t shell_speed);
/** Set number of steps that a new alien is created on average. */
void
spacey_alien_create_steps_set (uint8_t alien_create_steps);
/** Set maximum number of aliens on display at once. */
void
spacey_alien_num_set (uint8_t aliens_num);
/** Set maximum number of shells on display at once. */
void
spacey_shell_num_set (uint8_t shells_num);
/** Set game options. */
void
spacey_options_set (spacey_options_t options);
/** Move gun to right. */
void
spacey_gun_move_right (void);
/** Move gun to left. */
void
spacey_gun_move_left (void);
/** Fire gun. */
void
spacey_gun_fire (void);
/** Return number of aliens killed in current game. */
uint8_t
spacey_aliens_killed_get (void);
/** Return number of shells fired in current game. */
uint8_t
spacey_shells_fired_get (void);
#endif
+6
View File
@@ -0,0 +1,6 @@
/** @file ticker.c
@author M. P. Hayes, UCECE
@date 2 April 2007
@brief
*/
+45
View File
@@ -0,0 +1,45 @@
/** @file ticker.h
@author M. P. Hayes, UCECE
@date 2 April 2007
@brief
*/
#ifndef TICKER_H
#define TICKER_H
#include <config.h>
typedef struct
{
uint16_t period;
uint16_t clock;
} ticker_t;
typedef struct
{
uint16_t period;
uint16_t clock;
} ticker16_t;
typedef struct
{
uint8_t period;
uint8_t clock;
} ticker8_t;
#define TICKER_INIT(DEV, PERIOD) \
(DEV)->period = (PERIOD); \
(DEV)->clock = (DEV)->period;
/* Return non-zero when the ticker rolls over otherwise return 0. */
#define TICKER_UPDATE(DEV) \
(--(DEV)->clock ? 0 : ((DEV)->clock = (DEV)->period))
#define TICKER_START(DEV) \
(DEV)->clock = (DEV)->period;
#endif