diff --git a/firmware/.gitignore b/firmware/.gitignore index d2d2dd6..586d0f2 100644 --- a/firmware/.gitignore +++ b/firmware/.gitignore @@ -1,5 +1,5 @@ -firmware.bin -firmware.elf +*.bin +*.elf lpc1xxx/memory.ld applications/wrapper.c lcd/allfonts.h diff --git a/firmware/Makefile b/firmware/Makefile index 44f6a76..5cf7513 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -37,13 +37,13 @@ ifdef APP OUTFILE=$(APP) endif -LDFLAGS+= -Wl,--gc-sections +LDFLAGS+= --gc-sections OBJS += lpc1xxx/$(TARGET)_handlers.o lpc1xxx/LPC1xxx_startup.o ########################################################################## # Startup files ########################################################################## -LDLIBS = -lm +LDLIBS = LDLIBS += -Lapplications -lapp LDLIBS += -Lfunk -lfunk LDLIBS += -Lusbcdc -lusbcdc @@ -111,7 +111,7 @@ $(LD_TEMP): -@echo "INCLUDE $(LD_SCRIPT)" >> $(LD_TEMP) $(OUTFILE).elf: $(OBJS) $(SYS_OBJS) $(SUBDIRS) $(LPCFIX) $(LD_TEMP) - $(CC) $(LDFLAGS) -T $(LD_TEMP) -o $(OUTFILE).elf $(OBJS) $(LDLIBS) + $(LD) $(LDFLAGS) -T $(LD_TEMP) -o $(OUTFILE).elf $(OBJS) $(LDLIBS) -@echo "" $(SIZE) $(OUTFILE).elf -@echo "" diff --git a/firmware/Makefile.inc b/firmware/Makefile.inc index 3cf227d..dda77a0 100644 --- a/firmware/Makefile.inc +++ b/firmware/Makefile.inc @@ -42,7 +42,7 @@ CPU_TYPE = cortex-$(CORTEX_TYPE) # Compiler settings, parameters and flags ########################################################################## -CFLAGS = -std=c99 -c -g -Os $(INCLUDE_PATHS) -Wall -mthumb -ffunction-sections -fdata-sections -fmessage-length=0 -mcpu=$(CPU_TYPE) -DTARGET=$(TARGET) -DRAMCODE=$(RAMCODE) -fno-builtin -Wno-unused-function +CFLAGS = -std=c99 -c -g -Os $(INCLUDE_PATHS) -Wall -mthumb -ffunction-sections -fdata-sections -fmessage-length=0 -mcpu=$(CPU_TYPE) -DTARGET=$(TARGET) -DRAMCODE=$(RAMCODE) -fno-builtin -Wno-unused-function -ffreestanding LDFLAGS = -nostartfiles ifeq "$(USBSERIAL)" "YES" diff --git a/firmware/README.building b/firmware/README.building index 954edae..6575602 100644 --- a/firmware/README.building +++ b/firmware/README.building @@ -1,4 +1,13 @@ -make flags supported by this Makefile +### A note on the compiler +We are currently using the CodeSourcery gcc (see wiki for link). +You can also use a standard arm cross-gcc + (https://github.com/esden/summon-arm-toolchain) +but please note that this creates larger binaries. +We are talking about 100-200 bytes for firmware.bin, +you will run into space problems with the default firmware. +Sorry about that. + +### Make flags supported by this Makefile APP= - builds "application" foo (check .c and the subdir in applications/) @@ -28,5 +37,5 @@ make APP=l0dable LAPP= (=l0dable.bin) # build all l0dables make l0dables -#build one l0dable +# build one l0dable cd l0dables && make .c0d diff --git a/firmware/applications/final/mesh.c b/firmware/applications/final/mesh.c index 63fb4c1..f2692f0 100644 --- a/firmware/applications/final/mesh.c +++ b/firmware/applications/final/mesh.c @@ -186,6 +186,9 @@ void m_choose(){ case('r'): strcpy(p,"r0type"); break; + case('s'): + strcpy(p,"Snake"); + break; #endif default: p[0]=*mm; @@ -233,6 +236,9 @@ void m_choose(){ case('r'): strcpy(p,"r0type"); break; + case('s'): + strcpy(p,"Snake"); + break; #endif }; if(tmm[i]>='a' && tmm[i]<='z'){ diff --git a/firmware/basic/basic.c b/firmware/basic/basic.c index 51c1950..5b908df 100644 --- a/firmware/basic/basic.c +++ b/firmware/basic/basic.c @@ -18,7 +18,7 @@ void rbInit() { gpioSetDir(USB_CONNECT, gpioDirection_Output); gpioSetValue(USB_CONNECT, 1); - uint8_t ports[] = { RB_BTN0, RB_BTN1, RB_BTN2, RB_BTN3, RB_BTN4, + static uint8_t ports[] = { RB_BTN0, RB_BTN1, RB_BTN2, RB_BTN3, RB_BTN4, RB_LED0, RB_LED1, RB_LED2, RB_SPI_SS0, RB_SPI_SS1, RB_SPI_SS2, RB_SPI_SS3, RB_SPI_SS4, RB_SPI_SS5, diff --git a/firmware/basic/basic.h b/firmware/basic/basic.h index 4025232..694e778 100644 --- a/firmware/basic/basic.h +++ b/firmware/basic/basic.h @@ -171,12 +171,12 @@ uint16_t crc16(uint8_t * buf, int len); // menu.c struct MENU_DEF { - char *text; + const char *text; void (*callback)(void); }; struct MENU { - char *title; + const char *title; struct MENU_DEF entries[]; }; diff --git a/firmware/core/libc/string.c b/firmware/core/libc/string.c index 3fe0b9c..e6bb0fe 100644 --- a/firmware/core/libc/string.c +++ b/firmware/core/libc/string.c @@ -52,6 +52,7 @@ void * memcpy(void *pDestination, const void *pSource, size_t num) { unsigned char *pByteDestination; unsigned char *pByteSource; +#ifdef FAST_MEMCPY unsigned int *pAlignedSource = (unsigned int *) pSource; unsigned int *pAlignedDestination = (unsigned int *) pDestination; @@ -71,6 +72,10 @@ void * memcpy(void *pDestination, const void *pSource, size_t num) // Copy remaining bytes pByteDestination = (unsigned char *) pAlignedDestination; pByteSource = (unsigned char *) pAlignedSource; +#else + pByteDestination = (unsigned char *) pDestination; + pByteSource = (unsigned char *) pSource; +#endif while (num--) { *pByteDestination++ = *pByteSource++; diff --git a/firmware/filesystem/select.c b/firmware/filesystem/select.c index 07399f1..d9b2f45 100644 --- a/firmware/filesystem/select.c +++ b/firmware/filesystem/select.c @@ -8,6 +8,7 @@ #define FLEN 13 +/* if count is 0xff (-1) do not fill files and return the count instead */ int getFiles(char files[][FLEN], uint8_t count, uint16_t skip, const char *ext) { DIR dir; /* Directory object */ @@ -37,7 +38,9 @@ int getFiles(char files[][FLEN], uint8_t count, uint16_t skip, const char *ext) continue; }; - strcpy(files[pos++],Finfo.fname); + if(count != 0xff) + strcpy(files[pos],Finfo.fname); + pos++; if( pos == count ) break; } @@ -50,17 +53,19 @@ int selectFile(char *filename, const char *extension) int skip = 0; char key; int selected = 0; + int file_count = getFiles(NULL, 0xff, 0, extension); + font=&Font_7x8; + if(!file_count){ + lcdPrintln("No Files?"); + lcdRefresh(); + getInputWait(); + getInputWaitRelease(); + return -1; + }; while(1){ char files[PERPAGE][FLEN]; int count = getFiles(files, PERPAGE, skip, extension); - if(!count){ - lcdPrintln("No Files?"); - lcdRefresh(); - getInputWait(); - getInputWaitRelease(); - return -1; - }; if(count 0 ){ skip--; + } else { // wrap to bottom + skip = file_count - PERPAGE; + if(skip < 0) skip = 0; + selected = file_count - skip - 1; } } break; case BTN_LEFT: + getInputWaitRelease(); return -1; case BTN_ENTER: case BTN_RIGHT: strcpy(filename, files[selected]); + getInputWaitRelease(); return 0; } } diff --git a/firmware/funk/mesh.c b/firmware/funk/mesh.c index 235da21..6e4fa37 100644 --- a/firmware/funk/mesh.c +++ b/firmware/funk/mesh.c @@ -48,16 +48,16 @@ void initMesh(void){ #define MP_IGNORE 4 int mesh_sanity(uint8_t * pkt){ if(MO_TYPE(pkt)>0x7f || MO_TYPE(pkt)<0x20) - return MP_SEND|MP_RECV; + return MP_SEND; if(MO_TYPE(pkt)=='T' && MO_BODY(pkt)[5]) - return MP_SEND|MP_RECV; + return MP_SEND; if(MO_TYPE(pkt)=='T' && MO_TIME(pkt)<86400) return MP_OK; if(MO_TYPE(pkt)>='A' && MO_TYPE(pkt)<='Z'){ if(MO_TIME(pkt)>1370340000) /* 4.Jun 2013 */ - return MP_SEND|MP_RECV; + return MP_SEND; if(MO_TIME(pkt)<1325376000) /* 1.1.2012 */ - return MP_SEND|MP_RECV; + return MP_SEND; }else if(MO_TYPE(pkt)>='a' && MO_TYPE(pkt)<='z'){ if(MO_TIME(pkt)>16777216) /* 3-byte only */ return MP_SEND; @@ -73,7 +73,7 @@ int mesh_sanity(uint8_t * pkt){ MO_TYPE(pkt)!='G' && MO_TYPE(pkt)!='T' ){ - return MP_IGNORE|MP_RECV; + return MP_IGNORE; }; return MP_OK; }; @@ -103,7 +103,7 @@ MPKT * meshGetMessage(uint8_t type){ }; void meshPanic(uint8_t * pkt,int bufno){ -#if 1 +#if 0 static int done=0; if(!done){ gpioSetValue (RB_LED0, 1-gpioGetValue(RB_LED0)); diff --git a/firmware/l0dable/1boot.c b/firmware/l0dable/1boot.c index a544663..06a6063 100644 --- a/firmware/l0dable/1boot.c +++ b/firmware/l0dable/1boot.c @@ -117,7 +117,7 @@ static bool screen_overview() { while (key != BTN_ENTER) { lcdClear(); lcdPrintln("Privacy:"); - lcdPrintln(levels[GLOBAL(privacy)]); + lcdPrintln(levels[(int)GLOBAL(privacy)]); lcdPrintln(""); lcdPrintln("Nickname:"); lcdPrintln(GLOBAL(nickname)); diff --git a/firmware/l0dable/EXPORTS b/firmware/l0dable/EXPORTS index 1a3d7d5..13d3d3a 100644 --- a/firmware/l0dable/EXPORTS +++ b/firmware/l0dable/EXPORTS @@ -83,7 +83,7 @@ meshnice #external strcpy strlen -memcpy +memmove memset #stuff GetLight diff --git a/firmware/l0dable/jeopardy.c b/firmware/l0dable/jeopardy.c index c3b31d1..35b0c4c 100644 --- a/firmware/l0dable/jeopardy.c +++ b/firmware/l0dable/jeopardy.c @@ -90,6 +90,8 @@ void setLeft(); void setRight(); struct packet a; +void setJeopardy(); + void ram(void) { int priv = GLOBAL(privacy); @@ -103,7 +105,7 @@ void ram(void) nrf_config_set(&config); nrf_set_strength(3); - int rnd; +// int rnd; volatile uint16_t i; while( 1 ){ diff --git a/firmware/l0dable/jump.c b/firmware/l0dable/jump.c index a83d940..e1add11 100644 --- a/firmware/l0dable/jump.c +++ b/firmware/l0dable/jump.c @@ -221,7 +221,7 @@ static void draw_platforms() { } static void draw_player() { - bool* sprite; + const bool* sprite; if(game.player_y_vel > 0) { sprite = PLAYER_SPRITE_DOWN; } diff --git a/firmware/l0dable/nick_work.c b/firmware/l0dable/nick_work.c index 2875c3d..519fa4a 100644 --- a/firmware/l0dable/nick_work.c +++ b/firmware/l0dable/nick_work.c @@ -71,11 +71,12 @@ int melody_timeout; static void init_lilakit(void); static void tick_lilakit(void); +void melody_play(void); static void mainloop(); void handler(void); void ram(void) { - timer32Callback0 = handler; + timer32Callback0 = (uint32_t) handler; /* Enable the clock for CT32B0 */ SCB_SYSAHBCLKCTRL |= (SCB_SYSAHBCLKCTRL_CT32B0); diff --git a/firmware/l0dable/people.c b/firmware/l0dable/people.c index 4f85e17..28118f6 100644 --- a/firmware/l0dable/people.c +++ b/firmware/l0dable/people.c @@ -29,7 +29,7 @@ void ram(void) { if( nrf_rcv_pkt_time(64,sizeof(buf),buf) == 16 ){ buf[14] = 0; if( buf[1] == 0x23 || buf[1] == 0x24){ - lcdPrintln(buf+6); + lcdPrintln((char*)(buf+6)); //lcdPrintln("foo"); } lcdRefresh(); diff --git a/firmware/l0dable/pongo.c b/firmware/l0dable/pongo.c index 150ea22..891c05f 100644 --- a/firmware/l0dable/pongo.c +++ b/firmware/l0dable/pongo.c @@ -113,6 +113,9 @@ void init(); ** Code Section *********************************************/ +void init(); +void ram(); + void game(void) { init(); @@ -139,7 +142,7 @@ void game(void) } } -init() +void init() { // init ball ball1.size = PONG_BALL_SIZE; diff --git a/firmware/l0dable/r_player.c b/firmware/l0dable/r_player.c index c2602df..da538ca 100644 --- a/firmware/l0dable/r_player.c +++ b/firmware/l0dable/r_player.c @@ -34,11 +34,11 @@ struct packet{ uint8_t x; uint8_t y; uint8_t flags; - uint8_t text[16]; + char text[16]; }__attribute__((packed)) text; struct nick{ uint8_t flags; - uint8_t nick[18]; + char nick[18]; }__attribute__((packed)) nick; struct nickrequest{ uint8_t reserved[19]; @@ -55,7 +55,7 @@ struct packet{ uint8_t gameFlags; uint8_t interval; uint8_t jitter; - uint8_t gameTitle[8]; + char gameTitle[8]; }__attribute__((packed)) announce; struct join{ uint16_t gameId; @@ -93,7 +93,7 @@ uint16_t gameId; uint8_t interval; uint8_t jitter; uint8_t flags; -uint8_t *gameTitle; +char *gameTitle; void sendButton(uint8_t button); void sendJoin(uint32_t game); @@ -321,7 +321,7 @@ void processNickRequest( struct nickrequest *nq) p.id= id; p.ctr= ++ctr; p.c.nick.flags = 0; - uint8_t *nick = GLOBAL(nickname); + char *nick = GLOBAL(nickname); strcpy(p.c.nick.nick, nick); nrf_snd_pkt_crc(sizeof(p),(uint8_t*)&p); } @@ -374,7 +374,7 @@ void processText(struct text *t) if( t->flags & FLAGS_CLS ) lcdClear() ; lcdSetCrsr(t->x, t->y); - t->text[16] = 0; + t->text[16] = 0; // XXX:Actually ok, beause the CRC is there. But evil! lcdPrint(t->text); lcdRefresh(); } diff --git a/firmware/l0dable/scope.c b/firmware/l0dable/scope.c index 6b44ecb..7603be6 100644 --- a/firmware/l0dable/scope.c +++ b/firmware/l0dable/scope.c @@ -116,7 +116,7 @@ void ram(void) { case BTN_RIGHT: if (kok) { xs++; xs&=63; kok=0; } break; case BTN_UP: if (kok) { ch++; ch&=7; kok=0; } break; case BTN_DOWN: if (kok) { ch--; ch&=7; kok=0; } break; - case BTN_ENTER: return 0; + case BTN_ENTER: return; default: kok=1; } } diff --git a/firmware/l0dable/snake.c b/firmware/l0dable/snake.c new file mode 100644 index 0000000..ce7a56c --- /dev/null +++ b/firmware/l0dable/snake.c @@ -0,0 +1,322 @@ +/* + * snake + ******** + * a snake clone for the r0ket + * created by Flori4n (DrivenHoliday) & MascH (CCCHB tent) + ***************************************/ + +#include +#include + +#include "basic/basic.h" +#include "basic/config.h" +#include "basic/random.h" +#include "lcd/render.h" +#include "lcd/display.h" +#include "lcd/fonts.h" +#include "lcd/fonts/invaders.h" +//#Include "lcd/lcd.h" +//#include "lcd/print.h" +#include "funk/mesh.h" +#include "usetable.h" + +#define MAX_SNAKE_LEN (40) +#define SNAKE_DIM (3) +#define MIN_SPEED (25) +#define MAX_SPEED (3) +#define MIN_X 2 +#define MAX_X (RESX-3) +#define MIN_Y 8 +#define MAX_Y (RESY-2) +#define SIZE_X ((MAX_X-MIN_X)/SNAKE_DIM) +#define SIZE_Y ((MAX_Y-MIN_Y)/SNAKE_DIM) + +#define RIGHT 0 +#define LEFT 2 +#define UP 3 +#define DOWN 1 + +struct pos_s { + int x,y; +}; + +struct snake_s { + struct pos_s *tail; + int len, dir, speed, t_start; +}; + +static void reset(); +static void next_level(); +static void draw_block(); +static void handle_input(); +static void death_anim(); +static struct pos_s getFood(void); +static int hitWall(); +static int hitFood(); +static int hitSelf(); +static int showHighscore(); + +int points = 0; +struct snake_s snake = { NULL, 3, 0, MIN_SPEED, 2}; +struct pos_s food; + +void ram(void) +{ + int c=0, pos=0,del=0; + + struct pos_s tail[MAX_SNAKE_LEN]; + snake.tail = tail; + + // initially reset everything + reset(); + + while (1) + { + if(!(++c % snake.speed)) { + handle_input(); + + pos = (snake.t_start+1) % MAX_SNAKE_LEN; + snake.tail[pos].x = snake.tail[snake.t_start].x; + snake.tail[pos].y = snake.tail[snake.t_start].y; + + if(snake.dir == 0) + snake.tail[pos].x++; + else if(snake.dir == 1) + snake.tail[pos].y++; + else if(snake.dir == 2) + snake.tail[pos].x--; + else if(snake.dir == 3) + snake.tail[pos].y--; + + snake.t_start = pos; + + if (pos < snake.len) { + del = MAX_SNAKE_LEN - (snake.len - pos); + } else + del = pos - snake.len; + + // remove last, add first line + draw_block(snake.tail[del].x, snake.tail[del].y, 0); + draw_block(snake.tail[pos].x, snake.tail[pos].y, 1); + + // check for obstacle hit.. + if (hitWall() || hitSelf()) { + death_anim(); + if (showHighscore()) + break; + reset(); + } + else if (hitFood()) + next_level(); + + lcdDisplay(); + } + +#ifdef SIMULATOR + delayms(50); +#else + delayms(3); +#endif + } +} + +static struct pos_s getFood(void) +{ + int i,pos; + struct pos_s res; + + tryagain: + res.x = (getRandom() % (SIZE_X-1)) + 1; + res.y = (getRandom() % (SIZE_Y-3)) + 3; + + for(i=0; i= MAX_X) + || (snake.tail[snake.t_start].y*3 <= MIN_Y) + || (snake.tail[snake.t_start].y*3 >= MAX_Y) ) ? + 1 : 0; + +} + +static int hitSelf() +{ + int i, pos; + for (i=1; ipkt)>score) + return false; + + MO_TIME_set(mpkt->pkt,score); + strcpy((char*)MO_BODY(mpkt->pkt),nick); + if(GLOBAL(privacy)==0){ + uint32touint8p(GetUUID32(),mpkt->pkt+26); + mpkt->pkt[25]=0; + }; + return true; +} + +static uint32_t highscore_get(char nick[]){ + MPKT * mpkt= meshGetMessage('s'); + char * packet_nick = (char*)MO_BODY(mpkt->pkt); + // the packet crc end is already zeroed + if(MAXNICKpkt); +} + +static int showHighscore() +{ + int key = getInputRaw(); //throw away pending keypress + char nick[20]; + uint32_t score = 0; + + highscore_set(points,GLOBAL(nickname)); + score = highscore_get(nick); + + lcdClear(); + DoString(0,RESY/2-33, " Your Score"); + DoInt(RESX/2-4, RESY/2-25, points); + DoString(0,RESY/2-10, " Highscore"); + DoInt(RESX/2-4, RESY/2-2, score); + DoString(0, RESY/2+18, " UP to play "); + DoString(0, RESY/2+26, "DOWN to quit "); + + lcdDisplay(); + + while(1) { + key = getInputRaw(); + if (key&BTN_DOWN) { + return 1; + } else if (key&BTN_UP) { + return 0; + } + } +} + +static int hitFood() +{ + return ((snake.tail[snake.t_start].x == food.x) && (snake.tail[snake.t_start].y == food.y)) ? 1 : 0; +} diff --git a/firmware/l0dable/snake.c.disabled b/firmware/l0dable/snake.c.disabled deleted file mode 100644 index 9422712..0000000 --- a/firmware/l0dable/snake.c.disabled +++ /dev/null @@ -1,194 +0,0 @@ -#include -#include "basic/basic.h" -#include "basic/config.h" - -#include "lcd/lcd.h" -#include "lcd/print.h" -#include "usetable.h" - -struct elem -{ - int x,y; -}; - -void reset(struct elem snake[],size_t *snake_size,int *dirc, -int*speed, int*points,int*point_s); -void o_rectangle (int x0, int y0, int width, int height); -struct elem rnd(void); - -#define MAX_SNAKE_LEN (40) -#define SNAKE_DEM (3) -#define MIN_SPEED (25) -#define MAX_SPEED (3) -#define SIZE_X (RESX) -#define SIZE_Y (RESY) - -void ram(void) -{ - int inpt,dirc,c,grows = 0,dx,dy,points,point_s=1; - size_t n = 0, snake_size = 5, speed=MIN_SPEED; - struct elem snake[MAX_SNAKE_LEN], food; - char test[512]; /* scratch space */ - o_init (test, sizeof(test)); - - reset(snake,&snake_size,&dirc,&speed,&points,&point_s); - - food = rnd(); - - while (1) - { - head: - if(!(++c % speed)) - { - - -inpt = getInputRaw(); - -dx=DoString(0,0,IntToStrX(points,2)); - dx=(SIZE_X-dx)/2; - if(dx<0) - dx=0; - dy=(SIZE_Y-getFontHeight())/2; - - lcdFill(255); - o_rectangle(1,0,SIZE_X-2,SIZE_Y-2); - o_set_gray (0); - o_fill (); - - //o_identity (); /* reset tranforms */ - - o_set_gray (50); - - setExtFont("UBUNTU29"); - - lcdSetPixel(1,1,1); - DoString(dx,dy,IntToStrX(points,2)); - - o_set_gray (255); - - - for(n=0;n SIZE_Y/SNAKE_DEM-1 || -t.x > SIZE_X/SNAKE_DEM) - { - reset(snake,&snake_size,&dirc,&speed,&points,&point_s); - goto head; - } - - for(n=0;n MAX_SPEED) --speed; - food = rnd(); - } - } - - if(!grows) - { - for(n=0;n/dev/null && MAKE=gmake || MAKE=make +fi + TARG=../release if [ ! -d ../firmware ] ; then @@ -32,9 +38,9 @@ echo "###" echo "### Building final" echo "###" export FINAL=y -make clean +$MAKE clean ./l0dable/mktable.pl -make APP=final +$MAKE APP=final cp firmware.elf $TARG/final.elf cp firmware.bin $TARG/final.bin @@ -48,7 +54,7 @@ cp ../tools/image/lcd/i42.lcd $TARG/files/nick.lcd echo "###" echo "### Gathering loadables" echo "###" -(cd l0dable && make) +(cd l0dable && $MAKE) mv l0dable/*.c0d $TARG/files/ mv l0dable/*.int $TARG/files/ mv l0dable/*.nik $TARG/files/ @@ -59,7 +65,7 @@ if grep -q 'define ENCRYPT_L0DABLE' SECRETS ; then echo "###" echo "### Building crypto" echo "###" -(cd ../tools/crypto && make) +(cd ../tools/crypto && $MAKE) echo "###" echo "### Crypting loadables" diff --git a/tools/mesh/beacontrace.pl b/tools/mesh/beacontrace.pl new file mode 100755 index 0000000..fe90f61 --- /dev/null +++ b/tools/mesh/beacontrace.pl @@ -0,0 +1,118 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; +use Curses; +use POSIX qw(strftime); +use Time::HiRes qw(time); + +use lib '.'; +use r0ket; + +$|=1; + +r0ket::r0ket_init(); + +# Default openbeacon settings. +r0ket::set_txmac(pack("H*","0102030201")); +r0ket::set_rxmac(pack("H*","0102030201")); +r0ket::set_channel(81); +r0ket::set_rxlen(16); + +#r0ket::readbeacon(); + +my $str; +my %bdata; + +sub do_str; + +initscr; +END{endwin;} +use constant WIDTH => 80; +use constant m_height => 15; +my $win_top=subwin(2,WIDTH,0,0); +my $win=subwin(m_height,WIDTH,2,0); +noecho; +curs_set(0); +$win_top->addstr(0,0,"r0ket Beacon-Trace 0.1"); +$win_top->addstr(1,0,"-"x20); +$win_top->refresh; + +my $beaconctr=0; +use constant CLEAN => 10; +use constant UPDATE => 0.3; +my $lasttime; +my $lastcleantime; +my $clean; +my $crcerr=0; +while(1){ + $str=r0ket::get_packet(); + my $p=r0ket::nice_beacon($str); + if($p->{crc} ne "ok"){ + $crcerr++; + next; + }; + + if($p->{type} eq "beacon"){ + $bdata{$p->{beacon}}{seen}=time; + $bdata{$p->{beacon}}{beacon}=$p; + $bdata{$p->{beacon}}{stats}{$p->{strength}}++; + if(!defined($bdata{$p->{beacon}}{stats}{first})){ + $bdata{$p->{beacon}}{stats}{first}=time; + }; + }elsif($p->{type} eq "nick"){ + $bdata{$p->{beacon}}{nick}=$p->{nick}; + }else{ #unknown + ; + }; + + if(time>$lastcleantime+CLEAN){ + $clean=1; + $lastcleantime=time; + }else{ + $clean=0; + }; + + my $line=0; + if($clean){ + $win->clear; + for my $b (sort keys %bdata){ + if($bdata{$b}{seen}+10$lasttime+UPDATE){ + for my $b (sort keys %bdata){ + $win->addstr($line++,0, + sprintf "%s | bt=%s idx=%8s | %s | %s", + $b, + $bdata{$b}{beacon}->{button}, + $bdata{$b}{beacon}->{idx}, + do_str($bdata{$b}{stats}), + $bdata{$b}{nick}." " + ); + }; + $win_top->addstr(1,20,sprintf" cnt=%2d, crc=%d",scalar(keys %bdata),$crcerr); + $win_top->refresh; + + $win->refresh; + $lasttime=time; + }; +}; +r0ket::rest(); + +sub do_str{ + my $hr=shift; + my $df=time()-$hr->{first}; + $df=1 if $df==0; + my $out=""; +# for(sort keys %$hr){ + for(qw(00 55 aa ff)){ + next if $_ eq "first"; + $out.=sprintf("%3d% ",($hr->{$_}/$df)*100/2); + }; + + return $out; +}; diff --git a/tools/mesh/meshtrace.pl b/tools/mesh/meshtrace.pl new file mode 100755 index 0000000..2788083 --- /dev/null +++ b/tools/mesh/meshtrace.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; +use Curses; +use POSIX qw(strftime); + +use lib '.'; +use r0ket; + +$|=1; + +r0ket::r0ket_init(); + +# Default mesh settings. +r0ket::set_txmac("ORBIT"); +r0ket::set_rxmac("ORBIT"); +r0ket::set_channel(83); +r0ket::set_rxlen(32); + +r0ket::readbeacon(); + +my $str; +my %bdata; + +initscr; +END{endwin;} +use constant WIDTH => 80; +use constant m_height => 15; +my $win_top=subwin(2,WIDTH,0,0); +my $win=subwin(m_height,WIDTH,2,0); +noecho; +curs_set(0); +$win_top->addstr(0,0,"r0ket Mesh-Trace 0.1"); +$win_top->addstr(1,0,"-"x20); +$win_top->refresh; + +my $beaconctr=0; +my $crcerr=0; +while(1){ + $str=r0ket::get_packet(); + my $p=r0ket::nice_mesh($str); + if($p->{crc} ne "ok"){ + $crcerr++; + next; + }; + + if(!$bdata{$p->{beacon}}){ + $bdata{$p->{beacon}}=++$beaconctr; + }; + $win->addstr($bdata{$p->{beacon}},0, + sprintf "%s | g=%d rel=%s time=%s =%+4d | %s", + $p->{beacon}, + $p->{generation}, + $p->{release}, + strftime("%Y-%m-%d %H:%M:%S",gmtime $p->{time}), + $p->{time}-(time+3600), + r0ket::getbeacon($p->{beacon}) + ); + $win->refresh; +}; +r0ket::rest(); diff --git a/tools/mesh/r0ket.pm b/tools/mesh/r0ket.pm new file mode 100755 index 0000000..38baaab --- /dev/null +++ b/tools/mesh/r0ket.pm @@ -0,0 +1,345 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; + +use IO::Select; +package r0ket; + +use Digest::CRC qw(crcccitt); +use POSIX qw(strftime); +use Time::HiRes; + +our $verbose=0; +our $bridge; # Open device + +### Utility +sub sprint{ + return join("",map { + if (ord($_)>30 && ord($_)<127){ + $_; + }else{ +# "[x".unpack("H*",$_)."]"; + "\\".unpack("C",$_); + } + }split(//,shift)); +}; + +sub hprint{ + return unpack("H*",shift); +}; + +sub flagsstr { + my $in=shift; + my @f; + my $f=1; + for (@_){ + if($in & $f){ + push @f,$_; + }; + $f*=2; + }; + return join(",",@f); +}; + + + + +### Nickname/beacon helper functions +our %beacon; +sub readbeacon{ + return if( ! -f "BEACON" ); + open(B,"<","BEACON") || die "open: $!"; + while(){ + /(\w+)\s+(.*)/ && do { + $beacon{$1}=$2; + }; + }; + close(B); +}; +sub getbeacon{ + my $b=shift; + if(!$beacon{$b}){ + return ""; + }else{ + return $beacon{$b}; + }; +}; +sub resolvebeacon{ + my $b=shift; + if(!$beacon{$b}){ + return $b; + }else{ + return "$b ($beacon{$b})"; + }; +}; +sub addbeacon{ + my($b,$n)=@_; + if(!$beacon{$b}){ + $beacon{$b}=$n; + }; +}; +sub writebeacon{ + open(B,">","BEACON") || die "write: $!"; + for(sort keys %beacon){ + print B "$_ $beacon{$_}\n"; + }; + close(B); +}; + +### Packet mgmt + +our $buffer; +our $firstpkt=2; +sub get_packet{ + sub _get_bytes{ + my $rr; + sysread($bridge,$rr,1024); + if(length($rr)<=1){ + select(undef,undef,undef,0.05); + }; + $buffer.=$rr; + }; + + my $cnt=0; + while(++$cnt<100){ + if(length($buffer)<2){ + _get_bytes(); + }elsif($buffer !~ /^\\[12]/){ + $buffer=~s/^(.[^\\]*)//s; + if($firstpkt){ + $firstpkt--; + }else{ + print STDERR "Unparseable stuff: <",sprint($1),">\n"; + }; + }elsif ($buffer =~ s/^\\2\\0//s){ + return 'ack'; # In-band signalling. Evil %) + }elsif ($buffer =~ s/^\\1(.*?)\\0//s){ + my $str=$1; + $str=~s/\\\\/\\/g; # dequote + return $str; + }else{ + _get_bytes(); + }; + }; + die "No packets for 5seconds?\n"; +}; + +sub rest{ + if(length($buffer)>0){ + print "rest: <", sprint($buffer), ">\n"; + }; +}; + +### Pkt beautify +sub nice_mesh{ + my $pkt=shift; + my $out; + my $type=substr($pkt,0,1); +# next if(defined $arg && $arg ne $i); + $out->{type}=$type; + $out->{string}="[$type]"; + $out->{generation}=unpack("C",substr($pkt,1,1)); + $out->{string}.= " g=".$out->{generation}; + if($type eq "T"){ + $out->{time}= unpack("N",substr($pkt,2,4)); + $out->{release}=unpack("H*",substr($pkt,24,2)); + $out->{beacon}= unpack("H*",substr($pkt,26,4)); + + $out->{string}.=sprintf " t=%s (%+4d) rel=%s beacon=%s", + strftime("%Y-%m-%d %H:%M:%S",gmtime $out->{time}), + $out->{time}-(Time::HiRes::time+3600), + $out->{release}, + resolvebeacon($out->{beacon}); + }elsif($type eq "i"){ + $out->{score}=unpack("N",substr($pkt,2,4)); + $out->{nick}= unpack("Z*",substr($pkt,6,length($pkt)-8)); + + $out->{string}.=sprintf " score=%d nick=%s", + $out->{score}, + $out->{nick}; + }elsif($type eq "B"){ + $out->{time}=unpack("N",substr($pkt,2,4)); + $out->{id}= unpack("c",substr($pkt,6,1)); + $out->{hop}= unpack("n",substr($pkt,11,4)); + + $out->{string}.=sprintf " t=%d id=%s hop=%3d", + $out->{time}, + $out->{id}, + $out->{hop}; + }else{ + $out->{string}.= " "; + }; + + my $pkt_crc= unpack("n",substr($pkt,length($pkt)-2,2)); + my $calc_crc= crcccitt(substr($pkt,0,length($pkt)-2)); + + if ($pkt_crc eq $calc_crc){ + $out->{crc}="ok"; + }else{ + $out->{crc}="fail"; + $out->{string}.= " CRCFAIL"; + }; + + return $out; +}; + +sub nice_game{ + my $pkt=shift; + my $out; + my $type=substr($pkt,2,1); + + $out->{proto}=substr($pkt,1,1); + $out->{type} =substr($pkt,2,1); + $out->{id} =unpack("V",substr($pkt,3,4)); + $out->{ctr} =unpack("V",substr($pkt,7,4)); + + $out->{string}=sprintf "G[%s] id=%d ctr=%d", + $out->{type}, $out->{id}, $out->{ctr}; + + if($type eq "A"){ + $out->{mac} = substr($pkt,11,5); + $out->{channel} = unpack("C" ,substr($pkt,16,1)); + $out->{id} = unpack("v", substr($pkt,17,2)); + $out->{flags} = unpack("C", substr($pkt,19,1)); + $out->{flagsstr}=flagsstr($out->{flags},qw(mass short lrecv)); + $out->{interval} = unpack("C", substr($pkt,20,1)); + $out->{jitter} = unpack("C", substr($pkt,21,1)); + $out->{title} = unpack("Z*",substr($pkt,22,10)); + + $out->{string}.=sprintf " mac=%s ch=%s id=%d fl=<%s> itvl=%d j=%d %s", + sprint($out->{mac}), + $out->{channel}, + $out->{id}, + $out->{flagsstr}, + $out->{interval}, + $out->{jitter}, + $out->{title}; + }else{ + $out->{string}.= " "; + }; + + my $pkt_crc= unpack("n",substr($pkt,length($pkt)-2,2)); + my $calc_crc= crcccitt(substr($pkt,0,length($pkt)-2)); + + if ($pkt_crc eq $calc_crc){ + $out->{crc}="ok"; + }else{ + $out->{crc}="fail"; + $out->{string}.= " CRCFAIL"; + }; + + return $out; +}; + +sub nice_beacon{ + my $pkt=shift; + my $out; + my $type=substr($pkt,1,1); + $out->{type}=$type; + + if($type eq "\x17"){ + $out->{type}= "beacon"; + $out->{length}= unpack("C", substr($pkt,0,1)); + $out->{button}= unpack("H*",substr($pkt,2,1)); + $out->{strength}=unpack("H*",substr($pkt,3,1)); + $out->{idx}= unpack("N", substr($pkt,4,4)); + $out->{beacon}= unpack("H*",substr($pkt,8,4)); + $out->{unused}= unpack("H*",substr($pkt,12,2)); + + $out->{string}=sprintf "BEACON ln=%d bt=%s str=%s idx=%08x beacon=%s", + $out->{length}, + $out->{button}, + $out->{strength}, + $out->{idx}, + $out->{beacon}; + if(unpack("H*",substr($pkt,12,2)) ne "ffff"){ + print "unused=",unpack("H*",substr($pkt,12,2))," "; + }; + }elsif($type eq "\x23"){ + $out->{type}= "nick"; + $out->{beacon}= unpack("H*",substr($pkt,2,4)); + $out->{nick}= unpack("Z*",substr($pkt,6,length($pkt)-2)); + + $out->{string}=sprintf "NICK beacon=%s nick=%s", + $out->{beacon}, + $out->{nick}; + }else{ + $out->{string}=""; + }; + + my $pkt_crc= unpack("n",substr($pkt,length($pkt)-2,2)); + my $calc_crc= crcccitt(substr($pkt,0,length($pkt)-2)); + + if ($pkt_crc eq $calc_crc){ + $out->{crc}="ok"; + }else{ + $out->{crc}="fail"; + $out->{string}.= " CRCFAIL"; + }; + + return $out; +}; + +sub r0ket_init{ + my $ser; + if ($ARGV[0] eq "-s"){ + shift; + $ser=shift; + }; + if(!defined $ser){ + if (defined $ENV{R0KETBRIDGE} && -e $ENV{R0KETBRIDGE}){ + $ser=$ENV{R0KETBRIDGE} + }; + }; + if(!defined $ser){ + do {$ser=$_ if ( -e $_ ) } for qw(/dev/ttyS3 /dev/ttyACM0); + }; + open($bridge, "+<",$ser) || die "open serial: $!"; + if($verbose){ + print "using: $ser\n"; + }; +}; + +sub send_raw { + if($verbose){ + print "send: ",unpack("H*",$_[0]),"\n"; + }; + syswrite($bridge,shift); +}; + +sub send_pkt_num { + my $pkt=shift; + $pkt=~s/\\/\\\\/; + send_raw('\\'.shift().$pkt.'\0'); +}; + +sub send_pkt { + send_pkt_num(shift,1); +}; + +sub set_txmac { + send_pkt_num(shift,3); +}; +sub set_rxmac { + send_pkt_num(shift,4); +}; +sub set_channel { + send_pkt_num(pack("C",shift),5); +}; +sub set_rxlen { + send_pkt_num(pack("C",shift),6); +}; + +sub wait_ok { + my $pkt; + $pkt=get_packet(); + while($pkt ne "ack"){ + print "pkt=",(sprint $pkt),"\n"; + $pkt=get_packet(); + }; + print "ok!\n"; + return 1; +}; +1; diff --git a/tools/mesh/rf b/tools/mesh/rf new file mode 100755 index 0000000..7445876 --- /dev/null +++ b/tools/mesh/rf @@ -0,0 +1,266 @@ +#!/usr/bin/perl +# +# vim:set ts=4 sw=4: + +use strict; + +use IO::Select; +use Digest::CRC qw(crcccitt); +use POSIX qw(strftime); + +use FindBin; +use lib "$FindBin::Bin"; +use r0ket; + +$|=1; + +r0ket::r0ket_init(); + +my @fh; +my $read; + +if ($ARGV[0] =~ /^-?-?h/){ + print STDERR "Mini-Help:\n"; + print STDERR "-s (or \$R0KETBRIDGE)\n"; + print STDERR "-w write beacon2nick file\n"; + print STDERR "\n"; + print STDERR "recv: receive (number) pakets\n"; + print STDERR " - r hex : hexdump packets\n"; + print STDERR " - r ascii : asciidump packets\n"; + print STDERR " - r beacon : parse as openbeacon\n"; + print STDERR " - r mesh : parse as mesh packet\n"; + print STDERR " - r game : parse as game packet(incomplete)\n"; + print STDERR "\n"; + print STDERR "send: send packet (number) times\n"; + print STDERR " - s raw : send raw hex packet\n"; + print STDERR " - s hex : send packet with crc16\n"; + print STDERR " - s mesh t : send mesh time packet\n"; + print STDERR " - s mesh , see source :-)\n"; + print STDERR "\n"; + print STDERR "preset: config per preset\n"; + print STDERR "- p m - preset minimesh\n"; + print STDERR "- p b - preset openbeacon\n"; + print STDERR "- p a - preset game announce\n"; + print STDERR "- p r - preset sample game\n"; + print STDERR "config: config rf chip\n"; + print STDERR "- c rx - set rxmac\n"; + print STDERR "- c tx - set txmac\n"; + print STDERR "- c len - set rxlength\n"; + print STDERR "- c ch - set channel\n"; + print STDERR "- c hex - set any option via hex string\n"; + print STDERR "\n"; + print STDERR "etc...\n"; + exit(1); +}; + +my $writend=0; +if ($ARGV[0] eq "-w"){ + shift; + $writend=1; +}; + +END{ + r0ket::writebeacon if($writend); +}; + +my $cmd=shift; + +if($cmd =~ /^r/){ + r0ket::readbeacon(); + $cmd=~s/r(ecv)?//; + $cmd=100 if $cmd+0==0; + my $fmt=shift || "_"; + my $arg=shift || undef; + my $read=""; + + my $str; + while($cmd>0){ + $str=r0ket::get_packet(); + + if($fmt =~ /_/){ + if(substr($str,0,1)eq "\x10"){ + if(substr($str,1,1)eq"G"){ + $fmt="g_"; + }else{ + $fmt="b_"; + }; + }elsif(substr($str,0,1)eq "\x20"){ + $fmt="g_"; + }elsif(length($str)==32){ + $fmt="m_"; + }else{ + $fmt="x_"; + }; + }; + + if($fmt =~ /^m/){ + my $p=r0ket::nice_mesh($str); + print $p->{string}; + }elsif($fmt =~ /^b/){ + my $p=r0ket::nice_beacon($str); + print $p->{string}; + }elsif($fmt =~ /^g/){ + my $p=r0ket::nice_game($str); + print $p->{string}; + }elsif($fmt =~ /^(x|hex)/){ + my $pkt_crc= unpack("n",substr($str,length($str)-2,2)); + my $calc_crc= crcccitt(substr($str,0,length($str)-2)); + print "<",unpack("H*",$str),">"; + if($pkt_crc ne $calc_crc){ + print " CRCFAIL"; + }; + }elsif($fmt =~ /^a/){ + print "<", r0ket::sprint($str), ">"; + }else{ + die "Unknown packet format: $fmt\n"; + }; + print "\n"; + $cmd--; + next; + }; + r0ket::rest(); +}elsif ($cmd =~ /^p/){ # Preset + my $sub=shift; + if ($sub =~/^m/i){ # Default mesh settings. + r0ket::set_txmac("ORBIT"); + r0ket::set_rxmac("ORBIT"); + r0ket::set_channel(83); + r0ket::set_rxlen(32); + }elsif ($sub =~/^b/i){ # Default OpenBeacon settings + r0ket::set_txmac(pack("H*","0102030201")); + r0ket::set_rxmac(pack("H*","0102030201")); + r0ket::set_channel(81); + r0ket::set_rxlen(16); + }elsif ($sub =~/^a/i){ # Default rem0te announce settings + r0ket::set_txmac("REM0T"); + r0ket::set_rxmac("REM0T"); + r0ket::set_channel(87); + r0ket::set_rxlen(32); + }elsif ($sub =~/^r/i){ # Default bpong game settings + r0ket::set_txmac("BPONG"); + r0ket::set_rxmac("BPONG"); + r0ket::set_channel(91); + r0ket::set_rxlen(32); + }else{ + die "Unkown preset $sub\n"; + }; +}elsif ($cmd =~ /^c/){ + my $set=shift; + + if($set=~s/hex//){ + $ARGV[0]=pack("H*",$ARGV[0]); + }; + if ($set =~ /^tx/){ + r0ket::set_txmac(shift); + }elsif ($set =~ /^rx/){ + r0ket::set_rxmac(shift); + }elsif ($set =~ /^ch/){ + r0ket::set_channel(shift); + }elsif ($set =~ /^len/){ + r0ket::set_rxlen(shift); + }else{ + die "Unknown config argument $set\n"; + }; + r0ket::wait_ok(); + +}elsif ($cmd =~ /^s/){ + $cmd=~s/^//; + $cmd=1 if $cmd==0; + + my $pkt; + + my $sub=shift; + if($sub =~ /^raw/){ + $pkt=pack("H*",shift); + }elsif($sub =~ /^hex/){ + $pkt=pack("H*",shift); + $pkt.=pack("n",crcccitt($pkt)); + }elsif($sub =~ /^m/){ + my $scmd=shift; + + if($scmd eq "t"){ + $pkt.="T"; + $pkt.=chr(shift); #gen + $pkt.=pack("N",scalar(time)+1*60*60); + + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + }elsif($scmd eq "a"){ + $pkt.="A"; + $pkt.=chr(shift); #gen + $pkt.=pack("N",scalar(time)+1*60*60+ 300); + + $pkt.= pack("C",shift||0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + }elsif($scmd eq "b"){ + $pkt.="B"; + $pkt.=chr(shift); #gen + $pkt.=pack("N",scalar(time)+1*60*60+ 600); + + $pkt.= pack("C",shift||0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + }elsif($scmd eq "c"){ + $pkt.="\x1"; + $pkt.=chr(shift); #gen + $pkt.=pack("N",scalar(time)+1*60*60+ 600); + + $pkt.= pack("C",shift||0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + $pkt.= pack("C",0); + + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + $pkt.=pack("N",0); + }elsif($scmd eq "i"){ + $pkt.="i"; + $pkt.=chr(shift); #gen + $pkt.=pack("N",shift||42); + + $pkt.=shift; + $pkt.="\0"x(30-length($pkt)); + }else{ + die "Unknown mesh subtype: $scmd\n"; + }; + $pkt.=pack("n",crcccitt($pkt)); + }else{ + die "Unknown send subtype: $sub\n"; + }; + + print "Write: <", sprint($pkt),">, "; + print "crc: ",unpack("n",substr($pkt,length($pkt)-2,2))," "; + print "len: ",length($pkt),"\n"; + while($cmd-->0){ + r0ket::send_pkt($pkt); + r0ket::wait_ok; + }; +}else{ + die "Option not understood\n"; +}; + +#if (@fh = $sel->can_read(10)) { +# sysread($fh[0],$read,1024); +#} +#print "PostRead: <", sprint($read), ">\n"; diff --git a/tools/smartflash/.gitignore b/tools/smartflash/.gitignore new file mode 100644 index 0000000..b211c62 --- /dev/null +++ b/tools/smartflash/.gitignore @@ -0,0 +1,2 @@ +firmware.bin +files