//**************************************************************************************
// Simpel Keyer of the TYPE ACCU-KEYER - Just a keyer, nothing special                **
//**************************************************************************************

// Keyer pin settings - change if it fit your board better
// *************************************************************************************
// Paddles must have a PULL-UP-resistor on each port, 10 K Ohm to +5 Volt
#define DIT_PIN 9      // Paddle DIT - ARDUINO UNO DIGITAL pin 9
#define DAH_PIN 10     // Paddle DAH - ARDUINO UNO DIGITAL pin 10
// *************************************************************************************

// LED-diode must have a serial resistor 390 Ohm from pin til LED, 
// and other LED-pin goes to GND
// *************************************************************************************
#define LED 13         // LED diode  - ARDUINO UNO DIGITAL pin 13

// *************************************************************************************
// potentiometer is mounted between GND and + 5 Volt.
// mittle-pin goes to ANALOG pin A3, or after your needs.
// *************************************************************************************
#define POTPIN A3      // Potentiometer - ARDUINO UNO Analog pin A3

// *************************************************************************************
// **      END of Keyer pin settings                                                  **
// *************************************************************************************

//********************************************************
//**              VARIABEL DEFINITIONS                  **
//********************************************************

// ARDUINO tone on pin 3 - ATmega328P, pin 2 =PD0(PCINT16/RXD) - 
// A 8 Ohm lautspeaker in serie with a 100 Ohm Resistor make CW-sound
// *************************************************************************************
int audioOutPin = 3;   
float target_freq = 700.0;
// *************************************************************************************

int BAUD_DURATION;
int INTERBAUD_DURATION = BAUD_DURATION*1;
int INTERLETTER_DURATION = BAUD_DURATION*2;
int DIT_DURATION = BAUD_DURATION;
int DAH_DURATION = BAUD_DURATION*3;
enum{IDLE,DIT,DAH,PAUSE,};
int dit,dah;
int state;
int nextbaud;
int i;
int val;
long speed;
unsigned long currentTime;
unsigned long startTime;

//********************************************************
//**           READ THE SPEED WE ARE USING              **
//********************************************************
void readspeed()
{
  val = analogRead(POTPIN);                               // val between 0 and 1023
  if (val < 10)                                           // we do not like a zero from the val
  { 
    val = 10; 
  }
  BAUD_DURATION = map(val, 0, 1023, 20, 100); //
  speed = (1200L/BAUD_DURATION)*5;                         // here calculate char pr min..just for info
  INTERBAUD_DURATION = BAUD_DURATION*1;
  INTERLETTER_DURATION = BAUD_DURATION*2;
  DIT_DURATION = BAUD_DURATION;
  DAH_DURATION = BAUD_DURATION*3;
}
//**             END of void readspeed()                **
//********************************************************

//********************************************************
//**               READ ANALOG DIT-port                 **
//********************************************************
void readDit()
{
  if(digitalRead(DIT_PIN)) dit=0; else dit=1; 
} 
//**            END of void readDit()                   **                 
//********************************************************

//********************************************************
//**               READ Analog DAH port                 **
//********************************************************
void readDah()
{ 
  if(digitalRead(DAH_PIN)) dah=0; else dah=1;
}
//**            END of void readDah()                   **
//********************************************************

//********************************************************
//**                SETUP program                       **
//********************************************************
void setup()
{ 
  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);
  state = IDLE;
} 
//**             END of void setup()                    **
//********************************************************

//********************************************************
//**                    OUTPUT                          **
//********************************************************
void contact(unsigned char state)                            // here we make output ..Configure to your needs 
{
  if(state) 
  { 
    digitalWrite(LED,HIGH);                                  // led or reed relay or transistor goes high 
                                                             // pin 3 drives an 8 Ohm speaker with a tone 
    tone(audioOutPin,target_freq);                                // set tone 700 hz on pin 3
// **************************************************************************************
   }
  else
  { 
    digitalWrite(LED,LOW);                                   // led or reed relay or transistor goes low 
    noTone(audioOutPin);                                        // speaker tone off
  } 
} 
//**         END of void contact(unsigned char state)   **
//********************************************************

//********************************************************
//**                   MAIN LOOP                        **
//********************************************************
void loop()
{ 
  readspeed();                                               // start loop with checking speed 
  switch(state)
  { 
    case IDLE:                                               // keyer is waiting for action 
      readDit(); 
      if(dit) 
      { 
	nextbaud = DIT; 
      }
      else
      { 
	readDah();
	if(dah) 
        { 
	nextbaud = DAH; 
	} 
      }; 
      break; 
    case DIT:                                                 // keyer is making a DIT 
      nextbaud = IDLE;                                        // reset the memory to be sure we know it have been changed 
      contact(1);                                             // turn on the radio 
      currentTime = millis(); 
      startTime = millis(); 
      while (startTime + DIT_DURATION + INTERBAUD_DURATION >= currentTime)
      { 
	if (startTime + DIT_DURATION <= currentTime)
        { 
	  contact(0);                                         // when the bit time is over and we just have the bit pause turn off radio 
        } 
	readDah();                                            // check for DAH paddel 
        if(dah && nextbaud == DIT)
        {
          nextbaud = DAH;                                     // if we in this loop first have a DIT we will change to DAH to have iambic 
        } 
	if(dah && nextbaud == IDLE)
        { 
	  nextbaud = DAH;                                     // make a DAH next time 
        } 
	readDit(); 
	if (dit && nextbaud == IDLE )
        { 
	  nextbaud = DIT;                                     // make a DIT next time 
	} 
	if (!dit && nextbaud == DIT )
        { 
	  nextbaud = IDLE;                                    // if we do not release the DIT in good time we will have 2 DIT ..We do not like so we fix 
        } 
	if(!dit && !dah && nextbaud == IDLE) 
        { 
	  nextbaud = PAUSE;                                   // make a 2 BAUD pause if we do not hit the paddel 
	} 
	if((dit || dah) && nextbaud == PAUSE) 
        { 
	  nextbaud = IDLE;                                     // this to give us the full baud time to hit the paddel without making a pause 
	} 
        currentTime = millis();                                // Updates loopTime 
      };   
      break; 
    case DAH:                                                  // all comments are the same as in DIT case ...but wit DAH ;o) 
      nextbaud = IDLE; 
      contact(1); 
      currentTime = millis(); 
      startTime = millis(); 
      while (startTime + DAH_DURATION + INTERBAUD_DURATION >= currentTime)
      { 
	if (startTime + DAH_DURATION <= currentTime)
        {
	  contact(0);
	} 
	readDit(); 
	if(dit && nextbaud == IDLE)
        { 
	  nextbaud = DIT; 
	} 
	if(dit && nextbaud == DAH)
        { 
	  nextbaud = DIT; 
	} 
	readDah(); 
	if(dah && nextbaud == IDLE) 
        { 
	  nextbaud = DAH; 
	} 
	if(!dah && nextbaud == DAH) 
        { 
	  nextbaud = IDLE; 
	} 
	if(!dit && !dah && nextbaud == IDLE)
        { 
	  nextbaud = PAUSE; 
	}
        if((dit || dah) && nextbaud == PAUSE) 
        { 
	  nextbaud = IDLE; 
	} 
	  currentTime = millis();                                // Updates loopTime 
      }; 
      break; 
    case PAUSE: 
      nextbaud = IDLE; //reset the memory 
      currentTime = millis(); 
      startTime = millis(); 
      while (startTime + INTERLETTER_DURATION >= currentTime)    // lets wait 2 baud time 
      { 
        readDit();                                               // looking for next baud 
        if(dit && nextbaud == IDLE)
        { 
	  nextbaud = DIT; 
	} 
	readDah();                                               // looking for next baud 
        if(dah && nextbaud == IDLE) 
        { 
	  nextbaud = DAH; 
	}
        currentTime = millis(); // Updates loopTime 
      } 
      break; 
   }                                                              //switch 
   state = nextbaud; // reset next bit memory 
}  
//**                END of MAIN LOOP                    **
//********************************************************
//                   END of PROGRAM                     **
//********************************************************

