diff --git a/firmware/applications/mesh/mesh.c b/firmware/applications/mesh/mesh.c index dccfd6d..c1f2f1c 100644 --- a/firmware/applications/mesh/mesh.c +++ b/firmware/applications/mesh/mesh.c @@ -10,39 +10,12 @@ #include "funk/nrf24l01p.h" +#include "funk/mesh.h" + #include -#define MESH_CHANNEL 85 -#define MESH_MAC "MESHB" - /**************************************************************************/ -uint32_t const meshkey[4] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000 -}; - -#define MESHBUFSIZE 10 -#define MESHPKTSIZE 32 -typedef struct { - uint8_t pkt[32]; - char flags; -} MPKT; - -MPKT meshbuffer[MESHBUFSIZE]; - -#define MF_FREE (0) -#define MF_USED (1<<0) - -time_t _timet=0; - -// Timezones suck. Currently we only do it all in localtime. -// I know it's broken. Sorry -time_t getSeconds(void){ - return _timet+(getTimer()*SYSTICKSPEED/1000); -}; - -// ********************************************************************** - void m_init(void){ nrf_init(); @@ -56,169 +29,16 @@ void m_init(void){ nrf_config_set(&config); - for(int i=0;itm_sec = dayclock % 60; - timep->tm_min = (dayclock % 3600) / 60; - timep->tm_hour = dayclock / 3600; - timep->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */ - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - timep->tm_year = year - YEAR0; - timep->tm_yday = dayno; - timep->tm_mon = 0; - while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) { - dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon]; - timep->tm_mon++; - } - timep->tm_mday = dayno + 1; - timep->tm_isdst = 0; - - return timep; -} - -#define M_SENDINT 500 -#define M_RECVINT 1000 -#define M_RECVTIM 100 - - -void m_recv(void){ - __attribute__ ((aligned (4))) uint8_t buf[32]; - int len; - int recvend=M_RECVTIM/SYSTICKSPEED+getTimer(); - - static int toggle=0; - gpioSetValue (RB_LED2, toggle); - toggle=1-toggle; - - m_cleanup(); - - nrf_rcv_pkt_start(); - do{ - len=nrf_rcv_pkt_poll_dec(sizeof(buf),buf,meshkey); - - // Receive - if(len<=0){ - delayms_power(10); - continue; - }; - - int i; - for(i=0;i_timet) // Do not live in the past. - _timet = toff; - }else if (buf[0]>='A' && buf[0] <'T'){ // Truncate ascii packets. - meshbuffer[i].pkt[MESHPKTSIZE-3]=0; - }; - }while(getTimer()tm_year+YEAR0); lcdNl(); + + lcdNl(); + lcdPrint("<"); + + for(int i=0;i"); + + lcdPrint("Gen:"); + lcdPrintInt(meshgen); + lcdNl(); lcdRefresh(); delayms_queue(50); }while ((getInputRaw())==BTN_NONE); }; + + +inline void blink(char a, char b){ + gpioSetValue (a,b, 1-gpioGetValue(a,b)); +}; + + +int choose(char * texts, int8_t menuselection){ + uint8_t numentries = 0; + uint8_t visible_lines = 0; + uint8_t current_offset = 0; + + char*p=texts; + + do{ + lcdPrintln(p); + while(*p)p++; + numentries++;p++; + }while(*p); + numentries--; + + visible_lines = (RESY/font->u8Height)-1; // subtract title line + + while (1) { + // Display current menu page + lcdClear(); + lcdPrintln(texts); + p=texts; + while(*p++); + for(int i=0;i (current_offset + visible_lines-1) || menuselection >= numentries) { + if (menuselection >= numentries) { + menuselection = 0; + current_offset = 0; + } else { + current_offset += visible_lines; + } + } + break; + case BTN_LEFT: + return -1; + case BTN_RIGHT: + case BTN_ENTER: + return menuselection; + } + getInputWaitRelease(); + } + /* NOTREACHED */ +} + + + +/***********************************************************************/ + +char *meshmsgs(void){ + static char msgtypes[MESHBUFSIZE+1]; + memset(msgtypes,'_',MESHBUFSIZE); + msgtypes[MESHBUFSIZE]=0; + uint8_t lo=0; + uint8_t hi; + + for(int o=0;olo) + if(MO_TYPE(meshbuffer[i].pkt)tm_hour); + lcdPrint(":"); + lcdPrintInt(tm->tm_min); + lcdPrint(":"); + lcdPrintInt(tm->tm_sec); + lcdNl(); + char *foo=(char *)MO_BODY(meshbuffer[j].pkt); + while(strlen(foo)>13){ + int q; + for(q=0;q<13;q++){ + if(foo[q]==' ') + break; + }; + foo[q]=0; + lcdPrintln(foo); + foo[q]=' '; + foo+=q+1; + }; + lcdPrintln(foo); + lcdRefresh(); + getInputWaitRelease(); + }; +}; + + +void tick_mesh(void){ + mesh_systick(); +}; + diff --git a/firmware/basic/Makefile b/firmware/basic/Makefile index 5f772fd..ec760dc 100644 --- a/firmware/basic/Makefile +++ b/firmware/basic/Makefile @@ -21,6 +21,7 @@ OBJS += idle.o OBJS += config.o OBJS += itoa.o OBJS += stringin.o +OBJS += simpletime.o LIBNAME=basic diff --git a/firmware/basic/basic.h b/firmware/basic/basic.h index ec82179..185c9ed 100644 --- a/firmware/basic/basic.h +++ b/firmware/basic/basic.h @@ -208,4 +208,8 @@ int applyConfig(void); // itoa.c const char* IntToStrX(unsigned int num, unsigned int mxlen); +// simpletime.c + +#include "basic/simpletime.h" + #endif diff --git a/firmware/basic/simpletime.c b/firmware/basic/simpletime.c new file mode 100644 index 0000000..a43d683 --- /dev/null +++ b/firmware/basic/simpletime.c @@ -0,0 +1,46 @@ +#include +#include "simpletime.h" +#include "basic/basic.h" + +time_t _timet=0; + +int _ytab[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +struct tm * mygmtime(register const time_t time) { + static struct tm br_time; + register struct tm *timep = &br_time; + register unsigned long dayclock, dayno; + int year = EPOCH_YR; + + dayclock = (unsigned long)time % SECS_DAY; + dayno = (unsigned long)time / SECS_DAY; + + timep->tm_sec = dayclock % 60; + timep->tm_min = (dayclock % 3600) / 60; + timep->tm_hour = dayclock / 3600; + timep->tm_wday = (dayno + 4) % 7; /* day 0 was a thursday */ + while (dayno >= YEARSIZE(year)) { + dayno -= YEARSIZE(year); + year++; + } + timep->tm_year = year - YEAR0; + timep->tm_yday = dayno; + timep->tm_mon = 0; + while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) { + dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon]; + timep->tm_mon++; + } + timep->tm_mday = dayno + 1; + timep->tm_isdst = 0; + + return timep; +} + +// Timezones suck. Currently we only do it all in localtime. +// I know it's broken. Sorry +time_t getSeconds(void){ + return _timet+(getTimer()*SYSTICKSPEED/1000); +}; diff --git a/firmware/basic/simpletime.h b/firmware/basic/simpletime.h new file mode 100644 index 0000000..7efafe5 --- /dev/null +++ b/firmware/basic/simpletime.h @@ -0,0 +1,16 @@ +#ifndef __SIMPLETIME_H_ +#define __SIMPLETIME_H_ + +#include + +#define YEAR0 1900 /* the first year */ +#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */ +#define SECS_DAY (24L * 60L * 60L) +#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) +#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) + +extern time_t _timet; +struct tm * mygmtime(register const time_t time); +time_t getSeconds(void); + +#endif diff --git a/firmware/funk/Makefile b/firmware/funk/Makefile index 77e9a83..b8bd41f 100644 --- a/firmware/funk/Makefile +++ b/firmware/funk/Makefile @@ -8,6 +8,7 @@ OBJS += nrf24l01p.o OBJS += rftransfer.o OBJS += filetransfer.o OBJS += openbeacon.o +OBJS += mesh.o LIBNAME=funk diff --git a/firmware/funk/mesh.c b/firmware/funk/mesh.c new file mode 100644 index 0000000..e0f869f --- /dev/null +++ b/firmware/funk/mesh.c @@ -0,0 +1,163 @@ +#include +#include +#include "basic/basic.h" +#include "funk/mesh.h" +#include "funk/nrf24l01p.h" +#include "basic/byteorder.h" +#include "basic/random.h" + +char meshgen=0; // Generation +MPKT meshbuffer[MESHBUFSIZE]; + +uint32_t const meshkey[4] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +struct NRF_CFG oldconfig; + +void initMesh(void){ + for(int i=0;iSECS_DAY) + meshbuffer[i].flags=MF_FREE; + }; + }; +}; + +void mesh_recvloop(void){ + __attribute__ ((aligned (4))) uint8_t buf[32]; + int len; + int recvend=M_RECVTIM/SYSTICKSPEED+getTimer(); + int pktctr=0; + + nrf_config_get(&oldconfig); + + nrf_set_channel(MESH_CHANNEL); + nrf_set_rx_mac(0,MESHPKTSIZE,strlen(MESH_MAC),(uint8_t*)MESH_MAC); + + mesh_cleanup(); + + nrf_rcv_pkt_start(); + do{ + len=nrf_rcv_pkt_poll_dec(sizeof(buf),buf,meshkey); + + // Receive + if(len<=0){ + delayms_power(10); + continue; + }; + pktctr++; + + if(MO_GEN(buf)>meshgen){ + meshgen++; + _timet=0; + continue; + }; + + if(MO_TYPE(buf)=='T'){ + time_t toff=MO_TIME(buf)-(getTimer()*SYSTICKSPEED/1000); + if (toff>_timet) // Do not live in the past. + _timet = toff; + continue; + }; + + // Safety: Truncate ascii packets by 0-ing the CRC + if (MO_TYPE(buf) >='A' && MO_TYPE(buf) <='Z'){ + buf[MESHPKTSIZE-2]=0; + }; + + // Store packet in a free slot + int free=-1; + for(int i=0;i + MO_TIME(meshbuffer[i].pkt)){ + free=i; + break; + }else{ + free=-2; + break; + }; + }; + }; + + if(free==-1){ // Buffer full. Ah well. Kill a random packet + free=1; // XXX: GetRandom()? + }; + + if(free<0) + continue; + + memcpy(meshbuffer[free].pkt,buf,MESHPKTSIZE); + meshbuffer[free].flags=MF_USED; + + }while(getTimer()MESHBUFSIZE); + + nrf_rcv_pkt_end(); + nrf_config_set(&oldconfig); +} + +void mesh_sendloop(void){ + int ctr=0; + __attribute__ ((aligned (4))) uint8_t buf[32]; + int status; + + nrf_config_get(&oldconfig); + nrf_set_channel(MESH_CHANNEL); + nrf_set_tx_mac(strlen(MESH_MAC),(uint8_t*)MESH_MAC); + + // Update [T]ime packet + MO_TIME_set(meshbuffer[0].pkt,getSeconds()); + MO_GEN_set(meshbuffer[0].pkt,meshgen); + + for (int i=0;i