Compare commits

..

5 Commits

8 changed files with 416 additions and 396 deletions

View File

@ -31,6 +31,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/ **************************************************************************/
/*
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
//27 + 10 + 18 + 1(SPACE) = //56 //27 + 10 + 18 + 1(SPACE) = //56
@ -398,3 +399,4 @@ void controlAutoCW(){
} }
} }
*/

View File

@ -23,7 +23,7 @@
// Compile Option // Compile Option
//============================================================================== //==============================================================================
//Ubitx Board Version //Ubitx Board Version
#define UBITX_BOARD_VERSION 2 //v1 ~ v4 : 4, v5: 5 #define UBITX_BOARD_VERSION 5 //v1 ~ v4 : 4, v5: 5
//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below. //Depending on the type of LCD mounted on the uBITX, uncomment one of the options below.
//You must select only one. //You must select only one.
@ -39,9 +39,12 @@
#define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode #define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode
//Select betwen Analog S-Meter and DSP (I2C) Meter //Select betwen Analog S-Meter and DSP (I2C) Meter
#define USE_I2CSMETER //#define USE_I2CSMETER
#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP // Use alternate keyer?
#define USE_ALTKEYER
//#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP
//#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x //#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x
//Custom LPF Filter Mod //Custom LPF Filter Mod
@ -219,6 +222,12 @@ extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
#define ANALOG_SPARE (A7) #define ANALOG_SPARE (A7)
#define ANALOG_SMETER (A7) //by KD8CEC #define ANALOG_SMETER (A7) //by KD8CEC
#ifdef USE_ALTKEYER
#define DIGITAL_DOT (11) // can't remember if I need to swap still???
#define DIGITAL_DASH (12)
#define DIGITAL_KEY (A3)
#endif
/** /**
* The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig. * The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
* This assignment is as follows : * This assignment is as follows :
@ -332,4 +341,22 @@ extern void DisplayVersionInfo(const char* fwVersionInfo);
//I2C Signal Meter, Version 1.097 //I2C Signal Meter, Version 1.097
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
#define DIT_L 0x01 // DIT latch
#define DAH_L 0x02 // DAH latch
#define DIT_PROC 0x04 // DIT is being processed
#define PDLSWAP 0x08
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
// For compatibility w/ W0EB code
#define MODE_USB 0
#define MODE_LSB 1
#define MODE_CW 2
#define MODE_CWR 3
#define MODE_SWU 4
#define MODE_SWL 5
#define PTT_HNDKEY_DEBOUNCE_CT 2
#endif //end of if header define #endif //end of if header define

View File

@ -9,6 +9,8 @@
#define FIRMWARE_VERSION_INFO F("+v1.200") #define FIRMWARE_VERSION_INFO F("+v1.200")
#define FIRMWARE_VERSION_NUM 0x04 //1st Complete Project : 1 (Version 1.061), 2st Project : 2, 1.08: 3, 1.09 : 4 #define FIRMWARE_VERSION_NUM 0x04 //1st Complete Project : 1 (Version 1.061), 2st Project : 2, 1.08: 3, 1.09 : 4
extern void Connect_Interrupts(void);
/** /**
Cat Suppoort uBITX CEC Version Cat Suppoort uBITX CEC Version
This firmware has been gradually changed based on the original firmware created by Farhan, Jack, Jerry and others. This firmware has been gradually changed based on the original firmware created by Farhan, Jack, Jerry and others.
@ -165,7 +167,6 @@ int cwAdcBothFrom = 0;
int cwAdcBothTo = 0; int cwAdcBothTo = 0;
byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
bool Iambic_Key = true; bool Iambic_Key = true;
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
unsigned char keyerControl = IAMBICB; unsigned char keyerControl = IAMBICB;
byte isShiftDisplayCWFreq = 1; //Display Frequency byte isShiftDisplayCWFreq = 1; //Display Frequency
@ -187,10 +188,10 @@ byte userCallsignLength = 0; //7 : display callsign at system startup, 6~0 :
/** /**
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it * Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
*/ */
boolean txCAT = false; //turned on if the transmitting due to a CAT command volatile boolean txCAT = false; //turned on if the transmitting due to a CAT command
char inTx = 0; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat) bool inTx = false; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
char splitOn = 0; //working split, uses VFO B as the transmit frequency char splitOn = 0; //working split, uses VFO B as the transmit frequency
char keyDown = 0; //in cw mode, denotes the carrier is being transmitted //char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
char isUSB = 0; //upper sideband was selected, this is reset to the default for the char isUSB = 0; //upper sideband was selected, this is reset to the default for the
char cwMode = 0; //compatible original source, and extend mode //if cwMode == 0, mode check : isUSB, cwMode > 0, mode Check : cwMode char cwMode = 0; //compatible original source, and extend mode //if cwMode == 0, mode check : isUSB, cwMode > 0, mode Check : cwMode
@ -312,6 +313,7 @@ void saveBandFreqByIndex(unsigned long f, unsigned long mode, char bandIndex) {
When the delay is used, the program will generate an error because it is not communicating, When the delay is used, the program will generate an error because it is not communicating,
so Create a new delay function that can do background processing. so Create a new delay function that can do background processing.
*/ */
unsigned long delayBeforeTime = 0; unsigned long delayBeforeTime = 0;
byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle
delayBeforeTime = millis(); delayBeforeTime = millis();
@ -321,11 +323,11 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
if (fromType == 4) if (fromType == 4)
{ {
//CHECK PADDLE //CHECK PADDLE
if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual // if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual
return 1; // return 1;
//Check PTT while auto Sending //Check PTT while auto Sending
autoSendPTTCheck(); //autoSendPTTCheck();
Check_Cat(3); Check_Cat(3);
} }
@ -338,6 +340,7 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
return 0; return 0;
} }
/** /**
@ -444,7 +447,7 @@ void setFrequency(unsigned long f){
f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1]; f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1];
setTXFilters(f); setTXFilters(f);
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0)); unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (!inTx) ? ifShiftValue : 0));
int appliedTuneValue = 0; int appliedTuneValue = 0;
//applied if tune //applied if tune
@ -454,7 +457,7 @@ void setFrequency(unsigned long f){
appliedTuneValue = if1TuneValue; appliedTuneValue = if1TuneValue;
//In the LSB state, the optimum reception value was found. To apply to USB, 3Khz decrease is required. //In the LSB state, the optimum reception value was found. To apply to USB, 3Khz decrease is required.
if (sdrModeOn && (inTx == 0)) if (sdrModeOn && (!inTx))
appliedTuneValue -= 15; //decrease 1.55Khz appliedTuneValue -= 15; //decrease 1.55Khz
//if (isUSB) //if (isUSB)
@ -464,13 +467,13 @@ void setFrequency(unsigned long f){
//if1Tune RX, TX Enabled, ATT : only RX Mode //if1Tune RX, TX Enabled, ATT : only RX Mode
//The IF Tune shall be measured at the LSB. Then, move the 3Khz down for USB. //The IF Tune shall be measured at the LSB. Then, move the 3Khz down for USB.
long if1AdjustValue = ((inTx == 0) ? (attLevel * 100) : 0) + (appliedTuneValue * 100); //if1Tune RX, TX Enabled, ATT : only RX Mode //5600 long if1AdjustValue = ((!inTx) ? (attLevel * 100) : 0) + (appliedTuneValue * 100); //if1Tune RX, TX Enabled, ATT : only RX Mode //5600
//for DIY uBITX (custom filter) //for DIY uBITX (custom filter)
if ((advancedFreqOption1 & 0x80) != 0x00) //Reverse IF Tune (- Value for DIY uBITX) if ((advancedFreqOption1 & 0x80) != 0x00) //Reverse IF Tune (- Value for DIY uBITX)
if1AdjustValue *= -1; if1AdjustValue *= -1;
if (sdrModeOn && (inTx == 0)) //IF SDR MODE if (sdrModeOn && (!inTx)) //IF SDR MODE
{ {
//Fixed Frequency SDR (Default Frequency : 32Mhz, available change sdr Frequency by uBITX Manager) //Fixed Frequency SDR (Default Frequency : 32Mhz, available change sdr Frequency by uBITX Manager)
//Dynamic Frequency is for SWL without cat //Dynamic Frequency is for SWL without cat
@ -545,7 +548,7 @@ void setFrequency(unsigned long f){
* put the uBitx in tx mode. It takes care of rit settings, sideband settings * put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode * Note: In cw mode, doesnt key the radio, only puts it in tx mode
*/ */
void startTx(byte txMode, byte isDisplayUpdate){ void startTx(byte txMode, byte isDisplayUpdate = 0){
//Check Hamband only TX //Not found Hamband index by now frequency //Check Hamband only TX //Not found Hamband index by now frequency
if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) { if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) {
//no message //no message
@ -555,7 +558,7 @@ void startTx(byte txMode, byte isDisplayUpdate){
if ((isTxType & 0x01) != 0x01) if ((isTxType & 0x01) != 0x01)
digitalWrite(TX_RX, 1); digitalWrite(TX_RX, 1);
inTx = 1; inTx = true;
if (ritOn){ if (ritOn){
//save the current as the rx frequency //save the current as the rx frequency
@ -615,10 +618,12 @@ void startTx(byte txMode, byte isDisplayUpdate){
//reduce latency time when begin of CW mode //reduce latency time when begin of CW mode
if (isDisplayUpdate == 1) if (isDisplayUpdate == 1)
updateDisplay(); updateDisplay();
Serial.println("exiting startTx()");
} }
void stopTx(void){ void stopTx(void){
inTx = 0; inTx = false;
digitalWrite(TX_RX, 0); //turn off the tx digitalWrite(TX_RX, 0); //turn off the tx
SetCarrierFreq(); SetCarrierFreq();
@ -682,12 +687,12 @@ void checkPTT(){
if (cwTimeout > 0) if (cwTimeout > 0)
return; return;
if (digitalRead(PTT) == 0 && inTx == 0){ if (digitalRead(PTT) == 0 && !inTx){
startTx(TX_SSB, 1); startTx(TX_SSB, 1);
delay(50); //debounce the PTT delay(50); //debounce the PTT
} }
if (digitalRead(PTT) == 1 && inTx == 1) if (digitalRead(PTT) == 1 && inTx)
stopTx(); stopTx();
} }
#ifdef EXTEND_KEY_GROUP1 #ifdef EXTEND_KEY_GROUP1
@ -1292,6 +1297,11 @@ void initPorts(){
pinMode(ANALOG_KEYER, INPUT_PULLUP); pinMode(ANALOG_KEYER, INPUT_PULLUP);
pinMode(ANALOG_SMETER, INPUT); //by KD8CEC pinMode(ANALOG_SMETER, INPUT); //by KD8CEC
#ifdef USE_ALTKEYER
pinMode(DIGITAL_DOT, INPUT_PULLUP);
pinMode(DIGITAL_DASH, INPUT_PULLUP);
#endif
#ifdef USE_CUSTOM_LPF_FILTER #ifdef USE_CUSTOM_LPF_FILTER
if (isCustomFilter_A7) if (isCustomFilter_A7)
{ {
@ -1432,6 +1442,8 @@ void setup()
factory_alignment(); factory_alignment();
#endif #endif
Connect_Interrupts();
} }
//Auto save Frequency and Mode with Protected eeprom life by KD8CEC //Auto save Frequency and Mode with Protected eeprom life by KD8CEC
@ -1460,14 +1472,21 @@ void checkAutoSaveFreqMode()
void loop(){ void loop(){
if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
if (!txCAT) #ifdef USE_ALTKEYER
checkPTT(); // when using the alternate keyer, don't check the PTT if we're in CW mode, because
// the PTT is also a straight key
// if (!txCAT && (cwMode == 0))
// checkPTT();
#else
// if (!txCAT)
// checkPTT();
#endif
checkButton(); checkButton();
} }
else else
controlAutoCW(); ; //controlAutoCW();
cwKeyer(); //cwKeyer();
//tune only when not tranmsitting //tune only when not tranmsitting
if (!inTx){ if (!inTx){
@ -1487,7 +1506,8 @@ void loop(){
} //end of check TX Status } //end of check TX Status
//we check CAT after the encoder as it might put the radio into TX //we check CAT after the encoder as it might put the radio into TX
Check_Cat(inTx? 1 : 0); // Maybe make this do all four versions of Check_Cat depending on state
Check_Cat(inTx ? 1 : 0);
//for SEND SW Serial //for SEND SW Serial
#ifdef USE_SW_SERIAL #ifdef USE_SW_SERIAL

336
ubitx_20/ubitx_keyer.cpp Normal file
View File

@ -0,0 +1,336 @@
/**
* File name ubitx_keyer.cpp
* CW Keyer
*
* The CW keyer handles either a straight key or an iambic / paddle key.
* D12 for DOT Paddle and D11 for DASH Paddle and D* for PTT/Handkey
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
#include "ubitx.h"
#include <Arduino.h>
extern void stopTx(void);
extern void startTx(byte txMode, byte isDisplayUpdate = 0);
extern unsigned long sideTone;
extern int cwSpeed;
// extern long CW_TIMEOUT;
extern long cwTimeout;
#define CW_TIMEOUT (cwTimeout)
extern volatile bool inTx;
// extern volatile int ubitx_mode;
extern char isUSB;
extern char cwMode;
extern volatile unsigned char keyerControl;
// extern volatile unsigned char keyerState;
volatile unsigned char keyerState = IDLE;
// extern unsigned volatile char IAMBICB;
// extern unsigned volatile char PDLSWAP;
// extern volatile unsigned long Ubitx_Voltage;
// extern volatile int Ubitx_Voltage_Timer;
volatile bool keyDown = false; // in cw mode, denotes the carrier is being transmitted
volatile uint8_t Last_Bits = 0xFF;
;
volatile bool Dot_in_Progress = false;
volatile unsigned long Dot_Timer_Count = 0;
volatile bool Dash_in_Progress = false;
volatile unsigned long Dash_Timer_Count = 0;
volatile bool Inter_Bit_in_Progress = false;
volatile unsigned long Inter_Bit_Timer_Count = 0;
volatile bool Turn_Off_Carrier_in_Progress = false;
volatile unsigned long Turn_Off_Carrier_Timer_Count = 0;
volatile bool Ubitx_Voltage_Act = false;
volatile bool PTT_HANDKEY_ACTIVE = false;
volatile long last_interrupt_time = 20;
// extern bool Cat_Lock;
// extern volatile bool TX_In_Progress;
extern volatile bool txCAT;
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(void) {
keyDown = 1; // tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
#ifdef XMIT_LED
digitalWrite(ON_AIR, 0); // extinguish the LED on NANO's pin 13
#endif
}
/**
* Stops the CW carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(void) {
keyDown = 0; // tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
#ifdef XMIT_LED
digitalWrite(ON_AIR, 1); // extinguish the LED on NANO's pin 13
#endif
}
void update_PaddleLatch() {
// if (!digitalRead(DIGITAL_DOT) ) keyerControl |= DIT_L;
// if (!digitalRead(DIGITAL_DASH) ) keyerControl |= DAH_L;
if (digitalRead(DIGITAL_DOT) == LOW) {
if (keyerControl & PDLSWAP)
keyerControl |= DAH_L;
else
keyerControl |= DIT_L;
}
if (digitalRead(DIGITAL_DASH) == LOW) {
if (keyerControl & PDLSWAP)
keyerControl |= DIT_L;
else
keyerControl |= DAH_L;
}
}
//////////////////////////////////////////////////////////////////////////////////////////
// interupt handlers
//// timers
ISR(TIMER1_OVF_vect) {
static volatile bool i_am_running = false;
bool continue_loop = true;
if (i_am_running) return;
i_am_running = true;
// process if CW modes
// if( (ubitx_mode == MODE_CW)||(ubitx_mode == MODE_CWR)){
if (cwMode > 0) {
// process DOT and DASH timing
if ((Dot_in_Progress) && (Dot_Timer_Count > 0)) {
if (!inTx) {
keyDown = 0;
startTx(TX_CW);
}
if (keyDown == 0)
cwKeydown();
Dot_Timer_Count = Dot_Timer_Count - 1;
if (Dot_Timer_Count <= 0) {
Dot_Timer_Count = 0;
Dot_in_Progress = false;
cwKeyUp();
}
}
// process Inter Bit Timing
if ((Inter_Bit_in_Progress) && (Inter_Bit_Timer_Count > 0)) {
Inter_Bit_Timer_Count = Inter_Bit_Timer_Count - 1;
if (Inter_Bit_Timer_Count <= 0) {
Inter_Bit_Timer_Count = 0;
Inter_Bit_in_Progress = false;
}
}
// process turning off carrier
if ((Turn_Off_Carrier_in_Progress) && (Turn_Off_Carrier_Timer_Count > 0)) {
Turn_Off_Carrier_Timer_Count = Turn_Off_Carrier_Timer_Count - 1;
if (Turn_Off_Carrier_Timer_Count <= 0) {
Turn_Off_Carrier_in_Progress = false;
Turn_Off_Carrier_Timer_Count = 0;
stopTx();
}
}
// process hand key
if (digitalRead(DIGITAL_KEY) == 0) {
// If interrupts come faster than 5ms, assume it's a bounce and ignore
last_interrupt_time = last_interrupt_time - 1;
if (last_interrupt_time <= 0) {
last_interrupt_time = 0;
if (!inTx) {
keyDown = 0;
startTx(TX_CW);
}
if (keyDown == 0)
cwKeydown();
PTT_HANDKEY_ACTIVE = true;
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
}
} else if ((keyDown == 1) && (PTT_HANDKEY_ACTIVE == true)) {
cwKeyUp();
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
Turn_Off_Carrier_in_Progress = true;
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
PTT_HANDKEY_ACTIVE = false;
} else
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
if (PTT_HANDKEY_ACTIVE == false) {
while (continue_loop) {
switch (keyerState) {
case IDLE:
if ((!digitalRead(DIGITAL_DOT)) || (!digitalRead(DIGITAL_DASH)) ||
(keyerControl & 0x03)) {
update_PaddleLatch();
keyerState = CHK_DIT;
Dot_in_Progress = false;
Dot_Timer_Count = 0;
Turn_Off_Carrier_Timer_Count = 0;
Turn_Off_Carrier_in_Progress = false;
} else {
continue_loop = false;
}
break;
case CHK_DIT:
if (keyerControl & DIT_L) {
keyerControl |= DIT_PROC;
keyerState = KEYED_PREP;
Dot_Timer_Count = cwSpeed;
} else {
keyerState = CHK_DAH;
}
break;
case CHK_DAH:
if (keyerControl & DAH_L) {
keyerState = KEYED_PREP;
Dot_Timer_Count = cwSpeed * 3;
} else {
continue_loop = false;
keyerState = IDLE;
}
break;
case KEYED_PREP:
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
Turn_Off_Carrier_Timer_Count = 0;
Turn_Off_Carrier_in_Progress = false;
Dot_in_Progress = true;
break;
case KEYED:
if (Dot_in_Progress == false) { // are we at end of key down ?
Inter_Bit_in_Progress = true;
Inter_Bit_Timer_Count = cwSpeed;
keyerState = INTER_ELEMENT; // next state
} else if (keyerControl & IAMBICB) {
update_PaddleLatch(); // early paddle latch in Iambic B mode
continue_loop = false;
} else
continue_loop = false;
break;
case INTER_ELEMENT:
// Insert time between dits/dahs
update_PaddleLatch(); // latch paddle state
if (Inter_Bit_in_Progress == false) { // are we at end of inter-space ?
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
Turn_Off_Carrier_in_Progress = true;
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
} else {
keyerControl &= ~(DAH_L); // clear dah latch
keyerState = IDLE; // go idle
}
} else
continue_loop = false;
break;
}
}
}
}
// process PTT
// if( (ubitx_mode == MODE_USB)|| (ubitx_mode == MODE_LSB)){
if (cwMode == 0) {
if (digitalRead(PTT) == 0) {
// If interrupts come faster than 5ms, assume it's a bounce and ignore
last_interrupt_time = last_interrupt_time - 1;
if (last_interrupt_time <= 0) {
last_interrupt_time = 0;
if (!inTx)
startTx(TX_SSB);
}
} else if ((inTx) && (txCAT == false)) {
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
stopTx();
} else
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
}
i_am_running = false;
}
void Connect_Interrupts(void) {
keyerControl = 0;
cli();
TIMSK1 |= (1 << TOIE1);
sei();
}
/*
#define N_MORSE (sizeof(morsetab)/sizeof(morsetab[0]))
// Morse table
struct t_mtab { char c, pat; } ;
struct t_mtab morsetab[] = {
{'.', 106}, {',', 115}, {'?', 76}, {'/', 41}, {'A', 6}, {'B', 17}, {'C', 21}, {'D', 9},
{'E', 2}, {'F', 20}, {'G', 11}, {'H', 16}, {'I', 4}, {'J', 30}, {'K', 13}, {'L', 18},
{'M', 7}, {'N', 5}, {'O', 15}, {'P', 22}, {'Q', 27}, {'R', 10}, {'S', 8}, {'T', 3},
{'U', 12}, {'V', 24}, {'W', 14}, {'X', 25}, {'Y', 29}, {'Z', 19}, {'1', 62}, {'2', 60},
{'3', 56}, {'4', 48}, {'5', 32}, {'6', 33}, {'7', 35}, {'8', 39}, {'9', 47}, {'0', 63}
};
///////////////////////////////////////////////////////////////////////////////////////////
// CW generation routines for CQ message
void key(int LENGTH){
if( !inTx ) startTx(TX_CW);
cwKeydown();
delay(LENGTH*2);
cwKeyUp();
delay(cwSpeed*2);
}
void send(char c){
int i ;
if (c == ' ') {
delay(7*cwSpeed) ;
return ;
}
for (i=0; i<N_MORSE; i++){
if (morsetab[i].c == c){
unsigned char p = morsetab[i].pat ;
while (p != 1) {
if (p & 1) Dot_Timer_Count = cwSpeed*3;
else Dot_Timer_Count = cwSpeed;
key(Dot_Timer_Count);
p = p / 2 ;
}
delay(cwSpeed*5) ;
return ;
}
}
}
void sendmsg(char *str){
while (*str) send(*str++);
delay(650);
stopTx();
}
*/

View File

@ -1,369 +0,0 @@
/**
CW Keyer
CW Key logic change with ron's code (ubitx_keyer.cpp)
Ron's logic has been modified to work with the original uBITX by KD8CEC
Original Comment ----------------------------------------------------------------------------
* The CW keyer handles either a straight key or an iambic / paddle key.
* They all use just one analog input line. This is how it works.
* The analog line has the internal pull-up resistor enabled.
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
* When a paddle is connected, the dot and the dash are connected to the analog pin through
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
* So, the readings are as follows :
* 0v - straight key
* 1-2.5 v - paddle dot
* 2.5 to 4.5 v - paddle dash
* 2.0 to 0.5 v - dot and dash pressed
*
* The keyer is written to transparently handle all these cases
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
#define PADDLE_DOT 1
#define PADDLE_DASH 2
#define PADDLE_BOTH 3
#define PADDLE_STRAIGHT 4
//we store the last padde's character
//to alternatively send dots and dashes
//when both are simultaneously pressed
char lastPaddle = 0;
//reads the analog keyer pin and reports the paddle
byte getPaddle(){
int paddle = analogRead(ANALOG_KEYER);
if (paddle > 800) // above 4v is up
return 0;
if (paddle > 600) // 4-3v is dot
return PADDLE_DASH;
else if (paddle > 300) //1-2v is dash
return PADDLE_DOT;
else if (paddle > 50)
return PADDLE_BOTH; //both are between 1 and 2v
else
return PADDLE_STRAIGHT; //less than 1v is the straight key
}
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(){
keyDown = 1; //tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* Stops the cw carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(){
keyDown = 0; //tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
//Variables for Ron's new logic
#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
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
static unsigned long ktimer;
unsigned char keyerState = IDLE;
//Below is a test to reduce the keying error. do not delete lines
//create by KD8CEC for compatible with new CW Logic
char update_PaddleLatch(byte isUpdateKeyState) {
unsigned char tmpKeyerControl = 0;
int paddle = analogRead(ANALOG_KEYER);
if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
tmpKeyerControl |= DAH_L;
else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
tmpKeyerControl |= DIT_L;
else if (paddle >= cwAdcBothFrom && paddle <= cwAdcBothTo)
tmpKeyerControl |= (DAH_L | DIT_L) ;
else
{
if (Iambic_Key)
tmpKeyerControl = 0 ;
else if (paddle >= cwAdcSTFrom && paddle <= cwAdcSTTo)
tmpKeyerControl = DIT_L ;
else
tmpKeyerControl = 0 ;
}
if (isUpdateKeyState == 1)
keyerControl |= tmpKeyerControl;
return tmpKeyerControl;
}
/*****************************************************************************
// New logic, by RON
// modified by KD8CEC
******************************************************************************/
void cwKeyer(void){
lastPaddle = 0;
bool continue_loop = true;
unsigned tmpKeyControl = 0;
if( Iambic_Key ) {
while(continue_loop) {
switch (keyerState) {
case IDLE:
tmpKeyControl = update_PaddleLatch(0);
if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
update_PaddleLatch(1);
keyerState = CHK_DIT;
}else{
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
stopTx();
}
continue_loop = false;
}
break;
case CHK_DIT:
if (keyerControl & DIT_L) {
keyerControl |= DIT_PROC;
ktimer = cwSpeed;
keyerState = KEYED_PREP;
}else{
keyerState = CHK_DAH;
}
break;
case CHK_DAH:
if (keyerControl & DAH_L) {
ktimer = cwSpeed*3;
keyerState = KEYED_PREP;
}else{
keyerState = IDLE;
}
break;
case KEYED_PREP:
//modified KD8CEC
/*
ktimer += millis(); // set ktimer to interval end time
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
*/
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
ktimer += millis(); // set ktimer to interval end time
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
cwKeydown();
break;
case KEYED:
if (millis() > ktimer) { // are we at end of key down ?
cwKeyUp();
ktimer = millis() + cwSpeed; // inter-element time
keyerState = INTER_ELEMENT; // next state
}else if (keyerControl & IAMBICB) {
update_PaddleLatch(1); // early paddle latch in Iambic B mode
}
break;
case INTER_ELEMENT:
// Insert time between dits/dahs
update_PaddleLatch(1); // 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
}else{
keyerControl &= ~(DAH_L); // clear dah latch
keyerState = IDLE; // go idle
}
}
break;
}
Check_Cat(2);
} //end of while
}
else{
while(1){
if (update_PaddleLatch(0) == DIT_L) {
// if we are here, it is only because the key is pressed
if (!inTx){
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
startTx(TX_CW, 1);
}
cwKeydown();
while ( update_PaddleLatch(0) == DIT_L )
delay_background(1, 3);
cwKeyUp();
}
else{
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
//if (!cwTimeout) //removed by KD8CEC
// return;
// got back to the beginning of the loop, if no further activity happens on straight key
// we will time out, and return out of this routine
//delay(5);
//delay_background(5, 3); //removed by KD8CEC
//continue; //removed by KD8CEC
return; //Tx stop control by Main Loop
}
Check_Cat(2);
} //end of while
} //end of elese
}
//=======================================================================================
//Before logic
//by Farhan and modified by KD8CEC
//======================================================================================
/**
* The keyer handles the straight key as well as the iambic key
* This module keeps looping until the user stops sending cw
* if the cwTimeout is set to 0, then it means, we have to exit the keyer loop
* Each time the key is hit the cwTimeout is pushed to a time in the future by cwKeyDown()
*/
/*
void cwKeyer(){
byte paddle;
lastPaddle = 0;
while(1){
paddle = getPaddle();
// do nothing if the paddle has not been touched, unless
// we are in the cw mode and we have timed out
if (!paddle){
//modifed by KD8CEC for auto CW Send
if (isCWAutoMode > 1) //if while auto cw sending, dont stop tx by paddle position
return;
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
if (!cwTimeout)
return;
Check_Cat(2); //for uBITX on Raspberry pi, when straight keying, disconnect / test complete
continue;
}
//if while auto cw send, stop auto cw
//but isAutoCWHold for Manual Keying with cwAutoSend
if (isCWAutoMode > 1 && isAutoCWHold == 0)
isCWAutoMode = 1; //read status
//Remoark Debug code / Serial Use by CAT Protocol
//Serial.print("paddle:");Serial.println(paddle);
// if we are here, it is only because the key or the paddle is pressed
if (!inTx){
keyDown = 0;
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
}
// star the transmission)
// we store the transmitted character in the lastPaddle
cwKeydown();
if (paddle == PADDLE_DOT){
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
else if (paddle == PADDLE_DASH){
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}
else if (paddle == PADDLE_BOTH){ //both paddles down
//depending upon what was sent last, send the other
if (lastPaddle == PADDLE_DOT) {
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}else{
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
}
else if (paddle == PADDLE_STRAIGHT){
while (getPaddle() == PADDLE_STRAIGHT) {
delay(1);
Check_Cat(2);
}
lastPaddle = PADDLE_STRAIGHT;
}
cwKeyUp();
//introduce a dot long gap between characters if the keyer was used
if (lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed);
}
}
*/

View File

@ -93,7 +93,7 @@ char L_ritOn;
unsigned long L_ritTxFrequency; //ritTxFrequency unsigned long L_ritTxFrequency; //ritTxFrequency
#define CMD_IS_TX 't' //ct #define CMD_IS_TX 't' //ct
char L_inTx; bool L_inTx;
#define CMD_IS_DIALLOCK 'l' //cl #define CMD_IS_DIALLOCK 'l' //cl
byte L_isDialLock; //byte isDialLock byte L_isDialLock; //byte isDialLock

View File

@ -8,6 +8,10 @@ Ian KD8CEC
#include "ubitx.h" #include "ubitx.h"
#include "ubitx_eemap.h" #include "ubitx_eemap.h"
extern void cwKeydown();
extern void cwKeyUp();
extern volatile bool keyDown;
//Current Frequency and mode to active VFO by KD8CEC //Current Frequency and mode to active VFO by KD8CEC
void FrequencyToVFO(byte isSaveFreq) void FrequencyToVFO(byte isSaveFreq)
{ {

View File

@ -145,9 +145,9 @@ void si5351_set_calibration(int32_t cal){
void SetCarrierFreq() void SetCarrierFreq()
{ {
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0)); unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (!inTx) ? ifShiftValue : 0));
//si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier)); //si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier));
si5351bx_setfreq(0, ((sdrModeOn && (inTx == 0)) ? 0 : appliedCarrier)); //found bug by KG4GEK si5351bx_setfreq(0, ((sdrModeOn && (!inTx)) ? 0 : appliedCarrier)); //found bug by KG4GEK
/* /*