X-Git-Url: https://git.cryptolib.org/?p=labortage2013badge.git;a=blobdiff_plain;f=firmware%2Fpercnt2.c;fp=firmware%2Fpercnt2.c;h=72769af6b0e2841e5c27e3dc6808c158dbc5c767;hp=0000000000000000000000000000000000000000;hb=10cef9c333ab2ece1ae499ace212c3df212a4bfc;hpb=2b9eb2b94bce002cac2301745f93dc81407d9d34 diff --git a/firmware/percnt2.c b/firmware/percnt2.c new file mode 100644 index 0000000..72769af --- /dev/null +++ b/firmware/percnt2.c @@ -0,0 +1,260 @@ +/* + * + * author: Daniel Otte + * email: daniel.otte@rub.de + * license: GPLv3 + * + */ + + +#include /* labs() */ +#include +#include +#include + +#ifndef PERCNT_NO + #define PERCNT_NO 1 +#endif + +#ifndef PERCNT_BPC /* bytes per counter */ + #define PERCNT_BPC 16 +#endif + +#define PERCNT_MBS ((PERCNT_BPC + 7) / 8) /* mask block size */ + +#ifndef PERCNT_CS + #define PERCNT_CS 4 /* counter size (max 4)*/ +#endif + +#define PERCNT_RESETONERROR + +#ifndef PERCNT_POLICY_INC + #ifndef PERCNT_POLICY_STAY + #define PERCNT_POLICY_INC +// #error You have to specify a counter policy either PERCNT_POLICY_STAY or PERCNT_POLICY_INC + #endif +#endif + +#ifdef PERCNT_POLICY_INC + #ifdef PERCNT_POLICY_STAY + #error You have to specify a counter policy either PERCNT_POLICY_STAY or PERCNT_POLICY_INC (not both) + #endif +#endif + +uint8_t percnt_count[PERCNT_NO][3][PERCNT_BPC] EEMEM; + +uint8_t percnt_mb[PERCNT_NO][3][PERCNT_MBS] EEMEM; + +typedef enum __attribute__((packed)) {counterA = 0, counterB = 1, counterC = 2} percnt_active_t; + +percnt_active_t percnt_active[PERCNT_NO]; + +#ifdef PERCNT_CACHE +uint32_t percnt_cache[PERCNT_NO]; +#endif + +/** + * this function resets the counter given in the parameter back to zero + * this is quite unsafe + */ +void percnt_reset(uint8_t counter) { + uint8_t i; + for (i = 0; i < PERCNT_BPC; ++i) { + eeprom_write_byte(&(percnt_count[counter][counterA][i]), 0); + } + eeprom_write_byte(&(percnt_count[counter][counterB][0]), 1); + for (i = 1; i < PERCNT_BPC; ++i) { + eeprom_write_byte(&(percnt_count[counter][counterB][i]), 0); + } + eeprom_write_byte(&(percnt_count[counter][counterC][0]), 2); + for (i = 1; i < PERCNT_BPC; ++i) { + eeprom_write_byte(&(percnt_count[counter][counterC][i]), 0); + } + for (i = 0; i < PERCNT_MBS; ++i) { + eeprom_write_byte(&(percnt_mb[counter][counterA][i]), 0); + } + for (i = 0; i < PERCNT_MBS; ++i) { + eeprom_write_byte(&(percnt_mb[counter][counterB][i]), 0); + } + for (i = 0; i < PERCNT_MBS; ++i) { + eeprom_write_byte(&(percnt_mb[counter][counterC][i]), 0); + } + percnt_active[counter] = counterC; +} + + +static const uint8_t bitcnt_lut_P[16] PROGMEM = + { 0, 1, 1, 2, /* 0..3 */ + 1, 2, 2, 3, /* 4..7 */ + 1, 2, 2, 3, /* 8..B */ + 2, 3, 3, 4} ; /* C..F */ + + +static +uint8_t bitcnt(const void* a, uint8_t length){ + uint8_t ret = 0; + while (length--) { + ret += pgm_read_byte(&bitcnt_lut_P[(*((uint8_t*)a)) >> 4]); + ret += pgm_read_byte(&bitcnt_lut_P[(*((uint8_t*)a)) & 0x0f]); + } + return ret; +} + +/** + * returns 0 if everything went right, 1 or even 2 in the case of failure + */ +static +uint8_t percnt_writecntx(uint32_t v, uint8_t counter, percnt_active_t subc){ + uint8_t maskb[PERCNT_MBS]; + uint8_t free; + uint8_t i, j = 0, t; + eeprom_read_block(maskb, &(percnt_mb[counter][subc][0]), PERCNT_MBS); + free = PERCNT_BPC - bitcnt(maskb, PERCNT_MBS); + + for (i = 0; i < PERCNT_CS; ++i) { + if (free < PERCNT_CS) { + /* we don't have enough bytes left, so we can't count anymore :-( */ + return 1; + } + /* get next usable byte */ + while ((maskb[j / 8] >> (j % 8)) & 1) + ++j; + t = eeprom_read_byte(&(percnt_count[counter][subc][j])); + if(t != ((uint8_t*)&v)[i]){ + /* we have to do a write */ + eeprom_write_byte(&(percnt_count[counter][subc][j]), ((uint8_t*)&v)[i]); + /* and check back */ + t = eeprom_read_byte(&(percnt_count[counter][subc][j])); + if(t != ((uint8_t*)&v)[i]){ + /* thats not good, readback failed */ + /* mark byte as bad */ + maskb[j / 8] |= 1 << (j % 8); + eeprom_write_byte(&(percnt_mb[counter][subc][j / 8]), maskb[j / 8]); + /* check back the maskblock write*/ + t = eeprom_read_byte(&(percnt_mb[counter][subc][j / 8])); + if(t != maskb[j / 8]){ + /* uargghh! that should not happen, our bad byte table has a bad byte*/ + return 2; + } + --i; /* this makes this byte gets another try */ + } + } + ++j; + } + return 0; +} + +/******************************************************************************/ + +static +uint32_t percnt_readcntx(uint8_t counter, percnt_active_t subc){ + uint32_t ret = 0; + uint8_t maskb[PERCNT_MBS]; + uint8_t i, j = 0; + eeprom_read_block(maskb, &(percnt_mb[counter][subc][0]), PERCNT_MBS); + for (i = 0; i < PERCNT_CS; ++i) { + while (((maskb[j / 8]) >> (j % 8)) & 1) + ++j; + ((uint8_t*)&ret)[i] = eeprom_read_byte(&(percnt_count[counter][subc][j])); + ++j; + } + return ret; +} + +/******************************************************************************/ + +uint32_t percnt_get(uint8_t counter) { + return percnt_readcntx(counter, percnt_active[counter]) - 2; +} + +/******************************************************************************/ + +uint8_t percnt_inc(uint8_t counter) { + uint32_t t; + t = percnt_get(counter); + percnt_active[counter] += 1; + if (percnt_active[counter] == 3) + percnt_active[counter] = 0; + return percnt_writecntx(t + 1 + 2, counter, percnt_active[counter]); /* remember, _get subtracts two */ +} + +/******************************************************************************/ + +uint8_t percnt_init(uint8_t counter){ + uint32_t a,b,c; + uint32_t dab, dac, dbc; + a = percnt_readcntx(counter, counterA); + b = percnt_readcntx(counter, counterB); + c = percnt_readcntx(counter, counterC); + dab = labs(a - b); + dac = labs(a - c); + dbc = labs(b - c); + if (dab == 1 && dbc == 1 && dac == 2) { + percnt_active[counter] = counterC; + return 0; + } + if(dab == 1 && dbc == 2 && dac == 1) { + percnt_active[counter] = counterB; + return 0; + } + if(dab == 2 && dbc == 1 && dac == 1){ + percnt_active[counter] = counterA; + return 0; + } + + /* here it gets intresting */ + if(dab == 1 || dac == 1 || dbc == 1){ + /* we might got interrupted while incrementing */ + /* action depends on policy either finish the increment or not */ + #ifdef PERCNT_POLICY_STAY + if(dab == 1){ + percnt_active[counter]=(a < b) ? counterB : counterA; + c = (a < b) ? (a - 1) : (b - 1); + return percnt_writecntx(c, counter, counterC); + } + if(dac == 1){ + percnt_active[counter]=(a