#include <vectrex.h>
#include "controller.h"

#define true (0==0)
#define false (0!=0)

static inline void set_scale(unsigned int s) {
  VIA_t1_cnt_lo = s;
}

static void sprintl(char *dest, long num) { // left-aligned
#define show_digit(x) *dest++ = (char)((x)+'0')
  int digit, zeroes;

  // This replaces code that used divide by 10 and modulo 10.  Much faster.

  // handles full 16 bit range of -32768:32767  -  Uses negative numbers to avoid the issue of negating -32768

  if (num >= 0) num = -num; else *dest++ = '-';
  digit = 0;
  zeroes = 1; // CLRing is shorter
  // max 11 add/subtracts...
  if (num <= -20000) { num += 20000; digit += 2; zeroes = 0; }
  if (num <= -10000) { num += 10000; digit += 1; zeroes = 0; }
  if (!zeroes) show_digit(digit);
  digit = 0;
  if (num <= -8000) { num += 8000; digit += 8; zeroes = 0; } else if (num <= -4000) { num += 4000; digit += 4; zeroes = 0; }
  if (num <= -2000) { num += 2000; digit += 2; zeroes = 0; }
  if (num <= -1000) { num += 1000; digit += 1; zeroes = 0; }
  if (!zeroes) show_digit(digit);
  digit = 0;
  if (num <= -800) { num += 800; digit += 8; zeroes = 0; } else if (num <= -400) { num += 400; digit += 4; zeroes = 0; }
  if (num <= -200) { num += 200; digit += 2; zeroes = 0; }
  if (num <= -100) { num += 100; digit += 1; zeroes = 0; }
  if (!zeroes) show_digit(digit);
  digit = 0;
  if (num <= -80) { num += 80; digit += 8; zeroes = 0; } else if (num <= -40) { num += 40; digit += 4; zeroes = 0; }
  if (num <= -20) { num += 20; digit += 2; zeroes = 0; }
  if (num <= -10) { num += 10; digit += 1; zeroes = 0; }
  if (!zeroes) show_digit(digit);
  show_digit((int)-num);
  show_digit(0x80-'0');
  show_digit(0-'0');
  //*dest = 0x80;
}

#define high ((these_buttons & 16) == 0)
#define low  ((these_buttons & 16) != 0)
#define BIT_TIMEOUT 70U

unsigned int these_buttons = 0;

int falling(void) {
  unsigned int timeout = BIT_TIMEOUT;
  // it's high
  do {
    Read_Btns (); these_buttons = buttons_held();
    timeout -= 1U;
    if (timeout == 0U) return false;
  } while high;
  // it's low now
  return true;
}

int rising(void) {
  unsigned int timeout = BIT_TIMEOUT;
  // it's low
  do {
    Read_Btns (); these_buttons = buttons_held();
    timeout -= 1U;
    if (timeout == 0U) return false;
  } while low;
  // it's high now
  return true;
}

int main(void) {
  static char Text[85];
  static char Num[11];
  unsigned int textp = 2;
  unsigned int key = 0;

  Text[0] = Text[1] = ' '; Text[2] = 0x80; Text[3] = '\0';
  Num[0] = '0'; Num[1] = Num[2] = ' '; Num[3] = 0x80; Num[4] = '\0';
  enable_controller_1_x();
  enable_controller_1_y();

  // buttons to press in order to enter a character by hand, to check algorithm!

  //        \ \ \ \ \ \ \ 1
  //         \ \ \ \ 1 3 6 2
  //          1 2 4 8 6 2 4 8
  //  data W:  1 0 0 0 0 0 1 0
  // clock Q:   1 0 1 0 1 0 1 0 

  // Although an earlier version of the code did get an occasional corrupted
  // lower bit - this version gets the character correct every time ... however
  // it does sometimes miss characters - probably due to the inclusion of the
  // timeout code.  Up to the application developer whether he wants to retain that.
  for (;;) {
    Wait_Recal();
    Joy_Analog ();
    Intensity_7F ();
    Reset0Ref (); 
    set_scale(127);
    Moveto_d(0,0);
    Print_Str_d(-4, -120, Text);
    Print_Str_d(-32, -4, Num);

    // When the strobe is asserted ((these_buttons & 16) != 0) the data bit is
    // already in place, as the data bit is always written first and then the strobe.

    // default quiescent state is low.
    Read_Btns (); these_buttons = buttons_held(); // start bit *not* in a loop so that
                                                  // screen doesn't blank...
    if (high) { // Rising edge - bit 0
      // Extra 'start' bit to solve noise issue. (first bit was sometimes wrong)
                                                  // Wait for start-bit clock
      if (!falling()) continue;
      key = 0;                                    // Wait for next trigger = falling edge - bit 1
      if (!rising()) continue;
      key |= ((these_buttons&32U) ? 1U : 0);      // Wait for next trigger = rising edge - bit 2
      if (!falling()) continue;
      key |= ((these_buttons&32U) ? 2U : 0);      // Wait for next trigger = falling edge - bit 3
      if (!rising()) continue;
      key |= ((these_buttons&32U) ? 4U : 0);      // Wait for next trigger = rising edge - bit 4
      if (!falling()) continue;
      key |= ((these_buttons&32U) ? 8U : 0);      // Wait for next trigger = falling edge - bit 5
      if (!rising()) continue;
      key |= ((these_buttons&32U) ? 16U : 0);      // Wait for next trigger = rising edge - bit 6
      if (!falling()) continue;
      key |= ((these_buttons&32U) ? 32U : 0);      // Wait for next trigger = falling edge - bit 7
      if (!rising()) continue;
      key |= ((these_buttons&32U) ? 64U : 0);
      if (!falling()) continue;
      key |= ((these_buttons&32U) ? 128U : 0);
      //if (!rising()) continue;
      // swallow stop bit.  Back to quiescent 'low' state between characters.

      // first two places in Text are spaces.
      if (key >= 'a' && key <= 'z') { key = key - 'a' + 'A'; }
      if (key == 10 || key == 13) {
        textp = 2;
      } else if ((key == 127 || key == 8) && (textp > 2)) {
        textp -= 1;
      } else {
        if (textp == 80) textp = 2;
        Text[textp++] = key; 
      }
      Text[textp] = 0x80; Text[textp+1] = '\0';
      sprintl(Num, (long)key);
    }
  }

  return 0;
}