added ubitx_keyer.cpp from W0EB Raduino I2C

This commit is contained in:
Rob French 2022-03-17 19:59:02 -05:00
parent 89af919e42
commit 909b40e165

334
ubitx_20/ubitx_keyer.cpp Normal file
View File

@ -0,0 +1,334 @@
/**
* 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 <Arduino.h>
#include "ubitx.h"
extern void stopTx(void);
extern void startTx(byte txMode);
extern void updateDisplay(void);
extern void printLine2(char *c);
extern void printLine3(char *c);
extern void printLine4(char *c);
extern unsigned long sideTone;
extern int cwSpeed;
extern long CW_TIMEOUT;
extern volatile bool inTx;
extern volatile int ubitx_mode;
extern volatile unsigned char keyerControl;
extern volatile unsigned char keyerState;
extern unsigned volatile char IAMBIC;
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;
/**
* 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) {
bool continue_loop = true;
// timer for voltage display
if ( Ubitx_Voltage_Timer <= 0 ){
Ubitx_Voltage_Timer = Ubitx_Voltage_Timer_Count;
Ubitx_Voltage_Act = true;
}else Ubitx_Voltage_Timer = Ubitx_Voltage_Timer - 1;
// process if CW modes
if( (ubitx_mode == MODE_CW)||(ubitx_mode == MODE_CWR)){
// 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 & IAMBIC) {
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( 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)&&(Cat_Lock == false )&&(TX_In_Progress == false)){
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
stopTx();
}else last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
}
}
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();
}