commit fe14b29d15a2bf4b17da8883a2124d667cf2814c Author: tixiv Date: Wed Dec 3 05:40:16 2008 +0000 renamed project because it is to cool for stupid name diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1413272 --- /dev/null +++ b/Makefile @@ -0,0 +1,173 @@ +TARGET := image +TOPDIR = . + +SRC = \ + main.c \ + eeprom_reserve.c \ + pixel.c \ + util.c \ + + +LAUNCH_BOOTLOADER = launch-bootloader +SERIAL = /dev/ttyUSB0 + +export TOPDIR +############################################################################## +all: compile-$(TARGET) + @echo "===============================" + @echo "$(TARGET) compiled for: $(MCU)" + @echo "size is: " + @${TOPDIR}/scripts/size $(TARGET) + @echo "===============================" + + +############################################################################## +# generic fluff +include defaults.mk +#include $(TOPDIR)/rules.mk + +############################################################################## +# generate SUBDIRS variable +# + +.subdirs: autoconf.h + $(RM) -f $@ + echo "SUBDIRS += borg_hw" >> $@ + echo "SUBDIRS += animations" >> $@ + (for subdir in `grep -e "^#define .*_SUPPORT" autoconf.h \ + | sed -e "s/^#define //" -e "s/_SUPPORT.*//" \ + | tr "[A-Z]\\n" "[a-z] " `; do \ + test -d $$subdir && echo "SUBDIRS += $$subdir" ; \ + done) | sort -u >> $@ + +ifneq ($(no_deps),t) +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),mrproper) +ifneq ($(MAKECMDGOALS),menuconfig) + +include $(TOPDIR)/.subdirs +include $(TOPDIR)/.config + +endif # MAKECMDGOALS!=menuconfig +endif # MAKECMDGOALS!=mrproper +endif # MAKECMDGOALS!=clean +endif # no_deps!=t + +############################################################################## + +.PHONY: compile-subdirs +compile-subdirs: + for dir in $(SUBDIRS); do make -C $$dir lib$$dir.a || exit 5; done + +.PHONY: compile-$(TARGET) +compile-$(TARGET): compile-subdirs $(TARGET).hex $(TARGET).bin $(TARGET).lst + +OBJECTS += $(patsubst %.c,%.o,${SRC}) +LINKLIBS = $(foreach subdir,$(SUBDIRS),$(subdir)/lib$(subdir).a) + +# FIXME how can we omit specifying every file to be linked twice? +# This is currently necessary because of interdependencies between +# the libraries, which aren't denoted in these however. +$(TARGET): $(OBJECTS) $(LINKLIBS) + $(CC) $(LDFLAGS) -o $@ $(OBJECTS) \ + $(foreach subdir,$(SUBDIRS),-L$(subdir) -l$(subdir)) \ + $(foreach subdir,$(SUBDIRS),-l$(subdir)) \ + $(foreach subdir,$(SUBDIRS),-l$(subdir)) + + +############################################################################## + +%.hex: % + $(OBJCOPY) -O ihex -R .eeprom $< $@ + +ifeq ($(HTTPD_INLINE_FILES_SUPPORT),y) +INLINE_FILES := $(wildcard httpd/embed/*) +else +INLINE_FILES := +endif + +%.bin: % $(INLINE_FILES) + $(OBJCOPY) -O binary -R .eeprom $< $@ +ifeq ($(HTTPD_INLINE_FILES_SUPPORT),y) + $(MAKE) -C httpd httpd-concat + httpd/do-embed $(INLINE_FILES) + $(OBJCOPY) -O ihex -I binary $(TARGET).bin $(TARGET).hex +endif + +%.eep.hex: % + $(OBJCOPY) --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex -j .eeprom $< $@ + +%.lst: % + $(OBJDUMP) -h -S $< > $@ + +%-size: %.hex + $(SIZE) $< + +############################################################################## +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) + +menuconfig: + $(MAKE) -C scripts/lxdialog all + $(CONFIG_SHELL) scripts/Menuconfig config.in + test -e .config + @$(MAKE) no_deps=t what-now-msg + +what-now-msg: + @echo "" + @echo "Next, you can: " + @echo " * 'make' to compile your borgware" + @for subdir in $(SUBDIRS); do \ + test -e "$$subdir/configure" -a -e "$$subdir/cfgpp" \ + && echo " * 'make $$subdir/menuconfig' to" \ + "further configure $$subdir"; done || true + @echo "" +.PHONY: what-now-msg + +%/menuconfig: + $(SH) "$(@D)/configure" + @$(MAKE) what-now-msg + +############################################################################## +clean: + $(MAKE) -f rules.mk no_deps=t clean-common + $(RM) $(TARGET) $(TARGET).bin $(TARGET).hex .subdirs + for subdir in `find . -type d`; do \ + test "x$$subdir" != "x." \ + && test -e $$subdir/Makefile \ + && make no_deps=t -C $$subdir clean; done + +mrproper: + $(MAKE) clean + $(RM) -f autoconf.h .config config.mk .menuconfig.log .config.old + +sflash: $(TARGET).hex + $(LAUNCH_BOOTLOADER) $(SERIAL) 115200 + avrdude -p m32 -b 115200 -u -c avr109 -P $(SERIAL) -U f:w:$< -F + echo X > $(SERIAL) + + +.PHONY: clean mrproper sflash +############################################################################## +# configure ethersex +# +show-config: autoconf.h + @echo + @echo "These modules are currently enabled: " + @echo "======================================" + @grep -e "^#define .*_SUPPORT" autoconf.h | sed -e "s/^#define / * /" -e "s/_SUPPORT.*//" + +.PHONY: show-config + +autoconf.h .config: + @echo make\'s goal: $(MAKECMDGOALS) +ifneq ($(MAKECMDGOALS),menuconfig) + # make sure menuconfig isn't called twice, on `make menuconfig' + test -s autoconf.h -a -s .config || $(MAKE) no_deps=t menuconfig + # test the target file, test fails if it doesn't exist + # and will keep make from looping menuconfig. + test -s autoconf.h -a -s .config +endif + +include depend.mk diff --git a/Makefile-old b/Makefile-old new file mode 100644 index 0000000..68d666b --- /dev/null +++ b/Makefile-old @@ -0,0 +1,32 @@ + +OBJ = borg_hw.o main.o util.o pixel.o programm.o borg_can.o can.o \ + spi.o scrolltext3.o font_arial8.o joystick.o snake.o \ + eeprom_reserve.o persistentCounter.o prng.o matrix.o \ + invader_draw.o invader_init.o invader_proc.o invaders2.o \ + tetris/tetris.o menu.o gameoflife.o memxor.o noekeon_asm.o \ + mcuf.o uart.o + +CANADDR = 0x43 + +SERIAL = /dev/ttyUSB0 + +include ../../make/avr.mk + +.PHONY: tetris/tetris.o +tetris/tetris.o: + $(MAKE) "MCU_CC=$(MCU_CC)" "MCU_LD=$(MCU_LD)" "LDFLAGS=$(LDFLAGS)" \ + "CFLAGS=$(CFLAGS) -DNDEBUG -pedantic -std=c99" --directory=tetris + +LAUNCH_BOOTLOADER = launch-bootloader + +sflash: $(OUT).hex + $(LAUNCH_BOOTLOADER) $(SERIAL) 115200 + avrdude -p m32 -b 115200 -u -c avr109 -P $(SERIAL) -U f:w:$(OUT).hex -F + echo X > $(SERIAL) + +urflash: image_with_bootloader.hex + avrdude -p m32 -c bsd -P /dev/parport0 -U hfuse:w:0xdc:m + avrdude -p m32 -c bsd -P /dev/parport0 -U lfuse:w:0xef:m + avrdude -p m32 -c bsd -P /dev/parport0 -U f:w:image_with_bootloader.hex + avrdude -p m32 -c bsd -P /dev/parport0 -U e:w:image_eeprom.hex + avrdude -p m32 -c bsd -P /dev/parport0 -U lock:w:0x2f:m diff --git a/README b/README new file mode 100644 index 0000000..af48d55 --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +Source für Borg16 Controller + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..4f564ce --- /dev/null +++ b/README.txt @@ -0,0 +1,5 @@ + +Hier liegt der Versuch, eine universelle Codebasis für 2d-borgs zu bauen, die +durch 'make menuconfig' konfigurierbar ist. Das ganze ist grade nochnicht +besonders weit, und funktioniert noch garnicht. Work is in progress... + diff --git a/animations/Makefile b/animations/Makefile new file mode 100644 index 0000000..d9b2ba8 --- /dev/null +++ b/animations/Makefile @@ -0,0 +1,21 @@ +TARGET = libanimations.a +TOPDIR = .. + +include $(TOPDIR)/defaults.mk + +SRC = programm.c + +ifeq ($(ANIMATION_SNAKE),y) + SRC += snake.c +endif + +ifeq ($(ANIMATION_MATRIX),y) + SRC += matrix.c +endif + +ifeq ($(ANIMATION_GAMEOFLIFE),y) + SRC += gameoflife.c +endif + + +include $(TOPDIR)/rules.mk diff --git a/animations/gameoflife.c b/animations/gameoflife.c new file mode 100644 index 0000000..40db870 --- /dev/null +++ b/animations/gameoflife.c @@ -0,0 +1,312 @@ +/** + * Conways Game of life + * Author: Daniel Otte + * License: GPLv3 + * + * + */ + +#include +#include +#include /* for debugging */ +#include "../config.h" +#include "../random/prng.h" +#include "../pixel.h" +#include "../util.h" + +/******************************************************************************/ + +#undef DEBUG + +#define XSIZE NUM_COLS +#define YSIZE NUM_ROWS + +/* + * last line is for debug information + */ +#ifdef DEBUG + #undef YSIZE + #define YSIZE (NUM_ROWS-1) + #define DEBUG_ROW (NUM_ROWS-1) + #define DEBUG_BIT(pos, val) \ + setpixel((pixel){(pos)%XSIZE,DEBUG_ROW+(pos)/XSIZE},(val)?3:0) + #define DEBUG_BYTE(s,v) \ + DEBUG_BIT((s)*8+0, (v)&(1<<0)); \ + DEBUG_BIT((s)*8+1, (v)&(1<<1)); \ + DEBUG_BIT((s)*8+2, (v)&(1<<2)); \ + DEBUG_BIT((s)*8+3, (v)&(1<<3)); \ + DEBUG_BIT((s)*8+4, (v)&(1<<4)); \ + DEBUG_BIT((s)*8+5, (v)&(1<<5)); \ + DEBUG_BIT((s)*8+6, (v)&(1<<6)); \ + DEBUG_BIT((s)*8+7, (v)&(1<<7)) +#else + #define DEBUG_BIT(s,v) + #define DEBUG_BYTE(s,v) +#endif + +//#define GLIDER_TEST + +#define BITSTUFFED +#define LOOP_DETECT_BUFFER_SIZE 8 + +#ifndef GOL_DELAY + #define GOL_DELAY 1 /* milliseconds */ +#endif + +#ifndef GOL_CYCLES + #define GOL_CYCLES (2*60*3) +#endif + +/******************************************************************************/ +/******************************************************************************/ + +typedef enum{dead=0, alive=1} cell_t; + +#ifndef BITSTUFFED + +#define FIELD_XSIZE XSIZE +#define FIELD_YSIZE YSIZE + +typedef cell_t field_t[FIELD_XSIZE][FIELD_YSIZE]; + +/******************************************************************************/ + +void setcell(field_t pf, int x, int y, cell_t value){ + pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE] = value; +} + +/******************************************************************************/ + +cell_t getcell(field_t pf, int x, int y){ + return pf[(x+FIELD_XSIZE)%FIELD_XSIZE][(y+FIELD_YSIZE)%FIELD_YSIZE]; +} + +#else /* BITSTUFFED */ + +#define FIELD_XSIZE ((XSIZE+7)/8) +#define FIELD_YSIZE YSIZE + +typedef uint8_t field_t[FIELD_XSIZE][FIELD_YSIZE]; + +/******************************************************************************/ + +void setcell(field_t pf, int x, int y, cell_t value){ + uint8_t t; + x = (x+XSIZE) % XSIZE; + y = (y+YSIZE) % YSIZE; + + t = pf[x/8][y]; + if(value==alive){ + t |= 1<<(x&7); + } else { + t &= ~(1<<(x&7)); + } + pf[x/8][y] = t; +} + +/******************************************************************************/ + +cell_t getcell(field_t pf, int x, int y){ + x = (x+XSIZE) % XSIZE; + y = (y+YSIZE) % YSIZE; + + return ((pf[x/8][y])&(1<<(x&7)))?alive:dead; +} +#endif + +/******************************************************************************/ + +uint8_t countsurroundingalive(field_t pf, int x, int y){ + uint8_t ret=0; + ret += (getcell(pf, x-1, y-1)==alive)?1:0; + ret += (getcell(pf, x , y-1)==alive)?1:0; + ret += (getcell(pf, x+1, y-1)==alive)?1:0; + + ret += (getcell(pf, x-1, y )==alive)?1:0; + ret += (getcell(pf, x+1, y )==alive)?1:0; + + ret += (getcell(pf, x-1, y+1)==alive)?1:0; + ret += (getcell(pf, x , y+1)==alive)?1:0; + ret += (getcell(pf, x+1, y+1)==alive)?1:0; + return ret; +} + +/******************************************************************************/ + +void nextiteration(field_t dest, field_t src){ + int x,y; + uint8_t tc; + for(y=0; y +#include "../random/prng.h" +#include "../pixel.h" +#include "../util.h" + + +typedef struct{ + pixel start; + unsigned char len; + unsigned char decay; + unsigned char index; + unsigned char speed; +} streamer; + +typedef uint8_t pixel_matrix_t[NUM_COLS][NUM_ROWS/4]; + +inline static uint8_t get_bright(pixel_matrix_t *matrix, uint8_t x, uint8_t y){ + uint8_t ret; + ret = (*matrix)[x][y/4]; + return 0x3&(ret>>(2*(y%4))); +} + +inline static void set_bright(pixel_matrix_t *matrix, uint8_t x, uint8_t y, uint8_t value){ + uint8_t t; + t = (*matrix)[x][y/4]; + t &= ~(0x3<<(2*(y%4))); + t |= value<<(2*(y%4)); + (*matrix)[x][y/4] = t; +} + +void matrix() { + unsigned int counter = 500; /* run 500 cycles */ + streamer streamers[STREAMER_NUM]; + pixel_matrix_t matrix_bright; + unsigned char x, y; + unsigned char index = 0; + unsigned char draw; + unsigned char streamer_num = 0; + + while(counter--){ + unsigned char i, j; + /* initialise matrix-buffer */ + for(x=0;x>6) /* bright>>6 */ + draw = 1; + if(bright > (get_bright(&matrix_bright, str.start.x, str.start.y+j)<<6) ){ + set_bright(&matrix_bright, str.start.x, str.start.y+j, bright>>6); + + } + } + bright-=((bright>>5)*str.decay); + } + + str.len+=str.speed/2; + streamers[i] = str; + if(!draw){ + for(j=i;jNUM_ROWS-1) sy=0; + streamers[streamer_num] = (streamer){{random8()%NUM_COLS, sy}, 0, (random8()%8)+12, index++,(random8()%16)+3}; + streamer_num++; + } + } + wait(60); + + } +} + + + + + diff --git a/animations/matrix.h b/animations/matrix.h new file mode 100644 index 0000000..fcff13e --- /dev/null +++ b/animations/matrix.h @@ -0,0 +1,14 @@ +/** + * + * + * + * + * + */ + +#ifndef MATRIX_H_ +#define MATRIX_H_ + +void matrix(); + +#endif /* MATRIX_H_ */ diff --git a/animations/programm.c b/animations/programm.c new file mode 100644 index 0000000..fc760ba --- /dev/null +++ b/animations/programm.c @@ -0,0 +1,227 @@ + +#include "../config.h" +#include "../random/prng.h" +#include "../pixel.h" +#include "../util.h" + +#ifdef AVR + #include +#endif + +#define RANDOM8() (random8()) + +#ifdef ANIMATION_TESTS +void test1(){ + unsigned char x,y; + for (y=0;y>(i&0x01); + } + wait(200); + } +} +#endif + + +#ifdef ANIMATION_FEUER +#define FEUER_Y (NUM_ROWS + 3) + +void feuer() +{ + unsigned char y, x; + unsigned int t; + unsigned char world[NUM_COLS][FEUER_Y]; // double buffer + + + for(t=0; t<800; t++) { + // diffuse + for(y=1; y> 5) ); + } + }; + + wait(FEUER_DELAY); + } +} +#endif + +#ifdef ANIMATION_RANDOM_BRIGHT +/** + * 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)); + } + wait(200); + } +} +#endif diff --git a/animations/programm.h b/animations/programm.h new file mode 100644 index 0000000..49b8a66 --- /dev/null +++ b/animations/programm.h @@ -0,0 +1,22 @@ +#ifndef PROGRAMM_H_ +#define PROGRAMM_H_ + +void off(); +void spirale(unsigned int delay); +void joern1(); +void joern2(); +void draw_line( unsigned char yabs, signed char delta); +void schachbrett(unsigned char times); +void test1(); +void test_level1(); +void test_level2(); +void test_level3(); +void test_levels(); +void test_palette(); +void snake(); +void matrix(); +void fadein(); +void feuer(); +void random_bright(unsigned cycles); + +#endif /* PROGRAMM_H_ */ diff --git a/animations/snake.c b/animations/snake.c new file mode 100644 index 0000000..b1470a7 --- /dev/null +++ b/animations/snake.c @@ -0,0 +1,249 @@ + +#include "../config.h" +#include "../pixel.h" +#include "../util.h" +#include "../random/prng.h" +#include "snake.h" +#include "../joystick.h" + +#define RANDOM8() (random8()) + +void snake(){ + pixel pixels[64]; + pixels[0] = (pixel){NUM_COLS/2, NUM_ROWS/2}; + pixels[1] = (pixel){NUM_COLS/2, (NUM_ROWS/2)-1}; + + pixel * head = &pixels[1]; + pixel * tail = &pixels[0]; + pixel old_head; + + pixel apples[10]; + unsigned char apple_num = 0; + + direction dir = up; + + clear_screen(0); + + unsigned char x=0, dead=0; + while(1){ + x++; + old_head = *head; + if(++head == pixels + 64) head = pixels; + + unsigned char dead_cnt=0; + + unsigned char apple_found = 0, j; + for(j=0;jx > apples[j].x){ + distx = head->x - apples[j].x; + }else{ + distx = apples[j].x - head->x; + } + if(head->y > apples[j].y){ + disty = head->y - apples[j].y; + }else{ + disty = apples[j].y - head->y; + } + if ((distx + disty) < shortdist){ + shortdist = distx + disty; + nextapple = j; + xy = (distx > disty)?1:0; + } + } + if(xy){ + dir = (apples[nextapple].x > head->x)?left:right; + }else{ + dir = (apples[nextapple].y > head->y)?down:up; + } + } + } + + if( (apple_num<9) && ((RANDOM8()&0xff)<10) ){ + pixel new_apple = (pixel){RANDOM8()%NUM_COLS,RANDOM8()%NUM_ROWS}; + if(!get_pixel(new_apple)){ + apples[apple_num++]=new_apple; + } + } + + if(!apple_found){ + clearpixel(*tail); + if(++tail == pixels + 64) tail = pixels; + } + }else{ + while(tail != head){ + clearpixel(*tail); + if((++tail)>pixels+64) tail = pixels; + wait (60); + } + break; + } + + for(j=0;jx == apples[j].x) && + (head->y == apples[j].y) ){ + apple_found = 1; + for(; j < apple_num - 1; j++) { + apples[j] = apples[j+1]; + } + apple_num--; + goto apple_se; + } + } + if (get_pixel(*head)) { + dead = 1; + } + apple_se: + + if (!dead) { + setpixel(*head, 3); + + // setze neue €pfel + if ( (apple_num < 9) && (random8() < 10) ) { + pixel new_apple = (pixel) {(random8() % (NUM_COLS-2))+1, + (random8() % (NUM_ROWS-2))+1}; + if (!get_pixel(new_apple)){ + apples[apple_num++] = new_apple; + } + } + // lšsche Ende + if (!apple_found && !dead) { + clearpixel(*tail); + if (++tail == pixels + 64) + tail = pixels; + } + } else { + while (tail != head) { + clearpixel(*tail); + if ((++tail) > pixels + 64) + tail = pixels; + wait (60); + } + break; + } + + for (j = 0; j < apple_num; j++) { + if (x % 2) { + setpixel(apples[j], 3); + } else { + clearpixel(apples[j]); + } + } + for(j=0;j<20;j++){ + if(JOYISLEFT){ + joy = left; + }else if(JOYISRIGHT){ + joy = right; + }else{ + joy = 0xff; + } + if(joy != joy_old){ + joy_cmd = joy; + } + joy_old = joy; + wait (5); + } + } +} + diff --git a/animations/snake.h b/animations/snake.h new file mode 100644 index 0000000..bb09f14 --- /dev/null +++ b/animations/snake.h @@ -0,0 +1,8 @@ +#ifndef SNAKE_H_ +#define SNAKE_H_ + +void snake(); +void snake_game(); + + +#endif /* SNAKE_H_ */ diff --git a/borg_hw/Makefile b/borg_hw/Makefile new file mode 100644 index 0000000..5c2f863 --- /dev/null +++ b/borg_hw/Makefile @@ -0,0 +1,31 @@ +TARGET = libborg_hw.a +TOPDIR = .. + +include $(TOPDIR)/defaults.mk + + +ifeq ($(BORG_HW),HW_BORG_16) + SRC = borg_hw_borg16.c +endif + +ifeq ($(BORG_HW),HW_BORG_ANDRE) + SRC = borg_hw_andreborg.c +endif + +ifeq ($(BORG_HW),HW_BORG_LS) + SRC = borg_hw_borg_ls.c +endif + +ifeq ($(BORG_HW),HW_BORG_LS) + SRC = borg_hw_borg_ls.c +endif + +ifeq ($(BORG_HW),HW_BORG_MINI) + SRC = borg_hw_borg_mini.c +endif + +ifeq ($(SRC),'') + $(error no valid hardware driver selected ) +endif + +include $(TOPDIR)/rules.mk diff --git a/borg_hw/borg_hw.h b/borg_hw/borg_hw.h new file mode 100644 index 0000000..a7837d1 --- /dev/null +++ b/borg_hw/borg_hw.h @@ -0,0 +1,15 @@ +#ifndef BORG_HW_H +#define BORG_HW_H + +//Linebytes gibt die Zahl der Bytes pro Zeile in der +//Pixmap an, also Spaltenzahl/8 aufgerundet +#define LINEBYTES (((NUM_COLS-1)/8)+1) + + +extern unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + +void watchdog_enable(); +void borg_hw_init(); +void timer0_off(); + +#endif diff --git a/borg_hw/borg_hw_andreborg.c b/borg_hw/borg_hw_andreborg.c new file mode 100644 index 0000000..f466cc6 --- /dev/null +++ b/borg_hw/borg_hw_andreborg.c @@ -0,0 +1,168 @@ + +#include "../config.h" +#include "../makros.h" + +#include +#include +#include +#include "borg_hw.h" + +/* +// Diese #defines werden nun durch menuconfig gesetzt + +// 16 Spalten insgesamt direkt gesteuert, dafür 2 Ports +#define COLPORT1 PORTA +#define COLDDR1 DDRA + +#define COLPORT2 PORTC +#define COLDDR2 DDRC + +// Der andere Port übernimmt die Steuerung der Schieberegister +#define ROWPORT PORTD +#define ROWDDR DDRD +// Clock und reset gehen gemeinsam an beide Schieberegister +// der reset pin ist negiert +#define PIN_MCLR PD4 +#define PIN_CLK PD5 +//das dier sind die individuellen Dateneingänge für die Schieberegister +#define PIN_DATA1 PD6 +#define PIN_DATA2 PD7 +*/ + +#define COLDDR1 DDR(COLPORT1) +#define COLDDR2 DDR(COLPORT2) +#define ROWDDR DDR(ROWPORT) + +//Der Puffer, in dem das aktuelle Bild gespeichert wird +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + + +//Eine Zeile anzeigen +inline void rowshow(unsigned char row, unsigned char plane){ + //Die Zustände von der vorherigen Zeile löschen + COLPORT1 = 0; + COLPORT2 = 0; + + //kurze Warteschleife, damit die Treiber auch wirklich ausschalten + unsigned char i; + for(i=0;i<20;i++){ + asm volatile("nop"); + } + + + if (row == 0){ + //Zeile 0: Das erste Schieberegister initialisieren + ROWPORT&= ~(1< +#include +#include +#include "borg_hw.h" + +/* +// Diese #defines werden nun durch menuconfig gesetzt + + // 16 Spalten insgesamt direkt gesteuert, dafür 2 Ports +#define COLPORT1 PORTC +#define COLDDR1 DDRC + +#define COLPORT2 PORTA +#define COLDDR2 DDRA + +// Der andere Port übernimmt die Steuerung der Schieberegister +#define ROWPORT PORTD +#define ROWDDR DDRD +// Clock und reset gehen gemeinsam an beide Schieberegister +// der reset pin ist negiert +#define PIN_MCLR PD4 +#define PIN_CLK PD6 +//das dier sind die individuellen Dateneingänge für die Schieberegister +#define PIN_DATA PD7 +*/ + +#define COLDDR1 DDR(COLPORT1) +#define COLDDR2 DDR(COLPORT2) +#define ROWDDR DDR(ROWPORT) + +//Der Puffer, in dem das aktuelle Bild gespeichert wird +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + + +//zur nächsten Zeile weiterschalten +inline void nextrow(uint8_t row){ + //Die Zustände von der vorherigen Zeile löschen + COLPORT1 = 0; + COLPORT2 = 0; + + //kurze Warteschleife, damit die Treiber auch wirklich ausschalten + + unsigned char i; + for(i=0;i<10;i++){ + asm volatile("nop"); + } + + if (row == 0){ + //Zeile 0: Das erste Schieberegister initialisieren +#ifndef INVERSE_ROWS + ROWPORT&= ~(1<>1) + ((row & 0x01)?8:0 ); + tmp = pixmap[plane][row][0]; + tmp1 = pixmap[plane][row][1]; +#endif +#ifdef REVERSED_HARDWARE + tmp = (tmp >> 4) | (tmp << 4); + tmp = ((tmp & 0xcc) >> 2) | ((tmp & 0x33)<< 2); //0xcc = 11001100, 0x33 = 00110011 + tmp = ((tmp & 0xaa) >> 1) | ((tmp & 0x55)<< 1); //0xaa = 10101010, 0x55 = 1010101 + COLPORT2 = tmp; + tmp = tmp1; + tmp = (tmp >> 4) | (tmp << 4); + tmp = ((tmp & 0xcc) >> 2) | ((tmp & 0x33) << 2); //0xcc = 11001100, 0x33 = 00110011 + tmp = ((tmp & 0xaa) >> 1) | ((tmp & 0x55) << 1); //0xaa = 10101010, 0x55 = 1010101 + COLPORT1 = tmp; +#else +#ifdef INTERLACED_COLS + static uint8_t interlace_table[16] = { + 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 + }; + COLPORT1 = interlace_table[tmp&0x0f] | (interlace_table[tmp1&0x0f]<<1); + tmp>>=4; tmp1>>=4; + COLPORT2 = interlace_table[tmp] | (interlace_table[tmp1]<<1); +#else + COLPORT1 = tmp; + COLPORT2 = tmp1; +#endif +#endif + +} + + +//Dieser Interrupt wird je nach Ebene mit 50kHz 31,25kHz oder 12,5kHz ausgeführt +SIGNAL(SIG_OUTPUT_COMPARE0) +{ + static unsigned char plane = 0; + static unsigned char row = 0; + + //Watchdog zurücksetzen + wdt_reset(); + + //Zeile und Ebene inkrementieren + if(++plane==NUMPLANE){ + plane=0; + if(++row == NUM_ROWS){ + row = 0; + } + nextrow(row); + } + + //Die aktuelle Zeile in der aktuellen Ebene ausgeben + rowshow(row, plane); +} + + +void timer0_off(){ + cli(); + + COLPORT1 = 0; + COLPORT2 = 0; + ROWPORT = 0; + + TCCR0 = 0x00; + sei(); +} + + +// Den Timer, der denn Interrupt auslöst, initialisieren +void timer0_on(){ +/* TCCR0: FOC0 WGM00 COM01 COM00 WGM01 CS02 CS01 CS00 + CS02 CS01 CS00 + 0 0 0 stop + 0 0 1 clk + 0 1 0 clk/8 + 0 1 1 clk/64 + 1 0 0 clk/256 + 1 0 1 clk/1024 + +*/ + TCCR0 = 0x0C; // CTC Mode, clk/64 + TCNT0 = 0; // reset timer + OCR0 = 20; // Compare with this value + TIMSK = 0x02; // Compare match Interrupt on +} + +void borg_hw_init(){ + //Spalten Ports auf Ausgang + COLDDR1 = 0xFF; + COLDDR2 = 0xFF; + + //Pins am Zeilenport auf Ausgang + ROWDDR = (1< +#include +#include + +#include "borg_hw.h" + +/* +// Diese #defines werden nun durch menuconfig gesetzt + +#define ROWPORT PORTB +#define ROWDDR DDRB + +#define COLPORT PORTD +#define COLDDR DDRD + +#define PIN_DATA PC4 +#define PIN_CLK PC6 //active low +#define PIN_LINE_EN PC5 //active low + +*/ + +#define COLDDR DDR(COLPORT) +#define ROWDDR DDR(ROWPORT) + +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + + +inline void rowshow(unsigned char row, unsigned char plane){ + COLPORT |= (1<>=1; + COLPORT &= ~(1< +#include +#include + +#include "borg_hw.h" + +/* +// Diese #defines werden nun durch menuconfig gesetzt + +//An diesen Pins ist das Schieberegister +//für die Spalten angeschlossen. +#define COLPORT PORTC +#define COLDDR DDRC +#define BIT_DAT 4 //Daten-Eingang +#define BIT_CLK 5 //Takt-Eingang + +//An diesem Port sind die Zeilentreiber angeschlossen. +//Ein Null-Pegel schaltet den jeweiligen Transistor an. +#define ROWPORT1 PORTD +#define ROWDDR1 DDRD + +#define ROWPORT2 PORTC +#define ROWDDR2 DDRC +*/ + +#define COLDDR DDR(COLPORT) +#define ROWDDR1 DDR(ROWPORT1) +#define ROWDDR2 DDR(ROWPORT2) + +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + +inline void rowshow(unsigned char row, unsigned char plane){ + static uint8_t rowmask = 0xFF; + uint8_t x, tmp; + + //alle Zeilentreiber aus + ROWPORT1 |= 0xF3; + ROWPORT2 |= 0x0C; + + for(x=0;x<10;x++){ + asm volatile ("nop"); + } + + if (row == 0){ + rowmask = 0x7F; //0111 1111 + }else{ + rowmask >>= 1; + rowmask |= 0x80; + } + + switch (plane){ + case 0: + TCNT0 = 0x100-12; + break; + case 1: + TCNT0 = 0x100-20; + break; + case 2: + TCNT0 = 0x100-50; + } + + + + //Die fünf bits für das 2. Display in das + //Schieberegister takten + tmp = pixmap[plane][row][0]; + for(x=0;x<3;x++){ + if(tmp & 0x20){ + COLPORT &= ~(1<>=1; + + COLPORT |= (1<>=1; + + COLPORT |= (1<>=1; + + COLPORT |= (1< +#include +#include +#include +#include + +can_addr myaddr; +extern jmp_buf newmode_jmpbuf; + +void bcan_init() +{ + spi_init(); + can_init(); + + myaddr = eeprom_read_byte(0x00); + pdo_message *msg = (pdo_message *)can_buffer_get(); + msg->addr_src = myaddr; + msg->addr_dst = 0xff; + msg->port_src = PORT_BORG; + msg->port_dst = PORT_BORG; + msg->dlc = 4; + msg->cmd = FKT_BORG_INFO; + msg->data[0] = NUM_ROWS; + msg->data[1] = NUM_COLS; + msg->data[2] = NUM_PLANES; + + can_transmit((can_message *)msg); +} + +void process_mgt_msg(pdo_message *msg) +{ + pdo_message *rmsg; + + switch(msg->cmd) { + case FKT_MGT_RESET: + timer0_off(); + cli(); + while(1); + break; + case FKT_MGT_PING: + rmsg = (pdo_message *)can_buffer_get(); + rmsg->addr_dst = msg->addr_src; + rmsg->addr_src = myaddr; + rmsg->port_dst = msg->port_src; + rmsg->port_src = msg->port_dst; + rmsg->cmd = FKT_MGT_PONG; + rmsg->dlc = 1; + can_transmit((can_message *)rmsg); + break; + } +} + +void process_borg_msg(pdo_message *msg) +{ + unsigned char i, j; + + switch(msg->cmd) { + case FKT_BORG_MODE: + longjmp(newmode_jmpbuf, msg->data[0]); + break; + case FKT_BORG_SCROLLTEXT_RESET: + for(i=0; i < msg->dlc-1; i++) { + scrolltext_text[i] = msg->data[i]; + } + scrolltext_text[i] = 0; + + break; + case FKT_BORG_SCROLLTEXT_APPEND: + j=0; + while(scrolltext_text[j]) j++; + + for(i=0; i < msg->dlc-1; i++) { + scrolltext_text[i+j] = msg->data[i]; + } + scrolltext_text[i+j] = 0; + + break; + +#ifdef Hansi_hat_gelernt_Werte_vorher_zu_definieren + + //========== blinkenstuff + + //clear the blinkenbackbuffer to color + case FKT_BLINK_CLEARBUF: + blink_clearbuf(msg->data[0]); + break; + + //set auto position increment flag + case FKT_BLINK_SETAUTOPOS: + blink_setautopos(msg->data[0]); + break; + + //set the current blinkenbuffer offset position + case FKT_BLINK_SETPOS: + blink_setpos(msg->data[0]); + break; + + //puts the current blinkenbuffer to the frontbuffer + case FKT_BLINK_SHOW: + blink_show(); + break; + + //puts data into the blinkenbuffer + case FKT_BLINK_DATA: + blink_data(msg->data, msg->dlc - 1); + break; +#endif + } +} + +void bcan_process_messages() +{ + pdo_message *msg = (pdo_message*) can_get_nb(); + + while(msg) { + if (!msg) + return; + + if(msg->addr_dst == myaddr && msg->port_dst == PORT_MGT) + process_mgt_msg(msg); + + if(msg->addr_dst == myaddr && msg->port_dst == PORT_BORG) + process_borg_msg(msg); + + msg = (pdo_message*) can_get_nb(); + }; + +} diff --git a/can/borg_can.h b/can/borg_can.h new file mode 100644 index 0000000..07af73f --- /dev/null +++ b/can/borg_can.h @@ -0,0 +1,11 @@ +#ifndef BORG_CAN_H_ +#define BORG_CAN_H_ + +extern unsigned char borg_mode; +extern char scrolltext_text[]; + +void bcan_init(); +unsigned char bcan_mode(); +void bcan_process_messages(); + +#endif /* BORG_CAN_H */ diff --git a/can/can.c b/can/can.c new file mode 100644 index 0000000..5129228 --- /dev/null +++ b/can/can.c @@ -0,0 +1,496 @@ + +#ifndef __C64__ +#include +#include +#define asm asm volatile +#endif + +#include "can.h" +#include "spi.h" + +#define spi_clear_ss() SPI_PORT |= (1<msg.port_src << 2)) | (msg->msg.port_dst >> 4 ) ); + spi_data( (unsigned char)((msg->msg.port_dst & 0x0C) << 3) | (1<msg.port_dst & 0x03) ); + spi_data(msg->msg.addr_src); + spi_data(msg->msg.addr_dst); + spi_data(msg->msg.dlc); + for(x=0;xmsg.dlc;x++){ + spi_data(msg->msg.data[x]); + } + spi_clear_ss(); + spi_set_ss(); + spi_data(WRITE); + spi_data(TXB0CTRL); + spi_data( (1<msg.port_src = tmp1 >> 2; + tmp2 = spi_data(0); + tmp3 = (unsigned char)((unsigned char)(tmp2 >> 3) & 0x0C); + msg->msg.port_dst = ((unsigned char)(tmp1 <<4 ) & 0x30) | tmp3 | (unsigned char)(tmp2 & 0x03); + msg->msg.addr_src = spi_data(0); + msg->msg.addr_dst = spi_data(0); + msg->msg.dlc = spi_data(0) & 0x0F; + for(x=0;xmsg.dlc;x++){ + msg->msg.data[x] = spi_data(0); + } + spi_clear_ss(); + + mcp_bitmod(CANINTF, (1<flags & 0x01) ) { + message_fetch(&RX_BUFFER[RX_HEAD]); + RX_BUFFER[RX_HEAD].flags |= 0x01;//mark buffer as used + if( ++RX_HEAD == CAN_RX_BUFFER_SIZE) RX_HEAD = 0; + }else{ + //buffer overflow + //just clear the Interrupt condition, and lose the message + mcp_bitmod(CANINTF, (1<flags & 0x01) { + ((can_message_x*)&TX_BUFFER[TX_TAIL])->flags &= ~0x01; + TX_INT = 1; + message_load(&TX_BUFFER[TX_TAIL]); + if(++TX_TAIL == CAN_TX_BUFFER_SIZE) TX_TAIL = 0; + }else{ + TX_INT = 0; + } + mcp_bitmod(CANINTF, (1<msg); + } +} + +can_message * can_get(){ + can_message_x *p; + + while(RX_HEAD == RX_TAIL) { }; + + p = &RX_BUFFER[RX_TAIL]; + if(++RX_TAIL == CAN_RX_BUFFER_SIZE) RX_TAIL = 0; + + return &(p->msg); +} + + +//marks a receive buffer as unused again so it can be overwritten in Interrupt +void can_free(can_message * msg){ + can_message_x * msg_x = (can_message_x *) msg; + msg_x->flags = 0; +} + + +//returns pointer to the next can TX buffer +can_message * can_buffer_get(){ + can_message_x *p; + p = &TX_BUFFER[TX_HEAD]; + while (p->flags&0x01); //wait until buffer is free + if(++TX_HEAD == CAN_TX_BUFFER_SIZE) TX_HEAD = 0; + return &(p->msg); +} + + +//start transmitting can messages, and mark message msg as transmittable +void can_transmit(can_message* msg2){ + can_message_x* msg=(can_message_x*) msg2; + if(msg){ + msg->flags |= 0x01; + } + if(!TX_INT){ + if(((can_message_x*)&TX_BUFFER[TX_TAIL])->flags & 0x01){ + ((can_message_x*)&TX_BUFFER[TX_TAIL])->flags &= ~0x01; + TX_INT = 1; + message_load(&TX_BUFFER[TX_TAIL]); + if(++TX_TAIL == CAN_TX_BUFFER_SIZE) TX_TAIL = 0; + } + } +} + +#else // NON INTERRUPT VERSION + +can_message_x RX_MESSAGE, TX_MESSAGE; + +can_message * can_get_nb(){ + //check the pin, that the MCP's Interrup output connects to + if(SPI_REG_PIN_MCP_INT & (1< + +typedef unsigned char can_addr; +typedef unsigned char can_port; +typedef uint16_t can_channel_t; +typedef uint8_t can_subchannel_t; + +typedef struct +{ + uint32_t id; + uint8_t dlc; + uint8_t data[8]; +} can_message_raw; + +typedef struct{ + can_addr addr_src; + can_addr addr_dst; + can_port port_src; + can_port port_dst; + unsigned char dlc; + unsigned char data[8]; +}can_message; + +typedef struct +{ + can_channel_t channel; + can_subchannel_t subchannel; + can_addr addr_src; + can_addr addr_dst; + uint8_t dlc; + uint8_t data[8]; +} can_message_v2; + + +typedef enum { normal, mode_sleep, loopback, listenonly, config } can_mode_t ; + + +/***************************************************************************** + * Global variables + */ +#ifdef CAN_HANDLEERROR + extern unsigned char can_error; +#endif + + +/***************************************************************************** + * Management + */ + +void can_init(); +void can_setfilter(); +void can_setmode(can_mode_t); +void can_setled(unsigned char led, unsigned char state); + + +/***************************************************************************** + * Sending + */ + +can_message * can_buffer_get(); +void can_transmit( can_message *msg ); + + +/***************************************************************************** + * Receiving + */ + +can_message *can_get(); +can_message *can_get_nb(); + +// this is only needed for Interrupt driven Version +#ifndef CAN_INTERRUPT +// # define can_free(m) + void can_free(can_message * msg); +#else + void can_free(can_message * msg); +#endif + + +/***************************************************************************** + * Sending + */ + +can_message_raw * can_buffer_get_raw(); +void can_transmit_raw( can_message_raw *msg ); + + +/***************************************************************************** + * Receiving + */ + +can_message_raw *can_get_raw(); +can_message_raw *can_get_raw_nb(); + +// this is only needed for Interrupt driven Version +#ifndef CAN_INTERRUPT +// # define can_free(m) + void can_free_raw(can_message_raw * msg); +#else + void can_free_raw(can_message_raw * msg); +#endif + + + + +/***************************************************************************** + * Sending + */ + +void can_transmit_v2( can_message_v2 *msg ); + + +/***************************************************************************** + * Receiving + */ + +can_message_v2 *can_get_v2_nb(); + +void can_free_v2(can_message_v2 *msg); + + + +#endif diff --git a/can/spi.c b/can/spi.c new file mode 100644 index 0000000..30b7ea0 --- /dev/null +++ b/can/spi.c @@ -0,0 +1,55 @@ +#include +#include "spi.h" + + +void spi_init(){ + //set output SPI pins to output + SPI_DDR |= (1< $@ + @echo "#F_CPU = $(F_CPU)" >> $@ + @echo "#MCU = $(MCU)" >> $@ + @echo "created default config.mk, tune your settings there!" +-include $(TOPDIR)/config.mk + + +############################################################################## +# configure load address for bootloader, if enabled +# +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),mrproper) +ifneq ($(MAKECMDGOALS),menuconfig) + +include $(TOPDIR)/.config + +CPPFLAGS += -DF_CPU=$(FREQ)UL -mmcu=$(MCU) + +endif # MAKECMDGOALS!=menuconfig +endif # MAKECMDGOALS!=mrproper +endif # MAKECMDGOALS!=clean + +ifeq ($(BOOTLOADER_SUPPORT),y) +LDFLAGS += -Wl,--section-start=.text=0xE000 +CFLAGS += -mcall-prologues +endif + + +%.s: %.c + $(CC) -o $@ -O0 $(CPPFLAGS) -S $< + +%.E: %.c + $(CC) -o $@ -O0 $(CPPFLAGS) -C -E -dD $< + diff --git a/depend.mk b/depend.mk new file mode 100644 index 0000000..91b8f76 --- /dev/null +++ b/depend.mk @@ -0,0 +1,32 @@ +# How to build automatic dependencies + +# Don't include dependencies if $(no_deps) is set; the master makefile +# does this for clean and other such targets that don't need +# dependencies. That then avoids rebuilding dependencies. + +ifneq ($(no_deps),t) +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),mrproper) +ifneq ($(MAKECMDGOALS),menuconfig) + +# For each .o file we need a .d file. +-include $(subst .o,.d,$(filter %.o,$(OBJECTS))) /dev/null + +endif +endif +endif +endif + +# Here is how to build those dependency files + +define make-deps +set -e; $(CC) $(CFLAGS) $(CPPFLAGS) -M -MM $< | \ +sed > $@.new -e 's;$(*F)\.o:;$@ $*.o $*.E $*.s:;' \ + -e 's% [^ ]*/gcc-lib/[^ ]*\.h%%g' +if test -s $@.new; then mv -f $@.new $@; else rm -f $@.new; fi +endef + +# Here is how to make .d files from .c files +%.d: %.c $(TOPDIR)/pinning.c; $(make-deps) + +%.d: %.S ; $(make-deps) diff --git a/eeprom_reserve.c b/eeprom_reserve.c new file mode 100644 index 0000000..41412d8 --- /dev/null +++ b/eeprom_reserve.c @@ -0,0 +1,14 @@ +/* + * + * + * + * + * + */ + +#include +#include + +uint8_t EEMEM do_not_use; + + diff --git a/games/invader_draw.c b/games/invader_draw.c new file mode 100644 index 0000000..bbdea2c --- /dev/null +++ b/games/invader_draw.c @@ -0,0 +1,115 @@ +#include "invaders2.h" +/*----------------------getter/setter----------------------------*/ + +unsigned char getInvaderPixel(Invaders * iv, unsigned char x, unsigned char y) +{ + if (((x - iv->pos.x) < MAX_INVADER_WIDTH) && ((x - iv->pos.x) >= 0) && ((y + - iv->pos.y) < MAX_INVADER_HEIGHT) && ((y - iv->pos.y) >= 0)) + { + return iv->map[x - iv->pos.x][y - iv->pos.y]; + } + return 0; +} + +void setInvaderPixel(Invaders * iv, unsigned char x, unsigned char y, + unsigned char val) +{ + if (((x - iv->pos.x) < MAX_INVADER_WIDTH) && ((x - iv->pos.x) >= 0) && ((y + - iv->pos.y) < MAX_INVADER_HEIGHT) && ((y - iv->pos.y) >= 0)) + { + iv->map[x - iv->pos.x][y - iv->pos.y] = val; + } +} + +unsigned char getGuardPixel(unsigned char guards[BORG_WIDTH], unsigned char x, + unsigned char y) +{ + if (x < BORG_WIDTH && y == GUARD_LINE) + return guards[x]; + return 0; +} + +void setGuardPixel(unsigned char guards[BORG_WIDTH], unsigned char x, + unsigned char y, unsigned char val) +{ + if (x < BORG_WIDTH && y == GUARD_LINE && val <= 3) + guards[x] = val; +} + +/*----------------------drawing Method---------------------------*/ + +void draw(Invaders * iv, Spaceship * sc, Player * pl, Cannon * cn, + unsigned char guards[BORG_WIDTH], uPixel st[MAX_SHOTS], uPixel * shot) +{ + clearScreen (); + + int x, y; + + /*---SPACESHIP---*/ + if (sc->pos < RIGHT_BORDER) + { + setPixel (sc->pos, SPACESHIP_LINE, sc->lives); + } + if (sc->pos - 1 < RIGHT_BORDER) + { + setPixel (sc->pos + 1, SPACESHIP_LINE, sc->lives); + } + + /*---INVADERS--*/ + for (y = 0; y < MAX_INVADER_HEIGHT; y++) + { + for (x = 0; x < MAX_INVADER_WIDTH; x++) + { + //mal in oder statement umwandeln ;-) + if (iv->map[x][y] == 0) + continue; + if (x + iv->pos.x > RIGHT_BORDER) + continue; + if (x + iv->pos.x < 0) + continue; + + setPixel (x + iv->pos.x, y + iv->pos.y, iv->map[x][y]); + } + } + + /*---GUARDS---*/ + for (x = 0; x < BORG_WIDTH; ++x) + { + if (guards[x] != 0) + { + setPixel (x, GUARD_LINE, guards[x]); + } + } + + /*---SHOTS--*/ + int i; + for (i = 0; i < MAX_SHOTS; ++i) + { + if (st[i].x < BORG_WIDTH && st[i].y < BORG_HEIGHT) + { + setPixel (st[i].x, st[i].y, 3); + } + } + + /*draw player shot */ + if (!(cn->ready)) + { + setPixel (shot->x, shot->y, 3); + } + + /*-- CANNON --*/ + if (cn->pos >= LEFT_BORDER + 1) + { + setPixel (cn->pos - 1, 15, pl->lives); + } + if (cn->pos < BORG_WIDTH) + { + setPixel (cn->pos, 15, pl->lives); + setPixel (cn->pos, 14, pl->lives); + } + if (cn->pos < RIGHT_BORDER) + { + setPixel (cn->pos + 1, 15, pl->lives); + } + +} diff --git a/games/invader_init.c b/games/invader_init.c new file mode 100644 index 0000000..8fa56d4 --- /dev/null +++ b/games/invader_init.c @@ -0,0 +1,153 @@ +#include "invaders2.h" + +unsigned char peter[8][11] = +{ +{ 0, 0, P, 0, 0, 0, 0, 0, P, 0, 0 }, +{ 0, 0, 0, P, 0, 0, 0, P, 0, 0, 0 }, +{ 0, 0, P, P, P, P, P, P, P, 0, 0 }, +{ 0, P, P, 0, P, P, P, 0, P, P, 0 }, +{ P, P, P, P, P, P, P, P, P, P, P }, +{ P, 0, P, P, P, P, P, P, P, 0, P }, +{ P, 0, P, 0, 0, 0, 0, 0, P, 0, P }, +{ 0, 0, 0, P, P, 0, P, P, 0, 0, 0 } }; + +unsigned char hans[8][11] = +{ +{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, +{ 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1 }, +{ 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2 }, +{ 1, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1 }, +{ 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2 }, +{ 1, 2, 2, 1, 2, 1, 2, 1, 2, 2, 2 }, +{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, +{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; + +void initGuards(unsigned char guards[BORG_WIDTH]) +{ + int x; + for (x = 0; x < BORG_WIDTH; ++x) + { + guards[x] = 0; + } + + guards[3] = 3; + guards[6] = 3; + guards[10] = 3; + guards[13] = 3; + +} + +void initInvaders(Invaders * iv, unsigned char lv) +{ + unsigned char x, y; + + // first zero out map! + for (x = 0; x < MAX_INVADER_WIDTH; ++x) + { + for (y = 0; y < MAX_INVADER_HEIGHT; ++y) + { + iv->map[x][y] = 0; + } + } + + iv->speedinc = 0; + iv->isEdged = 0; + + switch (lv) + { + case 0: + for (x = 0; x < 8; ++x) + { + iv->map[x][0] = 2; + iv->map[x][1] = 2; + iv->map[x][2] = 2; + iv->map[x][3] = 1; + // iv->map[x][4] = 1; + } + + iv->pos.x = 4; + iv->pos.y = SPACESHIP_LINE + 1; + iv->speed = MIN_SPEED - 3; + iv->direction = 1; + break; + + case 1: + for (x = 0; x < 8; ++x) + { + //for(y = 0; y < MAX_INVADER_HEIGHT; ++y) { + iv->map[x][0] = 3; + iv->map[x][1] = 3; + iv->map[x][2] = 2; + iv->map[x][3] = 2; + // iv->map[x][4] = 1; + //} + } + + iv->pos.x = 4; + iv->pos.y = SPACESHIP_LINE + 1; + iv->speed = MIN_SPEED - 2; + + iv->direction = 1; + break; + + case 2: + for (x = 0; x < 8; ++x) + { + //for(y = 0; y < MAX_INVADER_HEIGHT; ++y) { + iv->map[x][0] = 3; + iv->map[x][1] = 3; + iv->map[x][2] = 2; + iv->map[x][3] = 2; + iv->map[x][4] = 1; + //} + } + + iv->pos.x = 4; + iv->pos.y = SPACESHIP_LINE + 1; + iv->speed = MIN_SPEED - 1; + + iv->direction = 1; + break; + + case 3: + for (x = 0; x < 11; ++x) + { + for (y = 0; y < 8; ++y) + { + if (hans[y][x] != 0) + { + iv->map[x][y] = 2; + } + } + } + + iv->pos.x = 3; + iv->pos.y = SPACESHIP_LINE + 1; + + iv->speed = MIN_SPEED + 2; + iv->direction = 1; + + break; + + case 4: + for (x = 0; x < 11; ++x) + { + for (y = 0; y < 8; ++y) + { + if (peter[y][x] != 0) + { + iv->map[x][y] = 2; + } + } + } + + iv->pos.x = 3; + iv->pos.y = SPACESHIP_LINE + 1; + + iv->speed = MIN_SPEED + 3; + iv->direction = 1; + + break; + + } +} diff --git a/games/invader_proc.c b/games/invader_proc.c new file mode 100644 index 0000000..bfd521f --- /dev/null +++ b/games/invader_proc.c @@ -0,0 +1,304 @@ +#include +#include "prng.h" +#include "invaders2.h" + +void procCannon(Cannon * cn, uPixel * shot) +{ + static unsigned char mv = 0; + if (mv >= CANNON_SPEED) + { + mv = 0; + if (JOYISLEFT) + { + if (cn->pos != RIGHT_BORDER) + { + cn->pos++; + } + } + else if (JOYISRIGHT) + { + if (cn->pos != LEFT_BORDER) + { + cn->pos--; + } + } + else if (JOYISFIRE) + { + + if (cn->ready) + { + shot->x = cn->pos; + shot->y = 14; + cn->ready = 0; + } + } + + } + else + { + mv++; + } + +} + +unsigned char areAtBorder(Invaders * iv) +{ + int y; + for (y = SPACESHIP_LINE + 1; y <= GUARD_LINE; ++y) + { + if (getInvaderPixel(iv, LEFT_BORDER, y) || getInvaderPixel(iv, + RIGHT_BORDER, y)) + { + return 1; + } + } + return 0; + +} + +void procInvaders(Invaders * iv, uPixel st[MAX_SHOTS]) +{ + static unsigned char mv = 0; + + if (mv >= iv->speed) + { + mv = 0; + if (areAtBorder(iv) && !(iv->isEdged)) + { + iv->pos.y++; + iv->direction = -iv->direction; + iv->isEdged = 1; + } + else + { + iv->pos.x += iv->direction; + iv->isEdged = 0; + } + + } + mv++; + + unsigned char i, y; + unsigned char spos = random8() % 16; + if (spos >= BORG_WIDTH) + return; + + unsigned char shoot = random8(); + + if (shoot < SHOOTING_RATE) + { + for (i = 0; i < MAX_SHOTS; ++i) + { + if (st[i].x > BORG_WIDTH || st[i].y > BORG_HEIGHT) + { + + for (y = GUARD_LINE; y > SPACESHIP_LINE; --y) + { + if (getInvaderPixel(iv, spos, y) != 0) + { + + st[i].x = spos; + st[i].y = y + 1; + return; + } + } + } + } //for SHOTS + } + +} + +void procShots(Invaders * iv, Player * pl, Cannon * cn, Spaceship * sc, + unsigned char guards[BORG_WIDTH], uPixel st[MAX_SHOTS], uPixel * shot) +{ + + int i; + static unsigned char cmv = 0, imv = 0; + + // shuß mit einen struct mit dem shuß!! + + if (cmv >= CANNON_SHOOTING_SPEED) + { + cmv = 0; + if (!(cn->ready)) + { + shot->y--; + } + if (shot->y > BORG_HEIGHT) + { + cn->ready = 1; + } + } + + if (imv >= INVADER_SHOOTING_SPEED) + { + imv = 0; + + for (i = 0; i < MAX_SHOTS; ++i) + { + if ( /*st[i].x < BORG_WIDTH && */st[i].y < BORG_HEIGHT) + { + st[i].y++; + } + } + } + + cmv++; + imv++; + + /****************************************************************/ + /* TESTE OB GETROFFEN */ + /****************************************************************/ + + // USER CANNON + + unsigned char tmp; + if (!(cn->ready)) + { + for (i = 0; i < MAX_SHOTS; ++i) + { + if (shot->x == st[i].x && shot->y == st[i].y) + { + st[i].x = 255; + st[i].y = 255; + cn->ready = 1; + } + } + + //GUARDS + if ((tmp = getGuardPixel(guards, shot->x, shot->y))) + { + --tmp; + setGuardPixel(guards, shot->x, shot->y, tmp); + cn->ready = 1; + goto invader_shots; + } + + //INVADER + if ((tmp = getInvaderPixel(iv, shot->x, shot->y))) + { + --tmp; + setInvaderPixel(iv, shot->x, shot->y, tmp); + + if (tmp == 0) + { + iv->speedinc++; + if (iv->speedinc == SPEED_INC_RATE) + { + iv->speedinc = 0; + iv->speed -= SPEED_INC_VALUE; + } + pl->points += POINTS_FOR_KILL; + } + else + { + pl->points += POINTS_FOR_HIT; + } + cn->ready = 1; + goto invader_shots; + } + + //SPACESHIP + + if (shot->y == SPACESHIP_LINE) + { + if (shot->x == sc->pos || shot->x == sc->pos + 1) + { + sc->pos = 255; + pl->points += POINTS_FOR_SPACESHIP; + cn->ready = 1; + goto invader_shots; + } + } + } // !(cn->ready) + + + invader_shots: for (i = 0; i < MAX_SHOTS; ++i) + { + if ((tmp = getGuardPixel(guards, st[i].x, st[i].y))) + { + --tmp; + setGuardPixel(guards, st[i].x, st[i].y, tmp); + st[i].x = 255; + st[i].y = 255; + } + + if (st[i].y == BORG_HEIGHT - 1) + { + if (st[i].x == cn->pos) + { + + pl->lives--; + st[i].x = 255; + st[i].y = 255; + } + } + } + +} + +void procSpaceship(Spaceship * sc) +{ + unsigned char rnd1 = random8(); + unsigned char rnd2 = random8(); + + static unsigned char sct = 0; + + if (sc->pos > RIGHT_BORDER) + { + + if (rnd1 == 73) + { + if (rnd2 >= 200) + { + sc->pos = RIGHT_BORDER; + sct = 0; + } + } + + } + else + { + if (sct == SPACESHIP_SPEED) + { + sct = 0; + if (sc->pos == 0) + { + sc->pos = 255; + } + else + { + sc->pos--; + } + } + } + sct++; +} + +unsigned char getStatus(Invaders * iv) +{ + + //count Invader! + unsigned char x, y, inv = 0; + for (x = 0; x < MAX_INVADER_WIDTH; ++x) + { + for (y = 0; y < MAX_INVADER_HEIGHT; ++y) + { + if (iv->map[x][y] != 0) + inv++; + } + } + + //LEVEL BEREINIGT + if (inv == 0) + return 1; + + //INVADERS REACHED EARTH + for (x = 0; x < BORG_WIDTH; ++x) + { + if (getInvaderPixel(iv, x, GUARD_LINE + 1)) + return 2; + } + + return 0; +} diff --git a/games/invaders2.c b/games/invaders2.c new file mode 100644 index 0000000..a4e7da5 --- /dev/null +++ b/games/invaders2.c @@ -0,0 +1,134 @@ +#include +#include "util.h" +#include "invaders2.h" + +//#include + +#ifndef __AVR__ +#define wait(_X) myWait(_X) +#endif + +void borg_invaders() +{ + // waitForFire = 0; + /****************************************************************/ + /* INITIALIZE */ + /****************************************************************/ + + Invaders iv; + Cannon cn; + Player pl; + Spaceship sc; + + unsigned char guards[BORG_WIDTH]; + + unsigned char level = 0; + unsigned char ivStatus = 0; + + uPixel st[MAX_SHOTS] = + { + { 255, 255}, + { 255, 255}, + { 255, 255}, + { 255, 255}, + { 255, 255} + }; + + uPixel shot; + // = {0,0}; + + pl.points = 0; + pl.lives = 3; + + //--------Init Cannon-------// + //cn.pos = 4; + //cn.ready = 1; + + /****************************************************************/ + /* INTRO */ + /****************************************************************/ + //drawIntroScreen(2000); + + + /****************************************************************/ + /* GAME LOOP */ + /****************************************************************/ + do + { + //----- INITIALIZE LEVEL-----// + initGuards(guards); + initInvaders(&iv, level); + + //Spaceship + sc.lives = 1; + sc.pos = 255; + + //Cannon + cn.pos = 7; + cn.ready = 1; + + draw(&iv, &sc, &pl, &cn, guards, st, &shot); + + while (1) + { + procInvaders(&iv, st); + procSpaceship(&sc); + + procShots(&iv, &pl, &cn, &sc, guards, st, &shot); + procCannon(&cn, &shot); + + draw(&iv, &sc, &pl, &cn, guards, st, &shot); + + ivStatus = getStatus(&iv); + + if (ivStatus == 2) //LOST + { + //pl.lives--; + pl.lives = 0; + break; + + } + else if (ivStatus == 1) //WON + { + unsigned int bonus= POINTS_FOR_LEVEL * (level + 1) * (12 - iv.pos.y); + pl.points += bonus; + //printf("cleared l: %d , y: %d bonus: %d \n", + // level, iv.pos.y, bonus); + if (level == MAX_LEVEL - 1) + { + level = 0; + } + else + { + level = (level + 1); + } + break; + } + + if (pl.lives <= 0) + { + //scrolltext("GAME OVER",0,80); + break; + } + + wait (WAIT_MS); + } //IN LEVEL LOOP + + } while (pl.lives > 0); //GAME LOOP + + clearScreen (); + //wait(5000); + char text[64]; + snprintf(text, 64, " +#include +#include +#include +#include "../joystick.h" +#include "../util.h" +#include "input.h" + +/* - the API simulator and the real API have different named wait functions + * - the macro PM helps in reading values from PROGMEM on the AVR arch + */ +#ifdef __AVR__ + #include + #define WAIT(ms) wait(ms) + #define PM(value) pgm_read_word(&value) +#else + #define PROGMEM + #define WAIT(ms) myWait(ms) + #define PM(value) (value) +#endif + + +/*********** + * defines * + ***********/ + +// amount of milliseconds that each loop cycle waits +#define TETRIS_INPUT_TICKS 5 + +// amount of milliseconds the input is ignored after the pause combo has been +// pressed, since it is difficult to release all buttons simultaneously +#define TETRIS_INPUT_PAUSE_TICKS 100 + +// amount of allowed loop cycles while in pause mode so that the game +// automatically continues after five minutes +#define TETRIS_INPUT_PAUSE_CYCLES 60000 + +// minimum of cycles in gliding mode +#define TETRIS_INPUT_GLIDE_CYCLES 75 + +// here you can adjust the delays (in loop cycles) for key repeat +#define TETRIS_INPUT_REPEAT_INITIALDELAY 40 +#define TETRIS_INPUT_REPEAT_DELAY 10 + +// Here you can adjust the amount of loop cycles a command is ignored after +// its button has been released (to reduce joystick chatter) +#define TETRIS_INPUT_CHATTER_TICKS_ROT_CW 24 +#define TETRIS_INPUT_CHATTER_TICKS_ROT_CCW 24 +#define TETRIS_INPUT_CHATTER_TICKS_LEFT 12 +#define TETRIS_INPUT_CHATTER_TICKS_RIGHT 12 +#define TETRIS_INPUT_CHATTER_TICKS_DOWN 12 +#define TETRIS_INPUT_CHATTER_TICKS_DROP 24 + + +/*************************** + * non-interface functions * + ***************************/ + +/* Function: tetris_input_chatterProtect; + * Description: sets an ignore counter to a command specific value if it is 0 + * Argument pIn: pointer to an input object + * Argument cmd: the command whose counter should be set + * Return value: void + */ +void tetris_input_chatterProtect (tetris_input_t *pIn, + tetris_input_command_t cmd) +{ + // never exceed the index + assert(cmd < TETRIS_INCMD_NONE); + + // amount of loop cycles a command is ignored after its button has been + // released (every command has its own counter) + const static uint8_t nInitialIgnoreValue[TETRIS_INCMD_NONE] PROGMEM = + { + TETRIS_INPUT_CHATTER_TICKS_ROT_CW, + TETRIS_INPUT_CHATTER_TICKS_ROT_CCW, + TETRIS_INPUT_CHATTER_TICKS_LEFT, + TETRIS_INPUT_CHATTER_TICKS_RIGHT, + TETRIS_INPUT_CHATTER_TICKS_DOWN, + TETRIS_INPUT_CHATTER_TICKS_DROP, + 0, // TETRIS_INCMD_GRAVITY (irrelevant because it doesn't have a button) + 0 // TETRIS_INCMD_PAUSE (is a combination of ROT_CW and DOWN) + }; + + // setting ignore counter according to the predefined array + if (pIn->nIgnoreCmdCounter[cmd] == 0) + { + // if the command isn't TETRIS_INCMD_PAUSE, setting the ignore counter + // is straight forward + if (cmd != TETRIS_INCMD_PAUSE) + { + pIn->nIgnoreCmdCounter[cmd] = PM(nInitialIgnoreValue[cmd]); + } + // TETRIS_INCMD_PAUSE is issued via a combination of the buttons for + // TETRIS_INCMD_ROT_CW and TETRIS_INCMD_DOWN, so we must set their + // ignore counters + else + { + pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW] = + TETRIS_INPUT_CHATTER_TICKS_ROT_CW; + pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN] = + TETRIS_INPUT_CHATTER_TICKS_DOWN; + } + } + + // The ignore counter of TETRIS_INCMD_PAUSE is either set to the counter + // value of TETRIS_INCMD_ROT_CW or TETRIS_INCMD_DOWN (whichever is higher). + if ((cmd == TETRIS_INCMD_ROT_CW) || (cmd == TETRIS_INCMD_DOWN)) + { + // helper variables (which the compiler hopefully optimizes away) + uint8_t nRotCw = pIn->nIgnoreCmdCounter[TETRIS_INCMD_ROT_CW]; + uint8_t nDown = pIn->nIgnoreCmdCounter[TETRIS_INCMD_DOWN]; + + pIn->nIgnoreCmdCounter[TETRIS_INCMD_PAUSE] = + (nRotCw > nDown ? nRotCw : nDown); + } +} + + +/* Function: tetris_input_queryJoystick + * Description: translates joystick movements into tetris_input_command_t + * Argument pIn: pointer to an input object + * Return value: see definition of tetris_input_command_t + */ +tetris_input_command_t tetris_input_queryJoystick() +{ + tetris_input_command_t cmdReturn; + + if (JOYISFIRE) + { + cmdReturn = TETRIS_INCMD_DROP; + } + else if (JOYISLEFT) + { + cmdReturn = TETRIS_INCMD_LEFT; + } + else if (JOYISRIGHT) + { + cmdReturn = TETRIS_INCMD_RIGHT; + } + else if (JOYISUP && JOYISDOWN) + { + cmdReturn = TETRIS_INCMD_PAUSE; + WAIT(TETRIS_INPUT_PAUSE_TICKS); + } + else if (JOYISDOWN) + { + cmdReturn = TETRIS_INCMD_DOWN; + } + else if (JOYISUP) + { + cmdReturn = TETRIS_INCMD_ROT_CW; + } + else + { + cmdReturn = TETRIS_INCMD_NONE; + } + + return cmdReturn; +} + + +/***************************** + * construction/destruction * + *****************************/ + +/* Function: tetris_input_construct + * Description: constructs an input object for André's borg + * Return value: pointer to a newly created input object + */ +tetris_input_t *tetris_input_construct() +{ + tetris_input_t *pIn = (tetris_input_t *)malloc(sizeof(tetris_input_t)); + assert(pIn != NULL); + + pIn->cmdLast = TETRIS_INCMD_NONE; + pIn->nLevel = 0xFF; + tetris_input_setLevel(pIn, 0); + pIn->nLoopCycles = 0; + pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY; + pIn->nPauseCount = 0; + memset(pIn->nIgnoreCmdCounter, 0, TETRIS_INCMD_NONE); + + return pIn; +} + + +/* Function: tetris_input_destruct + * Description: destructs an input structure + * Argument pIn: pointer to the input object which should to be destructed + * Return value: void + */ +void tetris_input_destruct(tetris_input_t *pIn) +{ + assert(pIn != NULL); + free(pIn); +} + + +/*************************** + * input related functions * + ***************************/ + +/* Function: retris_input_getCommand + * Description: retrieves commands from joystick or loop interval + * Argument pIn: pointer to an input object + * Argument nPace: falling pace (see definition of tetris_input_pace_t) + * Return value: see definition of tetris_input_command_t + */ +tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn, + tetris_input_pace_t nPace) +{ + assert (pIn != NULL); + + // holds the translated command value of the joystick + tetris_input_command_t cmdJoystick = TETRIS_INCMD_NONE; + + // this variable both serves as the return value and as a flag for not + // leaving the function as long as its value is TETRIS_INCMD_NONE + tetris_input_command_t cmdReturn = TETRIS_INCMD_NONE; + + uint8_t nMaxCycles; + + // if the piece is gliding we grant the player a reasonable amount of time + // to make the game more controllable at higher falling speeds + if ((nPace == TETRIS_INPACE_GLIDING) && + (pIn->nMaxCycles < TETRIS_INPUT_GLIDE_CYCLES)) + { + nMaxCycles = TETRIS_INPUT_GLIDE_CYCLES; + } + else + { + nMaxCycles = pIn->nMaxCycles; + } + + while (pIn->nLoopCycles < nMaxCycles) + { + cmdJoystick = tetris_input_queryJoystick(); + + // only obey current command if it is not considered as chattering + if (((cmdJoystick < TETRIS_INCMD_NONE) ? + pIn->nIgnoreCmdCounter[cmdJoystick] : 0) == 0) + { + switch (cmdJoystick) + { + case TETRIS_INCMD_LEFT: + case TETRIS_INCMD_RIGHT: + case TETRIS_INCMD_DOWN: + // only react if either the current command differs from the + // last one or enough loop cycles have been run on the same + // command (for key repeat) + if ((pIn->cmdLast != cmdJoystick) + || ((pIn->cmdLast == cmdJoystick) + && (pIn->nRepeatCount >= TETRIS_INPUT_REPEAT_DELAY))) + { + // reset repeat counter + if (pIn->cmdLast != cmdJoystick) + { + // different command: we set an extra initial delay + pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY; + } + else + { + // same command: there's no extra initial delay + pIn->nRepeatCount = 0; + } + + // update cmdLast and return value + pIn->cmdLast = cmdReturn = cmdJoystick; + } + else + { + // if not enough loop cycles have been run we increment the + // repeat counter, ensure that we continue the loop and + // keep the key repeat functioning + ++pIn->nRepeatCount; + cmdReturn = TETRIS_INCMD_NONE; + } + break; + + case TETRIS_INCMD_DROP: + case TETRIS_INCMD_ROT_CW: + case TETRIS_INCMD_ROT_CCW: + // no key repeat here + if (pIn->cmdLast != cmdJoystick) + { + pIn->cmdLast = cmdReturn = cmdJoystick; + } + else + { + // if we reach here the command is ignored + cmdReturn = TETRIS_INCMD_NONE; + } + break; + + case TETRIS_INCMD_PAUSE: + // if this is an initial pause command, make sure that the logic + // module is informed about it + if (pIn->cmdLast != TETRIS_INCMD_PAUSE) + { + pIn->cmdLast = cmdReturn = cmdJoystick; + pIn->nPauseCount = 0; + } + // consecutive pause commands should not cause the loop to leave + else + { + cmdReturn = TETRIS_INCMD_NONE; + } + break; + + case TETRIS_INCMD_NONE: + // chatter protection + if (pIn->cmdLast != TETRIS_INCMD_NONE) + { + tetris_input_chatterProtect(pIn, pIn->cmdLast); + } + + // If the game is paused (last command was TETRIS_INCMD_PAUSE) + // we ensure that the variable which holds that last command + // isn't touched. We use this as a flag so that the loop cycle + // counter doesn't get incremented. + // We count the number of pause cycles, though. If enough pause + // cycles have been run, we enforce the continuation of the game. + if ((pIn->cmdLast != TETRIS_INCMD_PAUSE) || + (++pIn->nPauseCount > TETRIS_INPUT_PAUSE_CYCLES)) + { + pIn->cmdLast = TETRIS_INCMD_NONE; + } + + // reset repeat counter + pIn->nRepeatCount = -TETRIS_INPUT_REPEAT_INITIALDELAY; + + // using cmdReturn as a flag for not leaving the loop + cmdReturn = TETRIS_INCMD_NONE; + break; + + default: + break; + } + } + // current command is considered as chattering + else + { + pIn->cmdLast = cmdReturn = TETRIS_INCMD_NONE; + } + + // decrement all ignore counters + for (int nIgnoreIndex = 0; nIgnoreIndex < TETRIS_INCMD_NONE; ++nIgnoreIndex) + { + if (pIn->nIgnoreCmdCounter[nIgnoreIndex] != 0) + { + --pIn->nIgnoreCmdCounter[nIgnoreIndex]; + } + } + + // reset automatic falling if the player has dropped a piece + if ((cmdReturn == TETRIS_INCMD_DOWN) + || (cmdReturn == TETRIS_INCMD_DROP)) + { + pIn->nLoopCycles = 0; + } + // otherwise ensure automatic falling (unless the game is running) + else if ((cmdReturn != TETRIS_INCMD_PAUSE) && + !((cmdReturn == TETRIS_INCMD_NONE) && + (pIn->cmdLast == TETRIS_INCMD_PAUSE))) + { + ++pIn->nLoopCycles; + } + + WAIT(TETRIS_INPUT_TICKS); + if (cmdReturn != TETRIS_INCMD_NONE) + { + return cmdReturn; + } + } + + // since we have left the loop we reset the cycle counter + pIn->nLoopCycles = 0; + + return TETRIS_INCMD_GRAVITY; +} + + +/* Function: tetris_input_setLevel + * Description: modifies time interval of input events + * Argument pIn: pointer to an input object + * Argument nLvl: desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1) + * Return value: void + */ +void tetris_input_setLevel(tetris_input_t *pIn, + uint8_t nLvl) +{ + assert(pIn != NULL); + assert(nLvl <= TETRIS_INPUT_LEVELS - 1); + if (pIn->nLevel != nLvl) + { + pIn->nLevel = nLvl; + pIn->nMaxCycles = 400 / (nLvl + 2); + } +} diff --git a/games/tetris/input.h b/games/tetris/input.h new file mode 100644 index 0000000..faf7aca --- /dev/null +++ b/games/tetris/input.h @@ -0,0 +1,129 @@ +#ifndef INPUT_H_ +#define INPUT_H_ + +#include + + +/*********** + * defines * + ***********/ + +// number of levels +#define TETRIS_INPUT_LEVELS 20 + + +/********* + * types * + *********/ + +typedef enum tetris_input_command_t +{ + TETRIS_INCMD_ROT_CW, // rotate clockwise + TETRIS_INCMD_ROT_CCW, // rotate counter clockwise + TETRIS_INCMD_LEFT, // move piece left + TETRIS_INCMD_RIGHT, // move piece right + TETRIS_INCMD_DOWN, // lower piece by one row + TETRIS_INCMD_DROP, // move piece to the ground immediately + TETRIS_INCMD_GRAVITY, // piece gets pulled by gravity + TETRIS_INCMD_PAUSE, // pause the game + TETRIS_INCMD_NONE // idle (must alway be the last one) +} +tetris_input_command_t; + + +typedef enum tetris_input_pace_t +{ + TETRIS_INPACE_HOVERING, // normal falling pace + TETRIS_INPACE_GLIDING /* guarantees a minimum docking time to avoid that + pieces are docked immediately if they hit something + in higher levels */ +} +tetris_input_pace_t; + + +typedef struct tetris_input_t +{ + // current level (determines falling speed) + uint8_t nLevel; + + // Amount of loop cycles between forced piece movements. This value gets + // set via the tetris_input_setLevel() function. + uint8_t nMaxCycles; + + // This counter keeps track of the number of loop cycles whoch have been + // done since the last forced piece movement. It gets reset if it either + // reaches a well defined value (causing a gravity command to be issued) + // or the player has moved down the piece herself/himself. + uint8_t nLoopCycles; + + // Amount of loop cycles in which the same command has been issued + // consecutively. It gets reset if either the current command differs from + // the last one or a well-defined value has been reached (thereby + // regulating the pace of the key repeat as commands are only processed + // if that value is reached). + int8_t nRepeatCount; + + // Keeps track of the number loop cycles which have been run while in + // pause mode. As soon as a well defined value is reached, the game + // continues (in case someone paused the game and forgot to resume it). + uint16_t nPauseCount; + + + // last command (important for key repeat) + tetris_input_command_t cmdLast; + + // Every command has its own counter. A command is ignored as long as its + // counter is unequal to 0. A counter gets set to a specific value (or 0) + // if the button of the corresponding command has been released by the + // player. All counters get decremented by one every loop cycle until they + // are zero. This is used to work against joystick chatter. Look at the + // TETRIS_INPUT_CHATTER_TICKS_... constants in input.c for the initial + // values of these counters. + uint8_t nIgnoreCmdCounter[TETRIS_INCMD_NONE]; +} +tetris_input_t; + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_input_construct + * Description: constructs an input object for André's borg + * Return value: pointer to a newly created input object + */ +tetris_input_t *tetris_input_construct(); + + +/* Function: tetris_input_destruct + * Description: destructs an input object + * Argument pIn: pointer to the input object which should be destructed + * Return value: void + */ +void tetris_input_destruct(tetris_input_t *pIn); + + +/*************************** + * input related functions * + ***************************/ + +/* Function: retris_input_getCommand + * Description: retrieves commands from joystick or loop interval + * Argument pIn: pointer to an input object + * Argument nPace: falling pace (see definition of tetris_input_pace_t) + * Return value: see definition of tetris_input_command_t + */ +tetris_input_command_t tetris_input_getCommand(tetris_input_t *pIn, + tetris_input_pace_t nPace); + + +/* Function: tetris_input_setLevel + * Description: modifies time interval of input events + * Argument pIn: pointer to an input object + * Argument nLvl: desired level (0 <= nLvl <= TETRIS_INPUT_LEVELS - 1) + * Return value: void + */ +void tetris_input_setLevel(tetris_input_t *pIn, + uint8_t nLvl); + + +#endif /*INPUT_H_*/ diff --git a/games/tetris/logic.c b/games/tetris/logic.c new file mode 100644 index 0000000..e9dc154 --- /dev/null +++ b/games/tetris/logic.c @@ -0,0 +1,467 @@ +/* Borgtris + * by: Christian Kroll + * date: Tuesday, 2007/09/16 + */ + +#include +#include +#include +#include + +#ifdef __AVR__ + #include + #include +#endif + +#include "logic.h" +#include "piece.h" +#include "playfield.h" +#include "view.h" +#include "input.h" +#include "../prng.h" + + +#ifdef EEMEM + /*********************** + * Highscore in EEPROM * + ***********************/ + + uint16_t tetris_logic_nHighscore EEMEM; +#endif + +/*************************** + * non-interface functions * + ***************************/ + +/* Function: tetris_logic_calculateLines + * Description: calculates number of lines for the given row mask + * Argument nRowMask: row mask from which the no. of lines will be calculated + * Return value: number of lines of the row mask + */ +uint8_t tetris_logic_calculateLines(uint8_t nRowMask) +{ + uint8_t nMask = 0x0001; + uint8_t nLines = 0; + for (uint8_t i = 0; i < 4; ++i) + { + if ((nMask & nRowMask) != 0) + { + ++nLines; + } + nMask <<= 1; + } + + return nLines; +} + +uint16_t tetris_logic_retrieveHighscore(void) +{ +#ifdef EEMEM + uint16_t nHighscore = 0; + nHighscore = eeprom_read_word(&tetris_logic_nHighscore); + + // a score of 65535 is most likely caused by uninitialized EEPROM addresses + if (nHighscore == 65535) + { + nHighscore = 0; + } + + return nHighscore; +#else + return 0; +#endif +} + +void tetris_logic_saveHighscore(uint16_t nHighscore) +{ +#ifdef EEMEM + if (nHighscore > tetris_logic_retrieveHighscore()) + { + eeprom_write_word(&tetris_logic_nHighscore, nHighscore); + } +#endif +} + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_logic_construct + * Description: constructs a logic object + * Return value: pointer to a newly created logic object + */ +tetris_logic_t *tetris_logic_construct() +{ + tetris_logic_t *pLogic = (tetris_logic_t *)malloc(sizeof(tetris_logic_t)); + assert(pLogic != NULL); + memset(pLogic, 0, sizeof(tetris_logic_t)); + return pLogic; +} + +/* Function: tetris_logic_destruct + * Description: destructs a logic object + * Argument pIn: pointer to the logic object to be destructed + * Return value: void + */ +void tetris_logic_destruct(tetris_logic_t *pLogic) +{ + assert(pLogic != 0); + free(pLogic); +} + + +/*************************** + * logic related functions * + ***************************/ + +/* Function: tetris + * Description: runs the tetris game + * Return value: void + */ +void tetris () +{ + // get view dependent dimensions of the playfield + int8_t nWidth; + int8_t nHeight; + tetris_view_getDimensions(&nWidth, &nHeight); + + // holds the current user command which should be processed + tetris_input_command_t inCmd; + + // prepare data structures that drive the game... + tetris_logic_t *pLogic = tetris_logic_construct(); + tetris_playfield_t *pPl = tetris_playfield_construct(nWidth, nHeight); + tetris_input_t *pIn = tetris_input_construct(); + tetris_view_t *pView = tetris_view_construct(pLogic, pPl); + + // runtime variable + int8_t nPieceRow; + + // retrieve highscore + static uint16_t nHighscore = 0; + if (nHighscore == 0) + { + nHighscore = tetris_logic_retrieveHighscore(); + } + + // initialize current and next piece + tetris_piece_t *pPiece = NULL; + tetris_piece_t *pNextPiece = pPiece = + tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + + // the view only monitors the logic and the playfield object for the game + // status so we must put information like the next piece or the current + // highscore to a place where the view can find it + tetris_logic_setHighscore(pLogic, nHighscore); + tetris_logic_setPreviewPiece(pLogic, pNextPiece); + + // pace flag + tetris_input_pace_t inPace; + + // game loop, runs as long as the game is not over + while (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) + { + // what we do strongly depends on the status of the playfield + switch (tetris_playfield_getStatus(pPl)) + { + // the playfield awaits a new piece + case TETRIS_PFS_READY: + // make preview piece the current piece and create new preview piece + pPiece = pNextPiece; + pNextPiece = + tetris_piece_construct(random8() % 7, TETRIS_PC_ANGLE_0); + tetris_logic_setPreviewPiece(pLogic, pNextPiece); + + // insert new piece into playfield + tetris_piece_t *pOldPiece; + tetris_playfield_insertPiece(pPl, pPiece, &pOldPiece); + + // destruct old piece (if it exists) since we don't need it anymore + if (pOldPiece != NULL) + { + tetris_piece_destruct(pOldPiece); + pOldPiece = NULL; + } + break; + + // a piece is hovering and can be controlled by the player + case TETRIS_PFS_HOVERING: + case TETRIS_PFS_GLIDING: + // if the piece is gliding the input module has to grant us + // a minimum amount of time to move it + if (tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) + { + inPace = TETRIS_INPACE_GLIDING; + } + else + { + inPace = TETRIS_INPACE_HOVERING; + } + + // ensure correct view mode if the game isn't paused + if ((inCmd = tetris_input_getCommand(pIn, inPace)) + != TETRIS_INCMD_PAUSE) + { + tetris_view_setViewMode(pView, TETRIS_VIMO_RUNNING); + } + + // what we do depends on what the input module tells us + switch (inCmd) + { + // game paused? + case TETRIS_INCMD_PAUSE: + // tell the view it should display the pause screen + tetris_view_setViewMode(pView, TETRIS_VIMO_PAUSED); + break; + + // the piece was pulled down by the almighty gravity + case TETRIS_INCMD_GRAVITY: + tetris_playfield_advancePiece(pPl); + break; + + // the player has pulled down the piece herself/himself + case TETRIS_INCMD_DOWN: + tetris_playfield_advancePiece(pPl); + // if the game still runs, reward the player with extra points + if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) + { + tetris_logic_singleDrop(pLogic, 1); + } + break; + + // player shifted the piece to the left + case TETRIS_INCMD_LEFT: + tetris_playfield_movePiece(pPl, TETRIS_PFD_LEFT); + break; + + // player shifted the piece to the right + case TETRIS_INCMD_RIGHT: + tetris_playfield_movePiece(pPl, TETRIS_PFD_RIGHT); + break; + + // player rotated the piece clockwise + case TETRIS_INCMD_ROT_CW: + tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CW); + break; + + // player rotated the piece counter clockwise + case TETRIS_INCMD_ROT_CCW: + tetris_playfield_rotatePiece(pPl, TETRIS_PC_ROT_CCW); + break; + + // the player decided to make an immediate drop + case TETRIS_INCMD_DROP: + nPieceRow = tetris_playfield_getRow(pPl); + // emulate immediate drop + while((tetris_playfield_getStatus(pPl) == TETRIS_PFS_GLIDING) || + (tetris_playfield_getStatus(pPl) == TETRIS_PFS_HOVERING)) + { + tetris_playfield_advancePiece(pPl); + } + // if the game still runs, reward the player with extra points + if (tetris_playfield_getStatus(pPl) != TETRIS_PFS_GAMEOVER) + { + tetris_logic_completeDrop(pLogic, + tetris_playfield_getRow(pPl) - nPieceRow); + } + break; + + // avoid compiler warnings + default: + break; + } + break; + + // the piece has irrevocably hit the ground + case TETRIS_PFS_DOCKED: + // remove complete lines (if any) + tetris_playfield_removeCompleteLines(pPl); + + // let the logic object decide how many points the player gets + // and whether the level gets changed + tetris_logic_removedLines(pLogic, tetris_playfield_getRowMask(pPl)); + tetris_input_setLevel(pIn, tetris_logic_getLevel(pLogic)); + break; + + // avoid compiler warnings + default: + break; + } + + // the view updates it state every loop cycle to make changes visible + tetris_view_update(pView); + } + + // game is over and we provide the player with her/his results + tetris_view_showResults(pView); + + // update highscore if it has been beaten + uint16_t nScore = tetris_logic_getScore(pLogic); + if (nScore > nHighscore) + { + nHighscore = nScore; + tetris_logic_saveHighscore(nHighscore); + } + + // clean up + tetris_view_destruct(pView); + tetris_input_destruct(pIn); + tetris_playfield_destruct(pPl); + tetris_logic_destruct(pLogic); + tetris_piece_destruct(pPiece); + tetris_piece_destruct(pNextPiece); +} + + +/* Function: tetris_logic_singleDrop + * Description: add points which result from single step dropping + * Argument pLogic: the logic object we want to modify + * Argument nLines: the number of rows involved + * Return value: void + */ +void tetris_logic_singleDrop(tetris_logic_t *pLogic, + uint8_t nLines) +{ + assert(pLogic != 0); + pLogic->nScore += nLines; +} + + +/* Function: tetris_logic_completeDrop + * Description: add points which result from a complete drop + * Argument pLogic: the logic object we want to modify + * Argument nLines: the number of rows involved + * Return value: void + */ +void tetris_logic_completeDrop(tetris_logic_t *pLogic, + uint8_t nLines) +{ + assert(pLogic != 0); + pLogic->nScore += nLines * 2; +} + + +/* Function: tetris_logic_removedLines + * Description: add points which result from removed rows + * Argument pLogic: the logic object we want to modify + * Argument nRowMask: see tetris_playfield_completeLines + * Return value: void + */ +void tetris_logic_removedLines(tetris_logic_t *pLogic, + uint8_t nRowMask) +{ + assert(pLogic != 0); + uint8_t nLines = tetris_logic_calculateLines(nRowMask); + pLogic->nLines += nLines; + pLogic->nLevel = ((pLogic->nLines / 10) < TETRIS_INPUT_LEVELS) ? + (pLogic->nLines / 10) : (TETRIS_INPUT_LEVELS - 1); + + switch (nLines) + { + case 1: + pLogic->nScore += 50; + break; + case 2: + pLogic->nScore += 150; + break; + case 3: + pLogic->nScore += 250; + break; + case 4: + pLogic->nScore += 400; + break; + } +} + + +/***************** + * get functions * + *****************/ + +/* Function: tetris_logic_getScore + * Description: returns the current score + * Argument pLogic: the logic object we want information from + * Return value: the score as uint16_t + */ +uint16_t tetris_logic_getScore(tetris_logic_t *pLogic) +{ + assert(pLogic != NULL); + return pLogic->nScore; +} + + +/* Function: tetris_logic_getHighscore + * Description: returns the current highscore + * Argument pLogic: the logic object we want information from + * Return value: the highscore as uint16_t + */ + +uint16_t tetris_logic_getHighscore(tetris_logic_t *pLogic) +{ + assert(pLogic != NULL); + return pLogic->nHighscore; +} + + +/* Function: tetris_logic_setHighscore + * Description: set highscore + * Argument pLogic: the logic object we want to modify + * Argmument nHighscore: highscore + */ +void tetris_logic_setHighscore(tetris_logic_t *pLogic, + uint16_t nHighscore) +{ + assert(pLogic != NULL); + pLogic->nHighscore = nHighscore; +} + + +/* Function: tetris_logic_getLevel + * Description: returns the current level + * Argument pLogic: the logic object we want information from + * Return value: the level as uint8_t + */ +uint8_t tetris_logic_getLevel(tetris_logic_t *pLogic) +{ + assert(pLogic != NULL); + return pLogic->nLevel; +} + + +/* Function: tetris_logic_getLines + * Description: returns the number of completed lines + * Argument pLogic: the logic object we want information from + * Return value: number of completed lines as uint16_t + */ +uint16_t tetris_logic_getLines(tetris_logic_t *pLogic) +{ + assert(pLogic != NULL); + return pLogic->nLines; +} + + +/* Function: tetris_logic_setPreviewPiece + * Description: help for the view to determine the preview piece + * Argument pLogic: the logic object we want to modify + * Argument pPiece: pointer to piece intended to be the next one (may be NULL) + * Return value: void + */ +void tetris_logic_setPreviewPiece(tetris_logic_t *pLogic, + tetris_piece_t *pPiece) +{ + assert(pLogic != NULL); + pLogic->pPreviewPiece = pPiece; +} + + +/* Function: tetris_logic_getPreviewPiece + * Description: returns piece which was set via tetris_logic_setPreviewPiece + * Argument pLogic: the logic object we want information from + * Return value: the piece intended to be the next one (may be NULL) + */ +tetris_piece_t* tetris_logic_getPreviewPiece(tetris_logic_t *pLogic) +{ + assert(pLogic != NULL); + return pLogic->pPreviewPiece; +} + diff --git a/games/tetris/logic.h b/games/tetris/logic.h new file mode 100644 index 0000000..67e9d06 --- /dev/null +++ b/games/tetris/logic.h @@ -0,0 +1,143 @@ +#ifndef TETRIS_LOGIC_H_ +#define TETRIS_LOGIC_H_ + +#include +#include "piece.h" + +/********* + * types * + *********/ + +typedef struct tetris_logic_t +{ + uint16_t nScore; // score of the player + uint16_t nHighscore; // highscore + uint8_t nLevel; // current level + uint16_t nLines; // number of completed lines + tetris_piece_t *pPreviewPiece; // the piece intended to be the next one +} +tetris_logic_t; + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_logic_construct + * Description: constructs a logic object + * Return value: pointer to a newly created logic object + */ +tetris_logic_t *tetris_logic_construct(); + +/* Function: tetris_logic_destruct + * Description: destructs a logic object + * Argument pIn: pointer to the logic object to be destructed + * Return value: void + */ +void tetris_logic_destruct(tetris_logic_t *pLogic); + +/*************************** + * logic related functions * + ***************************/ + +/* Function: tetris + * Description: runs the tetris game + * Return value: void + */ +void tetris(); + + +/* Function: tetris_logic_singleDrop + * Description: add points which result from single step dropping + * Argument pLogic: the logic object we want to modify + * Argument nLines: the number of rows involved + * Return value: void + */ +void tetris_logic_singleDrop(tetris_logic_t *pLogic, + uint8_t nLines); + + +/* Function: tetris_logic_completeDrop + * Description: add points which result from a complete drop + * Argument pLogic: the logic object we want to modify + * Argument nLines: the number of rows involved + * Return value: void + */ +void tetris_logic_completeDrop(tetris_logic_t *pLogic, + uint8_t nLines); + + +/* Function: tetris_logic_removedLines + * Description: add points which result from removed rows + * Argument pLogic: the logic object we want to modify + * Argument nRowMask: see tetris_playfield_completeLines + * Return value: void + */ +void tetris_logic_removedLines(tetris_logic_t *pLogic, + uint8_t nRowMask); + + +/********************* + * get/set functions * + *********************/ + +/* Function: tetris_logic_getScore + * Description: returns the current score + * Argument pLogic: the logic object we want information from + * Return value: the score as uint16_t + */ +uint16_t tetris_logic_getScore(tetris_logic_t *pLogic); + + +/* Function: tetris_logic_getHighscore + * Description: returns the current highscore + * Argument pLogic: the logic object we want information from + * Return value: the highscore as uint16_t + */ +uint16_t tetris_logic_getHighscore(tetris_logic_t *pLogic); + + +/* Function: tetris_logic_setHighscore + * Description: set highscore + * Argument pLogic: the logic object we want to modify + * Argmument nHighscore: highscore + */ +void tetris_logic_setHighscore(tetris_logic_t *pLogic, + uint16_t nHighscore); + + +/* Function: tetris_logic_getLevel + * Description: returns the current level + * Argument pLogic: the logic object we want information from + * Return value: the level as uint8_t + */ +uint8_t tetris_logic_getLevel(tetris_logic_t *pLogic); + + +/* Function: tetris_logic_getLines + * Description: returns the number of completed lines + * Argument pLogic: the logic object we want information from + * Return value: number of completed lines as uint16_t + */ +uint16_t tetris_logic_getLines(tetris_logic_t *pLogic); + + +/* Function: tetris_logic_setPreviewPiece + * Description: help for the view to determine the preview piece + * Argument pLogic: the logic object we want to modify + * Argument pPiece: pointer to piece intended to be the next one + * Return value: void + */ +void tetris_logic_setPreviewPiece(tetris_logic_t *pLogic, + tetris_piece_t *pPiece); + + +/* Function: tetris_logic_getPreviewPiece + * Description: returns piece which was set via tetris_logic_setPreviewPiece + * Argument pLogic: the logic object we want information from + * Return value: the piece intended to be the next one + */ +tetris_piece_t* tetris_logic_getPreviewPiece(tetris_logic_t *pLogic); + + +#endif /*TETRIS_LOGIC_H_*/ + diff --git a/games/tetris/piece.c b/games/tetris/piece.c new file mode 100644 index 0000000..815da6c --- /dev/null +++ b/games/tetris/piece.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include "piece.h" + +#ifdef __AVR__ + #include +#else + #define PROGMEM +#endif + + +/***************************** + * construction/destruction * + *****************************/ + +/* Function: tetris_piece_construct + * Description: constructs a piece with the given attributes + * Argument s: shape of the piece (see tetris_piece_shape_t) + * Argument a: its angle (see tetris_piece_angel_t) + * Return value: pointer to a newly created piece + */ +tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s, + tetris_piece_angle_t a) +{ + tetris_piece_t *p_piece = (tetris_piece_t*) malloc (sizeof(tetris_piece_t)); + assert(p_piece != NULL); + + p_piece->shape = s; + p_piece->angle = a; + + return p_piece; +} + +/* Function: tetris_piece_destruct + * Description: destructs a piece + * Argument pPc: pointer to the piece to be destructed + * Return value: void + */ +void tetris_piece_destruct(tetris_piece_t *pPc) +{ + assert(pPc != NULL); + free(pPc); +} + + +/**************************** + * piece related functions * + ****************************/ + +/* Function: tetris_piece_getBitmap + * Description: returns bitfield representation of the piece + * Argument pPc: piece from which the bitfield shuld be retrieved + * Return value: bitfield representation of the piece + * - nth nibble is nth row of the piece (from upper left) + * - the LSB of a nibble represents the left side of a row + */ +uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc) +{ + assert(pPc != NULL); + + // Lookup table: + // A value in an array represents a piece in a specific angle (rotating + // clockwise from index 0). + const static uint16_t piece[][4] PROGMEM = + {{0x0F00, 0x2222, 0x0F00, 0x2222}, // LINE + {0x4E00, 0x4640, 0x0E40, 0x4C40}, // T + {0x0660, 0x0660, 0x0660, 0x0660}, // SQUARE + {0x2E00, 0x88C0, 0x0E80, 0xC440}, // L + {0x8E00, 0x6440, 0x0E20, 0x44C0}, // LBACK + {0x6C00, 0x4620, 0x6C00, 0x4620}, // S + {0xC600, 0x4C80, 0xC600, 0x4C80}}; // Z + + #ifdef __AVR__ + return pgm_read_word(&piece[pPc->shape][pPc->angle]); + #else + return piece[pPc->shape][pPc->angle]; + #endif +} + + +/* Function: tetris_piece_rotate + * Description: rotates a piece + * Argument pPc: piece to rotate + * Argument r: type of rotation (see tetris_piece_rotation_t) + * Return value: void + */ +void tetris_piece_rotate(tetris_piece_t *pPc, + tetris_piece_rotation_t r) +{ + assert(pPc != NULL); + + // we just rotate through the available angles in the given direction and + // make wrap arounds where appropriate + switch (r) + { + case TETRIS_PC_ROT_CW: + if (pPc->angle == TETRIS_PC_ANGLE_270) + { + pPc->angle = TETRIS_PC_ANGLE_0; + } + else + { + ++pPc->angle; + } + break; + case TETRIS_PC_ROT_CCW: + if (pPc->angle == TETRIS_PC_ANGLE_0) + { + pPc->angle = TETRIS_PC_ANGLE_270; + } + else + { + --pPc->angle; + } + break; + } +} + diff --git a/games/tetris/piece.h b/games/tetris/piece.h new file mode 100644 index 0000000..0b1e809 --- /dev/null +++ b/games/tetris/piece.h @@ -0,0 +1,97 @@ +#ifndef TETRIS_PIECE_H_ +#define TETRIS_PIECE_H_ + +#include + + +/********* + * types * + *********/ + +typedef enum tetris_piece_shape_t +{ + TETRIS_PC_LINE, + TETRIS_PC_T, + TETRIS_PC_SQUARE, + TETRIS_PC_L, + TETRIS_PC_LBACK, + TETRIS_PC_S, + TETRIS_PC_Z +} +tetris_piece_shape_t; + + +typedef enum tetris_piece_angle_t +{ + TETRIS_PC_ANGLE_0, + TETRIS_PC_ANGLE_90, + TETRIS_PC_ANGLE_180, + TETRIS_PC_ANGLE_270 +} +tetris_piece_angle_t; + + +typedef enum tetris_piece_rotation_t +{ + TETRIS_PC_ROT_CW, // clockwise rotation + TETRIS_PC_ROT_CCW // counter clockwise rotation +} +tetris_piece_rotation_t; + + +typedef struct tetris_piece_t +{ + tetris_piece_shape_t shape; // specifies the shape of the piece + tetris_piece_angle_t angle; // specifies one of 4 angels +} +tetris_piece_t; + + +/***************************** + * construction/destruction * + *****************************/ + +/* Function: tetris_piece_construct + * Description: constructs a piece with the given attributes + * Argument s: shape of the piece (see tetris_piece_shape_t) + * Argument a: its angle (see tetris_piece_angel_t) + * Return value: pointer to a newly created piece + */ +tetris_piece_t *tetris_piece_construct(tetris_piece_shape_t s, + tetris_piece_angle_t a); + + +/* Function: tetris_piece_destruct + * Description: destructs a piece + * Argument pPc: pointer to the piece to be destructed + * Return value: void + */ + void tetris_piece_destruct(tetris_piece_t *pPc); + + +/**************************** + * piece related functions * + ****************************/ + +/* Function: tetris_piece_getBitmap + * Description: returns bitfield representation of the piece + * Argument pPc: piece from which the bitfield shuld be retrieved + * Return value: bitfield representation of the piece + * - nth nibble is nth row of the piece (from upper left) + * - the LSB of a nibble represents the left side of a row + */ +uint16_t tetris_piece_getBitmap(tetris_piece_t *pPc); + + +/* Function: tetris_piece_rotate + * Description: rotates a piece + * Argument pPc: piece to rotate + * Argument r: type of rotation (see tetris_piece_rotation_t) + * Return value: void + */ +void tetris_piece_rotate(tetris_piece_t *pPc, + tetris_piece_rotation_t r); + + +#endif /*TETRIS_PIECE_H_*/ + diff --git a/games/tetris/playfield.c b/games/tetris/playfield.c new file mode 100644 index 0000000..93204a2 --- /dev/null +++ b/games/tetris/playfield.c @@ -0,0 +1,595 @@ +#include +#include +#include +#include +#include "playfield.h" +#include "piece.h" + + +/*************************** + * non-interface functions * + ***************************/ + +/* Function: tetris_playfield_hoverStatus; + * Description: determines if piece is either hovering or gliding + * Argument pPl: playfield perform action on + * Return value: TETRIS_PFS_HOVERING or TETRIS_PFS_GLIDING + */ +tetris_playfield_status_t tetris_playfield_hoverStatus(tetris_playfield_t* pPl) +{ + // if the piece touches the dump we ensure that the status is "gliding" + if (tetris_playfield_collision(pPl, pPl->nColumn, pPl->nRow + 1)) + { + return TETRIS_PFS_GLIDING; + } + // otherwise the status must be "hovering" + else + { + return TETRIS_PFS_HOVERING; + } +} + + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_playfield_construct + * Description: constructs a playfield with the given diemensions + * Argument nWidth: width of playfield (4 <= n <= 16) + * Argument nHeight: height of playfield (4 <= n <= 124) + * Return value: pointer to a newly created playfield + */ +tetris_playfield_t *tetris_playfield_construct(int8_t nWidth, + int8_t nHeight) +{ + assert((nWidth >= 4) && (nWidth <= 16)); + assert((nHeight >= 4) && (nHeight <= 124)); + + tetris_playfield_t *pPlayfield = + (tetris_playfield_t*) malloc(sizeof(tetris_playfield_t)); + + if (pPlayfield != NULL) + { + // allocating mem for dump array + pPlayfield->dump = (uint16_t*) calloc(nHeight, sizeof(uint16_t)); + + if (pPlayfield->dump != NULL) + { + // setting desired attributes + pPlayfield->nWidth = nWidth; + pPlayfield->nHeight = nHeight; + tetris_playfield_reset(pPlayfield); + + return pPlayfield; + } + else + { + free(pPlayfield); + pPlayfield = NULL; + } + } + return NULL; +} + + +/* Function: tetris_playfield_destruct + * Description: destructs a playfield + * Argument pPl: pointer to the playfield to be destructed + * Return value: void + */ +void tetris_playfield_destruct(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + + // if memory for the dump array has been allocated, free it + if (pPl->dump != NULL) + { + free(pPl->dump); + } + free(pPl); +} + + +/******************************* + * playfield related functions * + *******************************/ + +/* Function: tetris_playfield_reset + * Description: resets playfield to begin a new game + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_reset(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + + pPl->pPiece = NULL; + pPl->nColumn = 0; + pPl->nRow = 0; + pPl->nRowMask = 0; + + // clear dump if it has been allocated in memory + if (pPl->dump != NULL) + { + memset(pPl->dump, 0, pPl->nHeight); + } + + pPl->status = TETRIS_PFS_READY; +} + + +/* Function: tetris_playfield_insertPiece + * Description: inserts a new piece + * Argument pPl: playfield to perform action on + * Argument pPiece: piece to be inserted + * Argument ppOldPiece: [out] indirect pointer to former piece for deallocation + * Return value: void + */ +void tetris_playfield_insertPiece(tetris_playfield_t *pPl, + tetris_piece_t *pPiece, + tetris_piece_t** ppOldPiece) +{ + assert((pPl != NULL) && (pPiece != NULL) && (ppOldPiece != NULL)); + + // a piece can only be inserted in state TETRIS_PFS_READY + assert(pPl->status == TETRIS_PFS_READY); + + // row mask is now meaningless + pPl->nRowMask = 0; + + // replace old piece + *ppOldPiece = pPl->pPiece; + pPl->pPiece = pPiece; + + // set horizontal start position (in the middle of the top line) + pPl->nColumn = (pPl->nWidth - 2) / 2; + + // set vertical start position (first piece row with matter at pos. 1) + uint16_t nPieceMap = tetris_piece_getBitmap(pPl->pPiece); + uint16_t nElementMask = 0xF000; + pPl->nRow = -3; + while ((nPieceMap & nElementMask) == 0) + { + ++pPl->nRow; + nElementMask >>= 4; + } + if (pPl->nRow < 0) + { + ++pPl->nRow; + } + + // did we already collide with something? + if (tetris_playfield_collision(pPl, pPl->nColumn, pPl->nRow) == 1) + { + // game over man, game over!! + pPl->status = TETRIS_PFS_GAMEOVER; + } + else + { + // bring it on! + pPl->status = tetris_playfield_hoverStatus(pPl); + } +} + + +/* Function: tetris_playfield_collision + * Description: detects if piece collides with s.th. at a given position + * Argument pPl: playfield to perform action on + * Argument nColumn: column where the piece should be moved + * Argument nRow: row where the piece should be moved + * Return value: 1 for collision, 0 otherwise + */ +uint8_t tetris_playfield_collision(tetris_playfield_t *pPl, + int8_t nColumn, + int8_t nRow) +{ + assert(pPl != NULL); + + // only allow coordinates which are within sane ranges + assert((nColumn >= -4) && (nColumn < pPl->nWidth)); + assert((nRow >= -4) && (nRow < pPl->nHeight)); + + // The rows of a piece get compared with the background one by one + // until either a collision occures or all rows are compared. Both the + // piece row and the part of the playfield it covers are represented in + // 4 bits which were singled out from their corresponding uint16_t + // values and are aligned to LSB. In case where a piece overlaps with + // either the left or the right border we "enhance" the playfield part + // via bit shifting and set all bits representing the border to 1. + // + // NOTE: LSB represents the left most position. + uint16_t nPieceMap = tetris_piece_getBitmap(pPl->pPiece); + uint16_t nPlayfieldPart; + uint16_t nPieceRowMap; + + // negative nRow values indicate that the piece hasn't fully entered the + // playfield yet which requires special treatment if the piece overlaps + // with either the left or the right border + if (nRow < 0) + { + uint16_t nBorderMask = 0x0000; + // piece overlaps with left border + if (nColumn < 0) + { + nBorderMask = 0x1111 << (-nColumn - 1); + } + // piece overlaps with right border + else if ((nColumn + 3) >= pPl->nWidth) + { + nBorderMask = 0x8888 >> ((nColumn + 3) - pPl->nWidth); + } + // return if piece collides with border + if ((nPieceMap & nBorderMask) != 0) + { + return 1; + } + } + + // here we check the part which has already entered the playfield + for (int8_t y = (nRow < 0) ? -nRow : 0; y < 4; ++y) + { + // current piece row overlaps with lower border + if ((y + nRow) >= pPl->nHeight) + { + // all 4 bits represent the lower border + nPlayfieldPart = 0x000F; + } + // piece overlaps with left border + else if (nColumn < 0) + { + // clear all bits we are not interested in + nPlayfieldPart = (pPl->dump[y + nRow] & (0x000F >> -nColumn)); + // add zeros to the left (the bits "behind" the left border) + nPlayfieldPart <<= -nColumn; + // set bits beyond left border to 1 + nPlayfieldPart |= 0x000F >> (4 + nColumn); + } + // piece overlaps with right border + else if ((nColumn + 3) >= pPl->nWidth) + { + // align the bits we are interested in to LSB + // (thereby clearing the rest) + nPlayfieldPart = pPl->dump[y + nRow] >> nColumn; + // set bits beyond right border to 1 + nPlayfieldPart |= 0xFFF8 >> (nColumn + 3 - pPl->nWidth); + } + // current row neither overlaps with left, right nor lower border + else + { + // clear all bits we are not interested in and align the + // remaing row to LSB + nPlayfieldPart = + (pPl->dump[y + nRow] & (0x000F << nColumn)) >> nColumn; + } + + // clear all bits of the piece we are not interested in and + // align the remaing row to LSB + nPieceRowMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2); + + // finally check for a collision + if ((nPlayfieldPart & nPieceRowMap) != 0) + { + return 1; + } + } + + // if we reach here, no collision was detected + return 0; +} + + +/* Function: tetris_playfield_advancePiece + * Description: lowers piece by one row or finally docks it + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_advancePiece(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + + // a piece can only be lowered if it is hovering or gliding + assert ((pPl->status == TETRIS_PFS_HOVERING) || + (pPl->status == TETRIS_PFS_GLIDING)); + + if (tetris_playfield_collision(pPl, pPl->nColumn, pPl->nRow + 1)) + { + uint16_t nPiece = tetris_piece_getBitmap(pPl->pPiece); + + // Is the playfield filled up? + if ((pPl->nRow < 0) && (nPiece & (0x0FFF >> ((3 + pPl->nRow) << 2))) != 0) + { + pPl->status = TETRIS_PFS_GAMEOVER; + } + else + { + // determine valid start point for dump index + int8_t nStartRow = ((pPl->nRow + 3) < pPl->nHeight) ? + (pPl->nRow + 3) : pPl->nHeight - 1; + for (int8_t i = nStartRow; i >= pPl->nRow; --i) + { + int8_t y = i - pPl->nRow; + + // clear all bits of the piece we are not interested in and + // align the rest to LSB + uint16_t nPieceMap = (nPiece & (0x000F << (y << 2))) >> (y << 2); + // shift the remaining content to the current column + if (pPl->nColumn >= 0) + { + nPieceMap <<= pPl->nColumn; + } + else + { + nPieceMap >>= -pPl->nColumn; + } + // embed piece in playfield + pPl->dump[i] |= nPieceMap; + } + + // the piece has finally been docked + pPl->status = TETRIS_PFS_DOCKED; + } + } + else + { + // since there is no collision the piece may continue its travel + // to the ground... + pPl->nRow++; + + // are we gliding? + pPl->status = tetris_playfield_hoverStatus(pPl); + } +} + + +/* Function: tetris_playfield_movePiece + * Description: moves piece to the given direction + * Argument pPl: playfield to perform action on + * Argument direction: direction (see tetris_playfield_direction_t) + * Return value: 1 if piece could be moved, 0 otherwise + */ +uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl, + tetris_playfield_direction_t direction) +{ + assert(pPl != NULL); + + // a piece can only be moved if it is still hovering or gliding + assert((pPl->status == TETRIS_PFS_HOVERING) || + (pPl->status == TETRIS_PFS_GLIDING)); + + int8_t nOffset = (direction == TETRIS_PFD_LEFT) ? -1 : 1; + if (tetris_playfield_collision(pPl, pPl->nColumn + nOffset, pPl->nRow) == 0) + { + pPl->nColumn += nOffset; + + // are we gliding? + pPl->status = tetris_playfield_hoverStatus(pPl); + return 1; + } + + return 0; +} + + +/* Function: tetris_playfield_rotatePiece + * Description: rotates piece to the given direction + * Argument pPl: playfield to perform action on + * Argument r: type of rotation (see tetris_piece_rotation_t) + * Return value: 1 if piece could be rotated, 0 otherwise + */ +uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl, + tetris_piece_rotation_t rotation) +{ + assert(pPl != NULL); + + // a piece can only be rotation if it is still hovering or gliding + assert((pPl->status == TETRIS_PFS_HOVERING) || + (pPl->status == TETRIS_PFS_GLIDING)); + + tetris_piece_rotate(pPl->pPiece, rotation); + + // does the rotated piece cause a collision? + if (tetris_playfield_collision(pPl, pPl->nColumn, pPl->nRow) != 0) + { + // in that case we revert the rotation + if (rotation == TETRIS_PC_ROT_CW) + { + tetris_piece_rotate(pPl->pPiece, TETRIS_PC_ROT_CCW); + } + else + { + tetris_piece_rotate(pPl->pPiece, TETRIS_PC_ROT_CW); + } + + return 0; + } + + // are we gliding? + pPl->status = tetris_playfield_hoverStatus(pPl); + + return 1; +} + + +/* Function: tetris_playfield_removeCompletedLines + * Description: removes completed lines (if any) and lowers the dump + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + + // rows can only be removed if we are in state TETRIS_PFS_DOCKED + assert(pPl->status == TETRIS_PFS_DOCKED); + + // bit mask of a full row + uint16_t nFullRow = 0xFFFF >> (16 - pPl->nWidth); + + // bit mask (only 4 bits) that tells us if the n-th row after the + // current nRow is complete (n-th bit set to 1, LSB represents nRow itself) + uint8_t nRowMask = 0; + + // determine sane start and stop values for the dump' index + int8_t nStartRow = + ((pPl->nRow + 3) >= pPl->nHeight) ? pPl->nHeight - 1 : pPl->nRow + 3; + int8_t nStopRow = (pPl->nRow < 0) ? 0 : pPl->nRow; + + // dump index variables + // for incomplete rows, both variables will be decremented + // for complete rows, only i gets decremented + int8_t nLowestRow = nStartRow; + + // this loop only considers rows which are affected by the piece + for (int8_t i = nStartRow; i >= nStopRow; --i) + { + // is current row a full row? + if ((nFullRow & pPl->dump[i]) == nFullRow) + { + // set corresponding bit for the row mask + // nRowMask |= 0x08 >> (nStartRow - i); + nRowMask |= 0x01 << (i - pPl->nRow); + } + else + { + // if nLowestRow and i differ, the dump has to be shifted + if (i < nLowestRow) + { + pPl->dump[nLowestRow] = pPl->dump[i]; + } + --nLowestRow; + } + } + + // if rows have been removed, this loop shifts the rest of the dump + uint8_t nComplete = nLowestRow - nStopRow + 1; + if (nComplete > 0) + { + for (int8_t i = nStopRow - 1; nLowestRow >= 0; --i) + { + // is the row we are copying from below the upper border? + if (i >= 0) + { + // just copy from that row + pPl->dump[nLowestRow] = pPl->dump[i]; + } + else + { + // rows above the upper border are always empty + pPl->dump[nLowestRow] = 0; + } + --nLowestRow; + } + } + + // ready to get the next piece + pPl->status = TETRIS_PFS_READY; + + pPl->nRowMask = nRowMask; +} + + +/***************** + * get functions * + *****************/ + +/* Function: tetris_playfield_getWidth + * Description: returns the width of the playfield + * Argument pPl: the playfield we want information from + * Return value: width of the playfield + */ +int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->nWidth; +} + + +/* Function: tetris_playfield_getHeight + * Description: returns the height of the playfield + * Argument pPl: the playfield we want information from + * Return value: height of the playfield + */ +int8_t tetris_playfield_getHeight(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->nHeight; +} + + +/* Function: tetris_playfield_getPiece + * Description: returns the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: pointer to the currently falling piece + */ +tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->pPiece; +} + + +/* Function: tetris_playfield_getColumn + * Description: returns the column of the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: column of the currently falling piece + */ +int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->nColumn; +} + + +/* Function: tetris_playfield_getRow + * Description: returns the row of the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: row of the currently falling piece + */ +int8_t tetris_playfield_getRow(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->nRow; +} + + +/* Function: tetris_playfield_getRowMask + * Description: returns the row mask relative to nRow + * Argument pPl: the playfield we want information from + * Return value: the first 4 bits indicate which lines (relative to nRow) + * have been removed if we are in status TETRIS_PFS_READY + * LSB is the highest line + */ +uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->nRowMask; +} + + +/* Function: tetris_playfield_getStatus + * Description: returns the status of the playfield + * Argument pPl: the playfield we want information from + * Return value: status of the playfield (see tetris_playfield_status_t) + */ +tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl) +{ + assert(pPl != NULL); + return pPl->status; +} + + +/* Function: tetris_playfield_getDumpRow + * Description: returns the given row of the dump (as bitmap) + * Argument pPl: the playfield we want information from + * Argument nRow: the number of the row (0 <= nRow < height of playfield) + * Return value: bitmap of the requested row (LSB is leftmost column) + */ +uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl, + int8_t nRow) +{ + assert(pPl != NULL); + assert((0 <= nRow) && (nRow < pPl->nHeight)); + return pPl->dump[nRow]; +} + diff --git a/games/tetris/playfield.h b/games/tetris/playfield.h new file mode 100644 index 0000000..ed8dfe7 --- /dev/null +++ b/games/tetris/playfield.h @@ -0,0 +1,213 @@ +#ifndef TETRIS_PLAYFIELD_H_ +#define TETRIS_PLAYFIELD_H_ + +#include +#include "piece.h" + + +/********* + * types * + *********/ + +// directions to which a piece can be moved +typedef enum tetris_playfield_direction_t +{ + TETRIS_PFD_LEFT, + TETRIS_PFD_RIGHT +} +tetris_playfield_direction_t; + + +// status of the playfield +typedef enum tetris_playfield_status_t +{ + TETRIS_PFS_READY, // ready to get next piece + TETRIS_PFS_HOVERING, // piece is still hovering + TETRIS_PFS_GLIDING, // piece is gliding on the dump + TETRIS_PFS_DOCKED, // piece has been docked + TETRIS_PFS_GAMEOVER // playfield is filled up +} +tetris_playfield_status_t; + + +// tetris_playfield_t +typedef struct tetris_playfield_t +{ + int8_t nWidth; // width of playfield + int8_t nHeight; // height of playfield + tetris_piece_t *pPiece; // currently falling piece + int8_t nColumn; // horz. piece pos. (0 is left) + int8_t nRow; // vert. piece pos. (0 is top) + uint8_t nRowMask; // removed lines relative to nRow (bitmap) + tetris_playfield_status_t status; // status + uint16_t *dump; // playfield itself +} +tetris_playfield_t; + + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_playfield_construct + * Description: constructs a playfield with the given diemensions + * Argument nWidth: width of playfield (4 <= n <= 16) + * Argument nHeight: height of playfield (4 <= n <= 124) + * Return value: pointer to a newly created playfield + */ +tetris_playfield_t *tetris_playfield_construct(int8_t nWidth, int8_t nHeight); + + +/* Function: tetris_playfield_destruct + * Description: destructs a playfield + * Argument pPl: pointer to the playfield to be destructed + * Return value: void + */ +void tetris_playfield_destruct(tetris_playfield_t *pPl); + + +/******************************* + * playfield related functions * + *******************************/ + +/* Function: tetris_playfield_reset + * Description: resets playfield to begin a new game + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_reset(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_insertPiece + * Description: inserts a new piece + * Argument pPl: playfield to perform action on + * Argument pPiece: piece to be inserted + * Argument ppOldPiece: [out] indirect pointer to former piece for deallocation + * Return value: void + */ +void tetris_playfield_insertPiece(tetris_playfield_t *pPl, + tetris_piece_t *pPiece, + tetris_piece_t** ppOldPiece); + + +/* Function: tetris_playfield_collision + * Description: detects if piece collides with s.th. at a given position + * Argument pPl: playfield to perform action on + * Argument nColumn: column where the piece should be moved + * Argument nRow: row where the piece should be moved + * Return value: 1 for collision, 0 otherwise + */ +uint8_t tetris_playfield_collision(tetris_playfield_t *pPl, + int8_t nColumn, + int8_t nRow); + + +/* Function: tetris_playfield_advancePiece + * Description: lowers piece by one row or finally docks it + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_advancePiece(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_movePiece + * Description: moves piece to the given direction + * Argument pPl: playfield to perform action on + * Argument direction: direction (see tetris_playfield_direction_t) + * Return value: 1 if piece could be moved, 0 otherwise + */ +uint8_t tetris_playfield_movePiece(tetris_playfield_t *pPl, + tetris_playfield_direction_t direction); + + +/* Function: tetris_playfield_rotatePiece + * Description: rotates piece to the given direction + * Argument pPl: playfield to perform action on + * Argument r: type of rotation (see tetris_piece_rotation_t) + * Return value: 1 if piece could be rotated, 0 otherwise + */ +uint8_t tetris_playfield_rotatePiece(tetris_playfield_t *pPl, + tetris_piece_rotation_t rotation); + + +/* Function: tetris_playfield_removeCompletedLines + * Description: removes completed lines (if any) and lowers the dump + * Argument pPl: playfield to perform action on + * Return value: void + */ +void tetris_playfield_removeCompleteLines(tetris_playfield_t *pPl); + + +/***************** + * get functions * + *****************/ + +/* Function: tetris_playfield_getWidth + * Description: returns the width of the playfield + * Argument pPl: the playfield we want information from + * Return value: width of the playfield + */ +int8_t tetris_playfield_getWidth(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getHeight + * Description: returns the height of the playfield + * Argument pPl: the playfield we want information from + * Return value: height of the playfield + */ +int8_t tetris_playfield_getHeight(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getPiece + * Description: returns the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: pointer to the currently falling piece + */ +tetris_piece_t *tetris_playfield_getPiece(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getColumn + * Description: returns the column of the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: column of the currently falling piece + */ +int8_t tetris_playfield_getColumn(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getRow + * Description: returns the row of the currently falling piece + * Argument pPl: the playfield we want information from + * Return value: row of the currently falling piece + */ +int8_t tetris_playfield_getRow(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getRowMask + * Description: returns the row mask relative to nRow + * Argument pPl: the playfield we want information from + * Return value: the first 4 bits indicate which lines (relative to nRow) + * have been removed if we are in status TETRIS_PFS_READY + */ +uint8_t tetris_playfield_getRowMask(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getStatus + * Description: returns the status of the playfield + * Argument pPl: the playfield we want information from + * Return value: status of the playfield (see tetris_playfield_status_t) + */ +tetris_playfield_status_t tetris_playfield_getStatus(tetris_playfield_t *pPl); + + +/* Function: tetris_playfield_getDumpRow + * Description: returns the given row of the dump (as bitmap) + * Argument pPl: the playfield we want information from + * Argument nRow: the number of the row (0 <= nRow <= 124) + * Return value: bitmap of the requested row (LSB is leftmost column) + */ +uint16_t tetris_playfield_getDumpRow(tetris_playfield_t *pPl, + int8_t nRow); + + +#endif /*TETRIS_PLAYFIELD_H_*/ + diff --git a/games/tetris/view.c b/games/tetris/view.c new file mode 100644 index 0000000..8b63667 --- /dev/null +++ b/games/tetris/view.c @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include +#include "../config.h" +#include "../pixel.h" +#include "../util.h" +#include "../scrolltext.h" +#include "logic.h" +#include "piece.h" +#include "playfield.h" +#include "view.h" + +/* the API simulator and the real API have different named wait functions */ +#ifdef __AVR__ + #define WAIT(ms) wait(ms) +#else + #define WAIT(ms) myWait(ms) +#endif + + +/*********** + * defines * + ***********/ + +// how often should the border blink (to indicate level up) +#define TETRIS_VIEW_BORDER_BLINK_COUNT 2 +// amount of time (in ms) between border color changes +#define TETRIS_VIEW_BORDER_BLINK_DELAY 100 + +// how often should the lines blink when they get removed +#define TETRIS_VIEW_LINE_BLINK_COUNT 3 +// amount of time (in ms) between line color changes +#define TETRIS_VIEW_LINE_BLINK_DELAY 75 + +// colors of game elements +#define TETRIS_VIEW_COLORSPACE 0 +#define TETRIS_VIEW_COLORBORDER 1 +#define TETRIS_VIEW_COLORFADE 2 +#define TETRIS_VIEW_COLORPIECE 3 + + +/*************************** + * non-interface functions * + ***************************/ + +/* Function: tetris_view_getPieceColor + * Description: helper function to dim the piece color if game is paused + * Argument pV: pointer to the view whose pause status is of interest + * Return value: void + */ +uint8_t tetris_view_getPieceColor (tetris_view_t *pV) +{ + if (pV->modeCurrent == TETRIS_VIMO_RUNNING) + { + return TETRIS_VIEW_COLORPIECE; + } + else + { + return TETRIS_VIEW_COLORBORDER; + } +} + + +/* Function: tetris_view_drawDump + * Description: redraws the dump and the falling piece (if necessary) + * Argument pV: pointer to the view on which the dump should be drawn + * Return value: void + */ +void tetris_view_drawDump(tetris_view_t *pV) +{ + assert(pV->pPl != NULL); + if (tetris_playfield_getRow(pV->pPl) <= -4) + { + return; + } + + int8_t nPieceRow = tetris_playfield_getRow(pV->pPl); + + // only redraw dump completely if the view mode has been changed + int8_t nStartRow; + if (pV->modeCurrent == pV->modeOld) + { + nStartRow = ((nPieceRow + 3) < 16) ? (nPieceRow + 3) : 15; + } + else + { + nStartRow = 15; + } + + uint16_t nRowMap; + uint16_t nElementMask; + + tetris_playfield_status_t status = tetris_playfield_getStatus(pV->pPl); + for (int8_t nRow = nStartRow; nRow >= 0; --nRow) + { + nRowMap = tetris_playfield_getDumpRow(pV->pPl, nRow); + + // if a piece is hovering or gliding it needs to be drawn + if ((status == TETRIS_PFS_HOVERING) || (status == TETRIS_PFS_GLIDING) || + (status == TETRIS_PFS_GAMEOVER)) + { + if ((nRow >= nPieceRow) && (nRow <= nPieceRow + 3)) + { + int8_t y = nRow - nPieceRow; + int8_t nColumn = tetris_playfield_getColumn(pV->pPl); + uint16_t nPieceMap = + tetris_piece_getBitmap(tetris_playfield_getPiece(pV->pPl)); + // clear all bits of the piece we are not interested in and + // align the remaining row to LSB + nPieceMap = (nPieceMap & (0x000F << (y << 2))) >> (y << 2); + // shift remaining part to current column + if (nColumn >= 0) + { + nPieceMap <<= nColumn; + } + else + { + nPieceMap >>= -nColumn; + } + // cut off unwanted stuff + nPieceMap &= 0x03ff; + // finally embed piece into the view + nRowMap |= nPieceMap; + } + } + + nElementMask = 0x0001; + + for (int8_t x = 0; x < 10; ++x) + { + unsigned char nColor; + if ((nRowMap & nElementMask) != 0) + { + nColor = tetris_view_getPieceColor(pV); + } + else + { + nColor = TETRIS_VIEW_COLORSPACE; + } + setpixel((pixel){14-x,nRow}, nColor); + nElementMask <<= 1; + } + } +} + + +/* Function: tetris_view_drawPreviewPiece + * Description: redraws the preview window + * Argument pV: pointer to the view on which the piece should be drawn + * Argmument pPc: pointer to the piece for the preview window (may be NULL) + * Return value: void + */ +void tetris_view_drawPreviewPiece(tetris_view_t *pV, tetris_piece_t *pPc) +{ + if (pPc != NULL) + { + uint8_t nColor; + uint16_t nElementMask = 0x0001; + uint16_t nPieceMap; + if (pV->modeCurrent == TETRIS_VIMO_RUNNING) + { + nPieceMap = tetris_piece_getBitmap(pPc); + } + else + { + nPieceMap = 0x26a6; + } + + for (uint8_t y = 0; y < 4; ++y) + { + for (uint8_t x = 0; x < 4; ++x) + { + if ((nPieceMap & nElementMask) != 0) + { + nColor = TETRIS_VIEW_COLORPIECE; + } + else + { + nColor = TETRIS_VIEW_COLORSPACE; + } + setpixel((pixel) {3 - x, y + 6}, nColor); + nElementMask <<= 1; + } + } + } + else + { + for (uint8_t y = 0; y < 4; ++y) + { + for (uint8_t x = 0; x < 4; ++x) + { + setpixel((pixel) {3 - x, y + 6}, TETRIS_VIEW_COLORSPACE); + } + } + } +} + + +/* Function: tetris_view_drawBorders + * Description: draws borders in the given color + * Argument nColor: the color for the border + * Return value: void + */ +void tetris_view_drawBorders(uint8_t nColor) +{ + // drawing playfield + uint8_t x, y; + for (y = 0; y < 16; ++y) + { + setpixel((pixel){4, y}, nColor); + setpixel((pixel){15, y}, nColor); + } + for (y = 0; y < 5; ++y) + { + for (x = 0; x <= 3; ++x){ + setpixel((pixel){x, y}, nColor); + setpixel((pixel){x, y + 11}, nColor); + } + } +} + + +/* Function: tetris_view_blinkBorders + * Description: lets the borders blink to notify player of a level change + * Return value: void + */ +void tetris_view_blinkBorders() +{ + for (uint8_t i = 0; i < TETRIS_VIEW_BORDER_BLINK_COUNT; ++i) + { + tetris_view_drawBorders(TETRIS_VIEW_COLORPIECE); + WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY); + tetris_view_drawBorders(TETRIS_VIEW_COLORBORDER); + WAIT(TETRIS_VIEW_BORDER_BLINK_DELAY); + } +} + + +/* Function: tetris_view_blinkLines + * Description: lets complete lines blink to emphasize their removal + * Argmument pPl: pointer to the playfield whose complete lines should blink + * Return value: void + */ +void tetris_view_blinkLines(tetris_playfield_t *pPl) +{ + // reduce necessity of pointer arithmetic + int8_t nRow = tetris_playfield_getRow(pPl); + uint8_t nRowMask = tetris_playfield_getRowMask(pPl); + + // don't try to draw below the border + int8_t nDeepestRowOffset = ((nRow + 3) < tetris_playfield_getHeight(pPl) ? + 3 : tetris_playfield_getHeight(pPl) - (nRow + 1)); + + // this loop controls how often the lines should blink + for (uint8_t i = 0; i < TETRIS_VIEW_LINE_BLINK_COUNT; ++i) + { + // this loop determines the color of the line to be drawn + for (uint8_t nColIdx = 0; nColIdx < 2; ++nColIdx) + { + // iterate through the possibly complete lines + for (uint8_t j = 0; j <= nDeepestRowOffset; ++j) + { + // is current line a complete line? + if ((nRowMask & (0x01 << j)) != 0) + { + // draw line in current color + uint8_t y = nRow + j; + for (uint8_t x = 0; x < 10; ++x) + { + + uint8_t nColor = (nColIdx == 0 ? TETRIS_VIEW_COLORFADE + : TETRIS_VIEW_COLORPIECE); + setpixel((pixel){14 - x, y}, nColor); + } + } + } + // wait a few ms to make the blink effect visible + WAIT(TETRIS_VIEW_LINE_BLINK_DELAY); + } + } +} + + +/**************************** + * construction/destruction * + ****************************/ + +/* Function: tetris_view_construct + * Description: constructs a view for André's borg + * Argument pPl: pointer to logic object which should be observed + * Argument pPl: pointer to playfield which should be observed + * Return value: pointer to a newly created view + */ +tetris_view_t *tetris_view_construct(tetris_logic_t *pLogic, + tetris_playfield_t *pPl) +{ + // memory allocation + assert((pLogic != NULL) && (pPl != NULL)); + tetris_view_t *pView = + (tetris_view_t *) malloc(sizeof(tetris_view_t)); + assert(pView != NULL); + + // init + memset(pView, 0, sizeof(tetris_view_t)); + pView->pLogic = pLogic; + pView->pPl = pPl; + pView->modeCurrent = TETRIS_VIMO_RUNNING; + pView->modeOld = TETRIS_VIMO_RUNNING; + + // drawing some first stuff + clear_screen(0); + tetris_view_drawBorders(TETRIS_VIEW_COLORBORDER); + + return pView; +} + + +/* Function: tetris_view_destruct + * Description: destructs a view + * Argument pView: pointer to the view which should be destructed + * Return value: void + */ +void tetris_view_destruct(tetris_view_t *pView) +{ + assert(pView != NULL); + free(pView); +} + + +/*************************** + * view related functions * + ***************************/ + +/* Function: tetris_view_getDimensions + * Description: destructs a view + * Argument w: [out] pointer to an int8_t to store the playfield width + * Argument h: [out] pointer to an int8_t to store the playfield height + * Return value: void + */ +void tetris_view_getDimensions(int8_t *w, + int8_t *h) +{ + assert((w != NULL) && (h != NULL)); + *w = 10; + *h = 16; +} + + +/* Function: tetris_view_setViewMode + * Description: sets the view mode (pause or running) + * Argument pV: pointer to the view whose mode should be set + * Argument vm: see definition of tetris_view_mode_t + * Return value: void + */ +void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm) +{ + pV->modeOld = pV->modeCurrent; + pV->modeCurrent = vm; +} + + +/* Function: tetris_view_update + * Description: informs a view about changes in the game + * Argument pV: pointer to the view which should be updated + * Return value: void + */ +void tetris_view_update(tetris_view_t *pV) +{ + assert(pV != NULL); + + // let complete lines blink (if there are any) + if (tetris_playfield_getRowMask(pV->pPl) != 0) + { + tetris_view_blinkLines(pV->pPl); + } + + // draw preview piece + tetris_view_drawPreviewPiece(pV, tetris_logic_getPreviewPiece(pV->pLogic)); + + // draw dump + tetris_view_drawDump(pV); + + // visual feedback to inform about a level change + uint8_t nLevel = tetris_logic_getLevel(pV->pLogic); + if (nLevel != pV->nOldLevel) + { + tetris_view_blinkBorders(); + pV->nOldLevel = nLevel; + } +} + + +/* Function: tetris_view_showResults + * Description: shows results after game + * Argument pV: pointer to the view which should show the reults + * Return value: void + */ +void tetris_view_showResults(tetris_view_t *pV) +{ + char pszResults[48]; + uint16_t nScore = tetris_logic_getScore(pV->pLogic); + uint16_t nHighscore = tetris_logic_getHighscore(pV->pLogic); + uint16_t nLines = tetris_logic_getLines(pV->pLogic); + + if (nScore <= nHighscore) + { + snprintf(pszResults, 48 * sizeof(char), + " +#include "logic.h" +#include "piece.h" +#include "playfield.h" + + +/********* + * types * + *********/ + +// presentation modes +typedef enum tetris_view_mode_t +{ + TETRIS_VIMO_PAUSED, + TETRIS_VIMO_RUNNING +} +tetris_view_mode_t; + +typedef struct tetris_view_t +{ + tetris_logic_t *pLogic; // associated logic object + tetris_playfield_t *pPl; // associated playfield + tetris_view_mode_t modeCurrent; // current presentation mode + tetris_view_mode_t modeOld; // old presentation mode + uint8_t nOldLevel; // helper variable to recognize level changes +} +tetris_view_t; + + +/***************************** + * construction/destruction * + *****************************/ + +/* Function: tetris_view_construct + * Description: constructs a view for André's borg + * Argument pPl: pointer to logic object which should be observed + * Argument pPl: pointer to playfield which should be observed + * Return value: pointer to a newly created view + */ +tetris_view_t *tetris_view_construct(tetris_logic_t *pLogic, + tetris_playfield_t *pPl); + + +/* Function: tetris_view_destruct + * Description: destructs a view + * Argument pView: pointer to the view to be destructed + * Return value: void + */ +void tetris_view_destruct(tetris_view_t *pView); + + +/*************************** + * view related functions * + ***************************/ + +/* Function: tetris_view_getDimensions + * Description: destructs a view + * Argument w: [out] pointer to an int8_t to store the playfield width + * Argument h: [out] pointer to an int8_t to store the playfield height + * Return value: void + */ +void tetris_view_getDimensions(int8_t *w, + int8_t *h); + + +/* Function: tetris_view_setViewMode + * Description: sets the view mode (pause or running) + * Argument pV: pointer to the view whose mode should be set + * Argument vm: see definition of tetris_view_mode_t + * Return value: void + */ +void tetris_view_setViewMode(tetris_view_t *pV, tetris_view_mode_t vm); + + +/* Function: tetris_view_update + * Description: informs a view about changes in the game + * Argument pV: pointer to the view which should be updated + * Return value: void + */ +void tetris_view_update(tetris_view_t *pV); + + +/* Function: tetris_view_showResults + * Description: shows results after game + * Argument pV: pointer to the view which should show the reults + * Return value: void + */ +void tetris_view_showResults(tetris_view_t *pV); + + +#endif /*TETRIS_VIEW_H_*/ + diff --git a/joystick.c b/joystick.c new file mode 100644 index 0000000..9888153 --- /dev/null +++ b/joystick.c @@ -0,0 +1,13 @@ +#include "joystick.h" +#include + +unsigned char waitForFire; + + +inline void joy_init(){ + DDRB &= ~((1< + +unsigned char waitForFire; +void joy_init(); + +#define BITFIRE PD3 +#define BITRIGHT PB3 +#define BITLEFT PB2 +#define BITDOWN PB1 +#define BITUP PB0 + +#define JOYISFIRE (!(PIND & (1< +#include +#include + +#include "autoconf.h" +//#include "config.h" +#include "scrolltext/scrolltext.h" +#include "animations/programm.h" +#include "animations/matrix.h" +#include "animations/gameoflife.h" +#include "borg_hw/borg_hw.h" +#include "can/borg_can.h" +#include "random/prng.h" +#include "random/persistentCounter.h" +#include "mcuf/mcuf.h" +#include "menu/menu.h" +#include "pixel.h" +#include "joystick.h" + +volatile unsigned char oldMode, oldOldmode, mode; + +jmp_buf newmode_jmpbuf; + +int main (void){ + clear_screen(0); + + borg_hw_init(); + +#ifdef RANDOM_SUPPORT + srandom32(percnt_get()); + percnt_inc(); +#endif + +#ifdef CAN_SUPPORT + bcan_init(); +#endif + +#ifdef JOYSTICK_SUPPORT + joy_init(); +#endif + +#ifdef UART_SUPPORT + uart_init(); +#endif + + sei(); + +// mcuf_serial_mode(); + + mode = setjmp(newmode_jmpbuf); + oldOldmode = oldMode; + waitForFire = 1; + for(;;){ + oldMode = mode; + switch(mode++) { + +#ifdef ANIMATION_SCROLLTEXT + case 1: + scrolltext(scrolltext_text); + { char a[14]; + sprintf(a,"height_l == 8 && mcuf->width_l == 18){ + uint8_t x,y; + for(y=0;y<8;y++){ + for(x=0;x<16;x++){ + setpixel((pixel){15-x, y+4}, mcuf->pixels[y*18 + x + 1] >> 6 ); + } + } + }else if(mcuf->height_l == 16 && mcuf->width_l == 16){ + uint8_t x,y; + for(y=0;y<16;y++){ + for(x=0;x<16;x++){ + setpixel((pixel){15-x, y}, mcuf->pixels[y*16 + x] >> 6 ); + } + } + } + +} + +static uint8_t mcuf_magic[4] = {0x23, 0x54, 0x26, 0x66}; + + +void mcuf_serial_mode(){ + mcuf_t mcuf_packet; + uint8_t c; + + while(1){ + uint16_t count = 0; + uint8_t x; + uint16_t num_pixels; + do{ + c = my_uart_getc(); + ((uint8_t*)&mcuf_packet)[count] = c; + if(c == mcuf_magic[count] ){ + count ++; + }else{ + count = 0; + } + }while(count != 4); + + for(x=0; x<4; x++){ + c = my_uart_getc(); + ((uint8_t*)&mcuf_packet)[count++] = c; + } + num_pixels = (uint16_t)mcuf_packet.width_l * mcuf_packet.height_l; + if(num_pixels <= 256){ + num_pixels += 4; + while(num_pixels--){ + c = my_uart_getc(); + ((uint8_t*)&mcuf_packet)[count++] = c; + } + parse_mcuf(&mcuf_packet); + } + } +} + + diff --git a/mcuf/mcuf.h b/mcuf/mcuf.h new file mode 100644 index 0000000..f931f15 --- /dev/null +++ b/mcuf/mcuf.h @@ -0,0 +1,3 @@ + +void mcuf_serial_mode(); + diff --git a/menu/menu.c b/menu/menu.c new file mode 100644 index 0000000..7c9d118 --- /dev/null +++ b/menu/menu.c @@ -0,0 +1,272 @@ +/* A game chooser for borgs + * by: Christian Kroll + * date: Thursday, 2008/03/16 + */ + +#include +#include +#include + +// architecture dependent stuff +#ifdef __AVR__ +#include +#define WAIT(ms) wait(ms) +#else +#define PROGMEM +#define WAIT(ms) myWait(ms) +#endif + +#include "menu.h" +#include "config.h" +#include "util.h" +#include "pixel.h" +#include "joystick.h" +#include "snake.h" +#include "tetris/logic.h" +#include "invaders2.h" + +// defines +#define MENU_WIDTH_ICON 8 +#define MENU_HEIGHT_ICON 8 +#define MENU_WIDTH_DELIMITER 2 +#define MENU_POLL_INTERVAL 10 +#define MENU_TIMEOUT_ITERATIONS 2000 +#define MENU_WAIT_CHATTER 60 +#define MENU_WAIT_INITIAL 40 +#define MENU_WAIT_INCREMENT 0 + +#define MENU_NEXTITEM(item) ((item + 1) % MENU_ITEM_MAX) +#define MENU_PREVITEM(item) ((item + MENU_ITEM_MAX - 1) % MENU_ITEM_MAX) + +void menu() +{ + // don't let WAIT() query fire button to prevent endless circular jumps + waitForFire = 0; + + clear_screen(0); + + // wait as long the fire button is pressed to prevent unwanted selections + while (JOYISFIRE) + { + WAIT(MENU_POLL_INTERVAL); + } + + // set initial menu item + static menu_item_t miSelection = MENU_ITEM_TETRIS; + // scroll in currently selected menu item + menu_animate(MENU_PREVITEM(miSelection), MENU_DIRECTION_LEFT); + + uint16_t nMenuIterations= MENU_TIMEOUT_ITERATIONS; + + while (1) + { + // the user has made her/his choice + if (JOYISFIRE) + { + // prevent unwanted selections + while (JOYISFIRE) + { + WAIT(MENU_POLL_INTERVAL); + } + // work against the chatter effects of dump joysticks + WAIT(MENU_WAIT_CHATTER); + + // call corresponding function + switch (miSelection) + { + case MENU_ITEM_SNAKE: + snake_game(); + break; + case MENU_ITEM_SPACEINVADERS: + borg_invaders(); + break; + case MENU_ITEM_TETRIS: + tetris(); + break; + default: + break; + } + break; + } + // change selected item and do some scrolling + else if (JOYISRIGHT) + { + menu_animate(miSelection, MENU_DIRECTION_LEFT); + miSelection = MENU_NEXTITEM(miSelection); + nMenuIterations = MENU_TIMEOUT_ITERATIONS; + } + else if (JOYISLEFT) + { + menu_animate(miSelection, MENU_DIRECTION_RIGHT); + miSelection = MENU_PREVITEM(miSelection); + nMenuIterations = MENU_TIMEOUT_ITERATIONS; + } + // exit menu + else if (JOYISUP) + { + break; + } + // return if timeout is reached + else + { + WAIT(MENU_POLL_INTERVAL); + if (--nMenuIterations == 0) + break; + } + } + + waitForFire = 1; + return; +} + +uint8_t menu_getIconPixel(menu_item_t item, int8_t x, int8_t y) +{ + // MSB is leftmost pixel + static uint8_t nIcon[][8] PROGMEM = + {{0xff, 0x81, 0xbd, 0xa5, 0xa5, 0xad, 0xa1, 0xbf}, // Snake icon + {0x66, 0x18, 0x3c, 0x5a, 0xff, 0xbd, 0xa5, 0x18}, // Invaders icon + {0x0f, 0x0f, 0xc3, 0xdb, 0xdb, 0xc3, 0xf0, 0xf0}}; // Tetris icon + + // is x within the icon or do we have reached the delimiter? + if (x < MENU_WIDTH_ICON) + { + // return pixel +#ifdef __AVR__ + return (0x80 >> x) & pgm_read_word(&nIcon[item][y]); +#else + return (0x80 >> x) & nIcon[item][y]; +#endif + } + else + { + // delimiter + return 0; + } +} + +void menu_animate(menu_item_t miInitial, menu_direction_t direction) +{ + int16_t nWait= MENU_WAIT_INITIAL; + + // space between left border and the icon in the middle + int8_t nWidthSide = (NUM_COLS - MENU_WIDTH_ICON) / 2; + + // determine the icon at the leftmost position + menu_item_t mi = miInitial + MENU_ITEM_MAX; + int8_t nBack = nWidthSide / (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER); + if ((nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) != 0) + { + ++nBack; + } + mi = (mi + MENU_ITEM_MAX - (nBack % MENU_ITEM_MAX)) % MENU_ITEM_MAX; + + // start and stop offsets for the scrolling icons (both are 0 for stills) + int8_t nStart, nStop; + if (direction == MENU_DIRECTION_STILL) + { + nStart = 0; + nStop = 0; + } + else + { + nStart = 1; + nStop = MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER; + } + + // draw menu screen for each offset within the nStart/nStop range + int8_t i; + for (i = nStart; i <= nStop; ++i) + { + int8_t nOffset; + if (direction == MENU_DIRECTION_LEFT) + nOffset = i; + else + nOffset = -i; + + // offset of the left most icon if it is cut by the left border + int8_t nInitialSideOffset = (((MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER) + - (nWidthSide % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))) + + nOffset + (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) + % (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER); + + // an initial side offset of 0 means the leftmost icon was changed + // if we are scrolling to the left, increment value for leftmost item + if (direction == MENU_DIRECTION_LEFT) + { + if (nInitialSideOffset == 0) + { + mi = MENU_NEXTITEM(mi); + } + } + + // draw the icons from the leftmost position (line by line) + int8_t y; + for (y = 0; y < MENU_HEIGHT_ICON; ++y) + { + menu_item_t miCurrent = mi; + int8_t nIconOffset = nInitialSideOffset; + int8_t x; + for (x = 0; x < NUM_COLS; ++x) + { + int8_t nPixel = menu_getIconPixel(miCurrent, nIconOffset, y); + + menu_setpixel(x, ((NUM_ROWS - MENU_HEIGHT_ICON) / 2) + y, + nPixel); + if (++nIconOffset >= (MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER)) + { + nIconOffset = 0; + miCurrent = MENU_NEXTITEM(miCurrent); + } + } + } + + // an initial side offset of 0 means the leftmost icon was changed + // if we are scrolling to the right, decrement value for leftmost item + if (direction == MENU_DIRECTION_RIGHT) + { + if (nInitialSideOffset == 0) + { + mi = MENU_PREVITEM(mi); + } + } + + // wait between the frames so that the animation can be seen + WAIT(nWait); + // animation speed can be throtteled + nWait += MENU_WAIT_INCREMENT; + } +} + +void menu_setpixel(int8_t x, int8_t y, int8_t isSet) +{ + uint8_t nColor; + + // mirror mirror on the wall, what's the quirkiest API of them all... + x = NUM_COLS - 1 - x; + uint8_t nMiddle = (NUM_COLS - MENU_WIDTH_ICON) / 2; + + if (isSet != 0) + { + if ((x >= nMiddle - MENU_WIDTH_DELIMITER) && (x < (nMiddle + + MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))) + { + nColor = 3; + } + else if ((x == (nMiddle - MENU_WIDTH_DELIMITER - 1)) || (x == (nMiddle + + MENU_WIDTH_ICON + MENU_WIDTH_DELIMITER))) + { + nColor = 2; + } + else + { + nColor = 1; + } + } + else + { + nColor = 0; + } + + setpixel((pixel){x, y}, nColor); +} + diff --git a/menu/menu.h b/menu/menu.h new file mode 100644 index 0000000..d23ca35 --- /dev/null +++ b/menu/menu.h @@ -0,0 +1,34 @@ +/* A game chooser for borgs + * by: Christian Kroll + * date: Tuesday, 2008/03/16 + */ + +#ifndef MENU_H_ +#define MENU_H_ + +#include + +typedef enum menu_item_t +{ + MENU_ITEM_SNAKE, + MENU_ITEM_SPACEINVADERS, + MENU_ITEM_TETRIS, + MENU_ITEM_MAX // fake entry to mark the end +} +menu_item_t; + +typedef enum menu_direction_t +{ + MENU_DIRECTION_LEFT, + MENU_DIRECTION_RIGHT, + MENU_DIRECTION_STILL +} +menu_direction_t; + +void menu(); +void menu_animate(menu_item_t currentItem, menu_direction_t direction); +uint8_t menu_getIconPixel(menu_item_t item, int8_t x, int8_t y); +void menu_setpixel(int8_t x, int8_t y, int8_t isSet); + +#endif /*MENU_H_*/ + diff --git a/pixel.c b/pixel.c new file mode 100644 index 0000000..dc7bf54 --- /dev/null +++ b/pixel.c @@ -0,0 +1,127 @@ +#define PIXEL_C + +#include "config.h" + +#include "pixel.h" +#include "borg_hw/borg_hw.h" + +unsigned char shl_table[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; + +void clear_screen(unsigned char value){ + unsigned char p,*pix,v=0xff; + unsigned int i; + for(p=0;pNUMPLANE) + value=NUMPLANE; + unsigned char pos = (p.y%NUM_ROWS)*LINEBYTES + (p.x/8); + unsigned char mask = shl_table[p.x%8]; + unsigned char plane; + for(plane=0;plane>= 1; + pixmap[plane][row][byte] |= (pixmap[plane][row][byte+1] & 0x01) * 0x80;; + } + pixmap[plane][row][LINEBYTES-1] >>= 1; + } + } +} + + +unsigned char get_pixel(pixel p){ + + if( (p.x >= NUM_COLS) || (p.y >= NUM_ROWS) ){ + return 0xff; + }else{ + return 0!= (pixmap[0][p.y][p.x/8] & shl_table[p.x%8]); + } +} + + +unsigned char get_next_pixel(pixel p, direction dir){ + pixel tmp; + switch (dir){ + case right: + tmp = (pixel){p.x-1, p.y}; + break; + case left: + tmp = (pixel){p.x+1, p.y}; + break; + case down: + tmp = (pixel){p.x, p.y+1}; + break; + case up: + tmp = (pixel){p.x, p.y-1}; + break; + default: + tmp = p; + break; + } + return get_pixel(tmp); +} + +direction direction_r(direction dir){ + switch (dir){ + case right: + return(down); + case down: + return(left); + case left: + return(up); + case up: + return (right); + } + return(0); +} + +void set_cursor(cursor* cur, pixel p){ + cur->pos = p; + switch (cur->mode){ + case clear: + clearpixel(p); + break; + case set: + setpixel(p,3); + break; + } +} + +pixel next_pixel(pixel pix, direction dir){ + switch (dir){ + case right: + return((pixel){pix.x-1, pix.y}); + break; + case left: + return((pixel){pix.x+1, pix.y}); + break; + case down: + return((pixel){pix.x, pix.y+1}); + break; + case up: + return((pixel){pix.x, pix.y-1}); + break; + + } + return (pixel){0,0}; +} diff --git a/pixel.h b/pixel.h new file mode 100644 index 0000000..a149d43 --- /dev/null +++ b/pixel.h @@ -0,0 +1,41 @@ +#ifndef PIXEL_H +#define PIXEL_H + +#define LINEBYTES (((NUM_COLS-1)/8)+1) + +extern unsigned char shl_table[]; +extern unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; + +typedef struct { + unsigned char x; + unsigned char y; +} pixel; + + +typedef enum {right,left,up,down} direction; +typedef struct { + pixel pos; + direction dir; + enum{clear=0, set=1} mode; +} cursor; + +/**************************************************************************** + * Pixel routines + */ +void clear_screen(unsigned char value); +void setpixel(pixel p, unsigned char value); +#define clearpixel(p) setpixel(p, 0); + +unsigned char get_pixel(pixel p); +unsigned char get_next_pixel(pixel p, direction dir); + +pixel next_pixel(pixel pix, direction dir); + +direction direction_r(direction dir); + +void shift_pixmap_l(); + + +void set_cursor(cursor* cur, pixel p); + +#endif // PIXEL_H diff --git a/random/memxor.S b/random/memxor.S new file mode 100644 index 0000000..b89fccd --- /dev/null +++ b/random/memxor.S @@ -0,0 +1,68 @@ +/* memxor.S */ +/* + This file is part of the Crypto-avr-lib/microcrypt-lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + 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 3 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, see . +*/ + +/* + * File: memxor.S + * Author: Daniel Otte + * Date: 2008-08-07 + * License: GPLv3 or later + * Description: memxor, XORing one block into another + * + */ + +/* + * void memxor(void* dest, const void* src, uint16_t n); + */ + /* + * param dest is passed in r24:r25 + * param src is passed in r22:r23 + * param n is passed in r20:r21 + */ +.global memxor +memxor: + movw r30, r24 + movw r26, r22 + movw r24, r20 + tst r24 + brne 1f + tst r25 + breq 2f +1: + ld r20, X+ + ld r21, Z + eor r20, r21 + st Z+, r20 + sbiw r24, 1 + brne 1b +2: + ret + + + + + + + + + + + + + + diff --git a/random/memxor.h b/random/memxor.h new file mode 100644 index 0000000..a62a616 --- /dev/null +++ b/random/memxor.h @@ -0,0 +1,7 @@ +#ifndef MEMXOR_H_ +#define MEMXOR_H_ +#include + +void memxor(void* dest, const void* src, uint16_t n); + +#endif diff --git a/random/noekeon.h b/random/noekeon.h new file mode 100644 index 0000000..5817d9f --- /dev/null +++ b/random/noekeon.h @@ -0,0 +1,76 @@ +/* noekeon.h */ +/* + This file is part of the Crypto-avr-lib/microcrypt-lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + 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 3 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, see . +*/ +#ifndef NOEKEON_H_ +#define NOEKEON_H_ + +/** + * \author Daniel Otte + * \email daniel.otte@rub.de + * \date 2008-04-11 + * \license GPLv3 + * \brief + * + * + */ + +#include + +typedef uint8_t noekeon_ctx_t[16]; + +/** \fn void noekeon_enc(void* buffer, void* key) + * \brief noekeon encrytion funtion + * + * This function encrypts a block (64 bit = 8 byte) with the noekeon encrytion + * algorithm. Due to the two modes of noekeon (direct mode and indirect mode) + * the second parameter either points directly to the key (direct mode) or to a + * context generated by the noekeon_init() function (indirect mode) + * \param buffer pointer to the 64 bit (8 byte) block to encrypt + * \param key pointer to either the key (128 bit = 16 byte; direct mode) or + * to the context (indirect mode) + */ +void noekeon_enc(void* buffer, const void* key); + +/** \fn void noekeon_enc(void* buffer, void* key) + * \brief noekeon encrytion funtion + * + * This function decrypts a block (64 bit = 8 byte) encrypted with the noekeon + * encrytion algorithm. Due to the two modes of noekeon (direct mode and + * indirect mode) the second parameter either points directly to the key + * (direct mode) or to a context generated by the noekeon_init() function + * (indirect mode) + * \param buffer pointer to the 64 bit (8 byte) block to decrypt + * \param key pointer to either the key (128 bit = 16 byte; direct mode) or + * to the context (indirect mode) + */ +void noekeon_dec(void* buffer, const void* key); + + +/** \fn void noekeon_init(void* key, noekeon_ctx_t* ctx) + * \brief noekeon context generation function for indirect mode + * + * This function generates a context from the supplied key for using + * noekeon in indirect mode. For using noekeon in direct mode supply the key + * direct to the noekeon_enc() and noekeon_dec() functions + * \param key pointer to the key (128 bit = 16 byte) + * \param ctx pointer to the context to fill with key material + * to the context (indirect mode) + */ +void noekeon_init(const void* key, noekeon_ctx_t* ctx); + +#endif /*NOEKEON_H_*/ diff --git a/random/noekeon_asm.S b/random/noekeon_asm.S new file mode 100644 index 0000000..5b23292 --- /dev/null +++ b/random/noekeon_asm.S @@ -0,0 +1,641 @@ +/* noekeon_asm.S */ +/* + This file is part of the Crypto-avr-lib/microcrypt-lib. + Copyright (C) 2008 Daniel Otte (daniel.otte@rub.de) + + 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 3 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, see . +*/ +/* + * noekeon assembler implementation for avr + * author: Daniel Otte + * email: daniel.otte@rub.de + * license: GPLv3 + */ + +#include + +.macro push_all + push r2 + push r3 + push r4 + push r5 + push r6 + push r7 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + push r16 + push r17 + push r28 + push r29 +.endm + +.macro pop_all + pop r29 + pop r28 + pop r17 + pop r16 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + clr r1 +.endm + +push_all_func: + pop r31 + pop r30 + push_all + ijmp + +pop_all_func: + pop r31 + pop r30 + pop_all + ijmp + +.macro xchg a b + eor \a, \b + eor \b, \a + eor \a, \b +.endm + +.macro op32 op a b + \op \a\()_0, \b\()_0 + \op \a\()_1, \b\()_1 + \op \a\()_2, \b\()_2 + \op \a\()_3, \b\()_3 +.endm + + +.macro op32_4t op a b c d w x y z + \op \a, \w + \op \b, \x + \op \c, \y + \op \d, \z +.endm + + +.macro op32_prefix op p q a b c d w x y z + \op \p\()\a, \q\()\w + \op \p\()\b, \q\()\x + \op \p\()\c, \q\()\y + \op \p\()\d, \q\()\z +.endm + +; === bigendian_rotl32 === +; this function rotates a 32bit bigendian word n bits to the left +; param1: the 32-bit value +; given in r25,r24,r23,r22 (r22 is most significant) +; param2: the 8-bit parameter giving the number of bits to rotate +; given in r20 +; return: the rotatet 32-bit word +; given in r25,r24,r23,r22 + +bigendian_rotl32: + /* copy high bit of r22 to carry */ + mov r1, r22 +2: + rol r1 + + rol r25 + rol r24 + rol r23 + rol r22 + + dec r20 + brne 2b +bigendian_rotl32_exit: + clr r1 + ret + + +/******************************************************************************/ + +; === bigendian_rotl32 === +; this function rotates a 32bit bigendian word n bits to the right +; param1: the 32-bit value +; given in r25,r24,r23,r22 (r22 is most significant) +; param2: the 8-bit parameter giving the number of bits to rotate +; given in r20 +; return: the rotatet 32-bit word +; given in r25,r24,r23,r22 + +bigendian_rotr32: + /* copy high bit of r25 to carry */ + + mov r1, r25 +2: + ror r1 + + ror r22 + ror r23 + ror r24 + ror r25 + dec r20 + brne 2b +bigendian_rotr32_exit: + clr r1 + ret + +/******************************************************************************/ +/* +void theta(uint32_t* k, uint32_t* a){ + uint32_t temp; + temp = a[0] ^ a[2]; temp ^= ROTR32(temp, 8) ^ ROTL32(temp, 8); + a[1] ^= temp; + a[3] ^= temp; + + a[0] ^= k[0]; + a[1] ^= k[1]; + a[2] ^= k[2]; + a[3] ^= k[3]; + + temp = a[1] ^ a[3]; temp ^= ROTR32(temp, 8) ^ ROTL32(temp, 8); + a[0] ^= temp; + a[2] ^= temp; +} +*/ + +round_const: .byte 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, \ + 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, \ + 0xD4 + +;-- a[0] +state0_0 = 2 +state0_1 = 3 +state0_2 = 4 +state0_3 = 5 +;-- a[1] +state1_0 = 6 +state1_1 = 7 +state1_2 = 8 +state1_3 = 9 +;-- a[2] +state2_0 = 10 +state2_1 = 11 +state2_2 = 12 +state2_3 = 13 +;-- a[3] +state3_0 = 14 +state3_1 = 15 +state3_2 = 16 +state3_3 = 17 + +; === theta === +; +; param1: the state in r2-r17 +; param2: pointer to k in X (r26,r27) +; +temp_a = 18 +temp_b = 19 +temp_c = 20 +temp_d = 21 + +theta: + /* temp = a[0] ^ a[2]; temp ^= temp>>>8 ^ temp<<<8 */ + op32_prefix mov, temp_, state0_, a,b,c,d, 0,1,2,3 + op32_prefix eor, temp_, state2_, a,b,c,d, 0,1,2,3 + + mov r1, temp_a + eor r1, temp_b + eor r1, temp_c + eor r1, temp_d + + op32_prefix eor, temp_, r, a,b,c,d, 1,1,1,1 + + /* temp is know a little bit mixed c,d,a,b (if abcd is normal order) */ + /* a[1] ^= temp */ + eor state1_0, temp_c + eor state1_1, temp_d + eor state1_2, temp_a + eor state1_3, temp_b + /* a[3] ^= temp */ + eor state3_0, temp_c + eor state3_1, temp_d + eor state3_2, temp_a + eor state3_3, temp_b + + /* state ^ k (X points to K) */ + ldi r28, 2 + clr r29 /* Y points to r2 aka state0_0 */ + ldi temp_a, 16 +1: + ld r1, X+ + ld r0, Y + eor r1, r0 + st Y+, r1 + dec temp_a + brne 1b + sbiw r26, 16 /* set X back to key */ + + mov temp_a, state1_0 + mov temp_b, state1_1 + mov temp_c, state1_2 + mov temp_d, state1_3 + eor temp_a, state3_0 + eor temp_b, state3_1 + eor temp_c, state3_2 + eor temp_d, state3_3 + mov r1, temp_a + eor r1, temp_b + eor r1, temp_c + eor r1, temp_d + eor temp_a, r1 + eor temp_b, r1 + eor temp_c, r1 + eor temp_d, r1 + /* temp is know a little bit mixed c,d,a,b (if abcd is normal order) */ + /* a[0] ^= temp */ + eor state0_0, temp_c + eor state0_1, temp_d + eor state0_2, temp_a + eor state0_3, temp_b + /* a[2] ^= temp */ + eor state2_0, temp_c + eor state2_1, temp_d + eor state2_2, temp_a + eor state2_3, temp_b + + clr r1 + ret + +/******************************************************************************/ +#ifndef NOEKEON_NO_ENC +; === noekeon_enc === +; +; param1: pointer to buffer (r24,r25) +; param2: pointer to k (r22,r23) +; +.global noekeon_enc +noekeon_enc: + rcall push_all_func + /* load state */ + movw r26, r22 + ldi r28, 2 + clr r29 /* Y points at r2 aka state0_0 */ + movw r30, r24 /* Z points at state */ + push r30 + push r31 + ldi r22, 16 + push r22 /* 16 is also the number of rounds and gets pushed here */ +1: + ld r0, Z+ + st Y+, r0 + dec r22 + brne 1b + /* state loaded */ + push r1 /* push round constan2 (0x00) */ + ldi r20, 0x80 + push r20 /* push round constan2 (0x00) */ + rjmp 3f +2: + ldi r30, lo8(round_const+15) + ldi r31, hi8(round_const+15) + sub r30, r22 + sbci r31, 0 + clr r1 + push r1 + lpm r0, Z + push r0 +3: + rcall round /* pops rc2 & rc1 */ + pop r22 + dec r22 + push r22 + brne 2b + + pop r22 + + ldi r22, 0xD4 + eor state0_3, r22 + rcall theta + + pop r31 + pop r30 + clr r29 + ldi r28, 2 + ldi r22, 16 +1: + ld r0, Y+ + st Z+, r0 + dec r22 + brne 1b + + rcall pop_all_func + ret +#endif +/******************************************************************************/ +/******************************************************************************/ +#ifndef NOEKEON_NO_DEC + +; === noekeon_dec === +; +; param1: pointer to buffer/state (r24,r25) +; param2: pointer to k (r22,r23) +; +.global noekeon_dec +noekeon_dec: + rcall push_all_func + /* allocate 16 bytes on the stack */ + in r30, _SFR_IO_ADDR(SPL) + in r31, _SFR_IO_ADDR(SPH) + sbiw r30, 16 + out _SFR_IO_ADDR(SPH), r31 + out _SFR_IO_ADDR(SPL), r30 + + adiw r30, 1 + /* push state pointer */ + push r24 + push r25 + movw r26, r22 /* move key ptr to X */ + + /* set stackkey to zero */ + ldi r22, 16 +1: st Z+, r1 + dec r22 + brne 1b + + /* copy key to state */ + clr r29 + ldi r28, 2 + ldi r22, 16 +1: ld r0, X+ + st Y+, r0 + dec r22 + brne 1b + + movw r26, r30 + sbiw r26, 16 /* set X back to begining of stack key */ + rcall theta + + /* mov state to stackkey */ + clr r29 + ldi r28, 2 + ldi r22, 16 +1: ld r0, Y+ + st X+, r0 + dec r22 + brne 1b + sbiw r26, 16 /* set X back to begining of stack key */ + + /* move data from stateptr to state */ + pop r31 + pop r30 + push r30 + push r31 + clr r29 + ldi r28, 2 + ldi r22, 16 + push r22 +1: ld r0, Z+ + st Y+, r0 + dec r22 + brne 1b + +;--- snip 8< ---- + + ldi r20, 0xD4 + push r20 /* push round constant2 (0xD4) */ + push r22 /* push round constan1 (0x00) */ + rjmp 3f +2: + ldi r30, lo8(round_const-1) + ldi r31, hi8(round_const-1) + clr r1 + add r30, r22 + adc r31, r1 + lpm r0, Z + push r0 + push r1 +3: + rcall round /* pops rc2 & rc1 */ + pop r22 + dec r22 + push r22 + brne 2b +;---- + pop r22 + + rcall theta + ldi r22, 0x80 + eor state0_3, r22 + +write_state_back: + /* write state back */ + pop r31 /* pop state pointer */ + pop r30 + clr r29 + ldi r28, 2 + ldi r22, 16 +1: + ld r0, Y+ + st Z+, r0 + dec r22 + brne 1b + + /* remove key from stack */ + in r30, _SFR_IO_ADDR(SPL) + in r31, _SFR_IO_ADDR(SPH) + adiw r30, 16 + out _SFR_IO_ADDR(SPH), r31 + out _SFR_IO_ADDR(SPL), r30 + rcall pop_all_func + ret +#endif +/******************************************************************************/ + + +round: + pop r24 + pop r25 + pop r1 + eor state0_3, r1 + rcall theta + pop r1 + eor state0_3, r1 + push r25 + push r24 +pi_gamma_pi: + ldi r30, pm_lo8(bigendian_rotl32) + ldi r31, pm_hi8(bigendian_rotl32) + rcall pi + /* pi1 done; now gamma */ + rcall gamma_1 + /* a[0] <-> a[3] */ + xchg state0_0, state3_0 + xchg state0_1, state3_1 + xchg state0_2, state3_2 + xchg state0_3, state3_3 + /* a[2] ^= a[0] ^ a[1] ^ a[3] */ + op32 eor, state2, state0 + op32 eor, state2, state1 + op32 eor, state2, state3 + + rcall gamma_1 + ldi r30, pm_lo8(bigendian_rotr32) + ldi r31, pm_hi8(bigendian_rotr32) + rcall pi + ret + +gamma_1: + /* a[1] ^= ~(a[3]|a[2])*/ + mov r1, state3_0 + or r1, state2_0 + com r1 + eor state1_0, r1 + + mov r1, state3_1 + or r1, state2_1 + com r1 + eor state1_1, r1 + + mov r1, state3_2 + or r1, state2_2 + com r1 + eor state1_2, r1 + + mov r1, state3_3 + or r1, state2_3 + com r1 + eor state1_3, r1 + + /* a[0] ^= a[2]&a[1] */ + mov r1, state2_0 + and r1, state1_0 + eor state0_0, r1 + + mov r1, state2_1 + and r1, state1_1 + eor state0_1, r1 + + mov r1, state2_2 + and r1, state1_2 + eor state0_2, r1 + + mov r1, state2_3 + and r1, state1_3 + eor state0_3, r1 + ret + +pi: + /* a[1] <<<= 1*/ + mov r22, state1_0 + mov r23, state1_1 + mov r24, state1_2 + mov r25, state1_3 + ldi r20, 1 + icall + mov state1_0, r22 + mov state1_1, r23 + mov state1_2, r24 + mov state1_3, r25 + /* a[2] <<<= 5*/ + mov r22, state2_0 + mov r23, state2_1 + mov r24, state2_2 + mov r25, state2_3 + ldi r20, 5 + icall + mov state2_0, r22 + mov state2_1, r23 + mov state2_2, r24 + mov state2_3, r25 + /* a[3] <<<= 2*/ + mov r22, state3_0 + mov r23, state3_1 + mov r24, state3_2 + mov r25, state3_3 + ldi r20, 2 + icall + mov state3_0, r22 + mov state3_1, r23 + mov state3_2, r24 + mov state3_3, r25 + ret + +/******************************************************************************/ + +/* +void noekeon_init(void* key, noekeon_ctx_t* ctx){ + uint8_t nullv[16]; + + memset(nullv, 0, 16); + memcpy(ctx, key, 16); + noekeon_enc(ctx, nullv); +} +*/ + +#ifndef NOEKEON_NO_INIT + +.global noekeon_init +noekeon_init: +; === noekeon_init === +; +; param1: pointer to key (r24,r25) +; param2: pointer to context (r22,r23) +; + in r30, _SFR_IO_ADDR(SPL) + in r31, _SFR_IO_ADDR(SPH) + sbiw r30, 16 + out _SFR_IO_ADDR(SPH), r31 + out _SFR_IO_ADDR(SPL), r30 + + movw r26, r22 + adiw r30, 1 + movw r22, r30 + /* set nullv(stack) to zero */ + ldi r20, 16 +1: st Z+, r1 + dec r20 + brne 1b + + /* copy key data to ctx */ + movw r30, r24 + ldi r20, 16 +1: ld r1, Z+ + st X+, r1 + dec r20 + brne 1b + clr r1 + + sbiw r26, 16 + movw r24, r26 + rcall noekeon_enc + + in r30, _SFR_IO_ADDR(SPL) + in r31, _SFR_IO_ADDR(SPH) + adiw r30, 16 + out _SFR_IO_ADDR(SPH), r31 + out _SFR_IO_ADDR(SPL), r30 + ret + +#endif + + diff --git a/random/persistentCounter.c b/random/persistentCounter.c new file mode 100644 index 0000000..5ccf85e --- /dev/null +++ b/random/persistentCounter.c @@ -0,0 +1,111 @@ +/** + * \file persistentCounter.c + * \author Daniel Otte + * \brief a persistent 24-bit counter in EEPROM for ATmega µC + * + */ + +#include +#include /* cli() & sei() */ +#include +#include "../config.h" + +#ifdef ERROR_HANDLING + #include "error-handling.h" + #define PERSISTENT_COUNTER_OVERFLOW (void*)0, 2,4,1 + #define PERSISTENT_COUNTER_WRITER_ERROR (void*)0, 2,4,2 +#endif + +#define RING_SIZE 168 + +uint8_t ring_idx = 0xff; + +uint16_t EEMEM B08_23; +uint8_t EEMEM B0_7[RING_SIZE]; + +#ifdef INIT_EEPROM +void init_buffer(void){ + uint8_t i; + eeprom_busy_wait(); + eeprom_write_word(&B08_23, 0x0000); + for(i=0; i>16)&0xff); + } + eeprom_busy_wait(); + eeprom_write_byte(&(((uint8_t*)&B08_23)[0]),((u+1)>>8)&0xff); + } + /* set least significant byte (in ringbuffer) */ + ring_idx = (ring_idx+1)%RING_SIZE; + eeprom_busy_wait(); + eeprom_write_byte(&(B0_7[ring_idx]),(u+1)&0xff); + eeprom_busy_wait(); + + if(u+1 != percnt_get()){ + #ifdef ERROR_HANDLING + error(PERSISTENT_COUNTER_WRITER_ERROR); + #endif + } + + sei(); +} + diff --git a/random/persistentCounter.h b/random/persistentCounter.h new file mode 100644 index 0000000..386fcd6 --- /dev/null +++ b/random/persistentCounter.h @@ -0,0 +1,23 @@ +/** + * \file persistentCounter.h + * \author Daniel Otte + * \brief a persistent 24-bit vounter in EEPROM for ATmega µC + * + * + */ + +#ifndef PERSISTENTCOUNTER_H_ +#define PERSISTENTCOUNTER_H_ + + +#include + +#define PERSISTENT_COUNTER_BITS 24 + +void percnt_init(void); +uint32_t percnt_get(void); +void percnt_inc(void); + + + +#endif /*PERSISTENTCOUNTER_H_*/ diff --git a/random/prng.c b/random/prng.c new file mode 100644 index 0000000..bca238d --- /dev/null +++ b/random/prng.c @@ -0,0 +1,49 @@ +/** + * \author Daniel Otte + * \date 2008-08-24 + * \license GPLv3 or later + * \brief random number generator based on noekeon running in CFB-mode + * + */ + +#include "noekeon.h" +#include "memxor.h" +#include +#include + +uint8_t random_state[16]; +uint8_t random_key[16]; + + +uint8_t random8(void){ + static uint8_t sr[16]; + static uint8_t i=0; + + if(i==0){ + noekeon_enc(random_state, random_key); + memcpy(sr, random_state, 16); + i=15; + return sr[15]; + } + --i; + return sr[i]; +} + +void random_block(void* dest){ + noekeon_enc(random_state, random_key); + memcpy(dest, random_state, 16); +} + +void srandom32(uint32_t seed){ + memcpy(random_key, &seed, 4); +} + +void random_seed(const void* buffer){ + memcpy(random_key, buffer, 16); +} + +void random_add(const void* buffer){ + memxor(random_key, buffer, 16); +} + + diff --git a/random/prng.h b/random/prng.h new file mode 100644 index 0000000..775eaac --- /dev/null +++ b/random/prng.h @@ -0,0 +1,22 @@ +/** + * \author Daniel Otte + * \date 2008-08-24 + * \license GPLv3 or later + * \brief random number generator based on noekeon running in CFB-mode + * + */ + +#ifndef PRNG_H_ +#define PRNG_H_ + +#include + +uint8_t random8(void); +void random_block(void* dest); +void srandom32(uint32_t seed); +void random_seed(const void* buffer); +void random_add(const void* buffer); + +#endif /* PRNG_H_*/ + + diff --git a/rules.mk b/rules.mk new file mode 100644 index 0000000..8062e1c --- /dev/null +++ b/rules.mk @@ -0,0 +1,21 @@ + +OBJECTS += $(patsubst %.c,%.o,${SRC}) +OBJECTS += $(patsubst %.S,%.o,${ASRC}) + +%.a: $(OBJECTS) + $(RM) $@ + $(AR) qcv $@ $^ +# $(STRIP) --strip-unneeded $@ + +%.o: %.S + $(CC) -o $@ $(CPPFLAGS) $(ASFLAGS) -c $< + +clean-common: + $(RM) $(TARGET) *.[odasE] *.d.new *~ + +clean: clean-common + +all: + make -C $(TOPDIR) all + +include $(TOPDIR)/depend.mk diff --git a/scripts/Menuconfig b/scripts/Menuconfig new file mode 100644 index 0000000..db37e8f --- /dev/null +++ b/scripts/Menuconfig @@ -0,0 +1,1697 @@ +#! /bin/sh +# +# This script is used to configure the borgware. +# +# It was derived from the Ethersex project. +# +# It was once derived from the Linux kernel's Menuconfig script. +# +# It uses a very modified/mutilated version of the "dialog" utility +# written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible +# for this script or the version of dialog used by this script. +# Please do not contact him with questions. The official version of +# dialog is available at sunsite.unc.edu or a sunsite mirror. +# + +# +# Change this to TRUE if you prefer all kernel options listed +# in a single menu rather than the standard menu hierarchy. +# +single_menu_mode= + +# +# Make sure we're really running bash. +# +[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; } + +# +# Cache function definitions, turn off posix compliance +# +set -h +o posix + + + +# Given a configuration variable, set the global variable $x to its value, +# and the global variable $info to the string " (NEW)" if this is a new +# variable. +# +# This function looks for: (1) the current value, or (2) the default value +# from the arch-dependent defconfig file, or (3) a default passed by the caller. + +function set_x_info () { + eval x=\$$1 + if [ -z "$x" ]; then + eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig` + eval x=\${$1:-\"$2\"} + eval $1=$x + eval INFO_$1="' (NEW)'" + fi + eval info=\"\$INFO_$1\" +} + +# +# Load the functions used by the config.in files. +# +# I do this because these functions must be redefined depending +# on whether they are being called for interactive use or for +# saving a configuration to a file. +# +# Thank the heavens bash supports nesting function definitions. +# +load_functions () { + +# +# Additional comments +# +function comment () { + comment_ctr=$[ comment_ctr + 1 ] + echo -ne "': $comment_ctr' '--- $1' " >>MCmenu +} + +function impossible () { + comment_ctr=$[ comment_ctr + 1 ] + echo -ne "': $comment_ctr' '[-] $1' " >>MCmenu +} + +# +# Define a boolean to a specific value. +# +function define_bool () { + eval $1=$2 +} + +function define_tristate () { + eval $1=$2 +} + +function define_hex () { + eval $1=$2 +} + +function define_int () { + eval $1=$2 +} + +function define_string () { + eval $1=\"$2\" +} + +# +# Create a boolean (Yes/No) function for our current menu +# which calls our local bool function. +# +function bool () { + set_x_info "$2" "n" + + case $x in + y|m) flag="*" ;; + n) flag=" " ;; + esac + + echo -ne "'$2' '[$flag] $1$info' " >>MCmenu + + echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists +} + +# +# Create a tristate (Yes/No/Module) radiolist function +# which calls our local tristate function. +# +# Collapses to a boolean (Yes/No) if module support is disabled. +# +function tristate () { + if [ "$CONFIG_MODULES" != "y" ] + then + bool "$1" "$2" + else + set_x_info "$2" "n" + + case $x in + y) flag="*" ;; + m) flag="M" ;; + *) flag=" " ;; + esac + + echo -ne "'$2' '<$flag> $1$info' " >>MCmenu + + echo -e " + function $2 () { l_tristate '$2' \"\$1\" ;}" >>MCradiolists + fi +} + +# +# Create a tristate radiolist function which is dependent on +# another kernel configuration option. +# +# Quote from the original configure script: +# +# If the option we depend upon is a module, +# then the only allowable options are M or N. If Y, then +# this is a normal tristate. This is used in cases where modules +# are nested, and one module requires the presence of something +# else in the kernel. +# +function dep_tristate () { + ques="$1" + var="$2" + dep=y + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y ]; then + shift + elif [ "$1" = m ]; then + dep=m + shift + else + dep=n + shift $# + fi + done + if [ "$dep" = y ]; then + tristate "$ques" "$var" + elif [ "$dep" = m ]; then + mod_bool "$ques" "$var" + else + define_tristate "$var" n + fi +} + +# +# Same as above, but now only Y and N are allowed as dependency +# (i.e. third and next arguments). +# +function dep_bool () { + ques="$1" + var="$2" + dep="$3" + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y ]; then + shift + else + dep=n + shift $# + fi + done + if [ "$dep" = y ]; then + bool "$ques" "$var" + else + impossible "$ques" + define_bool "$var" n + fi +} + +function dep_bool_menu () { + ques="$1"; shift + echo "haveMCmenu$1=y" >> MCradiolists + dep_bool "$ques --->" $* +} + +function dep_mbool () { + ques="$1" + var="$2" + dep=y + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y -o "$1" = m ]; then + shift + else + dep=n + shift $# + fi + done + if [ "$dep" = y ]; then + bool "$ques" "$var" + else + define_bool "$var" n + fi +} + +# +# Add a menu item which will call our local int function. +# +function int () { + set_x_info "$2" "$3" + + echo -ne "'$2' '($x) $1$info' " >>MCmenu + + echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local hex function. +# +function hex () { + set_x_info "$2" "$3" + x=${x##*[x,X]} + + echo -ne "'$2' '($x) $1$info' " >>MCmenu + + echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local string function. +# +function string () { + set_x_info "$2" "$3" + + echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu + + echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local editor function. +# +function editor () { + + echo -ne "'$2' ' Edit "$1"$info' " >>MCmenu + + echo -e "function $2 () { l_editor '$1';}" >>MCradiolists +} + +# +# Add a menu item which will call our local mac function. +# +function mac () { + set_x_info "$2" "$3" + + echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu + + echo -e "function $2 () { l_mac '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local ipv4 function. +# +function ipv4 () { + set_x_info "$2" "$3" + + echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu + + echo -e "function $2 () { l_ipv4 '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local ipv6 function. +# +function ipv6 () { + set_x_info "$2" "$3" + + echo -ne "'$2' ' $1: \"$x\"$info' " >>MCmenu + + echo -e "function $2 () { l_ipv6 '$1' '$2' '$3' '$x' ;}" >>MCradiolists +} + +# +# Add a menu item which will call our local One-of-Many choice list. +# +function choice () { + # + # Need to remember params cause they're gonna get reset. + # + title=$1 + choices=$2 + default=$3 + define_symbol=$4 + current= + + # + # Find out if one of the choices is already set. + # If it's not then make it the default. + # + set -- $choices + firstchoice=$2 + + + if [ -n "$define_symbol" ] + then + firstchoice=$define_symbol + while [ -n "$2" ] + do + if eval [ \"_\$$define_symbol\" == \"_$2\" ] + then + current=$1 + break + fi + shift ; shift + done + else + while [ -n "$2" ] + do + if eval [ \"_\$$2\" = \"_y\" ] + then + current=$1 + break + fi + shift ; shift + done + fi + + : ${current:=$default} + + echo -ne "'$firstchoice' '($current) $title' " >>MCmenu + + echo -e " + function $firstchoice () \ + { l_choice '$title' \"$choices\" \"$current\" \"$define_symbol\" ;}" >>MCradiolists +} + +} # END load_functions() + + + + + +# +# Extract available help for an option from Configure.help +# and send it to standard output. +# +# Most of this function was borrowed from the original kernel +# Configure script. +# +function extract_help () { + if [ -f Documentation/Configure.help ] + then + #first escape regexp special characters in the argument: + var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g') + #now pick out the right help text: + text=$(sed -n "/^$var[ ]*\$/,\${ + /^$var[ ]*\$/c\\ +${var}:\\ + + /^#/b + /^[^ ]/q + s/^ // + /]*\\)>/s//\\1/g + p + }" Documentation/Configure.help) + + if [ -z "$text" ] + then + echo "There is no help available for this option." + return 1 + else + echo "$text" + fi + else + echo "There is no help available for this option." + return 1 + fi +} + +# +# Activate a help dialog. +# +function help () { + if extract_help $1 >help.out + then + $DIALOG --backtitle "$backtitle" --title "$2"\ + --textbox help.out $ROWS $COLS + else + $DIALOG --backtitle "$backtitle" \ + --textbox help.out $ROWS $COLS + fi + rm -f help.out +} + +# +# Show the README file. +# +function show_readme () { + $DIALOG --backtitle "$backtitle" \ + --textbox scripts/README.Menuconfig $ROWS $COLS +} + +# +# Begin building the dialog menu command and Initialize the +# Radiolist function file. +# +function menu_name () { + echo -ne "$DIALOG --title '$1'\ + --backtitle '$backtitle' \ + --menu '$menu_instructions' \ + $ROWS $COLS $((ROWS-10)) \ + '$default' " >MCmenu + >MCradiolists +} + +# +# Add a submenu option to the menu currently under construction. +# +function submenu () { + echo -ne "'activate_menu $2' '$1 --->' " >>MCmenu +} + +# +# Handle a boolean (Yes/No) option. +# +function l_bool () { + if [ -n "$2" ] + then + case "$2" in + y|m) eval $1=y ;; + c) eval x=\$$1 + case $x in + y) eval $1=n ;; + n) eval $1=y ;; + *) eval $1=y ;; + esac ;; + *) eval $1=n ;; + esac + else + get_cmd='echo $haveMCmenu'"$1" + value="`eval $get_cmd`" + + if [ -n "$value" ]; then + eval activate_menu MCmenu$1 + else + echo -ne "\007" + fi + fi +} + +# +# Same as bool() except options are (Module/No) +# +function mod_bool () { + if [ "$CONFIG_MODULES" != "y" ]; then + define_bool "$2" "n" + else + set_x_info "$2" "n" + + case $x in + y|m) flag='M' ;; + *) flag=' ' ;; + esac + + echo -ne "'$2' '<$flag> $1$info' " >>MCmenu + + echo -e "function $2 () { l_mod_bool '$2' \"\$1\" ;}" >>MCradiolists + fi +} + +# +# Same as l_bool() except options are (Module/No) +# +function l_mod_bool() { + if [ -n "$2" ] + then + case "$2" in + y) echo -en "\007" + ${DIALOG} --backtitle "$backtitle" \ + --infobox "\ +This feature depends on another which has been configured as a module. \ +As a result, this feature will be built as a module." 4 70 + sleep 5 + eval $1=m ;; + m) eval $1=m ;; + c) eval x=\$$1 + case $x in + m) eval $1=n ;; + n) eval $1=m ;; + *) eval $1=m ;; + esac ;; + *) eval $1=n ;; + esac + else + echo -ne "\007" + fi +} + +# +# Handle a tristate (Yes/No/Module) option. +# +function l_tristate () { + if [ -n "$2" ] + then + eval x=\$$1 + + case "$2" in + y) eval $1=y ;; + m) eval $1=m ;; + c) eval x=\$$1 + case $x in + y) eval $1=n ;; + n) eval $1=m ;; + m) eval $1=y ;; + *) eval $1=y ;; + esac ;; + *) eval $1=n ;; + esac + else + echo -ne "\007" + fi +} + +# +# Create a dialog for entering an integer into a kernel option. +# +function l_int () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_int" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`cat MCdialog.out`" + answer="${answer:-$3}" + + # Semantics of + and ? in GNU expr changed, so + # we avoid them: + if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null + then + eval $2=\"$answer\" + else + eval $2=\"$3\" + echo -en "\007" + ${DIALOG} --backtitle "$backtitle" \ + --infobox "You have made an invalid entry." 3 43 + sleep 2 + fi + + break + fi + + help "$2" "$1" + done +} + +# +# Create a dialog for entering a hexadecimal into a kernel option. +# +function l_hex () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_hex" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`cat MCdialog.out`" + answer="${answer:-$3}" + answer="${answer##*[x,X]}" + + if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null + then + eval $2=\"$answer\" + else + eval $2=\"$3\" + echo -en "\007" + ${DIALOG} --backtitle "$backtitle" \ + --infobox "You have made an invalid entry." 3 43 + sleep 2 + fi + + break + fi + + help "$2" "$1" + done +} + +# +# Create a dialog for entering a string into a kernel option. +# +function l_string () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_string" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`cat MCdialog.out`" + answer="${answer:-$3}" + + # + # Someone may add a nice check for the entered + # string here... + # + eval $2=\"$answer\" + + break + fi + + help "$2" "$1" + done +} + +# +# Use an editor to edit a certain file +# + +function l_editor() { + if [ -n "$EDITOR" ]; then + $EDITOR $1 + elif [ -n "`which nano`" ]; then + nano $1 + fi +} + +# +# Create a dialog for entering a MAC address +# +function l_mac () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_ipv4" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`cat MCdialog.out`" + answer="${answer:-$3}" + + if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]$' >/dev/null + then + eval $2=\"$answer\" + else + eval $2=\"$3\" + echo -en "\007" + $DIALOG --backtitle "$backtitle" \ + --infobox "You have made an invalid entry." 3 43 + sleep 2 + fi + + break + fi + + help "$2" "$1" + done +} + + +# +# Create a dialog for entering an IPv4 address +# +function l_ipv4 () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_ipv4" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`cat MCdialog.out`" + answer="${answer:-$3}" + + if expr "$answer" : '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' >/dev/null + then + eval $2=\"$answer\" + else + eval $2=\"$3\" + echo -en "\007" + $DIALOG --backtitle "$backtitle" \ + --infobox "You have made an invalid entry." 3 43 + sleep 2 + fi + + break + fi + + help "$2" "$1" + done +} + + +# +# Create a dialog for entering an IPv6 address +# +function l_ipv6 () { + while true + do + if $DIALOG --title "$1" \ + --backtitle "$backtitle" \ + --inputbox "$inputbox_instructions_ipv6" \ + 10 75 "$4" 2>MCdialog.out + then + answer="`scripts/ipv6-expand "$(cat MCdialog.out)"`" + answer="${answer:-$3}" + + if scripts/ipv6-check "$answer" + then + eval $2=\"$answer\" + else + eval $2=\"$3\" + echo -en "\007" + $DIALOG --backtitle "$backtitle" \ + --infobox "You have made an invalid entry." 3 43 + sleep 2 + fi + + break + fi + + help "$2" "$1" + done +} + + +# +# Handle a one-of-many choice list. +# +function l_choice () { + # + # Need to remember params cause they're gonna get reset. + # + title="$1" + choices="$2" + current="$3" + define_symbol="$4" + chosen= + + # + # Scan current value of choices and set radiolist switches. + # + list= + set -- $choices + firstchoice=$2 + while [ -n "$2" ] + do + case "$1" in + "$current"*) if [ -z "$chosen" ]; then + list="$list $2 $1 ON " + chosen=1 + else + list="$list $2 $1 OFF " + fi ;; + *) list="$list $2 $1 OFF " ;; + esac + + shift ; shift + done + + while true + do + if $DIALOG --title "$title" \ + --backtitle "$backtitle" \ + --radiolist "$radiolist_instructions" \ + 15 70 6 $list 2>MCdialog.out + then + choice=`cat MCdialog.out` + break + fi + + help "$firstchoice" "$title" + done + + # + # Now set the boolean value of each option based on + # the selection made from the radiolist. + # + set -- $choices + while [ -n "$2" ] + do + if [ "$2" = "$choice" ] + then + if [ \! -z "$define_symbol" ]; then + eval $define_symbol="$2" + else + eval $2=\"y\" + fi + else + if [ -z "$define_symbol" ]; then + eval $2=\"n\" + fi + fi + + shift ; shift + done +} + +# +# Call awk, and watch for error codes, etc. +# +function callawk () { +awk "$1" || { echo "Awk died with error code $?. Giving up."; exit 1; } +} + +# +# A faster awk based recursive parser. (I hope) +# +function parser1 () { +callawk ' +BEGIN { + menu_no = 0 + comment_is_option = 0 + parser("'$CONFIG_IN'","MCmenu0") +} + +function parser(ifile,menu) { + + while ((getline 0) { + if ($1 == "mainmenu_option") { + comment_is_option = "1" + } + else if ($1 == "dep_bool_menu") { + print >>menu + + split ($0,ll,"\\\""); + split (ll[3],mm," "); + + newmenu = sprintf("MCmenu%s", mm[1]); + printf( "function MCmenu%s () {\n"\ + "default=$1\n"\ + "menu_name \"%s\"\n",\ + mm[1], ll[2]) > newmenu + + parser(ifile, newmenu) + } + else if ($1 == "comment" && comment_is_option == "1") { + comment_is_option= "0" + sub($1,"",$0) + ++menu_no + + printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu + + newmenu = sprintf("MCmenu%d", menu_no); + printf( "function MCmenu%s () {\n"\ + "default=$1\n"\ + "menu_name %s\n",\ + menu_no, $0) >newmenu + + parser(ifile, newmenu) + } + else if ($0 ~ /^#|\$MAKE|mainmenu_name/) { + printf("") >>menu + } + else if ($1 ~ "endmenu") { + printf("}\n") >>menu + return + } + else if ($1 == "source") { + parser($2,menu) + } + else { + print >>menu + } + } +}' +} + +# +# Secondary parser for single menu mode. +# +function parser2 () { +callawk ' +BEGIN { + parser("'$CONFIG_IN'","MCmenu0") +} + +function parser(ifile,menu) { + + while ((getline 0) { + if ($0 ~ /^#|$MAKE|mainmenu_name/) { + printf("") >>menu + } + else if ($1 ~ /mainmenu_option|endmenu/) { + printf("") >>menu + } + else if ($1 == "source") { + parser($2,menu) + } + else { + print >>menu + } + } +}' +} + +# +# Parse all the config.in files into mini scripts. +# +function parse_config_files () { + rm -f MCmenu* + + echo "function MCmenu0 () {" >MCmenu0 + echo 'default=$1' >>MCmenu0 + echo "menu_name 'Main Menu'" >>MCmenu0 + + echo "g_dflt_config" >>MCmenu0 + + if [ "_$single_menu_mode" = "_TRUE" ] + then + parser2 + else + parser1 + fi + + echo "comment ''" >>MCmenu0 + echo "g_alt_config" >>MCmenu0 + echo "s_alt_config" >>MCmenu0 + + echo "}" >>MCmenu0 + + # + # These mini scripts must be sourced into the current + # environment in order for all of this to work. Leaving + # them on the disk as executables screws up the recursion + # in activate_menu(), among other things. Once they are + # sourced we can discard them. + # + for i in MCmenu* + do + echo -n "." + source ./$i + done + #rm -f MCmenu* +} + +# +# This is the menu tree's bootstrap. +# +# Executes the parsed menus on demand and creates a set of functions, +# one per configuration option. These functions will in turn execute +# dialog commands or recursively call other menus. +# +function activate_menu () { + rm -f lxdialog.scrltmp + while true + do + comment_ctr=0 #So comment lines get unique tags + + $1 "$default" 2> MCerror #Create the lxdialog menu & functions + + if [ "$?" != "0" ] + then + clear + cat < /' MCerror + cat <MCdialog.out #Activate the lxdialog menu + ret=$? + + read selection "*|*"alt_config"*) + show_readme ;; + *) + eval help $selection ;; + esac + ;; + 255|1) + break + ;; + 139) + stty sane + clear + cat <' "\ + >>MCmenu +} + +get_dflt_config () { + config_files=`ls ./profiles/` + choices="" + for file in $config_files + do + choices="$choices $file $file 0" + done + + while true + do + $DIALOG --title "Load Default Configuration" \ + --backtitle "$backtitle" \ + --radiolist "\ +Select the default profile you wish to load. \ + to abort." \ + 15 70 7 \ + $choices \ + 2>MCdialog.out + + exit_status=$? + + if [ $exit_status -eq 0 ]; then + choice=`cat MCdialog.out` + echo $choice + load_config_file "./profiles/$choice" + break + elif [ $exit_status -eq 255 ]; then + break # ESC-ESC ... + elif [ $exit_status -eq 1 ]; then + help "$firstchoice" "$title" + fi + done + + rm -f help.out MCdialog.out +} + +# +# Create a menu item to load an alternate configuration file. +# +g_alt_config () { + echo -n "get_alt_config 'Load an Alternate Configuration File' "\ + >>MCmenu +} + +# +# Get alternate config file name and load the +# configuration from it. +# +get_alt_config () { + set -f ## Switch file expansion OFF + + while true + do + ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}" + + $DIALOG --backtitle "$backtitle" \ + --inputbox "\ +Enter the name of the configuration file you wish to load. \ +Accept the name shown to restore the configuration you \ +last retrieved. Leave blank to abort."\ + 11 55 "$ALT_CONFIG" 2>MCdialog.out + + if [ "$?" = "0" ] + then + ALT_CONFIG=`cat MCdialog.out` + + [ "_" = "_$ALT_CONFIG" ] && break + + if eval [ -r \"$ALT_CONFIG\" ] + then + eval load_config_file \"$ALT_CONFIG\" + break + else + echo -ne "\007" + $DIALOG --backtitle "$backtitle" \ + --infobox "File does not exist!" 3 38 + sleep 2 + fi + else + cat <help.out + +For various reasons, one may wish to keep several different kernel +configurations available on a single machine. + +If you have saved a previous configuration in a file other than the +kernel's default, entering the name of the file here will allow you +to modify that configuration. + +If you are uncertain, then you have probably never used alternate +configuration files. You should therefor leave this blank to abort. + +EOM + $DIALOG --backtitle "$backtitle"\ + --title "Load Alternate Configuration"\ + --textbox help.out $ROWS $COLS + fi + done + + set +f ## Switch file expansion ON + rm -f help.out MCdialog.out +} + +# +# Create a menu item to store an alternate config file. +# +s_alt_config () { + echo -n "save_alt_config 'Save Configuration to an Alternate File' "\ + >>MCmenu +} + +# +# Get an alternate config file name and save the current +# configuration to it. +# +save_alt_config () { + set -f ## Switch file expansion OFF + + while true + do + $DIALOG --backtitle "$backtitle" \ + --inputbox "\ +Enter a filename to which this configuration should be saved \ +as an alternate. Leave blank to abort."\ + 10 55 "$ALT_CONFIG" 2>MCdialog.out + + if [ "$?" = "0" ] + then + ALT_CONFIG=`cat MCdialog.out` + + [ "_" = "_$ALT_CONFIG" ] && break + + if eval touch $ALT_CONFIG 2>/dev/null + then + eval save_configuration $ALT_CONFIG + load_functions ## RELOAD + break + else + echo -ne "\007" + $DIALOG --backtitle "$backtitle" \ + --infobox "Can't create file! Probably a nonexistent directory." 3 60 + sleep 2 + fi + else + cat <help.out + +For various reasons, one may wish to keep different kernel +configurations available on a single machine. + +Entering a file name here will allow you to later retrieve, modify +and use the current configuration as an alternate to whatever +configuration options you have selected at that time. + +If you are uncertain what all this means then you should probably +leave this blank. +EOM + $DIALOG --backtitle "$backtitle"\ + --title "Save Alternate Configuration"\ + --textbox help.out $ROWS $COLS + fi + done + + set +f ## Switch file expansion ON + rm -f help.out MCdialog.out +} + +# +# Load config options from a file. +# Converts all "# OPTION is not set" lines to "OPTION=n" lines +# +function load_config_file () { + awk ' + /# .* is not set.*/ { printf("%s=n\n", $2) } + ! /# .* is not set.*/ { print } + ' $1 >.tmpconfig + + source ./.tmpconfig + rm -f .tmpconfig +} + +# +# Just what it says. +# +save_configuration () { + echo + echo -n "Saving your Borg configuration." + + # + # Now, let's redefine the configuration functions for final + # output to the config files. + # + # Nested function definitions, YIPEE! + # + function bool () { + set_x_info "$2" "n" + eval define_bool \"$2\" \"$x\" + } + + function tristate () { + set_x_info "$2" "n" + eval define_tristate \"$2\" \"$x\" + } + + function dep_tristate () { + set_x_info "$2" "n" + var="$2" + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y ]; then + shift + elif [ "$1" = m -a "$x" != n ]; then + x=m; shift + else + x=n; shift $# + fi + done + define_tristate "$var" "$x" + } + + function dep_bool () { + set_x_info "$2" "n" + var="$2" + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y ]; then + shift + else + x=n; shift $# + fi + done + define_bool "$var" "$x" + } + + function dep_bool_menu () { + ques="$1"; shift + dep_bool "" $* + } + + function dep_mbool () { + set_x_info "$2" "n" + var="$2" + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y -o "$1" = m ]; then + shift + else + x=n; shift $# + fi + done + define_bool "$var" "$x" + } + + function int () { + set_x_info "$2" "$3" + echo "$2=$x" >>$CONFIG + echo "#define $2 ($x)" >>$CONFIG_H + } + + function hex () { + set_x_info "$2" "$3" + echo "$2=$x" >>$CONFIG + echo "#define $2 \"$(echo "$x" | sed -e 's/\(..\)/\\x\1/g')\"" >>$CONFIG_H + } + + function string () { + set_x_info "$2" "$3" + echo "$2=\"$x\"" >>$CONFIG + echo "#define $2 \"$x\"" >>$CONFIG_H + } + + function mac () { + set_x_info "$2" "$3" + echo "$2=\"$x\"" >>$CONFIG + echo "#define $2 " \ + "\"\\x$(echo "$x" | sed -e 's;:;\\x;g')\"" >> $CONFIG_H + } + + function ipv4 () { + set_x_info "$2" "$3" + echo "$2=\"$x\"" >>$CONFIG + echo "#define $2 uip_ipaddr(ip," \ + $(echo "$x" | sed -e 's;\.;,;g') ")" >> $CONFIG_H + } + + function ipv6 () { + set_x_info "$2" "$3" + echo "$2=\"$x\"" >>$CONFIG + echo "#define $2 uip_ip6addr(ip," \ + "0x"$(echo "$x" | sed -e 's;:;,0x;g') ")" >> $CONFIG_H + } + + function define_hex () { + eval $1=\"$2\" + echo "$1=$2" >>$CONFIG + echo "#define $1 0x${2##*[x,X]}" >>$CONFIG_H + } + + function define_int () { + eval $1=\"$2\" + echo "$1=$2" >>$CONFIG + echo "#define $1 ($2)" >>$CONFIG_H + } + + function define_symbol () { + eval $1=\"$2\" + echo "$1=$2" >>$CONFIG + echo "#define $1 $2" >>$CONFIG_H + } + + function define_string () { + eval $1=\"$2\" + echo "$1=\"$2\"" >>$CONFIG + echo "#define $1 \"$2\"" >>$CONFIG_H + } + + function define_bool () { + define_tristate "$1" "$2" + } + + function define_tristate () { + eval $1=\"$2\" + + case "$2" in + y) + echo "$1=y" >>$CONFIG + echo "#define $1 1" >>$CONFIG_H + ;; + + m) + if [ "$CONFIG_MODULES" = "y" ] + then + echo "$1=m" >>$CONFIG + echo "#undef $1" >>$CONFIG_H + echo "#define $1_MODULE 1" >>$CONFIG_H + else + echo "$1=y" >>$CONFIG + echo "#define $1 1" >>$CONFIG_H + fi + ;; + + n) + echo "# $1 is not set" >>$CONFIG + echo "#undef $1" >>$CONFIG_H + ;; + esac + } + + function choice () { + # + # Find the first choice that's already set to 'y' + # + choices="$2" + default="$3" + define_symbol="$4" + current= + chosen= + + set -- $choices + if [ -n "$define_symbol" ] + then + while [ -n "$2" ] + do + if eval [ \"_\$$define_symbol\" == \"_$2\" ] + then + current=$1 + break + fi + shift ; shift + done + else + while [ -n "$2" ] + do + if eval [ \"_\$$2\" = \"_y\" ] + then + current=$1 + break + fi + shift ; shift + done + fi + + # + # Use the default if none were set. + # + : ${current:=$default} + + # + # Output all choices (to be compatible with other configs). + # + set -- $choices + while [ -n "$2" ] + do + case "$1" in + "$current"*) if [ -z "$chosen" ]; then + if [ \! -z "$define_symbol" ]; then + echo "$define_symbol=$2" >>$CONFIG + echo "#define $define_symbol $2" >>$CONFIG_H + else + define_bool "$2" "y" + fi + + chosen=1 + else + if [ -z "$define_symbol" ]; then + define_bool "$2" "n" + fi + fi ;; + *) if [ -z "$define_symbol" ]; then + define_bool "$2" "n" + fi ;; + esac + shift ; shift + done + } + + function mainmenu_name () { + : + } + + function mainmenu_option () { + comment_is_option=TRUE + } + + function endmenu () { + : + } + + function comment () { + if [ "$comment_is_option" ] + then + comment_is_option= + echo >>$CONFIG + echo "#" >>$CONFIG + echo "# $1" >>$CONFIG + echo "#" >>$CONFIG + + echo >>$CONFIG_H + echo "/*" >>$CONFIG_H + echo " * $1" >>$CONFIG_H + echo " */" >>$CONFIG_H + fi + } + + echo -n "." + + DEF_CONFIG="${1:-.config}" + DEF_CONFIG_H="autoconf.h" + + CONFIG=.tmpconfig + CONFIG_H=.tmpconfig.h + + echo "#" >$CONFIG + echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG + echo "#" >>$CONFIG + + echo "/*" >$CONFIG_H + echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H + echo " */" >>$CONFIG_H + echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H + + echo -n "." + if . $CONFIG_IN >>.menuconfig.log 2>&1 + then + if [ "$DEF_CONFIG" = ".config" ] + then + mv $CONFIG_H $DEF_CONFIG_H + fi + + if [ -f "$DEF_CONFIG" ] + then + rm -f ${DEF_CONFIG}.old + mv $DEF_CONFIG ${DEF_CONFIG}.old + fi + + mv $CONFIG $DEF_CONFIG + + return 0 + else + return 1 + fi +} + +# +# Remove temporary files +# +cleanup () { + cleanup1 + cleanup2 +} + +cleanup1 () { + rm -f MCmenu* MCradiolists MCdialog.out help.out +} + +cleanup2 () { + rm -f .tmpconfig .tmpconfig.h +} + +set_geometry () { + # Some distributions export these with incorrect values + # which can really screw up some ncurses programs. + LINES= COLUMNS= + + ROWS=${1:-24} COLS=${2:-80} + + # Just in case the nasty rlogin bug returns. + # + [ $ROWS = 0 ] && ROWS=24 + [ $COLS = 0 ] && COLS=80 + + if [ $ROWS -lt 19 -o $COLS -lt 80 ] + then + echo -e "\n\007Your display is too small to run Menuconfig!" + echo "It must be at least 19 lines by 80 columns." + exit 1 + fi + + ROWS=$((ROWS-4)) COLS=$((COLS-5)) +} + + +set_geometry `stty size 2>/dev/null` + +menu_instructions="\ +Arrow keys navigate the menu. \ + selects submenus --->. \ +Highlighted letters are hotkeys. \ +Pressing includes, excludes. to exit, for Help. \ +Legend: [*] enabled [ ] disabled [-] not available" + +radiolist_instructions="\ +Use the arrow keys to navigate this window or \ +press the hotkey of the item you wish to select \ +followed by the . +Press for additional information about this option." + +inputbox_instructions_int="\ +Please enter a decimal value. \ +Fractions will not be accepted. \ +Use the key to move from the input field to the buttons below it." + +inputbox_instructions_hex="\ +Please enter a hexadecimal string. \ +Use the key to move from the input field to the buttons below it." + +inputbox_instructions_string="\ +Please enter a string value. \ +Use the key to move from the input field to the buttons below it." + +DIALOG="./scripts/lxdialog/lxdialog" + +backtitle="Borg Configuration" + +trap "cleanup ; exit 1" 1 2 15 + + +# +# Locate default files. +# +CONFIG_IN=./config.in +if [ "$1" != "" ] ; then + CONFIG_IN=$1 +fi + +DEFAULTS=scripts/profiles/defconfig +if [ -f .config ]; then + DEFAULTS=.config +fi + +if [ -f $DEFAULTS ] +then + echo "Using defaults found in" $DEFAULTS + load_config_file $DEFAULTS +else + echo "No defaults found" +fi + + +# Fresh new log. +>.menuconfig.log + +# Load the functions used by the config.in files. +echo -n "Preparing scripts: functions" +load_functions + +if [ ! -e $CONFIG_IN ] +then + echo "Your main config.in file ($CONFIG_IN) does not exist" + exit 1 +fi + +if [ ! -x $DIALOG ] +then + echo "Your lxdialog utility does not exist" + exit 1 +fi + +# +# Read config.in files and parse them into one shell function per menu. +# +echo -n ", parsing" +parse_config_files $CONFIG_IN + +echo "done." +# +# Start the ball rolling from the top. +# +activate_menu MCmenu0 + +# +# All done! +# +cleanup1 + +# +# Confirm and Save +# +if $DIALOG --backtitle "$backtitle" \ + --yesno "Do you wish to save your new Borg configuration?" 5 60 +then + save_configuration + echo + echo + echo "*** End of Borg configuration." + echo +else + echo + echo + echo Your Borg configuration changes were NOT saved. + echo +fi + +# Remove log if empty. +if [ ! -s .menuconfig.log ] ; then + rm -f .menuconfig.log +fi + +exit 0 diff --git a/scripts/lxdialog/BIG.FAT.WARNING b/scripts/lxdialog/BIG.FAT.WARNING new file mode 100644 index 0000000..a8999d8 --- /dev/null +++ b/scripts/lxdialog/BIG.FAT.WARNING @@ -0,0 +1,4 @@ +This is NOT the official version of dialog. This version has been +significantly modified from the original. It is for use by the Linux +kernel configuration script. Please do not bother Savio Lam with +questions about this program. diff --git a/scripts/lxdialog/Makefile b/scripts/lxdialog/Makefile new file mode 100644 index 0000000..ed8d17c --- /dev/null +++ b/scripts/lxdialog/Makefile @@ -0,0 +1,46 @@ +HOSTCFLAGS += -DLOCALE +LIBS = -lncurses + +ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h)) + HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="" +else +ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h)) + HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="" +else +ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h)) + HOSTCFLAGS += -DCURSES_LOC="" +else + HOSTCFLAGS += -DCURSES_LOC="" +endif +endif +endif + + +OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \ + util.o lxdialog.o msgbox.o + +%.o: %.c + $(HOSTCC) $(HOSTCFLAGS) -c -o $@ $< + +all: ncurses lxdialog + +lxdialog: $(OBJS) + $(HOSTCC) -o lxdialog $(OBJS) $(LIBS) + +ncurses: + @echo "main() {}" > lxtemp.c + @if $(HOSTCC) -lncurses lxtemp.c ; then \ + rm -f lxtemp.c a.out; \ + else \ + rm -f lxtemp.c; \ + echo -e "\007" ;\ + echo ">> Unable to find the Ncurses libraries." ;\ + echo ">>" ;\ + echo ">> You must have Ncurses installed in order" ;\ + echo ">> to use 'make menuconfig'" ;\ + echo ;\ + exit 1 ;\ + fi + +clean: + rm -f core *.o *~ lxdialog diff --git a/scripts/lxdialog/checklist.c b/scripts/lxdialog/checklist.c new file mode 100644 index 0000000..4f78688 --- /dev/null +++ b/scripts/lxdialog/checklist.c @@ -0,0 +1,369 @@ +/* + * checklist.c -- implements the checklist box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension + * Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static int list_width, check_x, item_x, checkflag; + +/* + * Print list item + */ +static void +print_item (WINDOW * win, const char *item, int status, + int choice, int selected) +{ + int i; + + /* Clear 'residue' of last item */ + wattrset (win, menubox_attr); + wmove (win, choice, 0); + for (i = 0; i < list_width; i++) + waddch (win, ' '); + + wmove (win, choice, check_x); + wattrset (win, selected ? check_selected_attr : check_attr); + if (checkflag == FLAG_CHECK) + wprintw (win, "[%c]", status ? 'X' : ' '); + else + wprintw (win, "(%c)", status ? 'X' : ' '); + + wattrset (win, selected ? tag_selected_attr : tag_attr); + mvwaddch(win, choice, item_x, item[0]); + wattrset (win, selected ? item_selected_attr : item_attr); + waddstr (win, (char *)item+1); + if (selected) { + wmove (win, choice, check_x+1); + wrefresh (win); + } +} + +/* + * Print the scroll indicators. + */ +static void +print_arrows (WINDOW * win, int choice, int item_no, int scroll, + int y, int x, int height) +{ + wmove(win, y, x); + + if (scroll > 0) { + wattrset (win, uarrow_attr); + waddch (win, ACS_UARROW); + waddstr (win, "(-)"); + } + else { + wattrset (win, menubox_attr); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + + if ((height < item_no) && (scroll + choice < item_no - 1)) { + wattrset (win, darrow_attr); + waddch (win, ACS_DARROW); + waddstr (win, "(+)"); + } + else { + wattrset (win, menubox_border_attr); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + } +} + +/* + * Display the termination buttons + */ +static void +print_buttons( WINDOW *dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button (dialog, "Select", y, x, selected == 0); + print_button (dialog, " Help ", y, x + 14, selected == 1); + + wmove(dialog, y, x+1 + 14*selected); + wrefresh (dialog); +} + +/* + * Display a dialog box with a list of options that can be turned on or off + * The `flag' parameter is used to select between radiolist and checklist. + */ +int +dialog_checklist (const char *title, const char *prompt, int height, int width, + int list_height, int item_no, const char * const * items, int flag) + +{ + int i, x, y, box_x, box_y; + int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status; + WINDOW *dialog, *list; + + checkflag = flag; + + /* Allocate space for storing item on/off status */ + if ((status = malloc (sizeof (int) * item_no)) == NULL) { + endwin (); + fprintf (stderr, + "\nCan't allocate memory in dialog_checklist().\n"); + exit (-1); + } + + /* Initializes status */ + for (i = 0; i < item_no; i++) { + status[i] = !strcasecmp (items[i * 3 + 2], "on"); + if (!choice && status[i]) + choice = i; + } + + max_choice = MIN (list_height, item_no); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset (dialog, border_attr); + mvwaddch (dialog, height-3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + waddch (dialog, ACS_RTEE); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + + wattrset (dialog, dialog_attr); + print_autowrap (dialog, prompt, width - 2, 1, 3); + + list_width = width - 6; + box_y = height - list_height - 5; + box_x = (width - list_width) / 2 - 1; + + /* create new window for the list */ + list = subwin (dialog, list_height, list_width, y+box_y+1, x+box_x+1); + + keypad (list, TRUE); + + /* draw a box around the list items */ + draw_box (dialog, box_y, box_x, list_height + 2, list_width + 2, + menubox_border_attr, menubox_attr); + + /* Find length of longest item in order to center checklist */ + check_x = 0; + for (i = 0; i < item_no; i++) + check_x = MAX (check_x, + strlen (items[i * 3 + 1]) + 4); + + check_x = (list_width - check_x) / 2; + item_x = check_x + 4; + + if (choice >= list_height) { + scroll = choice - list_height + 1; + choice -= scroll; + } + + /* Print the list */ + for (i = 0; i < max_choice; i++) { + print_item (list, items[(scroll+i) * 3 + 1], + status[i+scroll], i, i == choice); + } + + print_arrows(dialog, choice, item_no, scroll, + box_y, box_x + check_x + 5, list_height); + + print_buttons(dialog, height, width, 0); + + wnoutrefresh (list); + wnoutrefresh (dialog); + doupdate (); + + while (key != ESC) { + key = wgetch (dialog); + + for (i = 0; i < max_choice; i++) + if (toupper(key) == toupper(items[(scroll+i)*3+1][0])) + break; + + + if ( i < max_choice || key == KEY_UP || key == KEY_DOWN || + key == '+' || key == '-' ) { + if (key == KEY_UP || key == '-') { + if (!choice) { + if (!scroll) + continue; + /* Scroll list down */ + if (list_height > 1) { + /* De-highlight current first item */ + print_item (list, items[scroll * 3 + 1], + status[scroll], 0, FALSE); + scrollok (list, TRUE); + wscrl (list, -1); + scrollok (list, FALSE); + } + scroll--; + print_item (list, items[scroll * 3 + 1], + status[scroll], 0, TRUE); + wnoutrefresh (list); + + print_arrows(dialog, choice, item_no, scroll, + box_y, box_x + check_x + 5, list_height); + + wrefresh (dialog); + + continue; /* wait for another key press */ + } else + i = choice - 1; + } else if (key == KEY_DOWN || key == '+') { + if (choice == max_choice - 1) { + if (scroll + choice >= item_no - 1) + continue; + /* Scroll list up */ + if (list_height > 1) { + /* De-highlight current last item before scrolling up */ + print_item (list, items[(scroll + max_choice - 1) * 3 + 1], + status[scroll + max_choice - 1], + max_choice - 1, FALSE); + scrollok (list, TRUE); + scroll (list); + scrollok (list, FALSE); + } + scroll++; + print_item (list, items[(scroll + max_choice - 1) * 3 + 1], + status[scroll + max_choice - 1], + max_choice - 1, TRUE); + wnoutrefresh (list); + + print_arrows(dialog, choice, item_no, scroll, + box_y, box_x + check_x + 5, list_height); + + wrefresh (dialog); + + continue; /* wait for another key press */ + } else + i = choice + 1; + } + if (i != choice) { + /* De-highlight current item */ + print_item (list, items[(scroll + choice) * 3 + 1], + status[scroll + choice], choice, FALSE); + /* Highlight new item */ + choice = i; + print_item (list, items[(scroll + choice) * 3 + 1], + status[scroll + choice], choice, TRUE); + wnoutrefresh (list); + wrefresh (dialog); + } + continue; /* wait for another key press */ + } + switch (key) { + case 'H': + case 'h': + case '?': + delwin (dialog); + free (status); + return 1; + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh (dialog); + break; + case 'S': + case 's': + case ' ': + case '\n': + if (!button) { + if (flag == FLAG_CHECK) { + status[scroll + choice] = !status[scroll + choice]; + wmove (list, choice, check_x); + wattrset (list, check_selected_attr); + wprintw (list, "[%c]", status[scroll + choice] ? 'X' : ' '); + } else { + if (!status[scroll + choice]) { + for (i = 0; i < item_no; i++) + status[i] = 0; + status[scroll + choice] = 1; + for (i = 0; i < max_choice; i++) + print_item (list, items[(scroll + i) * 3 + 1], + status[scroll + i], i, i == choice); + } + } + wnoutrefresh (list); + wrefresh (dialog); + + for (i = 0; i < item_no; i++) { + if (status[i]) { + if (flag == FLAG_CHECK) { + fprintf (stderr, "\"%s\" ", items[i * 3]); + } else { + fprintf (stderr, "%s", items[i * 3]); + } + + } + } + } + delwin (dialog); + free (status); + return button; + case 'X': + case 'x': + key = ESC; + case ESC: + break; + } + + /* Now, update everything... */ + doupdate (); + } + + + delwin (dialog); + free (status); + return -1; /* ESC pressed */ +} diff --git a/scripts/lxdialog/colors.h b/scripts/lxdialog/colors.h new file mode 100644 index 0000000..d34dd37 --- /dev/null +++ b/scripts/lxdialog/colors.h @@ -0,0 +1,161 @@ +/* + * colors.h -- color attribute definitions + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * Default color definitions + * + * *_FG = foreground + * *_BG = background + * *_HL = highlight? + */ +#define SCREEN_FG COLOR_CYAN +#define SCREEN_BG COLOR_BLUE +#define SCREEN_HL TRUE + +#define SHADOW_FG COLOR_BLACK +#define SHADOW_BG COLOR_BLACK +#define SHADOW_HL TRUE + +#define DIALOG_FG COLOR_BLACK +#define DIALOG_BG COLOR_WHITE +#define DIALOG_HL FALSE + +#define TITLE_FG COLOR_YELLOW +#define TITLE_BG COLOR_WHITE +#define TITLE_HL TRUE + +#define BORDER_FG COLOR_WHITE +#define BORDER_BG COLOR_WHITE +#define BORDER_HL TRUE + +#define BUTTON_ACTIVE_FG COLOR_WHITE +#define BUTTON_ACTIVE_BG COLOR_BLUE +#define BUTTON_ACTIVE_HL TRUE + +#define BUTTON_INACTIVE_FG COLOR_BLACK +#define BUTTON_INACTIVE_BG COLOR_WHITE +#define BUTTON_INACTIVE_HL FALSE + +#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE +#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE +#define BUTTON_KEY_ACTIVE_HL TRUE + +#define BUTTON_KEY_INACTIVE_FG COLOR_RED +#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE +#define BUTTON_KEY_INACTIVE_HL FALSE + +#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW +#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE +#define BUTTON_LABEL_ACTIVE_HL TRUE + +#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK +#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE +#define BUTTON_LABEL_INACTIVE_HL TRUE + +#define INPUTBOX_FG COLOR_BLACK +#define INPUTBOX_BG COLOR_WHITE +#define INPUTBOX_HL FALSE + +#define INPUTBOX_BORDER_FG COLOR_BLACK +#define INPUTBOX_BORDER_BG COLOR_WHITE +#define INPUTBOX_BORDER_HL FALSE + +#define SEARCHBOX_FG COLOR_BLACK +#define SEARCHBOX_BG COLOR_WHITE +#define SEARCHBOX_HL FALSE + +#define SEARCHBOX_TITLE_FG COLOR_YELLOW +#define SEARCHBOX_TITLE_BG COLOR_WHITE +#define SEARCHBOX_TITLE_HL TRUE + +#define SEARCHBOX_BORDER_FG COLOR_WHITE +#define SEARCHBOX_BORDER_BG COLOR_WHITE +#define SEARCHBOX_BORDER_HL TRUE + +#define POSITION_INDICATOR_FG COLOR_YELLOW +#define POSITION_INDICATOR_BG COLOR_WHITE +#define POSITION_INDICATOR_HL TRUE + +#define MENUBOX_FG COLOR_BLACK +#define MENUBOX_BG COLOR_WHITE +#define MENUBOX_HL FALSE + +#define MENUBOX_BORDER_FG COLOR_WHITE +#define MENUBOX_BORDER_BG COLOR_WHITE +#define MENUBOX_BORDER_HL TRUE + +#define ITEM_FG COLOR_BLACK +#define ITEM_BG COLOR_WHITE +#define ITEM_HL FALSE + +#define ITEM_SELECTED_FG COLOR_WHITE +#define ITEM_SELECTED_BG COLOR_BLUE +#define ITEM_SELECTED_HL TRUE + +#define TAG_FG COLOR_YELLOW +#define TAG_BG COLOR_WHITE +#define TAG_HL TRUE + +#define TAG_SELECTED_FG COLOR_YELLOW +#define TAG_SELECTED_BG COLOR_BLUE +#define TAG_SELECTED_HL TRUE + +#define TAG_KEY_FG COLOR_YELLOW +#define TAG_KEY_BG COLOR_WHITE +#define TAG_KEY_HL TRUE + +#define TAG_KEY_SELECTED_FG COLOR_YELLOW +#define TAG_KEY_SELECTED_BG COLOR_BLUE +#define TAG_KEY_SELECTED_HL TRUE + +#define CHECK_FG COLOR_BLACK +#define CHECK_BG COLOR_WHITE +#define CHECK_HL FALSE + +#define CHECK_SELECTED_FG COLOR_WHITE +#define CHECK_SELECTED_BG COLOR_BLUE +#define CHECK_SELECTED_HL TRUE + +#define UARROW_FG COLOR_GREEN +#define UARROW_BG COLOR_WHITE +#define UARROW_HL TRUE + +#define DARROW_FG COLOR_GREEN +#define DARROW_BG COLOR_WHITE +#define DARROW_HL TRUE + +/* End of default color definitions */ + +#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y))) +#define COLOR_NAME_LEN 10 +#define COLOR_COUNT 8 + +/* + * Global variables + */ + +typedef struct { + char name[COLOR_NAME_LEN]; + int value; +} color_names_st; + +extern color_names_st color_names[]; +extern int color_table[][3]; diff --git a/scripts/lxdialog/dialog.h b/scripts/lxdialog/dialog.h new file mode 100644 index 0000000..0e30d00 --- /dev/null +++ b/scripts/lxdialog/dialog.h @@ -0,0 +1,184 @@ + +/* + * dialog.h -- common declarations for all dialog modules + * + * AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include CURSES_LOC + +/* + * Colors in ncurses 1.9.9e do not work properly since foreground and + * background colors are OR'd rather than separately masked. This version + * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible + * with standard curses. The simplest fix (to make this work with standard + * curses) uses the wbkgdset() function, not used in the original hack. + * Turn it off if we're building with 1.9.9e, since it just confuses things. + */ +#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE) +#define OLD_NCURSES 1 +#undef wbkgdset +#define wbkgdset(w,p) /*nothing*/ +#else +#define OLD_NCURSES 0 +#endif + +#define TR(params) _tracef params + +#define ESC 27 +#define TAB 9 +#define MAX_LEN 2048 +#define BUF_SIZE (10*1024) +#define MIN(x,y) (x < y ? x : y) +#define MAX(x,y) (x > y ? x : y) + + +#ifndef ACS_ULCORNER +#define ACS_ULCORNER '+' +#endif +#ifndef ACS_LLCORNER +#define ACS_LLCORNER '+' +#endif +#ifndef ACS_URCORNER +#define ACS_URCORNER '+' +#endif +#ifndef ACS_LRCORNER +#define ACS_LRCORNER '+' +#endif +#ifndef ACS_HLINE +#define ACS_HLINE '-' +#endif +#ifndef ACS_VLINE +#define ACS_VLINE '|' +#endif +#ifndef ACS_LTEE +#define ACS_LTEE '+' +#endif +#ifndef ACS_RTEE +#define ACS_RTEE '+' +#endif +#ifndef ACS_UARROW +#define ACS_UARROW '^' +#endif +#ifndef ACS_DARROW +#define ACS_DARROW 'v' +#endif + +/* + * Attribute names + */ +#define screen_attr attributes[0] +#define shadow_attr attributes[1] +#define dialog_attr attributes[2] +#define title_attr attributes[3] +#define border_attr attributes[4] +#define button_active_attr attributes[5] +#define button_inactive_attr attributes[6] +#define button_key_active_attr attributes[7] +#define button_key_inactive_attr attributes[8] +#define button_label_active_attr attributes[9] +#define button_label_inactive_attr attributes[10] +#define inputbox_attr attributes[11] +#define inputbox_border_attr attributes[12] +#define searchbox_attr attributes[13] +#define searchbox_title_attr attributes[14] +#define searchbox_border_attr attributes[15] +#define position_indicator_attr attributes[16] +#define menubox_attr attributes[17] +#define menubox_border_attr attributes[18] +#define item_attr attributes[19] +#define item_selected_attr attributes[20] +#define tag_attr attributes[21] +#define tag_selected_attr attributes[22] +#define tag_key_attr attributes[23] +#define tag_key_selected_attr attributes[24] +#define check_attr attributes[25] +#define check_selected_attr attributes[26] +#define uarrow_attr attributes[27] +#define darrow_attr attributes[28] + +/* number of attributes */ +#define ATTRIBUTE_COUNT 29 + +/* + * Global variables + */ +extern bool use_colors; +extern bool use_shadow; + +extern chtype attributes[]; + +extern const char *backtitle; + +/* + * Function prototypes + */ +extern void create_rc (const char *filename); +extern int parse_rc (void); + + +void init_dialog (void); +void end_dialog (void); +void attr_clear (WINDOW * win, int height, int width, chtype attr); +void dialog_clear (void); +void color_setup (void); +void print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x); +void print_button (WINDOW * win, const char *label, int y, int x, int selected); +void draw_box (WINDOW * win, int y, int x, int height, int width, chtype box, + chtype border); +void draw_shadow (WINDOW * win, int y, int x, int height, int width); + +int first_alpha (const char *string, const char *exempt); +int dialog_yesno (const char *title, const char *prompt, int height, int width); +int dialog_msgbox (const char *title, const char *prompt, int height, + int width, int pause); +int dialog_textbox (const char *title, const char *file, int height, int width); +int dialog_menu (const char *title, const char *prompt, int height, int width, + int menu_height, const char *choice, int item_no, + const char * const * items); +int dialog_checklist (const char *title, const char *prompt, int height, + int width, int list_height, int item_no, + const char * const * items, int flag); +extern unsigned char dialog_input_result[]; +int dialog_inputbox (const char *title, const char *prompt, int height, + int width, const char *init); + +/* + * This is the base for fictitious keys, which activate + * the buttons. + * + * Mouse-generated keys are the following: + * -- the first 32 are used as numbers, in addition to '0'-'9' + * -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o') + * -- uppercase chars are used to invoke the button (M_EVENT + 'O') + */ +#define M_EVENT (KEY_MAX+1) + + +/* + * The `flag' parameter in checklist is used to select between + * radiolist and checklist + */ +#define FLAG_CHECK 1 +#define FLAG_RADIO 0 diff --git a/scripts/lxdialog/inputbox.c b/scripts/lxdialog/inputbox.c new file mode 100644 index 0000000..fa7bebc --- /dev/null +++ b/scripts/lxdialog/inputbox.c @@ -0,0 +1,240 @@ +/* + * inputbox.c -- implements the input box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +unsigned char dialog_input_result[MAX_LEN + 1]; + +/* + * Print the termination buttons + */ +static void +print_buttons(WINDOW *dialog, int height, int width, int selected) +{ + int x = width / 2 - 11; + int y = height - 2; + + print_button (dialog, " Ok ", y, x, selected==0); + print_button (dialog, " Help ", y, x + 14, selected==1); + + wmove(dialog, y, x+1+14*selected); + wrefresh(dialog); +} + +/* + * Display a dialog box for inputing a string + */ +int +dialog_inputbox (const char *title, const char *prompt, int height, int width, + const char *init) +{ + int i, x, y, box_y, box_x, box_width; + int input_x = 0, scroll = 0, key = 0, button = -1; + unsigned char *instr = dialog_input_result; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset (dialog, border_attr); + mvwaddch (dialog, height-3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + waddch (dialog, ACS_RTEE); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + + wattrset (dialog, dialog_attr); + print_autowrap (dialog, prompt, width - 2, 1, 3); + + /* Draw the input field box */ + box_width = width - 6; + getyx (dialog, y, x); + box_y = y + 2; + box_x = (width - box_width) / 2; + draw_box (dialog, y + 1, box_x - 1, 3, box_width + 2, + border_attr, dialog_attr); + + print_buttons(dialog, height, width, 0); + + /* Set up the initial value */ + wmove (dialog, box_y, box_x); + wattrset (dialog, inputbox_attr); + + if (!init) + instr[0] = '\0'; + else + strcpy (instr, init); + + input_x = strlen (instr); + + if (input_x >= box_width) { + scroll = input_x - box_width + 1; + input_x = box_width - 1; + for (i = 0; i < box_width - 1; i++) + waddch (dialog, instr[scroll + i]); + } else + waddstr (dialog, instr); + + wmove (dialog, box_y, box_x + input_x); + + wrefresh (dialog); + + while (key != ESC) { + key = wgetch (dialog); + + if (button == -1) { /* Input box selected */ + switch (key) { + case TAB: + case KEY_UP: + case KEY_DOWN: + break; + case KEY_LEFT: + continue; + case KEY_RIGHT: + continue; + case KEY_BACKSPACE: + case 127: + if (input_x || scroll) { + wattrset (dialog, inputbox_attr); + if (!input_x) { + scroll = scroll < box_width - 1 ? + 0 : scroll - (box_width - 1); + wmove (dialog, box_y, box_x); + for (i = 0; i < box_width; i++) + waddch (dialog, instr[scroll + input_x + i] ? + instr[scroll + input_x + i] : ' '); + input_x = strlen (instr) - scroll; + } else + input_x--; + instr[scroll + input_x] = '\0'; + mvwaddch (dialog, box_y, input_x + box_x, ' '); + wmove (dialog, box_y, input_x + box_x); + wrefresh (dialog); + } + continue; + default: + if (key < 0x100 && isprint (key)) { + if (scroll + input_x < MAX_LEN) { + wattrset (dialog, inputbox_attr); + instr[scroll + input_x] = key; + instr[scroll + input_x + 1] = '\0'; + if (input_x == box_width - 1) { + scroll++; + wmove (dialog, box_y, box_x); + for (i = 0; i < box_width - 1; i++) + waddch (dialog, instr[scroll + i]); + } else { + wmove (dialog, box_y, input_x++ + box_x); + waddch (dialog, key); + } + wrefresh (dialog); + } else + flash (); /* Alarm user about overflow */ + continue; + } + } + } + switch (key) { + case 'O': + case 'o': + delwin (dialog); + return 0; + case 'H': + case 'h': + delwin (dialog); + return 1; + case KEY_UP: + case KEY_LEFT: + switch (button) { + case -1: + button = 1; /* Indicates "Cancel" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 0: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove (dialog, box_y, box_x + input_x); + wrefresh (dialog); + break; + case 1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + } + break; + case TAB: + case KEY_DOWN: + case KEY_RIGHT: + switch (button) { + case -1: + button = 0; /* Indicates "OK" button is selected */ + print_buttons(dialog, height, width, 0); + break; + case 0: + button = 1; /* Indicates "Cancel" button is selected */ + print_buttons(dialog, height, width, 1); + break; + case 1: + button = -1; /* Indicates input box is selected */ + print_buttons(dialog, height, width, 0); + wmove (dialog, box_y, box_x + input_x); + wrefresh (dialog); + break; + } + break; + case ' ': + case '\n': + delwin (dialog); + return (button == -1 ? 0 : button); + case 'X': + case 'x': + key = ESC; + case ESC: + break; + } + } + + delwin (dialog); + return -1; /* ESC pressed */ +} diff --git a/scripts/lxdialog/lxdialog.c b/scripts/lxdialog/lxdialog.c new file mode 100644 index 0000000..6f4c1fd --- /dev/null +++ b/scripts/lxdialog/lxdialog.c @@ -0,0 +1,226 @@ +/* + * dialog - Display simple dialog boxes from shell scripts + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static void Usage (const char *name); + +typedef int (jumperFn) (const char *title, int argc, const char * const * argv); + +struct Mode { + char *name; + int argmin, argmax, argmod; + jumperFn *jumper; +}; + +jumperFn j_menu, j_checklist, j_radiolist, j_yesno, j_textbox, j_inputbox; +jumperFn j_msgbox, j_infobox; + +static struct Mode modes[] = +{ + {"--menu", 9, 0, 3, j_menu}, + {"--checklist", 9, 0, 3, j_checklist}, + {"--radiolist", 9, 0, 3, j_radiolist}, + {"--yesno", 5,5,1, j_yesno}, + {"--textbox", 5,5,1, j_textbox}, + {"--inputbox", 5, 6, 1, j_inputbox}, + {"--msgbox", 5, 5, 1, j_msgbox}, + {"--infobox", 5, 5, 1, j_infobox}, + {NULL, 0, 0, 0, NULL} +}; + +static struct Mode *modePtr; + +#ifdef LOCALE +#include +#endif + +int +main (int argc, const char * const * argv) +{ + int offset = 0, clear_screen = 0, end_common_opts = 0, retval; + const char *title = NULL; + +#ifdef LOCALE + (void) setlocale (LC_ALL, ""); +#endif + +#ifdef TRACE + trace(TRACE_CALLS|TRACE_UPDATE); +#endif + if (argc < 2) { + Usage (argv[0]); + exit (-1); + } + + while (offset < argc - 1 && !end_common_opts) { /* Common options */ + if (!strcmp (argv[offset + 1], "--title")) { + if (argc - offset < 3 || title != NULL) { + Usage (argv[0]); + exit (-1); + } else { + title = argv[offset + 2]; + offset += 2; + } + } else if (!strcmp (argv[offset + 1], "--backtitle")) { + if (backtitle != NULL) { + Usage (argv[0]); + exit (-1); + } else { + backtitle = argv[offset + 2]; + offset += 2; + } + } else if (!strcmp (argv[offset + 1], "--clear")) { + if (clear_screen) { /* Hey, "--clear" can't appear twice! */ + Usage (argv[0]); + exit (-1); + } else if (argc == 2) { /* we only want to clear the screen */ + init_dialog (); + refresh (); /* init_dialog() will clear the screen for us */ + end_dialog (); + return 0; + } else { + clear_screen = 1; + offset++; + } + } else /* no more common options */ + end_common_opts = 1; + } + + if (argc - 1 == offset) { /* no more options */ + Usage (argv[0]); + exit (-1); + } + /* use a table to look for the requested mode, to avoid code duplication */ + + for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */ + if (!strcmp (argv[offset + 1], modePtr->name)) + break; + + if (!modePtr->name) + Usage (argv[0]); + if (argc - offset < modePtr->argmin) + Usage (argv[0]); + if (modePtr->argmax && argc - offset > modePtr->argmax) + Usage (argv[0]); + + + + init_dialog (); + retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset); + + if (clear_screen) { /* clear screen before exit */ + attr_clear (stdscr, LINES, COLS, screen_attr); + refresh (); + } + end_dialog(); + + exit (retval); +} + +/* + * Print program usage + */ +static void +Usage (const char *name) +{ + fprintf (stderr, "\ +\ndialog, by Savio Lam (lam836@cs.cuhk.hk).\ +\n patched by Stuart Herbert (S.Herbert@shef.ac.uk)\ +\n modified/gutted for use as a Linux kernel config tool by \ +\n William Roadcap (roadcapw@cfw.com)\ +\n\ +\n* Display dialog boxes from shell scripts *\ +\n\ +\nUsage: %s --clear\ +\n %s [--title ] [--backtitle <backtitle>] --clear <Box options>\ +\n\ +\nBox options:\ +\n\ +\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\ +\n --checklist <text> <height> <width> <list height> <tag1> <item1> <status1>...\ +\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\ +\n --textbox <file> <height> <width>\ +\n --inputbox <text> <height> <width> [<init>]\ +\n --yesno <text> <height> <width>\ +\n", name, name); + exit (-1); +} + +/* + * These are the program jumpers + */ + +int +j_menu (const char *t, int ac, const char * const * av) +{ + return dialog_menu (t, av[2], atoi (av[3]), atoi (av[4]), + atoi (av[5]), av[6], (ac - 6) / 2, av + 7); +} + +int +j_checklist (const char *t, int ac, const char * const * av) +{ + return dialog_checklist (t, av[2], atoi (av[3]), atoi (av[4]), + atoi (av[5]), (ac - 6) / 3, av + 6, FLAG_CHECK); +} + +int +j_radiolist (const char *t, int ac, const char * const * av) +{ + return dialog_checklist (t, av[2], atoi (av[3]), atoi (av[4]), + atoi (av[5]), (ac - 6) / 3, av + 6, FLAG_RADIO); +} + +int +j_textbox (const char *t, int ac, const char * const * av) +{ + return dialog_textbox (t, av[2], atoi (av[3]), atoi (av[4])); +} + +int +j_yesno (const char *t, int ac, const char * const * av) +{ + return dialog_yesno (t, av[2], atoi (av[3]), atoi (av[4])); +} + +int +j_inputbox (const char *t, int ac, const char * const * av) +{ + int ret = dialog_inputbox (t, av[2], atoi (av[3]), atoi (av[4]), + ac == 6 ? av[5] : (char *) NULL); + if (ret == 0) + fprintf(stderr, dialog_input_result); + return ret; +} + +int +j_msgbox (const char *t, int ac, const char * const * av) +{ + return dialog_msgbox (t, av[2], atoi (av[3]), atoi (av[4]), 1); +} + +int +j_infobox (const char *t, int ac, const char * const * av) +{ + return dialog_msgbox (t, av[2], atoi (av[3]), atoi (av[4]), 0); +} + diff --git a/scripts/lxdialog/menubox.c b/scripts/lxdialog/menubox.c new file mode 100644 index 0000000..a234e9f --- /dev/null +++ b/scripts/lxdialog/menubox.c @@ -0,0 +1,443 @@ +/* + * menubox.c -- implements the menu box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Changes by Clifford Wolf (god@clifford.at) + * + * [ 1998-06-13 ] + * + * *) A bugfix for the Page-Down problem + * + * *) Formerly when I used Page Down and Page Up, the cursor would be set + * to the first position in the menu box. Now lxdialog is a bit + * smarter and works more like other menu systems (just have a look at + * it). + * + * *) Formerly if I selected something my scrolling would be broken because + * lxdialog is re-invoked by the Menuconfig shell script, can't + * remember the last scrolling position, and just sets it so that the + * cursor is at the bottom of the box. Now it writes the temporary file + * lxdialog.scrltmp which contains this information. The file is + * deleted by lxdialog if the user leaves a submenu or enters a new + * one, but it would be nice if Menuconfig could make another "rm -f" + * just to be sure. Just try it out - you will recognise a difference! + * + * [ 1998-06-14 ] + * + * *) Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files + * and menus change their size on the fly. + * + * *) If for some reason the last scrolling position is not saved by + * lxdialog, it sets the scrolling so that the selected item is in the + * middle of the menu box, not at the bottom. + * + * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net) + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus. + * This fixes a bug in Menuconfig where using ' ' to descend into menus + * would leave mis-synchronized lxdialog.scrltmp files lying around, + * fscanf would read in 'scroll', and eventually that value would get used. + */ + +#include "dialog.h" + +static int menu_width, item_x; + +/* + * Print menu item + */ +static void +print_item (WINDOW * win, const char *item, int choice, int selected, int hotkey) +{ + int j; + char menu_item[menu_width+1]; + + strncpy(menu_item, item, menu_width); + menu_item[menu_width] = 0; + j = first_alpha(menu_item, "YyNnMm"); + + /* Clear 'residue' of last item */ + wattrset (win, menubox_attr); + wmove (win, choice, 0); +#if OLD_NCURSES + { + int i; + for (i = 0; i < menu_width; i++) + waddch (win, ' '); + } +#else + wclrtoeol(win); +#endif + wattrset (win, selected ? item_selected_attr : item_attr); + mvwaddstr (win, choice, item_x, menu_item); + if (hotkey) { + wattrset (win, selected ? tag_key_selected_attr : tag_key_attr); + mvwaddch(win, choice, item_x+j, menu_item[j]); + } + if (selected) { + wmove (win, choice, item_x+1); + wrefresh (win); + } +} + +/* + * Print the scroll indicators. + */ +static void +print_arrows (WINDOW * win, int item_no, int scroll, + int y, int x, int height) +{ + int cur_y, cur_x; + + getyx(win, cur_y, cur_x); + + wmove(win, y, x); + + if (scroll > 0) { + wattrset (win, uarrow_attr); + waddch (win, ACS_UARROW); + waddstr (win, "(-)"); + } + else { + wattrset (win, menubox_attr); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + } + + y = y + height + 1; + wmove(win, y, x); + + if ((height < item_no) && (scroll + height < item_no)) { + wattrset (win, darrow_attr); + waddch (win, ACS_DARROW); + waddstr (win, "(+)"); + } + else { + wattrset (win, menubox_border_attr); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + waddch (win, ACS_HLINE); + } + + wmove(win, cur_y, cur_x); +} + +/* + * Display the termination buttons. + */ +static void +print_buttons (WINDOW *win, int height, int width, int selected) +{ + int x = width / 2 - 16; + int y = height - 2; + + print_button (win, "Select", y, x, selected == 0); + print_button (win, " Exit ", y, x + 12, selected == 1); + print_button (win, " Help ", y, x + 24, selected == 2); + + wmove(win, y, x+1+12*selected); + wrefresh (win); +} + +/* + * Display a menu for choosing among a number of options + */ +int +dialog_menu (const char *title, const char *prompt, int height, int width, + int menu_height, const char *current, int item_no, + const char * const * items) + +{ + int i, j, x, y, box_x, box_y; + int key = 0, button = 0, scroll = 0, choice = 0, first_item = 0, max_choice; + WINDOW *dialog, *menu; + FILE *f; + + max_choice = MIN (menu_height, item_no); + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset (dialog, border_attr); + mvwaddch (dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + wbkgdset (dialog, dialog_attr & A_COLOR); + waddch (dialog, ACS_RTEE); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + + wattrset (dialog, dialog_attr); + print_autowrap (dialog, prompt, width - 2, 1, 3); + + menu_width = width - 6; + box_y = height - menu_height - 5; + box_x = (width - menu_width) / 2 - 1; + + /* create new window for the menu */ + menu = subwin (dialog, menu_height, menu_width, + y + box_y + 1, x + box_x + 1); + keypad (menu, TRUE); + + /* draw a box around the menu items */ + draw_box (dialog, box_y, box_x, menu_height + 2, menu_width + 2, + menubox_border_attr, menubox_attr); + + /* + * Find length of longest item in order to center menu. + * Set 'choice' to default item. + */ + item_x = 0; + for (i = 0; i < item_no; i++) { + item_x = MAX (item_x, MIN(menu_width, strlen (items[i * 2 + 1]) + 2)); + if (strcmp(current, items[i*2]) == 0) choice = i; + } + + item_x = (menu_width - item_x) / 2; + + /* get the scroll info from the temp file */ + if ( (f=fopen("lxdialog.scrltmp","r")) != NULL ) { + if ( (fscanf(f,"%d\n",&scroll) == 1) && (scroll <= choice) && + (scroll+max_choice > choice) && (scroll >= 0) && + (scroll+max_choice <= item_no) ) { + first_item = scroll; + choice = choice - scroll; + fclose(f); + } else { + scroll=0; + remove("lxdialog.scrltmp"); + fclose(f); + f=NULL; + } + } + if ( (choice >= max_choice) || (f==NULL && choice >= max_choice/2) ) { + if (choice >= item_no-max_choice/2) + scroll = first_item = item_no-max_choice; + else + scroll = first_item = choice - max_choice/2; + choice = choice - scroll; + } + + /* Print the menu */ + for (i=0; i < max_choice; i++) { + print_item (menu, items[(first_item + i) * 2 + 1], i, i == choice, + (items[(first_item + i)*2][0] != ':')); + } + + wnoutrefresh (menu); + + print_arrows(dialog, item_no, scroll, + box_y, box_x+item_x+1, menu_height); + + print_buttons (dialog, height, width, 0); + wmove (menu, choice, item_x+1); + wrefresh (menu); + + while (key != ESC) { + key = wgetch(menu); + + if (key < 256 && isalpha(key)) key = tolower(key); + + if (strchr("ynm", key)) + i = max_choice; + else { + for (i = choice+1; i < max_choice; i++) { + j = first_alpha(items[(scroll+i)*2+1], "YyNnMm"); + if (key == tolower(items[(scroll+i)*2+1][j])) + break; + } + if (i == max_choice) + for (i = 0; i < max_choice; i++) { + j = first_alpha(items[(scroll+i)*2+1], "YyNnMm"); + if (key == tolower(items[(scroll+i)*2+1][j])) + break; + } + } + + if (i < max_choice || + key == KEY_UP || key == KEY_DOWN || + key == '-' || key == '+' || + key == KEY_PPAGE || key == KEY_NPAGE) { + + print_item (menu, items[(scroll+choice)*2+1], choice, FALSE, + (items[(scroll+choice)*2][0] != ':')); + + if (key == KEY_UP || key == '-') { + if (choice < 2 && scroll) { + /* Scroll menu down */ + scrollok (menu, TRUE); + wscrl (menu, -1); + scrollok (menu, FALSE); + + scroll--; + + print_item (menu, items[scroll * 2 + 1], 0, FALSE, + (items[scroll*2][0] != ':')); + } else + choice = MAX(choice - 1, 0); + + } else if (key == KEY_DOWN || key == '+') { + + print_item (menu, items[(scroll+choice)*2+1], choice, FALSE, + (items[(scroll+choice)*2][0] != ':')); + + if ((choice > max_choice-3) && + (scroll + max_choice < item_no) + ) { + /* Scroll menu up */ + scrollok (menu, TRUE); + scroll (menu); + scrollok (menu, FALSE); + + scroll++; + + print_item (menu, items[(scroll+max_choice-1)*2+1], + max_choice-1, FALSE, + (items[(scroll+max_choice-1)*2][0] != ':')); + } else + choice = MIN(choice+1, max_choice-1); + + } else if (key == KEY_PPAGE) { + scrollok (menu, TRUE); + for (i=0; (i < max_choice); i++) { + if (scroll > 0) { + wscrl (menu, -1); + scroll--; + print_item (menu, items[scroll * 2 + 1], 0, FALSE, + (items[scroll*2][0] != ':')); + } else { + if (choice > 0) + choice--; + } + } + scrollok (menu, FALSE); + + } else if (key == KEY_NPAGE) { + for (i=0; (i < max_choice); i++) { + if (scroll+max_choice < item_no) { + scrollok (menu, TRUE); + scroll(menu); + scrollok (menu, FALSE); + scroll++; + print_item (menu, items[(scroll+max_choice-1)*2+1], + max_choice-1, FALSE, + (items[(scroll+max_choice-1)*2][0] != ':')); + } else { + if (choice+1 < max_choice) + choice++; + } + } + + } else + choice = i; + + print_item (menu, items[(scroll+choice)*2+1], choice, TRUE, + (items[(scroll+choice)*2][0] != ':')); + + print_arrows(dialog, item_no, scroll, + box_y, box_x+item_x+1, menu_height); + + wnoutrefresh (dialog); + wrefresh (menu); + + continue; /* wait for another key press */ + } + + switch (key) { + case KEY_LEFT: + case TAB: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 2 : (button > 2 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh (menu); + break; + case ' ': + case 's': + case 'y': + case 'n': + case 'm': + /* save scroll info */ + if ( (f=fopen("lxdialog.scrltmp","w")) != NULL ) { + fprintf(f,"%d\n",scroll); + fclose(f); + } + delwin (dialog); + fprintf(stderr, "%s\n", items[(scroll + choice) * 2]); + switch (key) { + case 's': return 3; + case 'y': return 3; + case 'n': return 4; + case 'm': return 5; + case ' ': return 6; + } + return 0; + case 'h': + case '?': + button = 2; + case '\n': + delwin (dialog); + if (button == 2) + fprintf(stderr, "%s \"%s\"\n", + items[(scroll + choice) * 2], + items[(scroll + choice) * 2 + 1] + + first_alpha(items[(scroll + choice) * 2 + 1],"")); + else + fprintf(stderr, "%s\n", items[(scroll + choice) * 2]); + + remove("lxdialog.scrltmp"); + return button; + case 'e': + case 'x': + key = ESC; + case ESC: + break; + } + } + + delwin (dialog); + remove("lxdialog.scrltmp"); + return -1; /* ESC pressed */ +} diff --git a/scripts/lxdialog/msgbox.c b/scripts/lxdialog/msgbox.c new file mode 100644 index 0000000..93692e1 --- /dev/null +++ b/scripts/lxdialog/msgbox.c @@ -0,0 +1,85 @@ +/* + * msgbox.c -- implements the message box and info box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +/* + * Display a message box. Program will pause and display an "OK" button + * if the parameter 'pause' is non-zero. + */ +int +dialog_msgbox (const char *title, const char *prompt, int height, int width, + int pause) +{ + int i, x, y, key = 0; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + wattrset (dialog, dialog_attr); + print_autowrap (dialog, prompt, width - 2, 1, 2); + + if (pause) { + wattrset (dialog, border_attr); + mvwaddch (dialog, height - 3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + waddch (dialog, ACS_RTEE); + + print_button (dialog, " Ok ", + height - 2, width / 2 - 4, TRUE); + + wrefresh (dialog); + while (key != ESC && key != '\n' && key != ' ' && + key != 'O' && key != 'o' && key != 'X' && key != 'x') + key = wgetch (dialog); + } else { + key = '\n'; + wrefresh (dialog); + } + + delwin (dialog); + return key == ESC ? -1 : 0; +} diff --git a/scripts/lxdialog/textbox.c b/scripts/lxdialog/textbox.c new file mode 100644 index 0000000..ecf5541 --- /dev/null +++ b/scripts/lxdialog/textbox.c @@ -0,0 +1,556 @@ +/* + * textbox.c -- implements the text box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +static void back_lines (int n); +static void print_page (WINDOW * win, int height, int width); +static void print_line (WINDOW * win, int row, int width); +static char *get_line (void); +static void print_position (WINDOW * win, int height, int width); + +static int hscroll = 0, fd, file_size, bytes_read; +static int begin_reached = 1, end_reached = 0, page_length; +static char *buf, *page; + +/* + * Display text from a file in a dialog box. + */ +int +dialog_textbox (const char *title, const char *file, int height, int width) +{ + int i, x, y, cur_x, cur_y, fpos, key = 0; + int passed_end; + char search_term[MAX_LEN + 1]; + WINDOW *dialog, *text; + + search_term[0] = '\0'; /* no search term entered yet */ + + /* Open input file for reading */ + if ((fd = open (file, O_RDONLY)) == -1) { + endwin (); + fprintf (stderr, + "\nCan't open input file in dialog_textbox().\n"); + exit (-1); + } + /* Get file size. Actually, 'file_size' is the real file size - 1, + since it's only the last byte offset from the beginning */ + if ((file_size = lseek (fd, 0, SEEK_END)) == -1) { + endwin (); + fprintf (stderr, "\nError getting file size in dialog_textbox().\n"); + exit (-1); + } + /* Restore file pointer to beginning of file after getting file size */ + if (lseek (fd, 0, SEEK_SET) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in dialog_textbox().\n"); + exit (-1); + } + /* Allocate space for read buffer */ + if ((buf = malloc (BUF_SIZE + 1)) == NULL) { + endwin (); + fprintf (stderr, "\nCan't allocate memory in dialog_textbox().\n"); + exit (-1); + } + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, "\nError reading file in dialog_textbox().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; /* mark end of valid data */ + page = buf; /* page is pointer to start of page to be displayed */ + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + /* Create window for text region, used for scrolling text */ + text = subwin (dialog, height - 4, width - 2, y + 1, x + 1); + wattrset (text, dialog_attr); + wbkgdset (text, dialog_attr & A_COLOR); + + keypad (text, TRUE); + + /* register the new window, along with its borders */ + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + + wattrset (dialog, border_attr); + mvwaddch (dialog, height-3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + wbkgdset (dialog, dialog_attr & A_COLOR); + waddch (dialog, ACS_RTEE); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + print_button (dialog, " Exit ", height - 2, width / 2 - 4, TRUE); + wnoutrefresh (dialog); + getyx (dialog, cur_y, cur_x); /* Save cursor position */ + + /* Print first page of text */ + attr_clear (text, height - 4, width - 2, dialog_attr); + print_page (text, height - 4, width - 2); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh (dialog); + + while ((key != ESC) && (key != '\n')) { + key = wgetch (dialog); + switch (key) { + case 'E': /* Exit */ + case 'e': + case 'X': + case 'x': + delwin (dialog); + free (buf); + close (fd); + return 0; + case 'g': /* First page */ + case KEY_HOME: + if (!begin_reached) { + begin_reached = 1; + /* First page not in buffer? */ + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, + "\nError moving file pointer in dialog_textbox().\n"); + exit (-1); + } + if (fpos > bytes_read) { /* Yes, we have to read it in */ + if (lseek (fd, 0, SEEK_SET) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in " + "dialog_textbox().\n"); + exit (-1); + } + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, + "\nError reading file in dialog_textbox().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; + } + page = buf; + print_page (text, height - 4, width - 2); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh (dialog); + } + break; + case 'G': /* Last page */ + case KEY_END: + + end_reached = 1; + /* Last page not in buffer? */ + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, + "\nError moving file pointer in dialog_textbox().\n"); + exit (-1); + } + if (fpos < file_size) { /* Yes, we have to read it in */ + if (lseek (fd, -BUF_SIZE, SEEK_END) == -1) { + endwin (); + fprintf (stderr, + "\nError moving file pointer in dialog_textbox().\n"); + exit (-1); + } + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, + "\nError reading file in dialog_textbox().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; + } + page = buf + bytes_read; + back_lines (height - 4); + print_page (text, height - 4, width - 2); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh (dialog); + break; + case 'K': /* Previous line */ + case 'k': + case KEY_UP: + if (!begin_reached) { + back_lines (page_length + 1); + + /* We don't call print_page() here but use scrolling to ensure + faster screen update. However, 'end_reached' and + 'page_length' should still be updated, and 'page' should + point to start of next page. This is done by calling + get_line() in the following 'for' loop. */ + scrollok (text, TRUE); + wscrl (text, -1); /* Scroll text region down one line */ + scrollok (text, FALSE); + page_length = 0; + passed_end = 0; + for (i = 0; i < height - 4; i++) { + if (!i) { + /* print first line of page */ + print_line (text, 0, width - 2); + wnoutrefresh (text); + } else + /* Called to update 'end_reached' and 'page' */ + get_line (); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh (dialog); + } + break; + case 'B': /* Previous page */ + case 'b': + case KEY_PPAGE: + if (begin_reached) + break; + back_lines (page_length + height - 4); + print_page (text, height - 4, width - 2); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); + wrefresh (dialog); + break; + case 'J': /* Next line */ + case 'j': + case KEY_DOWN: + if (!end_reached) { + begin_reached = 0; + scrollok (text, TRUE); + scroll (text); /* Scroll text region up one line */ + scrollok (text, FALSE); + print_line (text, height - 5, width - 2); + wnoutrefresh (text); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); /* Restore cursor position */ + wrefresh (dialog); + } + break; + case KEY_NPAGE: /* Next page */ + case ' ': + if (end_reached) + break; + + begin_reached = 0; + print_page (text, height - 4, width - 2); + print_position (dialog, height, width); + wmove (dialog, cur_y, cur_x); + wrefresh (dialog); + break; + case '0': /* Beginning of line */ + case 'H': /* Scroll left */ + case 'h': + case KEY_LEFT: + if (hscroll <= 0) + break; + + if (key == '0') + hscroll = 0; + else + hscroll--; + /* Reprint current page to scroll horizontally */ + back_lines (page_length); + print_page (text, height - 4, width - 2); + wmove (dialog, cur_y, cur_x); + wrefresh (dialog); + break; + case 'L': /* Scroll right */ + case 'l': + case KEY_RIGHT: + if (hscroll >= MAX_LEN) + break; + hscroll++; + /* Reprint current page to scroll horizontally */ + back_lines (page_length); + print_page (text, height - 4, width - 2); + wmove (dialog, cur_y, cur_x); + wrefresh (dialog); + break; + case ESC: + break; + } + } + + delwin (dialog); + free (buf); + close (fd); + return -1; /* ESC pressed */ +} + +/* + * Go back 'n' lines in text file. Called by dialog_textbox(). + * 'page' will be updated to point to the desired line in 'buf'. + */ +static void +back_lines (int n) +{ + int i, fpos; + + begin_reached = 0; + /* We have to distinguish between end_reached and !end_reached + since at end of file, the line is not ended by a '\n'. + The code inside 'if' basically does a '--page' to move one + character backward so as to skip '\n' of the previous line */ + if (!end_reached) { + /* Either beginning of buffer or beginning of file reached? */ + if (page == buf) { + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in " + "back_lines().\n"); + exit (-1); + } + if (fpos > bytes_read) { /* Not beginning of file yet */ + /* We've reached beginning of buffer, but not beginning of + file yet, so read previous part of file into buffer. + Note that we only move backward for BUF_SIZE/2 bytes, + but not BUF_SIZE bytes to avoid re-reading again in + print_page() later */ + /* Really possible to move backward BUF_SIZE/2 bytes? */ + if (fpos < BUF_SIZE / 2 + bytes_read) { + /* No, move less then */ + if (lseek (fd, 0, SEEK_SET) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in " + "back_lines().\n"); + exit (-1); + } + page = buf + fpos - bytes_read; + } else { /* Move backward BUF_SIZE/2 bytes */ + if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) + == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer " + "in back_lines().\n"); + exit (-1); + } + page = buf + BUF_SIZE / 2; + } + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, "\nError reading file in back_lines().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; + } else { /* Beginning of file reached */ + begin_reached = 1; + return; + } + } + if (*(--page) != '\n') { /* '--page' here */ + /* Something's wrong... */ + endwin (); + fprintf (stderr, "\nInternal error in back_lines().\n"); + exit (-1); + } + } + /* Go back 'n' lines */ + for (i = 0; i < n; i++) + do { + if (page == buf) { + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, + "\nError moving file pointer in back_lines().\n"); + exit (-1); + } + if (fpos > bytes_read) { + /* Really possible to move backward BUF_SIZE/2 bytes? */ + if (fpos < BUF_SIZE / 2 + bytes_read) { + /* No, move less then */ + if (lseek (fd, 0, SEEK_SET) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer " + "in back_lines().\n"); + exit (-1); + } + page = buf + fpos - bytes_read; + } else { /* Move backward BUF_SIZE/2 bytes */ + if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), + SEEK_CUR) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer" + " in back_lines().\n"); + exit (-1); + } + page = buf + BUF_SIZE / 2; + } + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, "\nError reading file in " + "back_lines().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; + } else { /* Beginning of file reached */ + begin_reached = 1; + return; + } + } + } while (*(--page) != '\n'); + page++; +} + +/* + * Print a new page of text. Called by dialog_textbox(). + */ +static void +print_page (WINDOW * win, int height, int width) +{ + int i, passed_end = 0; + + page_length = 0; + for (i = 0; i < height; i++) { + print_line (win, i, width); + if (!passed_end) + page_length++; + if (end_reached && !passed_end) + passed_end = 1; + } + wnoutrefresh (win); +} + +/* + * Print a new line of text. Called by dialog_textbox() and print_page(). + */ +static void +print_line (WINDOW * win, int row, int width) +{ + int y, x; + char *line; + + line = get_line (); + line += MIN (strlen (line), hscroll); /* Scroll horizontally */ + wmove (win, row, 0); /* move cursor to correct line */ + waddch (win, ' '); + waddnstr (win, line, MIN (strlen (line), width - 2)); + + getyx (win, y, x); + /* Clear 'residue' of previous line */ +#if OLD_NCURSES + { + int i; + for (i = 0; i < width - x; i++) + waddch (win, ' '); + } +#else + wclrtoeol(win); +#endif +} + +/* + * Return current line of text. Called by dialog_textbox() and print_line(). + * 'page' should point to start of current line before calling, and will be + * updated to point to start of next line. + */ +static char * +get_line (void) +{ + int i = 0, fpos; + static char line[MAX_LEN + 1]; + + end_reached = 0; + while (*page != '\n') { + if (*page == '\0') { + /* Either end of file or end of buffer reached */ + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in " + "get_line().\n"); + exit (-1); + } + if (fpos < file_size) { /* Not end of file yet */ + /* We've reached end of buffer, but not end of file yet, + so read next part of file into buffer */ + if ((bytes_read = read (fd, buf, BUF_SIZE)) == -1) { + endwin (); + fprintf (stderr, "\nError reading file in get_line().\n"); + exit (-1); + } + buf[bytes_read] = '\0'; + page = buf; + } else { + if (!end_reached) + end_reached = 1; + break; + } + } else if (i < MAX_LEN) + line[i++] = *(page++); + else { + /* Truncate lines longer than MAX_LEN characters */ + if (i == MAX_LEN) + line[i++] = '\0'; + page++; + } + } + if (i <= MAX_LEN) + line[i] = '\0'; + if (!end_reached) + page++; /* move pass '\n' */ + + return line; +} + +/* + * Print current position + */ +static void +print_position (WINDOW * win, int height, int width) +{ + int fpos, percent; + + if ((fpos = lseek (fd, 0, SEEK_CUR)) == -1) { + endwin (); + fprintf (stderr, "\nError moving file pointer in print_position().\n"); + exit (-1); + } + wattrset (win, position_indicator_attr); + wbkgdset (win, position_indicator_attr & A_COLOR); + percent = !file_size ? + 100 : ((fpos - bytes_read + page - buf) * 100) / file_size; + wmove (win, height - 3, width - 9); + wprintw (win, "(%3d%%)", percent); +} diff --git a/scripts/lxdialog/util.c b/scripts/lxdialog/util.c new file mode 100644 index 0000000..b3a7af9 --- /dev/null +++ b/scripts/lxdialog/util.c @@ -0,0 +1,359 @@ +/* + * util.c + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + + +/* use colors by default? */ +bool use_colors = 1; + +const char *backtitle = NULL; + +const char *dialog_result; + +/* + * Attribute values, default is for mono display + */ +chtype attributes[] = +{ + A_NORMAL, /* screen_attr */ + A_NORMAL, /* shadow_attr */ + A_NORMAL, /* dialog_attr */ + A_BOLD, /* title_attr */ + A_NORMAL, /* border_attr */ + A_REVERSE, /* button_active_attr */ + A_DIM, /* button_inactive_attr */ + A_REVERSE, /* button_key_active_attr */ + A_BOLD, /* button_key_inactive_attr */ + A_REVERSE, /* button_label_active_attr */ + A_NORMAL, /* button_label_inactive_attr */ + A_NORMAL, /* inputbox_attr */ + A_NORMAL, /* inputbox_border_attr */ + A_NORMAL, /* searchbox_attr */ + A_BOLD, /* searchbox_title_attr */ + A_NORMAL, /* searchbox_border_attr */ + A_BOLD, /* position_indicator_attr */ + A_NORMAL, /* menubox_attr */ + A_NORMAL, /* menubox_border_attr */ + A_NORMAL, /* item_attr */ + A_REVERSE, /* item_selected_attr */ + A_BOLD, /* tag_attr */ + A_REVERSE, /* tag_selected_attr */ + A_BOLD, /* tag_key_attr */ + A_REVERSE, /* tag_key_selected_attr */ + A_BOLD, /* check_attr */ + A_REVERSE, /* check_selected_attr */ + A_BOLD, /* uarrow_attr */ + A_BOLD /* darrow_attr */ +}; + + +#include "colors.h" + +/* + * Table of color values + */ +int color_table[][3] = +{ + {SCREEN_FG, SCREEN_BG, SCREEN_HL}, + {SHADOW_FG, SHADOW_BG, SHADOW_HL}, + {DIALOG_FG, DIALOG_BG, DIALOG_HL}, + {TITLE_FG, TITLE_BG, TITLE_HL}, + {BORDER_FG, BORDER_BG, BORDER_HL}, + {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL}, + {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL}, + {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL}, + {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG, BUTTON_KEY_INACTIVE_HL}, + {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG, BUTTON_LABEL_ACTIVE_HL}, + {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG, + BUTTON_LABEL_INACTIVE_HL}, + {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL}, + {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL}, + {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL}, + {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL}, + {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL}, + {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL}, + {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL}, + {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL}, + {ITEM_FG, ITEM_BG, ITEM_HL}, + {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL}, + {TAG_FG, TAG_BG, TAG_HL}, + {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL}, + {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL}, + {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL}, + {CHECK_FG, CHECK_BG, CHECK_HL}, + {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL}, + {UARROW_FG, UARROW_BG, UARROW_HL}, + {DARROW_FG, DARROW_BG, DARROW_HL}, +}; /* color_table */ + +/* + * Set window to attribute 'attr' + */ +void +attr_clear (WINDOW * win, int height, int width, chtype attr) +{ + int i, j; + + wattrset (win, attr); + for (i = 0; i < height; i++) { + wmove (win, i, 0); + for (j = 0; j < width; j++) + waddch (win, ' '); + } + touchwin (win); +} + +void dialog_clear (void) +{ + attr_clear (stdscr, LINES, COLS, screen_attr); + /* Display background title if it exists ... - SLH */ + if (backtitle != NULL) { + int i; + + wattrset (stdscr, screen_attr); + mvwaddstr (stdscr, 0, 1, (char *)backtitle); + wmove (stdscr, 1, 1); + for (i = 1; i < COLS - 1; i++) + waddch (stdscr, ACS_HLINE); + } + wnoutrefresh (stdscr); +} + +/* + * Do some initialization for dialog + */ +void +init_dialog (void) +{ + initscr (); /* Init curses */ + keypad (stdscr, TRUE); + cbreak (); + noecho (); + + + if (use_colors) /* Set up colors */ + color_setup (); + + + dialog_clear (); +} + +/* + * Setup for color display + */ +void +color_setup (void) +{ + int i; + + if (has_colors ()) { /* Terminal supports color? */ + start_color (); + + /* Initialize color pairs */ + for (i = 0; i < ATTRIBUTE_COUNT; i++) + init_pair (i + 1, color_table[i][0], color_table[i][1]); + + /* Setup color attributes */ + for (i = 0; i < ATTRIBUTE_COUNT; i++) + attributes[i] = C_ATTR (color_table[i][2], i + 1); + } +} + +/* + * End using dialog functions. + */ +void +end_dialog (void) +{ + endwin (); +} + + +/* + * Print a string of text in a window, automatically wrap around to the + * next line if the string is too long to fit on one line. Newline + * characters '\n' are replaced by spaces. We start on a new line + * if there is no room for at least 4 nonblanks following a double-space. + */ +void +print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x) +{ + int newl, cur_x, cur_y; + int i, prompt_len, room, wlen; + char tempstr[MAX_LEN + 1], *word, *sp, *sp2; + + strcpy (tempstr, prompt); + + prompt_len = strlen(tempstr); + + /* + * Remove newlines + */ + for(i=0; i<prompt_len; i++) { + if(tempstr[i] == '\n') tempstr[i] = ' '; + } + + if (prompt_len <= width - x * 2) { /* If prompt is short */ + wmove (win, y, (width - prompt_len) / 2); + waddstr (win, tempstr); + } else { + cur_x = x; + cur_y = y; + newl = 1; + word = tempstr; + while (word && *word) { + sp = index(word, ' '); + if (sp) + *sp++ = 0; + + /* Wrap to next line if either the word does not fit, + or it is the first word of a new sentence, and it is + short, and the next word does not fit. */ + room = width - cur_x; + wlen = strlen(word); + if (wlen > room || + (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room + && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) { + cur_y++; + cur_x = x; + } + wmove (win, cur_y, cur_x); + waddstr (win, word); + getyx (win, cur_y, cur_x); + cur_x++; + if (sp && *sp == ' ') { + cur_x++; /* double space */ + while (*++sp == ' '); + newl = 1; + } else + newl = 0; + word = sp; + } + } +} + +/* + * Print a button + */ +void +print_button (WINDOW * win, const char *label, int y, int x, int selected) +{ + int i, temp; + + wmove (win, y, x); + wattrset (win, selected ? button_active_attr : button_inactive_attr); + waddstr (win, "<"); + temp = strspn (label, " "); + label += temp; + wattrset (win, selected ? button_label_active_attr + : button_label_inactive_attr); + for (i = 0; i < temp; i++) + waddch (win, ' '); + wattrset (win, selected ? button_key_active_attr + : button_key_inactive_attr); + waddch (win, label[0]); + wattrset (win, selected ? button_label_active_attr + : button_label_inactive_attr); + waddstr (win, (char *)label + 1); + wattrset (win, selected ? button_active_attr : button_inactive_attr); + waddstr (win, ">"); + wmove (win, y, x + temp + 1); +} + +/* + * Draw a rectangular box with line drawing characters + */ +void +draw_box (WINDOW * win, int y, int x, int height, int width, + chtype box, chtype border) +{ + int i, j; + + wattrset (win, 0); + for (i = 0; i < height; i++) { + wmove (win, y + i, x); + for (j = 0; j < width; j++) + if (!i && !j) + waddch (win, border | ACS_ULCORNER); + else if (i == height - 1 && !j) + waddch (win, border | ACS_LLCORNER); + else if (!i && j == width - 1) + waddch (win, box | ACS_URCORNER); + else if (i == height - 1 && j == width - 1) + waddch (win, box | ACS_LRCORNER); + else if (!i) + waddch (win, border | ACS_HLINE); + else if (i == height - 1) + waddch (win, box | ACS_HLINE); + else if (!j) + waddch (win, border | ACS_VLINE); + else if (j == width - 1) + waddch (win, box | ACS_VLINE); + else + waddch (win, box | ' '); + } +} + +/* + * Draw shadows along the right and bottom edge to give a more 3D look + * to the boxes + */ +void +draw_shadow (WINDOW * win, int y, int x, int height, int width) +{ + int i; + + if (has_colors ()) { /* Whether terminal supports color? */ + wattrset (win, shadow_attr); + wmove (win, y + height, x + 2); + for (i = 0; i < width; i++) + waddch (win, winch (win) & A_CHARTEXT); + for (i = y + 1; i < y + height + 1; i++) { + wmove (win, i, x + width); + waddch (win, winch (win) & A_CHARTEXT); + waddch (win, winch (win) & A_CHARTEXT); + } + wnoutrefresh (win); + } +} + +/* + * Return the position of the first alphabetic character in a string. + */ +int +first_alpha(const char *string, const char *exempt) +{ + int i, in_paren=0, c; + + for (i = 0; i < strlen(string); i++) { + c = tolower(string[i]); + + if (strchr("<[(", c)) ++in_paren; + if (strchr(">])", c)) --in_paren; + + if ((! in_paren) && isalpha(c) && + strchr(exempt, c) == 0) + return i; + } + + return 0; +} diff --git a/scripts/lxdialog/yesno.c b/scripts/lxdialog/yesno.c new file mode 100644 index 0000000..11fcc25 --- /dev/null +++ b/scripts/lxdialog/yesno.c @@ -0,0 +1,118 @@ +/* + * yesno.c -- implements the yes/no box + * + * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk) + * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com) + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "dialog.h" + +/* + * Display termination buttons + */ +static void +print_buttons(WINDOW *dialog, int height, int width, int selected) +{ + int x = width / 2 - 10; + int y = height - 2; + + print_button (dialog, " Yes ", y, x, selected == 0); + print_button (dialog, " No ", y, x + 13, selected == 1); + + wmove(dialog, y, x+1 + 13*selected ); + wrefresh (dialog); +} + +/* + * Display a dialog box with two buttons - Yes and No + */ +int +dialog_yesno (const char *title, const char *prompt, int height, int width) +{ + int i, x, y, key = 0, button = 0; + WINDOW *dialog; + + /* center dialog box on screen */ + x = (COLS - width) / 2; + y = (LINES - height) / 2; + + draw_shadow (stdscr, y, x, height, width); + + dialog = newwin (height, width, y, x); + keypad (dialog, TRUE); + + draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr); + wattrset (dialog, border_attr); + mvwaddch (dialog, height-3, 0, ACS_LTEE); + for (i = 0; i < width - 2; i++) + waddch (dialog, ACS_HLINE); + wattrset (dialog, dialog_attr); + waddch (dialog, ACS_RTEE); + + if (title != NULL && strlen(title) >= width-2 ) { + /* truncate long title -- mec */ + char * title2 = malloc(width-2+1); + memcpy( title2, title, width-2 ); + title2[width-2] = '\0'; + title = title2; + } + + if (title != NULL) { + wattrset (dialog, title_attr); + mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' '); + waddstr (dialog, (char *)title); + waddch (dialog, ' '); + } + + wattrset (dialog, dialog_attr); + print_autowrap (dialog, prompt, width - 2, 1, 3); + + print_buttons(dialog, height, width, 0); + + while (key != ESC) { + key = wgetch (dialog); + switch (key) { + case 'Y': + case 'y': + delwin (dialog); + return 0; + case 'N': + case 'n': + delwin (dialog); + return 1; + + case TAB: + case KEY_LEFT: + case KEY_RIGHT: + button = ((key == KEY_LEFT ? --button : ++button) < 0) + ? 1 : (button > 1 ? 0 : button); + + print_buttons(dialog, height, width, button); + wrefresh (dialog); + break; + case ' ': + case '\n': + delwin (dialog); + return button; + case ESC: + break; + } + } + + delwin (dialog); + return -1; /* ESC pressed */ +} diff --git a/scripts/size b/scripts/size new file mode 100644 index 0000000..d3e3f4a --- /dev/null +++ b/scripts/size @@ -0,0 +1,13 @@ +#!/bin/bash +j=0 +for i in ".text" ".data" ".bss" +do + val[$j]=$(avr-size -A $1 | grep $i | sed -e "s/^$i *//g" | cut -d " " -f1) + let j=$j+1 +done +echo "" +echo "Program: $(echo ${val[0]}+${val[1]}|bc) bytes" +echo "(.text + .data)" +echo "" +echo "Data: $(echo ${val[2]}+${val[1]}|bc) bytes" +echo "(.data + .bss)" diff --git a/scrolltext/Makefile b/scrolltext/Makefile new file mode 100644 index 0000000..3c066c6 --- /dev/null +++ b/scrolltext/Makefile @@ -0,0 +1,10 @@ +TARGET = libscrolltext.a +TOPDIR = .. + +include $(TOPDIR)/defaults.mk + +SRC = scrolltext3.c + +SRC += $(SCROLLTEXT_FONT).c + +include $(TOPDIR)/rules.mk diff --git a/scrolltext/config.in b/scrolltext/config.in new file mode 100644 index 0000000..bee4d83 --- /dev/null +++ b/scrolltext/config.in @@ -0,0 +1,20 @@ + +dep_bool_menu "Scrolltext Support" SCROLLTEXT_SUPPORT y + +choice 'Scrolltext Font' \ + 'Arial_8 font_arial8 \ + Small_6 font_small6 \ + Uni_53 font_uni53' \ + 'Arial_8' SCROLLTEXT_FONT + +int "Scrolltest buffer size" SCROLLTEXT_BUFFER_SIZE 128 +int "Scrolltext default delay" SCROLLTEXT_DELAY 60 + +int "Default x speed" SCROLL_X_SPEED 20 +int "Default y speed" SCROLL_Y_SPEED 20 + +string "Default text" SCROLLTEXT_TEXT "</#www.das-labor.org" + + + +endmenu diff --git a/scrolltext/font.h b/scrolltext/font.h new file mode 100644 index 0000000..904e134 --- /dev/null +++ b/scrolltext/font.h @@ -0,0 +1,21 @@ +#ifndef FONT_H +#define FONT_H +#ifdef AVR +# include <avr/pgmspace.h> +#else +# define PROGMEM +# define pgm_read_byte(B) *(B) +# define pgm_read_word(B) *(B) +#endif + +typedef struct{ + unsigned char fontHeight; + const unsigned int* fontIndex; + const unsigned char* fontData; + unsigned char glyph_beg; + unsigned char glyph_end; + unsigned char glyph_def; + unsigned char storebytes; +} font; + +#endif //FONT_H diff --git a/scrolltext/font_arial8.c b/scrolltext/font_arial8.c new file mode 100644 index 0000000..f473bf3 --- /dev/null +++ b/scrolltext/font_arial8.c @@ -0,0 +1,544 @@ +#include "font.h" + +unsigned int PROGMEM fontIndex_arial8[] = { + 0, /* */ + 2, /* ! */ + 4, /* " */ + 10, /* # */ + 20, /* $ */ + 30, /* % */ + 48, /* & */ + 60, /* ' */ + 62, /* ( */ + 68, /* ) */ + 74, /* * */ + 80, /* + */ + 90, /* , */ + 94, /* - */ + 100, /* . */ + 104, /* / */ + 110, /* 0 */ + 120, /* 1 */ + 126, /* 2 */ + 136, /* 3 */ + 146, /* 4 */ + 156, /* 5 */ + 166, /* 6 */ + 176, /* 7 */ + 186, /* 8 */ + 196, /* 9 */ + 206, /* : */ + 208, /* ; */ + 210, /* < */ + 220, /* = */ + 230, /* > */ + 240, /* ? */ + 250, /* @ */ + 270, /* A */ + 284, /* B */ + 296, /* C */ + 308, /* D */ + 320, /* E */ + 330, /* F */ + 340, /* G */ + 354, /* H */ + 366, /* I */ + 368, /* J */ + 376, /* K */ + 388, /* L */ + 398, /* M */ + 412, /* N */ + 424, /* O */ + 438, /* P */ + 448, /* Q */ + 462, /* R */ + 474, /* S */ + 486, /* T */ + 496, /* U */ + 508, /* V */ + 522, /* W */ + 542, /* X */ + 554, /* Y */ + 568, /* Z */ + 580, /* [ */ + 584, /* \ */ + 590, /* ] */ + 594, /* ^ */ + 604, /* _ */ + 616, /* ` */ + 620, /* a */ + 630, /* b */ + 640, /* c */ + 650, /* d */ + 660, /* e */ + 670, /* f */ + 676, /* g */ + 686, /* h */ + 696, /* i */ + 698, /* j */ + 700, /* k */ + 708, /* l */ + 710, /* m */ + 724, /* n */ + 734, /* o */ + 744, /* p */ + 754, /* q */ + 764, /* r */ + 770, /* s */ + 780, /* t */ + 784, /* u */ + 794, /* v */ + 804, /* w */ + 822, /* x */ + 832, /* y */ + 842, /* z */ + 852, /* { */ + 858, /* | */ + 860, /* } */ + 868, /* ~ */ + 878 +}; + +unsigned char PROGMEM fontData_arial8[] = { + 0x00, 0x00, /* */ + 0xfc, 0x02, /* # ###### */ + 0x1c, 0x00, /* ### */ + 0x00, 0x00, /* */ + 0x1c, 0x00, /* ### */ + 0x90, 0x03, /* ### # */ + 0xf0, 0x00, /* #### */ + 0x9c, 0x03, /* ### ### */ + 0xf0, 0x00, /* #### */ + 0x9c, 0x00, /* # ### */ + 0x18, 0x01, /* # ## */ + 0x24, 0x02, /* # # # */ + 0xfc, 0x07, /* ######### */ + 0x24, 0x02, /* # # # */ + 0xc8, 0x01, /* ### # */ + 0x18, 0x00, /* ## */ + 0x24, 0x00, /* # # */ + 0x24, 0x02, /* # # # */ + 0x98, 0x01, /* ## ## */ + 0x60, 0x00, /* ## */ + 0x98, 0x01, /* ## ## */ + 0x44, 0x02, /* # # # */ + 0x40, 0x02, /* # # */ + 0x80, 0x01, /* ## */ + 0x80, 0x01, /* ## */ + 0x58, 0x02, /* # # ## */ + 0x24, 0x02, /* # # # */ + 0x64, 0x02, /* # ## # */ + 0x98, 0x01, /* ## ## */ + 0x80, 0x02, /* # # */ + 0x1c, 0x00, /* ### */ + 0xf0, 0x03, /* ###### */ + 0x08, 0x04, /* # # */ + 0x04, 0x08, /* # # */ + 0x04, 0x08, /* # # */ + 0x08, 0x04, /* # # */ + 0xf0, 0x03, /* ###### */ + 0x28, 0x00, /* # # */ + 0x1c, 0x00, /* ### */ + 0x28, 0x00, /* # # */ + 0x40, 0x00, /* # */ + 0x40, 0x00, /* # */ + 0xf0, 0x01, /* ##### */ + 0x40, 0x00, /* # */ + 0x40, 0x00, /* # */ + 0x00, 0x00, /* */ + 0x00, 0x0e, /* ### */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x00, 0x00, /* */ + 0x00, 0x02, /* # */ + 0x00, 0x03, /* ## */ + 0xf0, 0x00, /* #### */ + 0x0c, 0x00, /* ## */ + 0xf8, 0x01, /* ###### */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0xf8, 0x01, /* ###### */ + 0x10, 0x00, /* # */ + 0x08, 0x00, /* # */ + 0xfc, 0x03, /* ######## */ + 0x08, 0x02, /* # # */ + 0x04, 0x03, /* ## # */ + 0x84, 0x02, /* # # # */ + 0x44, 0x02, /* # # # */ + 0x38, 0x02, /* # ### */ + 0x08, 0x01, /* # # */ + 0x04, 0x02, /* # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xd8, 0x01, /* ### ## */ + 0xc0, 0x00, /* ## */ + 0xb0, 0x00, /* # ## */ + 0x88, 0x00, /* # # */ + 0xfc, 0x03, /* ######## */ + 0x80, 0x00, /* # */ + 0x30, 0x01, /* # ## */ + 0x2c, 0x02, /* # # ## */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xc4, 0x01, /* ### # */ + 0xf8, 0x01, /* ###### */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xc8, 0x01, /* ### # */ + 0x04, 0x00, /* # */ + 0x84, 0x03, /* ### # */ + 0x64, 0x00, /* ## # */ + 0x1c, 0x00, /* ### */ + 0x04, 0x00, /* # */ + 0xd8, 0x01, /* ### ## */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xd8, 0x01, /* ### ## */ + 0x38, 0x01, /* # ### */ + 0x44, 0x02, /* # # # */ + 0x44, 0x02, /* # # # */ + 0x44, 0x02, /* # # # */ + 0xf8, 0x01, /* ###### */ + 0x10, 0x02, /* # # */ + 0x10, 0x0e, /* ### # */ + 0x40, 0x00, /* # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0x10, 0x01, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0x10, 0x01, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0xa0, 0x00, /* # # */ + 0x40, 0x00, /* # */ + 0x08, 0x00, /* # */ + 0x04, 0x00, /* # */ + 0xc4, 0x02, /* # ## # */ + 0x24, 0x00, /* # # */ + 0x18, 0x00, /* ## */ + 0xe0, 0x03, /* ##### */ + 0x18, 0x04, /* # ## */ + 0xc8, 0x09, /* # ### # */ + 0x24, 0x0a, /* # # # # */ + 0x14, 0x0a, /* # # # # */ + 0x14, 0x09, /* # # # # */ + 0xe4, 0x0b, /* # ##### # */ + 0x34, 0x0a, /* # # ## # */ + 0x08, 0x05, /* # # # */ + 0xf0, 0x04, /* # #### */ + 0x00, 0x03, /* ## */ + 0xc0, 0x00, /* ## */ + 0xb8, 0x00, /* # ### */ + 0x84, 0x00, /* # # */ + 0xb8, 0x00, /* # ### */ + 0xc0, 0x00, /* ## */ + 0x00, 0x03, /* ## */ + 0xfc, 0x03, /* ######## */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xf8, 0x01, /* ###### */ + 0xf0, 0x00, /* #### */ + 0x08, 0x01, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x08, 0x01, /* # # */ + 0xfc, 0x03, /* ######## */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x08, 0x01, /* # # */ + 0xf0, 0x00, /* #### */ + 0xfc, 0x03, /* ######## */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0xfc, 0x03, /* ######## */ + 0x24, 0x00, /* # # */ + 0x24, 0x00, /* # # */ + 0x24, 0x00, /* # # */ + 0x04, 0x00, /* # */ + 0xf0, 0x00, /* #### */ + 0x08, 0x01, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x44, 0x02, /* # # # */ + 0x48, 0x01, /* # # # */ + 0xc0, 0x00, /* ## */ + 0xfc, 0x03, /* ######## */ + 0x20, 0x00, /* # */ + 0x20, 0x00, /* # */ + 0x20, 0x00, /* # */ + 0x20, 0x00, /* # */ + 0xfc, 0x03, /* ######## */ + 0xfc, 0x03, /* ######## */ + 0x80, 0x01, /* ## */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0xfc, 0x01, /* ####### */ + 0xfc, 0x03, /* ######## */ + 0x40, 0x00, /* # */ + 0x20, 0x00, /* # */ + 0x70, 0x00, /* ### */ + 0x88, 0x01, /* ## # */ + 0x04, 0x02, /* # # */ + 0xfc, 0x03, /* ######## */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0xfc, 0x03, /* ######## */ + 0x18, 0x00, /* ## */ + 0xe0, 0x00, /* ### */ + 0x00, 0x03, /* ## */ + 0xe0, 0x00, /* ### */ + 0x18, 0x00, /* ## */ + 0xfc, 0x03, /* ######## */ + 0xfc, 0x03, /* ######## */ + 0x08, 0x00, /* # */ + 0x30, 0x00, /* ## */ + 0xc0, 0x00, /* ## */ + 0x00, 0x01, /* # */ + 0xfc, 0x03, /* ######## */ + 0xf0, 0x00, /* #### */ + 0x08, 0x01, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x04, 0x02, /* # # */ + 0x08, 0x01, /* # # */ + 0xf0, 0x00, /* #### */ + 0xfc, 0x03, /* ######## */ + 0x44, 0x00, /* # # */ + 0x44, 0x00, /* # # */ + 0x44, 0x00, /* # # */ + 0x38, 0x00, /* ### */ + 0xf0, 0x00, /* #### */ + 0x08, 0x01, /* # # */ + 0x04, 0x02, /* # # */ + 0x84, 0x02, /* # # # */ + 0x84, 0x02, /* # # # */ + 0x08, 0x01, /* # # */ + 0xf0, 0x02, /* # #### */ + 0xfc, 0x03, /* ######## */ + 0x24, 0x00, /* # # */ + 0x24, 0x00, /* # # */ + 0x64, 0x00, /* ## # */ + 0xa4, 0x01, /* ## # # */ + 0x18, 0x02, /* # ## */ + 0x18, 0x01, /* # ## */ + 0x24, 0x02, /* # # # */ + 0x24, 0x02, /* # # # */ + 0x44, 0x02, /* # # # */ + 0x44, 0x02, /* # # # */ + 0x88, 0x01, /* ## # */ + 0x04, 0x00, /* # */ + 0x04, 0x00, /* # */ + 0xfc, 0x03, /* ######## */ + 0x04, 0x00, /* # */ + 0x04, 0x00, /* # */ + 0xfc, 0x01, /* ####### */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0xfc, 0x01, /* ####### */ + 0x0c, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0xc0, 0x00, /* ## */ + 0x00, 0x03, /* ## */ + 0xc0, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0x0c, 0x00, /* ## */ + 0xf0, 0x00, /* #### */ + 0x00, 0x03, /* ## */ + 0xc0, 0x00, /* ## */ + 0x38, 0x00, /* ### */ + 0x04, 0x00, /* # */ + 0x38, 0x00, /* ### */ + 0xc0, 0x00, /* ## */ + 0x00, 0x03, /* ## */ + 0xf0, 0x00, /* #### */ + 0x0c, 0x00, /* ## */ + 0x04, 0x02, /* # # */ + 0x98, 0x01, /* ## ## */ + 0x60, 0x00, /* ## */ + 0x60, 0x00, /* ## */ + 0x98, 0x01, /* ## ## */ + 0x04, 0x02, /* # # */ + 0x04, 0x00, /* # */ + 0x18, 0x00, /* ## */ + 0x20, 0x00, /* # */ + 0xc0, 0x03, /* #### */ + 0x20, 0x00, /* # */ + 0x18, 0x00, /* ## */ + 0x04, 0x00, /* # */ + 0x00, 0x02, /* # */ + 0x04, 0x03, /* ## # */ + 0xc4, 0x02, /* # ## # */ + 0x34, 0x02, /* # ## # */ + 0x0c, 0x02, /* # ## */ + 0x04, 0x02, /* # # */ + 0xfc, 0x0f, /* ########## */ + 0x04, 0x08, /* # # */ + 0x0c, 0x00, /* ## */ + 0xf0, 0x00, /* #### */ + 0x00, 0x03, /* ## */ + 0x04, 0x08, /* # # */ + 0xfc, 0x0f, /* ########## */ + 0x20, 0x00, /* # */ + 0x18, 0x00, /* ## */ + 0x04, 0x00, /* # */ + 0x18, 0x00, /* ## */ + 0x20, 0x00, /* # */ + 0x00, 0x08, /* # */ + 0x00, 0x08, /* # */ + 0x00, 0x08, /* # */ + 0x00, 0x08, /* # */ + 0x00, 0x08, /* # */ + 0x00, 0x08, /* # */ + 0x04, 0x00, /* # */ + 0x08, 0x00, /* # */ + 0xa0, 0x01, /* ## # */ + 0x50, 0x02, /* # # # */ + 0x50, 0x02, /* # # # */ + 0x50, 0x01, /* # # # */ + 0xe0, 0x03, /* ##### */ + 0xfc, 0x03, /* ######## */ + 0x20, 0x01, /* # # */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0xe0, 0x01, /* #### */ + 0xe0, 0x01, /* #### */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0x20, 0x01, /* # # */ + 0xe0, 0x01, /* #### */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0x20, 0x01, /* # # */ + 0xfc, 0x03, /* ######## */ + 0xe0, 0x01, /* #### */ + 0x50, 0x02, /* # # # */ + 0x50, 0x02, /* # # # */ + 0x50, 0x02, /* # # # */ + 0x60, 0x01, /* # ## */ + 0x10, 0x00, /* # */ + 0xf8, 0x03, /* ####### */ + 0x14, 0x00, /* # # */ + 0xe0, 0x09, /* # #### */ + 0x10, 0x0a, /* # # # */ + 0x10, 0x0a, /* # # # */ + 0x20, 0x09, /* # # # */ + 0xf0, 0x07, /* ####### */ + 0xfc, 0x03, /* ######## */ + 0x20, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0xe0, 0x03, /* ##### */ + 0xf4, 0x03, /* ###### # */ + 0xf4, 0x07, /* ####### # */ + 0xfc, 0x03, /* ######## */ + 0x40, 0x00, /* # */ + 0xa0, 0x01, /* ## # */ + 0x10, 0x02, /* # # */ + 0xfc, 0x03, /* ######## */ + 0xf0, 0x03, /* ###### */ + 0x20, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0xf0, 0x03, /* ###### */ + 0x20, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0xe0, 0x03, /* ##### */ + 0xf0, 0x03, /* ###### */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0xe0, 0x03, /* ##### */ + 0xe0, 0x01, /* #### */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0xe0, 0x01, /* #### */ + 0xf0, 0x0f, /* ######## */ + 0x20, 0x01, /* # # */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0xe0, 0x01, /* #### */ + 0xe0, 0x01, /* #### */ + 0x10, 0x02, /* # # */ + 0x10, 0x02, /* # # */ + 0x20, 0x01, /* # # */ + 0xf0, 0x0f, /* ######## */ + 0xf0, 0x03, /* ###### */ + 0x20, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x20, 0x01, /* # # */ + 0x50, 0x02, /* # # # */ + 0x50, 0x02, /* # # # */ + 0x90, 0x02, /* # # # */ + 0x20, 0x01, /* # # */ + 0xfc, 0x03, /* ######## */ + 0x10, 0x02, /* # # */ + 0xf0, 0x01, /* ##### */ + 0x00, 0x02, /* # */ + 0x00, 0x02, /* # */ + 0x00, 0x01, /* # */ + 0xf0, 0x03, /* ###### */ + 0x30, 0x00, /* ## */ + 0xc0, 0x00, /* ## */ + 0x00, 0x03, /* ## */ + 0xc0, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0xc0, 0x00, /* ## */ + 0x00, 0x03, /* ## */ + 0xe0, 0x00, /* ### */ + 0x10, 0x00, /* # */ + 0xe0, 0x00, /* ### */ + 0x00, 0x03, /* ## */ + 0xc0, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0x10, 0x02, /* # # */ + 0x20, 0x01, /* # # */ + 0xc0, 0x00, /* ## */ + 0x20, 0x01, /* # # */ + 0x10, 0x02, /* # # */ + 0x10, 0x00, /* # */ + 0xe0, 0x09, /* # #### */ + 0x00, 0x07, /* ### */ + 0xc0, 0x00, /* ## */ + 0x30, 0x00, /* ## */ + 0x10, 0x02, /* # # */ + 0x10, 0x03, /* ## # */ + 0x90, 0x02, /* # # # */ + 0x70, 0x02, /* # ### */ + 0x10, 0x02, /* # # */ + 0x40, 0x00, /* # */ + 0xb8, 0x07, /* #### ### */ + 0x04, 0x08, /* # # */ + 0xfc, 0x0f, /* ########## */ + 0x00, 0x00, /* */ + 0x04, 0x08, /* # # */ + 0xb8, 0x07, /* #### ### */ + 0x40, 0x00, /* # */ + 0x60, 0x00, /* ## */ + 0x20, 0x00, /* # */ + 0x60, 0x00, /* ## */ + 0x40, 0x00, /* # */ + 0x20, 0x00, /* # */ +}; + +font font_arial8 = {13, fontIndex_arial8, fontData_arial8, ' ', '~', '.', 2}; diff --git a/scrolltext/font_arial8.h b/scrolltext/font_arial8.h new file mode 100644 index 0000000..b9fb486 --- /dev/null +++ b/scrolltext/font_arial8.h @@ -0,0 +1,8 @@ +#ifndef FONT_ARIAL8_H +#define FONT_ARIAL8_H + +#include "font.h" +extern font font_arial8; + +#endif /* FONT_ARIAL8_H */ + diff --git a/scrolltext/font_small6.c b/scrolltext/font_small6.c new file mode 100644 index 0000000..7a22f13 --- /dev/null +++ b/scrolltext/font_small6.c @@ -0,0 +1,439 @@ +#include "font.h" + +unsigned int PROGMEM fontIndex_small6[] = { + 0, /* */ + 1, /* ! */ + 2, /* " */ + 5, /* # */ + 10, /* $ */ + 13, /* % */ + 17, /* & */ + 21, /* ' */ + 22, /* ( */ + 24, /* ) */ + 26, /* * */ + 28, /* + */ + 31, /* , */ + 32, /* - */ + 34, /* . */ + 35, /* / */ + 37, /* 0 */ + 41, /* 1 */ + 43, /* 2 */ + 47, /* 3 */ + 51, /* 4 */ + 55, /* 5 */ + 58, /* 6 */ + 62, /* 7 */ + 65, /* 8 */ + 69, /* 9 */ + 73, /* : */ + 74, /* ; */ + 75, /* < */ + 78, /* = */ + 81, /* > */ + 84, /* ? */ + 88, /* @ */ + 95, /* A */ + 100, /* B */ + 105, /* C */ + 110, /* D */ + 115, /* E */ + 119, /* F */ + 123, /* G */ + 128, /* H */ + 132, /* I */ + 133, /* J */ + 136, /* K */ + 140, /* L */ + 143, /* M */ + 150, /* N */ + 155, /* O */ + 160, /* P */ + 164, /* Q */ + 169, /* R */ + 174, /* S */ + 178, /* T */ + 182, /* U */ + 187, /* V */ + 192, /* W */ + 199, /* X */ + 204, /* Y */ + 209, /* Z */ + 213, /* [ */ + 215, /* \ */ + 217, /* ] */ + 219, /* ^ */ + 222, /* _ */ + 226, /* ` */ + 228, /* a */ + 231, /* b */ + 235, /* c */ + 238, /* d */ + 242, /* e */ + 245, /* f */ + 247, /* g */ + 251, /* h */ + 254, /* i */ + 255, /* j */ + 256, /* k */ + 259, /* l */ + 260, /* m */ + 265, /* n */ + 268, /* o */ + 272, /* p */ + 276, /* q */ + 280, /* r */ + 282, /* s */ + 285, /* t */ + 287, /* u */ + 290, /* v */ + 293, /* w */ + 298, /* x */ + 301, /* y */ + 304, /* z */ + 307, /* { */ + 309, /* | */ + 310, /* } */ + 312, /* ~ */ + 316, /* ß */ + 321, /* ä */ + 324, /* ö */ + 328, /* ü */ + 331 +}; + +unsigned char PROGMEM fontData_small6[] = { + 0x00, /* */ + 0x2f, /* # #### */ + 0x03, /* ## */ + 0x00, /* */ + 0x03, /* ## */ + 0x12, /* # # */ + 0x3f, /* ###### */ + 0x12, /* # # */ + 0x3f, /* ###### */ + 0x12, /* # # */ + 0x26, /* # ## */ + 0x7f, /* ####### */ + 0x32, /* ## # */ + 0x13, /* # ## */ + 0x0b, /* # ## */ + 0x34, /* ## # */ + 0x32, /* ## # */ + 0x1a, /* ## # */ + 0x25, /* # # # */ + 0x1a, /* ## # */ + 0x28, /* # # */ + 0x03, /* ## */ + 0x7e, /* ###### */ + 0x81, /* # # */ + 0x81, /* # # */ + 0x7e, /* ###### */ + 0x03, /* ## */ + 0x03, /* ## */ + 0x08, /* # */ + 0x1c, /* ### */ + 0x08, /* # */ + 0x60, /* ## */ + 0x08, /* # */ + 0x08, /* # */ + 0x20, /* # */ + 0x38, /* ### */ + 0x07, /* ### */ + 0x1e, /* #### */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x1e, /* #### */ + 0x02, /* # */ + 0x3f, /* ###### */ + 0x32, /* ## # */ + 0x29, /* # # # */ + 0x29, /* # # # */ + 0x26, /* # ## */ + 0x12, /* # # */ + 0x21, /* # # */ + 0x25, /* # # # */ + 0x1a, /* ## # */ + 0x18, /* ## */ + 0x16, /* # ## */ + 0x3f, /* ###### */ + 0x10, /* # */ + 0x27, /* # ### */ + 0x25, /* # # # */ + 0x19, /* ## # */ + 0x1e, /* #### */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x18, /* ## */ + 0x01, /* # */ + 0x3d, /* #### # */ + 0x03, /* ## */ + 0x1a, /* ## # */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x1a, /* ## # */ + 0x12, /* # # */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x1e, /* #### */ + 0x24, /* # # */ + 0x64, /* ## # */ + 0x08, /* # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x08, /* # */ + 0x02, /* # */ + 0x29, /* # # # */ + 0x05, /* # # */ + 0x02, /* # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x49, /* # # # */ + 0x55, /* # # # # */ + 0x59, /* # ## # */ + 0x12, /* # # */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x0b, /* # ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x3f, /* ###### */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x1a, /* ## # */ + 0x1e, /* #### */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x12, /* # # */ + 0x3f, /* ###### */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x1e, /* #### */ + 0x3f, /* ###### */ + 0x25, /* # # # */ + 0x25, /* # # # */ + 0x21, /* # # */ + 0x3f, /* ###### */ + 0x05, /* # # */ + 0x05, /* # # */ + 0x01, /* # */ + 0x1e, /* #### */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x29, /* # # # */ + 0x3a, /* ### # */ + 0x3f, /* ###### */ + 0x04, /* # */ + 0x04, /* # */ + 0x3f, /* ###### */ + 0x3f, /* ###### */ + 0x30, /* ## */ + 0x20, /* # */ + 0x1f, /* ##### */ + 0x3f, /* ###### */ + 0x0c, /* ## */ + 0x12, /* # # */ + 0x21, /* # # */ + 0x3f, /* ###### */ + 0x20, /* # */ + 0x20, /* # */ + 0x3f, /* ###### */ + 0x03, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x03, /* ## */ + 0x3f, /* ###### */ + 0x3f, /* ###### */ + 0x03, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x3f, /* ###### */ + 0x1e, /* #### */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x21, /* # # */ + 0x1e, /* #### */ + 0x3f, /* ###### */ + 0x09, /* # # */ + 0x09, /* # # */ + 0x06, /* ## */ + 0x1e, /* #### */ + 0x21, /* # # */ + 0x29, /* # # # */ + 0x11, /* # # */ + 0x2e, /* # ### */ + 0x3f, /* ###### */ + 0x09, /* # # */ + 0x09, /* # # */ + 0x09, /* # # */ + 0x36, /* ## ## */ + 0x12, /* # # */ + 0x25, /* # # # */ + 0x29, /* # # # */ + 0x12, /* # # */ + 0x01, /* # */ + 0x3f, /* ###### */ + 0x01, /* # */ + 0x01, /* # */ + 0x1f, /* ##### */ + 0x20, /* # */ + 0x20, /* # */ + 0x20, /* # */ + 0x1f, /* ##### */ + 0x03, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x03, /* ## */ + 0x03, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x03, /* ## */ + 0x21, /* # # */ + 0x12, /* # # */ + 0x0c, /* ## */ + 0x12, /* # # */ + 0x21, /* # # */ + 0x01, /* # */ + 0x02, /* # */ + 0x3c, /* #### */ + 0x02, /* # */ + 0x01, /* # */ + 0x31, /* ## # */ + 0x29, /* # # # */ + 0x25, /* # # # */ + 0x23, /* # ## */ + 0x7f, /* ####### */ + 0x41, /* # # */ + 0x07, /* ### */ + 0x38, /* ### */ + 0x41, /* # # */ + 0x7f, /* ####### */ + 0x02, /* # */ + 0x01, /* # */ + 0x02, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x00, /* */ + 0x01, /* # */ + 0x14, /* # # */ + 0x24, /* # # */ + 0x38, /* ### */ + 0x3f, /* ###### */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x3f, /* ###### */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x28, /* # # */ + 0x3e, /* ##### */ + 0x05, /* # # */ + 0x18, /* ## */ + 0xa4, /* # # # */ + 0xa4, /* # # # */ + 0x7c, /* ##### */ + 0x3f, /* ###### */ + 0x04, /* # */ + 0x38, /* ### */ + 0x3d, /* #### # */ + 0xfd, /* ###### # */ + 0x3f, /* ###### */ + 0x08, /* # */ + 0x34, /* ## # */ + 0x3f, /* ###### */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x38, /* ### */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x38, /* ### */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0xfc, /* ###### */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0xfc, /* ###### */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x28, /* # # */ + 0x24, /* # # */ + 0x14, /* # # */ + 0x1e, /* #### */ + 0x24, /* # # */ + 0x1c, /* ### */ + 0x20, /* # */ + 0x3c, /* #### */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x30, /* ## */ + 0x0c, /* ## */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x9c, /* # ### */ + 0x60, /* ## */ + 0x1c, /* ### */ + 0x34, /* ## # */ + 0x24, /* # # */ + 0x2c, /* # ## */ + 0x08, /* # */ + 0x77, /* ### ### */ + 0x7f, /* ####### */ + 0x77, /* ### ### */ + 0x08, /* # */ + 0x01, /* # */ + 0x02, /* # */ + 0x01, /* # */ + 0x02, /* # */ + 0x3e, /* ##### */ + 0x05, /* # # */ + 0x26, /* # ## */ + 0x18, /* ## */ + 0x19, /* ## # */ + 0x24, /* # # */ + 0x29, /* # # # */ + 0x19, /* ## # */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x19, /* ## # */ + 0x1d, /* ### # */ + 0x20, /* # */ + 0x3d, /* #### # */ +}; + +font font_small6 = {8, fontIndex_small6, fontData_small6, ' ', '~', '.', 1}; diff --git a/scrolltext/font_small6.h b/scrolltext/font_small6.h new file mode 100644 index 0000000..d07d301 --- /dev/null +++ b/scrolltext/font_small6.h @@ -0,0 +1,7 @@ +#ifndef FONT_SMALL6_H +#define FONT_SMALL6_H + +#include "font.h" +extern font font_small6; + +#endif /* FONT_SMALL6_H_ */ diff --git a/scrolltext/font_uni53.c b/scrolltext/font_uni53.c new file mode 100644 index 0000000..ed54e91 --- /dev/null +++ b/scrolltext/font_uni53.c @@ -0,0 +1,503 @@ +#include "font.h" + +static unsigned int PROGMEM fontIndex_uni53[] = { 0, /* */ + 1, /* ! */ + 3, /* " */ + 6, /* # */ + 11, /* $ */ + 16, /* % */ + 21, /* & */ + 27, /* ' */ + 28, /* ( */ + 30, /* ) */ + 32, /* * */ + 37, /* + */ + 42, /* , */ + 44, /* - */ + 48, /* . */ + 49, /* / */ + 54, /* 0 */ + 59, /* 1 */ + 61, /* 2 */ + 66, /* 3 */ + 71, /* 4 */ + 76, /* 5 */ + 81, /* 6 */ + 86, /* 7 */ + 90, /* 8 */ + 95, /* 9 */ + 100, /* : */ + 102, /* ; */ + 104, /* < */ + 107, /* = */ + 112, /* > */ + 115, /* ? */ + 119, /* @ */ + 124, /* A */ + 129, /* B */ + 134, /* C */ + 139, /* D */ + 144, /* E */ + 149, /* F */ + 154, /* G */ + 159, /* H */ + 164, /* I */ + 165, /* J */ + 169, /* K */ + 174, /* L */ + 178, /* M */ + 183, /* N */ + 188, /* O */ + 193, /* P */ + 198, /* Q */ + 203, /* R */ + 208, /* S */ + 213, /* T */ + 218, /* U */ + 223, /* V */ + 228, /* W */ + 235, /* X */ + 240, /* Y */ + 245, /* Z */ + 250, /* [ */ + 252, /* \ */ + 257, /* ] */ + 259, /* ^ */ + 262, /* _ */ + 267, /* ` */ + 269, /* a */ + 273, /* b */ + 277, /* c */ + 281, /* d */ + 285, /* e */ + 289, /* f */ + 291, /* g */ + 295, /* h */ + 299, /* i */ + 300, /* j */ + 302, /* k */ + 306, /* l */ + 307, /* m */ + 314, /* n */ + 318, /* o */ + 322, /* p */ + 326, /* q */ + 330, /* r */ + 333, /* s */ + 337, /* t */ + 340, /* u */ + 344, /* v */ + 348, /* w */ + 355, /* x */ + 359, /* y */ + 363, /* z */ + 367, /* { */ + 370, /* | */ + 372, /* } */ + 375, /* ~ */ + 379, /* ß */ + 383, /* ä */ + 387, /* ö */ + 391, /* ü */ + 395 +}; + +static unsigned char PROGMEM fontData_uni53[] = { + 0x00, /* */ + 0x00, /* */ + 0x2e, /* # ### */ + 0x06, /* ## */ + 0x00, /* */ + 0x06, /* ## */ + 0x14, /* # # */ + 0x3e, /* ##### */ + 0x14, /* # # */ + 0x3e, /* ##### */ + 0x14, /* # # */ + 0x24, /* # # */ + 0x2a, /* # # # */ + 0x6b, /* ## # ## */ + 0x2a, /* # # # */ + 0x12, /* # # */ + 0x22, /* # # */ + 0x10, /* # */ + 0x08, /* # */ + 0x04, /* # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x24, /* # # */ + 0x10, /* # */ + 0x06, /* ## */ + 0x3e, /* ##### */ + 0x41, /* # # */ + 0x41, /* # # */ + 0x3e, /* ##### */ + 0x08, /* # */ + 0x2a, /* # # # */ + 0x1c, /* ### */ + 0x2a, /* # # # */ + 0x08, /* # */ + 0x08, /* # */ + 0x08, /* # */ + 0x3e, /* ##### */ + 0x08, /* # */ + 0x08, /* # */ + 0x80, /* # */ + 0x60, /* ## */ + 0x08, /* # */ + 0x08, /* # */ + 0x08, /* # */ + 0x08, /* # */ + 0x20, /* # */ + 0x20, /* # */ + 0x10, /* # */ + 0x08, /* # */ + 0x04, /* # */ + 0x02, /* # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x1c, /* ### */ + 0x02, /* # */ + 0x3e, /* ##### */ + 0x32, /* ## # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2c, /* # ## */ + 0x22, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x14, /* # # */ + 0x0e, /* ### */ + 0x08, /* # */ + 0x08, /* # */ + 0x08, /* # */ + 0x3e, /* ##### */ + 0x2e, /* # ### */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x12, /* # # */ + 0x1c, /* ### */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x10, /* # */ + 0x02, /* # */ + 0x02, /* # */ + 0x32, /* ## # */ + 0x0e, /* ### */ + 0x14, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x14, /* # # */ + 0x04, /* # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x1c, /* ### */ + 0x00, /* */ + 0x14, /* # # */ + 0x80, /* # */ + 0x64, /* ## # */ + 0x08, /* # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x08, /* # */ + 0x02, /* # */ + 0x2a, /* # # # */ + 0x0a, /* # # */ + 0x04, /* # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x0c, /* ## */ + 0x3c, /* #### */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x3c, /* #### */ + 0x3e, /* ##### */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x14, /* # # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x3e, /* ##### */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x1c, /* ### */ + 0x3e, /* ##### */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x22, /* # # */ + 0x3e, /* ##### */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x02, /* # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x3a, /* ### # */ + 0x3e, /* ##### */ + 0x08, /* # */ + 0x08, /* # */ + 0x08, /* # */ + 0x3e, /* ##### */ + 0x3e, /* ##### */ + 0x10, /* # */ + 0x20, /* # */ + 0x20, /* # */ + 0x1e, /* #### */ + 0x3e, /* ##### */ + 0x08, /* # */ + 0x08, /* # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x3e, /* ##### */ + 0x20, /* # */ + 0x20, /* # */ + 0x20, /* # */ + 0x3e, /* ##### */ + 0x04, /* # */ + 0x08, /* # */ + 0x04, /* # */ + 0x3e, /* ##### */ + 0x3e, /* ##### */ + 0x04, /* # */ + 0x08, /* # */ + 0x10, /* # */ + 0x3e, /* ##### */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x1c, /* ### */ + 0x3e, /* ##### */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x04, /* # */ + 0x1c, /* ### */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x22, /* # # */ + 0x5c, /* # ### */ + 0x3e, /* ##### */ + 0x0a, /* # # */ + 0x0a, /* # # */ + 0x1a, /* ## # */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x2a, /* # # # */ + 0x12, /* # # */ + 0x02, /* # */ + 0x02, /* # */ + 0x3e, /* ##### */ + 0x02, /* # */ + 0x02, /* # */ + 0x1e, /* #### */ + 0x20, /* # */ + 0x20, /* # */ + 0x20, /* # */ + 0x1e, /* #### */ + 0x0e, /* ### */ + 0x10, /* # */ + 0x20, /* # */ + 0x10, /* # */ + 0x0e, /* ### */ + 0x1e, /* #### */ + 0x20, /* # */ + 0x20, /* # */ + 0x1e, /* #### */ + 0x20, /* # */ + 0x20, /* # */ + 0x1e, /* #### */ + 0x22, /* # # */ + 0x14, /* # # */ + 0x08, /* # */ + 0x14, /* # # */ + 0x22, /* # # */ + 0x02, /* # */ + 0x04, /* # */ + 0x38, /* ### */ + 0x04, /* # */ + 0x02, /* # */ + 0x22, /* # # */ + 0x32, /* ## # */ + 0x2a, /* # # # */ + 0x26, /* # ## */ + 0x22, /* # # */ + 0x7f, /* ####### */ + 0x41, /* # # */ + 0x02, /* # */ + 0x04, /* # */ + 0x08, /* # */ + 0x10, /* # */ + 0x20, /* # */ + 0x41, /* # # */ + 0x7f, /* ####### */ + 0x04, /* # */ + 0x02, /* # */ + 0x04, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x40, /* # */ + 0x02, /* # */ + 0x04, /* # */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x38, /* ### */ + 0x3e, /* ##### */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x3e, /* ##### */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x34, /* ## # */ + 0x2c, /* # ## */ + 0x3c, /* #### */ + 0x0a, /* # # */ + 0x18, /* ## */ + 0xa4, /* # # # */ + 0xa4, /* # # # */ + 0x78, /* #### */ + 0x3e, /* ##### */ + 0x04, /* # */ + 0x04, /* # */ + 0x38, /* ### */ + 0x3a, /* ### # */ + 0x80, /* # */ + 0x7a, /* #### # */ + 0x3e, /* ##### */ + 0x10, /* # */ + 0x08, /* # */ + 0x34, /* ## # */ + 0x3e, /* ##### */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x04, /* # */ + 0x38, /* ### */ + 0x04, /* # */ + 0x04, /* # */ + 0x38, /* ### */ + 0x3c, /* #### */ + 0x04, /* # */ + 0x04, /* # */ + 0x38, /* ### */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0xfc, /* ###### */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x24, /* # # */ + 0xfc, /* ###### */ + 0x3c, /* #### */ + 0x08, /* # */ + 0x04, /* # */ + 0x28, /* # # */ + 0x2c, /* # ## */ + 0x34, /* ## # */ + 0x14, /* # # */ + 0x04, /* # */ + 0x3e, /* ##### */ + 0x04, /* # */ + 0x1c, /* ### */ + 0x20, /* # */ + 0x20, /* # */ + 0x3c, /* #### */ + 0x1c, /* ### */ + 0x20, /* # */ + 0x20, /* # */ + 0x1c, /* ### */ + 0x1c, /* ### */ + 0x20, /* # */ + 0x20, /* # */ + 0x1c, /* ### */ + 0x20, /* # */ + 0x20, /* # */ + 0x1c, /* ### */ + 0x24, /* # # */ + 0x18, /* ## */ + 0x18, /* ## */ + 0x24, /* # # */ + 0x1c, /* ### */ + 0xa0, /* # # */ + 0xa0, /* # # */ + 0x7c, /* ##### */ + 0x24, /* # # */ + 0x34, /* ## # */ + 0x2c, /* # ## */ + 0x24, /* # # */ + 0x08, /* # */ + 0x36, /* ## ## */ + 0x41, /* # # */ + 0x00, /* */ + 0x7f, /* ####### */ + 0x41, /* # # */ + 0x36, /* ## ## */ + 0x08, /* # */ + 0x08, /* # */ + 0x04, /* # */ + 0x08, /* # */ + 0x04, /* # */ + 0x3c, /* #### */ + 0x02, /* # */ + 0x2a, /* # # # */ + 0x14, /* # # */ + 0x19, /* ## # */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x39, /* ### # */ + 0x19, /* ## # */ + 0x24, /* # # */ + 0x24, /* # # */ + 0x19, /* ## # */ + 0x1d, /* ### # */ + 0x20, /* # */ + 0x20, /* # */ + 0x3d, /* #### # */ +}; + +font font_uni53 = {8, fontIndex_uni53, fontData_uni53, ' ', '~', '.', 1}; diff --git a/scrolltext/font_uni53.h b/scrolltext/font_uni53.h new file mode 100644 index 0000000..cfd7b6a --- /dev/null +++ b/scrolltext/font_uni53.h @@ -0,0 +1,8 @@ +#ifndef FONT_UNI53_H_ +#define FONT_UNI53_H_ + +#include "font.h" +extern font font_uni53; + +#endif /* FONT_UNI53_H_ */ + diff --git a/scrolltext/scrolltext.h b/scrolltext/scrolltext.h new file mode 100644 index 0000000..9f73d05 --- /dev/null +++ b/scrolltext/scrolltext.h @@ -0,0 +1,6 @@ +#ifndef SCROLLTEXT_H_ +#define SCROLLTEXT_H_ + +void scrolltext(char *str); + +#endif /* SCROLLTEXT_H_ */ diff --git a/scrolltext/scrolltext3.c b/scrolltext/scrolltext3.c new file mode 100644 index 0000000..e071b30 --- /dev/null +++ b/scrolltext/scrolltext3.c @@ -0,0 +1,578 @@ +#define SCROLLTEXT_C + +#include <stdlib.h> +#include <string.h> +#include <setjmp.h> + +#include "../config.h" +#include "scrolltext.h" +#ifdef AVR +# include "../borg_hw/borg_hw.h" +#endif + +#include "../pixel.h" +#include "../util.h" +#include "font_arial8.h" +#include "font_small6.h" +#include "font_uni53.h" + +#define MAX_FONTS 1 +font fonts[MAX_FONTS]; +#define MAX_SPECIALCOLORS 3 +unsigned char PROGMEM colorTable[MAX_SPECIALCOLORS*NUM_ROWS] = {1, 1, 2, 3, 3, 2, 1, 1, + 3, 3, 2, 1, 1, 2, 3, 3, + 3, 3, 2, 2, 3, 3, 2, 2 +}; + +char default_text[] PROGMEM = SCROLLTEXT_TEXT; +char scrolltext_text[SCROLLTEXT_BUFFER_SIZE]; + +/* Konzept + ======= +Text wird in Token unterteilt, jeder Token bekommt einen Command-String. +z.B. + +#b</#LABOR + +Es werden die Zeiger aus dem Eingabestring direkt übernommen, mit Stringlen. +Wenn der Command abgearbeitet ist wird automatisch das nächste Token eingelesen. + + */ + + +unsigned char (*text_pixmap)[NUM_ROWS][LINEBYTES]; + +void text_setpixel(pixel p, unsigned char value ){ + if(value){ + (*text_pixmap)[p.y%NUM_ROWS][p.x/8] |= shl_table[p.x%8]; + } +} + +void clear_text_pixmap(unsigned char value){ + unsigned char y, z; + for(y=0;y<NUM_ROWS;y++){ + for(z=0;z<LINEBYTES;z++){ + (*text_pixmap)[y][z] = 0; + } + } + +} + +void update_pixmap(){ + unsigned char x, y, z; + for(x=0;x<NUMPLANE;x++){ + for(y=0;y<NUM_ROWS;y++){ + for(z=0;z<LINEBYTES;z++){ + pixmap[x][y][z] = (*text_pixmap)[y][z]; + } + } + } +} + +enum waitfor_e{ + wait_new, + wait_posy, + wait_posx, + wait_out, + wait_timer, + wait_col_l, + wait_col_r +}; +#define DIRECTION_RIGHT 0x01 +#define DIRECTION_DOWN 0x02 + +struct blob_t_struct; +typedef struct blob_t_struct{ + struct blob_t_struct * next, * last; + char *str; + char *commands; + enum waitfor_e waitfor; + int sizex; + char sizey; + int posx; + char posy; + int tox; + char toy; + unsigned char delayx, delayx_rld; + unsigned char delayy, delayy_rld; + unsigned char delayb, delayb_rld; + unsigned char visible; + unsigned char direction; + unsigned int timer; + + const unsigned int* fontIndex; + const unsigned char* fontData; + unsigned char font_storebytes;/*bytes per char*/ + unsigned char space; +}blob_t; + + +/* +void showBlob(blob_t * blob){ + unsigned char * str = blob->str; + unsigned char tmp[200], x=0; + while(*str){ + tmp[x++] = (*str++) + ' ' -1; + } + tmp[x] = 0; + printf("this:\t%x\n",blob); + printf("last:\t%x\n",blob->last); + printf("next:\t%x\n",blob->next); + printf("str:\t%s\n",tmp); + printf("cmd:\t%s\n",blob->commands); + printf("sizex\t%d\n",blob->sizex); + printf("posx\t%d\n",blob->posx); + printf("posy\t%d\n",blob->posy); + printf("tox\t%d\n",blob->tox); + printf("toy\t%d\n",blob->toy); + printf("delayy_rld\t%d\n",blob->delayx_rld); + printf("delayx_rld\t%d\n",blob->delayy_rld); + printf("timer\t%d\n",blob->timer); + printf("\n"); +} +*/ + + +#define PW(a) pgm_read_word(&(a)) +#define PB(a) pgm_read_byte(&(a)) + +unsigned int getLen(blob_t *blob) { + unsigned char glyph; + unsigned int strLen = 0; + unsigned char * str = (unsigned char*)blob->str; + uint8_t space = blob->space * blob->font_storebytes; + + while ((glyph = *str++)) { + glyph -= 1; + strLen += PW(blob->fontIndex[glyph+1]) - PW(blob->fontIndex[glyph]); + strLen += space; + } + return strLen/blob->font_storebytes; +} + + +unsigned int getnum(blob_t * blob){ + unsigned int num=0; + unsigned char gotnum = 0; + + while( (*blob->commands >= '0') && (*blob->commands <='9') ){ + gotnum = 1; + num *= 10; + num += *blob->commands - '0'; + blob->commands++; + } + + if(gotnum){ + return num; + }else{ + return 0xffff; + } +} + +unsigned char blobNextCommand(blob_t * blob){ + unsigned int tmp; + unsigned char retval = 0; + while(*blob->commands != 0){ + switch (*blob->commands++){ + case '<': + blob->direction &= ~DIRECTION_RIGHT; + if((tmp = getnum(blob)) != 0xFFFF){ + blob->delayx_rld = tmp; + }else{ + blob->delayx_rld = SCROLL_X_SPEED; + } + blob->delayx = blob->delayx_rld; + break; + case '>': + blob->direction |= DIRECTION_RIGHT; + if((tmp = getnum(blob)) != 0xFFFF){ + blob->delayx_rld = tmp; + }else{ + blob->delayx_rld = SCROLL_X_SPEED; + } + blob->delayx = blob->delayx_rld; + break; + case 'd': + blob->direction |= DIRECTION_DOWN; + if((tmp = getnum(blob)) != 0xFFFF){ + blob->delayy_rld = tmp; + }else{ + blob->delayy_rld = SCROLL_Y_SPEED; + } + blob->delayy = blob->delayy_rld; + break; + case 'u': + blob->direction &= ~DIRECTION_DOWN; + if((tmp = getnum(blob)) != 0xFFFF){ + blob->delayy_rld = tmp; + }else{ + blob->delayy_rld = SCROLL_Y_SPEED; + } + blob->delayy = blob->delayy_rld; + break; + case 'x'://Place string at this x Position + if((tmp = getnum(blob)) != 0xFFFF){ + blob->posx = tmp; + }else{ + blob->posx = NUM_COLS/2 + blob->sizex/2; + } + break; + case 'y'://Place string at this y Position + if((tmp = getnum(blob)) != 0xFFFF){ + blob->posy = tmp - blob->sizey; + } + break; + case 'b'://blink blob + if((tmp = getnum(blob)) != 0xFFFF){ + blob->delayb_rld = tmp; + }else{ + blob->delayb_rld = 50; + } + blob->delayb = blob->delayb_rld; + break; + case '|': + if((tmp = getnum(blob)) != 0xFFFF){ + blob->tox = tmp; + }else{ + blob->tox = (NUM_COLS - 2 + blob->sizex)/2; + } + blob->waitfor = wait_posx; + return retval; + break; + case '-': + if((tmp = getnum(blob)) != 0xFFFF){ + blob->toy = tmp; + }else{ + blob->toy = (NUM_ROWS-blob->sizey) / 2; + } + blob->waitfor = wait_posy; + return retval; + break; + case 'p': + blob->delayx_rld = 0; + blob->delayy_rld = 0; + if((tmp = getnum(blob)) != 0xFFFF){ + blob->timer = tmp*64; + }else{ + blob->timer = 30*64; + } + blob->waitfor = wait_timer; + return retval; + break; + case '/': + blob->waitfor = wait_out; + return retval; + break; + case ';': + blob->waitfor = wait_col_l; + return (retval); + break; + case ':': + blob->waitfor = wait_col_r; + return (retval); + break; + case '+': + retval = 2; + break; + } + } + return 1;//this blob is finished, and can be deleted. +} + + +blob_t * setupBlob(char * str){ + /*char * strtok_r ( char * string, const char * delim, char ** last)*/ + static unsigned char chop_cnt; + static char *last; static char delim[] = "#"; + static char *lastcommands; + unsigned int tmp; + + if(str){ + chop_cnt = 0; + } + + blob_t *blob = malloc(sizeof (blob_t)); + + if(!chop_cnt){ + blob->commands = strtok_r (str, delim, &last); + if( blob->commands == 0) goto fail; + + if((tmp = getnum(blob)) != 0xFFFF){ + chop_cnt = tmp; + lastcommands = blob->commands; + } + } + + if(chop_cnt){ + chop_cnt--; + blob->commands = lastcommands; + } + + blob->str = strtok_r (0, delim, &last); + + if ( blob->str == 0) goto fail; + + blob->fontIndex = fonts[0].fontIndex; + blob->fontData = fonts[0].fontData; + blob->font_storebytes = fonts[0].storebytes; + + unsigned char tmp1, *strg = (unsigned char*)blob->str; + unsigned char glyph_beg = fonts[0].glyph_beg; + unsigned char glyph_end = fonts[0].glyph_end; + + //translate the string: subtract 1 to get offset in Table + while((tmp1 = *strg)){ + if((tmp1>=glyph_beg) && (tmp1<glyph_end)){ + *strg = 1 + tmp1 - glyph_beg; + }else{ + *strg = 1; + } + strg++; + } + + blob->space = 1; + + blob->sizey = fonts[0].fontHeight; + blob->sizex = getLen(blob); + if(*blob->commands == '<'){ + blob->posx = 0; + blob->posy = (NUM_ROWS-blob->sizey)/2; + }else if(*blob->commands == '>'){ + blob->posx = NUM_COLS+blob->sizex; + blob->posy = (NUM_ROWS-blob->sizey)/2; + }else if(*blob->commands == 'd'){ + blob->posy = -blob->sizey; + blob->posx = (NUM_COLS - 2 + blob->sizex)/2; + }else if(*blob->commands == 'u'){ + blob->posy = blob->sizey; + blob->posx = (NUM_COLS - 2 + blob->sizex)/2; + } + + blob->delayx_rld = 0; + blob->delayy_rld = 0; + blob->delayb_rld = 0; + + blob->waitfor = wait_new; + + return blob; + +fail: + free(blob); + return 0;//no more blobs to parse +} + + +unsigned char updateBlob(blob_t * blob){ + + if(blob->delayx_rld && (!(blob->delayx--))){ + blob->delayx = blob->delayx_rld; + (blob->direction & DIRECTION_RIGHT)?blob->posx--:blob->posx++; + } + + if(blob->delayy_rld && (!(blob->delayy--))){ + blob->delayy = blob->delayy_rld; + (blob->direction & DIRECTION_DOWN)?blob->posy++:blob->posy--; + } + + if(blob->delayb_rld){ + if(!(blob->delayb--)){ + blob->delayb = blob->delayb_rld; + blob->visible ^= 1; + } + }else{ + blob->visible = 1; + } + + unsigned char done=0; + switch (blob->waitfor){ + case wait_posy: + if (blob->posy == blob->toy)done = 1; + break; + case wait_posx: + if (blob->posx == blob->tox)done = 1; + break; + case wait_out: + if((blob->posx - blob->sizex) > NUM_COLS || blob->posx < 0) done = 1; + if((blob->posy) > NUM_ROWS || (blob->posy + blob->sizey) <0 ) done = 1; + break; + case wait_timer: + if(0 == blob->timer--){ + done = 1; + } + break; + case wait_col_l: + if(blob->last){ + if((blob->last->posx - blob->last->sizex) == blob->posx){ + done=1; + } + }else{ + done = 1; + } + break; + case wait_col_r: + if(blob->next){ + if(blob->next->posx == (blob->posx - blob->sizex)){ + done=1; + } + }else{ + done = 1; + } + break; + default: + done = 1; + break; + } + if(done){ + return (blobNextCommand(blob)); + } + return 0; +} + +void drawBlob(blob_t *blob) { + char x, y; + unsigned char byte=0, glyph, storebytes; + unsigned int charPos, charEnd; + + unsigned int posx; unsigned char posy, toy; + + if(!blob->visible) return; + + unsigned char * str = (unsigned char*)blob->str; + posx = blob->posx; + posy = blob->posy; + toy = posy + blob->sizey; + storebytes = blob->font_storebytes; + + glyph = (*blob->str)-1; + charPos = PW(blob->fontIndex[glyph]); + charEnd = PW(blob->fontIndex[glyph+1]); + + while (posx >= NUM_COLS) { + charPos += storebytes; + if (charPos < charEnd) { + posx--; + }else{ + posx -= blob->space + 1; + if (!(glyph = *++str)) return; + glyph -= 1; + charPos = PW(blob->fontIndex[glyph]); + charEnd = PW(blob->fontIndex[glyph+1]); + } + } + for (x = posx; x >= 0; x-- ) { + unsigned char mask = 0; + unsigned int datpos; + datpos = charPos; + + for (y = posy; (y < NUM_ROWS) && (y < toy); y++) { + + if((mask<<=1) == 0){ + mask = 0x01; + byte = PB(blob->fontData[datpos++]); + } + + if ((byte & mask) && y >= 0 ) { + text_setpixel((pixel){x, y},1); + } + } + charPos += storebytes; + if (charPos < charEnd) { + }else{ + x -= blob->space; + if (!(glyph = *++str)) return; + glyph -= 1; + charPos = PW(blob->fontIndex[glyph]); + charEnd = PW(blob->fontIndex[glyph+1]); + } + } +} + +extern jmp_buf newmode_jmpbuf; + +void scrolltext(char *str) { + jmp_buf tmp_jmpbuf; + char tmp_str[SCROLLTEXT_BUFFER_SIZE]; + int ljmp_retval; + + fonts[0] = SCROLLTEXT_FONT; + + text_pixmap = malloc(NUM_ROWS * LINEBYTES); + + if(scrolltext_text[0] == 0){ + strcpy_P(scrolltext_text, default_text); + } + memcpy(tmp_str, str, SCROLLTEXT_BUFFER_SIZE); + + blob_t *startblob=0, *aktblob, *nextblob=0; + + memcpy (tmp_jmpbuf, newmode_jmpbuf, sizeof(jmp_buf)); + + + if((ljmp_retval = setjmp(newmode_jmpbuf))){ + while(startblob){ + aktblob = startblob; + startblob = aktblob->next; + free(aktblob); + } + free(text_pixmap); + memcpy (newmode_jmpbuf, tmp_jmpbuf, sizeof(jmp_buf)); + longjmp(newmode_jmpbuf, ljmp_retval); + } + + if (!(startblob = setupBlob(tmp_str))){ + goto exit; + } + + unsigned char retval; + do{ + startblob->next = 0; + startblob->last = 0; + while(startblob){ + aktblob = startblob; + while(aktblob){ + retval = updateBlob(aktblob); + if(!retval){ + nextblob = aktblob->next; + }else if(retval == 1){ + if(aktblob == startblob){ + startblob = aktblob->next; + }else{ + aktblob->last->next = aktblob->next; + } + if(aktblob->next){ + aktblob->next->last = aktblob->last; + } + nextblob = aktblob->next; + free(aktblob); + }else if(retval == 2){ + blob_t * newblob = setupBlob(0); + if (newblob){ + newblob->last = aktblob; + newblob->next = aktblob->next; + if(aktblob->next){ + aktblob->next->last = newblob; + } + aktblob->next = newblob; + } + nextblob = aktblob->next; + } + aktblob = nextblob; + } + + aktblob = startblob; + clear_text_pixmap(0); + while(aktblob){ + drawBlob(aktblob); + aktblob = aktblob->next; + } + update_pixmap(); + wait(2); + }; + startblob = setupBlob(0); + //showBlob(startblob); + }while(startblob); + +exit: + free(text_pixmap); + memcpy (newmode_jmpbuf, tmp_jmpbuf, sizeof(jmp_buf)); +} diff --git a/simulator/Makefile b/simulator/Makefile new file mode 100644 index 0000000..b18ab3a --- /dev/null +++ b/simulator/Makefile @@ -0,0 +1,111 @@ +PRG = borgSim +OPTIMIZE = -O0 +LIBS = -lglut -lpthread -lGL -lGLU +CC = gcc +LD = ld + +override CFLAGS = -g -Wall -pedantic -std=c99 $(OPTIMIZE) +$(DEFS) +override LDFLAGS = -Wl,-Map,$(PRG).map + +OBJ = breakpoint.o font_arial8.o font_small6.o font_uni53.o invader_draw.o \ + invader_init.o invader_proc.o invaders2.o joystick.o main.o menu.o pixel.o \ + programm.o scrolltext3.o snake.o trackball.o util.o tetris/input.o \ + tetris/logic.o tetris/piece.o tetris/playfield.o tetris/view.o prng.o \ + memxor_c.o noekeon.o stonefly.o + +all: $(PRG) + +$(PRG): $(OBJ) + $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o $@ + +clean: + rm -rf $(OBJ) $(PRG) $(PRG).map + +breakpoint.o: breakpoint.c pixel.h util.h config.h + $(CC) $(CFLAGS) -c -o breakpoint.o breakpoint.c + +font_arial8.o: font_arial8.c font.h + $(CC) $(CFLAGS) -c -o font_arial8.o font_arial8.c + +font_small6.o: font_small6.c font.h + $(CC) $(CFLAGS) -c -o font_small6.o font_small6.c + +font_uni53.o: font_uni53.c font.h + $(CC) $(CFLAGS) -c -o font_uni53.o font_uni53.c + +invader_draw.o: invader_draw.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_draw.o invader_draw.c + +invader_init.o: invader_init.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_init.o invader_init.c + +invader_proc.o: invader_proc.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_proc.o invader_proc.c + +invaders2.o: invaders2.c util.h invaders2.h pixel.h config.h scrolltext.h \ + joystick.h + $(CC) $(CFLAGS) -c -o invaders2.o invaders2.c + +joystick.o: joystick.c joystick.h + $(CC) $(CFLAGS) -c -o joystick.o joystick.c + +main.o: main.c config.h pixel.h util.h programm.h menu.h tetris/logic.h \ + tetris/piece.h trackball.h snake.h scrolltext.h + $(CC) $(CFLAGS) -c -o main.o main.c + +menu.o: menu.c menu.h config.h util.h pixel.h joystick.h snake.h \ + tetris/logic.h tetris/piece.h invaders2.h scrolltext.h + $(CC) $(CFLAGS) -c -o menu.o menu.c + +pixel.o: pixel.c pixel.h util.h config.h + $(CC) $(CFLAGS) -c -o pixel.o pixel.c + +programm.o: programm.c pixel.h util.h config.h programm.h joystick.h + $(CC) $(CFLAGS) -c -o programm.o programm.c + +scrolltext3.o: scrolltext3.c config.h scrolltext.h pixel.h util.h \ + font_arial8.h font.h font_small6.h font_uni53.h + $(CC) $(CFLAGS) -c -o scrolltext3.o scrolltext3.c + +snake.o: snake.c pixel.h util.h config.h joystick.h + $(CC) $(CFLAGS) -c -o snake.o snake.c + +trackball.o: trackball.c trackball.h + $(CC) $(CFLAGS) -c -o trackball.o trackball.c + +util.o: util.c joystick.h + $(CC) $(CFLAGS) -c -o util.o util.c + +noekeon.o: noekeon.c noekeon.h memxor.h + $(CC) $(CFLAGS) -c -o $@ $< + +memxor_c.o: memxor_c.c memxor.h + $(CC) $(CFLAGS) -c -o $@ $< + +prng.o: prng.c prng.h noekeon.h memxor.h + $(CC) $(CFLAGS) -c -o $@ $< + +tetris/input.o: tetris/input.c joystick.h util.h tetris/input.h + $(CC) $(CFLAGS) -c -o tetris/input.o tetris/input.c + +logic.o: tetris/logic.c tetris/logic.h tetris/piece.h tetris/playfield.h \ + tetris/view.h tetris/input.h prng.h ../borg-base/prng.h + $(CC) $(CFLAGS) -c -o tetris/logic.o tetris/logic.c + +tetris/piece.o: tetris/piece.c tetris/piece.h + $(CC) $(CFLAGS) -c -o tetris/piece.o tetris/piece.c + +tetris/playfield.o: tetris/playfield.c tetris/playfield.h tetris/piece.h + $(CC) $(CFLAGS) -c -o tetris/playfield.o tetris/playfield.c + +tetris/view.o: tetris/view.c config.h pixel.h util.h scrolltext.h \ + tetris/logic.h tetris/piece.h tetris/playfield.h tetris/view.h + $(CC) $(CFLAGS) -c -o tetris/view.o tetris/view.c + +stonefly.o: stonefly.h stonefly.c pixel.h util.h config.h prng.h \ + ../borg-base/prng.h tetris/piece.h + $(CC) $(CFLAGS) -c -o stonefly.o stonefly.c diff --git a/simulator/Makefile.osx b/simulator/Makefile.osx new file mode 100644 index 0000000..4262f63 --- /dev/null +++ b/simulator/Makefile.osx @@ -0,0 +1,102 @@ +PRG = borgSim +APP = $(PRG).app/Contents/MacOS/$(PRG) +OPTIMIZE = -O2 +LIBS = -lpthread -framework Carbon -framework GLUT -framework OpenGL -framework Foundation -framework AppKit +CC = gcc +LD = ld + +override CFLAGS = -g -Wall -pedantic -std=c99 $(OPTIMIZE) -DOSX_ +$(DEFS) +override LDFLAGS = -Wl --prebind + +OBJ = breakpoint.o font_arial8.o font_small6.o font_uni53.o invader_draw.o \ + invader_init.o invader_proc.o invaders2.o joystick.o main.o menu.o pixel.o \ + programm.o scrolltext3.o snake.o trackball.o util.o tetris/input.o \ + tetris/logic.o tetris/piece.o tetris/playfield.o tetris/view.o + +all: Makefile.osx $(APP) + +$(APP): $(OBJ) + test -d $(PRG).app/Contents/MacOS/ || mkdir -p $(PRG).app/Contents/MacOS/ + test -d $(PRG).app/Contents/Resources/ || mkdir -p $(PRG).app/Resources/ + test $(PRG).app/Contents/Rescources/borg3d.icns || cp -f borg3d.icns $(PRG).app/Contents/Rescources/ + $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) $(OBJ) -o $@ + +clean: + rm -rf $(OBJ) $(PRG) $(PRG).app/ + +breakpoint.o: breakpoint.c pixel.h util.h config.h + $(CC) $(CFLAGS) -c -o breakpoint.o breakpoint.c + +font_arial8.o: font_arial8.c font.h + $(CC) $(CFLAGS) -c -o font_arial8.o font_arial8.c + +font_small6.o: font_small6.c font.h + $(CC) $(CFLAGS) -c -o font_small6.o font_small6.c + +font_uni53.o: font_uni53.c font.h + $(CC) $(CFLAGS) -c -o font_uni53.o font_uni53.c + +invader_draw.o: invader_draw.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_draw.o invader_draw.c + +invader_init.o: invader_init.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_init.o invader_init.c + +invader_proc.o: invader_proc.c invaders2.h pixel.h util.h config.h \ + scrolltext.h joystick.h + $(CC) $(CFLAGS) -c -o invader_proc.o invader_proc.c + +invaders2.o: invaders2.c util.h invaders2.h pixel.h config.h scrolltext.h \ + joystick.h + $(CC) $(CFLAGS) -c -o invaders2.o invaders2.c + +joystick.o: joystick.c joystick.h + $(CC) $(CFLAGS) -c -o joystick.o joystick.c + +main.o: main.c config.h pixel.h util.h programm.h menu.h tetris/logic.h \ + tetris/piece.h trackball.h snake.h scrolltext.h + $(CC) $(CFLAGS) -c -o main.o main.c + +menu.o: menu.c menu.h config.h util.h pixel.h joystick.h snake.h \ + tetris/logic.h tetris/piece.h invaders2.h scrolltext.h + $(CC) $(CFLAGS) -c -o menu.o menu.c + +pixel.o: pixel.c pixel.h util.h config.h + $(CC) $(CFLAGS) -c -o pixel.o pixel.c + +programm.o: programm.c pixel.h util.h config.h programm.h joystick.h + $(CC) $(CFLAGS) -c -o programm.o programm.c + +scrolltext3.o: scrolltext3.c config.h scrolltext.h pixel.h util.h \ + font_arial8.h font.h font_small6.h font_uni53.h + $(CC) $(CFLAGS) -c -o scrolltext3.o scrolltext3.c + +snake.o: snake.c pixel.h util.h config.h joystick.h + $(CC) $(CFLAGS) -c -o snake.o snake.c + +trackball.o: trackball.c trackball.h + $(CC) $(CFLAGS) -c -o trackball.o trackball.c + +util.o: util.c joystick.h + $(CC) $(CFLAGS) -c -o util.o util.c + +tetris/input.o: tetris/input.c joystick.h util.h tetris/input.h + $(CC) $(CFLAGS) -c -o tetris/input.o tetris/input.c + +tetris/logic.o: tetris/logic.c tetris/logic.h tetris/piece.h \ + tetris/playfield.h tetris/view.h tetris/input.h + $(CC) $(CFLAGS) -c -o tetris/logic.o tetris/logic.c + +tetris/piece.o: tetris/piece.c tetris/piece.h + $(CC) $(CFLAGS) -c -o tetris/piece.o tetris/piece.c + +tetris/playfield.o: tetris/playfield.c tetris/playfield.h tetris/piece.h + $(CC) $(CFLAGS) -c -o tetris/playfield.o tetris/playfield.c + +tetris/view.o: tetris/view.c config.h pixel.h util.h scrolltext.h \ + tetris/logic.h tetris/piece.h tetris/playfield.h tetris/view.h + $(CC) $(CFLAGS) -c -o tetris/view.o tetris/view.c + diff --git a/simulator/main.c b/simulator/main.c new file mode 100644 index 0000000..1bb51d9 --- /dev/null +++ b/simulator/main.c @@ -0,0 +1,309 @@ + + +#ifdef _WIN32 +# include <GL/glut.h> +# include <windows.h> +# include <process.h> +# define pthread_t int +#else +# ifdef OSX_ +# include <GLUT/glut.h> +# else +# include <GL/glut.h> +# endif +# include <pthread.h> // for threads in linux +# include <stdlib.h> +# include <sys/time.h> +# include <sys/types.h> +# include <unistd.h> +#endif + +#include <stdio.h> +#include <setjmp.h> +#include "config.h" +#include "pixel.h" +#include "programm.h" +#include "menu.h" +#include "tetris/logic.h" +#include "trackball.h" +#include "snake.h" +#include "stonefly.h" + +#include "scrolltext.h" + + + +unsigned char fakeport; +jmp_buf newmode_jmpbuf; +volatile unsigned char oldMode, oldOldmode, mode; +extern unsigned char waitForFire; + + +int WindWidth, WindHeight; + +unsigned char pixmap[NUMPLANE][NUM_ROWS][LINEBYTES]; +unsigned char joystick; + +float view_rotx = 0, view_roty = 0, view_rotz = 0; +int win; + + +pthread_t simthread; +GLUquadric* quad; + +void drawLED(int color, float pos_x, float pos_y, float pos_z) { + glPushMatrix(); + glTranslatef(pos_x, pos_y, pos_z); + glCallList(color); + glPopMatrix(); +} + +void display(void){ + int x, y, z, level, color; + tbReshape(WindWidth, WindHeight); + glClear(GL_COLOR_BUFFER_BIT); + glPushMatrix(); + glTranslatef(NUM_COLS*2., 0., NUM_ROWS*2.); + tbMatrix(); + glRotatef(view_rotx, 1.0, 0.0, 0.0); + glRotatef(view_roty, 0.0, 1.0, 0.0); + glRotatef(view_rotz, 0.0, 0.0, 1.0); + glTranslatef(-NUM_COLS*2, 0., -NUM_ROWS*2.); + for (x = 0; x < 1; x++) { + for (y = 0; y < NUM_COLS; y++) { + for (z = 0; z < NUM_ROWS; z++) { + color = 0; + for (level = 0; level < NUMPLANE; level++) { + if (pixmap[level][z%NUM_ROWS][y/8] & (1 << y % 8)) { + color = level+1; + } + } + drawLED(color, (float)y*4.0, + (float)x*4.0, + (float)(NUM_ROWS-1-z)*4.0); + } + } + } + glPopMatrix(); + glutSwapBuffers(); +#ifdef _WIN32 + Sleep(10); +#else + usleep(20000); +#endif + joystick = 255; +} + +void keyboard(unsigned char key, int x, int y){ + switch (key) { + case 'q': printf("Quit\n"); + glutDestroyWindow(win); + exit(0); + break; + case ' ': + fakeport |= 0x01; + break; + case 'a': + fakeport |= 0x02; + break; + case 'd': + fakeport |= 0x04; + break; + case 's': + fakeport |= 0x08; + break; + case 'w': + fakeport |= 0x10; + break; + } +} + +void keyboardup(unsigned char key, int x, int y){ + switch (key) { + case ' ': + fakeport &= ~0x01; + break; + case 'a': + fakeport &= ~0x02; + break; + case 'd': + fakeport &= ~0x04; + break; + case 's': + fakeport &= ~0x08; + break; + case 'w': + fakeport &= ~0x10; + break; + } +} + +void mouse(int button, int state, int x, int y) +{ + tbMouse(button, state, x, y); +} + +void motion(int x, int y) +{ + tbMotion(x, y); +} + +void reshape(int width, int height) +{ + + tbReshape(width, height); + + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0, (float)WindWidth/(float)WindWidth, 5., 1000.); + gluLookAt(NUM_ROWS*2., NUM_ROWS*2.+50., NUM_COLS*2., + NUM_ROWS*2., NUM_ROWS*2., NUM_COLS*2., + 0.0, 0.0, 1.0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + WindWidth = width; + WindHeight = height; +} + +/* change view angle */ +static void special(int k, int x, int y) { + switch (k) { + case GLUT_KEY_UP: + view_rotx += 5.0; + break; + case GLUT_KEY_DOWN: + view_rotx -= 5.0; + break; + case GLUT_KEY_LEFT: + view_rotz += 5.0; + break; + case GLUT_KEY_RIGHT: + view_rotz -= 5.0; + break; + default: + return; + } + glutPostRedisplay(); +} +/* +void timf(int value) { + glutPostRedisplay(); + glutTimerFunc(1, timf, 0); +}*/ + +void *display_loop(void * unused) { + unsigned char mode;;; + mode = setjmp(newmode_jmpbuf); + oldOldmode = oldMode; + waitForFire = 1; + scrolltext("</#Scrolltext3 Test"); + for(;;){ + oldMode = mode; + switch(mode++) { + case 1: + stonefly(); + break; + case 2: + breakpoint(); + break; + case 3: + schwarzesLoch(); + break; + case 4: + scrolltext("</#Scrolltext3 Test"); + break; + case 5: + spirale(20); + break; + case 6: + joern1(); + break; + case 7: + snake(); + break; + case 8: + schachbrett(20); + break; + case 9: + feuer(); + break; + case 10: + matrix(); + break; + case 31: + fadein(); + break; + case 32: + test1(); + break; + case 43: + menu(); + mode = oldOldmode; + default: + break; + } + } + +} + +int main(int argc, char **argv){ + WindHeight = 700; + WindWidth = 700; + glutInit(&argc,argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); + glutInitWindowSize(WindHeight, WindWidth); + win = glutCreateWindow("16x16 Borg Simulator"); + + // callback + //glutReshapeFunc(reshape); + glutDisplayFunc(display); + glutIdleFunc(display); + glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF); + glutKeyboardFunc(keyboard); + glutKeyboardUpFunc(keyboardup); + glutSpecialFunc(special); + glutMouseFunc(mouse); + glutMotionFunc(motion); + + // clearcolor & main loop + glClearColor(0,0,0,1.0); + gluPerspective(60.0, (float)WindWidth/(float)WindWidth, 5., 1000.); + gluLookAt(NUM_COLS*2., NUM_COLS*2.+50., NUM_ROWS*2., + NUM_COLS*2., NUM_COLS*2., NUM_ROWS*2., + 0.0, 0.0, 1.0); + + // init Call List for LED + quad = gluNewQuadric(); + glNewList(0, GL_COMPILE); + glColor4f(0.8, 0.0, 0.0, 1.); + gluSphere(quad, 1.0, 12, 12); + glEndList(); + glNewList(1, GL_COMPILE); + glColor4f(0.5, 0.0, 0.0, 1.); + gluSphere(quad, 1.4, 12, 12); + glEndList(); + glNewList(2, GL_COMPILE); + glColor4f(0.7, 0.0, 0.0, 1.); + gluSphere(quad, 1.55, 12, 12); + glEndList(); + glNewList(3, GL_COMPILE); + glColor4f(1.00, 0.0, 0.0, 1.); + gluSphere(quad, 1.7, 12, 12); + glEndList(); + + tbInit(GLUT_LEFT_BUTTON); + tbAnimate(GL_FALSE); + + // start display_loop thread +#ifdef _WIN32 + _beginthread((void (*)(void*))display_loop, 0, NULL); +#else + pthread_create(&simthread, NULL, display_loop, NULL); +#endif + //glutTimerFunc(40, timf, 0); // Set up timer for 40ms, about 25 fps + glutMainLoop(); + return 0; +} diff --git a/simulator/trackball.c b/simulator/trackball.c new file mode 100644 index 0000000..500b2d5 --- /dev/null +++ b/simulator/trackball.c @@ -0,0 +1,234 @@ +/* + * Simple trackball-like motion adapted (ripped off) from projtex.c + * (written by David Yu and David Blythe). See the SIGGRAPH '96 + * Advanced OpenGL course notes. + * + * + * Usage: + * + * o call tbInit() in before any other tb call + * o call tbReshape() from the reshape callback + * o call tbMatrix() to get the trackball matrix rotation + * o call tbStartMotion() to begin trackball movememt + * o call tbStopMotion() to stop trackball movememt + * o call tbMotion() from the motion callback + * o call tbAnimate(GL_TRUE) if you want the trackball to continue + * spinning after the mouse button has been released + * o call tbAnimate(GL_FALSE) if you want the trackball to stop + * spinning after the mouse button has been released + * + * Typical setup: + * + * + void + init(void) + { + tbInit(GLUT_MIDDLE_BUTTON); + tbAnimate(GL_TRUE); + . . . + } + + void + reshape(int width, int height) + { + tbReshape(width, height); + . . . + } + + void + display(void) + { + glPushMatrix(); + + tbMatrix(); + . . . draw the scene . . . + + glPopMatrix(); + } + + void + mouse(int button, int state, int x, int y) + { + tbMouse(button, state, x, y); + . . . + } + + void + motion(int x, int y) + { + tbMotion(x, y); + . . . + } + + int + main(int argc, char** argv) + { + . . . + init(); + glutReshapeFunc(reshape); + glutDisplayFunc(display); + glutMouseFunc(mouse); + glutMotionFunc(motion); + . . . + } + * + * */ + +/* includes */ +#include <math.h> +#include <assert.h> +#ifdef OSX_ +# include <GLUT/glut.h> +#elif _WIN32 +# include <GL/glut.h> +#else +# include <GL/glut.h> +#endif +#include "trackball.h" + + +/* globals */ +static GLuint tb_lasttime; +static GLfloat tb_lastposition[3]; + +static GLfloat tb_angle = 0.0; +static GLfloat tb_axis[3]; +static GLfloat tb_transform[4][4]; + +static GLuint tb_width; +static GLuint tb_height; + +static GLint tb_button = -1; +static GLboolean tb_tracking = GL_FALSE; +static GLboolean tb_animate = GL_TRUE; + + +/* functions */ +static void _tbPointToVector(int x, int y, int width, int height, float v[3]) +{ + float d, a; + + /* project x, y onto a hemi-sphere centered within width, height. */ + v[0] = (2.0 * x - width) / width; + v[1] = (height - 2.0 * y) / height; + d = sqrt(v[0] * v[0] + v[1] * v[1]); + v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0)); + a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] *= a; + v[1] *= a; + v[2] *= a; +} + +static void _tbAnimate(void) +{ + glutPostRedisplay(); +} + +void _tbStartMotion(int x, int y, int button, int time) +{ + assert(tb_button != -1); + + tb_tracking = GL_TRUE; + tb_lasttime = time; + _tbPointToVector(x, y, tb_width, tb_height, tb_lastposition); +} + +void _tbStopMotion(int button, unsigned time) +{ + assert(tb_button != -1); + + tb_tracking = GL_FALSE; + + if (time == tb_lasttime && tb_animate) { + glutIdleFunc(_tbAnimate); + } else { + tb_angle = 0.0; + if (tb_animate) + glutIdleFunc(0); + } +} + +void tbAnimate(GLboolean animate) +{ + tb_animate = animate; +} + +void tbInit(GLuint button) +{ + tb_button = button; + tb_angle = 0.0; + + /* put the identity in the trackball transform */ + glPushMatrix(); + glLoadIdentity(); + glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform); + glPopMatrix(); +} + +void tbMatrix() +{ + assert(tb_button != -1); + + glPushMatrix(); + glLoadIdentity(); + glRotatef(tb_angle, -tb_axis[0], tb_axis[2], tb_axis[1]); + glMultMatrixf((GLfloat *)tb_transform); + glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform); + glPopMatrix(); + + glMultMatrixf((GLfloat *)tb_transform); + } + +void tbReshape(int width, int height) +{ + assert(tb_button != -1); + + tb_width = width; + tb_height = height; +} + +void tbMouse(int button, int state, int x, int y) +{ + assert(tb_button != -1); + + if (state == GLUT_DOWN && button == tb_button) + _tbStartMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME)); + else if (state == GLUT_UP && button == tb_button) + _tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME)); +} + +void tbMotion(int x, int y) +{ + GLfloat current_position[3], dx, dy, dz; + + assert(tb_button != -1); + + if (tb_tracking == GL_FALSE) + return; + + _tbPointToVector(x, y, tb_width, tb_height, current_position); + + /* calculate the angle to rotate by (directly proportional to the + length of the mouse movement */ + dx = current_position[0] - tb_lastposition[0]; + dy = current_position[1] - tb_lastposition[1]; + dz = current_position[2] - tb_lastposition[2]; + tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz); + + /* calculate the axis of rotation (cross product) */ + tb_axis[0] = tb_lastposition[1] * current_position[2] - + tb_lastposition[2] * current_position[1]; + tb_axis[1] = tb_lastposition[2] * current_position[0] - + tb_lastposition[0] * current_position[2]; + tb_axis[2] = tb_lastposition[0] * current_position[1] - + tb_lastposition[1] * current_position[0]; + + /* reset for next time */ + tb_lasttime = glutGet(GLUT_ELAPSED_TIME); + tb_lastposition[0] = current_position[0]; + tb_lastposition[1] = current_position[1]; + tb_lastposition[2] = current_position[2]; + + /* remember to draw new position */ + glutPostRedisplay(); +} diff --git a/simulator/trackball.h b/simulator/trackball.h new file mode 100644 index 0000000..6c93ec0 --- /dev/null +++ b/simulator/trackball.h @@ -0,0 +1,89 @@ +/* + * Simple trackball-like motion adapted (ripped off) from projtex.c + * (written by David Yu and David Blythe). See the SIGGRAPH '96 + * Advanced OpenGL course notes. + * + * + * Usage: + * + * o call gltbInit() in before any other gltb call + * o call gltbReshape() from the reshape callback + * o call gltbMatrix() to get the trackball matrix rotation + * o call gltbStartMotion() to begin trackball movememt + * o call gltbStopMotion() to stop trackball movememt + * o call gltbMotion() from the motion callback + * o call gltbAnimate(GL_TRUE) if you want the trackball to continue + * spinning after the mouse button has been released + * o call gltbAnimate(GL_FALSE) if you want the trackball to stop + * spinning after the mouse button has been released + * + * Typical setup: + * + * + void + init(void) + { + gltbInit(GLUT_MIDDLE_BUTTON); + gltbAnimate(GL_TRUE); + . . . + } + + void + reshape(int width, int height) + { + gltbReshape(width, height); + . . . + } + + void + display(void) + { + glPushMatrix(); + + gltbMatrix(); + . . . draw the scene . . . + + glPopMatrix(); + } + + void + mouse(int button, int state, int x, int y) + { + gltbMouse(button, state, x, y); + . . . + } + + void + motion(int x, int y) + { + gltbMotion(x, y); + . . . + } + + int + main(int argc, char** argv) + { + . . . + init(); + glutReshapeFunc(reshape); + glutDisplayFunc(display); + glutMouseFunc(mouse); + glutMotionFunc(motion); + . . . + } + ***/ + + + /* functions */ + void tbInit(GLuint button); + + void tbMatrix(void); + + void tbReshape(int width, int height); + + void tbMouse(int button, int state, int x, int y); + + void tbMotion(int x, int y); + + void tbAnimate(GLboolean animate); + diff --git a/uart/uart.c b/uart/uart.c new file mode 100644 index 0000000..2642caa --- /dev/null +++ b/uart/uart.c @@ -0,0 +1,188 @@ +/* USART-Init beim ATmegaXX */ + + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <stdlib.h> + +#include "config.h" +#include "uart.h" + +#ifdef ATMEGA128 +#define UCSRB UCSR0B +#define UCSRC UCSR0C +#define UDR UDR0 +#define UBRRH UBRR0H +#define UBRRL UBRR0L +#define URSEL UMSEL +#endif + + +#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16L)) + + +#ifdef UART_INTERRUPT +volatile static char rxbuf[UART_RXBUFSIZE]; +volatile static char txbuf[UART_TXBUFSIZE]; +volatile static char *volatile rxhead, *volatile rxtail; +volatile static char *volatile txhead, *volatile txtail; + + +SIGNAL(SIG_UART_DATA) { +#ifdef UART_LEDS + PORTC ^= 0x01; +#endif + + if ( txhead == txtail ) { + UCSRB &= ~(1 << UDRIE); /* disable data register empty IRQ */ + } else { + UDR = *txtail; /* schreibt das Zeichen x auf die Schnittstelle */ + if (++txtail == (txbuf + UART_TXBUFSIZE)) txtail = txbuf; + } +} + +SIGNAL(SIG_UART_RECV) { + int diff; + +#ifdef UART_LEDS + PORTC ^= 0x02; +#endif + + /* buffer full? */ + diff = rxhead - rxtail; + if ( diff < 0 ) diff += UART_RXBUFSIZE; + if (diff < UART_RXBUFSIZE -1) { + // buffer NOT full + *rxhead = UDR; + if (++rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf; + } else { + UDR; //reads the buffer to clear the interrupt condition + } +} + +#endif // UART_INTERRUPT + + +void uart_init() { + PORTD |= 0x01; //Pullup an RXD an + + UCSRA = 0; + UCSRB |= (1<<TXEN); //UART TX einschalten + UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1 + + UCSRB |= ( 1 << RXEN ); //Uart RX einschalten + +// UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); +// UBRRL=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)); + + UBRRL = 8; + +#ifdef UART_INTERRUPT + // init buffers + rxhead = rxtail = rxbuf; + txhead = txtail = txbuf; + + // activate rx IRQ + UCSRB |= (1 << RXCIE); +#endif // UART_INTERRUPT +} + +#ifdef UART_INTERRUPT +void uart_putc(char c) { + volatile int diff; + + /* buffer full? */ + do { + diff = txhead - txtail; + if ( diff < 0 ) diff += UART_TXBUFSIZE; + } while ( diff >= UART_TXBUFSIZE -1 ); + + cli(); + *txhead = c; + if (++txhead == (txbuf + UART_TXBUFSIZE)) txhead = txbuf; + + UCSRB |= (1 << UDRIE); /* enable data register empty IRQ */ + sei(); +} +#else // WITHOUT INTERRUPT +void uart_putc(char c) { + while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich */ + UDR = c; /* schreibt das Zeichen x auf die Schnittstelle */ +} +#endif // UART_INTERRUPT + + +void uart_putstr(char *str) { + while(*str) { + uart_putc(*str++); + } +} + +void uart_putstr_P(PGM_P str) { + char tmp; + while((tmp = pgm_read_byte(str))) { + uart_putc(tmp); + str++; + } +} + +void uart_hexdump(char *buf, int len) +{ + unsigned char x=0; + char sbuf[3]; + + while(len--){ + itoa(*buf++, sbuf, 16); + if (sbuf[1] == 0) uart_putc(' '); + uart_putstr(sbuf); + uart_putc(' '); + if(++x == 16) { + uart_putstr_P(PSTR("\r\n")); + x = 0; + } + } +} + + +#ifdef UART_INTERRUPT +char uart_getc() +{ + char val; + + while(rxhead==rxtail) ; + + val = *rxtail; + if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf; + + return val; +} +#else // WITHOUT INTERRUPT +char uart_getc() +{ + while (!(UCSRA & (1<<RXC))); // warten bis Zeichen verfuegbar + return UDR; // Zeichen aus UDR zurueckgeben +} +#endif // UART_INTERRUPT + +// returns 1 on success +#ifdef UART_INTERRUPT +char uart_getc_nb(char *c) +{ + if (rxhead==rxtail) return 0; + + *c = *rxtail; + if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf; + + return 1; +} +#else // WITHOUT INTERRUPT +char uart_getc_nb(char *c) +{ + if (UCSRA & (1<<RXC)) { // Zeichen verfuegbar + *c = UDR; + return 1; + } + + return 0; +} +#endif // UART_INTERRUPT diff --git a/uart/uart.h b/uart/uart.h new file mode 100644 index 0000000..cee8519 --- /dev/null +++ b/uart/uart.h @@ -0,0 +1,35 @@ +#ifndef UART_H +#define UART_H + +/** + * UART Library + * + * #define F_CPU 16000000 // Oszillator-Frequenz in Hz + * #define UART_INTERRUPT 1 + * #define UART_BAUD_RATE 19200 + * #define UART_RXBUFSIZE 16 + * #define UART_TXBUFSIZE 16 + * #define UART_LINE_BUFFER_SIZE 40 + * #define UART_LEDS // LED1 and LED2 toggle on tx and rx interrupt + * + */ + +#include <inttypes.h> +#include <avr/pgmspace.h> + +void uart_init(); + +void uart_putc(char c); +void uart_putstr(char * str); +void uart_putstr_P(PGM_P str); +void uart_hexdump(char *buf, int len); + +char uart_getc(); +char uart_getc_nb(char *c); // returns 1 on success + +//get one Cariage return terminated line +//echo charakters back on Uart +//returns buffer with zero terminated line on success, 0 pointer otherwise +char * uart_getline_nb(); + +#endif diff --git a/util.c b/util.c new file mode 100644 index 0000000..27a2319 --- /dev/null +++ b/util.c @@ -0,0 +1,48 @@ +#include <avr/io.h> +#include <setjmp.h> + +#include "joystick.h" + +//this buffer is declared in main +extern jmp_buf newmode_jmpbuf; + +#ifdef CAN_SUPPORT +# include "can/borg_can.h" +#endif + + +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 + for(;ms>0;ms--){ + +#ifdef CAN_SUPPORT + bcan_process_messages(); +#endif + +#ifdef JOYSTICK_SUPPORT + if (waitForFire) { + //PORTJOYGND &= ~(1<<BITJOY0); + //PORTJOYGND &= ~(1<<BITJOY1); + if (JOYISFIRE) { + longjmp(newmode_jmpbuf, 43); + } + } +#endif + + while(!(TIFR&0x80)); //wait for compare match flag + TIFR=0x80; //reset flag + } +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..6548ae9 --- /dev/null +++ b/util.h @@ -0,0 +1,8 @@ +#ifndef UTIL_H +#define UTIL_H + +#include <avr/io.h> + +void wait(int ms); + +#endif