astra/iphone-encoder-counter
A CR2450-powered MSP430 FRAM counter combines an always-on dual-channel TMR rotation sensor, pushbutton input, and ST25DV NFC tag with an integrated tuned printed antenna and I²C/GPIO interface.
- Version
- 1.0.3
- License
- unset
- Stars
- 0
firmware/test_counter.c
#include "counter.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
static void walk(counter_t *c,const uint8_t *p,size_t n){for(size_t i=0;i<n;i++)counter_step(c,p[i]);}
int main(void){
counter_t c,r;uint32_t seq;uint8_t a[JOURNAL_BYTES],b[JOURNAL_BYTES],candidate[JOURNAL_BYTES];
const uint8_t forward[]={2,0,1,3},reverse[]={1,0,2,3};
counter_init(&c,3);walk(&c,forward,4);assert(c.ccw==1&&c.cw==0&&c.pending==0);
walk(&c,reverse,4);assert(c.cw==1&&c.ccw==1);
for(int i=0;i<10000;i++){counter_step(&c,2);counter_step(&c,3);}
assert(c.cw==1&&c.ccw==1&&c.pending==0); /* boundary chatter */
const uint8_t partial[]={2,0,2,3};walk(&c,partial,4);assert(c.cw==1&&c.ccw==1);
counter_step(&c,0);assert(c.invalid_transitions==1&&c.pending==0); /* two-bit skip */
counter_rebase(&c,3);assert(c.cw==1&&c.ccw==1&&c.pending==0);
for(int i=0;i<100000;i++)walk(&c,forward,4);assert(c.ccw==100001);
button_t btn;button_init(&btn,false,0);
assert(!button_update(&btn,&c,true,1));
assert(!button_update(&btn,&c,false,5));
assert(!button_update(&btn,&c,true,8));
assert(!button_update(&btn,&c,true,27));
assert(button_update(&btn,&c,true,28)&&c.presses==1);
assert(!button_update(&btn,&c,true,100000)&&c.presses==1);
button_update(&btn,&c,false,100001);button_update(&btn,&c,false,100021);
button_update(&btn,&c,true,100022);assert(button_update(&btn,&c,true,100042)&&c.presses==2);
button_init(&btn,true,0);assert(!button_update(&btn,&c,true,100)&&c.presses==2);
button_update(&btn,&c,false,101);button_update(&btn,&c,false,121);
button_update(&btn,&c,true,UINT32_MAX-10);assert(button_update(&btn,&c,true,9)&&c.presses==3);
journal_encode(a,&c,42);assert(journal_decode(a,&r,&seq)&&seq==42&&r.ccw==c.ccw&&r.presses==3);
c.ccw++;journal_encode(candidate,&c,43);
/* Interrupt inactive-slot update after every possible payload prefix. */
for(size_t cut=0;cut<=46;cut++){
memcpy(b,a,JOURNAL_BYTES);b[46]=b[47]=0;memcpy(b,candidate,cut);
assert(journal_restore(a,b,&r,&seq)==0&&seq==42);
}
memcpy(b,candidate,JOURNAL_BYTES);assert(journal_restore(a,b,&r,&seq)==1&&seq==43&&r.ccw==c.ccw);
for(size_t bit=0;bit<JOURNAL_BYTES*8;bit++){memcpy(b,candidate,JOURNAL_BYTES);b[bit/8]^=1u<<(bit%8);assert(!journal_decode(b,&r,&seq));}
journal_encode(a,&c,UINT32_MAX);journal_encode(b,&c,0);assert(journal_restore(a,b,&r,&seq)==1&&seq==0);
memset(a,0,JOURNAL_BYTES);memset(b,0,JOURNAL_BYTES);assert(journal_restore(a,b,&r,&seq)==-1);
counter_init(&c,3);c.ccw=UINT64_MAX;walk(&c,forward,4);assert(c.ccw==UINT64_MAX);
c.cw=1;assert(counter_total_twists(&c)==UINT64_MAX);
c.presses=UINT64_MAX;button_init(&btn,false,0);button_update(&btn,&c,true,1);
assert(button_update(&btn,&c,true,21)&&c.presses==UINT64_MAX);
puts("PASS: button bounce, hold, boot-held, time wrap, button saturation, persistence; directions, reversals, chatter, skipped states, 100000 rotations, saturation, journal corruption, torn writes, sequence wrap.");
}