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.");
}