215 lines
6.8 KiB
Arduino
215 lines
6.8 KiB
Arduino
|
//======================================================================
|
||
|
//
|
||
|
// nanoIO paddle keyer (c) 2018, David Freese, W1HKJ
|
||
|
//
|
||
|
// based on code from Iambic Keyer Code Keyer Sketch
|
||
|
// Copyright (c) 2009 Steven T. Elliott
|
||
|
//
|
||
|
// This library is free software; you can redistribute it and/or
|
||
|
// modify it under the terms of the GNU Lesser General Public
|
||
|
// License as published by the Free Software Foundation; either
|
||
|
// version 2.1 of the License, or (at your option) any later version.
|
||
|
//
|
||
|
// This library is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
// Lesser General Public License for more details:
|
||
|
//
|
||
|
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
|
// Boston, MA 02111-1307 USA
|
||
|
//
|
||
|
//======================================================================
|
||
|
|
||
|
//#include "Arduino.h"
|
||
|
//#include "TimerOne.h"
|
||
|
#include "config.h"
|
||
|
#include "keyer.h"
|
||
|
|
||
|
const uint8_t LP_in = KEYER_LEFT_PADDLE_PIN;
|
||
|
const uint8_t RP_in = KEYER_RIGHT_PADDLE_PIN;
|
||
|
|
||
|
//#define ST_Freq 600 // Set the Sidetone Frequency to 600 Hz
|
||
|
|
||
|
//======================================================================
|
||
|
// keyerControl bit definitions
|
||
|
//
|
||
|
#define DIT_L 0x01 // Dit latch
|
||
|
#define DAH_L 0x02 // Dah latch
|
||
|
#define DIT_PROC 0x04 // Dit is being processed
|
||
|
#define PDLSWAP 0x08 // 0 for normal, 1 for swap
|
||
|
//======================================================================
|
||
|
//
|
||
|
// State Machine Defines
|
||
|
|
||
|
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
|
||
|
|
||
|
Keyer::Keyer(int wpm, float weight)
|
||
|
{
|
||
|
//ptt_pin_ = PTT_PIN;
|
||
|
//cw_pin_ = CW_PIN;
|
||
|
// Setup outputs
|
||
|
pinMode(LP_in, INPUT_PULLUP); // sets Left Paddle digital pin as input
|
||
|
pinMode(RP_in, INPUT_PULLUP); // sets Right Paddle digital pin as input
|
||
|
|
||
|
// pinMode(ST_Pin, OUTPUT); // Sets the Sidetone digital pin as output
|
||
|
|
||
|
// digitalWrite(LP_in, HIGH); // Enable pullup resistor on Left Paddle Input Pin
|
||
|
// digitalWrite(RP_in, HIGH); // Enable pullup resistor on Right Paddle Input Pin
|
||
|
|
||
|
keyerState = IDLE;
|
||
|
keyerControl = 0;
|
||
|
key_mode = IAMBICA;
|
||
|
key_down = false;
|
||
|
_weight = weight;
|
||
|
|
||
|
_speed = wpm;
|
||
|
calc_ratio();
|
||
|
}
|
||
|
|
||
|
// Calculate the length of dot, dash and silence
|
||
|
void Keyer::calc_ratio()
|
||
|
{
|
||
|
float w = (1 + _weight) / (_weight -1);
|
||
|
_space_len = (1200 / _speed);
|
||
|
_dotlen = _space_len * (w - 1);
|
||
|
_dashlen = (1 + w) * _space_len;
|
||
|
}
|
||
|
|
||
|
//void Keyer::cw_pin(int pin)
|
||
|
//{
|
||
|
// ptt_pin_ = pin;
|
||
|
//}
|
||
|
|
||
|
//void Keyer::ptt_pin(int pin)
|
||
|
//{
|
||
|
// cw_pin_ = pin;
|
||
|
//}
|
||
|
|
||
|
void Keyer::set_mode(int md)
|
||
|
{
|
||
|
key_mode = md;
|
||
|
}
|
||
|
|
||
|
void Keyer::wpm(int wpm)
|
||
|
{
|
||
|
_speed = wpm;
|
||
|
calc_ratio();
|
||
|
}
|
||
|
|
||
|
//======================================================================
|
||
|
// Latch paddle press
|
||
|
//======================================================================
|
||
|
|
||
|
void Keyer::update_PaddleLatch()
|
||
|
{
|
||
|
if (digitalRead(LP_in) == LOW) {
|
||
|
keyerControl |= DIT_L;
|
||
|
}
|
||
|
if (digitalRead(RP_in) == LOW) {
|
||
|
keyerControl |= DAH_L;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Keyer::do_paddles()
|
||
|
{
|
||
|
if (key_mode == STRAIGHT) { // Straight Key
|
||
|
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW)) {
|
||
|
// Key from either paddle
|
||
|
// digitalWrite(ptt_pin_, HIGH);
|
||
|
// digitalWrite(cw_pin_, HIGH);
|
||
|
// tone(ST_Pin, 600);
|
||
|
key_down = true;
|
||
|
return true;
|
||
|
} else {
|
||
|
// digitalWrite(ptt_pin_, LOW);
|
||
|
// digitalWrite(cw_pin_, LOW);
|
||
|
// noTone(ST_Pin);
|
||
|
key_down = false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// keyerControl contains processing flags and keyer mode bits
|
||
|
// Supports Iambic A and B
|
||
|
// State machine based, uses calls to millis() for timing.
|
||
|
switch (keyerState) {
|
||
|
case IDLE: // Wait for direct or latched paddle press
|
||
|
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW) || (keyerControl & 0x03)) {
|
||
|
update_PaddleLatch();
|
||
|
keyerState = CHK_DIT;
|
||
|
// letting this fall through // return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
// break;
|
||
|
case CHK_DIT: // See if the dit paddle was pressed
|
||
|
if (keyerControl & DIT_L) {
|
||
|
keyerControl |= DIT_PROC;
|
||
|
ktimer = _dotlen;
|
||
|
keyerState = KEYED_PREP;
|
||
|
return true;
|
||
|
} else { // fall through
|
||
|
keyerState = CHK_DAH;
|
||
|
}
|
||
|
case CHK_DAH: // See if dah paddle was pressed
|
||
|
if (keyerControl & DAH_L) {
|
||
|
ktimer = _dashlen;
|
||
|
keyerState = KEYED_PREP;
|
||
|
// letting this fall through // return true;
|
||
|
} else {
|
||
|
keyerState = IDLE;
|
||
|
return false;
|
||
|
}
|
||
|
// break;
|
||
|
case KEYED_PREP: // Assert key down, start timing
|
||
|
// state shared for dit or dah
|
||
|
// digitalWrite(ptt_pin_, HIGH); // Enable PTT
|
||
|
// tone(ST_Pin, ST_Freq); // Turn the Sidetone on
|
||
|
// digitalWrite(cw_pin_, HIGH); // Key the CW line
|
||
|
key_down = true;
|
||
|
ktimer += millis(); // set ktimer to interval end time
|
||
|
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||
|
keyerState = KEYED; // next state
|
||
|
// letting this fall through // return true;
|
||
|
// break;
|
||
|
case KEYED: // Wait for timer to expire
|
||
|
if (millis() > ktimer) { // are we at end of key down ?
|
||
|
// digitalWrite(ptt_pin_, LOW); // Disable PTT
|
||
|
// noTone(ST_Pin); // Turn the Sidetone off
|
||
|
// digitalWrite(cw_pin_, LOW); // Unkey the CW line
|
||
|
key_down = false;
|
||
|
ktimer = millis() + _space_len; // inter-element time
|
||
|
keyerState = INTER_ELEMENT; // next state
|
||
|
// letting this fall through // return true;
|
||
|
} else if (key_mode == IAMBICB) { // Iambic B Mode ?
|
||
|
update_PaddleLatch(); // yes, early paddle latch in Iambic B mode
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
// break;
|
||
|
|
||
|
case INTER_ELEMENT: // Insert time between dits/dahs
|
||
|
update_PaddleLatch(); // latch paddle state
|
||
|
if (millis() > ktimer) { // are we at end of inter-space ?
|
||
|
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
|
||
|
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
|
||
|
keyerState = CHK_DAH; // dit done, check for dah
|
||
|
return true;
|
||
|
} else {
|
||
|
keyerControl &= ~(DAH_L); // clear dah latch
|
||
|
keyerState = IDLE; // go idle
|
||
|
return false;
|
||
|
}
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
// break;
|
||
|
}
|
||
|
|
||
|
return false; // resolve compiler warning; do we ever get here?
|
||
|
}
|
||
|
|
||
|
//======================================================================
|
||
|
// EOF
|
||
|
//======================================================================
|