diff --git a/.gitignore b/.gitignore index 4f6b597..c9e3e5a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.a *.swp release +*.pyc diff --git a/firmware/BRIDGE-PROTOCOL b/firmware/BRIDGE-PROTOCOL new file mode 100644 index 0000000..e812eae --- /dev/null +++ b/firmware/BRIDGE-PROTOCOL @@ -0,0 +1,18 @@ +Receiving: +r->h: \1\0 + +Sending: +h->r: \1\0 +r->h: \2\0 + +Settings: +h->r:\3\0 +r->h: \2\0 +h->r:\4\0 +r->h: \2\0 +h->r:\5\0 +r->h: \2\0 +h->r:\6\0 +r->h: \2\0 + + diff --git a/firmware/SECRETS.release b/firmware/SECRETS.release index 84d2d01..a87bb87 100644 --- a/firmware/SECRETS.release +++ b/firmware/SECRETS.release @@ -1,7 +1,7 @@ #ifndef _SECRETS_ #define _SECRETS_ -#define ENCRYPT_L0DABLE 1 +#undef ENCRYPT_L0DABLE 1 static uint32_t const meshkey[4] = { 0xafbbcb26, 0x39108427, 0x455ef5e5, 0x51b482d2 diff --git a/firmware/applications/default.c b/firmware/applications/default.c index b5a357c..7c518ea 100644 --- a/firmware/applications/default.c +++ b/firmware/applications/default.c @@ -82,7 +82,7 @@ void tick_default(void) { gpioSetValue (RB_LED0, 1); gpioSetValue (RB_LED2, 1); posleds = 1; - }else if( posleds = 1 ){ + }else if( posleds ){ gpioSetValue (RB_LED0, 0); gpioSetValue (RB_LED2, 0); } diff --git a/firmware/applications/remote/config.c b/firmware/applications/remote/config.c new file mode 100644 index 0000000..0d8df7c --- /dev/null +++ b/firmware/applications/remote/config.c @@ -0,0 +1,38 @@ +#include + +#include "basic/basic.h" + +#include "lcd/print.h" +#include "lcd/display.h" + +#include "filesystem/ff.h" + +#include + +/**************************************************************************/ + +void readcfg(void) { + readConfig(); +}; + +void savecfg(void){ + saveConfig(); +}; + +void applycfg(void){ + applyConfig(); +}; + +void show(void){ + lcdClear(); + lcdPrint("time:"); lcdPrintInt(globalconfig.time); lcdNl(); + lcdPrint("btrig:"); lcdPrintInt(globalconfig.backlighttrigger); lcdNl(); + lcdPrint("bval:"); lcdPrintInt(globalconfig.backlightvalue); lcdNl(); + lcdPrint("lcd:"); lcdPrintInt(globalconfig.lcdstate); lcdNl(); + lcdPrint("priv:"); lcdPrintInt(globalconfig.privacy); lcdNl(); + lcdRefresh(); +}; + +void lcdmirror(void){ + lcdToggleFlag(LCD_MIRRORX); +}; diff --git a/firmware/applications/remote/remote.c b/firmware/applications/remote/remote.c new file mode 100644 index 0000000..0c2dbb5 --- /dev/null +++ b/firmware/applications/remote/remote.c @@ -0,0 +1,272 @@ +#include + +#include "basic/basic.h" +#include "basic/byteorder.h" + +#include "lcd/lcd.h" +#include "lcd/print.h" + +#include "funk/nrf24l01p.h" +#include "usbcdc/usb.h" +#include "usbcdc/usbcore.h" +#include "usbcdc/usbhw.h" +#include "usbcdc/cdcuser.h" +#include "usbcdc/cdc_buf.h" +#include "usbcdc/util.h" + +#include + +#define REMOTE_CHANNEL 91 +#define REMOTE_MAC "REM0T" + +#if CFG_USBMSC +#error "MSC is defined" +#endif + +#if !CFG_USBCDC +#error "CDC is not defined" +#endif + +/**************************************************************************/ + +#include "SECRETS" + +void r_init(void){ + nrf_init(); + + struct NRF_CFG config = { + .channel= REMOTE_CHANNEL, + .txmac= REMOTE_MAC, + .nrmacs=1, + .mac0= REMOTE_MAC, + .maclen ="\x10", + }; + + nrf_config_set(&config); +}; + +void s_init(void){ + usbCDCInit(); + nrf_init(); + + struct NRF_CFG config = { + .channel= REMOTE_CHANNEL, + .txmac= REMOTE_MAC, + .nrmacs=1, + .mac0= REMOTE_MAC, + .maclen ="\x10", + }; + + nrf_config_set(&config); +}; + + void process(uint8_t * input){ + __attribute__ ((aligned (4))) uint8_t buf[32]; + puts("process: "); + puts(input); + puts("\r\n"); + if(input[0]=='M'){ + buf[0]=0x10; // Length: 16 bytes + buf[1]='M'; // Proto + buf[2]=0x01; + buf[3]=0x01; // Unused + + uint32touint8p(0,buf+4); + + uint32touint8p(0x41424344,buf+8); + + buf[12]=0xff; // salt (0xffff always?) + buf[13]=0xff; + nrf_snd_pkt_crc_encr(16,buf,remotekey); + nrf_rcv_pkt_start(); + }; + +}; + +#define INPUTLEN 99 +void r_recv(void){ + __attribute__ ((aligned (4))) uint8_t buf[32]; + int len; + + uint8_t input[INPUTLEN+1]; + int inputptr=0; + + nrf_rcv_pkt_start(); + puts("D start"); + + getInputWaitRelease(); + + while(!getInputRaw()){ + delayms(100); + + // Input + int l=INPUTLEN-inputptr; + CDC_OutBufAvailChar (&l); + + if(l>0){ + CDC_RdOutBuf (input+inputptr, &l); + input[inputptr+l+1]=0; + for(int i=0;i0){ + lcdPrint("Got!"); + lcdDisplay(); + break; + }; + delayms(10); + }; +}; + diff --git a/firmware/applications/remote/serial.c b/firmware/applications/remote/serial.c new file mode 100644 index 0000000..94d41b3 --- /dev/null +++ b/firmware/applications/remote/serial.c @@ -0,0 +1,139 @@ +#include + +#include "basic/basic.h" + +#include "lcd/lcd.h" +#include "lcd/print.h" + +#include "funk/nrf24l01p.h" + +#include "usbcdc/usb.h" +#include "usbcdc/usbcore.h" +#include "usbcdc/usbhw.h" +#include "usbcdc/cdcuser.h" +#include "usbcdc/cdc_buf.h" +#include "usbcdc/util.h" + +#include + +#define BEACON_CHANNEL 81 +#define BEACON_MAC "\x1\x2\x3\x2\1" + +uint32_t const testkey[4] = { + 0xB4595344,0xD3E119B6,0xA814D0EC,0xEFF5A24E +}; + +#if CFG_USBMSC +#error "MSC is defined" +#endif + +#if !CFG_USBCDC +#error "CDC is not defined" +#endif + +/**************************************************************************/ + + +void ser_enable(void) { + usbCDCInit(); +}; + +void ser_disable(void) { + usbCDCOff(); +}; + +#define myLEN 10 +void ser_read(){ + uint8_t buf[myLEN+1]; + int l=myLEN; + + lcdPrint("Bytes:"); + CDC_OutBufAvailChar (&l); + lcdPrintInt(l); + lcdNl(); + + lcdPrint("read:"); + CDC_RdOutBuf (buf, &l); + lcdPrintInt(l); + lcdNl(); + + buf[l]=0; + lcdPrintln(buf); +}; + +void ser_say(){ + puts("hello world\r\n"); +}; + +void f_init(){ + nrf_init(); + struct NRF_CFG config = { + .channel= BEACON_CHANNEL, + .txmac= BEACON_MAC, + .nrmacs=1, + .mac0= BEACON_MAC, + .maclen ="\x10", + }; + + nrf_config_set(&config); +}; + +void f_beacon(void){ + struct NRF_CFG config = { + .channel= BEACON_CHANNEL, + .txmac= BEACON_MAC, + .nrmacs=1, + .mac0= BEACON_MAC, + .maclen ="\x10", + }; + + nrf_config_set(&config); +}; + +int enctoggle=0; + +void f_enctog(){ + enctoggle=1-enctoggle; + lcdClear(); + lcdPrint("Encryption:"); + if(enctoggle) + lcdPrintln("ON"); + else + lcdPrintln("Off"); +}; + +void f_recser(void){ + __attribute__ ((aligned (4))) uint8_t buf[32]; + int len; + + getInputWaitRelease(); + + do{ + len=nrf_rcv_pkt_time_encr(1000,sizeof(buf),buf,enctoggle?testkey:NULL); + + if(len==0){ + puts("(Timeout)\r\n"); + }; + puts("pkt: "); + puts("[");puts(IntToStrX(len,2));puts("] "); + puts(IntToStrX( *(int*)(buf+ 0),2 )); + puts(" "); + puts(IntToStrX( *(int*)(buf+ 1),2 )); + puts(" "); + puts(IntToStrX( *(int*)(buf+ 2),2 )); + puts(" "); + puts(IntToStrX( *(int*)(buf+ 3),2 )); + puts("."); + puts(IntToStrX( *(int*)(buf+ 4),8 )); + puts("."); + puts(IntToStrX( *(int*)(buf+ 8),8 )); + puts("."); + puts(IntToStrX( *(int*)(buf+ 12),4 )); + puts(" ["); + + len=crc16(buf,14); + puts(IntToStrX(len,4)); puts("]\r\n"); + delayms(10); + }while ((getInputRaw())==BTN_NONE); + +}; diff --git a/firmware/applications/remote/util.c b/firmware/applications/remote/util.c new file mode 100644 index 0000000..8359628 --- /dev/null +++ b/firmware/applications/remote/util.c @@ -0,0 +1,128 @@ +#include + +#include "basic/basic.h" + +#include "lcd/lcd.h" +#include "lcd/print.h" +#include "lcd/allfonts.h" + +#include "filesystem/ff.h" +#include "filesystem/select.h" +#include "funk/nrf24l01p.h" +#include "usb/usbmsc.h" + +#include + +/**************************************************************************/ + +void show_ticks(void) { + int dx=0; + int dy=8; + lcdClear(); + dx=DoString(0,dy,"Ticks:"); + while ((getInputRaw())==BTN_NONE){ + DoInt(0,dy+8,_timectr); + lcdDisplay(); + }; + dy+=16; + dx=DoString(0,dy,"Done."); +}; + + +void chrg_stat(void) { + int stat; + while ((getInputRaw())==BTN_NONE){ + lcdClear(); + lcdPrintln("Chrg_stat:"); + stat=gpioGetValue(RB_PWR_CHRG); + lcdPrint(IntToStr(stat,3,0)); + lcdNl(); + lcdRefresh(); + }; + lcdPrintln("Done."); +}; +void adc_light(void) { + int dx=0; + int dy=8; + dx=DoString(0,dy,"Light:"); + DoString(0,dy+16,"Night:"); + while ((getInputRaw())==BTN_NONE){ + DoInt(dx,dy,GetLight()); + DoInt(dx,dy+16,isNight()); + DoInt(dx,dy+8,GLOBAL(daytrig)); + lcdDisplay(); + }; + dy+=8; + dx=DoString(0,dy,"Done."); +}; + +void uptime(void) { + int t; + int h; + char flag; + while ((getInputRaw())==BTN_NONE){ + lcdClear(); + lcdPrintln("Uptime:"); + t=getTimer()/(1000/SYSTICKSPEED); + h=t/60/60; + flag=F_ZEROS; + if(h>0){ + lcdPrint(IntToStr(h,2,flag)); + lcdPrint("h"); + flag|=F_LONG; + }; + h=t/60%60; + if(h>0){ + lcdPrint(IntToStr(h,2,flag)); + lcdPrint("m"); + flag|=F_LONG; + }; + h=t%60; + if(h>0){ + lcdPrint(IntToStr(h,2,flag)); + lcdPrint("s"); + }; + lcdNl(); + lcdRefresh(); + delayms_queue(200); + }; + lcdPrintln("done."); +}; + +void gotoISP(void) { + DoString(0,0,"Enter ISP!"); + lcdDisplay(); + ISPandReset(); +} + +void lcd_mirror(void) { + lcdToggleFlag(LCD_MIRRORX); +}; + +void lcd_invert(void) { + lcdToggleFlag(LCD_INVERTED); +}; + +void adc_check(void) { + int dx=0; + int dy=8; + // Print Voltage + dx=DoString(0,dy,"Voltage:"); + while ((getInputRaw())==BTN_NONE){ + DoInt(dx,dy,GetVoltage()); + lcdDisplay(); + }; + dy+=8; + dx=DoString(0,dy,"Done."); +}; + +void msc_menu(void){ + DoString(0,8,"MSC Enabled."); + lcdDisplay(); + usbMSCInit(); + getInputWaitRelease(); + getInputWait(); + DoString(0,16,"MSC Disabled."); + usbMSCOff(); +}; + diff --git a/firmware/applications/remote/uuid.c b/firmware/applications/remote/uuid.c new file mode 100644 index 0000000..601a5f7 --- /dev/null +++ b/firmware/applications/remote/uuid.c @@ -0,0 +1,26 @@ +#include + +#include "basic/basic.h" + +#include "lcd/lcd.h" +#include "lcd/print.h" + +#include "funk/nrf24l01p.h" + +#include + +#include "funk/rftransfer.h" +#include "funk/openbeacon.h" + +#include "core/iap/iap.h" + +/**************************************************************************/ + +void f_uuid(void) { + IAP_return_t iap_return; + iap_return = iapReadSerialNumber(); + lcdPrintIntHex(iap_return.Result[0]); lcdNl(); + lcdPrintIntHex(iap_return.Result[1]); lcdNl(); + lcdPrintIntHex(iap_return.Result[2]); lcdNl(); + lcdPrintIntHex(iap_return.Result[3]); lcdNl(); +} diff --git a/firmware/applications/schneider.c b/firmware/applications/schneider.c index 9e7ec11..ae8d5e5 100644 --- a/firmware/applications/schneider.c +++ b/firmware/applications/schneider.c @@ -6,52 +6,201 @@ #include "basic/basic.h" #include "lcd/render.h" #include "lcd/allfonts.h" +#include "basic/config.h" +#include "basic/byteorder.h" +#include "lcd/lcd.h" +#include "lcd/print.h" +#include "funk/nrf24l01p.h" +#include "usbcdc/usb.h" +#include "usbcdc/usbcore.h" +#include "usbcdc/usbhw.h" +#include "usbcdc/cdcuser.h" +#include "usbcdc/cdc_buf.h" +#include "usbcdc/util.h" +#include "core/ssp/ssp.h" -#include "ecc.c" -void backlightInit(void); +#if CFG_USBMSC +#error "MSC is defined" +#endif +#if !CFG_USBCDC +#error "CDC is not defined" +#endif + +#define CHANNEL 81 +#define MAC "\x1\x2\x3\x2\x1" + +#define SERIAL_NONE 0 +#define SERIAL_ESCAPE '\\' +#define SERIAL_STOP '0' +#define SERIAL_PACKETLEN 128 + +struct NRF_CFG config = { + .channel= CHANNEL, + .txmac= MAC, + .nrmacs=1, + .mac0= MAC, + .maclen ="\x20", +}; + +uint8_t serialmsg_message[SERIAL_PACKETLEN]; +uint8_t serialmsg_len = 0; + +void serialmsg_init(void); +uint8_t serialmsg_put(uint8_t data); +char snd_pkt_no_crc(int size, uint8_t * pkt); +void dump_encoded(int len, uint8_t *data); + +#define INPUTLEN 99 /**************************************************************************/ -void main_schneider(void) { - //int yctr=8; - int dx=0; - char key; - int ctr = 1; - backlightInit(); - font_direction = FONT_DIR_LTR; // LeftToRight is the default - //yctr=18; - bitstr_parse(poly, "800000000000000000000000000000000000000c9"); - bitstr_parse(coeff_b, "20a601907b8c953ca1481eb10512f78744a3205fd"); - bitstr_parse(base_x, "3f0eba16286a2d57ea0991168d4994637e8343e36"); - bitstr_parse(base_y, "0d51fbc6c71a0094fa2cdd545b11c5c0c797324f1"); - bitstr_parse(base_order, "40000000000000000000292fe77e70c12a4234c33"); +void main_schneider(void) +{ + GLOBAL(daytrig)=10; + GLOBAL(lcdbacklight)=10; + char input[64]; - ECIES_generate_key_pair(); // generate a public/private key pair - while (1) { - key= getInput(); - font=&Font_7x8; - - // Easy flashing - if(key==BTN_LEFT){ - DoString(0,8,"Enter ISP!"); - lcdDisplay(); - ISPandReset(); - }; - - // Display nickname - //font = &Font_Ubuntu36pt; - dx=DoString(0,0,"Test"); - dx=DoInt(dx,0,ctr++); - lcdDisplay(); - encryption_decryption_demo("This is encrypted", - "1c56d302cf642a8e1ba4b48cc4fbe2845ee32dce7", - "45f46eb303edf2e62f74bd68368d979e265ee3c03", - "0e10e787036941e6c78daf8a0e8e1dbfac68e26d2"); + usbCDCInit(); + delayms(500); + nrf_init(); + nrf_config_set(&config); + + nrf_rcv_pkt_start(); + while(1){ + int l, i, status; + CDC_OutBufAvailChar (&l); + if(l>0){ + CDC_RdOutBuf (input, &l); + for(i=0; i 0 ){ + puts("\\1"); + dump_encoded(len, buf); + puts("\\0"); + } } - return; +} + +void dump_encoded(int len, uint8_t *data) +{ + int i=0,j=0; + uint8_t buf[SERIAL_PACKETLEN*2]; + for(i=0; i MAX_PKT) + size=MAX_PKT; + + nrf_write_reg(R_CONFIG, + R_CONFIG_PWR_UP| // Power on + R_CONFIG_EN_CRC // CRC on, single byte + ); + + CS_LOW(); + xmit_spi(C_W_TX_PAYLOAD); + sspSend(0,pkt,size); + CS_HIGH(); + + CE_HIGH(); + delayms(1); // Send it. (only needs >10ys, i think) + CE_LOW(); + + return nrf_cmd_status(C_NOP); +}; + +void serialmsg_init(void) +{ + serialmsg_len = 0; +} + +//returns the message type or SERIAL_NONE +uint8_t serialmsg_put(uint8_t data) +{ + static uint8_t escaped = 0; + static uint8_t msgtype = SERIAL_NONE; + + if( data == SERIAL_ESCAPE && escaped == 0 ){ + //a control code will follow + escaped = 1; + return SERIAL_NONE; + }else if( escaped ){ + escaped = 0; + if( data != SERIAL_ESCAPE ){ + if( data == SERIAL_STOP ){ + uint8_t tmp = msgtype; + msgtype = SERIAL_NONE; + return tmp; + } + msgtype = data; + serialmsg_len=0; + return SERIAL_NONE; + } + } + serialmsg_message[serialmsg_len++] = data; + + //prevent a buffer overflow + if( serialmsg_len == SERIAL_PACKETLEN ) + serialmsg_len--; + + return SERIAL_NONE; +} + + diff --git a/firmware/l0dable/r_player.c b/firmware/l0dable/r_player.c new file mode 100644 index 0000000..d05b59f --- /dev/null +++ b/firmware/l0dable/r_player.c @@ -0,0 +1,312 @@ +#include + +#include "basic/basic.h" +#include "basic/byteorder.h" +#include "lcd/lcd.h" +#include "lcd/print.h" +#include "funk/nrf24l01p.h" +#include +#include "basic/random.h" +#include "basic/config.h" +#include "usetable.h" + + +//channel and mac used to transmit game announcements +#define ANNOUNCE_CHANNEL 81 +#define ANNOUNCE_MAC "REM0T" + +struct NRF_CFG config; + +struct packet{ + uint8_t len; + uint8_t protocol; + uint8_t command; + uint32_t id; + uint32_t ctr; + + //union with 19 bytes data + union content{ + struct button{ + uint8_t button; + uint8_t reserved[18]; + }__attribute__((packed)) button; + struct text{ + uint8_t x; + uint8_t y; + uint8_t flags; + uint8_t text[16]; + }__attribute__((packed)) text; + struct nick{ + uint8_t flags; + uint8_t nick[18]; + }__attribute__((packed)) nick; + struct nickrequest{ + uint8_t reserved[19]; + }__attribute__((packed)) nickrequest; + struct ack{ + uint8_t flags; + uint8_t reserved[18]; + }__attribute__((packed)) ack; + struct announce{ + uint8_t gameMac[5]; + uint8_t gameChannel; + //uint8_t playerMac[5]; playerMac = gameMac+1; + uint32_t gameId; + uint8_t gameFlags; + uint8_t gameTitle[8]; + }__attribute__((packed)) announce; + struct join{ + uint32_t gameId; + uint8_t reserved[15]; + }__attribute__((packed)) join; + }c; + uint16_t crc; +}__attribute__((packed)); + +#define FLAGS_MASS_GAME 1 +#define FLAGS_ACK_JOINOK 1 +#define MASS_ID 1 + +/**************************************************************************/ +/* l0dable for playing games which are announced by other r0kets with the l0dabel r_game */ +/* Values of buf[3]: + * B: packet sent by player, contain information which button is pressed + * T: packet sent by game, contain text for display + * N: packet sent by game, requesting nick + * n: packet sent player, containing nick + * A: packet sent by game, announcing game + * J: packet sent by player, requesting to join game + * a: ack, packet with $ctr was received + */ + + +uint32_t ctr; +uint32_t id; +uint32_t gameId; + +void sendButton(uint8_t button); +void sendJoin(uint32_t game); +void processPacket(struct packet *p); +void processAnnounce(struct announce *a); + +uint8_t selectGame(); +void playGame(); + +struct announce games[7]; +uint8_t gamecount; + +void ram(void) +{ + int priv = GLOBAL(privacy); + GLOBAL(privacy) = 3; + config.nrmacs=1; + config.maclen[0] = 32; + config.channel = ANNOUNCE_CHANNEL; + memcpy(config.mac0, ANNOUNCE_MAC, 5); + nrf_config_set(&config); + + id = getRandom(); + ctr = 1; + + while( selectGame() ){ + playGame(); + } + GLOBAL(privacy) = priv; +}; + +void playGame(void) +{ + int len; + struct packet p; + + while(1){ + uint8_t button = getInputRaw(); + sendButton(button); + + while(1){ + len = nrf_rcv_pkt_time(32,sizeof(p),(uint8_t*)&p); + if(len==sizeof(p)){ + processPacket(&p); + }else{ + break; + } + } + delayms(20); + }; +} + +void showGames(uint8_t selected) +{ + int i; + lcdClear(); + lcdPrintln("Games:"); + if( gamecount ){ + for(i=0;i 0 ){ + selected--; + } + break; + case BTN_LEFT: + return 0; + case BTN_ENTER: + case BTN_RIGHT: + if( gamecount == 0 ) + return 0; + gameId = games[selected].gameId; + memcpy(config.txmac, games[selected].gameMac, 5); + memcpy(config.mac0, games[selected].gameMac, 5); + config.mac0[4]++; + config.channel = games[selected].gameChannel; + nrf_config_set(&config); + if( games[selected].gameFlags & FLAGS_MASS_GAME ) + return 1; + else + return joinGame(); + } + } +} + +void processNickRequest( struct nickrequest *nq) +{ + struct packet p; + p.len=sizeof(p); + p.protocol='G'; // Proto + p.command='n'; + p.id= id; + p.ctr= ++ctr; + p.c.nick.flags = 0; + uint8_t *nick = GLOBAL(nickname); + strcpy(p.c.nick.nick, nick); + nrf_snd_pkt_crc(sizeof(p),(uint8_t*)&p); +} + +void processPacket(struct packet *p) +{ + if ((p->len==32) && (p->protocol=='G') && (p->id == id || p->id == 0) ){ //check sanity, protocol, id + if (p->command=='T'){ + //processText(&(p->c.text)); + } + else if (p->command=='N'){ + processNickRequest(&(p->c.nickrequest)); + } + else if (p->command=='A'){ + processAnnounce(&(p->c.announce)); + } + } +} + +void processAnnounce(struct announce *a) +{ + if( gamecount < sizeof(games)/sizeof(games[0]) ){ + games[gamecount] = *a; + gamecount++; + } +} + +//increment ctr and send button state, id and ctr +void sendButton(uint8_t button) +{ + struct packet p; + p.len=sizeof(p); + p.protocol='G'; // Proto + p.command='B'; + p.id= id; + p.ctr= ++ctr; + p.c.button.button=button; + + //lcdClear(); + //lcdPrint("Key:"); lcdPrintInt(buf[2]); lcdNl(); + + nrf_snd_pkt_crc(sizeof(p),(uint8_t*)&p); +} + diff --git a/firmware/loadable/.gitignore b/firmware/loadable/.gitignore deleted file mode 100644 index 7652361..0000000 --- a/firmware/loadable/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.elf -*.bin -*.h -loadable.ld diff --git a/firmware/loadable/Makefile b/firmware/loadable/Makefile deleted file mode 100644 index fa86f1e..0000000 --- a/firmware/loadable/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Make doesn't allow dependencies on parent directory, so we need to -# run make from one level up: - -MAKEFILE=loadable/Makefile.sub -MAKE+=--no-print-directory - -all: - @cd .. && $(MAKE) -f $(MAKEFILE) - -clean: - @cd .. && $(MAKE) -f $(MAKEFILE) clean - diff --git a/firmware/loadable/Makefile.sub b/firmware/loadable/Makefile.sub deleted file mode 100644 index aa2f3ee..0000000 --- a/firmware/loadable/Makefile.sub +++ /dev/null @@ -1,57 +0,0 @@ -DIR?= loadable - -########################################################################## -# User configuration and firmware specific object files -########################################################################## -SRCS = $(wildcard $(DIR)/*.c) -OBJS = $(foreach mod,$(SRCS),$(subst .c,.o,$(mod))) -ELFS = $(foreach mod,$(SRCS),$(subst .c,.elf,$(mod))) -BINS = $(foreach mod,$(SRCS),$(subst .c,.bin,$(mod))) -HDRS = $(foreach mod,$(SRCS),$(subst .c,.h,$(mod))) - -########################################################################## -# GNU GCC compiler flags -########################################################################## -ROOT_PATH?= . - -INCLUDE_PATHS = -I$(ROOT_PATH) -I$(ROOT_PATH)/core - -include $(ROOT_PATH)/Makefile.inc - -########################################################################## -# Compiler settings, parameters and flags -########################################################################## -FIRMWARE=$(ROOT_PATH)/$(OUTFILE).elf -LDSRCFILE=$(DIR)/ram.ld -LDFILE=$(DIR)/loadable.ld -CFLAGS+=-mlong-calls -fno-toplevel-reorder -LDFLAGS+= -R $(FIRMWARE) - -all: $(OBJS) $(ELFS) $(BINS) $(HDRS) - -$(LDFILE): - -@echo "MEMORY" > $(LDFILE) - -@echo "{" >> $(LDFILE) - -@echo " sram(rwx): ORIGIN = 0x10002000 - $(RAMCODE), LENGTH = $(RAMCODE)" >> $(LDFILE) - -@echo "}" >> $(LDFILE) - -@echo "INCLUDE $(LDSRCFILE)" >> $(LDFILE) - -%.o : %.c - $(CC) $(CFLAGS) -o $@ $< - -%.elf: %.o $(FIRMWARE) $(LDFILE) - $(LD) $(LDFLAGS) -T $(LDFILE) -o $@ $< - $(SIZE) $@ - -%.bin: %.elf - $(OBJCOPY) $(OCFLAGS) -O binary $< $@ - -%.h: %.bin $(DIR)/bin2h.pl - $(DIR)/bin2h.pl $< - -clean: - cd $(DIR) && rm -f *.o *.elf *.bin - -.SUFFIXES: - -.PHONY: $(LDFILE) diff --git a/firmware/loadable/bin2h.pl b/firmware/loadable/bin2h.pl deleted file mode 100755 index 185bc54..0000000 --- a/firmware/loadable/bin2h.pl +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/perl -# -# vim:set ts=4 sw=4: - -use strict; - -sub dwim{ - local $/=undef; - my $file=shift; - - open(IN,"<:bytes",$file) || die "Can't open $file: $!"; - my @bytes=unpack("C*",); - close(IN); - - $file=~s/\.[^.]+$//; - - open(OUT,">","${file}.h") || die "Can't write ${file}.h: $!"; - - $file=~s!.*/!!; - - print OUT "const uint16_t loadable_${file}_size = ", scalar @bytes, ";\n"; - print OUT "const uint8_t loadable_${file}[] = {\n"; - - my $ctr=0; - for(@bytes){ - print OUT "\t" if($ctr==0); - printf OUT "0x%02x, ",$_; - if(++$ctr==8){ - print OUT "\n"; - $ctr=0; - }; - }; - print OUT "\n" if($ctr!=0); - - print OUT "};\n"; - close(OUT); -}; - -for(@ARGV){ - dwim($_); -}; diff --git a/firmware/loadable/blinktest.c b/firmware/loadable/blinktest.c deleted file mode 100644 index 7530f14..0000000 --- a/firmware/loadable/blinktest.c +++ /dev/null @@ -1,10 +0,0 @@ -#include - -#include "basic/basic.h" - -void ram(void){ - for (int x=0;x<20;x++){ - gpioSetValue (RB_LED1, x%2); - delayms(50); - }; -}; diff --git a/firmware/loadable/mandelbrot.c b/firmware/loadable/mandelbrot.c deleted file mode 100644 index f66b691..0000000 --- a/firmware/loadable/mandelbrot.c +++ /dev/null @@ -1,190 +0,0 @@ -#include - -#include "basic/basic.h" - -#include "lcd/render.h" -#include "lcd/display.h" -#include "lcd/allfonts.h" - -#define FIXSIZE 25 -#define mul(a,b) ((((long long)a)*(b))>>FIXSIZE) -#define fixpt(a) ((long)(((a)*(1<>FIXSIZE) - -#define ZOOM_RATIO 0.90 -#define ITERATION_MAX 150 - -void mandelInit(); -void mandelMove(); -void mandelUpdate(); - -void ram(void) { - int key; - mandelInit(); - while (1) { - lcdDisplay(); - mandelMove(); - mandelUpdate(); - - // Exit on enter+direction - key=getInputRaw(); - if(key&BTN_ENTER && key>BTN_ENTER) - return; - } - return; -} - -struct mb { - long rmin, rmax, imin, imax; - bool dirty, dup, ddown, dleft, dright, clickmark; - int count, limitZIn, limitZOut; -} mandel; - -void mandelInit() { - //mandel.rmin = -2.2*0.9; - //mandel.rmax = 1.0*0.9; - //mandel.imin = -2.0*0.9; - //mandel.imax = 2.0*0.9; - mandel.rmin = fixpt(-2); - mandel.rmax = fixpt(1); - mandel.imin = fixpt(-2); - mandel.imax = fixpt(2); - mandel.count = 0; - mandel.limitZIn = 40; - mandel.limitZOut = 30; - - mandel.dirty = true; - mandel.dup = false; - mandel.ddown = false; - mandel.dleft = false; - mandel.dright = false; - mandel.clickmark = false; -} - -void mandelMove() { - //long delta_r = (mandel.rmax - mandel.rmin)/10; - //long delta_i = (mandel.imax - mandel.imin)/10; - - long rs =(mandel.rmax-mandel.rmin)/RESY; - long is =(mandel.imax-mandel.imin)/RESX; - - char key = getInputRaw(); - - if (key == BTN_LEFT) { - mandel.imax -=is; - mandel.imin -=is; - mandel.dleft = true; - } else if (key == BTN_RIGHT) { - mandel.imax += is; - mandel.imin += is; - mandel.dright = true; - } else if (key == BTN_DOWN) { - mandel.rmax += rs; - mandel.rmin += rs; - mandel.ddown = true; - } else if (key == BTN_UP) { - mandel.rmax -= rs; - mandel.rmin -= rs; - mandel.dup = true; - } else if (key == BTN_ENTER) { - if (mandel.count < mandel.limitZIn) { - mandel.count = mandel.count + 1; - } - } else if (key == BTN_NONE) { - if(mandel.count > 0 ) { - mandel.count = mandel.count - 1; - mandel.clickmark = true; - } - if (mandel.count == 0 ) { - mandel.clickmark = false; - } - } - if (mandel.count > mandel.limitZOut && mandel.clickmark && key == BTN_ENTER) { - mandel.imin = mandel.imin - (mandel.imax-mandel.imin)/10; - mandel.imax = mandel.imax + (mandel.imax-mandel.imin)/10; - mandel.rmin = mandel.rmin -(mandel.rmax-mandel.rmin)/10; - mandel.rmax = mandel.rmax +(mandel.rmax-mandel.rmin)/10; - mandel.dirty = true; - } - if (mandel.count == mandel.limitZIn && key == BTN_ENTER) { - mandel.imin = mandel.imin + (mandel.imax-mandel.imin)/10; - mandel.imax = mandel.imax - (mandel.imax-mandel.imin)/10; - mandel.rmin = mandel.rmin +(mandel.rmax-mandel.rmin)/10; - mandel.rmax = mandel.rmax -(mandel.rmax-mandel.rmin)/10; - mandel.dirty = true; - } -} - -void mandelPixel(int x, int y) { - long r0,i0,rn, p,q; - long rs,is; - int iteration; - - rs=(mandel.rmax-mandel.rmin)/RESY; - is=(mandel.imax-mandel.imin)/RESX; - //p=fixpt(mandel.rmin+y*rs); - //q=fixpt(mandel.imin+x*is); - p=mandel.rmin+y*rs; - q=mandel.imin+x*is; - - rn=0; - r0=0; - i0=0; - iteration=0; - while ((mul(rn,rn)+mul(i0,i0))1); - lcdSetPixel(x, y, pixel); -} - -void mandelUpdate() { - int xmin,xmax,ymin,ymax; - if (mandel.dirty) { - xmin = 0; - xmax = RESX; - ymin = 0; - ymax = RESY; - mandel.dirty = false; - } else if (mandel.dleft) { - lcdShift(1,0,false); - xmin = 0; - xmax = 1; - ymin = 0; - ymax = RESY; - mandel.dleft = false; - } else if (mandel.dright) { - lcdShift(-1,0,false); - xmin = RESX-1; - xmax = RESX; - ymin = 0; - ymax = RESY; - mandel.dright = false; - } else if (mandel.dup) { - lcdShift(0,-1,true); - xmin=0; - xmax=RESX; - ymin=0; - ymax=1; - mandel.dup = false; - } else if (mandel.ddown) { - lcdShift(0,1,true); - xmin=0; - xmax=RESX; - ymin=RESY-1; - ymax=RESY; - mandel.ddown = false; - } else { - return; - } - - for (int x = xmin; x sram - - /* - * More information about Special Section Indexes is available in the - * free "ELF for the ARM Architecture" document from ARM Limited - * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044d/IHI0044D_aaelf.pdf - * - */ - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > sram - __exidx_start = .; - .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > sram - __exidx_end = .; - - _etext = .; - - .data : AT (__exidx_end) - { - _data = .; - *(vtable) - *(.data*) - _edata = .; - } > sram - - /* zero initialized data */ - .bss : - { - _bss = .; - *(.bss*) - *(COMMON) - _ebss = .; - } > sram - - end = .; - - /* For GDB compatibility we decrease the top with 16 bytes */ - stack_entry = sram_top - 16; -} diff --git a/firmware/loadable/recvcard.c b/firmware/loadable/recvcard.c deleted file mode 100644 index 8571f7c..0000000 --- a/firmware/loadable/recvcard.c +++ /dev/null @@ -1,338 +0,0 @@ -#include -#include -#include -#include -#include -#include "basic/basic.h" -#include "lcd/render.h" -#include "lcd/allfonts.h" -#include "basic/ecc.h" -#include "funk/nrf24l01p.h" -#include "filesystem/ff.h" -#include "filesystem/diskio.h" -#include "funk/filetransfer.h" -#include "lcd/print.h" - -uint8_t mac[5] = {1,2,3,2,1}; - -void ram(void) -{ - if( sendKeys() ) - return; - - char priv[42]; - UINT readbytes; - FIL file; - - if( f_open(&file, "priv.key", FA_OPEN_EXISTING|FA_READ) ){ - return; - } - if( f_read(&file, priv, 41, &readbytes) || readbytes != 41 ){ - return; - } - f_close(&file); - priv[41] = 0; - - uint8_t done = 0; - uint8_t key; - uint8_t k1[16], k2[16], rx[4*NUMWORDS], ry[4*NUMWORDS]; - - while( !done ){ - lcdClear(); - lcdPrintln("Receiving file"); - lcdPrintln("Down=Abort"); - lcdRefresh(); - key = getInput(); - delayms(20); - if( key == BTN_DOWN ){ - return -1; - } - if( receiveR(rx,ry) ) - continue; - lcdPrintln("Creating key"); - lcdRefresh(); - ECIES_decryptkeygen(rx, ry, k1, k2, priv); - if( filetransfer_receive(mac,(uint32_t*)k1) < 0 ) - continue; - lcdPrintln("Right=OK"); - lcdPrintln("Left=Retry"); - lcdPrintln("Down=Abort"); - lcdRefresh(); - - while(1){ - key = getInput(); - delayms(20); - if( key == BTN_LEFT ){ - break; - }else if( key == BTN_RIGHT ){ - done = 1; - break; - }else if( key == BTN_DOWN ){ - return -1; - } - } - } -} - -void sendPublicKey(void) -{ - uint8_t exp[2 + 4*NUMWORDS + 2]; - char buf[42]; - UINT readbytes; - FIL file; - - if( f_open(&file, "pubx.key", FA_OPEN_EXISTING|FA_READ) ){ - return; - } - if( f_read(&file, buf, 41, &readbytes) || readbytes != 41 ){ - return; - } - f_close(&file); - buf[41] = 0; - - exp[0] = 'P'; - bitstr_parse_export((char*)exp+2, buf); - exp[1] = 'X'; - nrf_snd_pkt_crc(32, exp); - delayms(10); - - if( f_open(&file, "puby.key", FA_OPEN_EXISTING|FA_READ) ){ - return; - } - if( f_read(&file, buf, 41, &readbytes) || readbytes != 41 ){ - return; - } - f_close(&file); - buf[41] = 0; - - exp[1] = 'Y'; - bitstr_parse_export((char*)exp+2, buf); - nrf_snd_pkt_crc(32, exp); - delayms(10); -} - - -int receiveKey(uint8_t type, uint8_t *x, uint8_t *y) -{ - uint8_t buf[32]; - uint8_t n; - - n = nrf_rcv_pkt_time(1000, 32, buf); - if( n == 32 && buf[0] == type && buf[1] == 'X' ){ - for(int i=0; i -#include "funk/nrf24l01p.h" -#include "funk/filetransfer.h" -#include "funk/rftransfer.h" -#include "basic/basic.h" -#include "basic/xxtea.h" -#include "filesystem/ff.h" -#include "lcd/print.h" - - -int filetransfer_receive(uint8_t *mac, uint32_t const k[4]) -{ - uint8_t buf[MAXSIZE+1]; - uint16_t size; - uint8_t n; - - UINT written = 0; - FIL file; - FRESULT res; - //uint8_t macbuf[5]; - //nrf_get_rx_max(0,5,macbuf); - - uint8_t metadata[32]; - - //nrf_set_rx_mac(0, 32, 5, mac); - n = nrf_rcv_pkt_time_encr(3000, 32, metadata, k); - if( n != 32 ) - return 1; //timeout - //nrf_set_rx_mac(0, 32, 5, macbuf); - //lcdPrintln("got meta"); lcdRefresh(); - metadata[19] = 0; //enforce termination - size = (metadata[20] << 8) | metadata[21]; - - if( size > MAXSIZE ) {lcdPrintln("too big"); lcdRefresh(); while(1);} - if( size > MAXSIZE ) return 1; //file to big - //if(fileexists(metadata)) return 1; //file already exists - - //lcdPrint("open"); lcdPrintln((const char*)metadata); lcdRefresh(); - res = f_open(&file, (const char*)metadata, FA_OPEN_ALWAYS|FA_WRITE); - - //lcdPrintln("file opened"); lcdRefresh(); - if( res ) {lcdPrintln("res"); lcdPrint(f_get_rc_string(res)); lcdRefresh(); while(1);} - if( res ) - return res; - - uint16_t wordcount = (size+3)/4; - - //nrf_set_rx_mac(0, 32, 5, mac); - //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 1; - //nrf_set_rx_mac(0, 32, 5, macbuf); - - xxtea_decode_words((uint32_t *)buf, wordcount, k); - - res = f_write(&file, buf, size, &written); - f_close(&file); - if( res ) - return res; - if( written != size ) - return 1; //error while writing - lcdClear(); - lcdPrintln("Received"); lcdPrintln((const char*)metadata); lcdRefresh(); - - return 0; -} - -#define MAXPACKET 32 -int16_t rftransfer_receive(uint8_t *buffer, uint16_t maxlen, uint16_t timeout) -{ - uint8_t buf[MAXPACKET]; - uint8_t state = 0; - uint16_t pos = 0, seq = 0, size = 0, rand = 0, crc = 0; - int n,i; - unsigned int currentTick = systickGetTicks(); - unsigned int startTick = currentTick; - - while(systickGetTicks() < (startTick+timeout) ){//this fails if either overflows - n = nrf_rcv_pkt_time(1000, MAXPACKET, buf); - switch(state){ - case 0: - if( n == 32 && buf[0] == 'L' ){ - size = (buf[1] << 8) | buf[2]; - rand = (buf[3] << 8) | buf[4]; - seq = 0; - pos = 0; - if( size <= maxlen ){ - //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(); - if( seq == ((buf[1]<<8)|buf[2]) ){ - //lcdPrintln(" in seq"); lcdRefresh(); - for(i=5; i -#include -#include -#include -#include -#include "basic/basic.h" -#include "lcd/render.h" -#include "lcd/allfonts.h" -#include "basic/ecc.h" -#include "funk/nrf24l01p.h" -#include "filesystem/ff.h" -#include "filesystem/diskio.h" -#include "funk/filetransfer.h" -#include "lcd/print.h" - - - -uint8_t mac[5] = {1,2,3,2,1}; - -void ram(void) -{ - char file[13]; - selectFile(file,"TXT"); - sendFile(file); -} - -void sendR(uint8_t *rx, uint8_t *ry) -{ - uint8_t exp[2 + 4*NUMWORDS + 2]; - exp[0] = 'R'; - for(int i=0; i<4*NUMWORDS; i++) - exp[2+i] = rx[i]; - exp[1] = 'X'; - nrf_snd_pkt_crc(32, exp); - delayms(10); - exp[1] = 'Y'; - for(int i=0; i<4*NUMWORDS; i++) - exp[2+i] = ry[i]; - nrf_snd_pkt_crc(32, exp); - delayms(10); -} - -int receiveKey(uint8_t type, uint8_t *x, uint8_t *y) -{ - uint8_t buf[32]; - uint8_t n; - - n = nrf_rcv_pkt_time(1000, 32, buf); - if( n == 32 && buf[0] == type && buf[1] == 'X' ){ - for(int i=0; i -#include "funk/nrf24l01p.h" -#include "funk/filetransfer.h" -#include "funk/rftransfer.h" -#include "basic/basic.h" -#include "basic/xxtea.h" -#include "filesystem/ff.h" -#include "lcd/print.h" - - -//TODO: use a proper MAC to sign the message -int filetransfer_send(uint8_t *filename, uint16_t size, - uint8_t *mac, uint32_t const k[4]) -{ - uint8_t buf[MAXSIZE]; - FIL file; - FRESULT res; - UINT readbytes; - - - if( size > MAXSIZE ) - return 1; //File to big - - res=f_open(&file, (const char*)filename, FA_OPEN_EXISTING|FA_READ); - if( res ) - return res; - - //res = f_read(&file, (char *)buf, size, &readbytes); - for(uint16_t i=0; i> 8; - metadata[21] = size & 0xFF; - - //nrf_get_tx_max(5,macbuf); - - //nrf_set_tx_mac(5, mac); - nrf_snd_pkt_crc_encr(32, metadata, k); - delayms(20); - xxtea_encode_words((uint32_t *)buf, wordcount, k); - rftransfer_send(wordcount*4, buf); - //nrf_set_tx_mac(5, macbuf); - return 0; -} - -#include "funk/rftransfer.h" -#include "funk/nrf24l01p.h" -#include -#include -#include -#include - -#define MAXPACKET 32 -void rftransfer_send(uint16_t size, uint8_t *data) -{ - uint8_t buf[MAXPACKET]; - buf[0] = 'L'; - buf[1] = size >> 8; - buf[2] = size & 0xFF; - - uint16_t rand = getRandom() & 0xFFFF; - buf[3] = rand >> 8; - buf[4] = rand & 0xFF; - - nrf_snd_pkt_crc(32,buf); //setup packet - delayms(20); - uint16_t index = 0; - uint8_t i; - uint16_t crc = crc16(data,size); - - while(size){ - buf[0] = 'D'; - buf[1] = index >> 8; - buf[2] = index & 0xFF; - buf[3] = rand >> 8; - buf[4] = rand & 0xFF; - for(i=5; i0; i++,size--){ - buf[i] = *data++; - } - index++; - nrf_snd_pkt_crc(32,buf); //data packet - delayms(20); - } - - buf[0] = 'C'; - buf[1] = crc >> 8; - buf[2] = crc & 0xFF; - buf[3] = rand >> 8; - buf[4] = rand & 0xFF; - nrf_snd_pkt_crc(32,buf); //setup packet - delayms(20); -} - diff --git a/firmware/loadable/spaceinvaders.c b/firmware/loadable/spaceinvaders.c deleted file mode 100644 index fbcf38a..0000000 --- a/firmware/loadable/spaceinvaders.c +++ /dev/null @@ -1,462 +0,0 @@ -#include -#include - -#include "basic/basic.h" -#include "basic/random.h" - -#include "lcd/render.h" -#include "lcd/display.h" -#include "lcd/allfonts.h" - -/**************************************************************************/ -#define POS_PLAYER_Y 60 -#define POS_PLAYER_X RESX/2-3 -#define POS_UFO_Y 0 -#define ENEMY_ROWS 3 -#define ENEMY_COLUMNS 6 -#define DISABLED 255 - -#define UFO_PROB 1024 - -#define TYPE_PLAYER 1 -#define TYPE_ENEMY_A 3 -#define TYPE_ENEMY_B 2 -#define TYPE_ENEMY_C 4 -#define TYPE_UFO 5 - -#define BUNKERS 3 -#define BUNKER_WIDTH 10 -static const uint8_t BUNKER_X[] = {15, RESX/2-BUNKER_WIDTH/2,RESX-BUNKER_WIDTH-15}; -static const uint8_t ENEMY_WIDTHS[] = {8,10,12}; - -struct gamestate { - char player; - char ufo; - char shot_x, shot_y; - char shots_x[ENEMY_COLUMNS]; - char shots_y[ENEMY_COLUMNS]; - char alive; - int16_t move; - char direction, lastcol; - bool killed; - bool step; - uint32_t score; - uint16_t level; - int8_t rokets; - char enemy_x[ENEMY_ROWS][ENEMY_COLUMNS]; - char enemy_row_y[ENEMY_ROWS]; - uint8_t bunker[BUNKERS][BUNKER_WIDTH]; -} game; -char key; - -void init_game(); -void init_enemy(); -void check_end(); -void move_ufo(); -void move_shot(); -void move_shots(); -void move_player(); -void move_enemy(); -void draw_score(); -void draw_bunker(); -void draw_player(); -void draw_enemy(); -void draw_shots(); -void draw_sprite(char type, char x, char y); -void draw_ufo(); -void screen_intro(); -void screen_gameover(); -void screen_level(); -bool check_bunker(char xpos, char ypos, int8_t shift); - -void ram(void) { - //gpioSetValue (RB_LED1, CFG_LED_OFF); - //backlightInit(); - while(1) { - screen_intro(); - game.rokets = 3; - game.level = 1; - init_game(); - screen_level(); - while (game.rokets>=0) { - ////checkISP(); - lcdFill(0); - check_end(); - move_ufo(); - move_shot(); - move_shots(); - move_player(); - move_enemy(); - draw_score(); - draw_ufo(); - draw_bunker(); - draw_player(); - draw_enemy(); - draw_shots(); - // draw_status(); - lcdDisplay(); - delayms(12); - } - screen_gameover(); - } - return; -} - -void screen_intro() { - char key=0; - while(key==0) { - lcdFill(0); - font = &Font_Invaders; - DoString(28,25,"ABC"); - font = &Font_7x8; - DoString (28,40,"SPACE"); - DoString (18,50,"INVADERS"); - //DoString (20,RESY-24, "Highscore"); - DoString (0, 0, "12345"); - DoString (0, 9, "iggy"); - lcdDisplay(); - - delayms_queue(50); - key=getInput(); - } -} - -void screen_gameover() { - char key =0; - while(key==0) { - lcdFill(0); - font = &Font_7x8; - DoString (12,32, "GAME OVER"); - DoInt (0,0, game.score); - DoString (0,9,"HIGHSCORE!"); - lcdDisplay(); - delayms_queue(50); - key=getInput(); - } -} - -void screen_level() { - lcdFill(0); - draw_score(); - font = &Font_7x8; - int dx = DoString(20,32, "Level "); - DoInt(dx,32,game.level); - lcdDisplay(); - delayms(500); -} - -void init_game(void) { - game.player = POS_PLAYER_X; - game.shot_x = DISABLED; - game.shot_y = 0; - game.alive = ENEMY_ROWS*ENEMY_COLUMNS; - game.move = 0; - if (getRandom()%2 == 0) { - game.direction = -1; - game.lastcol = ENEMY_COLUMNS-1; - } else { - game.direction = 1; - game.lastcol = 0; - } - game.killed = 0; - game.step = false; - game.ufo = DISABLED; - game.score = 0; - init_enemy(); - - for (int col=0; colBUNKER_X[BUNKERS-1-b] && - xposRESY-16) { - int offset = BUNKER_WIDTH - (xpos-BUNKER_X[BUNKERS-1-b]); - if (game.bunker[b][offset]!=0) { - if (shift>0) - game.bunker[b][offset]&=game.bunker[b][offset]<>-shift; - return true; - } - } - } - return false; -} - -void move_shot() { - //No shot, do nothing - if(game.shot_x == DISABLED) { - return; - } - - //moving out of top, end shot - if (game.shot_y <= 0) { - game.shot_x = DISABLED; - return; - } - - if (check_bunker(game.shot_x,game.shot_y-5,1 )) - game.shot_x=DISABLED; - - //check for collision with enemy, kill enemy if - for (int row=0; row= game.shot_y && game.enemy_row_y[row]+6 < game.shot_y+7) { - for(int col = 0; col= game.enemy_x[row][col] && game.shot_x < game.enemy_x[row][col]+ENEMY_WIDTHS[row]) { - game.enemy_x[row][col]=DISABLED; - game.shot_x = DISABLED; - game.alive--; - game.score+=(3-row)*10; - return; - } - } - } - } - - //check for collision with ufo - if (game.ufo != DISABLED && - game.shot_x>game.ufo && - game.shot_x= RESY) { - game.shots_x[col] = DISABLED; - return; - } - //check for collision with bunker - if (check_bunker(game.shots_x[col],game.shots_y[col],-1)) - game.shots_x[col]=DISABLED; - - //check for collision with player - if (game.shots_y[col] >= RESY-13 && - game.shots_x[col] > game.player+1 && - game.shots_x[col] < game.player+6) { - - game.killed = true; - } - - //move shots down - game.shots_y[col] += 1; - } -} - -void move_ufo() { - if (game.ufo == DISABLED) { - if ((getRandom()%UFO_PROB)==0) { - game.ufo = 0; - } - return; - } - if (game.ufo >= RESX){ - game.ufo = DISABLED; - return; - } - game.ufo++; -} - -void move_player() { - if(gpioGetValue(RB_BTN0)==0 && game.player > 0 ){ - game.player-=1; - } - - if(gpioGetValue(RB_BTN1)==0 && game.player < RESX-8){ - game.player+=1; - } - - if(gpioGetValue(RB_BTN4)==0 && game.shot_x == 255){ - game.shot_x = game.player+4; - game.shot_y = POS_PLAYER_Y; - } -} - -void move_enemy() { - if(game.move > 0){ - game.move-=game.level/5+1; - return; - } - - game.step = !game.step; - for (int col = 0; col < ENEMY_COLUMNS; col++) { - for (int row = 0; row < ENEMY_ROWS; row++) { - char pos = game.enemy_x[row][(game.direction==1)?(ENEMY_COLUMNS-(col+1)):col]; - if (pos != DISABLED) { - //Check collision with player - if((game.enemy_row_y[row]+8 >= POS_PLAYER_Y && pos+8 >= game.player && pos < game.player+8) || - game.enemy_row_y[row]+8 >= POS_PLAYER_Y+8) { - for(int row=0; row=RESX-10 && game.direction == 1)){ - game.direction = (game.direction==1)?-1:1; - for (int r = 0; r=23?4:2; - } - return; - } - game.enemy_x[row][(game.direction==1)?(ENEMY_COLUMNS-(col+1)):col] += game.direction; - } - } - } - - game.move = game.alive*2-1; -} - -void draw_player() { - draw_sprite(TYPE_PLAYER, game.player, POS_PLAYER_Y); -} - -void draw_ufo() { - if (game.ufo!=DISABLED) - draw_sprite(TYPE_UFO, game.ufo, POS_UFO_Y); -} - -void draw_enemy() { - for (int row = 0; row flash diff --git a/firmware/main.c b/firmware/main.c index 9b02c7c..4dd682b 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -28,7 +28,7 @@ #define CRP_VALUE 0x0 // ANY non-magic value disables CRP #endif -__attribute__ ((used, section("crp"))) const uint32_t the_crp=CRP_VALUE; +//__attribute__ ((used, section("crp"))) const uint32_t the_crp=CRP_VALUE; /**************************************************************************/ diff --git a/firmware/usbcdc/Makefile b/firmware/usbcdc/Makefile index 3a9ea98..3019ad4 100644 --- a/firmware/usbcdc/Makefile +++ b/firmware/usbcdc/Makefile @@ -4,7 +4,6 @@ OBJS = OBJS += cdcuser.o -OBJS += cdc_buf.o OBJS += usbcore.o OBJS += usbdesc.o OBJS += usbhw.o diff --git a/firmware/usbcdc/cdc_buf.c b/firmware/usbcdc/cdc_buf.c deleted file mode 100644 index 2a7c1d5..0000000 --- a/firmware/usbcdc/cdc_buf.c +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************* - Copyright (C) 2009 FreakLabs - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the the copyright holder nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Originally written by Christopher Wang aka Akiba. - Please post support questions to the FreakLabs forum. -*******************************************************************/ - -/**************************************************************************/ -/*! - @file cdc_buf.c - @author Christopher Wang (Freaklabs) - Modified by: K. Townsend (microBuilder.eu) - @date 19 May 2010 - - Original code taken from the FreakUSB Open Source USB Device Stack - http://freaklabs.org/index.php/FreakUSB-Open-Source-USB-Device-Stack.html - - If it works well, you can thank Akiba at Freaklabs. If it fails - miserably, you can blame me (since parts of it it were rather - ungraciously modified). :-) - -*/ -/**************************************************************************/ - -#include "cdc_buf.h" - -static cdc_buffer_t cdcfifo; - -/**************************************************************************/ -/*! - Gets a pointer to the fifo buffer -*/ -/**************************************************************************/ -cdc_buffer_t *cdcGetBuffer() -{ - return &cdcfifo; -} - -/**************************************************************************/ -/*! - Initialises the RX FIFO buffer -*/ -/**************************************************************************/ -void cdcBufferInit() -{ - cdcfifo.len = 0; -} - -/**************************************************************************/ -/*! - Read one byte out of the RX buffer. This function will return the byte - located at the array index of the read pointer, and then increment the - read pointer index. If the read pointer exceeds the maximum buffer - size, it will roll over to zero. -*/ -/**************************************************************************/ -uint8_t cdcBufferRead() -{ - uint8_t data; - - data = cdcfifo.buf[cdcfifo.rd_ptr]; - cdcfifo.rd_ptr = (cdcfifo.rd_ptr + 1) % CFG_USBCDC_BUFFERSIZE; - cdcfifo.len--; - return data; -} - -/**************************************************************************/ -/*! - Reads x bytes from cdc buffer - */ -/**************************************************************************/ -uint32_t cdcBufferReadLen(uint8_t* buf, uint32_t len) -{ - uint32_t counter, actual; - counter = actual = 0; - - while(counter != len) - { - // Make sure we don't exceed buffer limits - if (cdcfifo.len > 0) - { - buf[counter] = cdcBufferRead(); - actual++; - counter++; - } - else - { - return actual; - } - } - - return actual; -} - -/**************************************************************************/ -/*! - Write one byte into the RX buffer. This function will write one - byte into the array index specified by the write pointer and increment - the write index. If the write index exceeds the max buffer size, then it - will roll over to zero. -*/ -/**************************************************************************/ -void cdcBufferWrite(uint8_t data) -{ - cdcfifo.buf[cdcfifo.wr_ptr] = data; - cdcfifo.wr_ptr = (cdcfifo.wr_ptr + 1) % CFG_USBCDC_BUFFERSIZE; - cdcfifo.len++; -} - -/**************************************************************************/ -/*! - Clear the fifo read and write pointers and set the length to zero. -*/ -/**************************************************************************/ -void cdcBufferClearFIFO() -{ - cdcfifo.rd_ptr = 0; - cdcfifo.wr_ptr = 0; - cdcfifo.len = 0; -} - -/**************************************************************************/ -/*! - Check whether there is any data pending on the RX buffer. -*/ -/**************************************************************************/ -uint8_t cdcBufferDataPending() -{ - if (cdcfifo.len != 0) - { - return 1; - } - - return 0; -} diff --git a/firmware/usbcdc/cdc_buf.h b/firmware/usbcdc/cdc_buf.h deleted file mode 100644 index c5cdfad..0000000 --- a/firmware/usbcdc/cdc_buf.h +++ /dev/null @@ -1,29 +0,0 @@ -/*---------------------------------------------------------------------------- - * Name: cdc_buf.h - * Purpose: usb cdc buffer handling - * Version: V1.00 - *---------------------------------------------------------------------------*/ - -#ifndef __CDC_BUF_H__ -#define __CDC_BUF_H__ - -#include "projectconfig.h" - -// Buffer used for circular fifo -typedef struct _cdc_buffer_t -{ - volatile uint8_t len; - volatile uint8_t wr_ptr; - volatile uint8_t rd_ptr; - uint8_t buf[CFG_USBCDC_BUFFERSIZE]; -} cdc_buffer_t; - -cdc_buffer_t * cdcGetBuffer(); -void cdcBufferInit(); -uint8_t cdcBufferRead(); -uint32_t cdcBufferReadLen(uint8_t* buf, uint32_t len); -void cdcBufferWrite(uint8_t data); -void cdcBufferClearFIFO(); -uint8_t cdcBufferDataPending(); - -#endif diff --git a/firmware/usbcdc/cdcuser.c b/firmware/usbcdc/cdcuser.c index d553f47..85fd77d 100644 --- a/firmware/usbcdc/cdcuser.c +++ b/firmware/usbcdc/cdcuser.c @@ -1,4 +1,4 @@ -/*---------------------------------------------------------------------------- +/*----------/BulkBufOut------------------------------------------------------------------ * U S B - K e r n e l *---------------------------------------------------------------------------- * Name: cdcuser.c @@ -17,6 +17,7 @@ *---------------------------------------------------------------------------*/ #include "projectconfig.h" +#include "basic/basic.h" #include "usb.h" #include "usbhw.h" @@ -24,15 +25,16 @@ #include "usbcore.h" #include "cdc.h" #include "cdcuser.h" -#include "cdc_buf.h" +#include "usbreg.h" -// unsigned char BulkBufIn [64]; // Buffer to store USB IN packet + +unsigned char BulkBufIn [64]; // Buffer to store USB IN packet unsigned char BulkBufOut [64]; // Buffer to store USB OUT packet unsigned char NotificationBuf [10]; CDC_LINE_CODING CDC_LineCoding = {CFG_USBCDC_BAUDRATE, 0, 0, 8}; unsigned short CDC_SerialState = 0x0000; -unsigned short CDC_DepInEmpty = 1; // Data IN EP is empty +volatile unsigned char CDC_DepInEmpty = 1; // Data IN EP is empty /*---------------------------------------------------------------------------- We need a buffer for incoming data on USB port because USB receives @@ -61,6 +63,7 @@ typedef struct __CDC_BUF_T } CDC_BUF_T; CDC_BUF_T CDC_OutBuf; // buffer for all CDC Out data +CDC_BUF_T CDC_InBuf; // buffer for all CDC Out data /*---------------------------------------------------------------------------- read data from CDC_OutBuf @@ -116,6 +119,71 @@ int CDC_OutBufAvailChar (int *availChar) } /* end Buffer handling */ +/*---------------------------------------------------------------------------- + read data from CDC_InBuf + *---------------------------------------------------------------------------*/ +int CDC_RdInBuf (char *buffer, const int *length) +{ + int bytesToRead, bytesRead; + + /* Read *length bytes, block if *bytes are not avaialable */ + bytesToRead = *length; + //bytesToRead = (bytesToRead < (*length)) ? bytesToRead : (*length); + bytesRead = bytesToRead; + + + // ... add code to check for underrun + + while (bytesToRead--) { + *buffer++ = CDC_BUF_RD(CDC_InBuf); + } + return (bytesRead); +} + +/*---------------------------------------------------------------------------- + write data to CDC_InBuf + *---------------------------------------------------------------------------*/ +int CDC_WrInBuf (const char *buffer, int *length) +{ + int bytesToWrite, bytesWritten; + + // Write *length bytes + bytesToWrite = *length; + bytesWritten = bytesToWrite; + + // Just block if we can't write all at once + // +1 to prevent an overflow of the ring buffer + while( CDC_BUF_SIZE - CDC_BUF_COUNT(CDC_InBuf) < bytesToWrite+1 ); + + //uint8_t flush = CDC_DepInEmpty; + + USB_DEVINTEN = 0; + while (bytesToWrite--) { + CDC_BUF_WR(CDC_InBuf, *buffer++); // Copy Data to buffer + } + //if( flush == 1 ){ + //if( CDC_DepInEmpty && CDC_BUF_COUNT(CDC_InBuf) ){ + if( CDC_DepInEmpty ){ + CDC_DepInEmpty = 0; + CDC_BulkIn(); + } + USB_DEVINTEN = DEV_STAT_INT | (0xFF<<1) | (USB_SOF_EVENT ? FRAME_INT : 0); + + return (bytesWritten); +} + +/*---------------------------------------------------------------------------- + check if character(s) are available at CDC_OutBuf + *---------------------------------------------------------------------------*/ +int CDC_InBufAvailChar (int *availChar) +{ + *availChar = CDC_BUF_COUNT(CDC_InBuf); + + return (0); +} +/* end Buffer handling */ + + /*---------------------------------------------------------------------------- CDC Initialisation @@ -129,12 +197,8 @@ void CDC_Init (void) CDC_SerialState = CDC_GetSerialState(); CDC_BUF_RESET(CDC_OutBuf); + CDC_BUF_RESET(CDC_InBuf); - // Initialise the CDC buffer. This is required to buffer outgoing - // data (MCU to PC) since data can only be sent 64 bytes per frame - // with at least 1ms between frames. To see how the buffer is used, - // see 'puts' in systeminit.c - cdcBufferInit(); } @@ -269,7 +333,6 @@ uint32_t CDC_SendBreak (unsigned short wDurationOfBreak) { return (TRUE); } - /*---------------------------------------------------------------------------- CDC_BulkIn call on DataIn Request Parameters: none @@ -277,25 +340,19 @@ uint32_t CDC_SendBreak (unsigned short wDurationOfBreak) { *---------------------------------------------------------------------------*/ void CDC_BulkIn(void) { -// int numBytesRead, numBytesAvail; -// -// // ToDo: Modify BulkIn to send incoming data to USB -// -// ser_AvailChar (&numBytesAvail); -// -// // ... add code to check for overwrite -// -// numBytesRead = ser_Read ((char *)&BulkBufIn[0], &numBytesAvail); -// -// // send over USB -// if (numBytesRead > 0) { -// USB_WriteEP (CDC_DEP_IN, &BulkBufIn[0], numBytesRead); -// } -// else { -// CDC_DepInEmpty = 1; -// } -// -// + int numBytesRead, numBytesAvail; + CDC_InBufAvailChar(&numBytesAvail); + numBytesRead = CDC_RdInBuf((char*)&BulkBufIn[0], &numBytesAvail); + // send over USB + if (numBytesRead > 0) { + //gpioSetValue (RB_LED0, 1); + USB_WriteEP (CDC_DEP_IN, &BulkBufIn[0], numBytesRead); + //gpioSetValue (RB_LED0, 0); + } else { + //USB_WriteEP (CDC_DEP_IN, "test\r\n", 6); + CDC_DepInEmpty = 1; + //gpioSetValue (RB_LED2, 1); + } } diff --git a/firmware/usbcdc/cdcuser.h b/firmware/usbcdc/cdcuser.h index 55cd910..d491b93 100644 --- a/firmware/usbcdc/cdcuser.h +++ b/firmware/usbcdc/cdcuser.h @@ -24,6 +24,7 @@ extern int CDC_RdOutBuf (char *buffer, const int *length); extern int CDC_WrOutBuf (const char *buffer, int *length); extern int CDC_OutBufAvailChar (int *availChar); +extern int CDC_WrInBuf (const char *buffer, int *length); /* CDC Data In/Out Endpoint Address */ #define CDC_DEP_IN 0x83 @@ -57,7 +58,7 @@ extern void CDC_Init (void); extern unsigned short CDC_GetSerialState (void); /* flow control */ -extern unsigned short CDC_DepInEmpty; // DataEndPoint IN empty +extern volatile unsigned char CDC_DepInEmpty; // DataEndPoint IN empty #endif /* __CDCUSER_H__ */ diff --git a/firmware/usbcdc/usbhw.c b/firmware/usbcdc/usbhw.c index 711190c..6fbf7ee 100644 --- a/firmware/usbcdc/usbhw.c +++ b/firmware/usbcdc/usbhw.c @@ -26,6 +26,7 @@ #include "usbhw.h" #include "usbcore.h" #include "usbuser.h" +#include "basic/basic.h" #include "usb/usbmsc.h" @@ -470,6 +471,10 @@ uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData) uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t cnt) { uint32_t n; + + //this seems rather brutal... + //disable all usb related interrupts or WrCmd might block + USB_DEVINTEN = 0; USB_CTRL = ((EPNum & 0x0F) << 2) | CTRL_WR_EN; /* 3 clock cycles to fetch the packet length from RAM. */ @@ -486,6 +491,9 @@ uint32_t USB_WriteEP (uint32_t EPNum, uint8_t *pData, uint32_t cnt) WrCmdEP(EPNum, CMD_VALID_BUF); + //enable interrupts again + USB_DEVINTEN = DEV_STAT_INT | (0xFF<<1) | (USB_SOF_EVENT ? FRAME_INT : 0); + return (cnt); } diff --git a/firmware/usbcdc/util.c b/firmware/usbcdc/util.c index fd3b041..d2c0c03 100644 --- a/firmware/usbcdc/util.c +++ b/firmware/usbcdc/util.c @@ -1,4 +1,5 @@ #include +#include #include "usbcdc/usb.h" #include "usbcdc/usbcore.h" @@ -6,54 +7,20 @@ #include "usbcdc/usbhw.h" #include "usbcdc/cdcuser.h" -#include "basic/basic.h" - -volatile unsigned int lastTick; - -// There must be at least 1ms between USB frames (of up to 64 bytes) -// This buffers all data and writes it out from the buffer one frame -// and one millisecond at a time int puts(const char * str){ if(!USB_Configuration) return -1; - - while(*str) - cdcBufferWrite(*str++); - - //XXX: This assumes systick is 1ms, which it isn't for us. - // this makes usbserial unnecessary slow. Ah well.... - - // Check if we can flush the buffer now or if we need to wait - unsigned int currentTick = systickGetTicks(); - if (currentTick != lastTick){ - uint8_t frame[64]; - uint32_t bytesRead = 0; - char repeat=0; - while (cdcBufferDataPending()){ - // Read up to 64 bytes as long as possible - bytesRead = cdcBufferReadLen(frame, 64); - USB_WriteEP (CDC_DEP_IN, frame, bytesRead); - if(repeat) - systickDelay(1); - else - repeat=1; - } - lastTick = currentTick; - } + + int len = strlen(str); + CDC_WrInBuf(str, &len); return 0; } int puts_plus(const char * str){ - if(!USB_Configuration) - return -1; - - while(*str) - cdcBufferWrite(*str++); - return 0; + return puts(str); } void usbCDCInit(){ - lastTick = systickGetTicks(); // Used to control output/printf timing CDC_Init(); // Initialise VCOM USB_Init(); // USB Initialization USB_Connect(TRUE); // USB Connect diff --git a/tools/game/py-pong/assets/ball.png b/tools/game/py-pong/assets/ball.png new file mode 100644 index 0000000..f80e521 Binary files /dev/null and b/tools/game/py-pong/assets/ball.png differ diff --git a/tools/game/py-pong/assets/bounce-paddle.wav b/tools/game/py-pong/assets/bounce-paddle.wav new file mode 100644 index 0000000..313fd93 Binary files /dev/null and b/tools/game/py-pong/assets/bounce-paddle.wav differ diff --git a/tools/game/py-pong/assets/bounce-wall.wav b/tools/game/py-pong/assets/bounce-wall.wav new file mode 100644 index 0000000..bd9f843 Binary files /dev/null and b/tools/game/py-pong/assets/bounce-wall.wav differ diff --git a/tools/game/py-pong/assets/digit_0.png b/tools/game/py-pong/assets/digit_0.png new file mode 100644 index 0000000..17d1daf Binary files /dev/null and b/tools/game/py-pong/assets/digit_0.png differ diff --git a/tools/game/py-pong/assets/digit_1.png b/tools/game/py-pong/assets/digit_1.png new file mode 100644 index 0000000..69ff195 Binary files /dev/null and b/tools/game/py-pong/assets/digit_1.png differ diff --git a/tools/game/py-pong/assets/digit_2.png b/tools/game/py-pong/assets/digit_2.png new file mode 100644 index 0000000..cdc5776 Binary files /dev/null and b/tools/game/py-pong/assets/digit_2.png differ diff --git a/tools/game/py-pong/assets/digit_3.png b/tools/game/py-pong/assets/digit_3.png new file mode 100644 index 0000000..74df4fe Binary files /dev/null and b/tools/game/py-pong/assets/digit_3.png differ diff --git a/tools/game/py-pong/assets/digit_4.png b/tools/game/py-pong/assets/digit_4.png new file mode 100644 index 0000000..5f5b150 Binary files /dev/null and b/tools/game/py-pong/assets/digit_4.png differ diff --git a/tools/game/py-pong/assets/digit_5.png b/tools/game/py-pong/assets/digit_5.png new file mode 100644 index 0000000..24eaa60 Binary files /dev/null and b/tools/game/py-pong/assets/digit_5.png differ diff --git a/tools/game/py-pong/assets/digit_6.png b/tools/game/py-pong/assets/digit_6.png new file mode 100644 index 0000000..215e7f9 Binary files /dev/null and b/tools/game/py-pong/assets/digit_6.png differ diff --git a/tools/game/py-pong/assets/digit_7.png b/tools/game/py-pong/assets/digit_7.png new file mode 100644 index 0000000..36d679b Binary files /dev/null and b/tools/game/py-pong/assets/digit_7.png differ diff --git a/tools/game/py-pong/assets/digit_8.png b/tools/game/py-pong/assets/digit_8.png new file mode 100644 index 0000000..8f5246f Binary files /dev/null and b/tools/game/py-pong/assets/digit_8.png differ diff --git a/tools/game/py-pong/assets/digit_9.png b/tools/game/py-pong/assets/digit_9.png new file mode 100644 index 0000000..c80204b Binary files /dev/null and b/tools/game/py-pong/assets/digit_9.png differ diff --git a/tools/game/py-pong/assets/dividing-line.png b/tools/game/py-pong/assets/dividing-line.png new file mode 100644 index 0000000..105682b Binary files /dev/null and b/tools/game/py-pong/assets/dividing-line.png differ diff --git a/tools/game/py-pong/assets/logo.png b/tools/game/py-pong/assets/logo.png new file mode 100644 index 0000000..9c1742d Binary files /dev/null and b/tools/game/py-pong/assets/logo.png differ diff --git a/tools/game/py-pong/assets/missed-ball.wav b/tools/game/py-pong/assets/missed-ball.wav new file mode 100644 index 0000000..b012be2 Binary files /dev/null and b/tools/game/py-pong/assets/missed-ball.wav differ diff --git a/tools/game/py-pong/assets/paddle.png b/tools/game/py-pong/assets/paddle.png new file mode 100644 index 0000000..7204eec Binary files /dev/null and b/tools/game/py-pong/assets/paddle.png differ diff --git a/tools/game/py-pong/main.py b/tools/game/py-pong/main.py new file mode 100644 index 0000000..b4b0dc0 --- /dev/null +++ b/tools/game/py-pong/main.py @@ -0,0 +1,122 @@ +import pygame, pypong +from pypong.player import BasicAIPlayer, KeyboardPlayer, MousePlayer, Rem0tePlayer +import r0ketrem0te.game +import time + +class Pong: + def __init__(self): + self.configuration = { + 'screen_size': (686,488), + 'paddle_image': 'assets/paddle.png', + 'paddle_left_position': 84., + 'paddle_right_position': 594., + 'paddle_velocity': 6., + 'paddle_bounds': (0, 488), # This sets the upper and lower paddle boundary.The original game didn't allow the paddle to touch the edge, + 'line_image': 'assets/dividing-line.png', + 'ball_image': 'assets/ball.png', + 'ball_velocity': 4., + 'ball_velocity_bounce_multiplier': 1.105, + 'ball_velocity_max': 32., + 'score_left_position': (141, 30), + 'score_right_position': (473, 30), + 'digit_image': 'assets/digit_%i.png', + 'sound_missed': 'assets/missed-ball.wav', + 'sound_paddle': 'assets/bounce-paddle.wav', + 'sound_wall': 'assets/bounce-wall.wav', + 'sound': True, + } + pygame.mixer.pre_init(22050, -16, 2, 1024) + pygame.init() + + self.rem0te = r0ketrem0te.game.Game('/dev/ttyACM0', "pong", 83, + 81, [ord(x) for x in 'REM0T'], 2, True) + self.rem0te.registerPlayerCallback(self.playercallback) + + self.player_right = Rem0tePlayer(self.rem0te) + self.player_left = Rem0tePlayer(self.rem0te) + + self.stop = True + self.start = False + self.restart() + + def playercallback(self, action, player): + if action == 'added': + if self.player_left.player == None: + self.player_left.player = player + elif self.player_right.player == None: + self.player_right.player = player + if self.player_left.player and self.player_right.player: + self.start = True + elif action == 'removed': + print 'got remove for', player.nick + if self.player_left.player == player: + print 'removing left player' + self.player_left.player = None + elif self.player_right.player == player: + print 'removing right player' + self.player_right.player = None + if self.player_left.player == None or self.player_right.player == None: + print 'halting game' + self.stop = True + + def restart(self): + self.display_surface = pygame.display.set_mode(self.configuration['screen_size']) + self.output_surface = self.display_surface.copy().convert_alpha() + self.output_surface.fill((0,0,0)) + #~ debug_surface = output_surface.copy() + #~ debug_surface.fill((0,0,0,0)) + self.debug_surface = None + self.clock = pygame.time.Clock() + self.input_state = {'key': None, 'mouse': None} + + # Prepare game + + self.game = pypong.Game(self.player_left, self.player_right, self.configuration) + + def run(self): + # Main game loop + timestamp = 1 + while self.game.running: + if self.start: + self.restart() + self.start = False + self.stop = False + + self.clock.tick(60) + now = pygame.time.get_ticks() + if timestamp > 0 and timestamp < now: + timestamp = now + 5000 + print self.clock.get_fps() + self.input_state['key'] = pygame.key.get_pressed() + self.input_state['mouse'] = pygame.mouse.get_pos() + if not self.stop: + self.game.update() + self.game.draw(self.output_surface) + + + #~ pygame.surfarray.pixels_alpha(output_surface)[:,::2] = 12 + self.display_surface.blit(self.output_surface, (0,0)) + + font = pygame.font.Font(None, 36) + if self.player_left.player: + text = font.render(self.player_left.player.nick, 1, (0, 255, 0)) + textpos = text.get_rect(centerx=self.output_surface.get_width()/4) + self.display_surface.blit(text, textpos) + + if self.player_right.player: + text = font.render(self.player_right.player.nick, 1, (0, 255, 0)) + textpos = text.get_rect(centerx=self.output_surface.get_width()/4*3) + self.display_surface.blit(text, textpos) + + if self.debug_surface: + self.display_surface.blit(self.debug_surface, (0,0)) + pygame.display.flip() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.game.running = False + elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: + self.game.running = False + +if __name__ == '__main__': + pong = Pong() + pong.run() diff --git a/tools/game/py-pong/pypong/__init__.py b/tools/game/py-pong/pypong/__init__.py new file mode 100644 index 0000000..856f0e5 --- /dev/null +++ b/tools/game/py-pong/pypong/__init__.py @@ -0,0 +1,150 @@ +import pygame, math, random, entity + +def load_image(path): + surface = pygame.image.load(path) + surface.convert() + pygame.surfarray.pixels3d(surface)[:,:,0:1:] = 0 + return surface + +def line_line_intersect(x1, y1, x2, y2, x3, y3, x4, y4): + # Taken from http://paulbourke.net/geometry/lineline2d/ + # Denominator for ua and ub are the same, so store this calculation + d = float((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)) + # n_a and n_b are calculated as seperate values for readability + n_a = float((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) + n_b = float((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) + # Make sure there is not a division by zero - this also indicates that + # the lines are parallel. + # If n_a and n_b were both equal to zero the lines would be on top of each + # other (coincidental). This check is not done because it is not + # necessary for this implementation (the parallel check accounts for this). + if d == 0: + return False + # Calculate the intermediate fractional point that the lines potentially intersect. + ua = n_a / d + ub = n_b / d + # The fractional point will be between 0 and 1 inclusive if the lines + # intersect. If the fractional calculation is larger than 1 or smaller + # than 0 the lines would need to be longer to intersect. + if ua >= 0. and ua <= 1. and ub >= 0. and ub <= 1.: + return [x1 + (ua * (x2 - x1)), y1 + (ua * (y2 - y1))] + return False + +class Game(object): + def __init__(self, player_left, player_right, configuration): + self.player_left = player_left + self.player_right = player_right + self.configuration = configuration + self.background = pygame.Surface(configuration['screen_size']) + self.sprites = pygame.sprite.OrderedUpdates() + line = entity.Line(load_image(configuration['line_image']), self.sprites) + line.rect.topleft = ((configuration['screen_size'][0]-line.rect.width)/2, 0) + paddle_image = load_image(configuration['paddle_image']) + self.paddle_left = entity.Paddle(configuration['paddle_velocity'], paddle_image, configuration['paddle_bounds'], self.sprites) + self.paddle_right = entity.Paddle(configuration['paddle_velocity'], paddle_image, configuration['paddle_bounds'], self.sprites) + self.paddle_left.rect.topleft = (self.configuration['paddle_left_position'], (self.configuration['screen_size'][1]-self.paddle_left.rect.height)/2) + self.paddle_right.rect.topleft = (self.configuration['paddle_right_position'], (self.configuration['screen_size'][1]-self.paddle_left.rect.height)/2) + digit_images = [load_image(configuration['digit_image'] % n) for n in xrange(10)] + self.score_left = entity.Score(digit_images, self.sprites) + self.score_left.rect.topleft = configuration['score_left_position'] + self.score_right = entity.Score(digit_images, self.sprites) + self.score_right.rect.topleft = configuration['score_right_position'] + ball_image = load_image(configuration['ball_image']) + self.ball = entity.Ball(self.configuration['ball_velocity'], ball_image, self.sprites) + self.bounds = pygame.Rect(20, 0, configuration['screen_size'][0]-ball_image.get_width()-20, configuration['screen_size'][1]-ball_image.get_height()) + self.sound_missed = pygame.mixer.Sound(configuration['sound_missed']) + self.sound_paddle = pygame.mixer.Sound(configuration['sound_paddle']) + self.sound_wall = pygame.mixer.Sound(configuration['sound_wall']) + self.reset_game(random.random()<0.5) + self.running = True + + def play_sound(self, sound): + if self.configuration['sound']: + sound.play() + + def reset_game(self, serveLeft=True): + y = self.configuration['screen_size'][1] - self.ball.rect.height + self.ball.position_x = (self.configuration['screen_size'][0]-self.ball.rect.width)/2.0 + self.ball.position_y = y * random.random() + self.ball.velocity = self.configuration['ball_velocity'] + a = random.random() * math.pi / 2. - math.pi / 4. + self.ball.velocity_vec[0] = self.ball.velocity * math.cos(a) + self.ball.velocity_vec[1] = self.ball.velocity * math.sin(a) + if random.random() < 0.5: + self.ball.velocity_vec[1] = -self.ball.velocity_vec[1] + if serveLeft: + self.ball.velocity_vec[0] *= -1 + + def update(self): + # Store previous ball position for line-line intersect test later + ball_position_x = self.ball.position_x + ball_position_y = self.ball.position_y + # Update sprites and players + self.sprites.update() + self.player_left.update(self.paddle_left, self) + self.player_right.update(self.paddle_right, self) + # Paddle collision check. Could probably just do a line-line intersect but I think I prefer having the pixel-pefect result of a rect-rect intersect test as well. + if self.ball.rect.x < self.bounds.centerx: + # Left side bullet-through-paper check on ball and paddle + if self.ball.velocity_vec[0] < 0: + intersect_point = line_line_intersect( + self.paddle_left.rect.right, self.paddle_left.rect.top, + self.paddle_left.rect.right, self.paddle_left.rect.bottom, + ball_position_x-self.ball.rect.width/2, ball_position_y+self.ball.rect.height/2, + self.ball.position_x-self.ball.rect.width/2, self.ball.position_y+self.ball.rect.height/2 + ) + if intersect_point: + self.ball.position_y = intersect_point[1]-self.ball.rect.height/2 + if intersect_point or (self.paddle_left.rect.colliderect(self.ball.rect) and self.ball.rect.right > self.paddle_left.rect.right): + self.ball.position_x = self.paddle_left.rect.right + velocity = self.paddle_left.calculate_bounce(min(1,max(0,(self.ball.rect.centery - self.paddle_left.rect.y)/float(self.paddle_left.rect.height)))) + self.ball.velocity = min(self.configuration['ball_velocity_max'], self.ball.velocity * self.configuration['ball_velocity_bounce_multiplier']) + self.ball.velocity_vec[0] = velocity[0] * self.ball.velocity + self.ball.velocity_vec[1] = velocity[1] * self.ball.velocity + self.player_left.hit() + self.play_sound(self.sound_paddle) + else: + # Right side bullet-through-paper check on ball and paddle. + if self.ball.velocity_vec[0] > 0: + intersect_point = line_line_intersect( + self.paddle_right.rect.left, self.paddle_right.rect.top, + self.paddle_right.rect.left, self.paddle_right.rect.bottom, + ball_position_x-self.ball.rect.width/2, ball_position_y+self.ball.rect.height/2, + self.ball.position_x-self.ball.rect.width/2, self.ball.position_y+self.ball.rect.height/2 + ) + if intersect_point: + self.ball.position_y = intersect_point[1]-self.ball.rect.height/2 + if intersect_point or (self.paddle_right.rect.colliderect(self.ball.rect) and self.ball.rect.x < self.paddle_right.rect.x): + self.ball.position_x = self.paddle_right.rect.x - self.ball.rect.width + velocity = self.paddle_right.calculate_bounce(min(1,max(0,(self.ball.rect.centery - self.paddle_right.rect.y)/float(self.paddle_right.rect.height)))) + self.ball.velocity = min(self.configuration['ball_velocity_max'], self.ball.velocity * self.configuration['ball_velocity_bounce_multiplier']) + self.ball.velocity_vec[0] = -velocity[0] * self.ball.velocity + self.ball.velocity_vec[1] = velocity[1] * self.ball.velocity + self.player_right.hit() + self.play_sound(self.sound_paddle) + # Bounds collision check + if self.ball.rect.y < self.bounds.top: + self.ball.position_y = float(self.bounds.top) + self.ball.velocity_vec[1] = -self.ball.velocity_vec[1] + self.play_sound(self.sound_wall) + elif self.ball.rect.y > self.bounds.bottom: + self.ball.position_y = float(self.bounds.bottom) + self.ball.velocity_vec[1] = -self.ball.velocity_vec[1] + self.play_sound(self.sound_wall) + # Check the ball is still in play + if self.ball.rect.x < self.bounds.x: + self.player_left.lost() + self.player_right.won() + self.score_right.score += 1 + self.reset_game(False) + self.play_sound(self.sound_missed) + if self.ball.rect.x > self.bounds.right: + self.player_left.won() + self.player_right.lost() + self.score_left.score += 1 + self.reset_game(True) + self.play_sound(self.sound_missed) + + def draw(self, display_surface): + self.sprites.clear(display_surface, self.background) + return self.sprites.draw(display_surface) diff --git a/tools/game/py-pong/pypong/entity.py b/tools/game/py-pong/pypong/entity.py new file mode 100644 index 0000000..170be57 --- /dev/null +++ b/tools/game/py-pong/pypong/entity.py @@ -0,0 +1,87 @@ +import pygame, math +from pygame.sprite import Sprite + +class Paddle(Sprite): + def __init__(self, velocity, image, bounds_y, *groups): + Sprite.__init__(self, *groups) + self.image = image + self.rect = self.image.get_rect() + self.direction = 0 + self.velocity = velocity + self.bounds_y = bounds_y + # Like original pong, we break this up into 8 segments from the edge angle (acute_angle) to pi/2 at the center + # Changing acute_angle lets us change the extreme edge angle of the paddle. + acute_angle = .125 + # Build the angles from acute_angle to the first 0.5 center value then append the values going from the + # second center 0.5 value by using the values we just calculated reversed. + angles = [acute_angle + (0.5-acute_angle)/3.0 * n for n in xrange(4)] + angles += map(lambda x: 1 + x * -1, reversed(angles)) + # Final table is the output vector (x,y) of each angle + self.bounce_table = [(math.cos(n*math.pi-math.pi/2.0), math.sin(n*math.pi-math.pi/2.0)) for n in angles] + + def update(self): + self.rect.y = max(self.bounds_y[0], min(self.bounds_y[1]-self.rect.height, self.rect.y + self.direction * self.velocity)) + + def calculate_bounce(self, delta): + return self.bounce_table[int(round(delta * (len(self.bounce_table)-1)))] + +class Line(Sprite): + def __init__(self, image, *groups): + Sprite.__init__(self, *groups) + self.image = image + self.rect = self.image.get_rect() + +class Ball(Sprite): + def __init__(self, velocity, image, *groups): + Sprite.__init__(self, *groups) + self.velocity = velocity + self.image = image + self.rect = self.image.get_rect() + self.position_vec = [0., 0.] + self.velocity_vec = [0., 0.] + + def update(self): + self.position_vec[0] += self.velocity_vec[0] + self.position_vec[1] += self.velocity_vec[1] + self.rect.x = self.position_vec[0] + self.rect.y = self.position_vec[1] + + def set_position_x(self, value): + self.position_vec[0] = value + self.rect.left = value + position_x = property(lambda self: self.position_vec[0], set_position_x) + + def set_position_y(self, value): + self.position_vec[1] = value + self.rect.top = value + position_y = property(lambda self: self.position_vec[1], set_position_y) + +class Score(Sprite): + def __init__(self, image_list, *groups): + Sprite.__init__(self, *groups) + self.image_list = image_list + self.image = None + self.rect = pygame.Rect(0,0,0,0) + self.score = 0 + + def get_score(self): + return self.score_value + + def set_score(self, value): + self.score_value = value + digit_spacing = 8 + digit_width = self.image_list[0].get_width() + digit_height = self.image_list[0].get_height() + values = map(int, reversed(str(self.score_value))) + surface_width = len(values) * digit_width + (len(values)-1) * digit_spacing + if not self.image or self.image.get_width() < surface_width: + self.image = pygame.Surface((surface_width, digit_height)) + self.image.fill((0,0,0)) + self.rect.width = self.image.get_width() + self.rect.height = self.image.get_height() + offset = self.image.get_width()-digit_width + for i in values: + self.image.blit(self.image_list[i], (offset, 0)) + offset = offset - (digit_width + digit_spacing) + + score = property(get_score, set_score) diff --git a/tools/game/py-pong/pypong/player.py b/tools/game/py-pong/pypong/player.py new file mode 100644 index 0000000..788b65d --- /dev/null +++ b/tools/game/py-pong/pypong/player.py @@ -0,0 +1,118 @@ +import pygame, random +import r0ketrem0te.game +import r0ketrem0te.bridge +import r0ketrem0te.packets +import time +import Queue +import threading + +class Rem0tePlayer(object): + def __init__(self, rem0te): + self.rem0te = rem0te + self.rem0te.bridge.registerCallback(self.receivedPacket) + self.state = 0 + self.player = None + + def receivedPacket(self, packet): + if self.player == None: + return + if packet.id == self.player.id: + if isinstance(packet, r0ketrem0te.packets.Button): + self.state = packet.button + + def update(self, paddle, game): + if self.state == 1: + paddle.direction = -1 + elif self.state == 2: + paddle.direction = 1 + else: + paddle.direction = 0 + + def hit(self): + pass + + def lost(self): + pass + + def won(self): + pass + +class BasicAIPlayer(object): + def __init__(self): + self.bias = random.random() - 0.5 + self.hit_count = 0 + + def update(self, paddle, game): + # Dead simple AI, waits until the ball is on its side of the screen then moves the paddle to intercept. + # A bias is used to decide which edge of the paddle is going to be favored. + if (paddle.rect.x < game.bounds.centerx and game.ball.rect.x < game.bounds.centerx) or (paddle.rect.x > game.bounds.centerx and game.ball.rect.x > game.bounds.centerx): + delta = (paddle.rect.centery + self.bias * paddle.rect.height) - game.ball.rect.centery + if abs(delta) > paddle.velocity: + if delta > 0: + paddle.direction = -1 + else: + paddle.direction = 1 + else: + paddle.direction = 0 + else: + paddle.direction = 0 + + def hit(self): + self.hit_count += 1 + if self.hit_count > 6: + self.bias = random.random() - 0.5 # Recalculate our bias, this game is going on forever + self.hit_count = 0 + + def lost(self): + # If we lose, randomise the bias again + self.bias = random.random() - 0.5 + + def won(self): + pass + +class KeyboardPlayer(object): + def __init__(self, input_state, up_key=None, down_key=None): + self.input_state = input_state + self.up_key = up_key + self.down_key = down_key + + def update(self, paddle, game): + if self.input_state['key'][self.up_key]: + paddle.direction = -1 + elif self.input_state['key'][self.down_key]: + paddle.direction = 1 + else: + paddle.direction = 0 + + def hit(self): + pass + + def lost(self): + pass + + def won(self): + pass + +class MousePlayer(object): + def __init__(self, input_state): + self.input_state = input_state + pygame.mouse.set_visible(False) + + def update(self, paddle, game): + centery = paddle.rect.centery/int(paddle.velocity) + mousey = self.input_state['mouse'][1]/int(paddle.velocity) + if centery > mousey: + paddle.direction = -1 + elif centery < mousey: + paddle.direction = 1 + else: + paddle.direction = 0 + + def hit(self): + pass + + def lost(self): + pass + + def won(self): + pass diff --git a/tools/game/r0ketrem0te/__init__.py b/tools/game/r0ketrem0te/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/game/r0ketrem0te/bridge.py b/tools/game/r0ketrem0te/bridge.py new file mode 100644 index 0000000..b1d1bff --- /dev/null +++ b/tools/game/r0ketrem0te/bridge.py @@ -0,0 +1,240 @@ +import serialinterface +import threading +import Queue +import crcmod +import packets +import traceback + +class QueuePacket: + def __init__(self, channel, mac, acked, packet, callback=None): + self.channel = channel + self.mac = mac + self.acked = acked + self.packet = packet + self.priority = packet.priority + self.retriesleft = 5 + self.timeout = 0.1 + self.timer = None + self.timedout = False + self.lock = threading.RLock() + self.isdone = False + self.callback = callback + + def __cmp__(self, other): + if not isinstance(other,QueuePacket): + return 1 + if self.priority < other.priority: + return -1 + if self.priority > other.priority: + return 1 + return 0 + + def valid(self): + with self.lock: + return self.retriesleft > 0 and not self.acked + + def sent(self, timeoutcallback): + with self.lock: + self.timedout = False + if self.retriesleft > 0: + self.retriesleft-=1 + if self.acked: + self.timeoutcallback = timeoutcallback + self.timer = threading.Timer(self.timeout, self.timercallback) + self.timer.start() + elif self.callback: + self.callback('done') + + def done(self): + with self.lock: + if self.timer != None: + self.timer.cancel() + self.timer = None + self.isdone = True + if self.callback: + self.callback('done') + + def timercallback(self): + with self.lock: + self.timedout = True + self.timeoutcallback(self) + if retriesleft == 0: + self.callback('timeout') + +class Bridge: + def __init__(self, path2device, channel, rxmac): + self.ser = serialinterface.SerialInterface(path2device, 115200, 0) + self.free = threading.Lock() + self.queueslock = threading.Lock() + self.packets = Queue.PriorityQueue() + self.outpackets = Queue.Queue() + self.crc = crcmod.predefined.mkCrcFun('crc-ccitt-false') + self.queues = {} + self.callbacks = [] + self.ctrs = {} + + self.reader = threading.Thread(target = self.readerThread) + self.reader.daemon = True + + self.writer = threading.Thread(target = self.writerThread) + self.writer.daemon = True + + self.writer.start() + self.reader.start() + + self.packetlength = None + self.txmac = None + self.rxmac = None + self.channel = None + self.gameChannel = channel + + self.setPacketLength(0x20) + self.setRxMAC(rxmac) + self.setChannel(channel) + + self.ctr = 0 + + def registerCallback(self, callback): + if callback not in self.callbacks: + self.callbacks.append(callback) + + def registerQueue(self, queue): + if queue not in self.queues: + self.queues[queue] = None + + def putInQueue(self, queue, qp): + if queue in self.queues: + queue.put(qp); + self.checkQueues() + + def processAck(self, ack): + #find the corresponding packet in the queues + found = False + for pq in self.queues.values(): + if pq.packet.id == ack.id and pq.packet.ctr == ack.ctr: + #notify it + pq.done() + found = True + #notify the queue system + if found: + self.checkQueues() + else: + print "got an ack for an unknown packet" + + def packetTimeout(self, qp): + self.checkQueues() + + def checkQueues(self): + with self.queueslock: + for q in self.queues: + #check if a packet has to be resent + #remove it from the packet slot if it has been resent to often + qp = self.queues[q] + if qp != None: + if qp.valid(): + self.queues[q] = None + elif qp.timedout: + print "packet timed out" + qp.packet + self.outpackets.put(qp) + #check if a idle queue has a new packet in line + qp = self.queues[q] + if qp == None and not q.empty(): + qp = q.get() + if not isinstance(qp.packet,packets.Ack): + self.ctr+=1 + qp.packet.ctr = self.ctr + self.queues[q] = qp + self.outpackets.put(qp) + + def writerThread(self): + while True: + try: + #wait until we have packets to take care of + qp = self.outpackets.get() + #send it and notify the queuepacket + self.setTxMAC(qp.mac) + self.setChannel(qp.channel) + self.sendPacket(qp.packet) + qp.sent(self.packetTimeout) + self.setChannel(self.gameChannel) + except Exception as e: + print e + traceback.print_stack() + + def readerThread(self): + while True: + try: + (command, data) = self.ser.readMessage() + if command == '1': + self.newPacket(data) + elif command == '2': + self.free.release() + except Exception as e: + print e + traceback.print_stack() + + def newPacket(self, data): + print "received:", list(data) + crc = self.crc(data[:-2]) + if data[-2:] == chr(crc>>8) + chr(crc&0xFF): + packet = packets.fromMessage(data) + print "received:", packet + if packet == None: + return + #if packet.id in self.ctrs and self.ctrs[packet.id] == packet.ctr: + # print 'ignoring duplicate' + # return + if isinstance(packet,packets.Ack): + self.ProcessAck(packet) + else: + for callback in self.callbacks: + callback(packet) + #self.packets.put(packet) + +# def gotPacket(self): +# return not self.packets.empty() + +# def getPacket(self): +# return self.packets.get() + + def sendPacket(self, packet): + print 'sending', packet + data = packet.toMessage() + crc = self.crc(data) + data += chr(crc>>8); + data += chr(crc&0xFF); + self.free.acquire() + #print 'sending packet: len:', len(data), 'data:', list(data) + self.ser.writeMessage('1',data); + + def setPacketLength(self, length): + if length == self.packetlength: + return + self.free.acquire() + self.ser.writeMessage('6', '%c'%length) + self.packetLength = length + + def setTxMAC(self, mac): + if mac == self.txmac: + return + self.free.acquire() + print "setting tx mac", mac + self.ser.writeMessage('3', ''.join([chr(x) for x in mac])) + self.txmac = mac + + def setRxMAC(self, mac): + if mac == self.rxmac: + return + self.free.acquire() + print "setting rx mac", mac + self.ser.writeMessage('4', ''.join([chr(x) for x in mac])) + self.rxmac = mac + + def setChannel(self, channel): + if channel == self.channel: + return + self.free.acquire() + print "setting channel", channel + self.ser.writeMessage('5', '%c'%channel) + self.channel = channel + diff --git a/tools/game/r0ketrem0te/game.py b/tools/game/r0ketrem0te/game.py new file mode 100644 index 0000000..3ee25c1 --- /dev/null +++ b/tools/game/r0ketrem0te/game.py @@ -0,0 +1,114 @@ +import bridge +import packets +import time +import Queue +import random +import threading + +class Player(): + def __init__(self, id): + self.id = id + self.nick = 'anonymous' + self.timeout = 10 + self.active = False + +class Game: + def __init__(self, device, gameName, gameChannel, announcechannel, announcemac, maxplayer=0, askname=False): + self.gameName = gameName + self.channel = gameChannel + self.gamemac = [int(random.random()*254) for x in range(1,6)] + self.playermac = list(self.gamemac) + self.playermac[4]+=1 + self.gameid = int(random.random()*(2**31)) + + self.bridge = bridge.Bridge(device, self.channel, self.gamemac) + self.announce = packets.Announce(self.gamemac, self.channel, + self.gameid, 0, "testgame") + + self.announcequeue = Queue.Queue() + self.bridge.registerQueue(self.announcequeue) + self.announcechannel = announcechannel + self.announcemac = announcemac + self.askname = askname + + self.sendAnnounce() + + self.maxplayer = maxplayer + self.players = {} + self.callbacks = [] + self.queue = Queue.Queue() + self.bridge.registerQueue(self.queue) + self.bridge.registerCallback(self.receivedPacket) + self.checkPlayers() + + def checkPlayers(self): + if self.maxplayer > 0: + toremove = [] + for id in self.players: + player = self.players[id] + player.timeout-=1 + if player.timeout == 0: + toremove.append(id) + for id in toremove: + player = self.players[id] + if self.askname: + print "removing player", player.nick + else: + print "removing player", id + + del self.players[id] + if player.active: + player.active = False + for callback in self.callbacks: + callback("removed", player) + self.timer = threading.Timer(1, self.checkPlayers) + self.timer.start() + + def receivedPacket(self, packet): + if self.maxplayer == 0: + return + if isinstance(packet, packets.Join): + # flags = 1: join ok + # flags = 0: join not ok + flags = 0 + if len(self.players) < self.maxplayer: + flags = 1 + self.players[packet.id] = Player(packet.id) + + ack = packets.Ack(packet.id, packet.ctr, flags) + qp = bridge.QueuePacket( + self.channel, self.playermac, False, ack) + self.bridge.putInQueue(self.queue, qp) + elif packet.id in self.players: + print "player known:", packet.id + player = self.players[packet.id] + player.timeout = 10 + if not player.active and isinstance(packet, packets.Button): + if self.askname: + nickrequest = packets.Nickrequest(packet.id) + qp = bridge.QueuePacket(self.channel, + self.playermac, False, nickrequest) + self.bridge.putInQueue(self.queue, qp) + else: + player.active = True + for callback in self.callbacks: + callback("added", player) + elif not player.active and isinstance(packet, packets.Nick): + if self.askname: + player.nick = packet.nick + player.active = True + for callback in self.callbacks: + callback("added", player) + else: + print "player unknown" + + def sendAnnounce(self): + aq = bridge.QueuePacket(self.announcechannel, + self.announcemac, False, self.announce) + self.bridge.putInQueue(self.announcequeue, aq) + self.announcetimer = threading.Timer(1, self.sendAnnounce) + self.announcetimer.start() + + def registerPlayerCallback(self, callback): + if not callback in self.callbacks: + self.callbacks.append(callback) diff --git a/tools/game/r0ketrem0te/packets.py b/tools/game/r0ketrem0te/packets.py new file mode 100644 index 0000000..571ba5f --- /dev/null +++ b/tools/game/r0ketrem0te/packets.py @@ -0,0 +1,207 @@ +def inttouint32(v): + return chr(v&0xff)+chr((v>>8)&0xff)+chr((v>>16)&0xff)+chr((v>>24)&0xff) + +def uint32toint(v): + return (ord(v[3])<< 24) + (ord(v[2])<<16) + (ord(v[1])<<8) + (ord(v[0])) + +class Packet: + def __init__(self, command, id=None): + self.ctr = 0 + if id == None: + message = command + command = message[2] + id = uint32toint(message[3:7]) + self.ctr = uint32toint(message[7:11]) + self.length = 32 + self.protocol = 'G' + self.command = command + self.id = id + self.priority = 5 + + def toMessage(self): + message = chr(self.length) + message += self.protocol + message += self.command + message += inttouint32(self.id) + message += inttouint32(self.ctr) + return message + + def headerString(self): + return "id=%d, ctr=%d"%(self.id, self.ctr) + + def __str__(self): + s = "Packet with protocol=" + self.protocol + s += ", command=" + self.command + s += ", "+ self.headerString() + return s + +class Button(Packet): + def __init__(self, id, button=None): + if button!= None: + Packet.__init__(self, 'B', id) + else: + message = id + Packet.__init__(self, message) + button = ord(message[11]) + self.button = button + + def toMessage(self): + base = Packet.toMessage(self) + return base + chr(self.button) + '\x00'*18 + + def __str__(self): + s = "Button packet with " + self.headerString() + s += ", button=%d"%self.button + return s + +class Announce(Packet): + def __init__(self, gameMac, gameChannel, gameId, gameFlags, gameTitle): + #always a broadcast + Packet.__init__(self, 'A', 0) + self.gameMac = gameMac + self.gameChannel = gameChannel + self.gameId = gameId + self.gameFlags = gameFlags + self.gameTitle = gameTitle[0:8] + self.priority = 3 + + def toMessage(self): + message = Packet.toMessage(self) + message += ''.join([chr(x) for x in self.gameMac]) + message += chr(self.gameChannel) + message += inttouint32(self.gameId) + message += chr(self.gameFlags) + message += self.gameTitle + if len(self.gameTitle) < 8: + message += '\x00'*(8-len(self.gameTitle)) + return message + + def __str__(self): + s = "Announce packet with " + self.headerString() + s += ", gameMac="+str(self.gameMac) + s += ", gameChannel=%d"%self.gameChannel + s += ", gameId=%d"%self.gameId + s += ", gameFlags=%d"%self.gameFlags + s += ", gameTitle="+self.gameTitle + return s + +class Join(Packet): + def __init__(self, id, gameId=None): + if gameId != None: + Packet.__init__(self, 'J', id) + else: + message = id + Packet.__init__(self, message) + gameId = uint32toint(message[11:15]) + self.gameId = gameId + + def toMessage(self): + message = Packet.toMessage(self) + message += inttouint32(self.gameId) + message += '\x00'*15 + return message + + def __str__(self): + s = "Join packet with " + self.headerString() + s += ", gameId=%d"%self.gameId + return s + +class Ack(Packet): + def __init__(self, id, ctr, flags=None): + if ctr != None and flags != None: + Packet.__init__(self, 'a', id) + self.ctr = ctr + else: + message = id + Packet.__init__(self, message) + flags = ord(message[11]) + self.flags = flags + self.priority = 3 + + def toMessage(self): + message = Packet.toMessage(self) + message += chr(self.flags) + message += '\x00'*18 + return message + + def __str__(self): + s = "Ack packet with " + self.headerString() + s += ", flags=%d"%self.flags + return s + +class Nickrequest(Packet): + def __init__(self, id): + Packet.__init__(self, 'N', id) + + def __str__(self): + s = "Nickrequest packet with " + self.headerString() + return s + + def toMessage(self): + message = Packet.toMessage(self) + message += '\x00'*19 + return message + +class Nick(Packet): + def __init__(self, id, flags=None, nick=None): + if flags != None and nick != None: + Packet.__init__(self, 'n', id) + else: + message = id + Packet.__init__(self, message) + flags = ord(message[11]) + nick = message[12:30].rstrip(' \t\r\n\0') + self.flags = flags + self.nick = nick + + def toMessage(self): + message = Packet.toMessage(self) + message += chr(self.flags) + message += self.nick + if len(self.nick) < 18: + message += '\x00'*(18-len(self.nick)) + return message + + def __str__(self): + s = "Nick packet with " + self.headerString() + s += ", flags=%d"%self.flags + s += ", nick="+self.nick + return s + +class Text(Packet): + def __init__(self, id, x, y, flags, text): + Packet.__init__(self, 'T', id) + self.x = x + self.y = y + self. flags = flags + self.text = text[0:16] + + def toMessage(self): + message = Packet.toMessage(self) + message += chr(self.x) + message += chr(self.y) + message += chr(self.flags) + message += self.text + if len(self.text) < 16: + message += '\x00'*(16-len(self.text)) + return message + + def __str__(self): + s = "Text packet with " + self.headerString() + s += ", x=%d"%self.x + s += ", y=%d"%self.y + s += ", flags=%d"%self.flags + s += ", text="+self.text + return s + +def fromMessage(message): + if len(message) >= 30 and ord(message[0]) == 32 and message[1] == 'G': + if message[2] == 'B': + return Button(message) + if message[2] == 'n': + return Nick(message) + if message[2] == 'J': + return Join(message) + if message[2] == 'a': + return Ack(message) + return None diff --git a/tools/game/r0ketrem0te/serialinterface.py b/tools/game/r0ketrem0te/serialinterface.py new file mode 100644 index 0000000..67821c1 --- /dev/null +++ b/tools/game/r0ketrem0te/serialinterface.py @@ -0,0 +1,92 @@ +import serial +import string +import sys +import time + +class SerialInterface: + def __init__ ( self, path2device, baudrate, timeout=0): + self.portopen = False + while not self.portopen: + try: + self.ser = serial.Serial(path2device, baudrate) + self.path2device = path2device + self.baudrate = baudrate + self.timeout = timeout+1 + self.ser.flushInput() + self.ser.flushOutput() + if timeout: + self.ser.setTimeout(timeout+1) + self.portopen = True + except serial.SerialException: + print "exception while opening" + pass + time.sleep(1) + #print "done" + def close(self): + try: + self.portopen = False + self.ser.close() + except serial.SerialException: + pass + def reinit(self): + self.close() + print "reopening" + while not self.portopen: + self.__init__(self.path2device, self.baudrate, self.timeout) + time.sleep(1) + print "done" + + def writeMessage(self,command,message): + enc = "\\"+ command + message.replace('\\','\\\\') + "\\0"; + #print 'writing %s' % list(enc) + try: + self.ser.write(enc) + except : + pass + #self.reinit() + + def readMessage(self): + data = "" + escaped = False + stop = False + start = False + inframe = False + command = '' + while True: + starttime = time.time() + c = self.ser.read(1) + endtime = time.time() + if len(c) == 0: #A timout occured + if endtime-starttime < self.timeout - 1: + print "port broken" + self.reinit() + raise Exception() + else: + #print 'TIMEOUT' + return (False, '') + if escaped: + if c == '\\': + d = '\\' + elif c == '0': + stop = True + inframe = False + else: + start = True + inframe = True + command = c + data = "" + escaped = False + elif c == '\\': + escaped = 1 + else: + d = c + + if start and inframe: + start = False + elif stop: + #print 'received message: len=%d data=%s'%(len(data),data) + #print 'received message. command=',command, "data=" ,list(data) + return (command, data) + elif escaped == False and inframe: + data += str(d) + diff --git a/tools/game/setup.py b/tools/game/setup.py new file mode 100644 index 0000000..9ef3851 --- /dev/null +++ b/tools/game/setup.py @@ -0,0 +1,5 @@ +from distutils.core import setup +setup(name='r0ketrem0te', + version='1.0', + packages=['r0ketrem0te'], + ) diff --git a/tools/game/testgame.py b/tools/game/testgame.py new file mode 100644 index 0000000..dc3c037 --- /dev/null +++ b/tools/game/testgame.py @@ -0,0 +1,16 @@ +import r0ketrem0te.game +import r0ketrem0te.bridge +import r0ketrem0te.packets +import time +import Queue + +def receivedPacket(packet): + pass +game = r0ketrem0te.game.Game('/dev/ttyACM0', "testgame", 83, + 81, [ord(x) for x in 'REM0T'], 2, True) +queue = Queue.Queue() +game.bridge.registerQueue(queue) +game.bridge.registerCallback(receivedPacket) + +while True: + time.sleep(1)