Compare commits
3 Commits
c3cc9a7cf7
...
47840e09dd
Author | SHA1 | Date |
---|---|---|
Rob French | 47840e09dd | |
Rob French | d2213e34ff | |
Rob French | 814fe6c733 |
|
@ -339,12 +339,12 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
|
||||||
//Check PTT while auto Sending
|
//Check PTT while auto Sending
|
||||||
autoSendPTTCheck();
|
autoSendPTTCheck();
|
||||||
|
|
||||||
Check_Cat(3);
|
//Check_Cat(3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//Background Work
|
//Background Work
|
||||||
Check_Cat(fromType);
|
//Check_Cat(fromType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,7 +806,7 @@ void checkButton(){
|
||||||
//wait for the button to go up again
|
//wait for the button to go up again
|
||||||
while(keyStatus == getBtnStatus()) {
|
while(keyStatus == getBtnStatus()) {
|
||||||
delay(10);
|
delay(10);
|
||||||
Check_Cat(0);
|
//Check_Cat(0);
|
||||||
}
|
}
|
||||||
//delay(50);//debounce
|
//delay(50);//debounce
|
||||||
}
|
}
|
||||||
|
@ -825,7 +825,7 @@ void checkButton(){
|
||||||
//wait for the button to go up again
|
//wait for the button to go up again
|
||||||
while(btnDown()) {
|
while(btnDown()) {
|
||||||
delay(10);
|
delay(10);
|
||||||
Check_Cat(0);
|
//Check_Cat(0);
|
||||||
}
|
}
|
||||||
//delay(50);//debounce
|
//delay(50);//debounce
|
||||||
}
|
}
|
||||||
|
@ -1402,7 +1402,8 @@ void setup()
|
||||||
//printLineF(1, FIRMWARE_VERSION_INFO);
|
//printLineF(1, FIRMWARE_VERSION_INFO);
|
||||||
DisplayVersionInfo(FIRMWARE_VERSION_INFO);
|
DisplayVersionInfo(FIRMWARE_VERSION_INFO);
|
||||||
|
|
||||||
Init_Cat(38400, SERIAL_8N1);
|
//Init_Cat(38400, SERIAL_8N1);
|
||||||
|
Serial.begin(38400);
|
||||||
initSettings();
|
initSettings();
|
||||||
initPorts();
|
initPorts();
|
||||||
|
|
||||||
|
@ -1475,6 +1476,13 @@ void checkAutoSaveFreqMode()
|
||||||
|
|
||||||
rigState.vfo[0] = vfoA;
|
rigState.vfo[0] = vfoA;
|
||||||
rigState.vfo[1] = vfoB;
|
rigState.vfo[1] = vfoB;
|
||||||
|
rigState.rit = ritRxFrequency - frequency;
|
||||||
|
rigState.flags = 0;
|
||||||
|
rigState.flags |= (vfoActive == VFO_B ? UBITX_VFOB_FLAG : 0);
|
||||||
|
rigState.flags |= (cwMode != 0 ? UBITX_CW_FLAG : 0);
|
||||||
|
rigState.flags |= (isUSB != 0 ? UBITX_USB_FLAG : 0);
|
||||||
|
rigState.flags |= (splitOn != 0 ? UBITX_SPLIT_FLAG : 0);
|
||||||
|
rigState.flags |= (ritOn != 0 ? UBITX_RIT_FLAG : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(){
|
void loop(){
|
||||||
|
@ -1497,13 +1505,14 @@ void loop(){
|
||||||
// controlAutoCW();
|
// controlAutoCW();
|
||||||
// KC4UPR: Note, implementation below leaves no manual way to abort TX due to CAT. May
|
// 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.
|
// want to add in a way to interrupt CAT transmission with a PTT/CW event.
|
||||||
if (!txCAT) {
|
//if (!txCAT) {
|
||||||
if (cwMode == 0)
|
if (cwMode == 0) {
|
||||||
checkPTT();
|
checkPTT();
|
||||||
else
|
} else {
|
||||||
cwKeyer();
|
cwKeyer();
|
||||||
|
}
|
||||||
checkButton();
|
checkButton();
|
||||||
}
|
//}
|
||||||
|
|
||||||
//cwKeyer();
|
//cwKeyer();
|
||||||
|
|
||||||
|
@ -1525,7 +1534,7 @@ void loop(){
|
||||||
} //end of check TX Status
|
} //end of check TX Status
|
||||||
|
|
||||||
//we check CAT after the encoder as it might put the radio into TX
|
//we check CAT after the encoder as it might put the radio into TX
|
||||||
Check_Cat(inTx? 1 : 0);
|
//Check_Cat(inTx? 1 : 0);
|
||||||
|
|
||||||
//for SEND SW Serial
|
//for SEND SW Serial
|
||||||
#ifdef USE_SW_SERIAL
|
#ifdef USE_SW_SERIAL
|
||||||
|
|
|
@ -341,6 +341,8 @@ extern void DisplayVersionInfo(const char* fwVersionInfo);
|
||||||
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
|
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
|
||||||
|
|
||||||
extern void doRaduinoToTeensy(UBitxRigState* r);
|
extern void doRaduinoToTeensy(UBitxRigState* r);
|
||||||
|
extern void updateStateFromRaduino(UBitxRigState& r);
|
||||||
|
extern void updateRaduinoFromState(UBitxRigState& r);
|
||||||
|
|
||||||
extern UBitxRigState rigState;
|
extern UBitxRigState rigState;
|
||||||
|
|
||||||
|
|
|
@ -997,23 +997,10 @@ UBitxRigState catState;
|
||||||
void idle_process()
|
void idle_process()
|
||||||
{
|
{
|
||||||
// KC4UPR 2021-02-05 added update process for Raduino-TeensyDSP coordination
|
// KC4UPR 2021-02-05 added update process for Raduino-TeensyDSP coordination
|
||||||
// Note, need to not have to copy this every time...
|
updateStateFromRaduino(rigState);
|
||||||
if (vfoActive == VFO_A) {
|
|
||||||
rigState.vfo[0] = frequency;
|
|
||||||
rigState.flags &= ~UBITX_VFOB_FLAG;
|
|
||||||
} else if (vfoActive == VFO_B) {
|
|
||||||
rigState.vfo[1] = frequency;
|
|
||||||
rigState.flags |= UBITX_VFOB_FLAG;
|
|
||||||
}
|
|
||||||
doRaduinoToTeensy(&rigState);
|
doRaduinoToTeensy(&rigState);
|
||||||
if (vfoActive == VFO_A) {
|
updateRaduinoFromState(rigState);
|
||||||
if (rigState.vfo[0] != frequency) {
|
|
||||||
setFrequency(rigState.vfo[0]);
|
|
||||||
} else if (vfoActive == VFO_B) {
|
|
||||||
setFrequency(rigState.vfo[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//S-Meter Display
|
//S-Meter Display
|
||||||
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
|
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
|
||||||
{
|
{
|
||||||
|
|
|
@ -350,3 +350,43 @@ void doRaduinoToTeensy(UBitxRigState* r) {
|
||||||
Serial.print(len);
|
Serial.print(len);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateStateFromRaduino(UBitxRigState& r) {
|
||||||
|
// Note, we really need to be checking a dirty flag for this. But, I don't have a dirty flag in this version of the data type...
|
||||||
|
if (vfoActive == VFO_A) {
|
||||||
|
rigState.vfo[0] = frequency;
|
||||||
|
rigState.flags &= ~UBITX_VFOB_FLAG;
|
||||||
|
} else if (vfoActive == VFO_B) {
|
||||||
|
rigState.vfo[1] = frequency;
|
||||||
|
rigState.flags |= UBITX_VFOB_FLAG;
|
||||||
|
}
|
||||||
|
rigState.rit = ritRxFrequency - frequency;
|
||||||
|
rigState.flags = 0;
|
||||||
|
rigState.flags |= (vfoActive == VFO_B ? UBITX_VFOB_FLAG : 0);
|
||||||
|
rigState.flags |= (cwMode != 0 ? UBITX_CW_FLAG : 0);
|
||||||
|
rigState.flags |= (isUSB != 0 ? UBITX_USB_FLAG : 0);
|
||||||
|
rigState.flags |= (splitOn != 0 ? UBITX_SPLIT_FLAG : 0);
|
||||||
|
rigState.flags |= (ritOn != 0 ? UBITX_RIT_FLAG : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateRaduinoFromState(UBitxRigState& r) {
|
||||||
|
vfoActive = rigState.flags & UBITX_VFOB_FLAG ? VFO_B : VFO_A;
|
||||||
|
if (vfoActive == VFO_A) {
|
||||||
|
if (rigState.vfo[0] != frequency) {
|
||||||
|
setFrequency(rigState.vfo[0]);
|
||||||
|
}
|
||||||
|
} else if (vfoActive == VFO_B) {
|
||||||
|
if (rigState.vfo[1] != frequency) {
|
||||||
|
setFrequency(rigState.vfo[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ritRxFrequency = frequency + rigState.rit;
|
||||||
|
splitOn = rigState.flags & UBITX_SPLIT_FLAG ? 1 : 0;
|
||||||
|
ritOn = rigState.flags & UBITX_RIT_FLAG ? 1 : 0;
|
||||||
|
isUSB = rigState.flags & UBITX_USB_FLAG ? 1 : 0;
|
||||||
|
if (rigState.flags & UBITX_CW_FLAG) {
|
||||||
|
cwMode = isUSB ? 2 : 1; // 2 = cwu / 1 = cwl
|
||||||
|
} else {
|
||||||
|
cwMode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
//======================================================================
|
||||||
|
//
|
||||||
|
// 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 + symWeight) / (symWeight -1);
|
||||||
|
spaceLen = (1200 / speed);
|
||||||
|
dotLen = spaceLen * (w - 1);
|
||||||
|
dashLen = (1 + w) * spaceLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UBitxKeyer::setWPM(int wpm)
|
||||||
|
{
|
||||||
|
speed = wpm;
|
||||||
|
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;
|
||||||
|
// letting this fall through // return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case CHK_DIT: // See if the dit paddle was pressed
|
||||||
|
if (keyerControl & DIT_L) {
|
||||||
|
keyerControl |= DIT_PROC;
|
||||||
|
ktimer = dotLen;
|
||||||
|
keyerState = KEYED_PREP;
|
||||||
|
return true;
|
||||||
|
} else { // fall through
|
||||||
|
keyerState = CHK_DAH;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CHK_DAH: // See if dah paddle was pressed
|
||||||
|
if (keyerControl & DAH_L) {
|
||||||
|
ktimer = dashLen;
|
||||||
|
keyerState = KEYED_PREP;
|
||||||
|
// letting this fall through // return true;
|
||||||
|
} else {
|
||||||
|
keyerState = IDLE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case KEYED_PREP: // Assert key down, start timing
|
||||||
|
// state shared for dit or dah
|
||||||
|
keyDown = true;
|
||||||
|
ktimer += millis(); // set ktimer to interval end time
|
||||||
|
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||||
|
keyerState = KEYED; // next state
|
||||||
|
// letting this fall through // return true;
|
||||||
|
// break;
|
||||||
|
|
||||||
|
case KEYED: // Wait for timer to expire
|
||||||
|
if (millis() > ktimer) { // are we at end of key down ?
|
||||||
|
keyDown = false;
|
||||||
|
ktimer = millis() + spaceLen; // inter-element time
|
||||||
|
keyerState = INTER_ELEMENT; // next state
|
||||||
|
// letting this fall through // return true;
|
||||||
|
} else if (keyMode == IAMBICB) { // Iambic B Mode ?
|
||||||
|
updatePaddleLatch(); // yes, early paddle latch in Iambic B mode
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // resolve compiler warning; do we ever get here?
|
||||||
|
}
|
||||||
|
|
||||||
|
UBitxKeyer basicKeyer(15, 3.0);
|
||||||
|
UBitxKeyer& Keyer = basicKeyer;
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// EOF
|
||||||
|
//======================================================================
|
|
@ -0,0 +1,79 @@
|
||||||
|
//**********************************************************************
|
||||||
|
//
|
||||||
|
// 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 void setMode(int mode) { keyMode = mode; }
|
||||||
|
inline int getMode() { return keyMode; }
|
||||||
|
inline bool isDown() { return keyDown; }
|
||||||
|
// void setWeight();
|
||||||
|
|
||||||
|
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
|
||||||
|
//======================================================================
|
|
@ -25,4 +25,150 @@ struct UBitxRigState {
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
|
template<typename T, int ID>
|
||||||
|
struct Field {
|
||||||
|
byte id = ID;
|
||||||
|
bool dirty;
|
||||||
|
T data;
|
||||||
|
|
||||||
|
inline size_t sizeOfWrite() { return dirty ? sizeof(byte) + sizeof(T) : 0; }
|
||||||
|
|
||||||
|
template<typename STREAM> void writeChanges() {
|
||||||
|
if (dirty) {
|
||||||
|
STREAM().write(id);
|
||||||
|
STREAM().write((byte*)&data, sizeof(T));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename STREAM> int read() {
|
||||||
|
size_t len = 0;
|
||||||
|
byte* ptr = (byte*)&data;
|
||||||
|
while (STREAM().available() && len < sizeof(T)) {
|
||||||
|
ptr[len++] = STREAM().read();
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void merge(Field<T,ID>& f) {
|
||||||
|
if (dirty) {
|
||||||
|
f.data = data;
|
||||||
|
f.dirty = true;
|
||||||
|
} else if (f.dirty) {
|
||||||
|
data = f.data;
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void markClean() { dirty = false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RigState {
|
||||||
|
Field<uint32_t, 0> vfoA;
|
||||||
|
Field<uint32_t, 1> vfoB;
|
||||||
|
Field<int32_t, 2> rit;
|
||||||
|
Field<int32_t, 3> xit;
|
||||||
|
Field<uint32_t, 4> flags;
|
||||||
|
|
||||||
|
inline size_t sizeOfWrite() {
|
||||||
|
size_t size = 0;
|
||||||
|
size += vfoA.sizeOfWrite();
|
||||||
|
size += vfoB.sizeOfWrite();
|
||||||
|
size += rit.sizeOfWrite();
|
||||||
|
size += xit.sizeOfWrite();
|
||||||
|
size += flags.sizeOfWrite();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename STREAM> void writeChanges() {
|
||||||
|
vfoA.writeChanges<STREAM>();
|
||||||
|
vfoB.writeChanges<STREAM>();
|
||||||
|
rit.writeChanges<STREAM>();
|
||||||
|
xit.writeChanges<STREAM>();
|
||||||
|
flags.writeChanges<STREAM>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename STREAM> void readChanges(size_t size) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (STREAM().available() && len < size) {
|
||||||
|
switch(STREAM().read()) {
|
||||||
|
case 0:
|
||||||
|
len += vfoA.read<STREAM>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
len += vfoB.read<STREAM>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
len += rit.read<STREAM>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
len += xit.read<STREAM>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
len += flags.read<STREAM>();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void merge(RigState& r) {
|
||||||
|
vfoA.merge(r.vfoA);
|
||||||
|
vfoB.merge(r.vfoB);
|
||||||
|
rit.merge(r.rit);
|
||||||
|
xit.merge(r.xit);
|
||||||
|
flags.merge(r.flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void markClean(RigState& r) {
|
||||||
|
vfoA.markClean();
|
||||||
|
vfoB.markClean();
|
||||||
|
rit.markClean();
|
||||||
|
xit.markClean();
|
||||||
|
flags.markClean();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
#endif
|
||||||
|
|
|
@ -7,10 +7,20 @@
|
||||||
|
|
||||||
UBitxTR TR(DSP);
|
UBitxTR TR(DSP);
|
||||||
|
|
||||||
void UBitxTR::update(bool cw) {
|
void UBitxTR::update(bool cw, bool extKey) {
|
||||||
|
updateKey();
|
||||||
|
|
||||||
|
if (cw) {
|
||||||
|
if ((keyEnable && keyDown) || extKey) {
|
||||||
|
setTX();
|
||||||
|
} else {
|
||||||
|
setRX();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
updatePTT();
|
updatePTT();
|
||||||
updateVOX();
|
updateVOX();
|
||||||
updateKey();
|
|
||||||
|
|
||||||
if (isTX) {
|
if (isTX) {
|
||||||
// If we are currently transmitting, then ANY T/R release (key
|
// If we are currently transmitting, then ANY T/R release (key
|
||||||
|
|
|
@ -87,8 +87,12 @@ class UBitxTR {
|
||||||
* @param cw
|
* @param cw
|
||||||
* True if CW mode is currently active; false otherwise.
|
* True if CW mode is currently active; false otherwise.
|
||||||
* Different/faster logic is used in CW mode.
|
* 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);
|
void update(bool cw = false, bool extKey = false);
|
||||||
|
|
||||||
void end() {
|
void end() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,17 +138,17 @@ TS590Error TS590Command::theError = NoError;
|
||||||
void TS590_FR::handleCommand(const char* cmd) {
|
void TS590_FR::handleCommand(const char* cmd) {
|
||||||
if (strlen(cmd) == 3) {
|
if (strlen(cmd) == 3) {
|
||||||
switch (cmd[2]) {
|
switch (cmd[2]) {
|
||||||
case 0:
|
case '0':
|
||||||
rig()->selectVFOA(true);
|
rig()->selectVFOA(true);
|
||||||
rig()->splitOff(true);
|
rig()->splitOff(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case '1':
|
||||||
rig()->selectVFOB(true);
|
rig()->selectVFOB(true);
|
||||||
rig()->splitOff(true);
|
rig()->splitOff(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case '2':
|
||||||
// TODO: Need to add something for channel mode.
|
// TODO: Need to add something for channel mode.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ void TS590_FR::sendResponse(const char* cmd) {
|
||||||
void TS590_FT::handleCommand(const char* cmd) {
|
void TS590_FT::handleCommand(const char* cmd) {
|
||||||
if (strlen(cmd) == 3) {
|
if (strlen(cmd) == 3) {
|
||||||
switch (cmd[2]) {
|
switch (cmd[2]) {
|
||||||
case 0:
|
case '0':
|
||||||
if (rig()->isVFOA()) {
|
if (rig()->isVFOA()) {
|
||||||
rig()->splitOff(true);
|
rig()->splitOff(true);
|
||||||
} else if (rig()->isVFOB()) {
|
} else if (rig()->isVFOB()) {
|
||||||
|
@ -185,7 +185,7 @@ void TS590_FT::handleCommand(const char* cmd) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case '1':
|
||||||
if (rig()->isVFOA()) {
|
if (rig()->isVFOA()) {
|
||||||
rig()->splitOn(true);
|
rig()->splitOn(true);
|
||||||
} else if (rig()->isVFOB()) {
|
} else if (rig()->isVFOB()) {
|
||||||
|
@ -215,16 +215,76 @@ void TS590_FT::sendResponse(const char* cmd) {
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
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()->selectLSB(true);
|
||||||
|
rig()->cwOff(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2': // USB
|
||||||
|
rig()->selectUSB(true);
|
||||||
|
rig()->cwOff(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3': // CW
|
||||||
|
rig()->selectUSB(true);
|
||||||
|
rig()->cwOn(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '7': // CW-R
|
||||||
|
rig()->selectLSB(true);
|
||||||
|
rig()->cwOn(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
setSyntaxError();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setSyntaxError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TS590_MD::sendResponse(const char* cmd) {
|
||||||
|
if (rig()->isCW()) {
|
||||||
|
if (rig()->isUSB()) {
|
||||||
|
ts590SendCommand("MD3");
|
||||||
|
} else {
|
||||||
|
ts590SendCommand("MD7");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rig()->isUSB()) {
|
||||||
|
ts590SendCommand("MD2");
|
||||||
|
} else {
|
||||||
|
ts590SendCommand("MD1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
TS590_FA cmdFA;
|
TS590_FA cmdFA;
|
||||||
TS590_FB cmdFB;
|
TS590_FB cmdFB;
|
||||||
TS590_FR cmdFR;
|
TS590_FR cmdFR;
|
||||||
TS590_FT cmdFT;
|
TS590_FT cmdFT;
|
||||||
|
TS590_MD cmdMD;
|
||||||
|
|
||||||
TS590Command* catCommands[] = {
|
TS590Command* catCommands[] = {
|
||||||
&cmdFA,
|
&cmdFA,
|
||||||
&cmdFB,
|
&cmdFB,
|
||||||
&cmdFR,
|
&cmdFR,
|
||||||
&cmdFT
|
&cmdFT,
|
||||||
|
&cmdMD
|
||||||
};
|
};
|
||||||
int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
|
int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,18 @@ class TS590_FT : public TS590Command {
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @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);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************************************************/
|
||||||
|
|
||||||
class UBitxTS590 {
|
class UBitxTS590 {
|
||||||
public:
|
public:
|
||||||
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
||||||
|
|
|
@ -10,6 +10,7 @@ KD8CEC, Ian Lee
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "DSP.h"
|
#include "DSP.h"
|
||||||
|
#include "Keyer.h"
|
||||||
#include "Nextion.h"
|
#include "Nextion.h"
|
||||||
#include "Rig.h"
|
#include "Rig.h"
|
||||||
#include "RigState.h"
|
#include "RigState.h"
|
||||||
|
|
|
@ -540,6 +540,13 @@ void loop()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If CW mode, we need to update keying a lot...
|
||||||
|
if (Rig.isCW()) {
|
||||||
|
if (Rig.isCW()) Keyer.doPaddles();
|
||||||
|
TR.update(Rig.isCW(), Keyer.isDown());
|
||||||
|
//if (TR.transmitting()) return;
|
||||||
|
}
|
||||||
|
|
||||||
// Start out by forwarding any data sitting in the RX buffer. We will
|
// Start out by forwarding any data sitting in the RX buffer. We will
|
||||||
// do this as often as possible.
|
// do this as often as possible.
|
||||||
forwardData();
|
forwardData();
|
||||||
|
@ -550,11 +557,13 @@ void loop()
|
||||||
sinceFrameMillis = 0;
|
sinceFrameMillis = 0;
|
||||||
|
|
||||||
// Update each of the subsystems, beginning with CAT control.
|
// Update each of the subsystems, beginning with CAT control.
|
||||||
TS590.update();
|
TS590.update();
|
||||||
TR.update();
|
TR.update(Rig.isCW(), Keyer.isDown());
|
||||||
Rig.update();
|
Rig.update();
|
||||||
DSP.update();
|
DSP.update();
|
||||||
|
|
||||||
|
//if (Rig.isCW()) return;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// For debugging, output some debug info every 1.0" (40 frames @ 40 Hz).
|
// For debugging, output some debug info every 1.0" (40 frames @ 40 Hz).
|
||||||
frameCounter++;
|
frameCounter++;
|
||||||
|
@ -676,6 +685,8 @@ void loop()
|
||||||
forwardData();
|
forwardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Rig.isCW()) return; // In CW, the ADC measurement messes with the timing. So need to use interrupts on the Keyer, and/or continuous ADC.
|
||||||
|
|
||||||
if (sinceADCMillis > adcIntervalMillis) {
|
if (sinceADCMillis > adcIntervalMillis) {
|
||||||
// Do stuff that we do once per ADC interval--ADC colllection.
|
// Do stuff that we do once per ADC interval--ADC colllection.
|
||||||
// TODO: debug output (frame skipping / utilization).
|
// TODO: debug output (frame skipping / utilization).
|
||||||
|
@ -692,6 +703,8 @@ void loop()
|
||||||
//forwardData();
|
//forwardData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if (Rig.isCW()) return;
|
||||||
|
|
||||||
// Check Response Command
|
// Check Response Command
|
||||||
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
|
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue