diff --git a/README.md b/README.md index 35f3d6f..61641a0 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ Firmware for AVR based two-dimensional LED matrices, especially the Main platform is the [Borg16](http://www.das-labor.org/wiki/Borg16) construction kit. Other supported platforms are the [LED Brett](http://www.hackerspace-ffm.de/wiki/index.php?title=LedBrett) -projector from [Hackerspace FFM](http://www.hackerspace-ffm.de) or the -[ELO Ping-Pong Board](http://www.elo-web.de/elo/mikrocontroller-und-programmierung/ping-pong/das-franzis-pingpong). +projector from [Hackerspace FFM](http://www.hackerspace-ffm.de), the +[ELO Ping-Pong Board](http://www.elo-web.de/elo/mikrocontroller-und-programmierung/ping-pong/das-franzis-pingpong) +or the [LoL Shield](http://jimmieprodgers.com/kits/lolshield/) from Jimmie P. +Rodgers. ![Small Borg16](/doc/img/Borg16-small.jpg) ![Glow Lamp Borg](/doc/img/Glow_Lamp_Borg.jpg) diff --git a/config.in b/config.in index 57cb324..6ed2601 100644 --- a/config.in +++ b/config.in @@ -7,12 +7,19 @@ comment "General Setup" choice 'Target MCU' \ "ATmega8 atmega8 \ + ATmega16 atmega16 \ + ATmega168 atmega168 \ + ATmega168P atmega168p \ ATmega32 atmega32 \ + ATmega32U4 atmega32u4 \ ATmega328 atmega328 \ + ATmega328p atmega328p \ ATmega644 atmega644 \ ATmega644p atmega644p \ + ATmega1280 atmega1280 \ ATmega1284 atmega1284 \ ATmega1284p atmega1284p \ + ATmega2560 atmega2560 \ ATmega8515 atmega8515" \ 'ATmega32' MCU diff --git a/defaults.mk b/defaults.mk index 129e2c5..3bbed3d 100644 --- a/defaults.mk +++ b/defaults.mk @@ -104,10 +104,14 @@ include $(MAKETOPDIR)/.config CPPFLAGS += -DF_CPU=$(FREQ)UL -mmcu=$(MCU) # flags for the linker, choose appropriate linker script -ifeq ($(findstring atmega128,$(MCU)),atmega128) - LDFLAGS += -T ld_scripts/avr51.x -Wl,-Map,image.map -mmcu=$(MCU) +ifeq ($(findstring atmega256,$(MCU)),atmega256) + LDFLAGS += -T ld_scripts/avr6.x -Wl,-Map,image.map -mmcu=$(MCU) else - LDFLAGS += -T ld_scripts/avr5.x -Wl,-Map,image.map -mmcu=$(MCU) + ifeq ($(findstring atmega128,$(MCU)),atmega128) + LDFLAGS += -T ld_scripts/avr51.x -Wl,-Map,image.map -mmcu=$(MCU) + else + LDFLAGS += -T ld_scripts/avr5.x -Wl,-Map,image.map -mmcu=$(MCU) + endif endif endif # MAKECMDGOALS!=menuconfig diff --git a/ld_scripts/avr51.x b/ld_scripts/avr51.x index a16ad36..3be4c35 100644 --- a/ld_scripts/avr51.x +++ b/ld_scripts/avr51.x @@ -4,7 +4,7 @@ OUTPUT_ARCH(avr:51) MEMORY { text (rx) : ORIGIN = 0, LENGTH = 128K - data (rw!x) : ORIGIN = 0x800060, LENGTH = 0xffa0 + data (rw!x) : ORIGIN = 0x800100, LENGTH = 0xff00 eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K fuse (rw!x) : ORIGIN = 0x820000, LENGTH = 1K lock (rw!x) : ORIGIN = 0x830000, LENGTH = 1K diff --git a/ld_scripts/avr6.x b/ld_scripts/avr6.x new file mode 100644 index 0000000..26db017 --- /dev/null +++ b/ld_scripts/avr6.x @@ -0,0 +1,231 @@ +/* Default linker script, for normal executables */ +OUTPUT_FORMAT("elf32-avr","elf32-avr","elf32-avr") +OUTPUT_ARCH(avr:6) +MEMORY +{ + text (rx) : ORIGIN = 0, LENGTH = 1024K + data (rw!x) : ORIGIN = 0x800200, LENGTH = 0xfe00 + eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = 64K + fuse (rw!x) : ORIGIN = 0x820000, LENGTH = 1K + lock (rw!x) : ORIGIN = 0x830000, LENGTH = 1K + signature (rw!x) : ORIGIN = 0x840000, LENGTH = 1K +} +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.init : { *(.rel.init) } + .rela.init : { *(.rela.init) } + .rel.text : + { + *(.rel.text) + *(.rel.text.*) + *(.rel.gnu.linkonce.t*) + } + .rela.text : + { + *(.rela.text) + *(.rela.text.*) + *(.rela.gnu.linkonce.t*) + } + .rel.fini : { *(.rel.fini) } + .rela.fini : { *(.rela.fini) } + .rel.rodata : + { + *(.rel.rodata) + *(.rel.rodata.*) + *(.rel.gnu.linkonce.r*) + } + .rela.rodata : + { + *(.rela.rodata) + *(.rela.rodata.*) + *(.rela.gnu.linkonce.r*) + } + .rel.data : + { + *(.rel.data) + *(.rel.data.*) + *(.rel.gnu.linkonce.d*) + } + .rela.data : + { + *(.rela.data) + *(.rela.data.*) + *(.rela.gnu.linkonce.d*) + } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + /* Internal text space or external memory. */ + .text : + { + *(.vectors) + KEEP(*(.vectors)) + /* For data that needs to reside in the lower 64k of progmem. */ + *(.progmem.gcc*) + *(.progmem*) + . = ALIGN(2); + __trampolines_start = . ; + /* The jump trampolines for the 16-bit limited relocs will reside here. */ + *(.trampolines) + *(.trampolines*) + __trampolines_end = . ; + /* For future tablejump instruction arrays for 3 byte pc devices. + We don't relax jump/call instructions within these sections. */ + *(.jumptables) + *(.jumptables*) + /* For code that needs to reside in the lower 128k progmem. */ + *(.lowtext) + *(.lowtext*) + __ctors_start = . ; + *(.ctors) + __ctors_end = . ; + __dtors_start = . ; + *(.dtors) + __dtors_end = . ; + KEEP(SORT(*)(.ctors)) + KEEP(SORT(*)(.dtors)) + /* From this point on, we don't bother about wether the insns are + below or above the 16 bits boundary. */ + *(.init0) /* Start here after reset. */ + KEEP (*(.init0)) + *(.init1) + KEEP (*(.init1)) + *(.init2) /* Clear __zero_reg__, set up stack pointer. */ + KEEP (*(.init2)) + *(.init3) + KEEP (*(.init3)) + *(.init4) /* Initialize data and BSS. */ + KEEP (*(.init4)) + *(.init5) + KEEP (*(.init5)) + *(.init6) /* C++ constructors. */ + KEEP (*(.init6)) + *(.init7) + KEEP (*(.init7)) + *(.init8) + KEEP (*(.init8)) + *(.init9) /* Call main(). */ + KEEP (*(.init9)) + *(.text) + . = ALIGN(2); + *(.text.*) + . = ALIGN(2); + *(.fini9) /* _exit() starts here. */ + KEEP (*(.fini9)) + *(.fini8) + KEEP (*(.fini8)) + *(.fini7) + KEEP (*(.fini7)) + *(.fini6) /* C++ destructors. */ + KEEP (*(.fini6)) + *(.fini5) + KEEP (*(.fini5)) + *(.fini4) + KEEP (*(.fini4)) + *(.fini3) + KEEP (*(.fini3)) + *(.fini2) + KEEP (*(.fini2)) + *(.fini1) + KEEP (*(.fini1)) + *(.fini0) /* Infinite loop after program termination. */ + KEEP (*(.fini0)) + _etext = . ; + } > text + .data : AT (ADDR (.text) + SIZEOF (.text)) + { + PROVIDE (__data_start = .) ; + *(.data) + *(.data*) + *(.rodata) /* We need to include .rodata here if gcc is used */ + *(.rodata*) /* with -fdata-sections. */ + *(.gnu.linkonce.d*) + PROVIDE (_game_descriptors_start__ = .) ; + *(.game_descriptors) + PROVIDE (_game_descriptors_end__ = .) ; + . = ALIGN(2); + _edata = . ; + PROVIDE (__data_end = .) ; + } > data + .bss SIZEOF(.data) + ADDR(.data) : + { + PROVIDE (__bss_start = .) ; + *(.bss) + *(.bss*) + *(COMMON) + PROVIDE (__bss_end = .) ; + } > data + __data_load_start = LOADADDR(.data); + __data_load_end = __data_load_start + SIZEOF(.data); + /* Global data not cleared after reset. */ + .noinit SIZEOF(.bss) + ADDR(.bss) : + { + PROVIDE (__noinit_start = .) ; + *(.noinit*) + PROVIDE (__noinit_end = .) ; + _end = . ; + PROVIDE (__heap_start = .) ; + } > data + .eeprom : + { + *(.eeprom*) + __eeprom_end = . ; + } > eeprom + .fuse : + { + KEEP(*(.fuse)) + KEEP(*(.lfuse)) + KEEP(*(.hfuse)) + KEEP(*(.efuse)) + } > fuse + .lock : + { + KEEP(*(.lock*)) + } > lock + .signature : + { + KEEP(*(.signature*)) + } > signature + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } +} diff --git a/profiles/FFM-Jochen b/profiles/FFM-Jochen index f509c24..f7a0072 100644 --- a/profiles/FFM-Jochen +++ b/profiles/FFM-Jochen @@ -37,7 +37,12 @@ SCROLL_X_SPEED=10 SCROLL_Y_SPEED=20 SCROLLTEXT_TEXT="5+:<5|90>6:<6|78>:p10d50/#Labor#<5;>5|30<6;>6|40<6;p10+d50/# Borg#2d50-+/#Widerstand#ist#d50-b20p15#ZWECKLOS !" +# RFM12_SUPPORT is not set + +# +# Joystick Support +# # JOYSTICK_SUPPORT is not set +JOYSTICK_CHOICE="JOY_PARALLEL" CAN_SUPPORT=y SPI_HARDWARE=y SPI_PORTIDX=1 @@ -68,7 +74,8 @@ ANIMATION_SPIRAL=y SPIRAL_DELAY=5 ANIMATION_JOERN1=y ANIMATION_SNAKE=y -SNAKE_CYCLE_DELAY=50 +SNAKE_GAME_DELAY=200 +SNAKE_ANIM_DELAY=50 SNAKE_TERMINATION_DELAY=60 SNAKE_MAX_LENGTH=64 SNAKE_MAX_APPLES=10 @@ -91,6 +98,7 @@ GOL_DELAY=12 GOL_CYCLES=180 # ANIMATION_BREAKOUT is not set # ANIMATION_MHERWEG is not set +# ANIMATION_MOIRE is not set # ANIMATION_LTN_ANT is not set ANIMATION_TIME=y TIME_MASTER_ADDR=00 @@ -99,9 +107,17 @@ TIME_UPDATE_TIMEOUT=50 # ANIMATION_LABORLOGO is not set # ANIMATION_AMPHIBIAN is not set # ANIMATION_LOGO_OOS is not set -# ANIMATION_LOGO_28C3 is not set +# ANIMATION_FAIRYDUST is not set + +# +# Fixed-point math patterns +# # ANIMATION_PLASMA is not set +FP_PLASMA_DELAY=1 # ANIMATION_PSYCHEDELIC is not set +FP_PSYCHO_DELAY=15 +# ANIMATION_BLACKHOLE is not set +# ANIMATION_SQUARES is not set ANIMATION_TESTS=y ANIMATION_OFF=y diff --git a/profiles/borgjacke b/profiles/borgjacke index 73bf84b..40057cd 100644 --- a/profiles/borgjacke +++ b/profiles/borgjacke @@ -49,9 +49,12 @@ BIT_MISO=6 BIT_SCK=7 PORT_SS=PORTB BIT_SS=4 + +# +# Joystick Support +# JOYSTICK_SUPPORT=y -# PARALLEL_JOYSTICK_SUPPORT is not set -# NES_PAD_SUPPORT is not set +JOYSTICK_CHOICE=JOY_RFM12 RFM12_JOYSTICK_SUPPORT=y # CAN_SUPPORT is not set MENU_SUPPORT=y @@ -65,7 +68,7 @@ GAME_TETRIS=y # GAME_TETRIS_FP is not set GAME_SPACE_INVADERS=y GAME_SNAKE=y -# GAME_BREAKOUT is not set +GAME_BREAKOUT=y # # Animations @@ -75,7 +78,8 @@ ANIMATION_SPIRAL=y SPIRAL_DELAY=5 ANIMATION_JOERN1=y ANIMATION_SNAKE=y -SNAKE_CYCLE_DELAY=100 +SNAKE_GAME_DELAY=200 +SNAKE_ANIM_DELAY=100 SNAKE_TERMINATION_DELAY=60 SNAKE_MAX_LENGTH=64 SNAKE_MAX_APPLES=10 @@ -91,14 +95,15 @@ MATRIX_STREAMER_NUM=30 MATRIX_CYCLES=500 MATRIX_DELAY=60 ANIMATION_RANDOM_BRIGHT=y -# ANIMATION_STONEFLY is not set -# ANIMATION_FLYINGDOTS is not set +ANIMATION_STONEFLY=y +ANIMATION_FLYINGDOTS=y ANIMATION_GAMEOFLIFE=y GOL_DELAY=100 GOL_CYCLES=360 -# ANIMATION_BREAKOUT is not set +ANIMATION_BREAKOUT=y # ANIMATION_MHERWEG is not set -# ANIMATION_LTN_ANT is not set +ANIMATION_MOIRE=y +ANIMATION_LTN_ANT=y # ANIMATION_TIME is not set TIME_MASTER_ADDR=0x00 TIME_UPDATE_TIMEOUT=23 @@ -107,9 +112,16 @@ ANIMATION_LABORLOGO=y # ANIMATION_AMPHIBIAN is not set # ANIMATION_LOGO_OOS is not set # ANIMATION_FAIRYDUST is not set + +# +# Fixed-point math patterns +# ANIMATION_PLASMA=y +FP_PLASMA_DELAY=1 ANIMATION_PSYCHEDELIC=y -# ANIMATION_BLACKHOLE is not set +FP_PSYCHO_DELAY=15 +ANIMATION_BLACKHOLE=y +ANIMATION_SQUARES=y ANIMATION_TESTS=y ANIMATION_OFF=y diff --git a/src/animations/blackhole.c b/src/animations/blackhole.c index 436a808..32cc5d1 100644 --- a/src/animations/blackhole.c +++ b/src/animations/blackhole.c @@ -54,7 +54,8 @@ static signed char cos_i(unsigned char const angle) { #define NUM_CIRCLE 7 - +#define W (NUM_COLS * 4) +#define H (NUM_ROWS * 4) /** * Draws a black hole like pattern (viewed from different perspectives). @@ -71,8 +72,8 @@ void blackhole(void) { for (signed char j = 0; j < 64; j += 8) { signed char a = (j & 0x08) ? 0 : 4; pixel p; - p.x = (64 + cos_i(angle + j + a) * helpRadius / 64) >> 3; - p.y = (64 + sin_i(angle + add + j + a) * helpRadius / 64) >> 3; + p.x = (W + cos_i(angle + j + a) * helpRadius / W) / 8u; + p.y = (H + sin_i(angle + add + j + a) * helpRadius / H) / 8u; if ((p.x < NUM_COLS) && (p.y < NUM_ROWS)) { setpixel(p, 3); } diff --git a/src/animations/config.in b/src/animations/config.in index 2d21fdd..7f9d88c 100644 --- a/src/animations/config.in +++ b/src/animations/config.in @@ -9,7 +9,8 @@ comment "Animations" bool "Joern1" ANIMATION_JOERN1 dep_bool_menu "Snake" ANIMATION_SNAKE $RANDOM_SUPPORT - int "Snake Round Delay" SNAKE_CYCLE_DELAY 100 + int "Snake Game Round Delay" SNAKE_GAME_DELAY 200 + int "Snake Anim Round Delay" SNAKE_ANIM_DELAY 100 int "Snake Termination Delay" SNAKE_TERMINATION_DELAY 60 uint "Snake Max Length" SNAKE_MAX_LENGTH 64 int "Snake Max Apples" SNAKE_MAX_APPLES 10 diff --git a/src/animations/ltn_ant.c b/src/animations/ltn_ant.c index 049f4cc..0cf3d8f 100644 --- a/src/animations/ltn_ant.c +++ b/src/animations/ltn_ant.c @@ -35,73 +35,51 @@ #define NX (UNUM_COLS - 1u) #define NY (UNUM_ROWS - 1u) -#if UNUM_ROWS == UNUM_COLS - static coord_t const dcomp[] = {0, P, NX}; - #define xdcomp dcomp - #define ydcomp dcomp -#else - static coord_t const xdcomp[] = {0, P, NX}; - static coord_t const ydcomp[] = {0, P, NY}; -#endif - +static coord_t const xdcomp[] = {0, NX, 0, P}; +static coord_t const ydcomp[] = {P, 0, NY, 0}; +typedef struct ant_s { + coord_t x, y; /* current postion */ + coord_t ox, oy; /* previous position, used to dim out old pixels */ + unsigned char vector_index; /* index to one of (0,1),(1,0),(0,-1),(-1,0) */ +} ant_t; void ltn_ant() { clear_screen(0); - struct { - coord_t x, y; - coord_t ox, oy; /* Used to set old pixels to brightness 2 */ - coord_t dx, dy; /* Vector can only be (0,1),(1,0),(0,-1),(-1,0) */ - } ant; - - unsigned char temp; + ant_t ant; + unsigned int cycles = 500; - /* Random start position and direction */ - ant.x = random8() % UNUM_COLS; - ant.y = random8() % UNUM_ROWS; + /* random start position and direction */ + ant.x = ant.ox = random8() % UNUM_COLS; + ant.y = ant.oy = random8() % UNUM_ROWS; - /* Make sure we do have a valid vector */ - ant.dx = xdcomp[random8() % 3]; - do { - ant.dy = ydcomp[random8() % 3]; - } while(ant.dx == ant.dy); + /* make sure we have a valid vector */ + ant.vector_index = random8() % 4u; - ant.ox = ant.x; - ant.oy = ant.y; - - while(cycles != 0) { - /* If the pixel is not set turn it on */ + while(cycles--) { + /* if the pixel is turned off turn it on */ if(get_pixel((pixel) {ant.x, ant.y}) == 0) { - setpixel((pixel) {ant.x, ant.y}, 3); - - temp = ant.dx; - ant.dx = ant.dy; - ant.dy = -temp; /* Turn 90 degrees to the right */ - - /* Lets the last pixel be darker than the latest */ - if((ant.ox != ant.x) || (ant.oy != ant.y)) - setpixel((pixel) {ant.ox, ant.oy}, 2); + setpixel((pixel) {ant.x, ant.y}, NUMPLANE); + ant.vector_index = (ant.vector_index + 3u) % 4u; // turn left + /* dim the previous pixel */ + setpixel((pixel){ant.ox, ant.oy}, NUMPLANE - 1); + + /* memorize this position */ ant.ox = ant.x; ant.oy = ant.y; - + /* if the pixel is turned on turn it off */ } else { setpixel((pixel) {ant.x, ant.y}, 0); - - temp = ant.dy; - ant.dy = ant.dx; - ant.dx = -temp; /* Turn 90 degrees to the left */ + ant.vector_index = (ant.vector_index + 1u) % 4u; // turn right } + /* move to next pixel, playing field is modeled after a torus */ + ant.x = (ant.x + xdcomp[ant.vector_index]) % UNUM_COLS; + ant.y = (ant.y + ydcomp[ant.vector_index]) % UNUM_ROWS; + wait(100); - - /* Playing field is modeled after a torus */ - ant.x = (coord_t)(ant.x + ant.dx) % UNUM_COLS; - ant.y = (coord_t)(ant.y + ant.dy) % UNUM_ROWS; - - cycles--; } - wait(300); } diff --git a/src/animations/mherweg.c b/src/animations/mherweg.c index 6f56575..3e98609 100644 --- a/src/animations/mherweg.c +++ b/src/animations/mherweg.c @@ -126,21 +126,29 @@ static void movinglines() */ static void rectangle1() { + // define a sane maximum expansion +#if NUM_COLS < NUM_ROWS +# define RECT_SIZE NUM_COLS +#else +# define RECT_SIZE NUM_ROWS +#endif + // we want a centered square - unsigned char const xcenter = NUM_COLS / 2, ycenter = NUM_ROWS / 2; - // it should be as big as the borg's height - unsigned char size = NUM_ROWS; +#define RECT_OFFSET_X ((UNUM_COLS - RECT_SIZE) / 2u) +#define RECT_OFFSET_Y ((UNUM_ROWS - RECT_SIZE) / 2u) + + unsigned char size = RECT_SIZE; // darkest color as a starting point for the gradient - unsigned char color = 0; + unsigned char color = 1; // wait about 500 ms between each frame int const delay = 500; // create a gradient by drawing shrinking rectangles on top of each other clear_screen(0); - for (unsigned char x = 8; x > 0; x--) + for (unsigned char pos = 0; pos < (RECT_SIZE / 2); ++pos) { // draw the rectangle and wait for a moment - filled_rectangle((pixel){(xcenter - x), (ycenter - x)}, + filled_rectangle((pixel){pos + RECT_OFFSET_X, pos + RECT_OFFSET_Y}, size, size, color); wait(delay); diff --git a/src/animations/moire.c b/src/animations/moire.c index ce35b30..5d47cd6 100644 --- a/src/animations/moire.c +++ b/src/animations/moire.c @@ -25,8 +25,12 @@ void moire(void) { // add rotating color map -#if NUMPLANE == 3 +#if NUMPLANE == 3 && NUM_COLS == 16 && NUM_ROWS == 16 static unsigned char const gradient[] = {0, 1, 2, 3, 2, 1}; +# define WRAP 6u +#elif NUMPLANE == 3 && NUM_COLS == 14 && NUM_ROWS == 9 + static unsigned char const gradient[] = {0, 1, 1, 2, 2, 3, 3, 2, 2, 1, 1}; +# define WRAP 11u #else static unsigned char gradient[NUMPLANE * 2u] = {0}; for (unsigned char i = 1; i <= NUMPLANE; ++i) @@ -34,6 +38,7 @@ void moire(void) gradient[i] = i; gradient[(NUMPLANE * 2) - i] = i; } +# define WRAP (2u * NUMPLANE) #endif unsigned int cycles = 30000; @@ -45,25 +50,25 @@ void moire(void) // walk around the border; do that by mapping a linear increasing value // to appropriate screen coordinates - // first pixel is between top right and top left corner - if (pos < NUM_COLS) + // pixel is between top right and top left corner + if (pos < (NUM_COLS - 1)) { - p1.x = pos; + p1.x = pos + 1; } - // first pixel is between top left and bottom left corner - else if (pos < (NUM_COLS + NUM_ROWS - 1)) + // pixel is between top left and bottom left corner + else if (pos < (NUM_COLS + NUM_ROWS - 2)) { - p1.y = pos - (NUM_COLS - 1); + p1.y = pos - (NUM_COLS - 2); } - // first pixel is between bottom left and bottom right corner - else if (pos < (2 * NUM_COLS + NUM_ROWS - 2)) + // pixel is between bottom left and bottom right corner + else if (pos < (2 * NUM_COLS + NUM_ROWS - 3)) { - p1.x = 2 * NUM_COLS + NUM_ROWS - 3 - pos; + p1.x = 2 * NUM_COLS + NUM_ROWS - 4 - pos; } - // first pixel is between bottom right and top left corner + // pixel is between bottom right and top left corner else { - p1.y = 3 * NUM_COLS + NUM_ROWS - 4 - pos; + p1.y = 2 * NUM_COLS + 2 * NUM_ROWS - 5 - pos; } // second pixel in opposite direction @@ -81,7 +86,7 @@ void moire(void) wait(40); } // ensure the color index keeps within bounds - color_index %= (2u * NUMPLANE); + color_index %= WRAP; } } diff --git a/src/animations/program.c b/src/animations/program.c index 7d0265d..c964731 100644 --- a/src/animations/program.c +++ b/src/animations/program.c @@ -47,45 +47,32 @@ void test_palette2(){ #ifdef ANIMATION_SPIRAL -static void walk(cursor_t* cur, unsigned char steps, int delay){ - unsigned char x; - for(x=steps;x--;){ - set_cursor(cur, next_pixel(cur->pos, cur->dir)); - wait(delay); - } -} - -void spiral(int delay){ +void spiral(int delay) { clear_screen(0); + static signed char const PROGMEM delta[5] = { 0, -1, 0, 1, 0 }; + unsigned char length[2] = { NUM_ROWS, NUM_COLS - 1 }; + unsigned char x = NUM_COLS - 1, y = NUM_ROWS, i = 0; - cursor_t cur; - cur.dir = right; - cur.mode = set; - set_cursor (&cur, (pixel){NUM_COLS-1,0}); - - unsigned char clearbit=0; - while(clearbit == 0){ - - clearbit = 1; - while (!get_next_pixel(cur.pos, cur.dir)){ - clearbit = 0; - walk(&cur, 1, delay); + while (length[i & 0x01]) { + for (unsigned char j = 0; j < length[i & 0x01]; ++j) { + x += pgm_read_byte(&delta[i]); + y += pgm_read_byte(&delta[i + 1]); + setpixel((pixel){x, y}, NUMPLANE); + wait(delay); } - cur.dir = direction_r(cur.dir); + length[i++ & 0x01]--; + i %= 4; } - - cur.mode = clear; - set_cursor(&cur, (pixel){(NUM_COLS/2)-1,(NUM_ROWS/2)-1}); - - for(clearbit=0;clearbit==0;){ - if( get_next_pixel(cur.pos, direction_r(cur.dir)) ){ - cur.dir = direction_r(cur.dir); - } - if( get_next_pixel(cur.pos, cur.dir) == 1 ){ - walk(&cur , 1, delay); - }else{ - clearbit = 1; + i = (i + 2u) % 4u; + while (length[0] <= NUM_ROWS && length[1] < NUM_COLS) { + for (unsigned char j = 0; j < length[i & 0x01]; ++j) { + setpixel((pixel){x, y}, 0); + x += pgm_read_byte(&delta[i]); + y += pgm_read_byte(&delta[i + 1]); + wait(delay); } + length[(i += 3) & 0x01]++; + i %= 4; } } #endif @@ -179,17 +166,18 @@ void fire() * void random_bright(void) * by Daniel Otte */ -void random_bright(unsigned cycles){ - uint8_t t,x,y; - while(cycles--){ - for(y=0; y>0)); - setpixel((pixel){x*4+1, y}, 0x3&(t>>2)); - setpixel((pixel){x*4+2, y}, 0x3&(t>>4)); - setpixel((pixel){x*4+3, y}, 0x3&(t>>6)); +void random_bright(unsigned int cycles) { + while (cycles--) { + for (unsigned char p = NUMPLANE; p--;) { + for (unsigned char y = NUM_ROWS; y--;) { + for (unsigned char x = LINEBYTES; x--;) { + if (p < (NUMPLANE - 1)) { + pixmap[p][y][x] |= pixmap[p + 1][y][x]; + } + pixmap[p][y][x] = random8(); + } } + } wait(200); } } diff --git a/src/borg_hw/Makefile b/src/borg_hw/Makefile index 78c6d38..9be92ba 100644 --- a/src/borg_hw/Makefile +++ b/src/borg_hw/Makefile @@ -27,6 +27,10 @@ ifeq ($(BORG_HW),HW_BORG_MH) SRC = borg_hw_borg_mh.c endif +ifeq ($(BORG_HW),HW_LOLSHIELD) + SRC = borg_hw_lolshield.c +endif + ifeq ($(BORG_HW),HW_BORG_LSJO) SRC = borg_hw_borg_lsjo.c endif diff --git a/src/borg_hw/borg_hw_lolshield.c b/src/borg_hw/borg_hw_lolshield.c new file mode 100644 index 0000000..88a4471 --- /dev/null +++ b/src/borg_hw/borg_hw_lolshield.c @@ -0,0 +1,923 @@ +/** + * @file borg_hw_lolshield.c + * @brief Driver for Jimmie Rodgers' LoL Shield + * @author Christian Kroll + * @author Jimmie Rodgers + * @date 2014 + * @copyright GNU Public License 2 or later + * @see http://jimmieprodgers.com/kits/lolshield/ + * + * This driver is partly based on Jimmie Rodger's LoL Shield Library which + * is available at https://code.google.com/p/lolshield/ (parts of the file + * "Charliplexing.cpp" have been incorporated into this file). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "../config.h" +#include "../makros.h" + +#include +#include +#include +#include +#include +#if NUMPLANE >= 8 +# include +#endif +#include "borg_hw.h" + +// buffer which holds the currently shown frame +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + +// Number of ticks of the prescaled timer per cycle per frame, based on the +// CPU clock speed and the desired frame rate. +#define FRAMERATE 80UL +#define TICKS (F_CPU + 6 * (FRAMERATE << SLOWSCALERSHIFT)) / (12 * (FRAMERATE << SLOWSCALERSHIFT)) +#define CUTOFF(scaler) ((128 * 12 - 6) * FRAMERATE * scaler) + +#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) || defined (__AVR_ATmega8__) +# if F_CPU < CUTOFF(8) +# define FASTPRESCALER (_BV(CS20)) // 1 +# define SLOWPRESCALER (_BV(CS21)) // 8 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 3 +# elif F_CPU < CUTOFF(32) +# define FASTPRESCALER (_BV(CS21)) // 8 +# define SLOWPRESCALER (_BV(CS21) | _BV(CS20)) // 32 +# define FASTSCALERSHIFT 2 +# define SLOWSCALERSHIFT 5 +# elif F_CPU < CUTOFF(64) +# define FASTPRESCALER (_BV(CS21)) // 8 +# define SLOWPRESCALER (_BV(CS22)) // 64 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 6 +# elif F_CPU < CUTOFF(128) +# define FASTPRESCALER (_BV(CS21) | _BV(CS20)) // 32 +# define SLOWPRESCALER (_BV(CS22) | _BV(CS20)) // 128 +# define FASTSCALERSHIFT 2 +# define SLOWSCALERSHIFT 7 +# elif F_CPU < CUTOFF(256) +# define FASTPRESCALER (_BV(CS21) | _BV(CS20)) // 32 +# define SLOWPRESCALER (_BV(CS22) | _BV(CS21)) // 256 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 8 +# elif F_CPU < CUTOFF(1024) +# define FASTPRESCALER (_BV(CS22) | _BV(CS20)) // 128 +# define SLOWPRESCALER (_BV(CS22) | _BV(CS21) | _BV(CS20)) // 1024 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 10 +# else +# error frame rate is too low +# endif +#elif defined (__AVR_ATmega32U4__) +# if F_CPU < CUTOFF(8) +# define FASTPRESCALER (_BV(WGM12) | _BV(CS10)) // 1 +# define SLOWPRESCALER (_BV(WGM12) | _BV(CS11)) // 8 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 3 +# elif F_CPU < CUTOFF(64) +# define FASTPRESCALER (_BV(WGM12) | _BV(CS11)) // 8 +# define SLOWPRESCALER (_BV(WGM12) | _BV(CS11) | _BV(CS10)) // 64 +# define FASTSCALERSHIFT 3 +# define SLOWSCALERSHIFT 6 +# elif F_CPU < CUTOFF(256) +# define FASTPRESCALER (_BV(WGM12) | _BV(CS11) | _BV(CS10)) // 64 +# define SLOWPRESCALER (_BV(WGM12) | _BV(CS12)) // 256 +# define FASTSCALERSHIFT 2 +# define SLOWSCALERSHIFT 8 +# elif F_CPU < CUTOFF(1024) +# define FASTPRESCALER (_BV(WGM12) | _BV(CS12)) // 256 +# define SLOWPRESCALER (_BV(WGM12) | _BV(CS12) | _BV(CS10)) // 1024 +# define FASTSCALERSHIFT 2 +# define SLOWSCALERSHIFT 10 +# else +# error frame rate is too low +# endif +#else +# error no support for this chip +#endif + + +#ifndef BRIGHTNESS +# define BRIGHTNESS 127 /* full brightness by default */ +#elif BRIGHTNESS < 0 || BRIGHTNESS > 127 +# error BRIGHTNESS must be between 0 and 127 +#endif + +#define BRIGHTNESSPERCENT ((BRIGHTNESS * BRIGHTNESS + 8ul) / 16ul) +#define M (TICKS << FASTSCALERSHIFT) * BRIGHTNESSPERCENT /*10b*/ +#define C(x) ((M * (unsigned long)(x * 1024) + (1 << 19)) >> 20) /*10b+10b-20b=0b*/ + +#if NUMPLANE < 8 +uint8_t const prescaler[NUMPLANE + 1] = { + FASTPRESCALER, +# if NUMPLANE >= 2 + FASTPRESCALER, +# endif +# if NUMPLANE >= 3 + FASTPRESCALER, +# endif +# if NUMPLANE >= 4 + FASTPRESCALER, +# endif +# if NUMPLANE >= 5 + FASTPRESCALER, +# endif +# if NUMPLANE >= 6 + FASTPRESCALER, +# endif +# if NUMPLANE >= 7 + FASTPRESCALER, +# endif + SLOWPRESCALER +}; +#else +uint8_t prescaler[NUMPLANE + 1] = {0}; +#endif + +uint8_t counts[NUMPLANE + 1] = {0}; + +/** + * Set the overall brightness of the screen from 0 (off) to 127 (full on). + */ +static void setBrightness() +{ + /* ---- This needs review! Please review. -- thilo */ + // set up page counts + uint8_t i; + + // NOTE: The argument of C() is calculated as follows: + // pow((double)x / (double)NUMPLANE, 1.8) with 0 <= x <= NUMPLANE + // Changing the scale of 1.8 invalidates any tables above! +#if NUMPLANE < 8 + int const temp_counts[NUMPLANE + 1] = { + 0.000000000000000000000000000, +# if NUMPLANE == 2 + C(0.287174588749258719033719), +# elif NUMPLANE == 3 + C(0.138414548846168578011273), + C(0.481987453865643789008288), +# elif NUMPLANE == 4 + C(0.082469244423305887448095), + C(0.287174588749258719033719), + C(0.595813410589956848895099), +# elif NUMPLANE == 5 + C(0.055189186458448592775827), + C(0.192179909437029006191722), + C(0.398723883569384374148115), + C(0.669209313658414961523135), +# elif NUMPLANE == 6 + C(0.039749141141812646682574), + C(0.138414548846168578011273), + C(0.287174588749258719033719), + C(0.481987453865643789008288), + C(0.720234228706005730202833), +# elif NUMPLANE == 7 + C(0.030117819624378608378557), + C(0.104876339357015443964904), + C(0.217591430058779483625031), + C(0.365200625214741059210155), + C(0.545719579451565794947498), + C(0.757697368024318751444923), +# endif + C(1.000000000000000000000000), + }; +#else +# warning "NUMPLANE >= 8 links floating point stuff into the image" + // NOTE: Changing "scale" invalidates any tables above! + const float scale = 1.8f; + int temp_counts[NUMPLANE + 1] = {0}; + + for (i = 1; i < (NUMPLANE + 1); i++) { + temp_counts[i] = C(pow(i / (float)(NUMPLANE), scale)); + } +#endif + + // Compute on time for each of the pages + // Use the fast timer; slow timer is only useful for < 3 shades. + for (i = 0; i < NUMPLANE; i++) { + int interval = temp_counts[i + 1] - temp_counts[i]; + counts[i] = 256 - (interval ? interval : 1); +#if NUMPLANE >= 8 + prescaler[i] = FASTPRESCALER; +#endif + } + + // Compute off time + int interval = TICKS - (temp_counts[i] >> FASTSCALERSHIFT); + counts[i] = 256 - (interval ? interval : 1); +#if NUMPLANE >= 8 + prescaler[i] = SLOWPRESCALER; +#endif +} + +/** + * Distributes the framebuffer content among current cycle pins. + * @param cycle The cycle whose pattern should to be composed. + * @param plane The plane ("page" in LoL Shield lingo) to be drawn. + */ +static void compose_cycle(uint8_t const cycle, uint8_t plane) { + // pointer to corresponding bitmap + uint8_t *const p = &pixmap[plane][0][0]; + +#if defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) +# ifdef __AVR_ATmega1280__ +# warning "BEWARE: Borgware-2D has not been tested on Arduino Mega 1280!" +# endif + + // Set sink pin to Vcc/source, turning off current. + static uint8_t sink_b = 0, sink_e = 0, sink_g = 0, sink_h = 0; + PINB = sink_b; + PINE = sink_e; + PING = sink_g; + PINH = sink_h; + + DDRB &= ~0xf0; + DDRE &= ~0x38; + DDRG &= ~0x20; + DDRH &= ~0x78; + + static uint8_t const PROGMEM sink_b_cycle[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x40, 0x80}; + static uint8_t const PROGMEM sink_e_cycle[] = + {0x10, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t const PROGMEM sink_g_cycle[] = + {0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t const PROGMEM sink_h_cycle[] = + {0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00}; + + uint8_t pins_b = sink_b = pgm_read_byte(&sink_b_cycle[cycle]); + uint8_t pins_e = sink_e = pgm_read_byte(&sink_e_cycle[cycle]); + uint8_t pins_g = sink_g = pgm_read_byte(&sink_g_cycle[cycle]); + uint8_t pins_h = sink_h = pgm_read_byte(&sink_h_cycle[cycle]); + + // convert framebuffer to LoL Shield cycles on Arduino Mega 1280/2560 + // (I could have done this with a lookup table, but that would be slower as + // non-constant bit shifts are quite expensive on AVR) + // NOTE: (0,0) is UPPER RIGHT in the Borgware realm + if (plane < NUMPLANE) { + switch(cycle) { + case 0: + pins_b |= (0x02u & p[ 0]) << 6; // x= 1, y= 0, mapped pin D13 + pins_b |= (0x02u & p[ 2]) << 5; // x= 1, y= 1, mapped pin D12 + pins_b |= (0x02u & p[ 4]) << 4; // x= 1, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 6]) << 3; // x= 1, y= 3, mapped pin D10 + pins_e |= (0x02u & p[16]) << 2; // x= 1, y= 8, mapped pin D5 + pins_h |= (0x02u & p[ 8]) << 5; // x= 1, y= 4, mapped pin D9 + pins_h |= (0x02u & p[10]) << 4; // x= 1, y= 5, mapped pin D8 + pins_h |= (0x02u & p[12]) << 3; // x= 1, y= 6, mapped pin D7 + pins_h |= (0x02u & p[14]) << 2; // x= 1, y= 7, mapped pin D6 + break; + case 1: + pins_b |= (0x08u & p[ 0]) << 4; // x= 3, y= 0, mapped pin D13 + pins_b |= (0x08u & p[ 2]) << 3; // x= 3, y= 1, mapped pin D12 + pins_b |= (0x08u & p[ 4]) << 2; // x= 3, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 6]) << 1; // x= 3, y= 3, mapped pin D10 + pins_e |= (0x08u & p[16]); // x= 3, y= 8, mapped pin D5 + pins_h |= (0x08u & p[ 8]) << 3; // x= 3, y= 4, mapped pin D9 + pins_h |= (0x08u & p[10]) << 2; // x= 3, y= 5, mapped pin D8 + pins_h |= (0x08u & p[12]) << 1; // x= 3, y= 6, mapped pin D7 + pins_h |= (0x08u & p[14]); // x= 3, y= 7, mapped pin D6 + break; + case 2: + pins_b |= (0x20u & p[ 0]) << 2; // x= 5, y= 0, mapped pin D13 + pins_b |= (0x20u & p[ 2]) << 1; // x= 5, y= 1, mapped pin D12 + pins_b |= (0x20u & p[ 4]); // x= 5, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 6]) >> 1; // x= 5, y= 3, mapped pin D10 + pins_e |= (0x20u & p[16]) >> 2; // x= 5, y= 8, mapped pin D5 + pins_h |= (0x20u & p[ 8]) << 1; // x= 5, y= 4, mapped pin D9 + pins_h |= (0x20u & p[10]); // x= 5, y= 5, mapped pin D8 + pins_h |= (0x20u & p[12]) >> 1; // x= 5, y= 6, mapped pin D7 + pins_h |= (0x20u & p[14]) >> 2; // x= 5, y= 7, mapped pin D6 + break; + case 3: + pins_b |= (0x20u & p[ 1]) << 2; // x=13, y= 0, mapped pin D13 + pins_b |= (0x20u & p[ 3]) << 1; // x=13, y= 1, mapped pin D12 + pins_b |= (0x20u & p[ 5]); // x=13, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 7]) >> 1; // x=13, y= 3, mapped pin D10 + pins_e |= (0x01u & p[16]) << 4; // x= 0, y= 8, mapped pin D2 + pins_e |= (0x04u & p[16]) << 3; // x= 2, y= 8, mapped pin D3 + pins_g |= (0x10u & p[16]) << 1; // x= 4, y= 8, mapped pin D4 + pins_h |= (0x20u & p[ 9]) << 1; // x=13, y= 4, mapped pin D9 + pins_h |= (0x20u & p[11]); // x=13, y= 5, mapped pin D8 + pins_h |= (0x20u & p[13]) >> 1; // x=13, y= 6, mapped pin D7 + pins_h |= (0x20u & p[15]) >> 2; // x=13, y= 7, mapped pin D6 + break; + case 4: + pins_b |= (0x10u & p[ 1]) << 3; // x=12, y= 0, mapped pin D13 + pins_b |= (0x10u & p[ 3]) << 2; // x=12, y= 1, mapped pin D12 + pins_b |= (0x10u & p[ 5]) << 1; // x=12, y= 2, mapped pin D11 + pins_b |= (0x10u & p[ 7]); // x=12, y= 3, mapped pin D10 + pins_e |= (0x01u & p[14]) << 4; // x= 0, y= 7, mapped pin D2 + pins_e |= (0x04u & p[14]) << 3; // x= 2, y= 7, mapped pin D3 + pins_e |= (0x20u & p[17]) >> 2; // x=13, y= 8, mapped pin D5 + pins_g |= (0x10u & p[14]) << 1; // x= 4, y= 7, mapped pin D4 + pins_h |= (0x10u & p[ 9]) << 2; // x=12, y= 4, mapped pin D9 + pins_h |= (0x10u & p[11]) << 1; // x=12, y= 5, mapped pin D8 + pins_h |= (0x10u & p[13]); // x=12, y= 6, mapped pin D7 + break; + case 5: + pins_b |= (0x08u & p[ 1]) << 4; // x=11, y= 0, mapped pin D13 + pins_b |= (0x08u & p[ 3]) << 3; // x=11, y= 1, mapped pin D12 + pins_b |= (0x08u & p[ 5]) << 2; // x=11, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 7]) << 1; // x=11, y= 3, mapped pin D10 + pins_e |= (0x01u & p[12]) << 4; // x= 0, y= 6, mapped pin D2 + pins_e |= (0x04u & p[12]) << 3; // x= 2, y= 6, mapped pin D3 + pins_e |= (0x10u & p[17]) >> 1; // x=12, y= 8, mapped pin D5 + pins_g |= (0x10u & p[12]) << 1; // x= 4, y= 6, mapped pin D4 + pins_h |= (0x08u & p[ 9]) << 3; // x=11, y= 4, mapped pin D9 + pins_h |= (0x08u & p[11]) << 2; // x=11, y= 5, mapped pin D8 + pins_h |= (0x10u & p[15]) >> 1; // x=12, y= 7, mapped pin D6 + break; + case 6: + pins_b |= (0x04u & p[ 1]) << 5; // x=10, y= 0, mapped pin D13 + pins_b |= (0x04u & p[ 3]) << 4; // x=10, y= 1, mapped pin D12 + pins_b |= (0x04u & p[ 5]) << 3; // x=10, y= 2, mapped pin D11 + pins_b |= (0x04u & p[ 7]) << 2; // x=10, y= 3, mapped pin D10 + pins_e |= (0x01u & p[10]) << 4; // x= 0, y= 5, mapped pin D2 + pins_e |= (0x04u & p[10]) << 3; // x= 2, y= 5, mapped pin D3 + pins_e |= (0x08u & p[17]); // x=11, y= 8, mapped pin D5 + pins_g |= (0x10u & p[10]) << 1; // x= 4, y= 5, mapped pin D4 + pins_h |= (0x04u & p[ 9]) << 4; // x=10, y= 4, mapped pin D9 + pins_h |= (0x08u & p[13]) << 1; // x=11, y= 6, mapped pin D7 + pins_h |= (0x08u & p[15]); // x=11, y= 7, mapped pin D6 + break; + case 7: + pins_b |= (0x02u & p[ 1]) << 6; // x= 9, y= 0, mapped pin D13 + pins_b |= (0x02u & p[ 3]) << 5; // x= 9, y= 1, mapped pin D12 + pins_b |= (0x02u & p[ 5]) << 4; // x= 9, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 7]) << 3; // x= 9, y= 3, mapped pin D10 + pins_e |= (0x01u & p[ 8]) << 4; // x= 0, y= 4, mapped pin D2 + pins_e |= (0x04u & p[ 8]) << 3; // x= 2, y= 4, mapped pin D3 + pins_e |= (0x04u & p[17]) << 1; // x=10, y= 8, mapped pin D5 + pins_g |= (0x10u & p[ 8]) << 1; // x= 4, y= 4, mapped pin D4 + pins_h |= (0x04u & p[11]) << 3; // x=10, y= 5, mapped pin D8 + pins_h |= (0x04u & p[13]) << 2; // x=10, y= 6, mapped pin D7 + pins_h |= (0x04u & p[15]) << 1; // x=10, y= 7, mapped pin D6 + break; + case 8: + pins_b |= (0x01u & p[ 1]) << 7; // x= 8, y= 0, mapped pin D13 + pins_b |= (0x01u & p[ 3]) << 6; // x= 8, y= 1, mapped pin D12 + pins_b |= (0x01u & p[ 5]) << 5; // x= 8, y= 2, mapped pin D11 + pins_e |= (0x01u & p[ 6]) << 4; // x= 0, y= 3, mapped pin D2 + pins_e |= (0x02u & p[17]) << 2; // x= 9, y= 8, mapped pin D5 + pins_e |= (0x04u & p[ 6]) << 3; // x= 2, y= 3, mapped pin D3 + pins_g |= (0x10u & p[ 6]) << 1; // x= 4, y= 3, mapped pin D4 + pins_h |= (0x02u & p[ 9]) << 5; // x= 9, y= 4, mapped pin D9 + pins_h |= (0x02u & p[11]) << 4; // x= 9, y= 5, mapped pin D8 + pins_h |= (0x02u & p[13]) << 3; // x= 9, y= 6, mapped pin D7 + pins_h |= (0x02u & p[15]) << 2; // x= 9, y= 7, mapped pin D6 + break; + case 9: + pins_b |= (0x01u & p[ 7]) << 4; // x= 8, y= 3, mapped pin D10 + pins_b |= (0x80u & p[ 0]); // x= 7, y= 0, mapped pin D13 + pins_b |= (0x80u & p[ 2]) >> 1; // x= 7, y= 1, mapped pin D12 + pins_e |= (0x01u & p[ 4]) << 4; // x= 0, y= 2, mapped pin D2 + pins_e |= (0x01u & p[17]) << 3; // x= 8, y= 8, mapped pin D5 + pins_e |= (0x04u & p[ 4]) << 3; // x= 2, y= 2, mapped pin D3 + pins_g |= (0x10u & p[ 4]) << 1; // x= 4, y= 2, mapped pin D4 + pins_h |= (0x01u & p[ 9]) << 6; // x= 8, y= 4, mapped pin D9 + pins_h |= (0x01u & p[11]) << 5; // x= 8, y= 5, mapped pin D8 + pins_h |= (0x01u & p[13]) << 4; // x= 8, y= 6, mapped pin D7 + pins_h |= (0x01u & p[15]) << 3; // x= 8, y= 7, mapped pin D6 + break; + case 10: + pins_b |= (0x40u & p[ 0]) << 1; // x= 6, y= 0, mapped pin D13 + pins_b |= (0x80u & p[ 4]) >> 2; // x= 7, y= 2, mapped pin D11 + pins_b |= (0x80u & p[ 6]) >> 3; // x= 7, y= 3, mapped pin D10 + pins_e |= (0x01u & p[ 2]) << 4; // x= 0, y= 1, mapped pin D2 + pins_e |= (0x04u & p[ 2]) << 3; // x= 2, y= 1, mapped pin D3 + pins_e |= (0x80u & p[16]) >> 4; // x= 7, y= 8, mapped pin D5 + pins_g |= (0x10u & p[ 2]) << 1; // x= 4, y= 1, mapped pin D4 + pins_h |= (0x80u & p[ 8]) >> 1; // x= 7, y= 4, mapped pin D9 + pins_h |= (0x80u & p[10]) >> 2; // x= 7, y= 5, mapped pin D8 + pins_h |= (0x80u & p[12]) >> 3; // x= 7, y= 6, mapped pin D7 + pins_h |= (0x80u & p[14]) >> 4; // x= 7, y= 7, mapped pin D6 + break; + case 11: + pins_b |= (0x40u & p[ 2]); // x= 6, y= 1, mapped pin D12 + pins_b |= (0x40u & p[ 4]) >> 1; // x= 6, y= 2, mapped pin D11 + pins_b |= (0x40u & p[ 6]) >> 2; // x= 6, y= 3, mapped pin D10 + pins_e |= (0x01u & p[ 0]) << 4; // x= 0, y= 0, mapped pin D2 + pins_e |= (0x04u & p[ 0]) << 3; // x= 2, y= 0, mapped pin D3 + pins_e |= (0x40u & p[16]) >> 3; // x= 6, y= 8, mapped pin D5 + pins_g |= (0x10u & p[ 0]) << 1; // x= 4, y= 0, mapped pin D4 + pins_h |= (0x40u & p[ 8]); // x= 6, y= 4, mapped pin D9 + pins_h |= (0x40u & p[10]) >> 1; // x= 6, y= 5, mapped pin D8 + pins_h |= (0x40u & p[12]) >> 2; // x= 6, y= 6, mapped pin D7 + pins_h |= (0x40u & p[14]) >> 3; // x= 6, y= 7, mapped pin D6 + break; + } + } + + // Enable pullups (by toggling) on new output pins. + PINB = PORTB ^ pins_b; + PINE = PORTE ^ pins_e; + PING = PORTG ^ pins_g; + PINH = PORTH ^ pins_h; + + // Set pins to output mode; pullups become Vcc/source. + DDRB |= pins_b; + DDRE |= pins_e; + DDRG |= pins_g; + DDRH |= pins_h; + + // Set sink pin to GND/sink, turning on current. + PINB = sink_b; + PINE = sink_e; + PING = sink_g; + PINH = sink_h; +#elif defined (__AVR_ATmega32U4__) + // Set sink pin to Vcc/source, turning off current. + static uint8_t sink_b = 0, sink_c = 0, sink_d = 0, sink_e = 0; + PINB = sink_b; + PINC = sink_c; + PIND = sink_d; + PINE = sink_e; + + DDRB &= ~0xF0; + DDRC &= ~0xC0; + DDRD &= ~0xD3; + DDRE &= ~0x40; + + static uint8_t const PROGMEM sink_b_cycle[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00}; + static uint8_t const PROGMEM sink_c_cycle[] = + {0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}; + static uint8_t const PROGMEM sink_d_cycle[] = + {0x02, 0x01, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00}; + static uint8_t const PROGMEM sink_e_cycle[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + uint8_t pins_b = sink_b = pgm_read_byte(&sink_b_cycle[cycle]); + uint8_t pins_c = sink_c = pgm_read_byte(&sink_c_cycle[cycle]); + uint8_t pins_d = sink_d = pgm_read_byte(&sink_d_cycle[cycle]); + uint8_t pins_e = sink_e = pgm_read_byte(&sink_e_cycle[cycle]); + + // convert Borgware-2D framebuffer to LoL Shield cycles on Arduino Leonardo + // (I could have done this with a lookup table, but that would be slower as + // non-constant bit shifts are quite expensive on AVR) + // NOTE: (0,0) is UPPER RIGHT in the Borgware realm + if (plane < NUMPLANE) { + switch(cycle) { + case 0: + pins_b |= (0x02u & p[ 4]) << 6; // x= 1, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 6]) << 5; // x= 1, y= 3, mapped pin D10 + pins_b |= (0x02u & p[ 8]) << 4; // x= 1, y= 4, mapped pin D9 + pins_b |= (0x02u & p[10]) << 3; // x= 1, y= 5, mapped pin D8 + pins_c |= (0x02u & p[ 0]) << 6; // x= 1, y= 0, mapped pin D13 + pins_c |= (0x02u & p[16]) << 5; // x= 1, y= 8, mapped pin D5 + pins_d |= (0x02u & p[ 2]) << 5; // x= 1, y= 1, mapped pin D12 + pins_d |= (0x02u & p[14]) << 6; // x= 1, y= 7, mapped pin D6 + pins_e |= (0x02u & p[12]) << 5; // x= 1, y= 6, mapped pin D7 + break; + case 1: + pins_b |= (0x08u & p[ 4]) << 4; // x= 3, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 6]) << 3; // x= 3, y= 3, mapped pin D10 + pins_b |= (0x08u & p[ 8]) << 2; // x= 3, y= 4, mapped pin D9 + pins_b |= (0x08u & p[10]) << 1; // x= 3, y= 5, mapped pin D8 + pins_c |= (0x08u & p[ 0]) << 4; // x= 3, y= 0, mapped pin D13 + pins_c |= (0x08u & p[16]) << 3; // x= 3, y= 8, mapped pin D5 + pins_d |= (0x08u & p[ 2]) << 3; // x= 3, y= 1, mapped pin D12 + pins_d |= (0x08u & p[14]) << 4; // x= 3, y= 7, mapped pin D6 + pins_e |= (0x08u & p[12]) << 3; // x= 3, y= 6, mapped pin D7 + break; + case 2: + pins_b |= (0x20u & p[ 4]) << 2; // x= 5, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 6]) << 1; // x= 5, y= 3, mapped pin D10 + pins_b |= (0x20u & p[ 8]); // x= 5, y= 4, mapped pin D9 + pins_b |= (0x20u & p[10]) >> 1; // x= 5, y= 5, mapped pin D8 + pins_c |= (0x20u & p[ 0]) << 2; // x= 5, y= 0, mapped pin D13 + pins_c |= (0x20u & p[16]) << 1; // x= 5, y= 8, mapped pin D5 + pins_d |= (0x20u & p[ 2]) << 1; // x= 5, y= 1, mapped pin D12 + pins_d |= (0x20u & p[14]) << 2; // x= 5, y= 7, mapped pin D6 + pins_e |= (0x20u & p[12]) << 1; // x= 5, y= 6, mapped pin D7 + break; + case 3: + pins_b |= (0x20u & p[ 5]) << 2; // x=13, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 7]) << 1; // x=13, y= 3, mapped pin D10 + pins_b |= (0x20u & p[ 9]); // x=13, y= 4, mapped pin D9 + pins_b |= (0x20u & p[11]) >> 1; // x=13, y= 5, mapped pin D8 + pins_c |= (0x20u & p[ 1]) << 2; // x=13, y= 0, mapped pin D13 + pins_d |= (0x01u & p[16]) << 1; // x= 0, y= 8, mapped pin D2 + pins_d |= (0x04u & p[16]) >> 2; // x= 2, y= 8, mapped pin D3 + pins_d |= (0x10u & p[16]); // x= 4, y= 8, mapped pin D4 + pins_d |= (0x20u & p[ 3]) << 1; // x=13, y= 1, mapped pin D12 + pins_d |= (0x20u & p[15]) << 2; // x=13, y= 7, mapped pin D6 + pins_e |= (0x20u & p[13]) << 1; // x=13, y= 6, mapped pin D7 + break; + case 4: + pins_b |= (0x10u & p[ 5]) << 3; // x=12, y= 2, mapped pin D11 + pins_b |= (0x10u & p[ 7]) << 2; // x=12, y= 3, mapped pin D10 + pins_b |= (0x10u & p[ 9]) << 1; // x=12, y= 4, mapped pin D9 + pins_b |= (0x10u & p[11]); // x=12, y= 5, mapped pin D8 + pins_c |= (0x10u & p[ 1]) << 3; // x=12, y= 0, mapped pin D13 + pins_c |= (0x20u & p[17]) << 1; // x=13, y= 8, mapped pin D5 + pins_d |= (0x01u & p[14]) << 1; // x= 0, y= 7, mapped pin D2 + pins_d |= (0x04u & p[14]) >> 2; // x= 2, y= 7, mapped pin D3 + pins_d |= (0x10u & p[ 3]) << 2; // x=12, y= 1, mapped pin D12 + pins_d |= (0x10u & p[14]); // x= 4, y= 7, mapped pin D4 + pins_e |= (0x10u & p[13]) << 2; // x=12, y= 6, mapped pin D7 + break; + case 5: + pins_b |= (0x08u & p[ 5]) << 4; // x=11, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 7]) << 3; // x=11, y= 3, mapped pin D10 + pins_b |= (0x08u & p[ 9]) << 2; // x=11, y= 4, mapped pin D9 + pins_b |= (0x08u & p[11]) << 1; // x=11, y= 5, mapped pin D8 + pins_c |= (0x08u & p[ 1]) << 4; // x=11, y= 0, mapped pin D13 + pins_c |= (0x10u & p[17]) << 2; // x=12, y= 8, mapped pin D5 + pins_d |= (0x01u & p[12]) << 1; // x= 0, y= 6, mapped pin D2 + pins_d |= (0x04u & p[12]) >> 2; // x= 2, y= 6, mapped pin D3 + pins_d |= (0x08u & p[ 3]) << 3; // x=11, y= 1, mapped pin D12 + pins_d |= (0x10u & p[12]); // x= 4, y= 6, mapped pin D4 + pins_d |= (0x10u & p[15]) << 3; // x=12, y= 7, mapped pin D6 + break; + case 6: + pins_b |= (0x04u & p[ 5]) << 5; // x=10, y= 2, mapped pin D11 + pins_b |= (0x04u & p[ 7]) << 4; // x=10, y= 3, mapped pin D10 + pins_b |= (0x04u & p[ 9]) << 3; // x=10, y= 4, mapped pin D9 + pins_c |= (0x04u & p[ 1]) << 5; // x=10, y= 0, mapped pin D13 + pins_c |= (0x08u & p[17]) << 3; // x=11, y= 8, mapped pin D5 + pins_d |= (0x01u & p[10]) << 1; // x= 0, y= 5, mapped pin D2 + pins_d |= (0x04u & p[ 3]) << 4; // x=10, y= 1, mapped pin D12 + pins_d |= (0x04u & p[10]) >> 2; // x= 2, y= 5, mapped pin D3 + pins_d |= (0x08u & p[15]) << 4; // x=11, y= 7, mapped pin D6 + pins_d |= (0x10u & p[10]); // x= 4, y= 5, mapped pin D4 + pins_e |= (0x08u & p[13]) << 3; // x=11, y= 6, mapped pin D7 + break; + case 7: + pins_b |= (0x02u & p[ 5]) << 6; // x= 9, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 7]) << 5; // x= 9, y= 3, mapped pin D10 + pins_b |= (0x04u & p[11]) << 2; // x=10, y= 5, mapped pin D8 + pins_c |= (0x02u & p[ 1]) << 6; // x= 9, y= 0, mapped pin D13 + pins_c |= (0x04u & p[17]) << 4; // x=10, y= 8, mapped pin D5 + pins_d |= (0x01u & p[ 8]) << 1; // x= 0, y= 4, mapped pin D2 + pins_d |= (0x02u & p[ 3]) << 5; // x= 9, y= 1, mapped pin D12 + pins_d |= (0x04u & p[ 8]) >> 2; // x= 2, y= 4, mapped pin D3 + pins_d |= (0x04u & p[15]) << 5; // x=10, y= 7, mapped pin D6 + pins_d |= (0x10u & p[ 8]); // x= 4, y= 4, mapped pin D4 + pins_e |= (0x04u & p[13]) << 4; // x=10, y= 6, mapped pin D7 + break; + case 8: + pins_b |= (0x01u & p[ 5]) << 7; // x= 8, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 9]) << 4; // x= 9, y= 4, mapped pin D9 + pins_b |= (0x02u & p[11]) << 3; // x= 9, y= 5, mapped pin D8 + pins_c |= (0x01u & p[ 1]) << 7; // x= 8, y= 0, mapped pin D13 + pins_c |= (0x02u & p[17]) << 5; // x= 9, y= 8, mapped pin D5 + pins_d |= (0x01u & p[ 3]) << 6; // x= 8, y= 1, mapped pin D12 + pins_d |= (0x01u & p[ 6]) << 1; // x= 0, y= 3, mapped pin D2 + pins_d |= (0x02u & p[15]) << 6; // x= 9, y= 7, mapped pin D6 + pins_d |= (0x04u & p[ 6]) >> 2; // x= 2, y= 3, mapped pin D3 + pins_d |= (0x10u & p[ 6]); // x= 4, y= 3, mapped pin D4 + pins_e |= (0x02u & p[13]) << 5; // x= 9, y= 6, mapped pin D7 + break; + case 9: + pins_b |= (0x01u & p[ 7]) << 6; // x= 8, y= 3, mapped pin D10 + pins_b |= (0x01u & p[ 9]) << 5; // x= 8, y= 4, mapped pin D9 + pins_b |= (0x01u & p[11]) << 4; // x= 8, y= 5, mapped pin D8 + pins_c |= (0x01u & p[17]) << 6; // x= 8, y= 8, mapped pin D5 + pins_c |= (0x80u & p[ 0]); // x= 7, y= 0, mapped pin D13 + pins_d |= (0x01u & p[ 4]) << 1; // x= 0, y= 2, mapped pin D2 + pins_d |= (0x01u & p[15]) << 7; // x= 8, y= 7, mapped pin D6 + pins_d |= (0x04u & p[ 4]) >> 2; // x= 2, y= 2, mapped pin D3 + pins_d |= (0x10u & p[ 4]); // x= 4, y= 2, mapped pin D4 + pins_d |= (0x80u & p[ 2]) >> 1; // x= 7, y= 1, mapped pin D12 + pins_e |= (0x01u & p[13]) << 6; // x= 8, y= 6, mapped pin D7 + break; + case 10: + pins_b |= (0x80u & p[ 4]); // x= 7, y= 2, mapped pin D11 + pins_b |= (0x80u & p[ 6]) >> 1; // x= 7, y= 3, mapped pin D10 + pins_b |= (0x80u & p[ 8]) >> 2; // x= 7, y= 4, mapped pin D9 + pins_b |= (0x80u & p[10]) >> 3; // x= 7, y= 5, mapped pin D8 + pins_c |= (0x40u & p[ 0]) << 1; // x= 6, y= 0, mapped pin D13 + pins_c |= (0x80u & p[16]) >> 1; // x= 7, y= 8, mapped pin D5 + pins_d |= (0x01u & p[ 2]) << 1; // x= 0, y= 1, mapped pin D2 + pins_d |= (0x04u & p[ 2]) >> 2; // x= 2, y= 1, mapped pin D3 + pins_d |= (0x10u & p[ 2]); // x= 4, y= 1, mapped pin D4 + pins_d |= (0x80u & p[14]); // x= 7, y= 7, mapped pin D6 + pins_e |= (0x80u & p[12]) >> 1; // x= 7, y= 6, mapped pin D7 + break; + case 11: + pins_b |= (0x40u & p[ 4]) << 1; // x= 6, y= 2, mapped pin D11 + pins_b |= (0x40u & p[ 6]); // x= 6, y= 3, mapped pin D10 + pins_b |= (0x40u & p[ 8]) >> 1; // x= 6, y= 4, mapped pin D9 + pins_b |= (0x40u & p[10]) >> 2; // x= 6, y= 5, mapped pin D8 + pins_c |= (0x40u & p[16]); // x= 6, y= 8, mapped pin D5 + pins_d |= (0x01u & p[ 0]) << 1; // x= 0, y= 0, mapped pin D2 + pins_d |= (0x04u & p[ 0]) >> 2; // x= 2, y= 0, mapped pin D3 + pins_d |= (0x10u & p[ 0]); // x= 4, y= 0, mapped pin D4 + pins_d |= (0x40u & p[ 2]); // x= 6, y= 1, mapped pin D12 + pins_d |= (0x40u & p[14]) << 1; // x= 6, y= 7, mapped pin D6 + pins_e |= (0x40u & p[12]); // x= 6, y= 6, mapped pin D7 + break; + } + } + + // Enable pullups (by toggling) on new output pins. + PINB = PORTB ^ pins_b; + PINC = PORTC ^ pins_c; + PIND = PORTD ^ pins_d; + PINE = PORTE ^ pins_e; + + // Set pins to output mode; pullups become Vcc/source. + DDRB |= pins_b; + DDRC |= pins_c; + DDRD |= pins_d; + DDRE |= pins_e; + + // Set sink pin to GND/sink, turning on current. + PINB = sink_b; + PINC = sink_c; + PIND = sink_d; + PINE = sink_e; +#else + // Set sink pin to Vcc/source, turning off current. + static uint8_t sink_b = 0, sink_d = 0; + PIND = sink_d; + PINB = sink_b; + + // Set pins to input mode; Vcc/source become pullups. + DDRD = 0; + DDRB = 0; + + static uint8_t const PROGMEM sink_d_cycle[] = + {0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t const PROGMEM sink_b_cycle[] = + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20}; + + uint8_t pins_d = sink_d = pgm_read_byte(&sink_d_cycle[cycle]); + uint8_t pins_b = sink_b = pgm_read_byte(&sink_b_cycle[cycle]); + + // convert Borgware-2D framebuffer to LoL Shield cycles on Diavolino + // (I could have done this with a lookup table, but that would be slower as + // non-constant bit shifts are quite expensive on AVR) + // NOTE: (0,0) is UPPER RIGHT in the Borgware realm + if (plane < NUMPLANE) { + switch(cycle) { + case 0: + pins_b |= (0x02u & p[ 0]) << 4; // x= 1, y= 0, mapped pin D13 + pins_b |= (0x02u & p[ 2]) << 3; // x= 1, y= 1, mapped pin D12 + pins_b |= (0x02u & p[ 4]) << 2; // x= 1, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 6]) << 1; // x= 1, y= 3, mapped pin D10 + pins_b |= (0x02u & p[ 8]); // x= 1, y= 4, mapped pin D9 + pins_b |= (0x02u & p[10]) >> 1; // x= 1, y= 5, mapped pin D8 + pins_d |= (0x02u & p[12]) << 6; // x= 1, y= 6, mapped pin D7 + pins_d |= (0x02u & p[14]) << 5; // x= 1, y= 7, mapped pin D6 + pins_d |= (0x02u & p[16]) << 4; // x= 1, y= 8, mapped pin D5 + break; + case 1: + pins_b |= (0x08u & p[ 0]) << 2; // x= 3, y= 0, mapped pin D13 + pins_b |= (0x08u & p[ 2]) << 1; // x= 3, y= 1, mapped pin D12 + pins_b |= (0x08u & p[ 4]); // x= 3, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 6]) >> 1; // x= 3, y= 3, mapped pin D10 + pins_b |= (0x08u & p[ 8]) >> 2; // x= 3, y= 4, mapped pin D9 + pins_b |= (0x08u & p[10]) >> 3; // x= 3, y= 5, mapped pin D8 + pins_d |= (0x08u & p[12]) << 4; // x= 3, y= 6, mapped pin D7 + pins_d |= (0x08u & p[14]) << 3; // x= 3, y= 7, mapped pin D6 + pins_d |= (0x08u & p[16]) << 2; // x= 3, y= 8, mapped pin D5 + break; + case 2: + pins_b |= (0x20u & p[ 0]); // x= 5, y= 0, mapped pin D13 + pins_b |= (0x20u & p[ 2]) >> 1; // x= 5, y= 1, mapped pin D12 + pins_b |= (0x20u & p[ 4]) >> 2; // x= 5, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 6]) >> 3; // x= 5, y= 3, mapped pin D10 + pins_b |= (0x20u & p[ 8]) >> 4; // x= 5, y= 4, mapped pin D9 + pins_b |= (0x20u & p[10]) >> 5; // x= 5, y= 5, mapped pin D8 + pins_d |= (0x20u & p[12]) << 2; // x= 5, y= 6, mapped pin D7 + pins_d |= (0x20u & p[14]) << 1; // x= 5, y= 7, mapped pin D6 + pins_d |= (0x20u & p[16]); // x= 5, y= 8, mapped pin D5 + break; + case 3: + pins_b |= (0x20u & p[ 1]); // x=13, y= 0, mapped pin D13 + pins_b |= (0x20u & p[ 3]) >> 1; // x=13, y= 1, mapped pin D12 + pins_b |= (0x20u & p[ 5]) >> 2; // x=13, y= 2, mapped pin D11 + pins_b |= (0x20u & p[ 7]) >> 3; // x=13, y= 3, mapped pin D10 + pins_b |= (0x20u & p[ 9]) >> 4; // x=13, y= 4, mapped pin D9 + pins_b |= (0x20u & p[11]) >> 5; // x=13, y= 5, mapped pin D8 + pins_d |= (0x01u & p[16]) << 2; // x= 0, y= 8, mapped pin D2 + pins_d |= (0x04u & p[16]) << 1; // x= 2, y= 8, mapped pin D3 + pins_d |= (0x10u & p[16]); // x= 4, y= 8, mapped pin D4 + pins_d |= (0x20u & p[13]) << 2; // x=13, y= 6, mapped pin D7 + pins_d |= (0x20u & p[15]) << 1; // x=13, y= 7, mapped pin D6 + break; + case 4: + pins_b |= (0x10u & p[ 1]) << 1; // x=12, y= 0, mapped pin D13 + pins_b |= (0x10u & p[ 3]); // x=12, y= 1, mapped pin D12 + pins_b |= (0x10u & p[ 5]) >> 1; // x=12, y= 2, mapped pin D11 + pins_b |= (0x10u & p[ 7]) >> 2; // x=12, y= 3, mapped pin D10 + pins_b |= (0x10u & p[ 9]) >> 3; // x=12, y= 4, mapped pin D9 + pins_b |= (0x10u & p[11]) >> 4; // x=12, y= 5, mapped pin D8 + pins_d |= (0x01u & p[14]) << 2; // x= 0, y= 7, mapped pin D2 + pins_d |= (0x04u & p[14]) << 1; // x= 2, y= 7, mapped pin D3 + pins_d |= (0x10u & p[13]) << 3; // x=12, y= 6, mapped pin D7 + pins_d |= (0x10u & p[14]); // x= 4, y= 7, mapped pin D4 + pins_d |= (0x20u & p[17]); // x=13, y= 8, mapped pin D5 + break; + case 5: + pins_b |= (0x08u & p[ 1]) << 2; // x=11, y= 0, mapped pin D13 + pins_b |= (0x08u & p[ 3]) << 1; // x=11, y= 1, mapped pin D12 + pins_b |= (0x08u & p[ 5]); // x=11, y= 2, mapped pin D11 + pins_b |= (0x08u & p[ 7]) >> 1; // x=11, y= 3, mapped pin D10 + pins_b |= (0x08u & p[ 9]) >> 2; // x=11, y= 4, mapped pin D9 + pins_b |= (0x08u & p[11]) >> 3; // x=11, y= 5, mapped pin D8 + pins_d |= (0x01u & p[12]) << 2; // x= 0, y= 6, mapped pin D2 + pins_d |= (0x04u & p[12]) << 1; // x= 2, y= 6, mapped pin D3 + pins_d |= (0x10u & p[12]); // x= 4, y= 6, mapped pin D4 + pins_d |= (0x10u & p[15]) << 2; // x=12, y= 7, mapped pin D6 + pins_d |= (0x10u & p[17]) << 1; // x=12, y= 8, mapped pin D5 + break; + case 6: + pins_b |= (0x04u & p[ 1]) << 3; // x=10, y= 0, mapped pin D13 + pins_b |= (0x04u & p[ 3]) << 2; // x=10, y= 1, mapped pin D12 + pins_b |= (0x04u & p[ 5]) << 1; // x=10, y= 2, mapped pin D11 + pins_b |= (0x04u & p[ 7]); // x=10, y= 3, mapped pin D10 + pins_b |= (0x04u & p[ 9]) >> 1; // x=10, y= 4, mapped pin D9 + pins_d |= (0x01u & p[10]) << 2; // x= 0, y= 5, mapped pin D2 + pins_d |= (0x04u & p[10]) << 1; // x= 2, y= 5, mapped pin D3 + pins_d |= (0x08u & p[13]) << 4; // x=11, y= 6, mapped pin D7 + pins_d |= (0x08u & p[15]) << 3; // x=11, y= 7, mapped pin D6 + pins_d |= (0x08u & p[17]) << 2; // x=11, y= 8, mapped pin D5 + pins_d |= (0x10u & p[10]); // x= 4, y= 5, mapped pin D4 + break; + case 7: + pins_b |= (0x02u & p[ 1]) << 4; // x= 9, y= 0, mapped pin D13 + pins_b |= (0x02u & p[ 3]) << 3; // x= 9, y= 1, mapped pin D12 + pins_b |= (0x02u & p[ 5]) << 2; // x= 9, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 7]) << 1; // x= 9, y= 3, mapped pin D10 + pins_b |= (0x04u & p[11]) >> 2; // x=10, y= 5, mapped pin D8 + pins_d |= (0x01u & p[ 8]) << 2; // x= 0, y= 4, mapped pin D2 + pins_d |= (0x04u & p[ 8]) << 1; // x= 2, y= 4, mapped pin D3 + pins_d |= (0x04u & p[13]) << 5; // x=10, y= 6, mapped pin D7 + pins_d |= (0x04u & p[15]) << 4; // x=10, y= 7, mapped pin D6 + pins_d |= (0x04u & p[17]) << 3; // x=10, y= 8, mapped pin D5 + pins_d |= (0x10u & p[ 8]); // x= 4, y= 4, mapped pin D4 + break; + case 8: + pins_b |= (0x01u & p[ 1]) << 5; // x= 8, y= 0, mapped pin D13 + pins_b |= (0x01u & p[ 3]) << 4; // x= 8, y= 1, mapped pin D12 + pins_b |= (0x01u & p[ 5]) << 3; // x= 8, y= 2, mapped pin D11 + pins_b |= (0x02u & p[ 9]); // x= 9, y= 4, mapped pin D9 + pins_b |= (0x02u & p[11]) >> 1; // x= 9, y= 5, mapped pin D8 + pins_d |= (0x01u & p[ 6]) << 2; // x= 0, y= 3, mapped pin D2 + pins_d |= (0x02u & p[13]) << 6; // x= 9, y= 6, mapped pin D7 + pins_d |= (0x02u & p[15]) << 5; // x= 9, y= 7, mapped pin D6 + pins_d |= (0x02u & p[17]) << 4; // x= 9, y= 8, mapped pin D5 + pins_d |= (0x04u & p[ 6]) << 1; // x= 2, y= 3, mapped pin D3 + pins_d |= (0x10u & p[ 6]); // x= 4, y= 3, mapped pin D4 + break; + case 9: + pins_b |= (0x01u & p[ 7]) << 2; // x= 8, y= 3, mapped pin D10 + pins_b |= (0x01u & p[ 9]) << 1; // x= 8, y= 4, mapped pin D9 + pins_b |= (0x01u & p[11]); // x= 8, y= 5, mapped pin D8 + pins_b |= (0x80u & p[ 0]) >> 2; // x= 7, y= 0, mapped pin D13 + pins_b |= (0x80u & p[ 2]) >> 3; // x= 7, y= 1, mapped pin D12 + pins_d |= (0x01u & p[ 4]) << 2; // x= 0, y= 2, mapped pin D2 + pins_d |= (0x01u & p[13]) << 7; // x= 8, y= 6, mapped pin D7 + pins_d |= (0x01u & p[15]) << 6; // x= 8, y= 7, mapped pin D6 + pins_d |= (0x01u & p[17]) << 5; // x= 8, y= 8, mapped pin D5 + pins_d |= (0x04u & p[ 4]) << 1; // x= 2, y= 2, mapped pin D3 + pins_d |= (0x10u & p[ 4]); // x= 4, y= 2, mapped pin D4 + break; + case 10: + pins_b |= (0x40u & p[ 0]) >> 1; // x= 6, y= 0, mapped pin D13 + pins_b |= (0x80u & p[ 4]) >> 4; // x= 7, y= 2, mapped pin D11 + pins_b |= (0x80u & p[ 6]) >> 5; // x= 7, y= 3, mapped pin D10 + pins_b |= (0x80u & p[ 8]) >> 6; // x= 7, y= 4, mapped pin D9 + pins_b |= (0x80u & p[10]) >> 7; // x= 7, y= 5, mapped pin D8 + pins_d |= (0x01u & p[ 2]) << 2; // x= 0, y= 1, mapped pin D2 + pins_d |= (0x04u & p[ 2]) << 1; // x= 2, y= 1, mapped pin D3 + pins_d |= (0x10u & p[ 2]); // x= 4, y= 1, mapped pin D4 + pins_d |= (0x80u & p[12]); // x= 7, y= 6, mapped pin D7 + pins_d |= (0x80u & p[14]) >> 1; // x= 7, y= 7, mapped pin D6 + pins_d |= (0x80u & p[16]) >> 2; // x= 7, y= 8, mapped pin D5 + break; + case 11: + pins_b |= (0x40u & p[ 2]) >> 2; // x= 6, y= 1, mapped pin D12 + pins_b |= (0x40u & p[ 4]) >> 3; // x= 6, y= 2, mapped pin D11 + pins_b |= (0x40u & p[ 6]) >> 4; // x= 6, y= 3, mapped pin D10 + pins_b |= (0x40u & p[ 8]) >> 5; // x= 6, y= 4, mapped pin D9 + pins_b |= (0x40u & p[10]) >> 6; // x= 6, y= 5, mapped pin D8 + pins_d |= (0x01u & p[ 0]) << 2; // x= 0, y= 0, mapped pin D2 + pins_d |= (0x04u & p[ 0]) << 1; // x= 2, y= 0, mapped pin D3 + pins_d |= (0x10u & p[ 0]); // x= 4, y= 0, mapped pin D4 + pins_d |= (0x40u & p[12]) << 1; // x= 6, y= 6, mapped pin D7 + pins_d |= (0x40u & p[14]); // x= 6, y= 7, mapped pin D6 + pins_d |= (0x40u & p[16]) >> 1; // x= 6, y= 8, mapped pin D5 + break; + } + } + + // Enable pullups on new output pins. + PORTD = pins_d; + PORTB = pins_b; + // Set pins to output mode; pullups become Vcc/source. + DDRD = pins_d; + DDRB = pins_b; + // Set sink pin to GND/sink, turning on current. + PIND = sink_d; + PINB = sink_b; +#endif +} + +#if !defined (__AVR_ATmega32U4__) +ISR(TIMER2_OVF_vect) { +#else +ISR(TIMER1_COMPA_vect) { +#endif + // For each cycle, we have potential planes to display. Once every plane has + // been displayed, then we move on to the next cycle. + // NOTE: a "cycle" is a subset of LEDs that can be driven at once. + + // 12 Cycles of Matrix + static uint8_t cycle = 0; + + // planes to display + // NOTE: a "plane" in the Borgware is the same as a "page" in Jimmie's lib + static uint8_t plane = 0; + +#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) + TCCR2B = prescaler[plane]; +#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega128__) + TCCR2 = prescaler[page]; +#elif defined (__AVR_ATmega32U4__) + TCCR1B = prescaler[plane]; +#endif +#if !defined (__AVR_ATmega32U4__) + TCNT2 = counts[plane]; +#else + TCNT1 = counts[plane]; +#endif + + // distribute framebuffer contents among current cycle pins + compose_cycle(cycle, plane++); + + if (plane >= (NUMPLANE + 1)) { + plane = 0; + cycle++; + if (cycle >= 12) { + cycle = 0; + } + } + wdt_reset(); +} + +void borg_hw_init() { + +#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) + TIMSK2 &= ~(_BV(TOIE2) | _BV(OCIE2A)); + TCCR2A &= ~(_BV(WGM21) | _BV(WGM20)); + TCCR2B &= ~_BV(WGM22); + ASSR &= ~_BV(AS2); +#elif defined (__AVR_ATmega8__) + TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2)); + TCCR2 &= ~(_BV(WGM21) | _BV(WGM20)); + ASSR &= ~_BV(AS2); +#elif defined (__AVR_ATmega128__) + TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2)); + TCCR2 &= ~(_BV(WGM21) | _BV(WGM20)); +#elif defined (__AVR_ATmega32U4__) + // The only 8bit timer on the Leonardo is used by default, so we use the 16bit Timer1 + // in CTC mode with a compare value of 256 to achieve the same behaviour. + TIMSK1 &= ~(_BV(TOIE1) | _BV(OCIE1A)); + TCCR1A &= ~(_BV(WGM10) | _BV(WGM11)); + OCR1A = 256; +#endif + + setBrightness(); + + // Then start the display +#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) + TIMSK2 |= _BV(TOIE2); + TCCR2B = FASTPRESCALER; +#elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega128__) + TIMSK |= _BV(TOIE2); + TCCR2 = FASTPRESCALER; +#elif defined (__AVR_ATmega32U4__) + // Enable output compare match interrupt + TIMSK1 |= _BV(OCIE1A); + TCCR1B = FASTPRESCALER; +#endif + // interrupt ASAP +#if !defined (__AVR_ATmega32U4__) + TCNT2 = 255; +#else + TCNT1 = 255; +#endif + + // activate watchdog timer + wdt_reset(); + wdt_enable(WDTO_15MS); // 15ms watchdog +} diff --git a/src/borg_hw/config.in b/src/borg_hw/config.in index d494ec3..7c1d244 100644 --- a/src/borg_hw/config.in +++ b/src/borg_hw/config.in @@ -14,6 +14,7 @@ choice 'Hardware Driver' \ Andre-Borg HW_BORG_ANDRE \ Laufschrift-Borg HW_BORG_LS \ Laufschrift-Borg-MH HW_BORG_MH \ + LoL-Shield HW_LOLSHIELD \ FFM-Jochen HW_BORG_LSJO \ FFM-LedBrett HW_LEDBRETT \ Borg-Mini HW_BORG_MINI \ @@ -45,6 +46,10 @@ if [ "$BORG_HW" == "HW_BORG_MH" ] ; then source src/borg_hw/config_borg_mh.in fi +if [ "$BORG_HW" == "HW_LOLSHIELD" ] ; then + source src/borg_hw/config_lolshield.in +fi + if [ "$BORG_HW" == "HW_BORG_LSJO" ] ; then source src/borg_hw/config_borg_lsjo.in fi diff --git a/src/borg_hw/config_lolshield.in b/src/borg_hw/config_lolshield.in new file mode 100644 index 0000000..fd99bed --- /dev/null +++ b/src/borg_hw/config_lolshield.in @@ -0,0 +1,8 @@ +mainmenu_option next_comment +comment "lolshield setup" + +define_int USER_TIMER0_FOR_WAIT 1 + +uint "Brightness (0-127)" BRIGHTNESS 127 + +endmenu diff --git a/src/games/breakout/playfield.c b/src/games/breakout/playfield.c index eeac23d..df24d32 100644 --- a/src/games/breakout/playfield.c +++ b/src/games/breakout/playfield.c @@ -67,7 +67,7 @@ static void brick_damage (int8_t in_x, int8_t in_y) void playfield_set (uint8_t in_x, uint8_t in_y, game_field_t in_field) { - if (in_x >= NUM_ROWS || in_y >= NUM_COLS) + if (in_x >= NUM_COLS || in_y >= NUM_ROWS) { return; } @@ -78,10 +78,10 @@ int8_t check_bounce (int8_t in_x, int8_t in_y) { int8_t ov = 0; /* overflow check */ - if (in_x >= NUM_ROWS || in_x < 0) + if (in_x >= NUM_COLS || in_x < 0) ov |= BOUNCE_X; - if (in_y >= NUM_COLS || in_y < 0) + if (in_y >= NUM_ROWS || in_y < 0) ov |= BOUNCE_Y; if (ov) @@ -119,9 +119,9 @@ void playfield_draw () { uint8_t x,y; - for (x=0;xaSegments[0] = (pixel){NUM_COLS / 2, NUM_ROWS / 2}; - pprotSnake->aSegments[1] = (pixel){NUM_COLS / 2, NUM_ROWS / 2 - 1}; +#if NUM_ROWS > NUM_COLS + pprotSnake->aSegments[0] = + (pixel){(NUM_COLS - 2) / 2 + 1, (NUM_ROWS - 2) / 2 + 1}; + pprotSnake->aSegments[1] = + (pixel){(NUM_COLS - 2) / 2 + 1, (NUM_ROWS - 2) / 2}; + pprotSnake->dir = SNAKE_DIR_DOWN; +#else + pprotSnake->aSegments[0] = + (pixel){(NUM_COLS - 2) / 2 + 1, (NUM_ROWS - 2) / 2 + 1}; + pprotSnake->aSegments[1] = + (pixel){(NUM_COLS - 2) / 2 + 2, (NUM_ROWS - 2) / 2 + 1}; + pprotSnake->dir = SNAKE_DIR_RIGHT; +#endif pprotSnake->nTailIndex = 0; pprotSnake->nHeadIndex = 1; - pprotSnake->dir = SNAKE_DIR_UP; } #ifdef GAME_SNAKE @@ -403,7 +418,7 @@ void snake_engine(uint8_t bDemoMode) clear_screen(0); snake_drawBorder(); - for (uint8_t nAppleColor = 0; 1; nAppleColor ^= SNAKE_COLOR_APPLE) + for (uint8_t nTick = 0; 1; nTick ^= SNAKE_COLOR_APPLE) { // determine new direction #if defined ANIMATION_SNAKE && defined GAME_SNAKE @@ -415,48 +430,66 @@ void snake_engine(uint8_t bDemoMode) { snake_userControl(&protSnake, &dirLast); } + if (bDemoMode || nTick) { #elif defined ANIMATION_SNAKE snake_autoRoute(&protSnake, &apples); + { #else snake_userControl(&protSnake, &dirLast); + if (nTick) { #endif - // actually move head - pixel pxOldHead = protSnake.aSegments[protSnake.nHeadIndex]; - protSnake.nHeadIndex = (protSnake.nHeadIndex + 1u) % USNAKE_MAX_LENGTH; - protSnake.aSegments[protSnake.nHeadIndex] = - snake_nextDirection(pxOldHead, protSnake.dir); + // actually move head + pixel pxOldHead = protSnake.aSegments[protSnake.nHeadIndex]; + protSnake.nHeadIndex = (protSnake.nHeadIndex + 1u) % USNAKE_MAX_LENGTH; + protSnake.aSegments[protSnake.nHeadIndex] = + snake_nextDirection(pxOldHead, protSnake.dir); - // look if we have found an apple - if (!snake_checkForApple(&apples, - protSnake.aSegments[protSnake.nHeadIndex])) - { - // quit game if we hit something which is not an apple - if (get_pixel(protSnake.aSegments[protSnake.nHeadIndex])) + // look if we have found an apple + if (!snake_checkForApple(&apples, + protSnake.aSegments[protSnake.nHeadIndex])) { - snake_eliminateProtagonist(&protSnake); - return; + // quit game if we hit something which is not an apple + if (get_pixel(protSnake.aSegments[protSnake.nHeadIndex])) + { + snake_eliminateProtagonist(&protSnake); + return; + } + + // remove last segment + clearpixel(protSnake.aSegments[protSnake.nTailIndex]) + protSnake.nTailIndex = + (protSnake.nTailIndex + 1u) % USNAKE_MAX_LENGTH; + + // new apples + snake_spawnApples(&apples); } - - // remove last segment - clearpixel(protSnake.aSegments[protSnake.nTailIndex]) - protSnake.nTailIndex = - (protSnake.nTailIndex + 1u) % USNAKE_MAX_LENGTH; - - // new apples - snake_spawnApples(&apples); + // draw new head + setpixel(protSnake.aSegments[protSnake.nHeadIndex], + SNAKE_COLOR_PROTAGONIST); } - // draw new head - setpixel(protSnake.aSegments[protSnake.nHeadIndex], - SNAKE_COLOR_PROTAGONIST); // draw apples for (uint8_t i = apples.nAppleCount; i--;) { - setpixel(apples.aApples[i], nAppleColor); + // nTick also serves as blinking color + setpixel(apples.aApples[i], nTick); } - wait(SNAKE_CYCLE_DELAY); +#if defined ANIMATION_SNAKE && defined GAME_SNAKE + if (bDemoMode) + { + wait(SNAKE_ANIM_DELAY); + } + else + { + wait(SNAKE_GAME_DELAY / 2); + } +#elif defined ANIMATION_SNAKE + wait(SNAKE_ANIM_DELAY); +#else + wait(SNAKE_GAME_DELAY / 2); +#endif } } @@ -466,6 +499,9 @@ void snake_engine(uint8_t bDemoMode) void snake_game(void) { snake_engine(0); +#if defined GAME_SNAKE && defined SCROLLTEXT_SUPPORT + scrolltext(" NUM_COLS - #define VIEWCOLS NUM_COLS - #define VIEWROWS NUM_COLS - #else - #define VIEWCOLS NUM_COLS - #define VIEWROWS NUM_ROWS - #endif +#if (NUM_ROWS < 16) && (NUM_COLS > NUM_ROWS) && (!defined GAME_TETRIS_FP) +# define VIEWCOLS NUM_ROWS +# define VIEWROWS NUM_COLS +# define VIEW_TILT #else - #define VIEWCOLS NUM_COLS - #define VIEWROWS NUM_ROWS +# define VIEWCOLS NUM_COLS +# define VIEWROWS NUM_ROWS #endif - #if VIEWROWS >= 20 #define TETRIS_VIEW_YOFFSET_DUMP ((VIEWROWS - 20) / 2) #define TETRIS_VIEW_HEIGHT_DUMP 20 @@ -127,6 +118,11 @@ static void tetris_view_setpixel(tetris_bearing_t nBearing, uint8_t y, uint8_t nColor) { +#ifdef VIEW_TILT + // tilt counter clockwise + nBearing = (nBearing + 3) % 4u; +#endif + x = VIEWCOLS - 1 - x; pixel px; diff --git a/src/joystick/Makefile b/src/joystick/Makefile index ff1c5f7..6a5b92e 100644 --- a/src/joystick/Makefile +++ b/src/joystick/Makefile @@ -18,6 +18,12 @@ endif ifeq ($(HC165_JOYSTICK_SUPPORT), y) SRC = hc165_joystick.c endif +ifeq ($(LOLSHIELD_JOYSTICK_SUPPORT), y) + SRC = lolshield_joystick.c +endif +ifeq ($(NULL_JOYSTICK_SUPPORT), y) + SRC = null_joystick.c +endif include $(MAKETOPDIR)/rules.mk diff --git a/src/joystick/config.in b/src/joystick/config.in index da6fff2..d67c536 100644 --- a/src/joystick/config.in +++ b/src/joystick/config.in @@ -1,18 +1,36 @@ -dep_bool_menu "joystick support" JOYSTICK_SUPPORT y +mainmenu_option next_comment +comment "Joystick Support" + +bool "Joystick Support" JOYSTICK_SUPPORT n + +if [ "x$JOYSTICK_CHOICE" == "x" ] ; then + define_string JOYSTICK_CHOICE "JOY_PARALLEL" +fi if [ "$JOYSTICK_SUPPORT" = "y" ]; then -###################### Parallel joystick menu ################################# - dep_bool_menu "parallel joystick support" PARALLEL_JOYSTICK_SUPPORT y + choice 'Joystick Type' \ + "Atari-9-Pin JOY_PARALLEL \ + NES-Game-Pad JOY_NES_PAD \ + RFM12 JOY_RFM12 \ + LED-Brett JOY_LEDBRETT \ + LoL-Shield JOY_LOLSHIELD \ + None JOY_NULL" \ + 'Atari-9-Pin' JOYSTICK_CHOICE - if [ "$PARALLEL_JOYSTICK_SUPPORT" = "y" ]; then - choice 'Pin up' \ +###################### parallel joystick menu ################################# + if [ "$JOYSTICK_CHOICE" == "JOY_PARALLEL" ]; then + mainmenu_option next_comment + comment "Joystick Settings" + + define_bool PARALLEL_JOYSTICK_SUPPORT y + choice 'Pin up' \ "PINA PINA \ PINB PINB \ PINC PINC \ PIND PIND" \ 'PINB' JOYSTICK_PIN_UP - choice 'Bit up' \ + choice 'Bit up' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -23,14 +41,14 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit0' JOYSTICK_BIT_UP - choice 'Pin down' \ + choice 'Pin down' \ "PINA PINA \ PINB PINB \ PINC PINC \ PIND PIND" \ 'PINB' JOYSTICK_PIN_DOWN - choice 'Bit down' \ + choice 'Bit down' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -41,14 +59,14 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit1' JOYSTICK_BIT_DOWN - choice 'Pin left' \ + choice 'Pin left' \ "PINA PINA \ PINB PINB \ PINC PINC \ PIND PIND" \ 'PINB' JOYSTICK_PIN_LEFT - choice 'Bit left' \ + choice 'Bit left' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -59,14 +77,14 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit2' JOYSTICK_BIT_LEFT - choice 'Pin right' \ + choice 'Pin right' \ "PINA PINA \ PINB PINB \ PINC PINC \ PIND PIND" \ 'PINB' JOYSTICK_PIN_RIGHT - choice 'Bit right' \ + choice 'Bit right' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -77,14 +95,14 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit3' JOYSTICK_BIT_RIGHT - choice 'Pin fire' \ + choice 'Pin fire' \ "PINA PINA \ PINB PINB \ PINC PINC \ PIND PIND" \ 'PIND' JOYSTICK_PIN_FIRE - choice 'Bit fire' \ + choice 'Bit fire' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -94,37 +112,40 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit6 6 \ Bit7 7" \ 'Bit3' JOYSTICK_BIT_FIRE - fi - endmenu + endmenu + fi ############################################################################### -###################### NES-Pad menu ################################# - dep_bool_menu "nes-pad support" NES_PAD_SUPPORT y +###################### NES-Pad menu ########################################### + if [ "$JOYSTICK_CHOICE" == "JOY_NES_PAD" ]; then + mainmenu_option next_comment + comment "Joystick Settings" - if [ "$NES_PAD_SUPPORT" = "y" ]; then - choice 'Port clk' \ + define_bool NES_PAD_SUPPORT y + + choice 'Port clk' \ "PORTA PORTA \ PORTB PORTB \ PORTC PORTC \ PORTD PORTD" \ 'PORTB' NES_PAD_PORT_CLK - choice 'Port ds' \ + choice 'Port ds' \ "PORTA PORTA \ PORTB PORTB \ PORTC PORTC \ PORTD PORTD" \ - 'PORTB' NES_PAD_PORT_PL + 'PORTB' NES_PAD_PORT_PL - choice 'Pin pl' \ + choice 'Pin pl' \ "PORTA PORTA \ PORTB PORTB \ PORTC PORTC \ PORTD PORTD" \ 'PORTB' NES_PAD_PORT_DS - choice 'Bit clk' \ + choice 'Bit clk' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -135,7 +156,7 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit0' NES_PAD_BIT_CLK - choice 'Bit pl' \ + choice 'Bit pl' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -146,7 +167,7 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit1' NES_PAD_BIT_PL - choice 'Bit ds' \ + choice 'Bit ds' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -157,28 +178,31 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit7 7" \ 'Bit2' NES_PAD_BIT_DS + endmenu fi - - endmenu ############################################################################### ###################### RFM12 joystick menu #################################### - dep_bool_menu "RFM12 Joystick support" RFM12_JOYSTICK_SUPPORT y - - endmenu + if [ "$JOYSTICK_CHOICE" == "JOY_RFM12" ]; then + define_bool RFM12_JOYSTICK_SUPPORT y + fi +############################################################################### ###################### 74HC165 joystick menu ################################# - dep_bool_menu "74HC165 joystick support" HC165_JOYSTICK_SUPPORT y + if [ "$JOYSTICK_CHOICE" == "JOY_LEDBRETT" ]; then + mainmenu_option next_comment + comment "Joystick Settings" - if [ "$HC165_JOYSTICK_SUPPORT" = "y" ]; then - choice 'Port load' \ + define_bool HC165_JOYSTICK_SUPPORT y + + choice 'Port load' \ "PORTA PORTA \ PORTB PORTB \ PORTC PORTC \ PORTD PORTD" \ 'PORTD' HC165_JOYSTICK_PORT_LOAD - choice 'Bit load' \ + choice 'Bit load' \ "Bit0 0 \ Bit1 1 \ Bit2 2 \ @@ -188,11 +212,23 @@ if [ "$JOYSTICK_SUPPORT" = "y" ]; then Bit6 6 \ Bit7 7" \ 'Bit2' HC165_JOYSTICK_BIT_LOAD - fi - endmenu + endmenu + fi +############################################################################### + +###################### LoL Shield joystick menu ############################### + if [ "$JOYSTICK_CHOICE" == "JOY_NULL" ]; then + define_bool NULL_JOYSTICK_SUPPORT y + fi +############################################################################### + +###################### null joystick menu ##################################### + if [ "$JOYSTICK_CHOICE" == "JOY_LOLSHIELD" ]; then + define_bool LOLSHIELD_JOYSTICK_SUPPORT y + fi ############################################################################### fi -endmenu +endmenu \ No newline at end of file diff --git a/src/joystick/joystick.h b/src/joystick/joystick.h index 04d3840..abd0a00 100644 --- a/src/joystick/joystick.h +++ b/src/joystick/joystick.h @@ -1,6 +1,10 @@ #ifndef JOYSTICK_H #define JOYSTICK_H +#ifdef __AVR__ +# include +#endif + #include "../config.h" extern unsigned char waitForFire; @@ -41,7 +45,71 @@ void joy_init(); # define JOYISFIRE (! ((1<<4) & hc165_joystick_val)) -# else +# elif defined(NULL_JOYSTICK_SUPPORT) + +# define JOYISUP (0) +# define JOYISDOWN (0) +# define JOYISLEFT (0) +# define JOYISRIGHT (0) +# define JOYISFIRE (0) + +# elif defined (LOLSHIELD_JOYSTICK_SUPPORT) + +# if defined (__AVR_ATmega48__) || \ + defined (__AVR_ATmega48P__) || \ + defined (__AVR_ATmega88__) || \ + defined (__AVR_ATmega88P__) || \ + defined (__AVR_ATmega168__) || \ + defined (__AVR_ATmega168P__) || \ + defined (__AVR_ATmega328__) || \ + defined (__AVR_ATmega328P__) + /* + * A0 => PC0 => JOYISUP + * A1 => PC1 => JOYISDOWN + * A2 => PC2 => JOYISLEFT + * A3 => PC3 => JOYISRIGHT + * A4 => PC4 => NC (JOYIS2GND) + * A5 => PC5 => JOYISFIRE + */ +# define JOYISUP (!(PINC & _BV(PINC0))) +# define JOYISDOWN (!(PINC & _BV(PINC1))) +# define JOYISLEFT (!(PINC & _BV(PINC2))) +# define JOYISRIGHT (!(PINC & _BV(PINC3))) +# define JOYISFIRE (!(PINC & _BV(PINC5))) +# elif defined (__AVR_ATmega32U4__) + /* + * A0 => PF7 => JOYISUP + * A1 => PF6 => JOYISDOWN + * A2 => PF5 => JOYISLEFT + * A3 => PF4 => JOYISRIGHT + * A4 => PF1 => NC (JOYIS2GND) + * A5 => PF0 => JOYISFIRE + */ +# define JOYISUP (!(PINF & _BV(PINF7))) +# define JOYISDOWN (!(PINF & _BV(PINF6))) +# define JOYISLEFT (!(PINF & _BV(PINF5))) +# define JOYISRIGHT (!(PINF & _BV(PINF4))) +# define JOYISFIRE (!(PINF & _BV(PINF0))) +# elif defined (__AVR_ATmega1280__) || \ + defined (__AVR_ATmega2560__) + /* + * A0 => PF0 => JOYISUP + * A1 => PF1 => JOYISDOWN + * A2 => PF2 => JOYISLEFT + * A3 => PF3 => JOYISRIGHT + * A4 => PF4 => NC (JOYIS2GND) + * A5 => PF5 => JOYISFIRE + */ +# define JOYISUP (!(PINF & _BV(PINF0))) +# define JOYISDOWN (!(PINF & _BV(PINF1))) +# define JOYISLEFT (!(PINF & _BV(PINF2))) +# define JOYISRIGHT (!(PINF & _BV(PINF3))) +# define JOYISFIRE (!(PINF & _BV(PINF5))) +# else +# error "Unsupported Arduino board!" +# endif + +# elif defined (PARALLEL_JOYSTICK_SUPPORT) # define JOYISUP (!(JOYSTICK_PIN_UP & (1< + +void joy_init(){ +#if defined (__AVR_ATmega48__) || \ + defined (__AVR_ATmega48P__) || \ + defined (__AVR_ATmega88__) || \ + defined (__AVR_ATmega88P__) || \ + defined (__AVR_ATmega168__) || \ + defined (__AVR_ATmega168P__) || \ + defined (__AVR_ATmega328__) || \ + defined (__AVR_ATmega328P__) + /* + * A0 => PC0 => JOYISUP + * A1 => PC1 => JOYISDOWN + * A2 => PC2 => JOYISLEFT + * A3 => PC3 => JOYISRIGHT + * A4 => PC4 => NC (JOYIS2GND) + * A5 => PC5 => JOYISFIRE + */ + + // set joystick pins to input + DDRC &= ~(_BV(PINC0) | _BV(PINC1) | _BV(PINC2) | + _BV(PINC3) | _BV(PINC4) | _BV(PINC5)); + // activate pullups + PORTC |= _BV(PINC0) | _BV(PINC1) | _BV(PINC2) | + _BV(PINC3) | _BV(PINC4) | _BV(PINC5); +#elif defined (__AVR_ATmega32U4__) + /* + * A0 => PF7 => JOYISUP + * A1 => PF6 => JOYISDOWN + * A2 => PF5 => JOYISLEFT + * A3 => PF4 => JOYISRIGHT + * A4 => PF1 => NC (JOYIS2GND) + * A5 => PF0 => JOYISFIRE + */ + + // set joystick pins to input + DDRF &= ~(_BV(PINF7) | _BV(PINF6) | _BV(PINF5) | + _BV(PINF4) | _BV(PINF1) | _BV(PINF0)); + // activate pullups + PORTF |= _BV(PINF7) | _BV(PINF6) | _BV(PINF5) | _BV(PINF4) | + _BV(PINF1) | _BV(PINF0); +#elif defined (__AVR_ATmega1280__) || \ + defined (__AVR_ATmega2560__) + /* + * A0 => PF0 => JOYISUP + * A1 => PF1 => JOYISDOWN + * A2 => PF2 => JOYISLEFT + * A3 => PF3 => JOYISRIGHT + * A4 => PF4 => NC (JOYIS2GND) + * A5 => PF5 => JOYISFIRE + */ + + // set joystick pins to input + DDRF &= ~(_BV(PINF0) | _BV(PINF1) | _BV(PINF2) | + _BV(PINF3) | _BV(PINF4) | _BV(PINF5)); + // activate pullups + PORTF |= _BV(PINF0) | _BV(PINF1) | _BV(PINF2) | + _BV(PINF3) | _BV(PINF4) | _BV(PINF5); +#else +# error "Unsupported Arduino board!" +#endif +} diff --git a/src/joystick/null_joystick.c b/src/joystick/null_joystick.c new file mode 100644 index 0000000..d29707e --- /dev/null +++ b/src/joystick/null_joystick.c @@ -0,0 +1,2 @@ +/* dummy */ +void joy_init(){} diff --git a/src/random/Makefile b/src/random/Makefile index 725498e..0597a7c 100644 --- a/src/random/Makefile +++ b/src/random/Makefile @@ -5,8 +5,13 @@ TARGET = objects_avr include $(MAKETOPDIR)/defaults.mk #for AVR -SRC = prng.c persistentCounter.c -ASRC = noekeon_asm.S memxor.S +ifeq ($(findstring atmega256,$(MCU)),atmega256) + # handmade assembler routines don't work on ATmega2560 + SRC = prng.c persistentCounter.c noekeon.c memxor_c.c +else + SRC = prng.c persistentCounter.c + ASRC = noekeon_asm.S memxor.S +endif #for simulator SRC_SIM = prng.c persistentCounter.c noekeon.c memxor_c.c diff --git a/src/random/noekeon.c b/src/random/noekeon.c index 8a4c23a..5772e8d 100644 --- a/src/random/noekeon.c +++ b/src/random/noekeon.c @@ -39,7 +39,7 @@ #define RC_POS 0 static -void gamma(uint32_t* a){ +void noekeon_gamma(uint32_t* a){ uint32_t tmp; a[1] ^= ~((a[3]) | (a[2])); @@ -94,13 +94,13 @@ void noekeon_round(uint32_t* key, uint32_t* state, uint8_t const1, uint8_t const theta(key, state); ((uint8_t*)state)[RC_POS] ^= const2; pi1(state); - gamma(state); + noekeon_gamma(state); pi2(state); } -uint8_t rc_tab[] +uint8_t const rc_tab[] #ifdef __AVR__ - PROGMEM + PROGMEM #endif = { /* 0x80, */ @@ -146,7 +146,7 @@ void noekeon_enc(void* buffer, const void* key){ for(i=0; i=0; --i){ #ifdef __AVR__ - rc = pgm_read_byte(rc_tab+i); + rc = pgm_read_byte(&rc_tab[i]); #else rc = rc_tab[i]; #endif diff --git a/src/scrolltext/font_small6.c b/src/scrolltext/font_small6.c index da0ebce..6d004fa 100644 --- a/src/scrolltext/font_small6.c +++ b/src/scrolltext/font_small6.c @@ -1,6 +1,6 @@ #include "font.h" -unsigned int PROGMEM fontIndex_small6[] = { +unsigned int const PROGMEM fontIndex_small6[] = { 0, /* */ 1, /* ! */ 2, /* " */ @@ -96,14 +96,14 @@ unsigned int PROGMEM fontIndex_small6[] = { 309, /* | */ 310, /* } */ 312, /* ~ */ - 316, /* ß */ - 321, /* ä */ - 324, /* ö */ - 328, /* ü */ + 316, /* � */ + 321, /* � */ + 324, /* � */ + 328, /* � */ 331 }; -unsigned char PROGMEM fontData_small6[] = { +unsigned char const PROGMEM fontData_small6[] = { 0x00, /* */ 0x2f, /* # #### */ 0x03, /* ## */ diff --git a/src/util.c b/src/util.c index 0629b68..87e366c 100644 --- a/src/util.c +++ b/src/util.c @@ -21,24 +21,19 @@ extern jmp_buf newmode_jmpbuf; void wait(int ms){ - -/* TCCR2: FOC2 WGM20 COM21 COM20 WGM21 CS22 CS21 CS20 - CS22 CS21 CS20 - 0 0 0 stop - 0 0 1 clk - 0 1 0 clk/8 - 0 1 1 clk/32 - 1 0 0 clk/64 - 1 0 1 clk/128 - 1 1 0 clk/256 - 1 1 1 clk/1024 -*/ - //TCCR2 = 0x0D; //CTC Mode, clk/128 - //OCR2 = (F_CPU/128000); //1000Hz - - TCCR1B = (1<0;ms--){ @@ -60,9 +55,16 @@ void wait(int ms){ } #endif -#if defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644__) || defined (__AVR_ATmega328__) || (__AVR_ATmega1284P__) || defined (__AVR_ATmega1284__) - while(!(TIFR1&(1<