From 30d3089cc82d08e69018badbf7bb27c6cc4b4332 Mon Sep 17 00:00:00 2001 From: Stefan `Sec` Zehl Date: Sat, 23 Jul 2011 14:30:20 +0200 Subject: [PATCH 1/6] Allow fonts from dataflash. use "setExtFont(filename)". for flash fonts use "setIntFont(&font)". --- firmware/applications/font.c | 49 ++++--- firmware/lcd/decoder.c | 34 +++-- firmware/lcd/fonts.h | 18 +-- firmware/lcd/render.c | 272 ++++++++++++++++++++++++++++++----- firmware/lcd/render.h | 17 +++ 5 files changed, 313 insertions(+), 77 deletions(-) diff --git a/firmware/applications/font.c b/firmware/applications/font.c index 9801653..a79b055 100644 --- a/firmware/applications/font.c +++ b/firmware/applications/font.c @@ -7,6 +7,7 @@ #include "lcd/allfonts.h" #include "filesystem/ff.h" +#include "filesystem/select.h" #include "funk/nrf24l01p.h" #include "usb/usbmsc.h" @@ -75,35 +76,22 @@ void f_init(void){ lcdPrintln("Done."); }; - -static FONT fonts[] = { - &Font_7x8, - &Font_Ubuntu18pt, - &Font_Ubuntu29pt, - &Font_Ubuntu36pt, - &Font_Orbitron14pt, - &Font_3x6, - &Font_5x8, - &Font_8x8, - &Font_8x8Thin, - &Font_Invaders -}; - +char fontname[15]; void f_nick(void){ static char ctr=0; char key; - signed char x=10; - signed char y=10; + static signed char x=10; + static signed char y=10; while (1) { lcdClear(); lcdFill(255); - font=fonts[ctr%10]; - DoString(x,y,nickname); -// lcdSafeSetPixel(x,y,1); + setExtFont(fontname); - font=&Font_7x8; + DoString(x,y,nickname); + + setIntFont(&Font_7x8); lcdSetCrsr(50,50); lcdPrintInt(x); lcdPrint("x"); @@ -135,6 +123,23 @@ void f_nick(void){ }; }; +void f_font(void){ + + if( selectFile(fontname,"F0N") != 0){ + lcdPrintln("No file selected."); + return; + }; + + lcdClear(); + lcdPrintln(fontname); + setExtFont(fontname); + lcdPrintln("PUabc€"); + setIntFont(&Font_7x8); + lcdPrintln("done."); + lcdDisplay(); + while(!getInputRaw())delayms(10); +}; + /***********************************************************************/ void gotoISP(void) { @@ -178,7 +183,7 @@ void msc_menu(void){ const struct MENU_DEF menu_ISP = {"Invoke ISP", &gotoISP}; const struct MENU_DEF menu_init = {"F Init", &f_init}; const struct MENU_DEF menu_nick = {"F Nick", &f_nick}; -//const struct MENU_DEF menu_snd = {"F Send", &f_send}; +const struct MENU_DEF menu_font = {"F sel", &f_font}; const struct MENU_DEF menu_mirror = {"Mirror", &lcd_mirror}; const struct MENU_DEF menu_invert = {"Invert", &lcd_invert}; const struct MENU_DEF menu_volt = {"Akku", &adc_check}; @@ -188,7 +193,7 @@ const struct MENU_DEF menu_nop = {"---", NULL}; static menuentry menu[] = { &menu_init, &menu_nick, -// &menu_snd, + &menu_font, &menu_nop, &menu_mirror, &menu_invert, diff --git a/firmware/lcd/decoder.c b/firmware/lcd/decoder.c index d4ff7b8..7073ee4 100644 --- a/firmware/lcd/decoder.c +++ b/firmware/lcd/decoder.c @@ -1,9 +1,6 @@ #include #include -#define MAXCHR (30*20) -static uint8_t buf[MAXCHR]; - // Local function: Get next nibble. int ctr=0; // offset for next nibble int hilo=0; // 0= high nibble next, 1=low nibble next @@ -15,7 +12,11 @@ static uint8_t buf[MAXCHR]; ctr++; hilo=1-hilo; if(hilo==1){ - byte=data[ctr]; + if(efont.type==FONT_EXTERNAL){ + byte=_getFontData(GET_DATA,0); + }else{ + byte=data[ctr]; + }; val=byte>>4; }else{ val=byte&0x0f; @@ -44,7 +45,7 @@ uint8_t * pk_decode(const uint8_t * ldata,int * len){ int length=*len; // Length of character bytestream int height; // Height of character in bytes int hoff; // bit position for non-integer heights - uint8_t * bufptr=buf; // Output buffer for decoded character + uint8_t * bufptr=charBuf; // Output buffer for decoded character height=(font->u8Height-1)/8+1; hoff=font->u8Height%8; @@ -55,10 +56,17 @@ uint8_t * pk_decode(const uint8_t * ldata,int * len){ int pos=0; // Decoder internal: current bit position (0..7) int nyb; // Decoder internal: current nibble / value - if(data[ctr]>>4 == 14){ // Char starts with 1-bits. - gnn(); - curbit=1; - }; + if(efont.type==FONT_EXTERNAL){ + if(_getFontData(PEEK_DATA,0)>>4 == 14){ // Char starts with 1-bits. + gnn(); + curbit=1; + }; + }else{ + if(data[ctr]>>4 == 14){ // Char starts with 1-bits. + gnn(); + curbit=1; + }; + }; while(ctr0){ for(int y=0;y + #include #include #include #include +#include "basic/basic.h" +#include "fonts/smallfonts.h" + +#include "filesystem/ff.h" /* Global Variables */ const struct FONT_DEF * font = NULL; -char font_direction = FONT_DIR_LTR; + +struct EXTFONT efont; + +FIL file; /* current font file */ /* Exported Functions */ +void setIntFont(const struct FONT_DEF * font){ + memcpy(&efont.def,font,sizeof(struct FONT_DEF)); + efont.type=FONT_INTERNAL; + font=NULL; +}; + +void setExtFont(const char *fname){ + if(strlen(fname)>8+4) + return; + strcpy(efont.name,fname); +// memcpy(efont.name+strlen(fname),".f0n",5); + + efont.type=FONT_EXTERNAL; + font=NULL; +}; + + +int _getFontData(int type, int offset){ + UINT readbytes; + UINT res; + static uint16_t extras; + static uint16_t character; + static const void * ptr; + + if(efont.type == FONT_EXTERNAL){ + + if (type == START_FONT){ + res = f_read(&file, &efont.def.u8Width, sizeof(uint8_t), &readbytes); + res = f_read(&file, &efont.def.u8Height, sizeof(uint8_t), &readbytes); + res = f_read(&file, &efont.def.u8FirstChar, sizeof(uint8_t), &readbytes); + res = f_read(&file, &efont.def.u8LastChar, sizeof(uint8_t), &readbytes); + res = f_read(&file, &extras, sizeof(uint16_t), &readbytes); + return 0; + }; + if (type == SEEK_EXTRAS){ + f_lseek(&file,6); + return 0; + }; + if(type == GET_EXTRAS){ + uint16_t word; + res = f_read(&file, &word, sizeof(uint16_t), &readbytes); + return word; + }; + if (type == SEEK_WIDTH){ + f_lseek(&file,6+(extras*sizeof(uint16_t))); + return 0; + }; + if(type == GET_WIDTH || type == GET_DATA){ + uint8_t width; + res = f_read(&file, &width, sizeof(uint8_t), &readbytes); + return width; + }; + if(type == SEEK_DATA){ + character=offset; + f_lseek(&file,6+ + (extras*sizeof(uint16_t))+ + ((extras+font->u8LastChar-font->u8FirstChar)*sizeof(uint8_t))+ + (offset*sizeof(uint8_t)) + ); + return 0; + }; + if(type == PEEK_DATA){ + uint8_t width; + res = f_read(&file, &width, sizeof(uint8_t), &readbytes); + f_lseek(&file,6+ + (extras*sizeof(uint16_t))+ + ((extras+font->u8LastChar-font->u8FirstChar)*sizeof(uint8_t))+ + (character*sizeof(uint8_t)) + ); + return width; + }; +#ifdef NOTYET + }else{ // efont.type==FONT_INTERNAL + + if (type == START_FONT){ + memcpy(&efont.def,font,sizeof(struct FONT_DEF)); + return 0; + }; + if (type == SEEK_EXTRAS){ + ptr=efont.def.charExtra; + return 0; + }; + if(type == GET_EXTRAS){ + uint16_t word; + word=*(uint16_t*)ptr; + ptr=((uint16_t*)ptr)+1; + return word; + }; + if (type == SEEK_WIDTH){ + ptr=efont.def.charInfo; + return 0; + }; + if(type == GET_WIDTH || type == GET_DATA){ + uint8_t width; + width=*(uint8_t*)ptr; + ptr=((uint8_t*)ptr)+1; + return width; + }; + if(type == SEEK_DATA){ + if(offset==REPEAT_LAST_CHARACTER) + offset=character; + else + character=offset; + + ptr=efont.def.au8FontTable; + return 0; + }; +#endif + }; + + /* NOTREACHED */ + return 0; +}; + +int _getIndex(int c){ +#define ERRCHR (font->u8FirstChar+1) + /* Does this font provide this character? */ + if(cu8FirstChar) + c=ERRCHR; + if(c>font->u8LastChar && efont.type!=FONT_EXTERNAL && font->charExtra == NULL) + c=ERRCHR; + + if(c>font->u8LastChar && (efont.type==FONT_EXTERNAL || font->charExtra != NULL)){ + if(efont.type==FONT_EXTERNAL){ + _getFontData(SEEK_EXTRAS,0); + int cc=0; + int cache; + while( (cache=_getFontData(GET_EXTRAS,0)) < c) + cc++; + if( cache > c) + c=ERRCHR; + else + c=font->u8LastChar+cc+1; + }else{ + int cc=0; + while( font->charExtra[cc] < c) + cc++; + if(font->charExtra[cc] > c) + c=ERRCHR; + else + c=font->u8LastChar+cc+1; + }; + }; + c-=font->u8FirstChar; + return c; +}; + +uint8_t charBuf[MAXCHR]; + int DoChar(int sx, int sy, int c){ +// font=NULL; + if(font==NULL){ + if(efont.type==FONT_INTERNAL){ + font=&efont.def; + }else if (efont.type==FONT_EXTERNAL){ + UINT res; + res=f_open(&file, efont.name, FA_OPEN_EXISTING|FA_READ); + if(res){ + efont.type=0; + font=&Font_7x8; + }else{ + _getFontData(START_FONT,0); + font=&efont.def; + }; + }else{ + font=&Font_7x8; + }; + }; + /* how many bytes is it high? */ char height=(font->u8Height-1)/8+1; char hoff=(8-(font->u8Height%8))%8; @@ -18,49 +195,76 @@ int DoChar(int sx, int sy, int c){ const uint8_t * data; int width,preblank=0,postblank=0; do { /* Get Character data */ - /* Does this font provide this character? */ - if(cu8FirstChar) - c=font->u8FirstChar+1; // error - if(c>font->u8LastChar && font->charExtra == NULL) - c=font->u8FirstChar+1; // error - - if(c>font->u8LastChar && font->charExtra != NULL){ - int cc=0; - while( font->charExtra[cc] < c) - cc++; - if(font->charExtra[cc] > c) - c=font->u8FirstChar+1; // error - else - c=font->u8LastChar+cc+1; - }; + /* Get intex into character list */ + c=_getIndex(c); /* starting offset into character source data */ int toff=0; if(font->u8Width==0){ - for(int y=0;yu8FirstChar;y++) - toff+=font->charInfo[y].widthBits; - width=font->charInfo[c-font->u8FirstChar].widthBits; + if(efont.type == FONT_EXTERNAL){ + _getFontData(SEEK_WIDTH,0); + for(int y=0;yau8FontTable[toff]; + _getFontData(SEEK_DATA,toff); + UINT res; + UINT readbytes; + res = f_read(&file, charBuf, width*height, &readbytes); + if(res != FR_OK || readbytescharInfo[y].widthBits; + width=font->charInfo[c].widthBits; + + toff*=height; + data=&font->au8FontTable[toff]; + }; postblank=1; }else if(font->u8Width==1){ // NEW CODE - // Find offset and length for our character - for(int y=0;yu8FirstChar;y++) - toff+=font->charInfo[y].widthBits; - width=font->charInfo[c-font->u8FirstChar].widthBits; - - if(font->au8FontTable[toff]>>4 == 15){ // It's a raw character! - preblank = font->au8FontTable[toff+1]; - postblank= font->au8FontTable[toff+2]; - data=&font->au8FontTable[toff+3]; - width=(width-3/height); + if(efont.type == FONT_EXTERNAL){ + _getFontData(SEEK_WIDTH,0); + for(int y=0;y>4 ==15){ + res = f_read(&file, &preblank, sizeof(uint8_t), &readbytes); + res = f_read(&file, &postblank, sizeof(uint8_t), &readbytes); + width-=3; + width/=height; + res = f_read(&file, charBuf, width*height, &readbytes); + if(res != FR_OK || readbytesau8FontTable[toff],&width); - } + // Find offset and length for our character + for(int y=0;ycharInfo[y].widthBits; + width=font->charInfo[c].widthBits; + if(font->au8FontTable[toff]>>4 == 15){ // It's a raw character! + preblank = font->au8FontTable[toff+1]; + postblank= font->au8FontTable[toff+2]; + data=&font->au8FontTable[toff+3]; + width=(width-3/height); + }else{ + data=pk_decode(&font->au8FontTable[toff],&width); + } + }; + }else{ - toff=(c-font->u8FirstChar)*font->u8Width*height; + toff=(c)*font->u8Width*height; width=font->u8Width; data=&font->au8FontTable[toff]; }; diff --git a/firmware/lcd/render.h b/firmware/lcd/render.h index 563c6a0..eaa69ef 100644 --- a/firmware/lcd/render.h +++ b/firmware/lcd/render.h @@ -2,6 +2,7 @@ #define __RENDER_H_ #include "display.h" +#include "fonts.h" /* #badge 96x68 @@ -33,5 +34,21 @@ int DoIntXn(int sx, int sy, unsigned int num, unsigned int maxlen); int DoIntX(int sx, int sy, unsigned int num); int DoCharX(int sx, int sy, unsigned char num); int DoShortX(int sx, int sy, uint16_t num); +void setIntFont(const struct FONT_DEF * font); +void setExtFont(const char *file); + +#define START_FONT 0 +#define SEEK_EXTRAS 1 +#define GET_EXTRAS 2 +#define SEEK_WIDTH 3 +#define GET_WIDTH 4 +#define SEEK_DATA 5 +#define GET_DATA 6 +#define PEEK_DATA 7 + +int _getFontData(int type, int offset); + +#define MAXCHR (30*20) +extern uint8_t charBuf[MAXCHR]; #endif From ec956a326364b3c745818a676eb3185773cdd81b Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 23 Jul 2011 15:35:00 +0200 Subject: [PATCH 2/6] working encrypted filetransfer. --- firmware/applications/vcard.c | 16 +++++++++++++--- firmware/funk/filetransfer.c | 4 ++++ firmware/funk/rftransfer.c | 11 ++++++++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/firmware/applications/vcard.c b/firmware/applications/vcard.c index 6cbda10..1cab24b 100644 --- a/firmware/applications/vcard.c +++ b/firmware/applications/vcard.c @@ -215,8 +215,10 @@ void receiveFile(void) } lcdRefresh(); #else - uint32_t k[4] = {0xffff,0xffff,0xffff,0xffff}; - if( filetransfer_receive(mac,(uint32_t*)k) ) + //uint32_t k[4] = {0xffff,0xffff,0xffff,0xffff}; + + //k[0] = 0; k[1] = 0; k[2] = 0; k[3] = 0; + if( filetransfer_receive(mac,(uint32_t*)k1) ) continue; lcdPrintln("Done"); lcdPrintln("Right=OK"); @@ -270,7 +272,8 @@ void sendFile(char *filename) #else delayms(3000); uint32_t k[4] = {0xffff,0xffff,0xffff,0xffff}; - filetransfer_send((uint8_t*)filename, 0, mac, (uint32_t*)k); + k[0] = 0; k[1] = 0; k[2] = 0; k[3] = 0; + filetransfer_send((uint8_t*)filename, 0, mac, (uint32_t*)k1); lcdPrintln("Done"); lcdPrintln("Right=OK"); lcdPrintln("Left=Retry"); @@ -340,6 +343,13 @@ void main_vcard(void) { lcdPrintln("Done"); lcdRefresh(); }else if(key==BTN_RIGHT){ + DoString(0,8,"MSC Enabled."); + lcdDisplay(); + usbMSCInit(); + while(!getInputRaw())delayms(10); + DoString(0,16,"MSC Disabled."); + usbMSCOff(); + } //encryption_decryption_demo("This is encrypted", diff --git a/firmware/funk/filetransfer.c b/firmware/funk/filetransfer.c index aa8618a..683a000 100644 --- a/firmware/funk/filetransfer.c +++ b/firmware/funk/filetransfer.c @@ -17,6 +17,7 @@ int filetransfer_send(uint8_t *filename, uint16_t size, FRESULT res; UINT readbytes; + if( size > MAXSIZE ) return 1; //File to big @@ -25,6 +26,9 @@ int filetransfer_send(uint8_t *filename, uint16_t size, return res; //res = f_read(&file, (char *)buf, size, &readbytes); + for(uint16_t i=0; i> 8; buf[4] = rand & 0xFF; - for(i=5; i0; i++,size--){ + for(i=5; i0; i++,size--){ buf[i] = *data++; } index++; @@ -45,6 +45,7 @@ void rftransfer_send(uint16_t size, uint8_t *data) //nrf_snd_pkt_crc(5,buf); //crc packet nrf_snd_pkt_crc(32,buf); //setup packet delayms(20); + lcdPrint("crc="); lcdPrintIntHex(crc);lcdPrintln("");lcdRefresh(); } uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) @@ -67,7 +68,8 @@ uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) pos = 0; if( size <= maxlen ){ lcdClear(); - lcdPrintln("got l"); lcdRefresh(); + lcdPrint("got l="); lcdPrintInt(size); + lcdPrintln(""); lcdRefresh(); state = 1; } } @@ -79,7 +81,7 @@ uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) lcdPrintln(" in seq"); lcdRefresh(); //if( (pos + n - 5) Date: Sat, 23 Jul 2011 17:58:56 +0200 Subject: [PATCH 3/6] vcard: small clean up --- firmware/applications/vcard.c | 79 ++++++----------------------------- firmware/funk/filetransfer.c | 24 ++++++++--- firmware/funk/rftransfer.c | 35 +++++++--------- firmware/funk/rftransfer.h | 2 +- 4 files changed, 47 insertions(+), 93 deletions(-) diff --git a/firmware/applications/vcard.c b/firmware/applications/vcard.c index 1cab24b..a5bf28a 100644 --- a/firmware/applications/vcard.c +++ b/firmware/applications/vcard.c @@ -58,7 +58,6 @@ int receiveKey(uint8_t type, uint8_t *x, uint8_t *y) uint8_t n; n = nrf_rcv_pkt_time(1000, 32, buf); - lcdPrint("pkt:"); lcdPrintInt(n);lcdPrintln(""); lcdRefresh(); if( n == 32 && buf[0] == type && buf[1] == 'X' ){ for(int i=0; i MAXSIZE ) return 1; //file to big //if(fileexists(metadata)) return 1; //file already exists - lcdPrint("open"); lcdPrintln((const char*)metadata); lcdRefresh(); + //lcdPrint("open"); lcdPrintln((const char*)metadata); lcdRefresh(); res = f_open(&file, (const char*)metadata, FA_OPEN_ALWAYS|FA_WRITE); //lcdPrintln("file opened"); lcdRefresh(); @@ -94,9 +97,18 @@ int filetransfer_receive(uint8_t *mac, uint32_t const k[4]) uint16_t wordcount = (size+3)/4; //nrf_set_rx_mac(0, 32, 5, mac); - lcdPrintln("get file"); lcdRefresh(); - rftransfer_receive(buf, wordcount*4, 1000); - lcdPrintln("got file"); lcdRefresh(); + //lcdPrintln("get file"); lcdRefresh(); + int fres = rftransfer_receive(buf, wordcount*4, 1000); + if( fres == -1 ){ + lcdPrintln("checksum wrong"); + }else if( fres == -2 ){ + lcdPrintln("timeout"); + }else{ + //lcdPrintln("got file"); + } + lcdRefresh(); + if( fres < 0 ) + return; //nrf_set_rx_mac(0, 32, 5, macbuf); xxtea_decode_words((uint32_t *)buf, wordcount, k); @@ -107,6 +119,8 @@ int filetransfer_receive(uint8_t *mac, uint32_t const k[4]) return res; if( written != size ) return 1; //error while writing + lcdClear(); + lcdPrintln("Received"); lcdPrintln((const char*)metadata); lcdRefresh(); return 0; } diff --git a/firmware/funk/rftransfer.c b/firmware/funk/rftransfer.c index 88022fb..7c52423 100644 --- a/firmware/funk/rftransfer.c +++ b/firmware/funk/rftransfer.c @@ -16,7 +16,6 @@ void rftransfer_send(uint16_t size, uint8_t *data) buf[3] = rand >> 8; buf[4] = rand & 0xFF; - //nrf_snd_pkt_crc(5,buf); //setup packet nrf_snd_pkt_crc(32,buf); //setup packet delayms(20); uint16_t index = 0; @@ -42,13 +41,11 @@ void rftransfer_send(uint16_t size, uint8_t *data) buf[2] = crc & 0xFF; buf[3] = rand >> 8; buf[4] = rand & 0xFF; - //nrf_snd_pkt_crc(5,buf); //crc packet nrf_snd_pkt_crc(32,buf); //setup packet delayms(20); - lcdPrint("crc="); lcdPrintIntHex(crc);lcdPrintln("");lcdRefresh(); } -uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) +int16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) { uint8_t buf[MAXPACKET]; uint8_t state = 0; @@ -57,7 +54,7 @@ uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) unsigned int currentTick = systickGetTicks(); unsigned int startTick = currentTick; - while(currentTick < (startTick+timeout) ){//this fails if either overflows + while(systickGetTicks() < (startTick+timeout) ){//this fails if either overflows n = nrf_rcv_pkt_time(1000, MAXPACKET, buf); switch(state){ case 0: @@ -67,49 +64,45 @@ uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) seq = 0; pos = 0; if( size <= maxlen ){ - lcdClear(); - lcdPrint("got l="); lcdPrintInt(size); - lcdPrintln(""); lcdRefresh(); + //lcdClear(); + //lcdPrint("got l="); lcdPrintInt(size); + //lcdPrintln(""); lcdRefresh(); state = 1; } } break; case 1: if( n == 32 && buf[0] == 'D' && ((buf[3]<<8)|buf[4])==rand ){ - lcdPrint("got d"); lcdRefresh(); + //lcdPrint("got d"); lcdRefresh(); if( seq == ((buf[1]<<8)|buf[2]) ){ - lcdPrintln(" in seq"); lcdRefresh(); - //if( (pos + n - 5) void rftransfer_send(uint16_t size, uint8_t *data); -uint16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout); +int16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout); #endif From 404b789c04a54d364c9c528866803ad97fd4aef6 Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 23 Jul 2011 19:17:14 +0200 Subject: [PATCH 4/6] openbeacon: use chip id --- firmware/applications/funk.c | 2 +- firmware/basic/uuid.c | 14 ++++++++++++-- firmware/basic/uuid.h | 8 ++++++++ firmware/funk/openbeacon.c | 5 +++-- 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 firmware/basic/uuid.h diff --git a/firmware/applications/funk.c b/firmware/applications/funk.c index 0160188..d592dbe 100644 --- a/firmware/applications/funk.c +++ b/firmware/applications/funk.c @@ -227,7 +227,7 @@ void main_funk(void) { backlightInit(); font=&Font_7x8; - openbeaconSetup(0x5ec); + openbeaconSetup(); while (1) { lcdFill(0); // clear display buffer lcdDisplay(); diff --git a/firmware/basic/uuid.c b/firmware/basic/uuid.c index 1758ddc..0b28f5d 100644 --- a/firmware/basic/uuid.c +++ b/firmware/basic/uuid.c @@ -1,14 +1,24 @@ #include "lpc134x.h" #include "sysdefs.h" #include "basic.h" +#include "xxtea.h" #include "core/iap/iap.h" uint32_t GetUUID32(void){ IAP_return_t iap_return; iap_return = iapReadSerialNumber(); - - return iap_return.Result[1]; + if (iap_return.ReturnCode == 0){ + uint32_t block[4]; + uint32_t k[4] = {1,2,3,4}; + block[0] = iap_return.Result[0]; + block[1] = iap_return.Result[1]; + block[2] = iap_return.Result[2]; + block[3] = iap_return.Result[3]; + xxtea_encode_words(block, 4, k); + return block[0]; + } + return 0; }; // What OpenBeacon used. Do we want this? diff --git a/firmware/basic/uuid.h b/firmware/basic/uuid.h new file mode 100644 index 0000000..d64d92b --- /dev/null +++ b/firmware/basic/uuid.h @@ -0,0 +1,8 @@ +#ifndef _UUID_H_ +#define _UUID_H_ +#include + +uint32_t GetUUID32(void); + +#endif + diff --git a/firmware/funk/openbeacon.c b/firmware/funk/openbeacon.c index 2b919bf..ab90436 100644 --- a/firmware/funk/openbeacon.c +++ b/firmware/funk/openbeacon.c @@ -4,6 +4,7 @@ #include "basic/byteorder.h" #include "sysdefs.h" #include "filesystem/ff.h" +#include "basic/uuid.h" //const uint32_t key[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; const uint32_t openbeaconkey[4] = { 0xB4595344,0xD3E119B6,0xA814D0EC,0xEFF5A24E }; @@ -59,9 +60,9 @@ void openbeaconRead() } -void openbeaconSetup(uint32_t id) +void openbeaconSetup(void) { - oid = id; + oid = GetUUID32(); strength = 0; openbeaconRead(); openbeaconSaveBlock(); From f77bb1f04a248efdebb5149aa1a5aafe76b2e2c8 Mon Sep 17 00:00:00 2001 From: schneider Date: Sat, 23 Jul 2011 21:47:29 +0200 Subject: [PATCH 5/6] basic: don't crash on bus interrupt --- firmware/basic/basic.c | 21 +++++++++++++++------ firmware/basic/basic.h | 1 - 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/firmware/basic/basic.c b/firmware/basic/basic.c index d60bff0..819de91 100644 --- a/firmware/basic/basic.c +++ b/firmware/basic/basic.c @@ -126,12 +126,7 @@ void rbInit() { gpioIntEnable(RB_BUSINT); // add this to catch interrupt: /* - void PIOINT3_IRQHandler(void) { - if (gpioIntStatus(RB_BUSINT)) { - // do something - gpioIntClear(RB_BUSINT); - } - } + */ //nrf_init(); @@ -139,3 +134,17 @@ void rbInit() { font=&Font_7x8; ECIES_setup(); } +#define WEAK_ALIAS(f) __attribute__ ((weak, alias (#f))); +void interrupt_undefined(void) { +} + +void businterrupt(void) WEAK_ALIAS(interrupt_undefined); + + +void PIOINT3_IRQHandler(void) { + if (gpioIntStatus(RB_BUSINT)) { + gpioIntClear(RB_BUSINT); + businterrupt(); + } +} + diff --git a/firmware/basic/basic.h b/firmware/basic/basic.h index f754f18..8c6f5d0 100644 --- a/firmware/basic/basic.h +++ b/firmware/basic/basic.h @@ -172,5 +172,4 @@ struct MENU { void handleMenu(const struct MENU *the_menu); - #endif From cb5899bc4692260ec7ec59466b786256f4543b37 Mon Sep 17 00:00:00 2001 From: Stefan `Sec` Zehl Date: Sat, 23 Jul 2011 21:52:02 +0200 Subject: [PATCH 6/6] Commit a few sample binary fonts --- tools/font/binary/invaders.f0n | Bin 0 -> 112 bytes tools/font/binary/orbit14.f0n | Bin 0 -> 1635 bytes tools/font/binary/ubuntu18.f0n | Bin 0 -> 2128 bytes tools/font/binary/ubuntu29.f0n | Bin 0 -> 3731 bytes tools/font/binary/ubuntu36.f0n | Bin 0 -> 4791 bytes 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/font/binary/invaders.f0n create mode 100644 tools/font/binary/orbit14.f0n create mode 100644 tools/font/binary/ubuntu18.f0n create mode 100644 tools/font/binary/ubuntu29.f0n create mode 100644 tools/font/binary/ubuntu36.f0n diff --git a/tools/font/binary/invaders.f0n b/tools/font/binary/invaders.f0n new file mode 100644 index 0000000000000000000000000000000000000000..9f5b2844f429e998ab0130b6b1f20c73aac75d65 GIT binary patch literal 112 zcmZSJaCBy42w(_hNMuN2NM`u|pPPr1U4Wa1qd=l|+a8-e+iE2W=FE#LGmnoqFN>Qu zCt{D7y}g;t4u=D8>g?;@98fT*cvEAeS68QJQ}d?6Kw+Lmt(lFDjajY5JejzE+d$g3 Q{fm>C5wk5mep}2805n@FIRF3v literal 0 HcmV?d00001 diff --git a/tools/font/binary/orbit14.f0n b/tools/font/binary/orbit14.f0n new file mode 100644 index 0000000000000000000000000000000000000000..cf77c3aa19fd161c00469fab1894fe965008d55d GIT binary patch literal 1635 zcmZ8hOKcle6!jaD_?N`?_>(w^YtNf;98dF5Gi{($nuSOGL`X*Uv=s+b z7uyx^4!GSeSC8A*-Q@~7!XdY-C**Othq!H_xZP_<9i2Xx)9rQixa?g)d#}UgbUA!Z zXDBk*J>=+c+WYzf-dKOo<47S^Ebd`u(2qMfxxf^Wk}?jHpj0^{jT=IiQFKlqok}G` zq+o^GY(0$d{$)u~&b;!oAZ$NIo-xq*x_?OEM|pm9r=Kw6Cec=jR+Z!sHUfTvQp!q7 zy>?WWeQ3CZDOHnHZ7iqZoW|ufHm~{e*VNl}GJ^~NltiOTZZVcbthUho z<#trAapY9<_})54H0G<4ukmMN-5Xv@7tlI7aTLuU*79!4!O8R|x7T5sVnXB+A|4j` zxXAAk1woAS;xHByoS1l3zk|jQgw8J-Ktf3UMp@1SEC6?)d<3>|p*&mGN_j@S~_+*@%n!b*L$7 zP@uFP8vm;(4#s?KC#4x8jZ#ig7QyXh!KgeE$YnBfl*T?3#dRSlo+6zo$P*dRs~bdi z8&EI&XNtL|{BglDegGT3yH8FxvWIvxE;CbQt+>+mmS(L;26mgI(2%DZa^8~X+U=TK zq-p-M(Il`v)!g*9$=nb{UB5!XnHzC3QhT}0B{;9&+Dd3Xh!ekhTm70<=doIxs2%jf zoKlVz{K&-2v>H|YUhe8FimE=gnUDO z9_Gtx48%%$F3UN?nc?>Fr=%`V@kIC=g zPb44u6G?Ny7NjZakJ`xw@dXa~?r$#O*a&r->ybH_e^oNaWhSqO`wxt6?yY7IH?rrz+mzp|X7|<}ThuB}Bj1dkAgo%E$dQKpc1-lel=ucFqsuvrF^D*l`5U|QK>Gjy literal 0 HcmV?d00001 diff --git a/tools/font/binary/ubuntu18.f0n b/tools/font/binary/ubuntu18.f0n new file mode 100644 index 0000000000000000000000000000000000000000..8d13d36ed25dbafd53aa15589fad452e7c4e6f8d GIT binary patch literal 2128 zcmZ8iZ%iBK8TZ`*2{a_&3*k?Im^&L|J8xFsnP4ENk~{vCt+y5%n5NCrI5#Ys&`!baG&gcI`Q%t96A1ZZ@+G$my?mcMt zr_w9mbI<#{@AJFg^Lrj+Eta2Dn|4eY)1K)srVmY@njV|pv3&kHUU{Um1=uQTkDaWp zs;oS5vZlScsj01@qpj*_V^t%0uC1ZLTvO9fQ(4=3r1exQ*>&nnwYiz~1D12+NWr z`=kUbY;>ti$W!DtQWDo>O$uyW^2yRvOwgm#*gb48w;(Z|h?iNCj*;iz z8;9KWEY10NVhRCs;s4U$doRsu9w1@$4}c_SJ>U8c)PBwoa+U-^b1r%{9Tm(u5-8Xh z_6C!AoY}XuJ^;VX5A$cl34$+5PJK|wYEoM^C`G9rzm$Q=ybV8o`b0?O_fxU zQ}&!s27ZihD{JvMxhT^SnGMT=WB?2@@%i|Qf_Grdy@V2nj)$E#N2kZ(5nRkWLGdIp zg9QtL2$`ispP<_~CaBp*pNJ~~xk5>M+_*o%AO z?R@B`X*$46Lc54hLOS5pLz5YCnNacj`Yi@&B*?}GnIwJc1CKh;gU#!kC&#yAijqj) zVxXhH&t*AhMDoyCR<>j~Bs$VpnhcMG&f*=&(*J5hVsL-;=&OBKEzcU;e*@3xxRI`6 zW~|8FL3K|SQoD5{#vZqlbAuqG4+5(MpLKoR@mw>gU&h^N@0Ns$@6z;ibSW#&WdfJ7 zkBWhfqKMYz)zP=Ui9+(+Qchenez{nVTkS;|{tpFp@ByygLpm6ALff|kT1p)-z3>vM z;Cy=3Iu0FY5o^6=*u~*Z9n zNzST*D3IAtvTknBqxSTVjskpHt0S{*iM%+M6&JP7&^SPZ6}Wq27`?Tk+>nhP^Bgu9 zFV8Y^%q+hxZ^+x28;`!rWJ;F$j5vJ&3n4RfvRBHK=)%WC*!sa;$s%G}oXc_R#KqFz zi(nmhBTt@NuegRr4C033VaZAZoTuULX#&+T9f_zV2Qbg7-CS?xg>LLpW|j48cF@kt z*vyx2+;Iv?8k|X2Oc^eZnN(SdJ8tF~Xr(xuCsk``j<|^L_UT!Q`=OaBTFlrawElwb z?xT8~RLSAI>_nn65@z;6Ox7r;Y&pm$2;` z{*gDmSg=qiytofm;Nv3qK9v`bsc*F$x(;tUgsS#{b_BHt(EilwC1MPZKCgBG1O0zo z{~M@wIrNXef&W=WS6dn}DyZ24X2Gl)6tN7Xt$-kTbpp`XKk$#7saOP-9F|7>Gj*5D z8?ExhAJ=ebU43l{}H>;oHhh^8wn1TfR4ZsQ00S^=Kzz<4e(3Gv{*zlEK(4` zbZmtam`oX~M;fUZD`m>8?up&VsA8O$!osMXi{%1%7fG8_h_Qp2^8@c|UV6f73!!$h zNrw4a&lh9ozYWR?Nt#Dl%Lp(|qZgmT`eQre#`NqsXc?^=u)OXm7t1=b{D-ZB@4EB? zmyGzO$ha>enE43L&=GbhM*HvP2E2w0DKBHCyjGg>mJI=+rhqYlB!)!#R ze}?kPG_qrU_SZ<7i1w}Ce(wb@N(jA>j+)%q%M`er+O6u`q9`g!QS==%L!ti;CcYKl Gn))~C_*Y{9 literal 0 HcmV?d00001 diff --git a/tools/font/binary/ubuntu29.f0n b/tools/font/binary/ubuntu29.f0n new file mode 100644 index 0000000000000000000000000000000000000000..60e33cf1de5e75c06cc28f5af02c68e7a3ac7c1f GIT binary patch literal 3731 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 literal 0 HcmV?d00001 diff --git a/tools/font/binary/ubuntu36.f0n b/tools/font/binary/ubuntu36.f0n new file mode 100644 index 0000000000000000000000000000000000000000..df0bd903a7dc322ec4b64331b14b393d4e061b93 GIT binary patch literal 4791 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 literal 0 HcmV?d00001