rushabhcodes/desk-fidget-counter

A desk knob assembly combining a circuit board with PETG-printed mechanical parts and vendor CAD-modeled hardware.

Version
5.6.1
License
MIT
Stars
0

firmware/counter.c

// SPDX-License-Identifier: MIT
#include "counter.h"
#include <limits.h>
#include <string.h>
void counter_init(Counter *c, uint64_t saved) {
  memset(c, 0, sizeof(*c));
  c->turns = saved;
}
bool counter_sample(Counter *c, uint16_t raw, bool valid, uint32_t ms,
                    bool enabled) {
  if (enabled != c->scrolling) {
    c->pending = 0;
    c->scroll_fraction = 0;
    c->scrolling = enabled;
  }
  if (!valid) {
    c->baseline = false;
    c->progress = 0;
    c->pending = 0;
    c->scroll_fraction = 0;
    c->rejected++;
    return false;
  }
  if (!c->baseline || (uint32_t)(ms - c->previous_ms) > 20) {
    c->previous = raw;
    c->previous_ms = ms;
    c->baseline = true;
    c->progress = 0;
    c->pending = 0;
    c->scroll_fraction = 0;
    return false;
  }
  int d = (int)raw - c->previous;
  c->previous = raw;
  c->previous_ms = ms;
  if (d > 32767)
    d -= 65536;
  else if (d < -32768)
    d += 65536;
  if (d > 48 || d < -48) {
    c->baseline = false;
    c->progress = 0;
    c->pending = 0;
    c->scroll_fraction = 0;
    c->rejected++;
    return false;
  }
  c->progress += d;
  bool changed = false;
  if (c->progress >= COUNTER_EDGES_PER_TURN ||
      c->progress <= -COUNTER_EDGES_PER_TURN) {
    if (c->turns < UINT64_MAX)
      c->turns++;
    c->progress +=
        (c->progress > 0 ? -COUNTER_EDGES_PER_TURN : COUNTER_EDGES_PER_TURN);
    changed = true;
  }
  if (enabled) {
    c->scroll_fraction += d;
    int ticks = c->scroll_fraction / COUNTER_EDGES_PER_SCROLL;
    c->scroll_fraction -= ticks * COUNTER_EDGES_PER_SCROLL;
    c->pending += ticks;
    if (c->pending > 127)
      c->pending = 127;
    if (c->pending < -127)
      c->pending = -127;
  }
  return changed;
}
int8_t counter_report(Counter *c) {
  int8_t n = (int8_t)c->pending;
  c->pending = 0;
  return n;
}
uint32_t record_crc(const uint8_t *p, unsigned n) {
  uint32_t c = ~0u;
  while (n--) {
    c ^= *p++;
    for (int k = 0; k < 8; k++)
      c = (c >> 1) ^ ((0u - (c & 1u)) & 0xedb88320u);
  }
  return ~c;
}
static void put32(uint8_t *p, uint32_t n) {
  for (int i = 0; i < 4; i++)
    p[i] = (uint8_t)(n >> (8 * i));
}
static uint32_t get32(const uint8_t *p) {
  return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 |
         (uint32_t)p[3] << 24;
}
void record_encode(uint8_t p[32], uint32_t seq, uint64_t turns) {
  memset(p, 0, 32);
  memcpy(p, "DKA1", 4);
  put32(p + 4, seq);
  put32(p + 8, (uint32_t)turns);
  put32(p + 12, (uint32_t)(turns >> 32));
  put32(p + 24, record_crc(p, 24));
  put32(p + 28, 0xa55a3cc3u);
}
bool record_decode(const uint8_t p[32], uint32_t *s, uint64_t *t) {
  if (memcmp(p, "DKA1", 4) || get32(p + 28) != 0xa55a3cc3u ||
      record_crc(p, 24) != get32(p + 24))
    return false;
  *s = get32(p + 4);
  *t = get32(p + 8) | (uint64_t)get32(p + 12) << 32;
  return true;
}

void counter_format_total(uint64_t turns, char out[21]) {
  char reverse[20];
  unsigned count = 0;
  do {
    reverse[count++] = (char)('0' + turns % 10);
    turns /= 10;
  } while (turns);
  for (unsigned i = 0; i < count; ++i)
    out[i] = reverse[count - i - 1];
  out[count] = '\0';
}