//====================================================================== // // 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 //#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 }; UBitxKeyer::UBitxKeyer(int wpm, float weight): speed(wpm), symWeight(weight) { // 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 keyerState = IDLE; keyerControl = 0; keyMode = IAMBICA; keyDown = false; calcRatio(); } // Calculate the length of dot, dash and silence void UBitxKeyer::calcRatio() { float w = (1.0 + symWeight) / (symWeight - 1.0); spaceLen = (1200 / speed); dotLen = spaceLen * (w - 1); dashLen = (1 + w) * spaceLen; } void UBitxKeyer::setWPM(int wpm) { speed = wpm; calcRatio(); } void UBitxKeyer::setWeight(float weight) { symWeight = weight; calcRatio(); } //====================================================================== // Latch paddle press //====================================================================== void UBitxKeyer::updatePaddleLatch() { if (digitalRead(LP_in) == LOW) { keyerControl |= DIT_L; } if (digitalRead(RP_in) == LOW) { keyerControl |= DAH_L; } } bool UBitxKeyer::doPaddles() { if (keyMode == STRAIGHT) { // Straight Key if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW)) { keyDown = true; return true; } else { keyDown = 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)) { updatePaddleLatch(); keyerState = CHK_DIT; return true; } 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; } // fall through keyerState = CHK_DAH; case CHK_DAH: // See if dah paddle was pressed if (keyerControl & DAH_L) { ktimer = dashLen; keyerState = KEYED_PREP; return true; } else { keyerState = IDLE; return false; } //break; case KEYED_PREP: // Assert key down, start timing // state shared for dit or dah keyDown = true; ktimer += millis(); // set ktimer to interval end time keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits keyerState = KEYED; // next state return true; //break; case KEYED: // Wait for timer to expire if (millis() > ktimer) { // are we at end of key down ? keyDown = false; ktimer = millis() + spaceLen; // inter-element time keyerState = INTER_ELEMENT; // next state return true; } else if (keyMode == IAMBICB) { // Iambic B Mode ? updatePaddleLatch(); // yes, early paddle latch in Iambic B mode } return true; // break; case INTER_ELEMENT: // Insert time between dits/dahs updatePaddleLatch(); // 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; } } return true; //break; } return false; // resolve compiler warning; do we ever get here? } UBitxKeyer basicKeyer(15, 3.0); UBitxKeyer& Keyer = basicKeyer; //====================================================================== // EOF //======================================================================