Lots of updates prior to first compile.

This commit is contained in:
Rob French 2021-01-26 22:22:02 -06:00
parent 16b350cb0f
commit c59d53fb9e
3 changed files with 219 additions and 956 deletions

View File

@ -8,6 +8,8 @@ KD8CEC, Ian Lee
**********************************************************************/
#include <Arduino.h>
#include "Nextion.h"
#include "Sensors.h"
//================================================================
//COMMUNICATION SECTION
@ -58,7 +60,3 @@ extern int magnitudelimit_low;
//SWR
#define I2CMETER_CALCR 0x55 //Calculated SWR Meter
#define I2CMETER_UNCALCR 0x54 //Uncalculated SWR Meter
#define SIGNAL_METER_ADC A7
#define POWER_METER_ADC A3
#define SWR_METER_ADC A2

View File

@ -7,232 +7,21 @@ Version : 0.8
License : See fftfunctions.cpp for FFT and CW Decode.
**********************************************************************/
#include <ADC.h>
#include <i2c_t3.h> // using i2c_t3 library for multiple I2C busses
#include <EEPROM.h>
#include "TeensyDSP.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
//const uint8_t responseHeader[11]={'p', 'm', '.', 's', 'p', '.', 't', 'x', 't', '=', '"'}; //for Spectrum from DSP
//const uint8_t responseFooter[4]={'"', 0xFF, 0xFF, 0xFF};
//const char hexCodes[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };
//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];
const uint8_t responseHeader[11]={'p', 'm', '.', 's', 'p', '.', 't', 'x', 't', '=', '"'}; //for Spectrum from DSP
const uint8_t responseFooter[4]={'"', 0xFF, 0xFF, 0xFF};
const char hexCodes[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };
void FFT(double *x,double *y, int n, long m);
double FFTReal[SAMPLESIZE];
double FFTImag[SAMPLESIZE];
int ADC_MAX = 0;
int ADC_MIN = 0;
int ADC_DIFF = 0;
unsigned long SAMPLE_INTERVAL = 0;
char nowADCSampling = 0; //prevent for loss signal
//===================================================================
//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
char L_nowdisp = -1; //Sended nowdisp
#define CMD_VFO_TYPE 'v' //cv
char L_vfoActive; //vfoActive
#define CMD_CURR_FREQ 'c' //vc
unsigned long L_vfoCurr; //vfoA
#define CMD_CURR_MODE 'c' //cc
byte L_vfoCurr_mode; //vfoA_mode
#define CMD_VFOA_FREQ 'a' //va
unsigned long L_vfoA; //vfoA
#define CMD_VFOA_MODE 'a' //ca
byte L_vfoA_mode; //vfoA_mode
#define CMD_VFOB_FREQ 'b' //vb
unsigned long L_vfoB; //vfoB
#define CMD_VFOB_MODE 'b' //cb
byte L_vfoB_mode; //vfoB_mode
#define CMD_IS_RIT 'r' //cr
char L_ritOn;
#define CMD_RIT_FREQ 'r' //vr
unsigned long L_ritTxFrequency; //ritTxFrequency
#define CMD_IS_TX 't' //ct
char L_inTx;
#define CMD_IS_DIALLOCK 'l' //cl
byte L_isDialLock; //byte isDialLock
#define CMD_IS_SPLIT 's' //cs
byte L_Split; //isTxType
#define CMD_IS_TXSTOP 'x' //cx
byte L_TXStop; //isTxType
#define CMD_TUNEINDEX 'n' //cn
byte L_tuneStepIndex; //byte tuneStepIndex
#define CMD_SMETER 'p' //cs
byte L_scaledSMeter; //scaledSMeter
#define CMD_SIDE_TONE 't' //vt
unsigned long L_sideTone; //sideTone
#define CMD_KEY_TYPE 'k' //ck
byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
#define CMD_CW_SPEED 's' //vs
unsigned int L_cwSpeed; //cwSpeed
#define CMD_CW_DELAY 'y' //vy
byte L_cwDelayTime; //cwDelayTime
#define CMD_CW_STARTDELAY 'e' //ve
byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
#define CMD_ATT_LEVEL 'f' //vf
byte L_attLevel;
byte L_isIFShift; //1 = ifShift, 2 extend
#define CMD_IS_IFSHIFT 'i' //ci
int L_ifShiftValue;
#define CMD_IFSHIFT_VALUE 'i' //vi
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;
byte scaledSMeter = 0;
/*!
@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]);
}
//=======================================================
//END OF Nextion Protocol
//=======================================================
int i2cCommand = 0;
void calculateCoeff(uint8_t freqIndex);
//void calculateCoeff(uint8_t freqIndex);
uint8_t cwDecodeHz = 9;
int magnitudelimit_low = 30;
char forwardBuff[MAX_FORWARD_BUFF_LENGTH + 1];
static int nowBuffIndex = 0;
@ -250,6 +39,9 @@ char FFTToUartIdleCount = 0;
elapsedMillis sinceForward = 0;
uint8_t responseCommand = 0; //
bool isTX = false;
/**********************************************************************/
void responseConfig()
{
if (responseCommand == 2)
@ -357,7 +149,7 @@ char commandParser(int lastIndex)
else if (cmd1 >= 100 && cmd1 <= 145)
{
cwDecodeHz = cmd1 - 100;
calculateCoeff(cwDecodeHz);
//calculateCoeff(cwDecodeHz);
DSPType = 2;
EEPROM.put(EEPROM_DSPTYPE, DSPType);
EEPROM.put(EEPROM_CW_FREQ, cwDecodeHz);
@ -462,49 +254,11 @@ void forwardData(void)
}
}
/**********************************************************************/
void sendMeterData(uint8_t isSend)
{
//basic : 1.5Khz
int newScaledSMeter = 0;
//if (ADC_DIFF > 26) //-63dBm : S9 + 10dBm
if (ADC_DIFF > 26) //-63dBm : S9 + 10dBm (subtract loss rate)
//if (ADC_DIFF > 55) //-63dBm : S9 + 15dBm
{
newScaledSMeter = 8;
}
else if (ADC_DIFF > 11) //~ -72 S9
{
newScaledSMeter = 7;
}
else if (ADC_DIFF > 8)
{
newScaledSMeter = 6;
}
else if (ADC_DIFF > 6) //~-80 S7
//else if (ADC_DIFF > 5) //~-80 S7
{
newScaledSMeter = 5;
}
else if (ADC_DIFF > 4)
{
newScaledSMeter = 4; //79 S8
}
else if (ADC_DIFF > 3)
{
newScaledSMeter = 3; //-81 ~ -78 => S7
}
else if (ADC_DIFF > 2)
{
newScaledSMeter = 2; // -88 ~ -82 => S7 or S6
}
else if (ADC_DIFF > 1) //-93 ~ -89 => S5 or S4
{
newScaledSMeter = 1;
}
else // ~ -93.0dBm ~S3 or S4
{
newScaledSMeter = 0;
}
scaledSMeter = Sensors.sMeterScaled();
/*
1 : with noise (not use 0 ~ S3)
@ -514,8 +268,6 @@ void sendMeterData(uint8_t isSend)
5 : -77 ~ -72
6 : -71 ~ -69
*/
scaledSMeter = newScaledSMeter;
if (isSend == 1)
{
@ -527,74 +279,32 @@ void sendMeterData(uint8_t isSend)
}
}
/**********************************************************************/
void grepADC(void)
{
int readValue = 0;
unsigned long currentms = 0;
int readSampleCount = 0;
if (DSPType == 2 || DSPType == 0) //Decode Morse
{
readSampleCount = DECODE_MORSE_SAMPLESIZE;
}
else if (DSPType == 3) //Decode RTTY
{
readSampleCount = DECODE_MORSE_SAMPLESIZE;
}
else
{
readSampleCount = SAMPLESIZE;
}
ADC_MAX = 0;
ADC_MIN = 30000;
for(int i=0; i < readSampleCount; i++)
{
currentms = micros();
readValue = analogRead(SIGNAL_METER_ADC);;
FFTReal[i] = readValue;
FFTImag[i] = 0;
if (ADC_MAX < readValue)
{
ADC_MAX = readValue;
}
if (ADC_MIN > readValue)
{
ADC_MIN = readValue;
}
while(micros() < (currentms + SAMPLE_INTERVAL)){}
} //end of for
}
void sendFFTData(void)
{
int readValue = 0;
for (int i = 0; i < 11; i++)
Serial1.write(responseHeader[i]);
for(int i = 1; i < 64; i++)
{
readValue = (int)(FFTReal[i]);
if (readValue < 0)
{
readValue = 0;
}
else if (readValue>255)
{
readValue=255;
}
Serial1.write(hexCodes[readValue >> 4]);
Serial1.write(hexCodes[readValue & 0xf]);
}
for (int i = 0; i < 4; i++)
Serial1.write(responseFooter[i]);
}
//void sendFFTData(void)
//{
// int readValue = 0;
// for (int i = 0; i < 11; i++)
// Serial1.write(responseHeader[i]);
//
// for(int i = 1; i < 64; i++)
// {
// readValue = (int)(FFTReal[i]);
// if (readValue < 0)
// {
// readValue = 0;
// }
// else if (readValue>255)
// {
// readValue=255;
// }
// Serial1.write(hexCodes[readValue >> 4]);
// Serial1.write(hexCodes[readValue & 0xf]);
// }
//
// for (int i = 0; i < 4; i++)
// Serial1.write(responseFooter[i]);
//}
void setup()
{
@ -666,8 +376,8 @@ void i2cReceiveEvent(size_t numBytes)
}
/*!
@brief Respond to a request from the I2C Master (Raduino). Returns the appropriate data
based on whatever command was previously issued.
* @brief Respond to a request from the I2C Master (Raduino). Returns the appropriate data
* based on whatever command was previously issued.
*/
void i2cRequestEvent(void)
{
@ -684,53 +394,17 @@ void i2cRequestEvent(void)
case I2CMETER_UNCALCS:
// Returns a raw signal strength value.
// KC4UPR: I'm going to replace this with a "process" that continually updates the ADC values.
// So then this would just grab the current value, and return it.
for(int i=0; i < 7; i++)
{
curr = micros();
readValue = analogRead(SIGNAL_METER_ADC);;
if (readValue > maxValue)
{
maxValue = readValue;
}
if (readValue < minValue)
{
minValue = readValue;
}
while(micros() < (curr + 127)){} //8Khz / 7
} //end of for
readValue = maxValue - minValue;
readValue = readValue * readValue;
//readValue = readValue / 2;
if (readValue < 0)
{
readValue = 0;
}
else if (readValue > 255)
{
readValue = 255;
}
Wire1.write(readValue);
Wire1.write(Sensors.sMeterUnscaled() >> 2); // divided by 4... do we want this?
break;
case I2CMETER_CALCP:
// Returns a raw forward power value.
// KC4UPR: I'm going to replace this with a "process" that continually updates the ADC values.
// So then this would just grab the current value, and return it.
readValue = analogRead(POWER_METER_ADC); //POWER
Wire1.write(readValue);
Wire1.write(fwdPower);
break;
case I2CMETER_CALCR:
// Returns a raw reverse power value.
// KC4UPR: I'm going to replace this with a "process" that continually updates the ADC values.
// So then this would just grab the current value, and return it.
readValue = analogRead(SWR_METER_ADC);
Wire1.write(readValue);
Wire1.write(revPower);
break;
default:
@ -738,28 +412,40 @@ void i2cRequestEvent(void)
}
}
extern void Decode_Morse(float magnitude);
extern double coeff;
//extern void Decode_Morse(float magnitude);
//extern double coeff;
#define LAST_TIME_INTERVAL 159
//int SWRAdcValue = 0;
float adcFWD = 0;
float adcRWD = 0;
uint16_t adjustPower = 230;
float swrMeasured;
int clcCount = 0;
// for boot delay, a lot of data to transfer
// Delay 2.5 Sec
byte isBooted = 0;
//======================================================================
// ADC PROCESSES
//======================================================================
elapsedMillis sinceFrameMillis = 0;
elapsedMillis sinceADCMillis = 0;
#define FRAME_RATE 40
#define FRAME_INTERVAL_MS (1000/FRAME_RATE)
const int frameIntervalMillis = FRAME_INTERVAL_MS;
#define ADC_SAMPLE_RATE 120
#define ADC_INTERVAL_MS (1000/ADC_SAMPLE_RATE)
const int adcIntervalMillis = ADC_INTERVAL_MS;
//======================================================================
// MAIN LOOP
//======================================================================
void loop()
{
char isProcess = 0; // 0: init, 1: complete ADC sampling, 2: complete FFT
isProcess = 0;
//char isProcess = 0; // 0: init, 1: complete ADC sampling, 2: complete FFT
//isProcess = 0;
forwardData();
@ -775,229 +461,169 @@ void loop()
return;
}
//===========================================
// TRANSCEIVER STATUS : TX
//===========================================
if (isTX) //TX Mode
{
//************************************************
//Read FWD and RWD
adcFWD = adcFWD * 0.8 + analogRead(A2) * 0.2;
adcRWD = adcRWD * 0.8 + analogRead(A3) * 0.2;
if (adcRWD > adcFWD)
{
adcRWD = adcFWD;
}
if (sinceFrameMillis > frameIntervalMillis) {
// Do stuff that we do once per frame--I/O.
// TODO: debug output (frame skipping / utilization).
sinceFrame = 0;
//for realtime LCD Display
forwardData();
if (clcCount++ > 10)
{
//Calculated Power and swr and Send Information
clcCount = 0;
//Calc PWR
float PWR = pow(adcFWD, 2);
PWR = PWR / adjustPower / 100;
//Calc SWR
float Vratio = adcRWD / adcFWD;
if (adcRWD < 0.05 && adcFWD < 0.05)
{
//No signal
swrMeasured = 0;
}
else if (Vratio > 0.99)
{
swrMeasured = 1999;
}
else
{
swrMeasured = ((1 + Vratio)/ (1 - Vratio));
}
//For Version 0.8
//Send SWR Information using Receive Signal Meter Protocol
scaledSMeter = (int)(swrMeasured + 0.5);
if (scaledSMeter > 9)
{
scaledSMeter = 9;
}
if (L_scaledSMeter != scaledSMeter)
{
L_scaledSMeter = scaledSMeter;
sendCommand1Num(CMD_SMETER, L_scaledSMeter);
}
//For Version 1.0
//need mod uBITX firmware and Nextion LCD and add Power adjust value option (uBITX Manager)
//Send Information
//SWR Send
//sendCommandL('m', SWRAdcValue);
//sendCommand1Num('m', 3);
//SMeterToUartIdleCount = 0;
//Send Power Information
int readValue = (int)(PWR * 100);
sendCommandL('m', readValue);
sendCommand1Num('m',2);
//Delay 250msec ~ 500msec for Nextion LCD Processing (using m protocol)
for (int i = 0; i < 10; i++)
{
forwardData();
if (!isTX) //if TX -> RX break
{
break;
}
delay(25);
} //end of delay time
if (isTX) {
calcVSWR = Sensors.VSWR();
scaledVSWR = byte(Sensors.scaledVSWR());
fwdPower = Sensors.Pfwd();
revPower = Sensors.Prev();
//Send SWR
readValue = (int)(swrMeasured * 100);
sendCommandL('m', readValue);
sendCommand1Num('m', 3);
// Send SWR meter information.
if (L_scaledVSWR != scaledVSWR) {
L_scaledVSWR = scaledVSWR
sendCommand1Num(CMD_SMETER, scaledVSWR);
}
// Send forward power.
if (L_fwdPower != fwdPower) {
L_fwdPower = fwdPower;
sendCommandL('m', fwdPower * 100); // watts x 100?
sendCommand1Num('m', 2);
}
// Send reverse power.
//if (L_revPower != revPower) {
// L_revPower = revPower;
// sendCommandL('m', revPower * 100); // watts x 100?
// sendCommand1Num('m', 2);
//}
//delay(50);
//return;
}
delay(30);
return; //Do not processing ADC, FFT, Decode Morse or RTTY, only Power and SWR Data Return
}
// Does there need to be some kind of 250-500ms delay after this???
// Delay 250msec ~ 500msec for Nextion LCD Processing (using m protocol)
//for (int i = 0; i < 10; i++) {
// forwardData();
// if (!isTX) { //if TX -> RX break
// break;
// }
// delay(25);
//} //end of delay time
// Send SWR.
if (L_calcSWR != calcSWR) {
L_calcSWR = calcSWR;
sendCommandL('m', int(calcSWR * 100.0)); // SWR x 100?
sendCommand1Num('m', 3);
}
} else { // RX
//===========================================
//TRANSCEIVER STATUS : RX
//===========================================
//===========================================
// ADC Sampling
//===========================================
if (nowSendingProtocol == 0) //Idle Status
{
nowADCSampling = 1; //Mark => Start Sampling
grepADC();
//if(nowADCSampling == 2) //Marked ? While ADC Sampling, receive I2C
//{
// nowADCSampling = 0; //Mark => Finish Sampling
// i2cRequestEvent();
//}
nowADCSampling = 0; //Mark => Finish Sampling
int newDiff = ADC_MAX - ADC_MIN; //Calculated for Signal Meter (ADC_DIFF => Signal Strength)
//ADC_DIFF = ((ADC_DIFF * 7) + (newDiff * 3)) / 10;
ADC_DIFF = newDiff;
isProcess = 1; //Mark => Complete ADC Sampling
}
forwardData();
//===========================================
// Send Signal Meter to UART
//===========================================
if (SMeterToUartSend == 1) //SMeter To Uart Send
{
//When selected Morse decode mode, not send signal Meter
//if ((DSPType != 2) && (SMeterToUartIdleCount++ > (SMeterToUartInterval * (DSPType == 1 ? 1 : 12))))
//User Option
if (SMeterToUartIdleCount++ > (SMeterToUartInterval * (DSPType == 1 ? 1 : 12)))
{
//nowSendingProtocol -> not finished data forward, (not found 0xff, 0xff, 0xff yet)
if (nowSendingProtocol == 0 && isProcess == 1) //Complete ADC Sampling and Idle status
// Send Signal Meter to UART
if (SMeterToUartSend == 1 && nowSendingProtocol == 0) //SMeter To Uart Send
{
//nowSendingProtocol -> not finished data forward, (not found 0xff, 0xff, 0xff yet)
sendMeterData(1);
SMeterToUartIdleCount = 0;
} else {
sendMeterData(0); //only calculate Signal Level
}
}
} //end of if
else
{
sendMeterData(0); //only calculate Signal Level
}
forwardData();
//Check Response Command
// Forward any data that came in while we were updating stuff.
ForwardData();
}
if (sinceADCMillis > adcIntervalMillis) {
// Do stuff that we do once per ADC interval--ADC colllection.
// TODO: debug output (frame skipping / utilization).
sinceADC = 0;
if (isTX) {
Sensors.updatePower();
} else { // RX
Sensors.updateSMeter();
Sensors.updateSupply();
}
// Forward any data that came in while we were reading sensors.
//ForwardData();
}
// Check Response Command
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
{
responseConfig();
}
//===================================================================================
// DSP Routine
//===================================================================================
if (DSPType == 1 && sinceForward > LAST_TIME_INTERVAL) // spectrum: FFT => send To UART
{
FFTToUartIdleCount = 0;
if (isProcess == 1)
{
FFT(FFTReal, FFTImag, SAMPLESIZE, 7);
isProcess = 2;
}
forwardData();
if (isProcess == 2)
{
for (uint16_t k = 0; k < SAMPLESIZE; k++)
{
FFTReal[k] = sqrt(FFTReal[k] * FFTReal[k] + FFTImag[k] * FFTImag[k]);
}
isProcess = 3;
}
forwardData();
if (isProcess == 3)
{
if (nowSendingProtocol == 0) //Idle Status
{
sendFFTData();
}
}
}
else if (DSPType == 2) //Decode Morse
{
//Implement Goertzel_algorithm
//https://en.wikipedia.org/wiki/Goertzel_algorithm
// //===========================================
// //TRANSCEIVER STATUS : RX
// //===========================================
// //===================================================================================
// // DSP Routine
// //===================================================================================
// if (DSPType == 1 && sinceForward > LAST_TIME_INTERVAL) // spectrum: FFT => send To UART
// {
// FFTToUartIdleCount = 0;
//
// if (isProcess == 1)
// {
// FFT(FFTReal, FFTImag, SAMPLESIZE, 7);
// isProcess = 2;
// }
//
// forwardData();
//
// if (isProcess == 2)
// {
// for (uint16_t k = 0; k < SAMPLESIZE; k++)
// {
// FFTReal[k] = sqrt(FFTReal[k] * FFTReal[k] + FFTImag[k] * FFTImag[k]);
// }
//
// isProcess = 3;
// }
//
// forwardData();
//
// if (isProcess == 3)
// {
// if (nowSendingProtocol == 0) //Idle Status
// {
// sendFFTData();
// }
// }
// }
// else if (DSPType == 2) //Decode Morse
// {
// //Implement Goertzel_algorithm
// //https://en.wikipedia.org/wiki/Goertzel_algorithm
//
// /*
// ω = 2 * π * Kterm / Nterms;
// cr = cos(ω);
// ci = sin(ω);
// coeff = 2 * cr;
//
// sprev = 0;
// sprev2 = 0;
// for each index n in range 0 to Nterms-1
// s = x[n] + coeff * sprev - sprev2;
// sprev2 = sprev;
// sprev = s;
// end
//
// power = sprev2 * sprev2 + sprev * sprev - coeff * sprev * sprev2;
// */
// double Q1 = 0;
// double Q2 = 0;
//
// for (unsigned index = 0; index < DECODE_MORSE_SAMPLESIZE; index++)
// {
// float Q0;
// Q0 = coeff * Q1 - Q2 + FFTReal[index];
// Q2 = Q1;
// Q1 = Q0;
// }
// double magnitudeSquared = (Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff; // we do only need the real part //
// double magnitude = sqrt(magnitudeSquared);
//
// Decode_Morse(magnitude);
// } //end of if
/*
ω = 2 * π * Kterm / Nterms;
cr = cos(ω);
ci = sin(ω);
coeff = 2 * cr;
sprev = 0;
sprev2 = 0;
for each index n in range 0 to Nterms-1
s = x[n] + coeff * sprev - sprev2;
sprev2 = sprev;
sprev = s;
end
power = sprev2 * sprev2 + sprev * sprev - coeff * sprev * sprev2;
*/
double Q1 = 0;
double Q2 = 0;
for (unsigned index = 0; index < DECODE_MORSE_SAMPLESIZE; index++)
{
float Q0;
Q0 = coeff * Q1 - Q2 + FFTReal[index];
Q2 = Q1;
Q1 = Q0;
}
double magnitudeSquared = (Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff; // we do only need the real part //
double magnitude = sqrt(magnitudeSquared);
Decode_Morse(magnitude);
} //enf of if
} //end of main
}
//======================================================================
// EOF

View File

@ -1,361 +0,0 @@
/*
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_FREQUENCY));
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, const 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;
}