4 * email: daniel.otte@rub.de
10 #include <stdlib.h> /* labs() */
12 #include <avr/eeprom.h>
13 #include <avr/pgmspace.h>
19 #ifndef PERCNT_BPC /* bytes per counter */
23 #define PERCNT_MBS ((PERCNT_BPC + 7) / 8) /* mask block size */
26 #define PERCNT_CS 4 /* counter size (max 4)*/
29 #define PERCNT_RESETONERROR
31 #ifndef PERCNT_POLICY_INC
32 #ifndef PERCNT_POLICY_STAY
33 #define PERCNT_POLICY_INC
34 // #error You have to specify a counter policy either PERCNT_POLICY_STAY or PERCNT_POLICY_INC
38 #ifdef PERCNT_POLICY_INC
39 #ifdef PERCNT_POLICY_STAY
40 #error You have to specify a counter policy either PERCNT_POLICY_STAY or PERCNT_POLICY_INC (not both)
44 uint8_t percnt_count[PERCNT_NO][3][PERCNT_BPC] EEMEM;
46 uint8_t percnt_mb[PERCNT_NO][3][PERCNT_MBS] EEMEM;
48 typedef enum __attribute__((packed)) {counterA = 0, counterB = 1, counterC = 2} percnt_active_t;
50 percnt_active_t percnt_active[PERCNT_NO];
53 uint32_t percnt_cache[PERCNT_NO];
57 * this function resets the counter given in the parameter back to zero
58 * this is quite unsafe
60 void percnt_reset(uint8_t counter) {
62 for (i = 0; i < PERCNT_BPC; ++i) {
63 eeprom_write_byte(&(percnt_count[counter][counterA][i]), 0);
65 eeprom_write_byte(&(percnt_count[counter][counterB][0]), 1);
66 for (i = 1; i < PERCNT_BPC; ++i) {
67 eeprom_write_byte(&(percnt_count[counter][counterB][i]), 0);
69 eeprom_write_byte(&(percnt_count[counter][counterC][0]), 2);
70 for (i = 1; i < PERCNT_BPC; ++i) {
71 eeprom_write_byte(&(percnt_count[counter][counterC][i]), 0);
73 for (i = 0; i < PERCNT_MBS; ++i) {
74 eeprom_write_byte(&(percnt_mb[counter][counterA][i]), 0);
76 for (i = 0; i < PERCNT_MBS; ++i) {
77 eeprom_write_byte(&(percnt_mb[counter][counterB][i]), 0);
79 for (i = 0; i < PERCNT_MBS; ++i) {
80 eeprom_write_byte(&(percnt_mb[counter][counterC][i]), 0);
82 percnt_active[counter] = counterC;
86 static const uint8_t bitcnt_lut_P[16] PROGMEM =
87 { 0, 1, 1, 2, /* 0..3 */
88 1, 2, 2, 3, /* 4..7 */
89 1, 2, 2, 3, /* 8..B */
90 2, 3, 3, 4} ; /* C..F */
94 uint8_t bitcnt(const void* a, uint8_t length){
97 ret += pgm_read_byte(&bitcnt_lut_P[(*((uint8_t*)a)) >> 4]);
98 ret += pgm_read_byte(&bitcnt_lut_P[(*((uint8_t*)a)) & 0x0f]);
104 * returns 0 if everything went right, 1 or even 2 in the case of failure
107 uint8_t percnt_writecntx(uint32_t v, uint8_t counter, percnt_active_t subc){
108 uint8_t maskb[PERCNT_MBS];
111 eeprom_read_block(maskb, &(percnt_mb[counter][subc][0]), PERCNT_MBS);
112 free = PERCNT_BPC - bitcnt(maskb, PERCNT_MBS);
114 for (i = 0; i < PERCNT_CS; ++i) {
115 if (free < PERCNT_CS) {
116 /* we don't have enough bytes left, so we can't count anymore :-( */
119 /* get next usable byte */
120 while ((maskb[j / 8] >> (j % 8)) & 1)
122 t = eeprom_read_byte(&(percnt_count[counter][subc][j]));
123 if(t != ((uint8_t*)&v)[i]){
124 /* we have to do a write */
125 eeprom_write_byte(&(percnt_count[counter][subc][j]), ((uint8_t*)&v)[i]);
127 t = eeprom_read_byte(&(percnt_count[counter][subc][j]));
128 if(t != ((uint8_t*)&v)[i]){
129 /* thats not good, readback failed */
130 /* mark byte as bad */
131 maskb[j / 8] |= 1 << (j % 8);
132 eeprom_write_byte(&(percnt_mb[counter][subc][j / 8]), maskb[j / 8]);
133 /* check back the maskblock write*/
134 t = eeprom_read_byte(&(percnt_mb[counter][subc][j / 8]));
135 if(t != maskb[j / 8]){
136 /* uargghh! that should not happen, our bad byte table has a bad byte*/
139 --i; /* this makes this byte gets another try */
147 /******************************************************************************/
150 uint32_t percnt_readcntx(uint8_t counter, percnt_active_t subc){
152 uint8_t maskb[PERCNT_MBS];
154 eeprom_read_block(maskb, &(percnt_mb[counter][subc][0]), PERCNT_MBS);
155 for (i = 0; i < PERCNT_CS; ++i) {
156 while (((maskb[j / 8]) >> (j % 8)) & 1)
158 ((uint8_t*)&ret)[i] = eeprom_read_byte(&(percnt_count[counter][subc][j]));
164 /******************************************************************************/
166 uint32_t percnt_get(uint8_t counter) {
167 return percnt_readcntx(counter, percnt_active[counter]) - 2;
170 /******************************************************************************/
172 uint8_t percnt_inc(uint8_t counter) {
174 t = percnt_get(counter);
175 percnt_active[counter] += 1;
176 if (percnt_active[counter] == 3)
177 percnt_active[counter] = 0;
178 return percnt_writecntx(t + 1 + 2, counter, percnt_active[counter]); /* remember, _get subtracts two */
181 /******************************************************************************/
183 uint8_t percnt_init(uint8_t counter){
185 uint32_t dab, dac, dbc;
186 a = percnt_readcntx(counter, counterA);
187 b = percnt_readcntx(counter, counterB);
188 c = percnt_readcntx(counter, counterC);
192 if (dab == 1 && dbc == 1 && dac == 2) {
193 percnt_active[counter] = counterC;
196 if(dab == 1 && dbc == 2 && dac == 1) {
197 percnt_active[counter] = counterB;
200 if(dab == 2 && dbc == 1 && dac == 1){
201 percnt_active[counter] = counterA;
205 /* here it gets intresting */
206 if(dab == 1 || dac == 1 || dbc == 1){
207 /* we might got interrupted while incrementing */
208 /* action depends on policy either finish the increment or not */
209 #ifdef PERCNT_POLICY_STAY
211 percnt_active[counter]=(a < b) ? counterB : counterA;
212 c = (a < b) ? (a - 1) : (b - 1);
213 return percnt_writecntx(c, counter, counterC);
216 percnt_active[counter]=(a<c)?counterC:counterA;
217 b = (a < c) ? (a - 1) : (c - 1);
218 return percnt_writecntx(b, counter, counterB);
221 percnt_active[counter]=(b<c)?counterC:counterB;
222 a = (b < c) ? (b - 1) : (c - 1);
223 return percnt_writecntx(a, counter, counterA);
226 #ifdef PERCNT_POLICY_INC
228 percnt_active[counter] = counterC;
229 c = (a < b) ? (a - 1) : (b - 1);
230 return percnt_writecntx(c + 1, counter, counterC);
233 percnt_active[counter] = counterB;
234 b = (a < c) ? (a - 1) : (c - 1);
235 return percnt_writecntx(b + 1, counter, counterB);
238 percnt_active[counter] = counterA;
239 a = (b < c) ? (b - 1) : (c - 1);
240 return percnt_writecntx(a + 1, counter, counterA);
244 /* something really strange happened */
245 /* may be we have to initialize or so, but we must make sure that no one evil drives us here */
246 #ifdef PERCNT_RESETONERROR
247 percnt_reset(counter);
253 /* we won't get here, but to keep the compile quiet: */