// JI3BNB SSTV ENCODER (ROBOT B/W 8S MODE) v1.0 2016.04.08
// ARDUINO UNO + AD9850 DDS
// THIS PROGRAM IS IN THE PUBLIC DOMAIN

#include <TimerOne.h>

#define  CLK   8  //UNO:PORT_B0
#define  FQ    9  //UNO:PORT_B1
#define  DATA  10 //UNO:PORT_B2
#define  RST   11 //UNO:PORT_B3

volatile long  oFrq = 7171000; // ***** set operating Frequency here in Hz *****
volatile byte  sSq;
volatile int   ti;
volatile int   line;

char line00[7] = "CQSSTV";
char line01[7] = "JI3BNB";

const uint8_t font_a[]   = {0x00, 0x18, 0x24, 0x62, 0x62, 0x62, 0x7E, 0x62, 0x62, 0x62, 0x00};
const uint8_t font_b[]   = {0x00, 0x7C, 0x32, 0x32, 0x32, 0x3C, 0x32, 0x32, 0x32, 0x7C, 0x00};
const uint8_t font_c[]   = {0x00, 0x3C, 0x62, 0x62, 0x60, 0x60, 0x60, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_d[]   = {0x00, 0x7C, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x7C, 0x00};
const uint8_t font_e[]   = {0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x7E, 0x00};
const uint8_t font_f[]   = {0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00};
const uint8_t font_g[]   = {0x00, 0x3C, 0x62, 0x62, 0x60, 0x60, 0x66, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_h[]   = {0x00, 0x62, 0x62, 0x62, 0x62, 0x7E, 0x62, 0x62, 0x62, 0x62, 0x00};
const uint8_t font_i[]   = {0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00};
const uint8_t font_j[]   = {0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x4C, 0x4C, 0x4C, 0x38, 0x00};
const uint8_t font_k[]   = {0x00, 0x62, 0x64, 0x68, 0x70, 0x68, 0x64, 0x62, 0x62, 0x62, 0x00};
const uint8_t font_l[]   = {0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00};
const uint8_t font_m[]   = {0x00, 0x42, 0x62, 0x76, 0x6A, 0x62, 0x62, 0x62, 0x62, 0x62, 0x00};
const uint8_t font_n[]   = {0x00, 0x42, 0x62, 0x72, 0x6A, 0x66, 0x62, 0x62, 0x62, 0x62, 0x00};
const uint8_t font_o[]   = {0x00, 0x3C, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_p[]   = {0x00, 0x7C, 0x62, 0x62, 0x62, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00};
const uint8_t font_q[]   = {0x00, 0x3C, 0x62, 0x62, 0x62, 0x62, 0x62, 0x6A, 0x6A, 0x3C, 0x08};
const uint8_t font_r[]   = {0x00, 0x7C, 0x62, 0x62, 0x62, 0x7C, 0x68, 0x64, 0x62, 0x62, 0x00};
const uint8_t font_s[]   = {0x00, 0x3C, 0x62, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x46, 0x3C, 0x00};
const uint8_t font_t[]   = {0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00};
const uint8_t font_u[]   = {0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_v[]   = {0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x22, 0x14, 0x08, 0x00};
const uint8_t font_w[]   = {0x00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x6A, 0x76, 0x62, 0x42, 0x00};
const uint8_t font_x[]   = {0x00, 0x42, 0x62, 0x74, 0x38, 0x1C, 0x2E, 0x46, 0x42, 0x42, 0x00};
const uint8_t font_y[]   = {0x00, 0x42, 0x62, 0x74, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00};
const uint8_t font_z[]   = {0x00, 0x7E, 0x06, 0x0E, 0x0C, 0x18, 0x30, 0x70, 0x60, 0x7E, 0x00};
const uint8_t font_0[]   = {0x00, 0x3C, 0x62, 0x62, 0x66, 0x6A, 0x72, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_1[]   = {0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00};
const uint8_t font_2[]   = {0x00, 0x3C, 0x46, 0x06, 0x06, 0x1C, 0x20, 0x60, 0x60, 0x7E, 0x00};
const uint8_t font_3[]   = {0x00, 0x3C, 0x46, 0x06, 0x06, 0x1C, 0x06, 0x06, 0x46, 0x3C, 0x00};
const uint8_t font_4[]   = {0x00, 0x0C, 0x1C, 0x2C, 0x4C, 0x4C, 0x7E, 0x0C, 0x0C, 0x0C, 0x00};
const uint8_t font_5[]   = {0x00, 0x7E, 0x60, 0x60, 0x60, 0x7C, 0x06, 0x06, 0x46, 0x3C, 0x00};
const uint8_t font_6[]   = {0x00, 0x3C, 0x62, 0x60, 0x60, 0x7C, 0x62, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_7[]   = {0x00, 0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00};
const uint8_t font_8[]   = {0x00, 0x3C, 0x62, 0x62, 0x62, 0x3C, 0x62, 0x62, 0x62, 0x3C, 0x00};
const uint8_t font_9[]   = {0x00, 0x3C, 0x46, 0x46, 0x46, 0x3E, 0x06, 0x06, 0x46, 0x3C, 0x00};
const uint8_t font_slu[] = {0x00, 0x00, 0x02, 0x06, 0x0E, 0x1C, 0x38, 0x70, 0x60, 0x40, 0x00};
const uint8_t font_das[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00};
const uint8_t font_dot[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00};
const uint8_t font_que[] = {0x00, 0x3C, 0x46, 0x06, 0x06, 0x0C, 0x10, 0x00, 0x30, 0x30, 0x00};
const uint8_t font_eks[] = {0x00, 0x18, 0x18, 0x18, 0x18, 0x10, 0x10, 0x00, 0x18, 0x18, 0x00};
const uint8_t font_col[] = {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00};
const uint8_t font_spa[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

boolean textArea[1232]; //56*22

void shortPulse (char PIN)
{
  digitalWrite(PIN, 1);
  digitalWrite(PIN, 0);
}

void setFreq(double freq)
{
  //--calculate
  int32_t d_Phase = freq * pow(2, 32) / 125000000;
  //--send first 32bit
  for (int i=0; i<32; i++, d_Phase>>=1)
  {
    if(d_Phase & 1 == 1)
    {
      PORTB |=  _BV(2); //--data
    }
    else
    {
      PORTB &= ~_BV(2); //--data
    }
    //--short pulse clk
    PORTB |=  _BV(0);
    PORTB &= ~_BV(0);
  }
  //--send rest 8bit
  PORTB &= ~_BV(2); //--data
  for (int i=0; i<8; i++)
  {
    //--short pulse clk
    PORTB |=  _BV(0);
    PORTB &= ~_BV(0);
  }
  //--finish, short pulse fq
  PORTB |=  _BV(1);
  delayMicroseconds(30);
  PORTB &= ~_BV(1);
}

void setup()
{
  Timer1.initialize();
  Timer1.attachInterrupt(timer1_interrupt, 999); //-- SLANT ADJUST --
  
  digitalWrite(6, 1); //INTERNAL PULL UP
  
  pinMode(CLK, OUTPUT);
  pinMode(FQ, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RST, OUTPUT);
  //--reset
  shortPulse(RST);
  shortPulse(CLK);
  //--change mode
  shortPulse(FQ);
  //--done
  delay(5);
  
  //Serial.begin(9600);
}

void timer1_interrupt(void)
{
  int p;
  
  if(sSq == 3)
  {
    if(line >= 40 && line <= 61)
    {
      if(ti < 56)
      {
        p = 56 * (line - 40) + ti;
        if(textArea[p])
        {
          setFreq(oFrq - 1500);
        }
        else
        {
          setFreq(oFrq - 2300);
        }
      }
      else if(ti == 56)
      {
        line++;
        sSq = 2;
      }
    }
    else
    {
      switch(ti)
      {
        case 0:
          setFreq(oFrq - 1500);
          break;
        case 14:
          setFreq(oFrq - 1767);
          break;
        case 28:
          setFreq(oFrq - 2033);
          break;
        case 42:
          setFreq(oFrq - 2300);
          break;
        case 56:
          line++;
          if(line == 120)
          {
            sSq = 0;
          }
          else
          {
            sSq = 2;
          }
          break;
      }
    }
    ti++;
  }
}

void loop()
{
  int x;
  int y;
  int i;
  int p;

  if(sSq == 0)
  {
    setFreq(2);
    while(sSq == 0)
    {
      if(digitalRead(6) == 0) // - SEND SW -
      {
        sSq = 1;
      }
      else
      {
        delay(30);
      }
    }
  }
  if(sSq == 1)
  {
    for(i = 0; i < 1232; i++)
    {
      textArea[i] = false;
    }
    
    for(i = 0; i < 12; i++)
    {
      char ch;
      
      if(i < 6)
      {
        ch = line00[i];
      }
      else
      {
        ch = line01[i - 6];
      }
      
      for(y = 0; y < 11; y++)
      {
        for(x = 0; x < 8; x++)
        {
          if(i < 6)
          {
            p = 4 + (56 * y) + (8 * i) + x;
          }
          else
          {
            p = 4 + (56 * 11) + (56 * y) + (8 * (i - 6)) + x;
          }
          
          uint8_t mask;
          
               if(x == 0){mask = B10000000;}
          else if(x == 1){mask = B01000000;}
          else if(x == 2){mask = B00100000;}
          else if(x == 3){mask = B00010000;}
          else if(x == 4){mask = B00001000;}
          else if(x == 5){mask = B00000100;}
          else if(x == 6){mask = B00000010;}
          else if(x == 7){mask = B00000001;}          
               
          if(ch == 'A')
          {
            if((font_a[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'B')
          {
            if((font_b[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'C')
          {
            if((font_c[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'D')
          {
            if((font_d[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'E')
          {
            if((font_e[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'F')
          {
            if((font_f[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'G')
          {
            if((font_g[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'H')
          {
            if((font_h[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'I')
          {
            if((font_i[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'J')
          {
            if((font_j[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'K')
          {
            if((font_k[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'L')
          {
            if((font_l[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'M')
          {
            if((font_m[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'N')
          {
            if((font_n[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'O')
          {
            if((font_o[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'P')
          {
            if((font_p[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'Q')
          {
            if((font_q[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'R')
          {
            if((font_r[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'S')
          {
            if((font_s[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'T')
          {
            if((font_t[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'U')
          {
            if((font_u[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'V')
          {
            if((font_v[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'W')
          {
            if((font_w[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'X')
          {
            if((font_x[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'Y')
          {
            if((font_y[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == 'Z')
          {
            if((font_z[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '0')
          {
            if((font_0[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '1')
          {
            if((font_1[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '2')
          {
            if((font_2[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '3')
          {
            if((font_3[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '4')
          {
            if((font_4[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '5')
          {
            if((font_5[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '6')
          {
            if((font_6[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '7')
          {
            if((font_7[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '8')
          {
            if((font_8[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '9')
          {
            if((font_9[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '/')
          {
            if((font_slu[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '-')
          {
            if((font_das[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '.')
          {
            if((font_dot[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '?')
          {
            if((font_que[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == '!')
          {
            if((font_eks[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == ':')
          {
            if((font_col[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
          else if(ch == ' ')
          {
            if((font_spa[y] & mask) != 0)
            {
              textArea[p] = true;
            }
          }
        }
      }
    }
    
    delay(400);
    
    //--VIS SEQUENCE
    //VIS CODE for ROBOT B/W 8S is B0000010 (DECIMAL 2)
    setFreq(oFrq - 1900);
    delay(300);
    setFreq(oFrq - 1200); //BREAK
    delay(10);
    setFreq(oFrq - 1900);
    delay(300);
    setFreq(oFrq - 1200); //START BIT
    delay(30);
    setFreq(oFrq - 1300); //BIT 0 (LSB FIRST)
    delay(30);
    setFreq(oFrq - 1100); //BIT 1
    delay(30);
    setFreq(oFrq - 1300); //BIT 2, 3, 4, 5, 6
    delay(150);
    setFreq(oFrq - 1100); //EVEN PARITY
    delay(30);
    setFreq(oFrq - 1200); //STOP BIT
    delay(30);
    //--VIS SEQUENCE DONE
    line = 0;
    sSq  = 2;
  }
  if(sSq == 2)
  {
    //--sync
    setFreq(oFrq - 1200);
    delayMicroseconds(9990);
    //--
    ti  = 0;
    sSq = 3;
  }
}