/*
  reads out a lcd display
  based on:
  https://lowpowerlab.com/forum/projects/moteino-kitchen-scale/

  An Arduino Pro Micro was used first as a simple logic analyser,
  to find the common pins and the segment pins. See the other sketch.
  Later the same arduino was put with this sketch inside the scale to provide
  serial output via usb.
  
  This paricular display is part of a transtek kitchen scale
  (pcb label: tsk759)

  The connector in numbered like this

      ----top border of the board----

    0   2   4   6   8   10   12   14
      1   3   5   7   9   11   13   15

  Pins 0 to 3 are the common pins, but since they are phase shifted by 90° only one
  is needed.

  Only Pins 8 to 15 carry useful information. All others are ignored.
  
*/

byte samples[2][56];

// lcd mapping
int seg1[2] = { PINB2, PINB6 };
int seg2[2] = { PINB4, PINB3 };
int seg3[2] = { PINB2, PINB6 };
int seg4[2] = { PINB2, PINB6 };

void setup() {
  Serial.begin(115200);
}

void loop() {
 get_samples();  // reads out the registers
 if (Serial.read() > 0) {
  int pulse = get_pulse();
  //print_segments(pulse);
  print_4digit(pulse);
  print_3digit(pulse);
  print_digit(pulse, seg2);
  print_digit(pulse, seg1); 
  Serial.println();
 }
}

void get_samples() {
  int f=0;
  while (f<56) {
    samples[0][f] = PINB;
    samples[1][f] = PIND;
    delayMicroseconds(333);  // = 1/3 ms. three samples in 1ms, which is the approximate pulse width.
    f++;
  }
}

// try to find the position, where the control signal triggers
// looking for a sequence of more than four ones seams sufficient
int get_pulse() {
  int n = 0; 
  int f = 0;
  while (f<30) {
    if ((samples[1][f]& (1 << PIND3))) {
      n++;
      if (n>4) break; 
    }
    else n=0;
    f++; 
  }
  return f - 3;  // sets the index in the first 1ms of the trigger event
}

void print_digit(int start, int seg[]) {
  byte digit = InterpretSevenSegmentSet(
          samples[0][start + 18]&(1<<seg[0]), // A or D
          samples[0][start + 6]&(1<<seg[1]), // B     
          samples[0][start + 12]&(1<<seg[1]), // C
          samples[0][start]&(1<<seg[1]),  // A or D
          samples[0][start + 12]&(1<<seg[0]), // E
          samples[0][start]&(1<<seg[0]), // F
          samples[0][start + 6]&(1<<seg[0]) // G
          );
  if (digit == 255) return;
  else Serial.print(digit, DEC);
}

void print_4digit(int start) {
 // print 4th digit
 // B1 is 8
 // D4 is 9
  byte digit = InterpretSevenSegmentSet(
          samples[0][start + 18]&(1<<PINB1), // A or D
          samples[1][start + 6]&(1<<PIND4), // B     
          samples[1][start + 12]&(1<<PIND4), // C
          samples[1][start]&(1<<PIND4),  // A or D
          samples[0][start + 12]&(1<<PINB1), // E
          samples[0][start]&(1<<PINB1), // F
          samples[0][start + 6]&(1<<PINB1) // G
          );
  if (digit == 255) return;
  else Serial.print(digit, DEC);
}

void print_3digit(int start) {
 // print 3rd digit
 // D7 is A
 // B5 is B
  byte digit = InterpretSevenSegmentSet(
          samples[1][start + 18]&(1<<PIND7), // A or D
          samples[0][start + 6]&(1<<PINB5), // B //    
          samples[0][start + 12]&(1<<PINB5), // C //
          samples[0][start]&(1<<PINB5),  // A or D
          samples[1][start + 12]&(1<<PIND7), // E //
          samples[1][start]&(1<<PIND7), // F
          samples[1][start + 6]&(1<<PIND7) // G
          );
  if (digit == 255) return;
  else Serial.print(digit, DEC);
}

void print_2digit(int start) {
 // print 2nd digit
 // B4 is C
 // B3 is D
  byte digit = InterpretSevenSegmentSet(
          samples[0][start + 18]&(1<<PINB4), // A or D
          samples[0][start + 6]&(1<<PINB3), // B //    
          samples[0][start + 12]&(1<<PINB3), // C //
          samples[0][start]&(1<<PINB3),  // A or D
          samples[0][start + 12]&(1<<PINB4), // E //
          samples[0][start]&(1<<PINB4), // F
          samples[0][start + 6]&(1<<PINB4) // G
              );
  Serial.print(digit, DEC);
}

void print_1digit(int start) {
 // print 1st digit
 // B2 is E
 // B6 is F
  byte digit = InterpretSevenSegmentSet(
          samples[0][start + 18]&(1<<PINB2), // A or D
          samples[0][start + 6]&(1<<PINB6), // B //    
          samples[0][start + 12]&(1<<PINB6), // C //
          samples[0][start]&(1<<PINB6),  // A or D
          samples[0][start + 12]&(1<<PINB2), // E //
          samples[0][start]&(1<<PINB2), // F
          samples[0][start + 6]&(1<<PINB2) // G
              );
  Serial.print(digit, DEC);
}


/*
  attention! in this decision tree  '1' represents off-segments
  maybe you have to inverse it.

  for a given digit, we have:
    A
  F   B
    G 
  E   C
    D
  then, the algorithm is:
 */
byte InterpretSevenSegmentSet(byte A, byte B, byte C, byte D, byte E, byte F, byte G ) {
  byte digit;
  if(E) {
    if(F) {
      if(A) {
        if(B) digit = 0xff; // off
        else {
          if(D) digit = 1;
          else  digit = 7;
        }
      }
      else  digit = 3;    
    }
    else {
      if(A) digit = 4;
      else {   
        if(B) digit = 5;
        else  digit = 9;
      }
    }
  }
  else { 
      if(B) {
        if(C)  {
          if(A) digit = 114; // "r"
          else  digit = 69;  // "E"
        } 
        else digit = 6;     
        }
      else { 
        if(G) digit = 0;
        else {
          if(C) digit = 2;
          else  digit = 8;      
        }
      }
    }    
 return digit;
}

// this is only needed once to map the pins correcly when using this script for another display
// here the case index corresponds to the number of the pad at the display to make mapping easier. 
void print_segments(int start) {
int i=2;
  while(i<16) {
    int f = start;
    Serial.print(i, HEX); Serial.print(": ");
    while (f< (start + 23))
    {
    switch(i) {
      case 9:  if( (samples[1][f]& (1 << PIND4))) Serial.print("1"); else Serial.print("0"); break;
      case 10: if( (samples[1][f]& (1 << PIND7))) Serial.print("1"); else Serial.print("0"); break;
      case 12:  if( (samples[0][f]& (1 << PINB4))) Serial.print("1"); else Serial.print("0"); break;
      case 11: if( (samples[0][f]& (1 << PINB5))) Serial.print("1"); else Serial.print("0"); break;
      case 15:  if( (samples[0][f]& (1 << PINB6))) Serial.print("1"); else Serial.print("0"); break;
      case 14:  if( (samples[0][f]& (1 << PINB2))) Serial.print("1"); else Serial.print("0"); break;
      case 13:  if( (samples[0][f]& (1 << PINB3))) Serial.print("1"); else Serial.print("0"); break;
      case 8:  if( (samples[0][f]& (1 << PINB1))) Serial.print("1"); else Serial.print("0"); break;
    }
    f = f + 6;
    }
    Serial.println();
    i++;
  }
}
