Compare commits
No commits in common. "mode-based-rig" and "master" have entirely different histories.
mode-based
...
master
@ -1 +0,0 @@
|
||||
../TeensyDSP/Debug.h
|
@ -1,4 +1,4 @@
|
||||
//Firmware Version
|
||||
//Firmware Version
|
||||
//+ : This symbol identifies the firmware.
|
||||
// It was originally called 'CEC V1.072' but it is too long to waste the LCD window.
|
||||
// I do not want to make this Firmware users's uBITX messy with my callsign.
|
||||
@ -122,8 +122,7 @@ char vfoActive = VFO_A;
|
||||
int8_t meter_reading = 0; // a -1 on meter makes it invisible
|
||||
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier, cwmCarrier;
|
||||
unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life
|
||||
unsigned long frequency;
|
||||
unsigned long ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
|
||||
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
|
||||
|
||||
unsigned int cwSpeed = 100; //this is actuall the dot period in milliseconds
|
||||
extern int32_t calibration;
|
||||
@ -317,17 +316,6 @@ unsigned long delayBeforeTime = 0;
|
||||
byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle
|
||||
delayBeforeTime = millis();
|
||||
|
||||
/*
|
||||
* KC4UPR - IOP review, 2020-05-03
|
||||
*
|
||||
* I don't see anything in here that is either important to, or will adversely affect, IOP
|
||||
* operation. I'm not planning on using the uBITX autokeyer (since all keying will be in the
|
||||
* IOP), so neither getPaddle() nor autoSendPTTCheck() will be issues. I do need to look into
|
||||
* overall CAT operation, in general.
|
||||
*
|
||||
* UPDATE: Fixed getPaddle() to be compatible.
|
||||
*/
|
||||
|
||||
while (millis() - delayBeforeTime <= delayTime) {
|
||||
|
||||
if (fromType == 4)
|
||||
@ -337,14 +325,14 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
|
||||
return 1;
|
||||
|
||||
//Check PTT while auto Sending
|
||||
//autoSendPTTCheck();
|
||||
autoSendPTTCheck();
|
||||
|
||||
//Check_Cat(3);
|
||||
Check_Cat(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Background Work
|
||||
//Check_Cat(fromType);
|
||||
Check_Cat(fromType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,10 +678,6 @@ void ritDisable(){
|
||||
*/
|
||||
|
||||
void checkPTT(){
|
||||
/*
|
||||
* KC4UPR - note that some of this is superfluous now that checkPTT() is only executed
|
||||
* in SSB mode, and cwKeyer is only executed in CW mode...
|
||||
*/
|
||||
//we don't check for ptt when transmitting cw
|
||||
if (cwTimeout > 0)
|
||||
return;
|
||||
@ -806,7 +790,7 @@ void checkButton(){
|
||||
//wait for the button to go up again
|
||||
while(keyStatus == getBtnStatus()) {
|
||||
delay(10);
|
||||
//Check_Cat(0);
|
||||
Check_Cat(0);
|
||||
}
|
||||
//delay(50);//debounce
|
||||
}
|
||||
@ -825,7 +809,7 @@ void checkButton(){
|
||||
//wait for the button to go up again
|
||||
while(btnDown()) {
|
||||
delay(10);
|
||||
//Check_Cat(0);
|
||||
Check_Cat(0);
|
||||
}
|
||||
//delay(50);//debounce
|
||||
}
|
||||
@ -1402,8 +1386,7 @@ void setup()
|
||||
//printLineF(1, FIRMWARE_VERSION_INFO);
|
||||
DisplayVersionInfo(FIRMWARE_VERSION_INFO);
|
||||
|
||||
//Init_Cat(38400, SERIAL_8N1);
|
||||
Serial.begin(38400);
|
||||
Init_Cat(38400, SERIAL_8N1);
|
||||
initSettings();
|
||||
initPorts();
|
||||
|
||||
@ -1449,7 +1432,6 @@ void setup()
|
||||
factory_alignment();
|
||||
#endif
|
||||
|
||||
rigState.begin();
|
||||
}
|
||||
|
||||
//Auto save Frequency and Mode with Protected eeprom life by KD8CEC
|
||||
@ -1477,35 +1459,15 @@ void checkAutoSaveFreqMode()
|
||||
}
|
||||
|
||||
void loop(){
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Getting rid of the autokeyer code... not planning on using, since any autokeying
|
||||
* would actually be done by the IOP. We'll check the PTT, but only in SSB mode
|
||||
* (same line as CW, so it would be caught by cwKeyer() in CW mode).
|
||||
*
|
||||
* Only check the CW keyer if we are in one of the CW modes. Why? Because we
|
||||
* are using the same input for PTT and CW.
|
||||
*/
|
||||
// if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
|
||||
// if (!txCAT)
|
||||
// checkPTT();
|
||||
// checkButton();
|
||||
// }
|
||||
// else
|
||||
// controlAutoCW();
|
||||
// KC4UPR: Note, implementation below leaves no manual way to abort TX due to CAT. May
|
||||
// want to add in a way to interrupt CAT transmission with a PTT/CW event.
|
||||
//if (!txCAT) {
|
||||
if (cwMode == 0) {
|
||||
if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
|
||||
if (!txCAT)
|
||||
checkPTT();
|
||||
} else {
|
||||
cwKeyer();
|
||||
}
|
||||
checkButton();
|
||||
//}
|
||||
}
|
||||
else
|
||||
controlAutoCW();
|
||||
|
||||
//cwKeyer();
|
||||
cwKeyer();
|
||||
|
||||
//tune only when not tranmsitting
|
||||
if (!inTx){
|
||||
@ -1525,7 +1487,7 @@ void loop(){
|
||||
} //end of check TX Status
|
||||
|
||||
//we check CAT after the encoder as it might put the radio into TX
|
||||
//Check_Cat(inTx? 1 : 0);
|
||||
Check_Cat(inTx? 1 : 0);
|
||||
|
||||
//for SEND SW Serial
|
||||
#ifdef USE_SW_SERIAL
|
||||
|
@ -1 +0,0 @@
|
||||
../TeensyDSP/RigState.cpp
|
@ -1 +0,0 @@
|
||||
../TeensyDSP/RigState.h
|
@ -19,13 +19,11 @@
|
||||
|
||||
#include <Arduino.h> //for Linux, On Linux it is case sensitive.
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
//==============================================================================
|
||||
// Compile Option
|
||||
//==============================================================================
|
||||
//Ubitx Board Version
|
||||
#define UBITX_BOARD_VERSION 5 //v1 ~ v4 : 4, v5: 5
|
||||
#define UBITX_BOARD_VERSION 2 //v1 ~ v4 : 4, v5: 5
|
||||
|
||||
//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below.
|
||||
//You must select only one.
|
||||
@ -50,8 +48,8 @@
|
||||
//#define USE_CUSTOM_LPF_FILTER //LPF FILTER MOD
|
||||
|
||||
//#define ENABLE_FACTORYALIGN
|
||||
//#define FACTORY_RECOVERY_BOOTUP //Whether to enter Factory Recovery mode by pressing FKey and turning on power
|
||||
//#define ENABLE_ADCMONITOR //Starting with Version 1.07, you can read ADC values directly from uBITX Manager. So this function is not necessary.
|
||||
#define FACTORY_RECOVERY_BOOTUP //Whether to enter Factory Recovery mode by pressing FKey and turning on power
|
||||
#define ENABLE_ADCMONITOR //Starting with Version 1.07, you can read ADC values directly from uBITX Manager. So this function is not necessary.
|
||||
|
||||
extern byte I2C_LCD_MASTER_ADDRESS; //0x27 //if Set I2C Address by uBITX Manager, read from EEProm
|
||||
extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
|
||||
@ -255,12 +253,6 @@ extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
|
||||
#define I2CMETER_CALCR 0x55 //Calculated SWR Meter
|
||||
#define I2CMETER_UNCALCR 0x54 //Uncalculated SWR Meter
|
||||
|
||||
// Raduino<=>TeensyDSP data exchange
|
||||
#define I2CMETER_RIGINF 0x50
|
||||
|
||||
// Raduino requests any CAT updates from TeensyDSP
|
||||
//#define I2CMETER_REQCAT 0x51
|
||||
|
||||
//==============================================================================
|
||||
// for public, Variable, functions
|
||||
//==============================================================================
|
||||
|
@ -39,22 +39,6 @@ char lastPaddle = 0;
|
||||
|
||||
//reads the analog keyer pin and reports the paddle
|
||||
byte getPaddle(){
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* (1) It uses the PTT input line.
|
||||
*
|
||||
* (2) It's always "straight key" mode (the IOP provides the keyer).
|
||||
*/
|
||||
|
||||
if (digitalRead(PTT) == 1) // key/PTT is up
|
||||
return 0;
|
||||
else
|
||||
return PADDLE_STRAIGHT;
|
||||
|
||||
/*
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
|
||||
if (paddle > 800) // above 4v is up
|
||||
@ -68,7 +52,6 @@ byte getPaddle(){
|
||||
return PADDLE_BOTH; //both are between 1 and 2v
|
||||
else
|
||||
return PADDLE_STRAIGHT; //less than 1v is the straight key
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,17 +96,6 @@ 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) {
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* No iambic keyer. It's always "straight key" based on the IOP.
|
||||
*
|
||||
* It uses the PTT line.
|
||||
*/
|
||||
return (digitalRead(PTT) ? 0 : DIT_L);
|
||||
/*
|
||||
unsigned char tmpKeyerControl = 0;
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
|
||||
@ -147,7 +119,6 @@ char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
keyerControl |= tmpKeyerControl;
|
||||
|
||||
return tmpKeyerControl;
|
||||
*/
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -155,113 +126,106 @@ char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
// modified by KD8CEC
|
||||
******************************************************************************/
|
||||
void cwKeyer(void){
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* No iambic keyer. It's always "straight key" based on the IOP.
|
||||
*/
|
||||
// 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{
|
||||
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
|
||||
@ -296,9 +260,9 @@ void cwKeyer(void){
|
||||
return; //Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
//Check_Cat(2);
|
||||
Check_Cat(2);
|
||||
} //end of while
|
||||
// } //end of elese
|
||||
} //end of elese
|
||||
}
|
||||
|
||||
|
||||
@ -401,3 +365,5 @@ void cwKeyer(){
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
@ -993,14 +993,6 @@ char checkCountSMeter = 0;
|
||||
//execute interval : 0.25sec
|
||||
void idle_process()
|
||||
{
|
||||
// KC4UPR 2021-02-05 added update process for Raduino-TeensyDSP coordination
|
||||
rigState.send_RIGINF();
|
||||
delay(1);
|
||||
rigState.receive_RIGINF();
|
||||
//updateStateFromRaduino(rigState);
|
||||
//doRaduinoToTeensy(&rigState);
|
||||
//updateRaduinoFromState(rigState);
|
||||
|
||||
//S-Meter Display
|
||||
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
|
||||
{
|
||||
|
@ -263,7 +263,7 @@ void menuCHMemory(int btn, byte isMemoryToVfo){
|
||||
}
|
||||
}
|
||||
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
} //end of while (knob)
|
||||
|
||||
if (selectChannel < 20 && selectChannel >= 0)
|
||||
@ -697,7 +697,7 @@ int getValueByKnob(int valueType, int targetValue, int minKnobValue, int maxKnob
|
||||
}
|
||||
}
|
||||
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
}
|
||||
|
||||
return targetValue;
|
||||
@ -1290,7 +1290,7 @@ void doMenu(){
|
||||
default :
|
||||
menuExit(btnState); break;
|
||||
} //end of switch
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
} //end of while
|
||||
|
||||
//****************************************************************************
|
||||
@ -1690,7 +1690,7 @@ void menuSetupCarrier(int btn){
|
||||
si5351bx_setfreq(0, usbCarrier);
|
||||
printCarrierFreq(usbCarrier);
|
||||
|
||||
//Check_Cat(0); //To prevent disconnections
|
||||
Check_Cat(0); //To prevent disconnections
|
||||
delay(100);
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,6 @@ const PROGMEM uint8_t meters_bitmap[] = {
|
||||
};
|
||||
*/
|
||||
|
||||
//#include "RigState.h"
|
||||
|
||||
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
|
||||
|
||||
#ifdef OPTION_SKINNYBARS //We want skninny bars with more text
|
||||
@ -298,4 +296,4 @@ int GetI2CSmeterValue(int valueType)
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
@ -1,342 +0,0 @@
|
||||
EESchema-LIBRARY Version 2.4
|
||||
#encoding utf-8
|
||||
#
|
||||
# Amplifier_Operational_LM324A
|
||||
#
|
||||
DEF Amplifier_Operational_LM324A U 0 5 Y Y 5 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_LM324A" 0 -200 50 H V L CNN
|
||||
F2 "" -50 100 50 H I C CNN
|
||||
F3 "" 50 200 50 H I C CNN
|
||||
ALIAS LM324 TLC274 TLC279 TL074 LM324A MCP6004 TL084 TL064 LMV324 LMC6484 MCP604 MC33079 MC33174 MC33179 OPA1604 OPA1679 OPA4134 OPA4340UA OPA4376 MCP6L94 TSV914 ADA4807-4 TSV994
|
||||
$FPLIST
|
||||
SOIC*3.9x8.7mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TSSOP*4.4x5mm*P0.65mm*
|
||||
SSOP*5.3x6.2mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.5mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 3 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 4 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X + 10 -300 100 100 R 50 50 3 1 I
|
||||
X ~ 8 300 0 100 L 50 50 3 1 O
|
||||
X - 9 -300 -100 100 R 50 50 3 1 I
|
||||
X + 12 -300 100 100 R 50 50 4 1 I
|
||||
X - 13 -300 -100 100 R 50 50 4 1 I
|
||||
X ~ 14 300 0 100 L 50 50 4 1 O
|
||||
X V- 11 -100 -300 150 U 50 50 5 1 W
|
||||
X V+ 4 -100 300 150 D 50 50 5 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Amplifier_Operational_LM358
|
||||
#
|
||||
DEF Amplifier_Operational_LM358 U 0 5 Y Y 3 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_LM358" 0 -200 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
SOIC*3.9x4.9mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TO*99*
|
||||
OnSemi*Micro8*
|
||||
TSSOP*3x3mm*P0.65mm*
|
||||
TSSOP*4.4x3mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.65mm*
|
||||
SSOP*3.9x4.9mm*P0.635mm*
|
||||
LFCSP*2x2mm*P0.5mm*
|
||||
*SIP*
|
||||
SOIC*5.3x6.2mm*P1.27mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X V- 4 -100 -300 150 U 50 50 3 1 W
|
||||
X V+ 8 -100 300 150 D 50 50 3 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Amplifier_Operational_TL072
|
||||
#
|
||||
DEF Amplifier_Operational_TL072 U 0 5 Y Y 3 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_TL072" 0 -200 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
ALIAS LM358 AD8620 LMC6062 LMC6082 TL062 TL072 TL082 NE5532 SA5532 RC4558 RC4560 RC4580 LMV358 TS912 TSV912IDT TSV912IST TLC272 TLC277 MCP602 OPA1678 OPA2134 OPA2340 OPA2376xxD OPA2376xxDGK MC33078 MC33178 LM4562 OP249 OP275 ADA4075-2 MCP6002-xP MCP6002-xSN MCP6002-xMS LM7332 OPA2333xxD OPA2333xxDGK LMC6482 LT1492 LTC6081xMS8 LM6172 MCP6L92 NJM2043 NJM2114 NJM4556A NJM4558 NJM4559 NJM4560 NJM4580 NJM5532 ADA4807-2ARM OPA2691 LT6234 OPA2356xxD OPA2356xxDGK OPA1612AxD MC33172 OPA1602 TLV2372 LT6237 OPA2277
|
||||
$FPLIST
|
||||
SOIC*3.9x4.9mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TO*99*
|
||||
OnSemi*Micro8*
|
||||
TSSOP*3x3mm*P0.65mm*
|
||||
TSSOP*4.4x3mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.65mm*
|
||||
SSOP*3.9x4.9mm*P0.635mm*
|
||||
LFCSP*2x2mm*P0.5mm*
|
||||
*SIP*
|
||||
SOIC*5.3x6.2mm*P1.27mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X V- 4 -100 -300 150 U 50 50 3 1 W
|
||||
X V+ 8 -100 300 150 D 50 50 3 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x02_Male
|
||||
#
|
||||
DEF Connector_Conn_01x02_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 100 50 H V C CNN
|
||||
F1 "Connector_Conn_01x02_Male" 0 -200 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
X Pin_1 1 200 0 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 -100 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x03_Male
|
||||
#
|
||||
DEF Connector_Conn_01x03_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 200 50 H V C CNN
|
||||
F1 "Connector_Conn_01x03_Male" 0 -200 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
S 34 105 0 95 1 1 6 F
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
P 2 1 1 6 50 100 34 100 N
|
||||
X Pin_1 1 200 100 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 0 150 L 50 50 1 1 P
|
||||
X Pin_3 3 200 -100 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x06_Male
|
||||
#
|
||||
DEF Connector_Conn_01x06_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 300 50 H V C CNN
|
||||
F1 "Connector_Conn_01x06_Male" 0 -400 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -295 0 -305 1 1 6 F
|
||||
S 34 -195 0 -205 1 1 6 F
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
S 34 105 0 95 1 1 6 F
|
||||
S 34 205 0 195 1 1 6 F
|
||||
P 2 1 1 6 50 -300 34 -300 N
|
||||
P 2 1 1 6 50 -200 34 -200 N
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
P 2 1 1 6 50 100 34 100 N
|
||||
P 2 1 1 6 50 200 34 200 N
|
||||
X Pin_1 1 200 200 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 100 150 L 50 50 1 1 P
|
||||
X Pin_3 3 200 0 150 L 50 50 1 1 P
|
||||
X Pin_4 4 200 -100 150 L 50 50 1 1 P
|
||||
X Pin_5 5 200 -200 150 L 50 50 1 1 P
|
||||
X Pin_6 6 200 -300 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_C
|
||||
#
|
||||
DEF Device_C C 0 10 N Y 1 F N
|
||||
F0 "C" 25 100 50 H V L CNN
|
||||
F1 "Device_C" 25 -100 50 H V L CNN
|
||||
F2 "" 38 -150 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
C_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 20 -80 -30 80 -30 N
|
||||
P 2 0 1 20 -80 30 80 30 N
|
||||
X ~ 1 0 150 110 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 110 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_CP1
|
||||
#
|
||||
DEF Device_CP1 C 0 10 N N 1 F N
|
||||
F0 "C" 25 100 50 H V L CNN
|
||||
F1 "Device_CP1" 25 -100 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
CP_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
A 0 -150 128 1287 513 0 1 20 N -80 -50 80 -50
|
||||
P 2 0 1 20 -80 30 80 30 N
|
||||
P 2 0 1 0 -70 90 -30 90 N
|
||||
P 2 0 1 0 -50 70 -50 110 N
|
||||
X ~ 1 0 150 110 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 130 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_D
|
||||
#
|
||||
DEF Device_D D 0 40 N N 1 F N
|
||||
F0 "D" 0 100 50 H V C CNN
|
||||
F1 "Device_D" 0 -100 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
TO-???*
|
||||
*_Diode_*
|
||||
*SingleDiode*
|
||||
D_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 8 -50 50 -50 -50 N
|
||||
P 2 0 1 0 50 0 -50 0 N
|
||||
P 4 0 1 8 50 50 50 -50 -50 0 50 50 N
|
||||
X K 1 -150 0 100 R 50 50 1 1 P
|
||||
X A 2 150 0 100 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_R_POT_US
|
||||
#
|
||||
DEF Device_R_POT_US RV 0 40 Y N 1 F N
|
||||
F0 "RV" -175 0 50 V V C CNN
|
||||
F1 "Device_R_POT_US" -100 0 50 V V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Potentiometer*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 0 0 -90 0 -100 N
|
||||
P 2 0 1 0 0 100 0 90 N
|
||||
P 2 0 1 0 100 0 60 0 N
|
||||
P 4 0 1 0 45 0 90 20 90 -20 45 0 F
|
||||
P 5 0 1 0 0 -30 40 -45 0 -60 -40 -75 0 -90 N
|
||||
P 5 0 1 0 0 30 40 15 0 0 -40 -15 0 -30 N
|
||||
P 5 0 1 0 0 90 40 75 0 60 -40 45 0 30 N
|
||||
X 1 1 0 150 50 D 50 50 1 1 P
|
||||
X 2 2 150 0 50 L 50 50 1 1 P
|
||||
X 3 3 0 -150 50 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_R_US
|
||||
#
|
||||
DEF Device_R_US R 0 0 N Y 1 F N
|
||||
F0 "R" 100 0 50 V V C CNN
|
||||
F1 "Device_R_US" -100 0 50 V V C CNN
|
||||
F2 "" 40 -10 50 V I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
R_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 0 0 -90 0 -100 N
|
||||
P 2 0 1 0 0 90 0 100 N
|
||||
P 5 0 1 0 0 -30 40 -45 0 -60 -40 -75 0 -90 N
|
||||
P 5 0 1 0 0 30 40 15 0 0 -40 -15 0 -30 N
|
||||
P 5 0 1 0 0 90 40 75 0 60 -40 45 0 30 N
|
||||
X ~ 1 0 150 50 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 50 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Transistor_BJT_PN2222A
|
||||
#
|
||||
DEF Transistor_BJT_PN2222A Q 0 0 Y N 1 F N
|
||||
F0 "Q" 200 75 50 H V L CNN
|
||||
F1 "Transistor_BJT_PN2222A" 200 0 50 H V L CNN
|
||||
F2 "Package_TO_SOT_THT:TO-92_Inline" 200 -75 50 H I L CIN
|
||||
F3 "" 0 0 50 H I L CNN
|
||||
$FPLIST
|
||||
TO?92*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
C 50 0 111 0 1 10 N
|
||||
P 2 0 1 0 0 0 25 0 N
|
||||
P 2 0 1 0 100 -100 25 -25 N
|
||||
P 2 0 1 0 100 100 25 25 N
|
||||
P 3 0 1 20 25 75 25 -75 25 -75 N
|
||||
P 3 0 1 0 95 -95 75 -75 75 -75 N
|
||||
P 5 0 1 0 45 -65 65 -45 85 -85 45 -65 45 -65 F
|
||||
X E 1 100 -200 100 U 50 50 1 1 P
|
||||
X B 2 -200 0 200 R 50 50 1 1 I
|
||||
X C 3 100 200 100 D 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# power_+5V
|
||||
#
|
||||
DEF power_+5V #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -150 50 H I C CNN
|
||||
F1 "power_+5V" 0 140 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
P 2 0 1 0 -30 50 0 100 N
|
||||
P 2 0 1 0 0 0 0 100 N
|
||||
P 2 0 1 0 0 100 30 50 N
|
||||
X +5V 1 0 0 0 U 50 50 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# power_GND
|
||||
#
|
||||
DEF power_GND #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -250 50 H I C CNN
|
||||
F1 "power_GND" 0 -150 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
|
||||
X GND 1 0 0 0 D 50 50 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
@ -1 +0,0 @@
|
||||
(kicad_pcb (version 4) (host kicad "dummy file") )
|
@ -1,33 +0,0 @@
|
||||
update=22/05/2015 07:44:53
|
||||
version=1
|
||||
last_client=kicad
|
||||
[general]
|
||||
version=1
|
||||
RootSch=
|
||||
BoardNm=
|
||||
[pcbnew]
|
||||
version=1
|
||||
LastNetListRead=
|
||||
UseCmpFile=1
|
||||
PadDrill=0.600000000000
|
||||
PadDrillOvalY=0.600000000000
|
||||
PadSizeH=1.500000000000
|
||||
PadSizeV=1.500000000000
|
||||
PcbTextSizeV=1.500000000000
|
||||
PcbTextSizeH=1.500000000000
|
||||
PcbTextThickness=0.300000000000
|
||||
ModuleTextSizeV=1.000000000000
|
||||
ModuleTextSizeH=1.000000000000
|
||||
ModuleTextSizeThickness=0.150000000000
|
||||
SolderMaskClearance=0.000000000000
|
||||
SolderMaskMinWidth=0.000000000000
|
||||
DrawSegmentWidth=0.200000000000
|
||||
BoardOutlineThickness=0.100000000000
|
||||
ModuleOutlineThickness=0.150000000000
|
||||
[cvpcb]
|
||||
version=1
|
||||
NetIExt=net
|
||||
[eeschema]
|
||||
version=1
|
||||
LibDir=
|
||||
[eeschema/libraries]
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
||||
EESchema Schematic File Version 4
|
||||
EELAYER 30 0
|
||||
EELAYER END
|
||||
$Descr A4 11693 8268
|
||||
encoding utf-8
|
||||
Sheet 2 2
|
||||
Title ""
|
||||
Date ""
|
||||
Rev ""
|
||||
Comp ""
|
||||
Comment1 ""
|
||||
Comment2 ""
|
||||
Comment3 ""
|
||||
Comment4 ""
|
||||
$EndDescr
|
||||
$EndSCHEMATC
|
Binary file not shown.
@ -1,360 +0,0 @@
|
||||
//======================================================================
|
||||
// DSP.cpp
|
||||
//======================================================================
|
||||
|
||||
#include "DSP.h"
|
||||
|
||||
#include <i2c_t3.h>
|
||||
//#include <Wire.h>
|
||||
//#include <SPI.h>
|
||||
//#include <SD.h>
|
||||
//#include <SerialFlash.h>
|
||||
|
||||
#define RX_AUDIO_CH 0
|
||||
|
||||
const int txMicInChannel = TX_MIC_IN_CH;
|
||||
const int txLineInChannel = TX_LINE_IN_CH;
|
||||
const int txUSBInChannel = TX_USB_IN_CH;
|
||||
const int txNumChannels = TX_NUM_CHANNELS;
|
||||
|
||||
const int txLineInVOX = TX_LINE_IN_VOX;
|
||||
const int txUSBInLVOX = TX_USB_IN_L_VOX;
|
||||
const int txUSBInRVOX = TX_USB_IN_R_VOX;
|
||||
const int txNumVOX = TX_NUM_VOX;
|
||||
|
||||
|
||||
UBitxDSP DSP;
|
||||
|
||||
//static struct {
|
||||
|
||||
// GUItool: begin automatically generated code
|
||||
AudioInputUSB usbIn; //xy=153,341
|
||||
AudioInputI2S lineIn; //xy=161,233
|
||||
AudioAnalyzeRMS usbInRMS_R; //xy=276,431
|
||||
AudioAnalyzeRMS usbInRMS_L; //xy=335,392
|
||||
AudioAnalyzeRMS lineInRMS; //xy=387,273
|
||||
AudioMixer4 rxAudio; //xy=418,147
|
||||
AudioMixer4 txAudio; //xy=422,335
|
||||
AudioFilterFIR rxFilter; //xy=583,139
|
||||
AudioAmplifier usbOutAmp; //xy=748,135
|
||||
AudioAmplifier lineOutAmp; //xy=749,198
|
||||
AudioAmplifier usbBypassAmp; //xy=756,261
|
||||
AudioOutputI2S lineOut; //xy=966,330
|
||||
AudioOutputUSB usbOut; //xy=968,291
|
||||
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
|
||||
AudioConnection patchCord2(usbIn, 0, usbInRMS_L, 0);
|
||||
AudioConnection patchCord3(usbIn, 1, usbInRMS_R, 0);
|
||||
AudioConnection patchCord4(lineIn, 0, rxAudio, 0);
|
||||
AudioConnection patchCord5(lineIn, 1, txAudio, 0);
|
||||
AudioConnection patchCord6(lineIn, 1, lineInRMS, 0);
|
||||
AudioConnection patchCord7(rxAudio, rxFilter);
|
||||
AudioConnection patchCord8(rxAudio, usbBypassAmp);
|
||||
AudioConnection patchCord9(txAudio, 0, lineOut, 1);
|
||||
AudioConnection patchCord10(rxFilter, usbOutAmp);
|
||||
AudioConnection patchCord11(rxFilter, lineOutAmp);
|
||||
AudioConnection patchCord12(usbOutAmp, 0, usbOut, 0);
|
||||
AudioConnection patchCord13(lineOutAmp, 0, lineOut, 0);
|
||||
AudioConnection patchCord14(usbBypassAmp, 0, usbOut, 1);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=427,476
|
||||
// GUItool: end automatically generated code
|
||||
|
||||
//} audio;
|
||||
|
||||
UBitxDSP::UBitxDSP() {
|
||||
voxRMS[txLineInVOX] = &lineInRMS;
|
||||
voxRMS[txUSBInLVOX] = &usbInRMS_L;
|
||||
voxRMS[txUSBInRVOX] = &usbInRMS_R;
|
||||
}
|
||||
|
||||
void UBitxDSP::begin() {
|
||||
AudioMemory(16);
|
||||
audioCtrl.enable();
|
||||
audioCtrl.volume(0.0); // headphone volume...
|
||||
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == RX_AUDIO_CH)
|
||||
rxAudio.gain(i, 1.0);
|
||||
else
|
||||
rxAudio.gain(i, 0.0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
|
||||
// SETUP THE AUDIO INPUTS
|
||||
|
||||
// Rig (Line) Input (RX)
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
audioCtrl.unmuteLineout();
|
||||
audioCtrl.lineInLevel(9, 5); // RX, TX
|
||||
audioCtrl.lineOutLevel(29, 31); //RX, TX
|
||||
|
||||
// Mic Input (TX)
|
||||
audioCtrl.micGain(0); // TODO: set value
|
||||
|
||||
// Line Input (TX)
|
||||
|
||||
// USB Input (TX)
|
||||
|
||||
// SETUP THE AUDIO OUTPUTS
|
||||
|
||||
// Line Output (RX)
|
||||
lineOutAmp.gain(1.0);
|
||||
|
||||
// USB Output (RX)
|
||||
usbOutAmp.gain(1.0);
|
||||
usbBypassAmp.gain(1.0);
|
||||
|
||||
// Rig (Line) Output (TX)
|
||||
|
||||
// Default to RX.
|
||||
rx();
|
||||
|
||||
// Setup the VOX - clean this up
|
||||
state.voxActive[TX_LINE_IN_VOX] = false;
|
||||
state.voxThresh[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_THRESH;
|
||||
state.voxDelay[TX_LINE_IN_VOX] = TX_LINE_IN_VOX_DELAY;
|
||||
state.voxTimeout[TX_LINE_IN_VOX] = 0;
|
||||
state.voxActive[TX_USB_IN_L_VOX] = false;
|
||||
state.voxThresh[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_THRESH;
|
||||
state.voxDelay[TX_USB_IN_L_VOX] = TX_USB_IN_L_VOX_DELAY;
|
||||
state.voxTimeout[TX_USB_IN_L_VOX] = 0;
|
||||
state.voxActive[TX_USB_IN_R_VOX] = false;
|
||||
state.voxThresh[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_THRESH;
|
||||
state.voxDelay[TX_USB_IN_R_VOX] = TX_USB_IN_R_VOX_DELAY;
|
||||
state.voxTimeout[TX_USB_IN_R_VOX] = 0;
|
||||
|
||||
// Setup the RX Filter.
|
||||
setRxFilter(300, 3000);
|
||||
|
||||
sinceLastUpdate = 0;
|
||||
}
|
||||
|
||||
void UBitxDSP::update() {
|
||||
// Only going to adjust the USB volume periodically.
|
||||
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
|
||||
float vol = usbIn.volume();
|
||||
setTxInputLevel(txUSBInChannel, vol);
|
||||
sinceLastUpdate = 0;
|
||||
}
|
||||
|
||||
// Update the VOX switches.
|
||||
// TODO: Move the enable logic in here, so we don't process unnecessarily.
|
||||
for (int i = 0; i < txNumVOX; i++) {
|
||||
if (voxRMS[i]->available()) {
|
||||
float lvl = voxRMS[i]->read();
|
||||
if (lvl > state.voxThresh[i]) {
|
||||
state.voxTimeout[i] = millis() + state.voxDelay[i];
|
||||
state.voxActive[i] = true;
|
||||
}
|
||||
}
|
||||
if (millis() > state.voxTimeout[i]) {
|
||||
state.voxActive[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::end() {
|
||||
}
|
||||
|
||||
void UBitxDSP::rx() {
|
||||
// mute all tx audio
|
||||
audioCtrl.micGain(0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
// select line in for rx
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
// restore rx audio
|
||||
rxAudio.gain(RX_AUDIO_CH, 1.0); // restore the RX audio
|
||||
}
|
||||
|
||||
void UBitxDSP::txMicIn() {
|
||||
// mute the rx audio
|
||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
||||
// restore the tx mic audio
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||
audioCtrl.micGain(12);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == TX_MIC_IN_CH)
|
||||
txAudio.gain(i, 0.1);
|
||||
else
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::txLineIn() {
|
||||
// mute the rx audio
|
||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
||||
// restore the tx line in audio
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == TX_LINE_IN_CH)
|
||||
txAudio.gain(i, 0.1);
|
||||
else
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::txUSBIn() {
|
||||
// mute the rx audio
|
||||
rxAudio.gain(RX_AUDIO_CH, 0.0);
|
||||
// restore the tx usb in audio
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i == TX_USB_IN_CH)
|
||||
txAudio.gain(i, 0.1);
|
||||
else
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
// RX filter settings
|
||||
|
||||
const float minRxFilterLo = MIN_RX_FILTER_LO;
|
||||
const float maxRxFilterHi = MAX_RX_FILTER_HI;
|
||||
const float minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
||||
const float maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
||||
const float minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
||||
const float maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
||||
|
||||
/*!
|
||||
* @brief Bypass the RX audio filter.
|
||||
*/
|
||||
void UBitxDSP::bypassRxFilter() {
|
||||
rxFilter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the RX audio filter using the currently set low and
|
||||
* high frequencies. This is called by each of the public
|
||||
* filter methods to update the filter with new frequencies.
|
||||
*/
|
||||
void UBitxDSP::updateRxFilter() {
|
||||
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
|
||||
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilter(float lo, float hi) {
|
||||
if (hi < lo + minRxFilterWidth) {
|
||||
hi = lo + minRxFilterWidth;
|
||||
}
|
||||
if (hi > maxRxFilterHi) {
|
||||
hi = maxRxFilterHi;
|
||||
}
|
||||
if (lo > hi - minRxFilterWidth) {
|
||||
lo = hi - minRxFilterWidth;
|
||||
}
|
||||
if (lo < minRxFilterLo) {
|
||||
lo = minRxFilterLo;
|
||||
}
|
||||
state.rxFilterHi = hi;
|
||||
state.rxFilterLo = lo;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterLo(float lo) {
|
||||
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
||||
lo = state.rxFilterHi - minRxFilterWidth;
|
||||
}
|
||||
if (lo < minRxFilterLo) {
|
||||
lo = minRxFilterLo;
|
||||
}
|
||||
state.rxFilterLo = lo;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterHi(float hi) {
|
||||
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
||||
hi = state.rxFilterLo + minRxFilterWidth;
|
||||
}
|
||||
if (hi > maxRxFilterHi) {
|
||||
hi = maxRxFilterHi;
|
||||
}
|
||||
state.rxFilterHi = hi;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterWidth(float width) {
|
||||
if (width < minRxFilterWidth) {
|
||||
width = minRxFilterWidth;
|
||||
} else if (width > maxRxFilterWidth) {
|
||||
width = maxRxFilterWidth;
|
||||
}
|
||||
float center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
||||
float lo = center - (width / 2);
|
||||
float hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterCenter(float center) {
|
||||
if (center < minRxFilterCenter) {
|
||||
center = minRxFilterCenter;
|
||||
} else if (center > maxRxFilterCenter) {
|
||||
center = maxRxFilterCenter;
|
||||
}
|
||||
float width = state.rxFilterHi - state.rxFilterLo;
|
||||
float lo = center - (width / 2);
|
||||
float hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
// TX audio input settings
|
||||
|
||||
void UBitxDSP::setTxInputLevel(int ch, float lvl) {
|
||||
if ((ch > -1) && (ch < txNumChannels)) {
|
||||
state.txInLvl[ch] = lvl;
|
||||
float vol = lvl * float(state.txInEnable[ch] * state.txInTx[ch]);
|
||||
txAudio.gain(ch, vol);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::enableTxInput(int ch) {
|
||||
if ((ch > -1) && (ch < txNumChannels)) {
|
||||
state.txInEnable[ch] = 1;
|
||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
||||
txAudio.gain(ch, vol);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::disableTxInput(int ch) {
|
||||
if ((ch > -1) && (ch < txNumChannels)) {
|
||||
state.txInEnable[ch] = 0;
|
||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
||||
txAudio.gain(ch, vol);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::startTxInput(int ch) {
|
||||
if ((ch > -1) && (ch < txNumChannels)) {
|
||||
state.txInTx[ch] = 1;
|
||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
||||
txAudio.gain(ch, vol);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::stopTxInput(int ch) {
|
||||
if ((ch > -1) && (ch < txNumChannels)) {
|
||||
state.txInTx[ch] = 0;
|
||||
float vol = state.txInLvl[ch] * float(state.txInEnable[ch] * state.txInTx[ch]);
|
||||
txAudio.gain(ch, vol);
|
||||
}
|
||||
}
|
||||
|
||||
// VOX settings
|
||||
bool UBitxDSP::isVoxActive(int vox) {
|
||||
if ((vox > -1) && (vox < 3)) {
|
||||
return state.voxActive[vox];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
145
TeensyDSP/DSP.h
145
TeensyDSP/DSP.h
@ -1,145 +0,0 @@
|
||||
//======================================================================
|
||||
// DSP.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __DSP_h__
|
||||
#define __DSP_h__
|
||||
|
||||
#include <Audio.h>
|
||||
#include <dynamicFilters.h>
|
||||
#include "Debug.h"
|
||||
|
||||
#define MIN_RX_FILTER_LO 0.0
|
||||
#define MAX_RX_FILTER_HI 5000.0
|
||||
#define MIN_RX_FILTER_WIDTH 0.0
|
||||
#define MAX_RX_FILTER_WIDTH 5000.0
|
||||
#define MIN_RX_FILTER_CENTER 0.0
|
||||
#define MAX_RX_FILTER_CENTER 5000.0
|
||||
|
||||
#define DSP_MILLIS_PER_UPDATE 100
|
||||
|
||||
#define TX_MIC_IN_CH 0
|
||||
#define TX_LINE_IN_CH 0
|
||||
#define TX_USB_IN_CH 1
|
||||
#define TX_NUM_CHANNELS 2
|
||||
|
||||
#define TX_LINE_IN_VOX 0
|
||||
#define TX_USB_IN_L_VOX 1
|
||||
#define TX_USB_IN_R_VOX 2
|
||||
#define TX_NUM_VOX 3
|
||||
|
||||
#define TX_LINE_IN_VOX_THRESH 0.25
|
||||
#define TX_USB_IN_L_VOX_THRESH 0.25
|
||||
#define TX_USB_IN_R_VOX_THRESH 0.25
|
||||
|
||||
#define TX_LINE_IN_VOX_DELAY 500
|
||||
#define TX_USB_IN_L_VOX_DELAY 500
|
||||
#define TX_USB_IN_R_VOX_DELAY 500
|
||||
|
||||
struct DSPState {
|
||||
|
||||
// RX audio output settings
|
||||
|
||||
// RX filter settings
|
||||
float rxFilterLo = 300.0;
|
||||
float rxFilterHi = 3000.0;
|
||||
|
||||
// TX audio input settings
|
||||
float txInLvl[4] = {0.5, 0.5, 0.0, 0.0};
|
||||
int txInEnable[4] = {1, 1, 0, 0};
|
||||
int txInTx[4] = {0, 0, 0, 0};
|
||||
|
||||
// VOX settings
|
||||
bool voxActive[3];
|
||||
float voxThresh[3];
|
||||
unsigned voxDelay[3];
|
||||
unsigned voxTimeout[3];
|
||||
};
|
||||
|
||||
enum TRState {
|
||||
TRANSMIT,
|
||||
RECEIVE
|
||||
};
|
||||
|
||||
enum RxAudioIn {
|
||||
RIG_AUDIO
|
||||
};
|
||||
|
||||
enum TxAudioIn {
|
||||
MIC_IN,
|
||||
LINE_IN,
|
||||
USB_IN
|
||||
};
|
||||
|
||||
class UBitxDSP {
|
||||
public:
|
||||
UBitxDSP();
|
||||
void begin();
|
||||
void update();
|
||||
void end();
|
||||
void rx();
|
||||
void txMicIn();
|
||||
void txLineIn();
|
||||
void txUSBIn();
|
||||
|
||||
// RX audio output settings
|
||||
|
||||
// RX filter settings
|
||||
void bypassRxFilter();
|
||||
void setRxFilter(float lo, float hi);
|
||||
void setRxFilterLo(float lo);
|
||||
void setRxFilterHi(float hi);
|
||||
void setRxFilterWidth(float width);
|
||||
void setRxFilterCenter(float center);
|
||||
|
||||
/*!
|
||||
* @brief Get the current low frequency bound of the RX band pass filter.
|
||||
* @return The low frequency bound.
|
||||
*/
|
||||
inline int getRxFilterLo() { return state.rxFilterLo; }
|
||||
|
||||
/*!
|
||||
* @brief Get the current high frequency bound of the RX band pass filter.
|
||||
* @return The high frequency bound.
|
||||
*/
|
||||
inline int getRxFilterHi() { return state.rxFilterHi; }
|
||||
|
||||
/*!
|
||||
* @brief Get the current width of the RX band pass filter.
|
||||
* @return The filter width.
|
||||
*/
|
||||
inline int getRxFilterWidth() { return state.rxFilterHi - state.rxFilterLo; }
|
||||
|
||||
/*!
|
||||
* @brief Get the current center frequency of the RX band pass filter.
|
||||
* @return The center frequency.
|
||||
*/
|
||||
inline int getRxFilterCenter() { return (state.rxFilterHi + state.rxFilterLo) / 2; }
|
||||
|
||||
// TX audio input settings
|
||||
void setTxInputLevel(int ch, float lvl);
|
||||
void enableTxInput(int ch);
|
||||
void disableTxInput(int ch);
|
||||
void startTxInput(int ch);
|
||||
void stopTxInput(int ch);
|
||||
|
||||
// VOX settings
|
||||
bool isVoxActive(int vox);
|
||||
|
||||
private:
|
||||
void updateRxFilter();
|
||||
|
||||
DSPState state;
|
||||
short coefficients[NUM_COEFFICIENTS];
|
||||
elapsedMillis sinceLastUpdate;
|
||||
|
||||
AudioAnalyzeRMS* voxRMS[3];
|
||||
};
|
||||
|
||||
extern UBitxDSP DSP;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
@ -1,20 +0,0 @@
|
||||
#ifndef __Debug_h__
|
||||
#define __Debug_h__
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBGPRINT(MSG) do { Serial.print("DBG: "); Serial.print(MSG); } while (0)
|
||||
#define DBGPRINTLN(MSG) do { Serial.print("DBG: "); Serial.println(MSG); } while (0)
|
||||
#define DBGNEWLINE() do { Serial.println(); } while (0)
|
||||
#define DBGCMD(CMD) do { Serial.print("DBG: "); Serial.println(#CMD); CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do { CMD; } while (0)
|
||||
#else
|
||||
#define DBGPRINT(MSG) do {} while (0)
|
||||
#define DBGPRINTLN(MSG) do {} while (0)
|
||||
#define DBGNEWLINE() do {} while (0)
|
||||
#define DBGCMD(CMD) do { CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,186 +0,0 @@
|
||||
#ifndef __HamFuncs_h__
|
||||
#define __HamFuncs_h__
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef HF_PWR_DEFAULT_LOAD
|
||||
#define HF_PWR_DEFAULT_LOAD 50.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_VSWR_MAX_REPORTED
|
||||
#define HF_VSWR_MAX_REPORTED 9.9
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_FWD_VRECT
|
||||
#define HF_BRIDGE_FWD_VRECT 0.25
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_FWD_TURNS
|
||||
#define HF_BRIDGE_FWD_TURNS 10.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_REV_VRECT
|
||||
#define HF_BRIDGE_REV_VRECT 0.25
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_REV_TURNS
|
||||
#define HF_BRIDGE_REV_TURNS 10.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_ADC_DEFAULT_BITS
|
||||
#define HF_ADC_DEFAULT_BITS 10
|
||||
#endif
|
||||
|
||||
#ifndef HF_ADC_DEFAULT_VREF
|
||||
#define HF_ADC_DEFAULT_VREF 3.3
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
namespace HF {
|
||||
|
||||
const float pwrDefaultLoad = HF_PWR_DEFAULT_LOAD;
|
||||
const float vswrMaxReported = HF_VSWR_MAX_REPORTED;
|
||||
const float bridgeFwdVrect = HF_BRIDGE_FWD_VRECT;
|
||||
const float bridgeFwdTurns = HF_BRIDGE_FWD_TURNS;
|
||||
const float bridgeRevVrect = HF_BRIDGE_REV_VRECT;
|
||||
const float bridgeRevTurns = HF_BRIDGE_REV_TURNS;
|
||||
const unsigned adcDefaultBits = HF_ADC_DEFAULT_BITS;
|
||||
const float adcDefaultVref = HF_ADC_DEFAULT_VREF;
|
||||
|
||||
const float rms = sqrt(2.0) / 2.0;
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Calculate the output voltage of a resistive divider
|
||||
* network, given the input voltage and the values of the
|
||||
* resistors. The input voltage is applied to R1, the output
|
||||
* voltage is taken from the junction of R1 and R2, and R2 is
|
||||
* connected to ground.
|
||||
* @param Vin
|
||||
* Input voltage.
|
||||
* @param R1
|
||||
* Input resistor (ohms). Input voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @param R2
|
||||
* Output resistor (ohms). Output voltage is measured
|
||||
* between the top of this resistor and ground.
|
||||
* @return Output voltage.
|
||||
*/
|
||||
inline float divOut(float Vin, float R1, float R2) {
|
||||
return Vin * R2 / (R1 + R2);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate the input voltage of a resistive divider
|
||||
* network, given the output voltage and the values of the
|
||||
* resistors. The input voltage is applied to R1, the output
|
||||
* voltage is taken from the junction of R1 and R2, and R2 is
|
||||
* connected to ground.
|
||||
* @param Vout
|
||||
* Output voltage.
|
||||
* @param R1
|
||||
* Input resistor (ohms). Input voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @param R2
|
||||
* Output resistor (ohms). Output voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @return Input voltage.
|
||||
*/
|
||||
inline float divIn(float Vout, float R1, float R2) {
|
||||
return Vout * (R1 + R2) / R2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the power in watts, given a
|
||||
* resistance and the voltage across the resistance.
|
||||
* @param V
|
||||
* Voltage across the load.
|
||||
* @param R
|
||||
* (optional) Resistance of the load (ohms). If not provided,
|
||||
* a default is used (HF_PWR_DEFAULT_LOAD).
|
||||
* @return Power dissipated (watts). This is calculated as
|
||||
* P = V^2/R.
|
||||
*/
|
||||
inline float P(float V, float R = pwrDefaultLoad) {
|
||||
return (V * V) / R;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the Voltage Standing Wave Ratio
|
||||
* (VSWR) based on the given forward and reverse voltages.
|
||||
* @param Vfwd
|
||||
* Measured forward voltage.
|
||||
* @param Vrev
|
||||
* Measured reverse voltage.
|
||||
* @param VSWRmax
|
||||
* (optional) Maximum reported VSWR. The output will be
|
||||
* clamped to this value if necessary (HF_VSWR_MAX_REPORTED).
|
||||
* @return Voltage Standing Wave Ratio (VSWR). This is calculated
|
||||
* as VSWR = (Vfwd + Vrev) / (Vfwd - Vrev).
|
||||
*/
|
||||
inline float VSWR(float Vfwd, float Vrev, float VSWRmax = vswrMaxReported) {
|
||||
if (Vfwd - Vrev == 0.0) {
|
||||
return VSWRmax;
|
||||
} else {
|
||||
float swr = (Vfwd + Vrev) / (Vfwd - Vrev);
|
||||
return (swr > VSWRmax ? VSWRmax : swr);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the forward RMS input voltage across
|
||||
* a Stockton bridge.
|
||||
* @param Vout
|
||||
* Rectified output voltage (e.g. read via an ADC).
|
||||
* @param Vrect
|
||||
* (optional) Voltage drop across the rectifier diode. If
|
||||
* not provided, a default is used (HF_BRIDGE_FWD_VRECT).
|
||||
* @param turns
|
||||
* (optional) Coupling transformer turns ratio. If not
|
||||
* provided, a default is used (HF_BRIDGE_FWD_TURNS).
|
||||
* @return Input voltage (i.e. the actual forward voltage).
|
||||
*/
|
||||
inline float bridgeFwd(float Vout, float Vrect = bridgeFwdVrect, float turns = bridgeFwdTurns) {
|
||||
return (Vout + Vrect) * turns * rms;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the reverse RMS input voltage across
|
||||
* a Stockton bridge.
|
||||
* @param Vout
|
||||
* Rectified output voltage (e.g. read via an ADC).
|
||||
* @param Vrect
|
||||
* (optional) Voltage drop across the rectifier diode. If
|
||||
* not provided, a default is used (HF_BRIDGE_REV_VRECT).
|
||||
* @param turns
|
||||
* (optional) Coupling transformer turns ratio. If not
|
||||
* provided, a default is used (HF_BRIDGE_REV_TURNS).
|
||||
* @return Input voltage (i.e. the actual reverse voltage).
|
||||
*/
|
||||
inline float bridgeRev(float Vout, float Vrect = bridgeRevVrect, float turns = bridgeRevTurns) {
|
||||
return (Vout + Vrect) * turns * rms;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the input voltage to an Analog-to-
|
||||
* Digital Converter (ADC) given the resolution (number of
|
||||
* bits) and the voltage reference of the ADC.
|
||||
* @param counts
|
||||
* Value of the ADC measurement (in unitless counts).
|
||||
* @param res
|
||||
* (optional) Resolution (in bits) of the ADC. If not
|
||||
* provided, the default is used (HF_ADC_DEFAULT_BITS).
|
||||
* @param Vref
|
||||
* (optional) Voltage reference of the ADC. If not
|
||||
* provided, the default is used (HF_ADC_DEFAULT_VREF).
|
||||
* @return Input voltage to the ADC.
|
||||
*/
|
||||
inline float adcIn(unsigned counts, unsigned res = adcDefaultBits, float Vref = adcDefaultVref) {
|
||||
return float(counts) * Vref / float(1 << res);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
@ -1,188 +0,0 @@
|
||||
//======================================================================
|
||||
//
|
||||
// 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 };
|
||||
|
||||
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
|
||||
//======================================================================
|
@ -1,81 +0,0 @@
|
||||
//**********************************************************************
|
||||
//
|
||||
// Keyer, a part of nanoIO
|
||||
//
|
||||
// nanoIO paddle keyer (c) 2018, David Freese, W1HKJ
|
||||
//
|
||||
// based on code from Iambic Keyer Code Keyer Sketch
|
||||
// Copyright (c) 2009 Steven T. Elliott
|
||||
//
|
||||
// nanoIO is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// nanoIO 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//Revisions:
|
||||
//
|
||||
//1.0.0: Initial release
|
||||
//
|
||||
//**********************************************************************
|
||||
|
||||
|
||||
#ifndef __Keyer_h__
|
||||
#define __Keyer_h__
|
||||
|
||||
#define IAMBICA 0
|
||||
#define IAMBICB 1
|
||||
#define STRAIGHT 2
|
||||
|
||||
#define KEYER_LEFT_PADDLE_PIN 17
|
||||
#define KEYER_RIGHT_PADDLE_PIN 16
|
||||
|
||||
class UBitxKeyer
|
||||
{
|
||||
public:
|
||||
UBitxKeyer(int wpm, float weight);
|
||||
//void cw_pin(int pin);
|
||||
//void ptt_pin(int pin);
|
||||
void setWPM(int wpm);
|
||||
inline int getWPM() { return speed; }
|
||||
void setWeight(float weight);
|
||||
inline float getWeight() { return symWeight; }
|
||||
inline void setMode(int mode) { keyMode = mode; }
|
||||
inline int getMode() { return keyMode; }
|
||||
inline bool isDown() { return keyDown; }
|
||||
|
||||
bool doPaddles();
|
||||
|
||||
private:
|
||||
void calcRatio();
|
||||
void updatePaddleLatch();
|
||||
|
||||
bool keyDown;
|
||||
|
||||
long ktimer;
|
||||
|
||||
int speed;
|
||||
int dashLen; // Length of dash
|
||||
int dotLen; // Length of dot
|
||||
int spaceLen; // Length of space
|
||||
float symWeight;
|
||||
|
||||
char keyerControl;
|
||||
char keyerState;
|
||||
int keyMode;
|
||||
};
|
||||
|
||||
extern UBitxKeyer& Keyer;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
@ -1,141 +0,0 @@
|
||||
#include "Nextion.h"
|
||||
|
||||
char L_nowdisp = -1; //Sended nowdisp
|
||||
char L_vfoActive; //vfoActive
|
||||
unsigned long L_vfoCurr; //vfoA
|
||||
byte L_vfoCurr_mode; //vfoA_mode
|
||||
unsigned long L_vfoA; //vfoA
|
||||
byte L_vfoA_mode; //vfoA_mode
|
||||
unsigned long L_vfoB; //vfoB
|
||||
byte L_vfoB_mode; //vfoB_mode
|
||||
char L_ritOn;
|
||||
unsigned long L_ritTxFrequency; //ritTxFrequency
|
||||
char L_inTx;
|
||||
byte L_isDialLock; //byte isDialLock
|
||||
byte L_Split; //isTxType
|
||||
byte L_TXStop; //isTxType
|
||||
byte L_tuneStepIndex; //byte tuneStepIndex
|
||||
byte L_scaledSMeter; //scaledSMeter
|
||||
unsigned long L_sideTone; //sideTone
|
||||
byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
|
||||
unsigned int L_cwSpeed; //cwSpeed
|
||||
byte L_cwDelayTime; //cwDelayTime
|
||||
byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
|
||||
byte L_attLevel;
|
||||
byte L_isIFShift; //1 = ifShift, 2 extend
|
||||
int L_ifShiftValue;
|
||||
byte L_sdrModeOn;
|
||||
byte scaledSMeter = 0;
|
||||
float calcVSWR = 0.0;
|
||||
float L_calcVSWR = 0.0;
|
||||
byte scaledVSWR = 0;
|
||||
byte L_scaledVSWR = 0;
|
||||
float fwdPower = 0;
|
||||
float L_fwdPower = 0;
|
||||
float revPower = 0;
|
||||
float L_revPower = 0;
|
||||
|
||||
|
||||
//Control must have prefix 'v' or 's'
|
||||
char softSTRHeader[11] = {'p', 'm', '.', 's', '0', '.', 't', 'x', 't', '=', '\"'};
|
||||
char softINTHeader[10] = {'p', 'm', '.', 'v', '0', '.', 'v', 'a', 'l', '='};
|
||||
|
||||
char softTemp[20];
|
||||
|
||||
/*!
|
||||
@brief Send a string or numeric variable to the Nextion LCD.
|
||||
@param varType
|
||||
The type of the variable being sent to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendHeader(char varType, char varIndex)
|
||||
{
|
||||
if (varType == SWS_HEADER_STR_TYPE)
|
||||
{
|
||||
softSTRHeader[4] = varIndex;
|
||||
for (unsigned i = 0; i < sizeof(softSTRHeader)/sizeof(softSTRHeader[0]); i++)
|
||||
Serial1.write(softSTRHeader[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
softINTHeader[4] = varIndex;
|
||||
for (unsigned i = 0; i < sizeof(softINTHeader)/sizeof(softINTHeader[0]); i++)
|
||||
Serial1.write(softINTHeader[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send an unsigned long variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandUL(char varIndex, unsigned long sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
|
||||
|
||||
memset(softTemp, 0, 20);
|
||||
ultoa(sendValue, softTemp, DEC);
|
||||
Serial1.print(softTemp);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send a (signed) long variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandL(char varIndex, long sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
|
||||
|
||||
memset(softTemp, 0, 20);
|
||||
ltoa(sendValue, softTemp, DEC);
|
||||
Serial1.print(softTemp);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send a string variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandStr(char varIndex, const char* sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_STR_TYPE, varIndex);
|
||||
|
||||
Serial1.print(sendValue);
|
||||
Serial1.write('\"');
|
||||
Serial1.write(0xFF);
|
||||
Serial1.write(0xFF);
|
||||
Serial1.write(0xFF);
|
||||
}
|
||||
|
||||
unsigned char softBuff1Num[14] = {'p', 'm', '.', 'c', '0', '.', 'v', 'a', 'l', '=', 0, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
/*!
|
||||
@brief Send a single digit variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
Values 0~9 are: Mode, nowDisp, ActiveVFO, IsDialLock, IsTxtType, IsSplitType.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommand1Num(char varIndex, char sendValue)
|
||||
{
|
||||
softBuff1Num[4] = varIndex;
|
||||
softBuff1Num[10] = sendValue + 0x30; // convert to character digit
|
||||
|
||||
for (unsigned i = 0; i < sizeof(softBuff1Num)/sizeof(softBuff1Num[0]); i++)
|
||||
Serial1.write(softBuff1Num[i]);
|
||||
}
|
@ -1,126 +0,0 @@
|
||||
#ifndef __Nextion_h__
|
||||
#define __Nextion_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Debug.h"
|
||||
|
||||
#define SWS_HEADER_CHAR_TYPE 'c' //1Byte Protocol Prefix
|
||||
#define SWS_HEADER_INT_TYPE 'v' //Numeric Protocol Prefex
|
||||
#define SWS_HEADER_STR_TYPE 's' //for TEXT Line compatiable Character LCD Control
|
||||
|
||||
//===================================================================
|
||||
//Begin of Nextion LCD Protocol
|
||||
//
|
||||
// v0~v9, va~vz : Numeric (Transceiver -> Nextion LCD)
|
||||
// s0~s9 : String (Text) (Transceiver -> Nextion LCD)
|
||||
// vlSendxxx, vloxxx: Reserve for Nextion (Nextion LCD -> Transceiver)
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#define CMD_NOW_DISP '0' //c0
|
||||
extern char L_nowdisp; //Sended nowdisp
|
||||
|
||||
#define CMD_VFO_TYPE 'v' //cv
|
||||
extern char L_vfoActive; //vfoActive
|
||||
|
||||
#define CMD_CURR_FREQ 'c' //vc
|
||||
extern unsigned long L_vfoCurr; //vfoA
|
||||
#define CMD_CURR_MODE 'c' //cc
|
||||
extern byte L_vfoCurr_mode; //vfoA_mode
|
||||
|
||||
#define CMD_VFOA_FREQ 'a' //va
|
||||
extern unsigned long L_vfoA; //vfoA
|
||||
#define CMD_VFOA_MODE 'a' //ca
|
||||
extern byte L_vfoA_mode; //vfoA_mode
|
||||
|
||||
#define CMD_VFOB_FREQ 'b' //vb
|
||||
extern unsigned long L_vfoB; //vfoB
|
||||
#define CMD_VFOB_MODE 'b' //cb
|
||||
extern byte L_vfoB_mode; //vfoB_mode
|
||||
|
||||
#define CMD_IS_RIT 'r' //cr
|
||||
extern char L_ritOn;
|
||||
#define CMD_RIT_FREQ 'r' //vr
|
||||
extern unsigned long L_ritTxFrequency; //ritTxFrequency
|
||||
|
||||
#define CMD_IS_TX 't' //ct
|
||||
extern char L_inTx;
|
||||
|
||||
#define CMD_IS_DIALLOCK 'l' //cl
|
||||
extern byte L_isDialLock; //byte isDialLock
|
||||
|
||||
#define CMD_IS_SPLIT 's' //cs
|
||||
extern byte L_Split; //isTxType
|
||||
#define CMD_IS_TXSTOP 'x' //cx
|
||||
extern byte L_TXStop; //isTxType
|
||||
|
||||
#define CMD_TUNEINDEX 'n' //cn
|
||||
extern byte L_tuneStepIndex; //byte tuneStepIndex
|
||||
|
||||
#define CMD_SMETER 'p' //cs
|
||||
extern byte L_scaledSMeter; //scaledSMeter
|
||||
|
||||
#define CMD_SIDE_TONE 't' //vt
|
||||
extern unsigned long L_sideTone; //sideTone
|
||||
#define CMD_KEY_TYPE 'k' //ck
|
||||
extern byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
|
||||
|
||||
#define CMD_CW_SPEED 's' //vs
|
||||
extern unsigned int L_cwSpeed; //cwSpeed
|
||||
|
||||
#define CMD_CW_DELAY 'y' //vy
|
||||
extern byte L_cwDelayTime; //cwDelayTime
|
||||
|
||||
#define CMD_CW_STARTDELAY 'e' //ve
|
||||
extern byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
|
||||
|
||||
#define CMD_ATT_LEVEL 'f' //vf
|
||||
extern byte L_attLevel;
|
||||
|
||||
extern byte L_isIFShift; //1 = ifShift, 2 extend
|
||||
#define CMD_IS_IFSHIFT 'i' //ci
|
||||
|
||||
extern int L_ifShiftValue;
|
||||
#define CMD_IFSHIFT_VALUE 'i' //vi
|
||||
|
||||
extern byte L_sdrModeOn;
|
||||
#define CMD_SDR_MODE 'j' //cj
|
||||
|
||||
#define CMD_UBITX_INFO 'm' //cm Complete Send uBITX Information
|
||||
|
||||
//Once Send Data, When boot
|
||||
//arTuneStep, When boot, once send
|
||||
//long arTuneStep[5];
|
||||
|
||||
#define CMD_AR_TUNE1 '1' //v1
|
||||
#define CMD_AR_TUNE2 '2' //v2
|
||||
#define CMD_AR_TUNE3 '3' //v3
|
||||
#define CMD_AR_TUNE4 '4' //v4
|
||||
#define CMD_AR_TUNE5 '5' //v5
|
||||
|
||||
//int idleStep = 0;
|
||||
extern byte scaledSMeter;
|
||||
|
||||
extern float calcVSWR;
|
||||
extern float L_calcVSWR;
|
||||
|
||||
extern byte scaledVSWR;
|
||||
extern byte L_scaledVSWR;
|
||||
|
||||
extern float fwdPower;
|
||||
extern float L_fwdPower;
|
||||
|
||||
extern float revPower;
|
||||
extern float L_revPower;
|
||||
|
||||
void sendHeader(char varType, char varIndex);
|
||||
void sendCommandUL(char varIndex, unsigned long sendValue);
|
||||
void sendCommandL(char varIndex, long sendValue);
|
||||
void sendCommandStr(char varIndex, const char* sendValue);
|
||||
void sendCommand1Num(char varIndex, char sendValue);
|
||||
|
||||
//=======================================================
|
||||
//END OF Nextion Protocol
|
||||
//=======================================================
|
||||
|
||||
#endif
|
@ -1,3 +0,0 @@
|
||||
#include "Rig.h"
|
||||
|
||||
UBitxRig Rig;
|
126
TeensyDSP/Rig.h
126
TeensyDSP/Rig.h
@ -1,126 +0,0 @@
|
||||
#ifndef __Rig_h__
|
||||
#define __Rig_h__
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
#define DEFAULT_SSB_LO_CUT 300.0
|
||||
#define DEFAULT_SSB_HI_CUT 3000.0
|
||||
#define DEFAULT_CW_WIDTH 500.0
|
||||
#define DEFAULT_LOW_USB false
|
||||
#define DEFAULT_LOW_CWU true
|
||||
#define DEFAULT_HIGH_USB true
|
||||
#define DEFAULT_HIGH_CWU true
|
||||
|
||||
enum HamBand {
|
||||
BAND_80M = 0,
|
||||
BAND_60M,
|
||||
BAND_40M,
|
||||
BAND_30M,
|
||||
BAND_20M,
|
||||
BAND_17M,
|
||||
BAND_15M,
|
||||
BAND_12M,
|
||||
BAND_10M,
|
||||
NUM_BANDS
|
||||
};
|
||||
|
||||
struct ModeConfig {
|
||||
bool isUpper;
|
||||
float dspLo;
|
||||
float dspHi;
|
||||
};
|
||||
|
||||
struct BandConfig {
|
||||
ModeConfig cw;
|
||||
ModeConfig ssb;
|
||||
};
|
||||
|
||||
struct RigConfig {
|
||||
//bool isData = false;
|
||||
bool useUSBInput = true; // whether or not to use the USB input for data
|
||||
};
|
||||
|
||||
class UBitxRig {
|
||||
public:
|
||||
UBitxRig();
|
||||
|
||||
inline void begin() {}
|
||||
inline void update() {}
|
||||
|
||||
inline unsigned getFreqA() const { return radState.getFreqA(); }
|
||||
inline unsigned getFreqB() const { return radState.getFreqB(); }
|
||||
|
||||
inline int getRIT() const { return radState.getRIT(); }
|
||||
inline int getXIT() const { return radState.getXIT(); }
|
||||
|
||||
inline bool isVFOA() const { return radState.isVFOA(); }
|
||||
inline bool isVFOB() const { return radState.isVFOB(); }
|
||||
inline bool isSplit() const { return radState.isSplit(); }
|
||||
inline bool isRIT() const { return radState.isRIT(); }
|
||||
inline bool isXIT() const { return radState.isXIT(); }
|
||||
inline bool isModeCWAny() const { return radState.isModeCWAny(); }
|
||||
inline bool isModeCW() const { return radState.isModeCW(); }
|
||||
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
||||
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
||||
inline bool isModeLSB() const { return radState.isModeLSB(); }
|
||||
|
||||
inline float getCWSidetone() const { return static_cast<float>(radState.getSidetone()); }
|
||||
|
||||
inline bool isUSBInput() const { return conf.useUSBInput; }
|
||||
inline bool isLineInput() const { return !conf.useUSBInput; }
|
||||
|
||||
inline bool isAI() const { return autoInfo; }
|
||||
|
||||
inline void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
||||
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
||||
|
||||
inline void setRIT(int freq) { catState.setRIT(freq); }
|
||||
inline void setXIT(int freq) { catState.setXIT(freq); }
|
||||
|
||||
inline void setVFOA() { catState.setVFOA(); }
|
||||
inline void setVFOB() { catState.setVFOB(); }
|
||||
inline void setSplitOn() { catState.setSplitOn(); }
|
||||
inline void setSplitOff() { catState.setSplitOff(); }
|
||||
inline void setRITOn() { catState.setRITOn(); }
|
||||
inline void setRITOff() { catState.setRITOff(); }
|
||||
inline void setXITOn() { catState.setXITOn(); }
|
||||
inline void setXITOff() { catState.setXITOff(); }
|
||||
inline void setModeCW() { catState.setModeCW(); }
|
||||
inline void setModeCWR() { catState.setModeCWR(); }
|
||||
inline void setModeUSB() { catState.setModeUSB(); }
|
||||
inline void setModeLSB() { catState.setModeLSB(); }
|
||||
|
||||
inline void setCWSidetone(float f) { catState.setSidetone(static_cast<uint16_t>(f)); }
|
||||
|
||||
inline void setUSBInput() { conf.useUSBInput = true; }
|
||||
inline void setLineInput() { conf.useUSBInput = false; }
|
||||
|
||||
inline void aiOn() { autoInfo = true; }
|
||||
inline void aiOff() { autoInfo = false; }
|
||||
|
||||
inline UBitxRigState& cat() { return catState; }
|
||||
inline UBitxRigState& rad() { return radState; }
|
||||
|
||||
/********************************************************************/
|
||||
// New functional/mode-based Rig methods
|
||||
|
||||
// AG
|
||||
//void setVolOut(uint8_t level);
|
||||
//uint8_t getVolOut();
|
||||
|
||||
// BD/BU
|
||||
//void setBand();
|
||||
//void getBand();
|
||||
|
||||
private:
|
||||
RigConfig conf;
|
||||
UBitxRigState catState;
|
||||
UBitxRigState radState;
|
||||
bool autoInfo = false;
|
||||
|
||||
BandConfig band[NUM_BANDS];
|
||||
};
|
||||
|
||||
extern UBitxRig Rig;
|
||||
|
||||
#endif
|
@ -1,447 +0,0 @@
|
||||
/*!
|
||||
* @file RigState.cpp
|
||||
*
|
||||
* @mainpage uBITX V5X Software - RigState
|
||||
*
|
||||
* @section introsec Introduction
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section dependencies Dependencies
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Rob "Scrape" French, KC4UPR
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* TBD
|
||||
*/
|
||||
|
||||
#include "Debug.h"
|
||||
#include "RigState.h"
|
||||
|
||||
/***********************************************************************
|
||||
* COMMON FUNCTIONS
|
||||
*
|
||||
* The following are all common to RigState objects, whether on the
|
||||
* Raduino or on the TeensyDSP.
|
||||
**********************************************************************/
|
||||
|
||||
static uint32_t zeroes[1] = {0}; // used to transmit zeroes
|
||||
|
||||
/*!
|
||||
* @brief Begin using the RigState object. In order to force an
|
||||
* initial update (i.e. sending current state to the remote
|
||||
* device), all fields are initially marked dirty.
|
||||
*/
|
||||
void UBitxRigState::begin() {
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RADUINO FUNCTIONS
|
||||
*
|
||||
* The following are specific to the Raduino implementation. Note that
|
||||
* this depends on the use of the TEENSYDUINO #define, which may result
|
||||
* in a fragile implementation for other development environments (e.g.
|
||||
* if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
#include <Wire.h>
|
||||
#include "ubitx.h"
|
||||
#include "ubitx_eemap.h"
|
||||
|
||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency, sideTone;
|
||||
extern unsigned long vfoA;
|
||||
extern unsigned long vfoB;
|
||||
extern char cwMode;
|
||||
extern char isUSB;
|
||||
extern char vfoActive;
|
||||
extern char ritOn;
|
||||
extern char splitOn;
|
||||
extern char inTx;
|
||||
void setFrequency(unsigned long);
|
||||
|
||||
/*!
|
||||
* @brief Send the RigState from the Raduino to the TeensyDSP. The
|
||||
* basic process is: (1) read in any updated (dirty) data
|
||||
* from the Raduino's state variables; (2) transmit the dirty
|
||||
* data to the TeensyDSP; (2a) for clean data, zeroes are
|
||||
* transmitted; (3) mark all data as clean.
|
||||
*/
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
readDirty();
|
||||
Wire.beginTransmission(I2CMETER_ADDR);
|
||||
Wire.write(I2CMETER_RIGINF);
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
// otherwise, send out zeroes
|
||||
Wire.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
Wire.endTransmission();
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
//IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean();
|
||||
}
|
||||
|
||||
// delay(1); // 1ms - some delay required between ending transmission and requesting?
|
||||
|
||||
/*!
|
||||
* @brief Receive the RigState from the TeensyDSP. This generally
|
||||
* reflects changes due to CAT transmission to the TeensyDSP.
|
||||
* @param numBytes
|
||||
* Number of bytes received from the TeensyDSP.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
// Retrieve all of the deltas. Mark any received fields as dirty. It
|
||||
// is assumed that send_RIGINF() was called immedaitely before this,
|
||||
// so the fields are already clean.
|
||||
byte* ptr = (byte*)&data;
|
||||
Wire.requestFrom(I2CMETER_ADDR, sizeof(data));
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire.available(); j++) {
|
||||
byte incomingByte = Wire.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
writeDirty();
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
//IFDEBUG( serialPrettyState("Rcvd") );
|
||||
setClean(); // They get marked dirty as req'd during readDirty().
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Write dirty fields from the RigState out to the Raduino
|
||||
* variables.
|
||||
*/
|
||||
void UBitxRigState::writeDirty() {
|
||||
// VFO A frequency
|
||||
if (isDirty(VFOA_WORD)) {
|
||||
if (vfoActive == VFO_A) {
|
||||
setFrequency(getFreqA());
|
||||
} else {
|
||||
vfoA = getFreqA();
|
||||
}
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
if (isDirty(VFOB_WORD)) {
|
||||
if (vfoActive == VFO_B) {
|
||||
setFrequency(getFreqB());
|
||||
} else {
|
||||
vfoB = getFreqB();
|
||||
}
|
||||
}
|
||||
|
||||
// RIT and XIT frequencies
|
||||
if (isDirty(OFFSETS_WORD)) {
|
||||
// RIT
|
||||
ritRxFrequency = getRIT() + ritTxFrequency;
|
||||
if (ritOn == 1) {
|
||||
if (inTx == 0) {
|
||||
setFrequency(ritRxFrequency);
|
||||
} else {
|
||||
setFrequency(ritTxFrequency);
|
||||
}
|
||||
}
|
||||
// XIT - TODO
|
||||
}
|
||||
|
||||
// Various flags
|
||||
if (isDirty(FLAGS_WORD)) {
|
||||
|
||||
// VFO A/B selection
|
||||
char prev = vfoActive;
|
||||
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
||||
if (vfoActive != prev) {
|
||||
if (vfoActive == VFO_A) {
|
||||
if (vfoA != frequency) {
|
||||
setFrequency(vfoA);
|
||||
}
|
||||
} else if (vfoActive == VFO_B) {
|
||||
if (vfoB != frequency) {
|
||||
setFrequency(vfoB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split on/off
|
||||
splitOn = isSplit() ? 1 : 0;
|
||||
|
||||
// RIT on/off
|
||||
prev = ritOn;
|
||||
ritOn = isRIT() ? 1 : 0;
|
||||
if (ritOn != prev) {
|
||||
if ((ritOn == 1) && (inTx == 0)) {
|
||||
setFrequency(ritRxFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// XIT on/off
|
||||
// TODO
|
||||
|
||||
// Mode
|
||||
prev = (cwMode << 1) | isUSB;
|
||||
isUSB = isModeUSB() ? 1 : 0;
|
||||
if (isModeCW()) {
|
||||
cwMode = 2; // 2 = cwu
|
||||
} else if (isModeCWR()) {
|
||||
cwMode = 1; // 1 = cwl
|
||||
} else {
|
||||
cwMode = 0; // 0 = no cw
|
||||
}
|
||||
if ((cwMode << 1) | isUSB != prev) {
|
||||
setFrequency(frequency);
|
||||
}
|
||||
}
|
||||
|
||||
// Keyer information
|
||||
if (isDirty(KEYER_WORD)) {
|
||||
|
||||
// Sidetone frequency
|
||||
sideTone = static_cast<unsigned long>(getSidetone());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Read current Raduino variables into the RigState
|
||||
* (if they are changed) and set the appropriate dirty flags.
|
||||
* @param r
|
||||
* RigState reference to put the values into.
|
||||
*/
|
||||
void UBitxRigState::readDirty() {
|
||||
unsigned long freq;
|
||||
short offset;
|
||||
|
||||
// VFO A frequency
|
||||
freq = (vfoActive == VFO_A) ? frequency : vfoA;
|
||||
if (getFreqA() != freq) {
|
||||
setFreqA(freq);
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
freq = (vfoActive == VFO_B) ? frequency : vfoB;
|
||||
if (getFreqB() != freq) {
|
||||
setFreqB(freq);
|
||||
}
|
||||
|
||||
// RIT frequency
|
||||
if (inTx) {
|
||||
offset = ritRxFrequency - ritTxFrequency;
|
||||
} else {
|
||||
offset = frequency - ritTxFrequency;
|
||||
}
|
||||
if (getRIT() != offset) {
|
||||
setRIT(offset);
|
||||
}
|
||||
|
||||
// XIT frequency
|
||||
offset = 0; // xitRxFrequency - frequency;
|
||||
if (getXIT() != offset) {
|
||||
setXIT(offset);
|
||||
}
|
||||
|
||||
// VFO A/B selection
|
||||
if (isVFOA() && vfoActive == VFO_B) {
|
||||
setVFOB();
|
||||
} else if (isVFOB() && vfoActive == VFO_A) {
|
||||
setVFOA();
|
||||
}
|
||||
|
||||
// Split selection
|
||||
if (isSplit() && splitOn == 0) {
|
||||
setSplitOff();
|
||||
} else if (!isSplit() && splitOn != 0) {
|
||||
setSplitOn();
|
||||
}
|
||||
|
||||
// RIT selection
|
||||
if (isRIT() && ritOn == 0) {
|
||||
setRITOff();
|
||||
} else if (!isRIT() && ritOn != 0) {
|
||||
setRITOn();
|
||||
}
|
||||
|
||||
// XIT selection
|
||||
//setXITOff();
|
||||
// TODO
|
||||
|
||||
// Mode
|
||||
char prev = (isModeCW() ? 4 : 0) | (isModeCWR() ? 2 : 0) | (isModeUSB() ? 1 : 0);
|
||||
char curr = (cwMode << 1) | isUSB;
|
||||
if (curr != prev) {
|
||||
if (cwMode == 2) {
|
||||
setModeCW();
|
||||
} else if (cwMode == 1) {
|
||||
setModeCWR();
|
||||
} else {
|
||||
if (isUSB) {
|
||||
setModeUSB();
|
||||
} else {
|
||||
setModeLSB();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sidetone
|
||||
if (getSidetone() != static_cast<uint16_t>(sideTone)) {
|
||||
setSidetone(static_cast<uint16_t>(sideTone));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TEENSYDSP FUNCTIONS
|
||||
*
|
||||
* The following are specific to the TeensyDSP implementation. Note
|
||||
* that this depends on the use of the TEENSYDUINO #define, which may
|
||||
* result in a fragile implementation for other development environments
|
||||
* (e.g. if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#else
|
||||
|
||||
#include <i2c_t3.h>
|
||||
|
||||
/*!
|
||||
* @brief Receive RIGINF data from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'radState' (Raduino state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* receives the incoming data from the Raduino and updates the
|
||||
* state.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
byte* ptr = (byte*)&data;
|
||||
setClean(); // we'll get new dirty bits via the I2C message
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire1.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire1.available(); j++) {
|
||||
byte incomingByte = Wire1.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Do anything that needs to happen when something is updated by the
|
||||
// Raduino... this would be due to e.g. changes through the menu.
|
||||
// Current (as of 2/19/2021) things that DON'T need to have any
|
||||
// updates: frequency (those just get requested by CAT as needed).
|
||||
// Current things that do need to get updated: sidetone (used to
|
||||
// update CW filter values).
|
||||
//--------------------------------------------------------------------
|
||||
processDirty();
|
||||
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
IFDEBUG( serialPrettyState("Rcvd") );
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGINF signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'catState' (CAT state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* sends a response to the Raduino via I2C, using the Wire1
|
||||
* interface.
|
||||
*/
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire1.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
// otherwise, send out zeroes
|
||||
Wire1.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean(); // now that we've sent them, they're clean
|
||||
//--------------------------------------------------------------------
|
||||
// TODO: Need to look at possibly merging the two states together at
|
||||
// this point. The purpose would be to minimize the turnaround time
|
||||
// for getting the most recent data to a CAT response.
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform required actions based on any dirty bits set.
|
||||
*/
|
||||
void UBitxRigState::processDirty() {
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
char debugString[81] = {'\0'};
|
||||
|
||||
void UBitxRigState::serialHexState(const char* label = "RigState") {
|
||||
Serial.print(label);
|
||||
sprintf(debugString, ": %#010lx, %#010lx, %#010lx, %#010lx, %#010lx",
|
||||
data[DIRTY_WORD], data[VFOA_WORD], data[VFOB_WORD], data[OFFSETS_WORD], data[FLAGS_WORD]);
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
void UBitxRigState::serialPrettyState(const char* label = "RigState") {
|
||||
Serial.println(label);
|
||||
sprintf(debugString, "VFO A : %011ld %1c / VFO B : %011ld %1c",
|
||||
getFreqA(), isDirty(VFOA_WORD) ? 'D' : ' ', getFreqB(), isDirty(VFOB_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "RIT : %011ld %1c / XIT : %011ld %1c",
|
||||
getRIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ', getXIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "Split? %1c / VFO? %1c / RIT? %1c / XIT? %1c / Mode? %3s",
|
||||
isSplit() ? 'Y' : 'N', isVFOA() ? 'A' : 'B', isRIT() ? 'Y' : 'N', isXIT() ? 'Y' : 'N',
|
||||
isModeUSB() ? "USB" : (isModeLSB() ? "LSB" : (isModeCW() ? "CW " : (isModeCWR() ? "CWR" : " "))));
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
UBitxRigState _rigState;
|
||||
UBitxRigState& rigState = _rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
@ -1,391 +0,0 @@
|
||||
/*!
|
||||
* @file RigState.h
|
||||
*/
|
||||
|
||||
#ifndef __RigState_h__
|
||||
#define __RigState_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define UBITX_VFOB_FLAG 0x00000001
|
||||
#define UBITX_SPLIT_FLAG 0x00000002
|
||||
#define UBITX_RIT_FLAG 0x00000004
|
||||
#define UBITX_XIT_FLAG 0x00000008
|
||||
#define UBITX_CW_FLAG 0x00000010
|
||||
#define UBITX_USB_FLAG 0x00000020
|
||||
#define UBITX_TX_FLAG 0x00000040
|
||||
|
||||
#define UBITX_SIDETONE_MASK 0x000007FF
|
||||
#define UBITX_KEYER_MODE_MASK 0x00003800
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
||||
#else
|
||||
#define DISABLEINTS(CMD) do { CMD; } while (0)
|
||||
#endif
|
||||
|
||||
enum RigStateWord {
|
||||
DIRTY_WORD = 0,
|
||||
VFOA_WORD,
|
||||
VFOB_WORD,
|
||||
OFFSETS_WORD,
|
||||
FLAGS_WORD,
|
||||
KEYER_WORD,
|
||||
NUM_WORDS
|
||||
};
|
||||
|
||||
inline RigStateWord& operator++(RigStateWord& orig) {
|
||||
orig = static_cast<RigStateWord>(orig + 1);
|
||||
// NOTE: Will overflow...
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline RigStateWord operator++(RigStateWord& orig, int) {
|
||||
RigStateWord rVal = orig;
|
||||
++orig;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
struct UBitxRigState {
|
||||
volatile uint32_t data[NUM_WORDS] = {0};
|
||||
|
||||
void begin();
|
||||
|
||||
void send_RIGINF();
|
||||
void receive_RIGINF(int numBytes = sizeof(data));
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as dirty.
|
||||
*/
|
||||
inline void setDirty(RigStateWord w) {
|
||||
data[DIRTY_WORD] |= w < NUM_WORDS ? 1 << w : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bits for all words.
|
||||
*/
|
||||
inline void setDirty() { DISABLEINTS( data[DIRTY_WORD] = 0xFFFFFFFF ); }
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as clean.
|
||||
*/
|
||||
inline void setClean(RigStateWord w) {
|
||||
data[DIRTY_WORD] &= ~(w < NUM_WORDS ? 1 << w : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bits for all words.
|
||||
*/
|
||||
inline void setClean() { DISABLEINTS( data[DIRTY_WORD] = 0 ); }
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is clean.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for clean status.
|
||||
*
|
||||
* @return True if the word is clean.
|
||||
*/
|
||||
inline bool isClean(RigStateWord w) {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = ((1 << w) & data[DIRTY_WORD]) > 0 ? false : true );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is clean (as a whole).
|
||||
*
|
||||
* @return True if the data is clean (no dirty fields).
|
||||
*/
|
||||
inline bool isClean() {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = data[DIRTY_WORD] == 0 );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is dirty.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for dirty status.
|
||||
*
|
||||
* @return True if the word is dirty.
|
||||
*/
|
||||
inline bool isDirty(RigStateWord w) {
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = ((1 << w) & data[DIRTY_WORD]) > 0 ? true : false );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is dirty (as a whole).
|
||||
*
|
||||
* @return True if the data is dirty (at least one dirty field).
|
||||
*/
|
||||
inline bool isDirty() {
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = data[DIRTY_WORD] != 0 );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the VFO A frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqA(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOA_WORD] = freq;
|
||||
if (mark) setDirty(VFOA_WORD) );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqA() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOA_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the VFO B frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqB(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOB_WORD] = freq );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqB() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOB_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (int32_t(offset) << 16) | (0x0000FFFF & data[OFFSETS_WORD]);
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getRIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = data[OFFSETS_WORD] >> 16 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (0xFFFF0000 & data[OFFSETS_WORD]) | offset;
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getXIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = 0x0000FFFF & data[OFFSETS_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setVFOA(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setVFOB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isVFOA() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? false : true );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isVFOB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setSplitOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setSplitOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isSplit() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_SPLIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setRITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isRIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_RIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setXITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isXIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_XIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setModeUSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setModeLSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setModeCW(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setModeCWR(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isModeUSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeLSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWAny() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = (data[FLAGS_WORD] & UBITX_CW_FLAG) > 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCW() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWR() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setSidetone(uint16_t f, bool mark = true) {
|
||||
DISABLEINTS( data[KEYER_WORD] &= ~UBITX_SIDETONE_MASK;
|
||||
data[KEYER_WORD] |= (uint32_t(f) & UBITX_SIDETONE_MASK);
|
||||
if (mark) setDirty(KEYER_WORD) );
|
||||
}
|
||||
|
||||
inline uint16_t getSidetone() {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[KEYER_WORD] & UBITX_SIDETONE_MASK );
|
||||
return uint16_t(result);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void serialHexState(const char* label);
|
||||
void serialPrettyState(const char* label);
|
||||
#endif
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
// These methods are only defined in the Raduino (Arduino) case of the
|
||||
// RigState, not in the TeensyDSP (Teensy) case.
|
||||
void writeDirty(); // write fields FROM RigState TO Raduino
|
||||
void readDirty(); // read variables FROM Raduino TO RigState
|
||||
#else
|
||||
// These methods are only defined (currently) in the TeensyDSP case.
|
||||
void processDirty();
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
extern UBitxRigState& rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
NOTE: This is all currently OBE, leaving it here for reference/future cleanup.
|
||||
|
||||
Protocol discussion:
|
||||
- I2C master: Raduino
|
||||
- I2C slave: TeensyDSP
|
||||
|
||||
Raduino state:
|
||||
- Baseline uBITX variables
|
||||
- I2C buffer
|
||||
- On I2C transmit: make updates based on current variables
|
||||
- On I2C receive:
|
||||
- Update based on received I2C responses
|
||||
- Update associated variables
|
||||
|
||||
TeensyDSP state:
|
||||
- CAT buffer
|
||||
- Used to receive command from CAT (when commands arrive via Serial)
|
||||
- Used to transmit state to Raduino (when requested via Wire1)
|
||||
- Raduino buffer
|
||||
- Used to receive state from Raduino (when received via Wire1)
|
||||
- Used to transmit responses to CAT (over Serial)
|
||||
- Questions
|
||||
- How can these be synchronized?
|
||||
- At the tail end of an I2C request handler. Before sending the response to the Raduino via I2C:
|
||||
- Copy updated CAT buffer items to the Raduino buffer.
|
||||
- Copy updated Raduino buffer items to the CAT buffer.
|
||||
- In the case of conflicts, CAT wins.
|
||||
- Transmit the CAT buffer state to the Raduino.
|
||||
- TeensyDSP updates 'outgoing' state based on CAT inputs.
|
||||
- Make change to data.
|
||||
- Mark data as dirty, if different than incoming state.
|
||||
- When requested, Teensy DSP sends 'outgoing' state to Raduino.
|
||||
- Send dirty data over I2C.
|
||||
- Mark data as clean.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
@ -1,5 +0,0 @@
|
||||
#include "Sensors.h"
|
||||
|
||||
UBitxSensors Sensors;
|
||||
|
||||
ADC adc;
|
@ -1,363 +0,0 @@
|
||||
#ifndef __Sensor_h__
|
||||
#define __Sensor_h__
|
||||
|
||||
#include <ADC.h>
|
||||
#include "Debug.h"
|
||||
#include "HamFuncs.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_PIN
|
||||
#define UBITX_SENSORS_S_METER_PIN 28
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_PIN
|
||||
#define UBITX_SENSORS_FWD_PWR_PIN 26
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_PIN
|
||||
#define UBITX_SENSORS_REV_PWR_PIN 20
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_PIN
|
||||
#define UBITX_SENSORS_SUPPLY_PIN 21
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SPARE1_PIN
|
||||
#define UBITX_SENSORS_SPARE1_PIN 27
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SPARE2_PIN
|
||||
#define UBITX_SENSORS_SPARE2_PIN 31
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_AVG_SAMPLES
|
||||
#define UBITX_SENSORS_AVG_SAMPLES 16
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_R1
|
||||
#define UBITX_SENSORS_S_METER_R1 0.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_R2
|
||||
#define UBITX_SENSORS_S_METER_R2 1.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_R1
|
||||
#define UBITX_SENSORS_FWD_PWR_R1 22000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_R2
|
||||
#define UBITX_SENSORS_FWD_PWR_R2 33000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_R1
|
||||
#define UBITX_SENSORS_REV_PWR_R1 22000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_R2
|
||||
#define UBITX_SENSORS_REV_PWR_R2 33000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_R1
|
||||
#define UBITX_SENSORS_SUPPLY_R1 56000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_R2
|
||||
#define UBITX_SENSORS_SUPPLY_R2 10000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL0
|
||||
#define UBITX_SENSORS_S_METER_LVL0 2
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL1
|
||||
#define UBITX_SENSORS_S_METER_LVL1 4
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL2
|
||||
#define UBITX_SENSORS_S_METER_LVL2 8
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL3
|
||||
#define UBITX_SENSORS_S_METER_LVL3 16
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL4
|
||||
#define UBITX_SENSORS_S_METER_LVL4 32
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL5
|
||||
#define UBITX_SENSORS_S_METER_LVL5 64
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL6
|
||||
#define UBITX_SENSORS_S_METER_LVL6 128
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL7
|
||||
#define UBITX_SENSORS_S_METER_LVL7 256
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL8
|
||||
#define UBITX_SENSORS_S_METER_LVL8 512
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
const int uBitxSensorsSMeterPin = UBITX_SENSORS_S_METER_PIN;
|
||||
const int uBitxSensorsFwdPwrPin = UBITX_SENSORS_FWD_PWR_PIN;
|
||||
const int uBitxSensorsRevPwrPin = UBITX_SENSORS_REV_PWR_PIN;
|
||||
const int uBitxSensorsSupplyPin = UBITX_SENSORS_SUPPLY_PIN;
|
||||
const int uBitxSensorsSpare1Pin = UBITX_SENSORS_SPARE1_PIN;
|
||||
const int uBitxSensorsSpare2Pin = UBITX_SENSORS_SPARE2_PIN;
|
||||
const int uBitxSensorsAvgSamples = UBITX_SENSORS_AVG_SAMPLES;
|
||||
const float uBitxSensorsSMeterR1 = UBITX_SENSORS_S_METER_R1;
|
||||
const float uBitxSensorsSMeterR2 = UBITX_SENSORS_S_METER_R2;
|
||||
const float uBitxSensorsFwdPwrR1 = UBITX_SENSORS_FWD_PWR_R1;
|
||||
const float uBitxSensorsFwdPwrR2 = UBITX_SENSORS_FWD_PWR_R2;
|
||||
const float uBitxSensorsRevPwrR1 = UBITX_SENSORS_REV_PWR_R1;
|
||||
const float uBitxSensorsRevPwrR2 = UBITX_SENSORS_REV_PWR_R2;
|
||||
const float uBitxSensorsSupplyR1 = UBITX_SENSORS_SUPPLY_R1;
|
||||
const float uBitxSensorsSupplyR2 = UBITX_SENSORS_SUPPLY_R2;
|
||||
|
||||
const int uBitxSensorsSMeterValues[] = {
|
||||
UBITX_SENSORS_S_METER_LVL0,
|
||||
UBITX_SENSORS_S_METER_LVL1,
|
||||
UBITX_SENSORS_S_METER_LVL2,
|
||||
UBITX_SENSORS_S_METER_LVL3,
|
||||
UBITX_SENSORS_S_METER_LVL4,
|
||||
UBITX_SENSORS_S_METER_LVL5,
|
||||
UBITX_SENSORS_S_METER_LVL6,
|
||||
UBITX_SENSORS_S_METER_LVL7,
|
||||
UBITX_SENSORS_S_METER_LVL8
|
||||
};
|
||||
|
||||
const int uBitxSensorsSMeterLevels = sizeof(uBitxSensorsSMeterValues) /
|
||||
sizeof(uBitxSensorsSMeterValues[0]);
|
||||
|
||||
extern ADC adc;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Class that maintains a "trailing average" of the last X
|
||||
* samples provided. It is a template that can be instantiated
|
||||
* with both the (numeric) data type that is being stored and
|
||||
* averaged, as well as the number of samples to maintain the
|
||||
* trailing average across.
|
||||
*/
|
||||
template <typename T, int N>
|
||||
class TrailingAverage {
|
||||
public:
|
||||
/*!
|
||||
* @brief Create a new TrailingAverage object. Data type averaged,
|
||||
* and number of elements to average, are determined when the
|
||||
* template is instantiated.
|
||||
*/
|
||||
TrailingAverage():
|
||||
average(T(0)),
|
||||
current(0),
|
||||
divisor(T(N))
|
||||
{
|
||||
for (int i = 0; i < N; i++) {
|
||||
data[i] = T(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Add a new element to the average. The current last (Nth)
|
||||
* element is removed, and the new element is added.
|
||||
* @param val
|
||||
* The new element/value to incorporate into the average.
|
||||
*/
|
||||
inline void add(T val) {
|
||||
//int last = (current - 1) % N;
|
||||
//average -= data[last];
|
||||
//current = (current + 1) % N;
|
||||
//data[current] = val / divisor;
|
||||
//average += data[current];
|
||||
average -= data[current];
|
||||
data[current] = val / divisor;
|
||||
average += data[current];
|
||||
current = (current + 1) % N;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Read the current value of the average.
|
||||
* @return The current average.
|
||||
*/
|
||||
inline T read() {
|
||||
return average;
|
||||
}
|
||||
|
||||
private:
|
||||
T data[N];
|
||||
T average;
|
||||
int current;
|
||||
T divisor;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Class that handles the various sensors in the uBitx:
|
||||
* S-Meter, forward/reverse power and SWR, and supply voltage.
|
||||
*/
|
||||
class UBitxSensors {
|
||||
public:
|
||||
/*!
|
||||
* @brief Create a new UBitxSensors object. It uses the default
|
||||
* S-Meter, Forward Power, Reverse Power, and Supply Voltage
|
||||
* ADC pins.
|
||||
*/
|
||||
UBitxSensors():
|
||||
sMeterPin(uBitxSensorsSMeterPin),
|
||||
fwdPwrPin(uBitxSensorsFwdPwrPin),
|
||||
revPwrPin(uBitxSensorsRevPwrPin),
|
||||
supplyPin(uBitxSensorsSupplyPin),
|
||||
spare1Pin(uBitxSensorsSpare1Pin),
|
||||
spare2Pin(uBitxSensorsSpare2Pin)
|
||||
{
|
||||
pinMode(sMeterPin, INPUT); // analog
|
||||
pinMode(fwdPwrPin, INPUT); // analog
|
||||
pinMode(revPwrPin, INPUT); // analog
|
||||
pinMode(supplyPin, INPUT); // analog
|
||||
pinMode(spare1Pin, INPUT); // analog
|
||||
pinMode(spare2Pin, INPUT); // analog
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the S-Meter by reading the associated
|
||||
* ADC pin.
|
||||
*/
|
||||
inline void updateSMeter() {
|
||||
int value = adc.analogRead(sMeterPin);
|
||||
sMeter.add(value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the Forward and Reverse Power
|
||||
* measurements by reading the associated ADC pin.
|
||||
*/
|
||||
void updatePower() {
|
||||
ADC::Sync_result value = adc.analogSyncRead(revPwrPin, fwdPwrPin);
|
||||
|
||||
float fwdV = HF::adcIn(value.result_adc0);
|
||||
float revV = HF::adcIn(value.result_adc1);
|
||||
|
||||
fwdV = HF::divIn(fwdV, uBitxSensorsFwdPwrR1, uBitxSensorsFwdPwrR2);
|
||||
fwdV = HF::bridgeFwd(fwdV);
|
||||
|
||||
revV = HF::divIn(revV, uBitxSensorsRevPwrR1, uBitxSensorsRevPwrR2);
|
||||
revV = HF::bridgeFwd(revV);
|
||||
|
||||
fwdPwr.add(HF::P(fwdV));
|
||||
revPwr.add(HF::P(revV));
|
||||
vswr.add(HF::VSWR(fwdV, revV));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the Supply Voltage measurement by
|
||||
* reading the associated ADC pin.
|
||||
*/
|
||||
inline void updateSupply() {
|
||||
float value = HF::adcIn(adc.analogRead(supplyPin));
|
||||
value = HF::divIn(value, uBitxSensorsSupplyR1, uBitxSensorsSupplyR2);
|
||||
supply.add(value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the unscaled value of the S-Meter reading.
|
||||
* @return Unscaled S-Meter reading.
|
||||
*/
|
||||
inline int sMeterUnscaled() {
|
||||
return sMeter.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the scaled value of the S-Meter reading. This
|
||||
* is the value that is used to directly control the S-Meter
|
||||
* display on the Nextion LCD.
|
||||
* @return Scaled S-Meter reading.
|
||||
*/
|
||||
int sMeterScaled() {
|
||||
int sig = sMeter.read() >> 2;
|
||||
// small number of elements; just doing a linear search
|
||||
for (int i = uBitxSensorsSMeterLevels; i > 0; i--) {
|
||||
if (sig > uBitxSensorsSMeterValues[i - 1]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Forward Power measurement.
|
||||
* @return Forward Power measurement.
|
||||
*/
|
||||
inline float Pfwd() {
|
||||
return fwdPwr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Reverse Power measurement.
|
||||
* @return Reverse Power measurement.
|
||||
*/
|
||||
inline float Prev() {
|
||||
return revPwr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Voltage Standing Wave Ration (VSWR).
|
||||
* @return Current VSWR calculation.
|
||||
*/
|
||||
inline float VSWR() {
|
||||
return vswr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Voltage Standing Wave Ration (VSWR),
|
||||
* scaled for the Nextion display protocol.
|
||||
* @return Current VSWR calculation (scaled).
|
||||
*/
|
||||
float scaledVSWR() {
|
||||
int val = int(vswr.read());
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > uBitxSensorsSMeterLevels) {
|
||||
return uBitxSensorsSMeterLevels;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Supply Voltage measurement.
|
||||
* @return Current Supply Voltage.
|
||||
*/
|
||||
inline float supplyVoltage() {
|
||||
return supply.read();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Pins
|
||||
int sMeterPin;
|
||||
int fwdPwrPin;
|
||||
int revPwrPin;
|
||||
int supplyPin;
|
||||
int spare1Pin;
|
||||
int spare2Pin;
|
||||
|
||||
// Buffers for averages
|
||||
TrailingAverage<int, uBitxSensorsAvgSamples> sMeter;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> fwdPwr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> revPwr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> vswr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> supply;
|
||||
};
|
||||
|
||||
extern UBitxSensors Sensors;
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
//======================================================================
|
||||
// TR.cpp
|
||||
//======================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "TR.h"
|
||||
|
||||
UBitxTR _tr(DSP);
|
||||
UBitxTR& TR = _tr;
|
||||
|
||||
void UBitxTR::update(bool cw, bool extKey) {
|
||||
updateKey();
|
||||
|
||||
if (cw) {
|
||||
if ((keyEnable && keyDown) || extKey) {
|
||||
setTX();
|
||||
} else {
|
||||
setRX();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
updatePTT();
|
||||
updateVOX();
|
||||
|
||||
if (isTX) {
|
||||
// If we are currently transmitting, then ANY T/R release (key
|
||||
// release) will result in exitting transmit... except for VOX
|
||||
// and CAT which can only function as a release if it was enabled.
|
||||
if (pttReleased() || keyReleased() ||
|
||||
(voxEnable && voxDeactivated()) ||
|
||||
(catEnable && catDeactivated())) {
|
||||
// first, stop transmitting; then, setup RX audio
|
||||
DBGCMD( setRX() );
|
||||
DBGCMD( dsp.rx() );
|
||||
}
|
||||
} else {
|
||||
if ((pttEnable && pttPressed()) || (voxEnable && voxActivated())) {
|
||||
// first, setup TX audio; then, start transmitting (from Mic)
|
||||
DBGCMD( dsp.txMicIn() );
|
||||
DBGCMD( setTX() );
|
||||
} else if (keyEnable && keyPressed()) {
|
||||
// first, setup TX audio; then, start transmitting (from Line In)
|
||||
DBGCMD( dsp.txLineIn() );
|
||||
DBGCMD( setTX() );
|
||||
} else if (catEnable && catActivated()) {
|
||||
// first, setup TX audio; then, start transmitting (USB)
|
||||
DBGCMD( dsp.txUSBIn() );
|
||||
DBGCMD( setTX() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
165
TeensyDSP/TR.h
165
TeensyDSP/TR.h
@ -1,165 +0,0 @@
|
||||
//======================================================================
|
||||
// TR.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __TR_h__
|
||||
#define __TR_h__
|
||||
|
||||
#include <Bounce2.h>
|
||||
#include "Debug.h"
|
||||
#include "DSP.h"
|
||||
|
||||
#define UBITX_TR_OUT_PIN 2
|
||||
#define UBITX_TR_PTT_PIN 3
|
||||
#define UBITX_TR_VOX_PIN 4
|
||||
#define UBITX_TR_KEY_PIN 5
|
||||
|
||||
const int uBitxTROutPin = UBITX_TR_OUT_PIN;
|
||||
const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
|
||||
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
|
||||
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
|
||||
|
||||
struct TxSource {
|
||||
MIC_SOURCE = 0,
|
||||
LINE_SOURCE,
|
||||
USB_SOURCE,
|
||||
};
|
||||
|
||||
class UBitxTR {
|
||||
public:
|
||||
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
|
||||
dsp(d), outPin(out), pttPin(p), voxPin(v), keyPin(k) {}
|
||||
|
||||
void begin() {
|
||||
pinMode(outPin, OUTPUT);
|
||||
pinMode(voxPin, INPUT_PULLUP);
|
||||
pinMode(keyPin, INPUT_PULLUP);
|
||||
ptt.attach(pttPin, INPUT_PULLUP);
|
||||
ptt.interval(5);
|
||||
|
||||
// default configuration: PTT, key, and CAT enabled; VOX disabled
|
||||
DBGCMD( enablePTT() );
|
||||
DBGCMD( disableVOX() );
|
||||
DBGCMD( enableKey() );
|
||||
DBGCMD( enableCAT() );
|
||||
|
||||
DBGCMD( setRX() );
|
||||
}
|
||||
|
||||
inline void enablePTT() { pttEnable = true; }
|
||||
inline void enableVOX() { voxEnable = true; }
|
||||
inline void enableKey() { keyEnable = true; }
|
||||
inline void enableCAT() { catEnable = true; }
|
||||
inline void disablePTT() { pttEnable = false; }
|
||||
inline void disableVOX() { voxEnable = false; }
|
||||
inline void disableKey() { keyEnable = false; }
|
||||
inline void disableCAT() { catEnable = false; }
|
||||
|
||||
inline bool pttEnabled() { return pttEnable; }
|
||||
inline bool voxEnabled() { return voxEnable; }
|
||||
inline bool keyEnabled() { return keyEnable; }
|
||||
inline bool catEnabled() { return catEnable; }
|
||||
|
||||
inline bool pttPressed() { return ptt.fell(); }
|
||||
inline bool pttReleased() { return ptt.rose(); }
|
||||
inline bool voxActivated() { return (L_voxActive != voxActive) && L_voxActive; }
|
||||
inline bool voxDeactivated() { return (L_voxActive != voxActive) && voxActive; }
|
||||
inline bool keyPressed() { return (L_keyDown != keyDown) && L_keyDown; }
|
||||
inline bool keyReleased() { return (L_keyDown != keyDown) && keyDown; }
|
||||
inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
|
||||
inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
|
||||
|
||||
inline void catTX(TxSource src) {
|
||||
L_catActive = catActive;
|
||||
catActive = true;
|
||||
txSource = src;
|
||||
}
|
||||
|
||||
inline void catRX() {
|
||||
L_catActive = catActive;
|
||||
catActive = false;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
|
||||
inline bool transmitting() { return isTX; }
|
||||
inline bool receiving() { return !isTX; }
|
||||
inline TxSource source() const { return txSource; }
|
||||
|
||||
/*!
|
||||
* @brief Check if any of the PTT's have been pressed or released
|
||||
* since the last update. Only one thing is allowed to occur
|
||||
* based on an order of precedence. The highest priority is
|
||||
* to stop transmitting.
|
||||
*
|
||||
* @param cw
|
||||
* True if CW mode is currently active; false otherwise.
|
||||
* Different/faster logic is used in CW mode.
|
||||
*
|
||||
* @param extKey
|
||||
* True if an external keying signal (ie. CW keyer) is
|
||||
* currently active (ie. key down).
|
||||
*/
|
||||
void update(bool cw = false, bool extKey = false);
|
||||
|
||||
void end() {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void setTX() {
|
||||
digitalWrite(outPin, LOW);
|
||||
isTX = true;
|
||||
}
|
||||
|
||||
inline void setRX() {
|
||||
isTX = false;
|
||||
digitalWrite(outPin, HIGH);
|
||||
}
|
||||
|
||||
inline void updatePTT() {
|
||||
ptt.update();
|
||||
}
|
||||
|
||||
inline void updateVOX() {
|
||||
L_voxActive = voxActive;
|
||||
voxActive = (digitalRead(voxPin) == LOW);
|
||||
}
|
||||
|
||||
inline void updateKey() {
|
||||
L_keyDown = keyDown;
|
||||
keyDown = (digitalRead(keyPin) == LOW);
|
||||
}
|
||||
|
||||
UBitxDSP& dsp;
|
||||
|
||||
Bounce ptt;
|
||||
|
||||
int outPin;
|
||||
int pttPin;
|
||||
int voxPin;
|
||||
int keyPin;
|
||||
|
||||
bool isTX = false;
|
||||
|
||||
bool pttEnable = false;
|
||||
bool voxEnable = false;
|
||||
bool keyEnable = false;
|
||||
bool catEnable = false;
|
||||
|
||||
bool voxActive = false;
|
||||
bool L_voxActive = false;
|
||||
bool keyDown = false;
|
||||
bool L_keyDown = false;
|
||||
bool catActive = false;
|
||||
bool L_catActive = false;
|
||||
TxSource txSource = MIC_SOURCE;
|
||||
};
|
||||
|
||||
extern UBitxTR TR;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
@ -1,552 +0,0 @@
|
||||
#include <Arduino.h>
|
||||
#include "TS590.h"
|
||||
#include "Debug.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Send a command to the PC via CAT. Note that the command
|
||||
* should not include the trailing terminator (;). That will
|
||||
* be automatically added.
|
||||
* @param format
|
||||
* A printf-style format string.
|
||||
* @param args
|
||||
* Zero or more arguments to include in the command.
|
||||
*/
|
||||
void ts590SendCommand(const char* format, ...) {
|
||||
static char outBuf[ts590CommandMaxLength];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(outBuf, format, args);
|
||||
va_end(args);
|
||||
Serial.print(outBuf);
|
||||
Serial.print(";");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Create a new CAT command. It should be initialized with
|
||||
* a 2-character command prefix.
|
||||
* @param pre
|
||||
* A 2-character command prefix. If more than 2 characters
|
||||
* are supplied, only the first two will be used. If less
|
||||
* than two are supplied, then the command will be
|
||||
* initialized with a null prefix.
|
||||
*/
|
||||
TS590Command::TS590Command(const char* pre) {
|
||||
if (strlen(pre) >= 2) {
|
||||
myPrefix[0] = pre[0];
|
||||
myPrefix[1] = pre[1];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Determine whether this is a Read command or not. by
|
||||
* default, if it's a 2-letter command, it's a Read.
|
||||
* @return True if a Read command; false otherwise.
|
||||
*/
|
||||
bool TS590Command::isReadCommand(const char* cmd) const {
|
||||
if (strlen(cmd) == 2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Process the provided command. If the command is a Set
|
||||
* command, it calls handleCommand(). If Auto Information
|
||||
* is eet (by the rig), sendResponse() is called at the end.
|
||||
* If the command is a Read command, it also calls
|
||||
* sendResponse(). Finally, if necessary, it will return
|
||||
* any error codes to the PC.
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
void TS590Command::process(const char* cmd) {
|
||||
theError = NoError;
|
||||
|
||||
if (isReadCommand(cmd)) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
} else {
|
||||
DBGCMD( handleCommand(cmd) );
|
||||
switch(theError) {
|
||||
case NoError:
|
||||
if (theRig->isAI()) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxError:
|
||||
DBGCMD( ts590SyntaxError() );
|
||||
break;
|
||||
|
||||
case CommError:
|
||||
DBGCMD( ts590CommError() );
|
||||
break;
|
||||
|
||||
case ProcessError:
|
||||
DBGCMD( ts590ProcessError() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the syntax error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setSyntaxError() {
|
||||
theError = SyntaxError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the comms error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setCommError() {
|
||||
theError = CommError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the process error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setProcessError() {
|
||||
theError = ProcessError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the rig that will be used to process commands.
|
||||
* @param r
|
||||
* Pointer to the UBitxRig object.
|
||||
*/
|
||||
void TS590Command::setRig(UBitxRig* r) {
|
||||
theRig = r;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the DSP that will be used to process commands.
|
||||
* @param d
|
||||
* Pointer to the UBitxDSP object.
|
||||
*/
|
||||
void TS590Command::setDSP(UBitxDSP* d) {
|
||||
theDSP = d;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the T/R that will be used to process commands.
|
||||
* @param t
|
||||
* Pointer to the UBitxTR object.
|
||||
*/
|
||||
void TS590Command::setDSP(UBitxTR* t) {
|
||||
theTR = t;
|
||||
}
|
||||
|
||||
UBitxRig* TS590Command::theRig = &Rig;
|
||||
UBitxDSP* TS590Command::theDSP = &DSP;
|
||||
UBitxTR* TR590Command::theTR = &TR;
|
||||
TS590Error TS590Command::theError = NoError;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FR::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
rig()->setVFOA();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '1':
|
||||
rig()->setVFOB();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '2':
|
||||
// TODO: Need to add something for channel mode.
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FR::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand("FR0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand("FR1");
|
||||
} else {
|
||||
ts590SendCommand("FR2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FT::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->setSplitOff();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->setSplitOn();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
case '1':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->setSplitOn();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->setSplitOff();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FT::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT1" : "FT0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT0" : "FT1");
|
||||
} else {
|
||||
ts590SendCommand("FT2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_MD::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0': // None (setting failure)
|
||||
case '4': // FM - not supported
|
||||
case '5': // AM - not supported
|
||||
case '6': // FSK - not supported
|
||||
case '8': // None (setting failure)
|
||||
case '9': // FSK-R - not supported
|
||||
setProcessError();
|
||||
break;
|
||||
|
||||
case '1': // LSB
|
||||
rig()->setModeLSB();
|
||||
break;
|
||||
|
||||
case '2': // USB
|
||||
rig()->setModeUSB();
|
||||
break;
|
||||
|
||||
case '3': // CW
|
||||
rig()->setModeCW();
|
||||
break;
|
||||
|
||||
case '7': // CW-R
|
||||
rig()->setModeCWR();
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_MD::sendResponse(const char* cmd) {
|
||||
if (rig()->isModeCW()) {
|
||||
ts590SendCommand("MD3");
|
||||
} else if (rig()->isModeCWR()) {
|
||||
ts590SendCommand("MD7");
|
||||
} else if (rig()->isModeUSB()) {
|
||||
ts590SendCommand("MD2");
|
||||
} else if (rig()->isModeLSB()) {
|
||||
ts590SendCommand("MD1");
|
||||
} else {
|
||||
ts590SendCommand("MD0");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
int ssbHiCut[14] = {1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000, 3400, 4000, 5000};
|
||||
int ssbLoCut[12] = {0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
||||
|
||||
int ssbWidth[14] = {50, 80, 100, 150, 200, 250, 300, 400, 500, 600, 1000, 1500, 2000, 2500};
|
||||
int ssbCenter[14] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2100, 2210};
|
||||
|
||||
void TS590_SH::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 4) {
|
||||
index = strtoul(&cmd[2], NULL, 10);
|
||||
if (index < sizeof(ssbHiCut) / sizeof(ssbHiCut[0])) {
|
||||
dsp()->setRxFilterHi(ssbHiCut[index]);
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_SH::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("SH%02u", index);
|
||||
}
|
||||
|
||||
void TS590_SL::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 4) {
|
||||
index = strtoul(&cmd[2], NULL, 10);
|
||||
if (index < sizeof(ssbLoCut) / sizeof(ssbLoCut[0])) {
|
||||
dsp()->setRxFilterLo(ssbLoCut[index]);
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_SL::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("SL%02u", index);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_TX::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
tr.catTX(MIC_SOURCE);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
tr.catTX(rig.isUSBInput() ? USB_INPUT : LINE_INPUT);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
// TODO: Need to implement w/ Teensy Audio Tool.
|
||||
//tr.catTX();
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else if (strlen(cmd) == 2) {
|
||||
tr.catTX(MIC_SOURCE);
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_TX::sendResponse(const char* cmd) {
|
||||
char src;
|
||||
switch (tr.source()) {
|
||||
case MIC_SOURCE:
|
||||
src = '0';
|
||||
break;
|
||||
|
||||
case LINE_SOURCE:
|
||||
case USB_SOURCE:
|
||||
src = '1';
|
||||
break;
|
||||
}
|
||||
ts590SeondCommand("TX%1c", src);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Create a new CAT EX command. It should be initialized with
|
||||
* a 3-character P1 parameter (command number).
|
||||
* @param pre
|
||||
* A 3-character command prefix. If more than 3 characters
|
||||
* are supplied, only the first two will be used. If less
|
||||
* than three are supplied, then the command will be
|
||||
* initialized with a null prefix.
|
||||
*/
|
||||
TS590EXCommand::TS590EXCommand(const char* P1):
|
||||
TS590Command("EX") {
|
||||
if (strlen(P1) >= 3) {
|
||||
strncpy(myMenu, P1, 3);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Determine whether this is a Read command or not. by
|
||||
* default, if it's a 2-letter command, it's a Read.
|
||||
* @return True if a Read command; false otherwise.
|
||||
*/
|
||||
bool TS590EXCommand::isReadCommand(const char* cmd) const {
|
||||
if (strlen(cmd) == 9) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void TS590EXCommand::sendResponse(const char* cmd) {
|
||||
ts590sendCommand("%2c%3c0000%s", prefix(), menu(), getReturnValue());
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_EX034::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10 || strlen(cmd) == 11) {
|
||||
index = (uint8_t)atol(&cmd[9]);
|
||||
if (index < 15) {
|
||||
rig().setCWSidetone(300.0 + (float)(index * 50));
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_EX034::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("EX0340000%02d", index % 15);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_EX063::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10) {
|
||||
if (cmd[9] == '0') {
|
||||
rig().setLineInput();
|
||||
} else if (cmd[9] == '1') {
|
||||
rig().setUSBInput();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_EX063::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("EX0630000%1c", rig().isUSBInput() ? '1' : '0');
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
TS590_FA cmdFA;
|
||||
TS590_FB cmdFB;
|
||||
TS590_FR cmdFR;
|
||||
TS590_FT cmdFT;
|
||||
TS590_MD cmdMD;
|
||||
TS590_SH cmdSH;
|
||||
TS590_SL cmdSL;
|
||||
|
||||
TS590Command* catCommands[] = {
|
||||
&cmdFA,
|
||||
&cmdFB,
|
||||
&cmdFR,
|
||||
&cmdFT,
|
||||
&cmdMD,
|
||||
&cmdSH,
|
||||
&cmdSL
|
||||
};
|
||||
int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
void UBitxTS590::begin() {
|
||||
Serial.begin(9600); // USB is always 12 Mbit/sec
|
||||
#ifdef DEBUG
|
||||
delay(500);
|
||||
Serial.print("DBG: Number of CAT commands: ");
|
||||
Serial.println(numCommands);
|
||||
for (int i = 0; i < numCommands; i++) {
|
||||
Serial.print(" ");
|
||||
Serial.println(commands[i]->prefix());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UBitxTS590::update() {
|
||||
char incomingChar;
|
||||
|
||||
while (Serial.available()) {
|
||||
if (bufLen < ts590CommandMaxLength) {
|
||||
incomingChar = Serial.read();
|
||||
if (incomingChar == ';') {
|
||||
buf[bufLen++] = '\0';
|
||||
strupr(buf);
|
||||
processCommand();
|
||||
} else if (incomingChar == '\n' && bufLen == 0) {
|
||||
;
|
||||
} else {
|
||||
buf[bufLen++] = incomingChar;
|
||||
}
|
||||
} else {
|
||||
// too long... we're going to bail on this.
|
||||
ts590SyntaxError();
|
||||
bufLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef class TS590Command* PCmd;
|
||||
|
||||
int compareCATCommands(const void* a, const void* b) {
|
||||
TS590Command const *B = *(TS590Command const **)b;
|
||||
int cmp = strncmp((char*)a, (char*)B->prefix(), 2);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Comparison: ");
|
||||
Serial.print((char*)a);
|
||||
Serial.print(" ? ");
|
||||
Serial.print((char*)B->prefix());
|
||||
Serial.print(" --> ");
|
||||
Serial.println(cmp);
|
||||
#endif
|
||||
return cmp;
|
||||
}
|
||||
|
||||
int compareCATEXCommands(const void* a, const void* b) {
|
||||
TS590Command const *B = *(TS590Command const **)b;
|
||||
int cmp = strncmp((char*)a, (char*)B->prefix(), 5);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Comparison: ");
|
||||
Serial.print((char*)a);
|
||||
Serial.print(" ? ");
|
||||
Serial.print((char*)B->prefix());
|
||||
Serial.print(" --> ");
|
||||
Serial.println(cmp);
|
||||
#endif
|
||||
return cmp;
|
||||
}
|
||||
|
||||
void UBitxTS590::processCommand() {
|
||||
TS590Command** cmd;
|
||||
if (strncmp(buf, "EX", 2) == 0) {
|
||||
cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATEXCommands);
|
||||
} else {
|
||||
cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATCommands);
|
||||
}
|
||||
if (cmd == NULL) {
|
||||
ts590SyntaxError();
|
||||
} else {
|
||||
(*cmd)->process(buf);
|
||||
}
|
||||
bufLen = 0;
|
||||
}
|
||||
|
||||
UBitxTS590 TS590(catCommands, numCatCommands);
|
||||
|
||||
/**********************************************************************/
|
@ -1,354 +0,0 @@
|
||||
#ifndef __TS590_h__
|
||||
#define __TS590_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "DSP.h"
|
||||
#include "Rig.h"
|
||||
#include "TR.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
// uncomment to use TS-590SG / comment to use TS-590S
|
||||
#define USE_TS590SG
|
||||
|
||||
#define TS590_COMMAND_MAX_LENGTH 50 // including terminator (which will get converted to null)
|
||||
|
||||
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
||||
|
||||
void ts590SendCommand(const char*, ...);
|
||||
|
||||
/*!
|
||||
* @brief Send a syntax error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590SyntaxError() { ts590SendCommand("?"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a communications error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590CommError() { ts590SendCommand("E"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a processing error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590ProcessError() { ts590SendCommand("O"); }
|
||||
|
||||
enum TS590Error {
|
||||
NoError,
|
||||
SyntaxError,
|
||||
CommError,
|
||||
ProcessError
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief A TS590S/SG "CAT" command. This is the base class for all
|
||||
* CAT commands.
|
||||
*/
|
||||
class TS590Command {
|
||||
public:
|
||||
TS590Command(const char* pre);
|
||||
virtual ~TS590Command() = 0;
|
||||
|
||||
/*!
|
||||
* @brief Return the 2-character prefix for the command.
|
||||
* @return The 2-character prefix for the command.
|
||||
*/
|
||||
inline const char* prefix() const { return &myPrefix[0]; }
|
||||
|
||||
/*!
|
||||
* @brief Return the rig that this command will be used to control.
|
||||
*/
|
||||
inline UBitxRig* rig() const { return theRig; }
|
||||
|
||||
/*!
|
||||
* @brief Return the DSP that this command will be used to control.
|
||||
*/
|
||||
inline UBitxDSP* dsp() const { return theDSP; }
|
||||
|
||||
/*!
|
||||
* @brief Return the T/R that this command will be used to control.
|
||||
*/
|
||||
inline UBitxDSP* tr() const { return theTR; }
|
||||
|
||||
/*!
|
||||
* @brief Handle the provided Set command. If the Set command
|
||||
* results in an error, then set the appropriate flag with
|
||||
* setSyntaxError(), setCommError(), or setProcessError().
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
virtual void handleCommand(const char* cmd) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Send a response back to the PC. This assumes a
|
||||
* successful command (no errors).
|
||||
*/
|
||||
virtual void sendResponse(const char* cmd) = 0;
|
||||
|
||||
virtual bool isReadCommand(const char* cmd) const;
|
||||
|
||||
void process(const char* cmd);
|
||||
|
||||
static void setSyntaxError();
|
||||
static void setCommError();
|
||||
static void setProcessError();
|
||||
static void setRig(UBitxRig* r);
|
||||
static void setDSP(UBitxDSP* d);
|
||||
static void setTR(UBitxTR* t);
|
||||
|
||||
private:
|
||||
char myPrefix[3] = "\0\0";
|
||||
static TS590Error theError;
|
||||
static UBitxRig* theRig;
|
||||
static UBitxDSP* theDSP;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting or reading the VFO A/B frequency.
|
||||
*/
|
||||
template<bool VFOA>
|
||||
class TS590_FAB : public TS590Command {
|
||||
public:
|
||||
TS590_FAB(): TS590Command(VFOA ? "FA" : "FB") {}
|
||||
|
||||
virtual void handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 13) {
|
||||
unsigned long freq = strtoul(&cmd[2], NULL, 10);
|
||||
if (VFOA) {
|
||||
rig()->setFreqA(freq);
|
||||
} else {
|
||||
rig()->setFreqB(freq);
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void sendResponse(const char* cmd) {
|
||||
ts590SendCommand(VFOA ? "FA%011u" : "FB%011u", VFOA ? rig()->getFreqA() : rig()->getFreqB());
|
||||
}
|
||||
};
|
||||
|
||||
typedef TS590_FAB<true> TS590_FA;
|
||||
typedef TS590_FAB<false> TS590_FB;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver VFO. This will always
|
||||
* disable split mode, if it was previously enabled.
|
||||
*/
|
||||
class TS590_FR : public TS590Command {
|
||||
public:
|
||||
TS590_FR(): TS590Command("FR") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the transmitter VFO. If it is
|
||||
* different than the receiver VFO, then split mode will be
|
||||
* automatically enabled.
|
||||
*/
|
||||
class TS590_FT : public TS590Command {
|
||||
public:
|
||||
TS590_FT(): TS590Command("FT") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the mode.
|
||||
*/
|
||||
class TS590_MD : public TS590Command {
|
||||
public:
|
||||
TS590_MD(): TS590Command("MD") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver high-cut frequency.
|
||||
*/
|
||||
class TS590_SH : public TS590Command {
|
||||
public:
|
||||
TS590_SH(): TS590Command("SH") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
private:
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver low-cut frequency.
|
||||
*/
|
||||
class TS590_SL : public TS590Command {
|
||||
public:
|
||||
TS590_SL(): TS590Command("SL") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
private:
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief CAT command to start transmitting.
|
||||
*/
|
||||
class TS590_TX : public TS590Command {
|
||||
public:
|
||||
TS590_TX(): TS590Command("TX") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
class TS590EXCommand : public TS590Command {
|
||||
public:
|
||||
TS590EXCommand(const char *P1);
|
||||
virtual ~TS590EXCommand() = 0;
|
||||
|
||||
inline const char* menu() const { return &myMenu[0]; }
|
||||
|
||||
virtual const char* getReturnValue() const = 0;
|
||||
|
||||
virtual void sendResponse(const char* cmd);
|
||||
|
||||
private:
|
||||
char myMenu[4] = "\0\0\0";
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the sidetone pitch/frequency.
|
||||
*/
|
||||
class TS590_EX034 : public TS590EXCommand {
|
||||
public:
|
||||
TS590_EX034(): TS590EXCommand("034") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual const char* getReturnValue();
|
||||
private:
|
||||
uint8_t index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief CAT command for selecting the data input line.
|
||||
*/
|
||||
class TS590_EX063 : public TS590EXCommand {
|
||||
public:
|
||||
TS590_EX063(): TS590EXCommand("063") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual const char* getReturnValue();
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting USB/Line audio input levels.
|
||||
*/
|
||||
template<bool USB, bool SG>
|
||||
class TS590_EXDataAudioInLevel : public TS590EXCommand {
|
||||
public:
|
||||
TS590_EXDataAudioInLevel(): TS590EXCommand(USB ? (SG ? "071" : "064") : (SG ? "073" : "066")) {}
|
||||
|
||||
virtual void handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10) {
|
||||
uint8_t val = (cmd[9] - 48) % 10;
|
||||
if (USB) {
|
||||
// set USB input level
|
||||
} else {
|
||||
// set Line input level
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char* getReturnValue() {
|
||||
static char str[2] = "\0";
|
||||
// get input level - decimal 0 to 9 ... str[1] = ...
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_TS590SG
|
||||
typedef TS590_EXDataAudioInLevel<true, true> TS590_EX071;
|
||||
typedef TS590_EXDataAudioInLevel<false, true> TS590_EX073;
|
||||
#else
|
||||
typedef TS590_EXDataAudioInLevel<true, false> TS590_EX064;
|
||||
typedef TS590_EXDataAudioInLevel<true, false> TS590_EX066;
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting USB/Line audio output levels.
|
||||
*/
|
||||
template<bool USB, bool SG>
|
||||
class TS590_EXDataAudioOutLevel : public TS590EXCommand {
|
||||
public:
|
||||
TS590_EXDataAudioOutLevel(): TS590EXCommand(USB ? (SG ? "072" : "065") : (SG ? "074" : "067")) {}
|
||||
|
||||
virtual void handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 10) {
|
||||
uint8_t val = (cmd[9] - 48) % 10;
|
||||
if (USB) {
|
||||
// set USB output level
|
||||
} else {
|
||||
// set Line output level
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
virtual const char* getReturnValue() {
|
||||
static char str[2] = "\0";
|
||||
// get output level - decimal 0 to 9 ... str[1] = ...
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_TS590SG
|
||||
typedef TS590_EXDataAudioOutLevel<true, true> TS590_EX072;
|
||||
typedef TS590_EXDataAudioOutLevel<false, true> TS590_EX074;
|
||||
#else
|
||||
typedef TS590_EXDataAudioOutLevel<true, false> TS590_EX065;
|
||||
typedef TS590_EXDataAudioOutLevel<true, false> TS590_EX067;
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
class UBitxTS590 {
|
||||
public:
|
||||
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
||||
|
||||
void begin();
|
||||
void update();
|
||||
|
||||
private:
|
||||
void processCommand();
|
||||
|
||||
char buf[ts590CommandMaxLength] = {0};
|
||||
int bufLen = 0;
|
||||
TS590Command** commands;
|
||||
int numCommands;
|
||||
};
|
||||
|
||||
extern UBitxTS590 TS590;
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
@ -7,27 +7,30 @@ KD8CEC, Ian Lee
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Debug.h"
|
||||
#include "DSP.h"
|
||||
#include "Keyer.h"
|
||||
#include "Nextion.h"
|
||||
#include "Rig.h"
|
||||
#include "RigState.h"
|
||||
#include "Sensors.h"
|
||||
#include "TR.h"
|
||||
#include "TS590.h"
|
||||
#include <arduino.h>
|
||||
|
||||
//================================================================
|
||||
//COMMUNICATION SECTION
|
||||
//================================================================
|
||||
#define USE_SW_SERIAL
|
||||
|
||||
extern void SWSerial_Write(uint8_t b);
|
||||
extern void SWSerial_Print(uint8_t *b);
|
||||
|
||||
#ifdef USE_SW_SERIAL
|
||||
extern void SWSerial_Begin(long speedBaud);
|
||||
extern int SWSerial_Available(void);
|
||||
extern int SWSerial_Read(void);
|
||||
#else
|
||||
|
||||
#define PRINT_MAX_LENGTH 30
|
||||
#endif
|
||||
|
||||
//================================================================
|
||||
// FFT and Decode Morse
|
||||
//FFT and Decode Morse
|
||||
//================================================================
|
||||
|
||||
#define FFTSIZE 64
|
||||
#define SAMPLE_FREQUENCY 6000
|
||||
#define SAMPLE_PREQUENCY 6000
|
||||
#define SAMPLESIZE (FFTSIZE * 2)
|
||||
#define DECODE_MORSE_SAMPLESIZE 48
|
||||
|
||||
@ -35,9 +38,8 @@ extern uint8_t cwDecodeHz;
|
||||
extern int magnitudelimit_low;
|
||||
|
||||
//================================================================
|
||||
// EEPROM Section
|
||||
//EEPROM Section
|
||||
//================================================================
|
||||
|
||||
#define MAX_FORWARD_BUFF_LENGTH 128
|
||||
#define EEPROM_DSPTYPE 100
|
||||
#define EEPROM_SMETER_UART 111
|
||||
@ -50,9 +52,8 @@ extern int magnitudelimit_low;
|
||||
#define EEPROM_RTTYDECODEHZ 130
|
||||
|
||||
//================================================================
|
||||
// DEFINE for I2C Command
|
||||
//DEFINE for I2C Command
|
||||
//================================================================
|
||||
|
||||
//S-Meter Address
|
||||
#define I2CMETER_ADDR 0x58 //changed from 0x6A
|
||||
//VALUE TYPE============================================
|
||||
@ -68,8 +69,8 @@ extern int magnitudelimit_low;
|
||||
#define I2CMETER_CALCR 0x55 //Calculated SWR Meter
|
||||
#define I2CMETER_UNCALCR 0x54 //Uncalculated SWR Meter
|
||||
|
||||
// Raduino<=>TeensyDSP data exchange
|
||||
#define I2CMETER_RIGINF 0x50
|
||||
#define SIGNAL_METER_ADC A7
|
||||
#define POWER_METER_ADC A3
|
||||
#define SWR_METER_ADC A2
|
||||
|
||||
|
||||
// Raduino requests any CAT updates from TeensyDSP
|
||||
//#define I2CMETER_REQCAT 0x51
|
||||
|
File diff suppressed because it is too large
Load Diff
362
TeensyDSP/fftfunctions.cpp
Normal file
362
TeensyDSP/fftfunctions.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
FFTFunctions for Nextion LCD and Control MCU
|
||||
This code is for FFT and CW Decode.
|
||||
KD8CEC, Ian Lee
|
||||
-----------------------------------------------------------------------
|
||||
//The section on CW decode logic is specified at the bottom of this code.
|
||||
License : I follow the license of the previous code and I do not add any extra constraints.
|
||||
I hope that the Comment I made or the Comment of OZ1JHM will be maintained.
|
||||
**********************************************************************/
|
||||
#include <arduino.h>
|
||||
#include "TeensyDSP.h"
|
||||
|
||||
// Code Referency : http://paulbourke.net/miscellaneous/dft/
|
||||
// DFT, FFT Wiritten by Paul Bourke, June 1993
|
||||
void FFT(double *x,double *y, int n, long m)
|
||||
{
|
||||
long i,i1,j,k,i2,l,l1,l2;
|
||||
double c1,c2,tx,ty,t1,t2,u1,u2,z;
|
||||
short int dir = 0;
|
||||
|
||||
/* Do the bit reversal */
|
||||
i2 = n >> 1;
|
||||
j = 0;
|
||||
for (i=0;i<n-1;i++) {
|
||||
if (i < j) {
|
||||
tx = x[i];
|
||||
ty = y[i];
|
||||
x[i] = x[j];
|
||||
y[i] = y[j];
|
||||
x[j] = tx;
|
||||
y[j] = ty;
|
||||
}
|
||||
k = i2;
|
||||
while (k <= j) {
|
||||
j -= k;
|
||||
k >>= 1;
|
||||
}
|
||||
j += k;
|
||||
}
|
||||
|
||||
/* Compute the FFT */
|
||||
c1 = -1.0;
|
||||
c2 = 0.0;
|
||||
l2 = 1;
|
||||
|
||||
for (l=0;l<m;l++)
|
||||
{
|
||||
l1 = l2;
|
||||
l2 <<= 1;
|
||||
u1 = 1.0;
|
||||
u2 = 0.0;
|
||||
for (j=0;j<l1;j++)
|
||||
{
|
||||
for (i=j;i<n;i+=l2)
|
||||
{
|
||||
i1 = i + l1;
|
||||
t1 = u1 * x[i1] - u2 * y[i1];
|
||||
t2 = u1 * y[i1] + u2 * x[i1];
|
||||
x[i1] = x[i] - t1;
|
||||
y[i1] = y[i] - t2;
|
||||
x[i] += t1;
|
||||
y[i] += t2;
|
||||
}
|
||||
z = u1 * c1 - u2 * c2;
|
||||
u2 = u1 * c2 + u2 * c1;
|
||||
u1 = z;
|
||||
}
|
||||
c2 = sqrt((1.0 - c1) / 2.0);
|
||||
if (dir == 1)
|
||||
c2 = -c2;
|
||||
c1 = sqrt((1.0 + c1) / 2.0);
|
||||
}
|
||||
|
||||
/* Scaling for forward transform */
|
||||
/*
|
||||
if (dir == 1) {
|
||||
for (i=0;i<n;i++) {
|
||||
x[i] /= n;
|
||||
y[i] /= n;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
*/
|
||||
|
||||
//return(TRUE);
|
||||
}
|
||||
|
||||
double coeff;
|
||||
|
||||
void CalculateCoeff(uint8_t freqIndex)
|
||||
{
|
||||
float omega;
|
||||
int targetFrequency = freqIndex * 50 + 300;
|
||||
int k = (int) (0.5 + ((DECODE_MORSE_SAMPLESIZE * targetFrequency) / SAMPLE_PREQUENCY));
|
||||
omega = (2.0 * PI * k) / DECODE_MORSE_SAMPLESIZE;
|
||||
coeff = 2.0 * cos(omega);
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
//The CW Decode code refers to the site code below.
|
||||
//https://k2jji.org/2014/09/18/arduino-base-cw-decoder/
|
||||
//Some code has been modified, but the original comments remain intact.
|
||||
// code below is optimal for use in Arduino.
|
||||
//Thanks to OZ1JHM
|
||||
//KD8CEC
|
||||
//=====================================================================
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// CW Decoder made by Hjalmar Skovholm Hansen OZ1JHM VER 1.01 //
|
||||
// Feel free to change, copy or what ever you like but respect //
|
||||
// that license is http://www.gnu.org/copyleft/gpl.html //
|
||||
// Discuss and give great ideas on //
|
||||
// https://groups.yahoo.com/neo/groups/oz1jhm/conversations/messages //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Read more here http://en.wikipedia.org/wiki/Goertzel_algorithm //
|
||||
// if you want to know about FFT the http://www.dspguide.com/pdfbook.htm //
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//int magnitudelimit = 50;
|
||||
//int magnitudelimit_low = 50;
|
||||
int magnitudelimit = 30;
|
||||
int magnitudelimit_low = 30;
|
||||
char realstate = LOW;
|
||||
char realstatebefore = LOW;
|
||||
char filteredstate = LOW;
|
||||
char filteredstatebefore = LOW;
|
||||
long laststarttime = 0;
|
||||
int nbtime = 6; /// ms noise blanker
|
||||
|
||||
long starttimehigh;
|
||||
long highduration;
|
||||
long lasthighduration;
|
||||
long hightimesavg;
|
||||
long lowtimesavg;
|
||||
long startttimelow;
|
||||
long lowduration;
|
||||
|
||||
char code[20];
|
||||
uint8_t stop = LOW;
|
||||
int wpm;
|
||||
uint8_t cwDecodeHz = 9;
|
||||
|
||||
extern void SendCommandStr(char varIndex, char* sendValue);
|
||||
|
||||
void printascii(int asciinumber)
|
||||
{
|
||||
char rstDecode[4] = {0, 0, 0, 0};
|
||||
|
||||
if (asciinumber == 3)
|
||||
{
|
||||
|
||||
}
|
||||
else if (asciinumber == 4)
|
||||
{
|
||||
|
||||
}
|
||||
else if (asciinumber == 6)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
rstDecode[0] = asciinumber;
|
||||
}
|
||||
SendCommandStr('b', rstDecode);
|
||||
|
||||
//Serial.write(asciinumber);
|
||||
//if (writeCount++ > 20)
|
||||
//{
|
||||
//writeCount = 0;
|
||||
//Serial.println("");
|
||||
//}
|
||||
}
|
||||
|
||||
uint8_t docode()
|
||||
{
|
||||
if (strcmp(code,".-") == 0) printascii(65);
|
||||
if (strcmp(code,"-...") == 0) printascii(66);
|
||||
if (strcmp(code,"-.-.") == 0) printascii(67);
|
||||
if (strcmp(code,"-..") == 0) printascii(68);
|
||||
if (strcmp(code,".") == 0) printascii(69);
|
||||
if (strcmp(code,"..-.") == 0) printascii(70);
|
||||
if (strcmp(code,"--.") == 0) printascii(71);
|
||||
if (strcmp(code,"....") == 0) printascii(72);
|
||||
if (strcmp(code,"..") == 0) printascii(73);
|
||||
if (strcmp(code,".---") == 0) printascii(74);
|
||||
if (strcmp(code,"-.-") == 0) printascii(75);
|
||||
if (strcmp(code,".-..") == 0) printascii(76);
|
||||
if (strcmp(code,"--") == 0) printascii(77);
|
||||
if (strcmp(code,"-.") == 0) printascii(78);
|
||||
if (strcmp(code,"---") == 0) printascii(79);
|
||||
if (strcmp(code,".--.") == 0) printascii(80);
|
||||
if (strcmp(code,"--.-") == 0) printascii(81);
|
||||
if (strcmp(code,".-.") == 0) printascii(82);
|
||||
if (strcmp(code,"...") == 0) printascii(83);
|
||||
if (strcmp(code,"-") == 0) printascii(84);
|
||||
if (strcmp(code,"..-") == 0) printascii(85);
|
||||
if (strcmp(code,"...-") == 0) printascii(86);
|
||||
if (strcmp(code,".--") == 0) printascii(87);
|
||||
if (strcmp(code,"-..-") == 0) printascii(88);
|
||||
if (strcmp(code,"-.--") == 0) printascii(89);
|
||||
if (strcmp(code,"--..") == 0) printascii(90);
|
||||
|
||||
if (strcmp(code,".----") == 0) printascii(49);
|
||||
if (strcmp(code,"..---") == 0) printascii(50);
|
||||
if (strcmp(code,"...--") == 0) printascii(51);
|
||||
if (strcmp(code,"....-") == 0) printascii(52);
|
||||
if (strcmp(code,".....") == 0) printascii(53);
|
||||
if (strcmp(code,"-....") == 0) printascii(54);
|
||||
if (strcmp(code,"--...") == 0) printascii(55);
|
||||
if (strcmp(code,"---..") == 0) printascii(56);
|
||||
if (strcmp(code,"----.") == 0) printascii(57);
|
||||
if (strcmp(code,"-----") == 0) printascii(48);
|
||||
|
||||
if (strcmp(code,"..--..") == 0) printascii(63);
|
||||
if (strcmp(code,".-.-.-") == 0) printascii(46);
|
||||
if (strcmp(code,"--..--") == 0) printascii(44);
|
||||
if (strcmp(code,"-.-.--") == 0) printascii(33);
|
||||
if (strcmp(code,".--.-.") == 0) printascii(64);
|
||||
if (strcmp(code,"---...") == 0) printascii(58);
|
||||
if (strcmp(code,"-....-") == 0) printascii(45);
|
||||
if (strcmp(code,"-..-.") == 0) printascii(47);
|
||||
|
||||
if (strcmp(code,"-.--.") == 0) printascii(40);
|
||||
if (strcmp(code,"-.--.-") == 0) printascii(41);
|
||||
if (strcmp(code,".-...") == 0) printascii(95);
|
||||
if (strcmp(code,"...-..-") == 0) printascii(36);
|
||||
if (strcmp(code,"...-.-") == 0) printascii(62);
|
||||
if (strcmp(code,".-.-.") == 0) printascii(60);
|
||||
if (strcmp(code,"...-.") == 0) printascii(126);
|
||||
//////////////////
|
||||
// The specials //
|
||||
//////////////////
|
||||
if (strcmp(code,".-.-") == 0) printascii(3);
|
||||
if (strcmp(code,"---.") == 0) printascii(4);
|
||||
if (strcmp(code,".--.-") == 0) printascii(6);
|
||||
|
||||
}
|
||||
|
||||
void Decode_Morse(float magnitude)
|
||||
{
|
||||
//magnitudelimit auto Increase
|
||||
if (magnitude > magnitudelimit_low)
|
||||
{
|
||||
magnitudelimit = (magnitudelimit +((magnitude - magnitudelimit)/6)); /// moving average filter
|
||||
}
|
||||
|
||||
if (magnitudelimit < magnitudelimit_low)
|
||||
magnitudelimit = magnitudelimit_low;
|
||||
|
||||
if(magnitude > magnitudelimit*0.6) // just to have some space up
|
||||
realstate = HIGH;
|
||||
else
|
||||
realstate = LOW;
|
||||
|
||||
if (realstate != realstatebefore)
|
||||
laststarttime = millis();
|
||||
|
||||
if ((millis()-laststarttime) > nbtime)
|
||||
{
|
||||
if (realstate != filteredstate)
|
||||
{
|
||||
filteredstate = realstate;
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredstate != filteredstatebefore)
|
||||
{
|
||||
if (filteredstate == HIGH)
|
||||
{
|
||||
starttimehigh = millis();
|
||||
lowduration = (millis() - startttimelow);
|
||||
}
|
||||
|
||||
if (filteredstate == LOW)
|
||||
{
|
||||
startttimelow = millis();
|
||||
highduration = (millis() - starttimehigh);
|
||||
|
||||
if (highduration < (2*hightimesavg) || hightimesavg == 0)
|
||||
{
|
||||
hightimesavg = (highduration+hightimesavg+hightimesavg)/3; // now we know avg dit time ( rolling 3 avg)
|
||||
}
|
||||
|
||||
if (highduration > (5*hightimesavg) )
|
||||
{
|
||||
hightimesavg = highduration+hightimesavg; // if speed decrease fast ..
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// now we will check which kind of baud we have - dit or dah //
|
||||
// and what kind of pause we do have 1 - 3 or 7 pause //
|
||||
// we think that hightimeavg = 1 bit //
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
if (filteredstate != filteredstatebefore)
|
||||
{
|
||||
stop = LOW;
|
||||
if (filteredstate == LOW)
|
||||
{
|
||||
if (highduration < (hightimesavg*2) && highduration > (hightimesavg*0.6)) /// 0.6 filter out false dits
|
||||
{
|
||||
strcat(code,".");
|
||||
}
|
||||
if (highduration > (hightimesavg*2) && highduration < (hightimesavg*6))
|
||||
{
|
||||
strcat(code,"-");
|
||||
wpm = (wpm + (1200/((highduration)/3)))/2; //// the most precise we can do ;o)
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredstate == HIGH)
|
||||
{
|
||||
float lacktime = 1;
|
||||
if(wpm > 25)lacktime=1.0; /// when high speeds we have to have a little more pause before new letter or new word
|
||||
if(wpm > 30)lacktime=1.2;
|
||||
if(wpm > 35)lacktime=1.5;
|
||||
|
||||
if (lowduration > (hightimesavg*(2*lacktime)) && lowduration < hightimesavg*(5*lacktime)) // letter space
|
||||
{
|
||||
docode();
|
||||
code[0] = '\0';
|
||||
}
|
||||
if (lowduration >= hightimesavg*(5*lacktime))
|
||||
{ // word space
|
||||
docode();
|
||||
code[0] = '\0';
|
||||
printascii(32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((millis() - startttimelow) > (highduration * 6) && stop == LOW)
|
||||
{
|
||||
docode();
|
||||
code[0] = '\0';
|
||||
stop = HIGH;
|
||||
}
|
||||
|
||||
/*
|
||||
if(filteredstate == HIGH)
|
||||
{
|
||||
digitalWrite(ledPin, HIGH);
|
||||
tone(audioOutPin,target_freq);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(ledPin, LOW);
|
||||
noTone(audioOutPin);
|
||||
}
|
||||
*/
|
||||
|
||||
realstatebefore = realstate;
|
||||
lasthighduration = highduration;
|
||||
filteredstatebefore = filteredstate;
|
||||
}
|
||||
|
386
TeensyDSP/temp.h
386
TeensyDSP/temp.h
@ -1,386 +0,0 @@
|
||||
const int rxLoCutSSB[] = { 0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
||||
const int rxHiCutSSB[] = {1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000, 3400, 4000, 5000};
|
||||
const int rxDataWidth[] = { 50, 80, 100, 150, 200, 250, 300, 400, 500, 600, 1000, 1500, 2000, 2500};
|
||||
#ifdef USE_TS590SG
|
||||
const int rxDataShift[] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2100, 2210};
|
||||
#else
|
||||
const int rxDataShift[] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2210};
|
||||
#endif
|
||||
|
||||
const int txLowCutFilter[] = { 10, 100, 200, 300, 400, 500};
|
||||
const int txHighCutFilter[] = {2500, 2600, 2700, 2800, 2900, 3000};
|
||||
const int timeOutMinutes[] = {3, 5, 10, 20, 30};
|
||||
|
||||
#define MAX_MENU_TITLE_LEN 13
|
||||
#define MAX_MENU_OPTION_LEN 13
|
||||
|
||||
typedef void (*toggleFunc)(UBitxRig&);
|
||||
typedef bool (*boolStatus)(UBitxRig&);
|
||||
|
||||
#define KEYER_MIN_SPEED 4
|
||||
#define KEYER_MAX_SPEED 60
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Abstract base class for a switch/toggle (on/off, A/B, etc.)
|
||||
* option. Derived classes must provide set() and get()
|
||||
* methods for controlling the state of the switch.
|
||||
*/
|
||||
struct ConfigSwitch {
|
||||
virtual ~ConfigSwitch() = 0;
|
||||
virtual void set(bool on) = 0;
|
||||
virtual bool get() const = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Abstract base class for an option that supports a linear
|
||||
* sequence of integer values. There can be a minimum and a
|
||||
* maximum value, but otherwise, all integers between those
|
||||
* should be acceptable. The base class takes care of checking
|
||||
* min/max bounds, so the derived class must provide an get()
|
||||
* and onSet() methods. In addition, derived classes can
|
||||
* optionally override the onTooHigh() and onTooLow(), which
|
||||
* by default clamp any out-of-band inputs to the min/max.
|
||||
*/
|
||||
struct ConfigInteger {
|
||||
ConfigInteger(int min, int max)
|
||||
: myMin(min), myMax(max) {}
|
||||
|
||||
virtual ~ConfigInteger() = 0;
|
||||
|
||||
inline void set(int val) {
|
||||
if (val > myMax) val = onTooHigh(val);
|
||||
if (val < myMin) val = onTooLow(val);
|
||||
onSet(val);
|
||||
}
|
||||
|
||||
virtual int get() const = 0;
|
||||
virtual void onSet() = 0;
|
||||
virtual int onTooHigh(int val) const { return myMax; }
|
||||
virtual int onTooLow(int val) const { return myMin; }
|
||||
|
||||
int myMin, myMax;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief Abstract base class for an option that supports a set
|
||||
* of integer values stored in an array. The derived
|
||||
* class must provide get() and onSet() methods. It can
|
||||
* optionally provide an onTooHigh() method, which by
|
||||
* default will clamp indices to the highest allowable.
|
||||
*/
|
||||
struct ConfigArray {
|
||||
ConfigArray(int len, int* data)
|
||||
: myLen(len), myData(data) {}
|
||||
|
||||
virtual ~ConfigArray() = 0;
|
||||
|
||||
inline void set(int i) {
|
||||
if (i < 0) i = 0;
|
||||
if (i > myLen - 1) i = onTooHigh(i);
|
||||
onSet(myData[i]);
|
||||
}
|
||||
|
||||
virtual int get() const = 0;
|
||||
virtual void onSet(int val) = 0;
|
||||
virtual int onTooHigh(int i) const { return myLen - 1; }
|
||||
inline int getData(int i) { return myData[i]; }
|
||||
|
||||
int myLen;
|
||||
int *myData;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Option class to set the configuration of the RX DSP filter.
|
||||
*/
|
||||
template<bool isHIGH>
|
||||
struct ConfigRXFilter : public ConfigArray {
|
||||
ConfigFilter(UBitxDSP& d, int default)
|
||||
: ConfigArray(0, NULL), dsp(d), useData(false) {
|
||||
if (isHIGH) {
|
||||
current[0] = 10; // SSB - hi cut
|
||||
current[1] = 05; // Data - center (shift)
|
||||
data[0] = rxHiCutSSB;
|
||||
data[1] = rxDataShift;
|
||||
length[0] = sizeof(rxHiCutSSB)/sizeof(rxHiCutSSB[0]);
|
||||
length[1] = sizeof(rxDataShift)/sizeof(rxDataShift[0]);
|
||||
} else {
|
||||
current[0] = 04; // SSB - lo cut
|
||||
current[1] = 12; // Data - width
|
||||
data[0] = rxLoCutSSB;
|
||||
data[1] = rxDataWidth;
|
||||
length[0] = sizeof(rxLoCutSSB)/sizeof(rxLoCutSSB[0]);
|
||||
length[1] = sizeof(rxDataWidth)/sizeof(rxDataWidth[0]);
|
||||
}
|
||||
}
|
||||
// TODO - A TON MORE TO DO HERE TO MAKE IT CONSISTENT WITH CONSTRUCTION
|
||||
inline void setSSB() {
|
||||
useData = false;
|
||||
}
|
||||
inline void setData() { useData = true; }
|
||||
|
||||
virtual void get() { return current; }
|
||||
virtual void onSet(int i) {
|
||||
current = i;
|
||||
float value = static_cast<float>(getData(i));
|
||||
if (isHIGH) {
|
||||
if (useCENTER) {
|
||||
dsp.setRxFilterCenter(value);
|
||||
} else {
|
||||
dsp.setRxFilterHi(value);
|
||||
}
|
||||
} else {
|
||||
if (useCENTER) {
|
||||
dsp.setRxFilterWidth(value);
|
||||
} else {
|
||||
dsp.setRxFilterLo(static_cast<float>(getData(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
UBitxDSP& dsp;
|
||||
int* data[2];
|
||||
int length[2];
|
||||
int current[2];
|
||||
int mode; // 0 = SSB, 1 = Data
|
||||
};
|
||||
typedef ConfigRXFilter<false, false> ConfigRxLoCutSSB;
|
||||
typedef ConfigRXFilter<true, false> ConfigRxHiCutSSB;
|
||||
typedef ConfigRXFilter<false, true > ConfigRxLoCutData;
|
||||
typedef ConfigRXFilter<true, true > ConfigRxHiCutData;
|
||||
|
||||
struct DSPConfigurator {
|
||||
DSPConfigurator(UBitxDSP& d)
|
||||
: dsp(d) {}
|
||||
|
||||
ConfigRxLoCutSSB ssbRxLoCut;
|
||||
ConfigRxHiCutSSB ssbRxHiCut;
|
||||
ConfigRxLoCutData dataRxLoCut;
|
||||
ConfigRxHiCutData dataRxHiCut;
|
||||
|
||||
private:
|
||||
UBitxDSP& dsp;
|
||||
} dspConfigurator(DSP);
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief A configuration class for the Keyer. Since the Keyer has
|
||||
* its own state that is not 100% compatible with the way way
|
||||
* the Rig will interact with it (primarily in terms of CAT
|
||||
* commands), this class provides the glue. (This is mostly
|
||||
* used because, while the configuration objects are generally
|
||||
* all separate, there is some state that needs to be
|
||||
* communicated between e.g. the iambic mode configuration and
|
||||
* the bug mode configuration.)
|
||||
*/
|
||||
struct KeyerConfigurator {
|
||||
KeyerConfigurator(UBitxKeyer& k): keyer(k) { iambicAB = keyer.getMode(); }
|
||||
|
||||
/*!
|
||||
* @brief An inner class that supports switching between Iambic A & B.
|
||||
*/
|
||||
struct IambicMode : public ConfigSwitch {
|
||||
IambicMode(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
||||
virtual void set(bool on) {
|
||||
config.iambicAB = on;
|
||||
if (config.keyer.getMode() != STRAIGHT) {
|
||||
config.keyer.setMode(config.iambicAB ? IAMBICB : IAMBICA);
|
||||
}
|
||||
}
|
||||
virtual bool get() const { return config.iambicAB; }
|
||||
private: KeyerConfigurator& config;
|
||||
} iambicMode;
|
||||
|
||||
/*!
|
||||
* @brief An inner class that supports switching bug mode on/off.
|
||||
*/
|
||||
struct BugMode : public ConfigSwitch {
|
||||
BugMode(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
||||
virtual void set(bool on) {
|
||||
config.isBug = on;
|
||||
if (config.isBug && (config.keyer.getMode() != STRAIGHT)) {
|
||||
config.keyer.setMode(STRAIGHT);
|
||||
} else if (!config.isBug && (config.keyer.getMode() == STRAIGHT)) {
|
||||
config.keyer.setMode(config.iambicAB ? IAMBICB : IAMBICA);
|
||||
}
|
||||
}
|
||||
virtual bool get() const { return config.isBug; }
|
||||
private: KeyerConfigurator& config;
|
||||
} bugMode;
|
||||
|
||||
/*!
|
||||
* @brief An inner class that supports switching the left and right
|
||||
* paddles. TODO: This currently does nothing.
|
||||
*/
|
||||
struct PaddleSwap : public ConfigSwitch {
|
||||
PaddleSwap(KeyerConfigurator& c): ConfigSwitch(), config(c) {}
|
||||
virtual void set(bool on) { ; }
|
||||
virtual bool get() const { return false(); }
|
||||
private: KeyerConfigurator& config;
|
||||
} paddleSwap;
|
||||
|
||||
/*!
|
||||
* @brief An inner class that supports changing the keyer speed.
|
||||
*/
|
||||
struct KeyerSpeed : public ConfigInteger {
|
||||
KeyerSpeed(KeyerConfigurator& c): ConfigInteger(KEYER_MIN_SPEED, KEYER_MAX_SPEED), config(c) {}
|
||||
virtual void onSet(int val) { config.keyer.setWPM(val); }
|
||||
virtual int get { return config.keyer.getWPM(); }
|
||||
private: KeyerConfigurator& config;
|
||||
} keyerSpeed;
|
||||
|
||||
private:
|
||||
Keyer& keyer;
|
||||
bool iambicAB;
|
||||
bool isBug;
|
||||
} keyerConfigurator(Keyer);
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
class MenuItem {
|
||||
public:
|
||||
MenuItem(int idno, const char* title, int numOpt, int defOpt, ): myID(idno), myTitle(title), numOptions(numOpt), selected(defOpt) {}
|
||||
virtual ~MenuItem() = 0;
|
||||
|
||||
inline void id() { return myID; }
|
||||
|
||||
inline void writeTitle(char* outbuf, int maxlen) { strncpy(outbuf, myTitle, maxlen); }
|
||||
inline char* writeOption(char* outbuf, int o = -1, int maxlen = MAX_MENU_OPTION_LEN) {
|
||||
if (o == -1) {
|
||||
setOptionText(selected);
|
||||
} else if ((o >= 0) && (o < numOptions)) {
|
||||
setOptionTitle(o);
|
||||
} else {
|
||||
memset(myOption, '\0', MAX_MENU_OPTION_LEN);
|
||||
}
|
||||
return strncpy(outbuf, myOption, maxlen);
|
||||
}
|
||||
|
||||
inline int getNumOptions() { return numOptions; }
|
||||
inline int getSelected() { return selected; }
|
||||
inline int nextOption(bool doUpdate = true) {
|
||||
selected = (selected + 1) % numOptions;
|
||||
if (doUpdate) update();
|
||||
return selected;
|
||||
}
|
||||
inline int prevOption(bool doUpdate = true) {
|
||||
selected = (selected - 1) % numOptions;
|
||||
if (doUpdate) update();
|
||||
return selected;
|
||||
}
|
||||
inline int gotoOption(int o, bool doUpdate = true) {
|
||||
selected = o >= numOptions ? numOptions : (o < 0 ? 0 : o);
|
||||
if (doUpdate) update();
|
||||
return selected;
|
||||
}
|
||||
virtual void update() = 0;
|
||||
|
||||
private:
|
||||
int myID;
|
||||
char myTitle[MAX_MENU_TITLE_LEN] = {'\0'};
|
||||
char myOption[MAX_MENU_OPTION_LEN] = {'\0'};
|
||||
|
||||
int numOptions;
|
||||
int selected;
|
||||
};
|
||||
|
||||
class StepItem : public MenuItem {
|
||||
public:
|
||||
StepItem(int idno, const char* title, int numOpt, int defOpt): MenuItem(idno, title, numOpt, defOpt) {}
|
||||
};
|
||||
|
||||
static const char off_str[] = "OFF";
|
||||
static const char on_str[] = "ON";
|
||||
static const char line_str[] = "LINE";
|
||||
static const char usb_str[] = "USB";
|
||||
static const char key_a_str[] = "A";
|
||||
static const char key_b_str[] = "B";
|
||||
|
||||
class ToggleItem : public MenuItem {
|
||||
public:
|
||||
ToggleItem(int idno, const char* title, const char* off, const char* on, int defOpt): MenuItem(idno, title, 2, defOpt) {}
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
struct MenuConfig {
|
||||
byte sidetoneVolume = 9;
|
||||
byte ssbLoCut = 0;
|
||||
byte ssbHiCut = 5;
|
||||
byte dataLoCut = 0;
|
||||
byte dataHiCut = 0;
|
||||
byte keyerAB = 0;
|
||||
byte sidetonePitch = 6;
|
||||
};
|
||||
|
||||
// CAT COMMANDS - BASIC
|
||||
|
||||
// KS - Sets and reads the Keying speed.
|
||||
IntegerItem ("KS", "KEYER SPEED", 0, 2, keyerConfigurator.keyerSpeed),
|
||||
ArrayItem ("SH", "RX HI CUT ", 0, 2, dspConfigurator.ssbRxHiCut),
|
||||
ArrayItem ("SL", "RX LO CUT ", 0, 2, dspConfigurator.ssbRxLoCut),
|
||||
|
||||
// CAT COMMANDS - EX MENU
|
||||
|
||||
// Sidetone volume
|
||||
Steps {004, "ST VOL ", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// SSB/AM Low Cut transmit filter (Hz)
|
||||
Steps {025, "SSB TX LO ", 6, [](auto x) { return txLowCutFilter[x]; }},
|
||||
// SSB/AM High Cut transmit filter (Hz)
|
||||
Steps {026, "SSB TX HI ", 6, [](auto x) { return txHighCutFilter[x]; }},
|
||||
// SSB-DATA Low Cut transmit filter (Hz)
|
||||
Steps {027, "DATA TX LO ", 6, [](auto x) { return txLowCutFilter[x]; }},
|
||||
// SSB-DATA High Cut transmit filter (Hz)
|
||||
Steps {028, "DATA TX HI ", 6, [](auto x) { return txHighCutFilter[x]; }},
|
||||
// Electronic keyer operation mode
|
||||
ToggleItem (032, "KEYER A/B ", "A ", "B ", keyerConfigurator.iambicMode),
|
||||
// Sidetone/ pitch frequency setting (Hz)
|
||||
Steps {034, "ST PITCH ", 15, [](auto x) { return 300+(x*50); }},
|
||||
// Keying weight ratio
|
||||
StepsSpec {036, "KEYER WEIGHT", 17, ...},
|
||||
// Bug key function
|
||||
ToggleItem (038, "KEYER BUG ", "OFF ", "ON ", keyerConfigurator.bugMode),
|
||||
// Paddle dot/dash replacement setting
|
||||
ToggleItem (039, "KEYER SWAP ", "OFF ", "ON ", keyerConfigurator.paddleSwap),
|
||||
// Auto CW TX in SSB mode
|
||||
//ToggleItem (041, "AUTO CW TX ", "OFF ", "ON ", [&Rig](bool on) { Rig.setKeyerAutoTransmitCW(on); } ),
|
||||
// Time-out Timer
|
||||
//StepsSpec {049, "TIMEOUT ", 6, ... },
|
||||
// Transmit inhibit
|
||||
ToggleItem (060, "TX INHIBIT ", "OFF ", "ON ", [&Rig](bool on) { Rig.setTransmitInhibit(on); } ),
|
||||
// DATA moduleation line
|
||||
ToggleItem (063, "DATA LINE ", "LINE", "USB ", [&Rig](bool usb) { Rig.setDataInputLine(usb); } ),
|
||||
// USB audio input level
|
||||
Steps {064, "USB IN LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// USB audio output level
|
||||
Steps {065, "USB OUT LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// ACC2 terminal AF input level
|
||||
Steps {066, "LINE IN LVL ", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// ACC2 terminal AF output level
|
||||
Steps {067, "LINE OUT LVL", [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// DATA VOX
|
||||
ToggleItem (069, "DATA VOX ", "OFF ", "ON ", [&Rig](bool on) { Rig.setDataVoxOn(on); } ),
|
||||
// DATA VOX delay
|
||||
Steps {070, "DATA VOX DEL", 20, ...},
|
||||
// DATA VOX gain for USB audio input
|
||||
Steps {071, "USB VOX LVL ", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
// DATA VOX gain for ACC2 terminal input
|
||||
Steps {072, "LINE VOX LVL", 10, [](auto x) { return static_cast<double>(x-48)/9.0; }},
|
||||
|
||||
|
||||
|
||||
|
355
TeensyDSP/uart_forward.cpp
Normal file
355
TeensyDSP/uart_forward.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
/*
|
||||
Softserial for Nextion LCD and Control MCU
|
||||
KD8CEC, Ian Lee
|
||||
-----------------------------------------------------------------------
|
||||
It is a library rewritten in C format based on SoftwareSerial.c.
|
||||
I tried to use as much as possible without modifying the SoftwareSerial.
|
||||
But eventually I had to modify the code.
|
||||
|
||||
I rewrote it in C for the following reasons.
|
||||
- Problems occurred when increasing Program Size and Program Memory
|
||||
- We had to reduce the program size.
|
||||
Of course, Software Serial is limited to one.
|
||||
- reduce the steps for transmitting and receiving
|
||||
|
||||
useage
|
||||
extern void SWSerial_Begin(long speedBaud);
|
||||
extern void SWSerial_Write(uint8_t b);
|
||||
extern int SWSerial_Available(void);
|
||||
extern int SWSerial_Read(void);
|
||||
extern void SWSerial_Print(uint8_t *b);
|
||||
|
||||
If you use Softwreserial library instead of this library, you can modify the code as shown below.
|
||||
I kept the function name of SoftwareSerial so you only need to modify a few lines of code.
|
||||
|
||||
define top of source code
|
||||
#include <SoftwareSerial.h>
|
||||
SoftwareSerial sSerial(10, 11); // RX, TX
|
||||
|
||||
replace source code
|
||||
SWSerial_Begin to sSerial.begin
|
||||
SWSerial_Write to sSerial.write
|
||||
SWSerial_Available to sSerial.available
|
||||
SWSerial_Read to sSerial.read
|
||||
|
||||
KD8CEC, Ian Lee
|
||||
-----------------------------------------------------------------------
|
||||
License
|
||||
All licenses for the source code are subject to the license of the original source SoftwareSerial Library.
|
||||
However, if you use or modify this code, please keep the all comments in this source code.
|
||||
KD8CEC
|
||||
-----------------------------------------------------------------------
|
||||
License from SoftwareSerial
|
||||
-----------------------------------------------------------------------
|
||||
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
|
||||
Multi-instance software serial library for Arduino/Wiring
|
||||
-- Interrupt-driven receive and other improvements by ladyada
|
||||
(http://ladyada.net)
|
||||
-- Tuning, circular buffer, derivation from class Print/Stream,
|
||||
multi-instance support, porting to 8MHz processors,
|
||||
various optimizations, PROGMEM delay tables, inverse logic and
|
||||
direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||
|
||||
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.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
The latest version of this library can always be found at
|
||||
http://arduiniana.org.
|
||||
*/
|
||||
#include "TeensyDSP.h"
|
||||
|
||||
#ifdef USE_SW_SERIAL
|
||||
//================================================================
|
||||
//Public Variable
|
||||
//================================================================
|
||||
#define TX_PIN 9
|
||||
#define RX_PIN 8
|
||||
#define _SS_MAX_RX_BUFF 35 // RX buffer size
|
||||
#define PRINT_MAX_LENGTH 30
|
||||
|
||||
//================================================================
|
||||
//Internal Variable from SoftwareSerial.c and SoftwareSerial.h
|
||||
//================================================================
|
||||
//variable from softwareserial.c and softwareserial.h
|
||||
static uint8_t swr_receive_buffer[_SS_MAX_RX_BUFF];
|
||||
|
||||
volatile uint8_t *_transmitPortRegister; //Write Port Register
|
||||
uint8_t transmit_RegMask; //use Mask bit 1
|
||||
uint8_t transmit_InvMask; //use mask bit 0
|
||||
|
||||
volatile uint8_t *_receivePortRegister; //Read Port Register
|
||||
uint8_t _receiveBitMask;
|
||||
|
||||
//delay value for Bit
|
||||
uint16_t _tx_delay;
|
||||
|
||||
//delay value for Receive
|
||||
uint16_t _rx_delay_stopbit;
|
||||
uint16_t _rx_delay_centering;
|
||||
uint16_t _rx_delay_intrabit;
|
||||
|
||||
//Customize for uBITX Protocol
|
||||
int8_t receiveIndex = 0;
|
||||
int8_t receivedCommandLength = 0;
|
||||
int8_t ffCount = 0;
|
||||
|
||||
//Values for Receive Buffer
|
||||
//uint16_t _buffer_overflow;
|
||||
//static volatile uint8_t _receive_buffer_head;
|
||||
//static volatile uint8_t _receive_buffer_tail;
|
||||
|
||||
//Values for Interrupt (check Start Bit)
|
||||
volatile uint8_t *_pcint_maskreg;
|
||||
uint8_t _pcint_maskvalue;
|
||||
|
||||
//================================================================
|
||||
//Internal Function from SoftwareSerial.c
|
||||
//================================================================
|
||||
uint16_t subtract_cap(uint16_t num, uint16_t sub)
|
||||
{
|
||||
if (num > sub)
|
||||
return num - sub;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline void tunedDelay(uint16_t delay)
|
||||
{
|
||||
_delay_loop_2(delay);
|
||||
}
|
||||
|
||||
void setRxIntMsk(bool enable)
|
||||
{
|
||||
if (enable)
|
||||
*_pcint_maskreg |= _pcint_maskvalue;
|
||||
else
|
||||
*_pcint_maskreg &= ~_pcint_maskvalue;
|
||||
}
|
||||
|
||||
uint8_t rx_pin_read()
|
||||
{
|
||||
return *_receivePortRegister & _receiveBitMask;
|
||||
}
|
||||
|
||||
//
|
||||
// The receive routine called by the interrupt handler
|
||||
//
|
||||
void softSerail_Recv()
|
||||
{
|
||||
#if GCC_VERSION < 40302
|
||||
// Work-around for avr-gcc 4.3.0 OSX version bug
|
||||
// Preserve the registers that the compiler misses
|
||||
// (courtesy of Arduino forum user *etracer*)
|
||||
asm volatile(
|
||||
"push r18 \n\t"
|
||||
"push r19 \n\t"
|
||||
"push r20 \n\t"
|
||||
"push r21 \n\t"
|
||||
"push r22 \n\t"
|
||||
"push r23 \n\t"
|
||||
"push r26 \n\t"
|
||||
"push r27 \n\t"
|
||||
::);
|
||||
#endif
|
||||
|
||||
uint8_t d = 0;
|
||||
|
||||
// If RX line is high, then we don't see any start bit
|
||||
// so interrupt is probably not for us
|
||||
if (!rx_pin_read()) //Start Bit
|
||||
{
|
||||
// Disable further interrupts during reception, this prevents
|
||||
// triggering another interrupt directly after we return, which can
|
||||
// cause problems at higher baudrates.
|
||||
setRxIntMsk(false);
|
||||
|
||||
// Wait approximately 1/2 of a bit width to "center" the sample
|
||||
tunedDelay(_rx_delay_centering);
|
||||
|
||||
// Read each of the 8 bits
|
||||
for (uint8_t i=8; i > 0; --i)
|
||||
{
|
||||
tunedDelay(_rx_delay_intrabit);
|
||||
d >>= 1;
|
||||
|
||||
if (rx_pin_read())
|
||||
d |= 0x80;
|
||||
}
|
||||
|
||||
if (receivedCommandLength == 0) //check Already Command
|
||||
{
|
||||
//Set Received Data
|
||||
swr_receive_buffer[receiveIndex++] = d;
|
||||
|
||||
//Finded Command
|
||||
if (d == 0x73 && ffCount > 1 && receiveIndex > 6)
|
||||
{
|
||||
receivedCommandLength = receiveIndex;
|
||||
receiveIndex = 0;
|
||||
ffCount = 0;
|
||||
}
|
||||
else if (receiveIndex > _SS_MAX_RX_BUFF)
|
||||
{
|
||||
//Buffer Overflow
|
||||
receiveIndex = 0;
|
||||
ffCount = 0;
|
||||
}
|
||||
else if (d == 0xFF)
|
||||
{
|
||||
ffCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// skip the stop bit
|
||||
tunedDelay(_rx_delay_stopbit);
|
||||
|
||||
// Re-enable interrupts when we're sure to be inside the stop bit
|
||||
setRxIntMsk(true);
|
||||
}
|
||||
|
||||
#if GCC_VERSION < 40302
|
||||
// Work-around for avr-gcc 4.3.0 OSX version bug
|
||||
// Restore the registers that the compiler misses
|
||||
asm volatile(
|
||||
"pop r27 \n\t"
|
||||
"pop r26 \n\t"
|
||||
"pop r23 \n\t"
|
||||
"pop r22 \n\t"
|
||||
"pop r21 \n\t"
|
||||
"pop r20 \n\t"
|
||||
"pop r19 \n\t"
|
||||
"pop r18 \n\t"
|
||||
::);
|
||||
#endif
|
||||
}
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
softSerail_Recv();
|
||||
}
|
||||
|
||||
//================================================================
|
||||
//Public Function from SoftwareSerial.c and modified and create
|
||||
//================================================================
|
||||
// Read data from buffer
|
||||
void SWSerial_Read(uint8_t * receive_cmdBuffer)
|
||||
{
|
||||
for (int i = 0; i < receivedCommandLength; i++)
|
||||
receive_cmdBuffer[i] = swr_receive_buffer[i];
|
||||
}
|
||||
|
||||
void SWSerial_Write(uint8_t b)
|
||||
{
|
||||
volatile uint8_t *reg = _transmitPortRegister;
|
||||
uint8_t oldSREG = SREG;
|
||||
uint16_t delay = _tx_delay;
|
||||
|
||||
cli(); // turn off interrupts for a clean txmit
|
||||
|
||||
// Write the start bit
|
||||
*reg &= transmit_InvMask;
|
||||
|
||||
tunedDelay(delay);
|
||||
|
||||
// Write each of the 8 bits
|
||||
for (uint8_t i = 8; i > 0; --i)
|
||||
{
|
||||
if (b & 1) // choose bit
|
||||
*reg |= transmit_RegMask; // send 1
|
||||
else
|
||||
*reg &= transmit_InvMask; // send 0
|
||||
|
||||
tunedDelay(delay);
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
// restore pin to natural state
|
||||
*reg |= transmit_RegMask;
|
||||
|
||||
SREG = oldSREG; // turn interrupts back on
|
||||
tunedDelay(_tx_delay);
|
||||
}
|
||||
|
||||
void SWSerial_Print(uint8_t *b)
|
||||
{
|
||||
for (int i = 0; i < PRINT_MAX_LENGTH; i++)
|
||||
{
|
||||
if (b[i] == 0x00)
|
||||
break;
|
||||
else
|
||||
SWSerial_Write(b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void SWSerial_Begin(long speedBaud)
|
||||
{
|
||||
//INT TX_PIN
|
||||
digitalWrite(TX_PIN, HIGH);
|
||||
pinMode(TX_PIN, OUTPUT);
|
||||
transmit_RegMask = digitalPinToBitMask(TX_PIN); //use Bit 1
|
||||
transmit_InvMask = ~digitalPinToBitMask(TX_PIN); //use Bit 0
|
||||
_transmitPortRegister = portOutputRegister(digitalPinToPort(TX_PIN));
|
||||
|
||||
//INIT RX_PIN
|
||||
pinMode(RX_PIN, INPUT);
|
||||
digitalWrite(RX_PIN, HIGH); // pullup for normal logic!
|
||||
_receiveBitMask = digitalPinToBitMask(RX_PIN);
|
||||
_receivePortRegister = portInputRegister(digitalPinToPort(RX_PIN));
|
||||
|
||||
//Set Values
|
||||
uint16_t bit_delay = (F_CPU / speedBaud) / 4;
|
||||
_tx_delay = subtract_cap(bit_delay, 15 / 4);
|
||||
|
||||
if (digitalPinToPCICR(RX_PIN))
|
||||
{
|
||||
_rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4);
|
||||
_rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4);
|
||||
_rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4);
|
||||
*digitalPinToPCICR(RX_PIN) |= _BV(digitalPinToPCICRbit(RX_PIN));
|
||||
_pcint_maskreg = digitalPinToPCMSK(RX_PIN);
|
||||
_pcint_maskvalue = _BV(digitalPinToPCMSKbit(RX_PIN));
|
||||
|
||||
tunedDelay(_tx_delay); // if we were low this establishes the end
|
||||
}
|
||||
|
||||
//Start Listen
|
||||
setRxIntMsk(true);
|
||||
}
|
||||
#else
|
||||
void SWSerial_Write(uint8_t b)
|
||||
{
|
||||
Serial.write(b);
|
||||
//Serial.flush();
|
||||
}
|
||||
|
||||
void SWSerial_Print(uint8_t *b)
|
||||
{
|
||||
for (int i = 0; i < PRINT_MAX_LENGTH; i++)
|
||||
{
|
||||
if (b[i] == 0x00)
|
||||
break;
|
||||
else
|
||||
SWSerial_Write(b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user