ubitx-v5d/ubitx_20/ubitx_20.ino

1161 lines
37 KiB
Arduino
Raw Normal View History

//Firmware Version
2018-04-12 13:08:43 +00:00
#define FIRMWARE_VERSION_INFO F("CEC v1.071")
#define FIRMWARE_VERSION_NUM 0x02 //1st Complete Project : 1 (Version 1.061), 2st Project : 2
/**
Cat Suppoort uBITX CEC Version
2018-01-26 09:23:52 +00:00
Most features(TX, Frequency Range, Ham Band, TX Control, CW delay, start Delay... more) have been added by KD8CEC.
However, the license rules are subject to the original source rules.
Ian KD8CEC
2018-01-26 09:23:52 +00:00
Original source comment -------------------------------------------------------------
* This source file is under General Public License version 3.
*
* This verision uses a built-in Si5351 library
* Most source code are meant to be understood by the compilers and the computers.
* Code that has to be hackable needs to be well understood and properly documented.
* Donald Knuth coined the term Literate Programming to indicate code that is written be
* easily read and understood.
*
* The Raduino is a small board that includes the Arduin Nano, a 16x2 LCD display and
* an Si5351a frequency synthesizer. This board is manufactured by Paradigm Ecomm Pvt Ltd
*
* To learn more about Arduino you may visit www.arduino.cc.
*
* The Arduino works by starts executing the code in a function called setup() and then it
* repeatedly keeps calling loop() forever. All the initialization code is kept in setup()
* and code to continuously sense the tuning knob, the function button, transmit/receive,
* etc is all in the loop() function. If you wish to study the code top down, then scroll
* to the bottom of this file and read your way up.
*
* Below are the libraries to be included for building the Raduino
* The EEPROM library is used to store settings like the frequency memory, caliberation data,
* callsign etc .
*
* The main chip which generates upto three oscillators of various frequencies in the
* Raduino is the Si5351a. To learn more about Si5351a you can download the datasheet
* from www.silabs.com although, strictly speaking it is not a requirment to understand this code.
* Instead, you can look up the Si5351 library written by xxx, yyy. You can download and
* install it from www.url.com to complile this file.
* The Wire.h library is used to talk to the Si5351 and we also declare an instance of
* Si5351 object to control the clocks.
*/
#include <Wire.h>
#include <EEPROM.h>
2018-03-09 13:02:10 +00:00
#include "ubitx.h"
2018-04-12 13:08:43 +00:00
#include "ubitx_eemap.h"
/**
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
* this shift is due to the loading on the 45 Mhz crystal filter by the matching
* L-network used on it's either sides.
* The first oscillator works between 48 Mhz and 75 MHz. The signal is subtracted
* from the first oscillator to arriive at 45 Mhz IF. Thus, it is inverted : LSB becomes USB
* and USB becomes LSB.
* The second IF of 12 Mhz has a ladder crystal filter. If a second oscillator is used at
* 57 Mhz, the signal is subtracted FROM the oscillator, inverting a second time, and arrives
* at the 12 Mhz ladder filter thus doouble inversion, keeps the sidebands as they originally were.
* If the second oscillator is at 33 Mhz, the oscilaltor is subtracated from the signal,
* thus keeping the signal's sidebands inverted. The USB will become LSB.
* We use this technique to switch sidebands. This is to avoid placing the lsbCarrier close to
* 12 MHz where its fifth harmonic beats with the arduino's 16 Mhz oscillator's fourth harmonic
*/
// the second oscillator should ideally be at 57 MHz, however, the crystal filter's center frequency
// is shifted down a little due to the loading from the impedance matching L-networks on either sides
#define SECOND_OSC_USB (56995000l)
#define SECOND_OSC_LSB (32995000l)
//these are the two default USB and LSB frequencies. The best frequencies depend upon your individual taste and filter shape
#define INIT_USB_FREQ (11996500l)
// limits the tuning and working range of the ubitx between 3 MHz and 30 MHz
#define LOWEST_FREQ (3000000l)
#define HIGHEST_FREQ (30000000l)
2018-01-10 02:34:15 +00:00
//When the frequency is moved by the dial, the maximum value by KD8CEC
#define LOWEST_FREQ_DIAL (3000l)
#define HIGHEST_FREQ_DIAL (60000000l)
char ritOn = 0;
char vfoActive = VFO_A;
int8_t meter_reading = 0; // a -1 on meter makes it invisible
2018-01-30 04:20:52 +00:00
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier, cwmCarrier;
2018-01-10 02:34:15 +00:00
unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
2018-01-20 13:05:04 +00:00
unsigned int cwSpeed = 100; //this is actuall the dot period in milliseconds
extern int32_t calibration;
2018-01-10 02:34:15 +00:00
//for store the mode in eeprom
byte vfoA_mode=0, vfoB_mode = 0; //0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
byte vfoA_mode_eeprom, vfoB_mode_eeprom; //for protect eeprom life
//KD8CEC
//for AutoSave and protect eeprom life
byte saveIntervalSec = 10; //second
unsigned long saveCheckTime = 0;
unsigned long saveCheckFreq = 0;
byte cwDelayTime = 60;
byte delayBeforeCWStartTime = 50;
//sideTonePitch + sideToneSub = sideTone
byte sideTonePitch=0;
byte sideToneSub = 0;
//DialLock
2018-01-12 00:54:38 +00:00
byte isDialLock = 0; //000000[0]vfoB [0]vfoA 0Bit : A, 1Bit : B
2018-01-13 07:19:23 +00:00
byte isTxType = 0; //000000[0 - isSplit] [0 - isTXStop]
2018-02-02 11:49:00 +00:00
long arTuneStep[5];
2018-01-22 12:16:29 +00:00
byte tuneStepIndex; //default Value 0, start Offset is 0 because of check new user
2018-01-10 02:34:15 +00:00
2018-03-20 12:41:24 +00:00
byte commonOption0 = 0;
2018-01-29 09:38:48 +00:00
byte displayOption1 = 0;
byte displayOption2 = 0;
2018-01-26 12:47:15 +00:00
//CW ADC Range
2018-01-27 07:39:54 +00:00
int cwAdcSTFrom = 0;
int cwAdcSTTo = 0;
int cwAdcDotFrom = 0;
int cwAdcDotTo = 0;
int cwAdcDashFrom = 0;
int cwAdcDashTo = 0;
int cwAdcBothFrom = 0;
int cwAdcBothTo = 0;
2018-01-29 09:38:48 +00:00
byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
bool Iambic_Key = true;
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
unsigned char keyerControl = IAMBICB;
2018-01-26 12:47:15 +00:00
byte isShiftDisplayCWFreq = 1; //Display Frequency
int shiftDisplayAdjustVal = 0; //
2018-01-10 02:34:15 +00:00
//Variables for auto cw mode
byte isCWAutoMode = 0; //0 : none, 1 : CW_AutoMode_Menu_Selection, 2 : CW_AutoMode Sending
byte cwAutoTextCount = 0; //cwAutoText Count
byte beforeCWTextIndex = 255; //when auto cw start, always beforeCWTextIndex = 255, (for first time check)
byte cwAutoDialType = 0; //0 : CW Text Change, 1 : Frequency Tune
#define AUTO_CW_RESERVE_MAX 3
byte autoCWSendReserv[AUTO_CW_RESERVE_MAX]; //Reserve CW Auto Send
byte autoCWSendReservCount = 0; //Reserve CW Text Cound
byte sendingCWTextIndex = 0; //cw auto seding Text Index
byte userCallsignLength = 0; //7 : display callsign at system startup, 6~0 : callsign length (range : 1~18)
/**
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
*/
boolean txCAT = false; //turned on if the transmitting due to a CAT command
char inTx = 0; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
2018-01-30 03:13:52 +00:00
char splitOn = 0; //working split, uses VFO B as the transmit frequency
char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
char isUSB = 0; //upper sideband was selected, this is reset to the default for the
2018-01-30 04:20:52 +00:00
char cwMode = 0; //compatible original source, and extend mode //if cwMode == 0, mode check : isUSB, cwMode > 0, mode Check : cwMode
//iscwMode = 0 : ssbmode, 1 :cwl, 2 : cwu, 3 : cwn (none tx)
//frequency when it crosses the frequency border of 10 MHz
byte menuOn = 0; //set to 1 when the menu is being displayed, if a menu item sets it to zero, the menu is exited
unsigned long cwTimeout = 0; //milliseconds to go before the cw transmit line is released and the radio goes back to rx mode
unsigned long dbgCount = 0; //not used now
unsigned char txFilter = 0; //which of the four transmit filters are in use
boolean modeCalibrate = false;//this mode of menus shows extended menus to calibrate the oscillators and choose the proper
//beat frequency
byte advancedFreqOption1; //255 : Bit0: use IFTune_Value, Bit1 : use Stored enabled SDR Mode, Bit2~Bit3 : dynamic sdr frequency, bit 7: IFTune_Value Reverse for DIY uBITX
2018-04-06 12:43:36 +00:00
byte attLevel = 0; //ATT : RF Gain Control (Receive) <-- IF1 Shift, 0 : Off, ShiftValue is attLevel * 100; attLevel 150 = 15K
byte if1TuneValue = 0; //0 : OFF, IF1 + if1TuneValue * 100; // + - 12500;
2018-04-06 12:43:36 +00:00
byte sdrModeOn = 0; //SDR MODE ON / OFF
2018-04-12 13:08:43 +00:00
unsigned long SDR_Center_Freq; //
2018-04-06 12:43:36 +00:00
2018-01-29 09:38:48 +00:00
unsigned long beforeIdle_ProcessTime = 0; //for check Idle time
byte line2DisplayStatus = 0; //0:Clear, 1 : menu, 1: DisplayFrom Idle,
char lcdMeter[17];
byte isIFShift = 0; //1 = ifShift, 2 extend
2018-03-20 12:41:24 +00:00
int ifShiftValue = 0; //
2018-01-29 09:38:48 +00:00
/**
* Below are the basic functions that control the uBitx. Understanding the functions before
* you start hacking around
*/
2018-01-12 00:54:38 +00:00
//Ham Band
#define MAX_LIMIT_RANGE 10 //because limited eeprom size
byte useHamBandCount = 0; //0 use full range frequency
2018-01-13 07:19:23 +00:00
byte tuneTXType = 0; //0 : use full range, 1 : just Change Dial speed, 2 : just ham band change, but can general band by tune, 3 : only ham band (just support 0, 2 (0.26 version))
//100 : use full range but not TX on general band, 101 : just change dial speed but.. 2 : jut... but.. 3 : only ham band (just support 100, 102 (0.26 version))
2018-01-12 00:54:38 +00:00
unsigned int hamBandRange[MAX_LIMIT_RANGE][2]; // = //Khz because reduce use memory
//-1 : not found, 0 ~ 9 : Hamband index
char getIndexHambanBbyFreq(unsigned long f)
{
f = f / 1000;
for (byte i = 0; i < useHamBandCount; i++)
if (hamBandRange[i][0] <= f && f < hamBandRange[i][1])
return i;
return -1;
}
//when Band change step = just hamband
//moveDirection : 1 = next, -1 : prior
void setNextHamBandFreq(unsigned long f, char moveDirection)
{
unsigned long resultFreq = 0;
byte loadMode = 0;
char findedIndex = getIndexHambanBbyFreq(f);
if (findedIndex == -1) { //out of hamband
f = f / 1000;
for (byte i = 0; i < useHamBandCount -1; i++) {
if (hamBandRange[i][1] <= f && f < hamBandRange[i + 1][0]) {
findedIndex = i + moveDirection;
//return (unsigned long)(hamBandRange[i + 1][0]) * 1000;
}
} //end of for
}
else if (((moveDirection == 1) && (findedIndex < useHamBandCount -1)) || //Next
((moveDirection == -1) && (findedIndex > 0)) ) { //Prior
findedIndex += moveDirection;
}
else
findedIndex = -1;
if (findedIndex == -1)
findedIndex = (moveDirection == 1 ? 0 : useHamBandCount -1);
EEPROM.get(HAM_BAND_FREQS + 4 * findedIndex, resultFreq);
2018-01-30 04:20:52 +00:00
//loadMode = (byte)(resultFreq >> 30);
//resultFreq = resultFreq & 0x3FFFFFFF;
loadMode = (byte)(resultFreq >> 29);
resultFreq = resultFreq & 0x1FFFFFFF;
2018-01-12 00:54:38 +00:00
2018-01-20 13:05:04 +00:00
if ((resultFreq / 1000) < hamBandRange[(unsigned char)findedIndex][0] || (resultFreq / 1000) > hamBandRange[(unsigned char)findedIndex][1])
resultFreq = (unsigned long)(hamBandRange[(unsigned char)findedIndex][0]) * 1000;
2018-01-12 00:54:38 +00:00
setFrequency(resultFreq);
2018-02-03 07:35:27 +00:00
byteToMode(loadMode, 1);
2018-01-12 00:54:38 +00:00
}
2018-01-13 10:42:39 +00:00
void saveBandFreqByIndex(unsigned long f, unsigned long mode, char bandIndex) {
2018-01-12 00:54:38 +00:00
if (bandIndex >= 0)
2018-01-30 04:20:52 +00:00
//EEPROM.put(HAM_BAND_FREQS + 4 * bandIndex, (f & 0x3FFFFFFF) | (mode << 30) );
EEPROM.put(HAM_BAND_FREQS + 4 * bandIndex, (f & 0x1FFFFFFF) | (mode << 29) );
2018-01-12 00:54:38 +00:00
}
2018-01-10 02:34:15 +00:00
/*
KD8CEC
When using the basic delay of the Arduino, the program freezes.
When the delay is used, the program will generate an error because it is not communicating,
so Create a new delay function that can do background processing.
*/
unsigned long delayBeforeTime = 0;
byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle
delayBeforeTime = millis();
2018-01-20 13:05:04 +00:00
while (millis() - delayBeforeTime <= delayTime) {
2018-01-10 02:34:15 +00:00
if (fromType == 4)
{
//CHECK PADDLE
if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual
return 1;
//Check PTT while auto Sending
autoSendPTTCheck();
Check_Cat(3);
}
else
{
//Background Work
Check_Cat(fromType);
}
}
return 0;
}
/**
* Select the properly tx harmonic filters
* The four harmonic filters use only three relays
* the four LPFs cover 30-21 Mhz, 18 - 14 Mhz, 7-10 MHz and 3.5 to 5 Mhz
* Briefly, it works like this,
* - When KT1 is OFF, the 'off' position routes the PA output through the 30 MHz LPF
* - When KT1 is ON, it routes the PA output to KT2. Which is why you will see that
* the KT1 is on for the three other cases.
* - When the KT1 is ON and KT2 is off, the off position of KT2 routes the PA output
* to 18 MHz LPF (That also works for 14 Mhz)
* - When KT1 is On, KT2 is On, it routes the PA output to KT3
* - KT3, when switched on selects the 7-10 Mhz filter
* - KT3 when switched off selects the 3.5-5 Mhz filter
* See the circuit to understand this
*/
void setTXFilters(unsigned long freq){
if (freq > 21000000L){ // the default filter is with 35 MHz cut-off
digitalWrite(TX_LPF_A, 0);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
}
else if (freq >= 14000000L){ //thrown the KT1 relay on, the 30 MHz LPF is bypassed and the 14-18 MHz LPF is allowd to go through
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
}
else if (freq > 7000000L){
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 1);
digitalWrite(TX_LPF_C, 0);
}
else {
digitalWrite(TX_LPF_A, 1);
digitalWrite(TX_LPF_B, 1);
digitalWrite(TX_LPF_C, 1);
}
}
/**
* This is the most frequently called function that configures the
* radio to a particular frequeny, sideband and sets up the transmit filters
*
* The transmit filter relays are powered up only during the tx so they dont
* draw any current during rx.
*
* The carrier oscillator of the detector/modulator is permanently fixed at
* uppper sideband. The sideband selection is done by placing the second oscillator
* either 12 Mhz below or above the 45 Mhz signal thereby inverting the sidebands
* through mixing of the second local oscillator.
*/
void setFrequency(unsigned long f){
2018-01-22 12:16:29 +00:00
f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1];
setTXFilters(f);
2018-03-19 12:35:41 +00:00
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0));
int appliedTuneValue = 0;
2018-03-19 12:35:41 +00:00
//applied if tune
//byte advancedFreqOption1; //255 : Bit0: use IFTune_Value, Bit1 : use Stored enabled SDR Mode, Bit2 : dynamic sdr frequency0, Bit3 : dynamic sdr frequency1, bit 7: IFTune_Value Reverse for DIY uBITX
if ((advancedFreqOption1 & 0x01) != 0x00)
{
appliedTuneValue = if1TuneValue;
//In the LSB state, the optimum reception value was found. To apply to USB, 3Khz decrease is required.
if (sdrModeOn && (inTx == 0))
appliedTuneValue -= 15; //decrease 1.55Khz
//if (isUSB)
if (cwMode == 2 || (cwMode == 0 && (isUSB)))
appliedTuneValue -= 30; //decrease 3Khz
}
//if1Tune RX, TX Enabled, ATT : only RX Mode
//The IF Tune shall be measured at the LSB. Then, move the 3Khz down for USB.
long if1AdjustValue = ((inTx == 0) ? (attLevel * 100) : 0) + (appliedTuneValue * 100); //if1Tune RX, TX Enabled, ATT : only RX Mode //5600
//for DIY uBITX (custom filter)
if ((advancedFreqOption1 & 0x80) != 0x00) //Reverse IF Tune (- Value for DIY uBITX)
if1AdjustValue *= -1;
if (sdrModeOn && (inTx == 0)) //IF SDR MODE
2018-04-06 12:43:36 +00:00
{
//Fixed Frequency SDR (Default Frequency : 32Mhz, available change sdr Frequency by uBITX Manager)
//Dynamic Frequency is for SWL without cat
//byte advancedFreqOption1; //255 : Bit0: use IFTune_Value, Bit1 : use Stored enabled SDR Mode, Bit2 : dynamic sdr frequency0, Bit3 : dynamic sdr frequency1, bit 7: IFTune_Value Reverse for DIY uBITX
long moveFrequency = 0;
//7 6 5 4 3 2 1 0
// _ _ <-- SDR Freuqncy Option
byte sdrOption = (advancedFreqOption1 >> 2) & 0x03;
if (sdrOption == 1) // SDR Frequency + frequenc
{
//example : offset Freq : 20 Mhz and frequency = 7.080 => 27.080 Mhz
//example : offset Freq : 0 Mhz and frequency = 7.080 => 7.080 Mhz
//for available HF, SDR
moveFrequency = f;
}
else if (sdrOption == 2) //Mhz move
{
//Offset Frequency + Mhz,
//Example : Offset Frequency : 30Mhz and current Frequncy is 7.080 => 37.080Mhz
// Offset Frequency : 30Mhz and current Frequncy is 14.074 => 34.074Mhz
moveFrequency = (f % 10000000);
}
else if (sdrOption == 3) //Khzz move
{
//Offset Frequency + Khz,
//Example : Offset Frequency : 30Mhz and current Frequncy is 7.080 => 30.080Mhz
// Offset Frequency : 30Mhz and current Frequncy is 14.074 => 30.074Mhz
moveFrequency = (f % 1000000);
}
si5351bx_setfreq(2, 44991500 + if1AdjustValue + f);
si5351bx_setfreq(1, 44991500
+ if1AdjustValue
+ SDR_Center_Freq
//+ ((advancedFreqOption1 & 0x04) == 0x00 ? 0 : (f % 10000000))
+ moveFrequency
+ 2390);
2018-04-06 12:43:36 +00:00
}
else
{
if (cwMode == 1 || (cwMode == 0 && (!isUSB))) //cwl or lsb
2018-04-06 12:43:36 +00:00
{
//CWL(cwMode == 1) or LSB (cwMode == 0 && (!isUSB))
si5351bx_setfreq(2, SECOND_OSC_LSB + if1AdjustValue + appliedCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_LSB + if1AdjustValue);
}
else //cwu or usb
2018-04-06 12:43:36 +00:00
{
//CWU (cwMode == 2) or USB (cwMode == 0 and isUSB)
2018-04-06 12:43:36 +00:00
si5351bx_setfreq(2, SECOND_OSC_USB + if1AdjustValue - appliedCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_USB + if1AdjustValue);
2018-04-06 12:43:36 +00:00
}
}
/*
2018-01-30 04:20:52 +00:00
if (cwMode == 0)
{
if (isUSB){
2018-03-19 12:35:41 +00:00
si5351bx_setfreq(2, SECOND_OSC_USB - appliedCarrier + f);
2018-01-30 04:20:52 +00:00
si5351bx_setfreq(1, SECOND_OSC_USB);
}
else{
2018-03-19 12:35:41 +00:00
si5351bx_setfreq(2, SECOND_OSC_LSB + appliedCarrier + f);
2018-01-30 04:20:52 +00:00
si5351bx_setfreq(1, SECOND_OSC_LSB);
}
}
2018-01-30 04:20:52 +00:00
else
{
if (cwMode == 1){ //CWL
2018-03-19 12:35:41 +00:00
si5351bx_setfreq(2, SECOND_OSC_LSB + appliedCarrier + f);
2018-01-30 04:20:52 +00:00
si5351bx_setfreq(1, SECOND_OSC_LSB);
}
else{ //CWU
2018-03-19 12:35:41 +00:00
si5351bx_setfreq(2, SECOND_OSC_USB - appliedCarrier + f);
2018-01-30 04:20:52 +00:00
si5351bx_setfreq(1, SECOND_OSC_USB);
}
}
2018-04-06 12:43:36 +00:00
*/
frequency = f;
}
/**
* startTx is called by the PTT, cw keyer and CAT protocol to
* put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode
*/
2018-01-10 02:34:15 +00:00
void startTx(byte txMode, byte isDisplayUpdate){
2018-01-12 00:54:38 +00:00
//Check Hamband only TX //Not found Hamband index by now frequency
if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) {
//no message
return;
}
2018-01-13 07:19:23 +00:00
if ((isTxType & 0x01) != 0x01)
2018-01-10 02:34:15 +00:00
digitalWrite(TX_RX, 1);
2018-01-13 07:19:23 +00:00
inTx = 1;
if (ritOn){
//save the current as the rx frequency
ritRxFrequency = frequency;
setFrequency(ritTxFrequency);
}
2018-03-19 12:35:41 +00:00
else
{
if (splitOn == 1) {
2018-01-30 03:13:52 +00:00
if (vfoActive == VFO_B) {
vfoActive = VFO_A;
frequency = vfoA;
2018-02-03 07:35:27 +00:00
byteToMode(vfoA_mode, 0);
2018-01-30 03:13:52 +00:00
}
else if (vfoActive == VFO_A){
vfoActive = VFO_B;
frequency = vfoB;
2018-02-03 07:35:27 +00:00
byteToMode(vfoB_mode, 0);
2018-01-30 03:13:52 +00:00
}
2018-03-19 12:35:41 +00:00
}
2018-01-30 03:13:52 +00:00
2018-03-19 12:35:41 +00:00
setFrequency(frequency);
2018-01-30 03:13:52 +00:00
} //end of else
2018-03-19 12:35:41 +00:00
SetCarrierFreq();
if (txMode == TX_CW){
//turn off the second local oscillator and the bfo
si5351bx_setfreq(0, 0);
si5351bx_setfreq(1, 0);
//shif the first oscillator to the tx frequency directly
//the key up and key down will toggle the carrier unbalancing
//the exact cw frequency is the tuned frequency + sidetone
2018-01-30 04:20:52 +00:00
if (cwMode == 0)
{
if (isUSB)
si5351bx_setfreq(2, frequency + sideTone);
else
si5351bx_setfreq(2, frequency - sideTone);
}
else if (cwMode == 1) //CWL
{
si5351bx_setfreq(2, frequency - sideTone);
}
else //CWU
{
si5351bx_setfreq(2, frequency + sideTone);
}
}
2018-01-10 02:34:15 +00:00
//reduce latency time when begin of CW mode
if (isDisplayUpdate == 1)
updateDisplay();
}
2018-03-09 13:02:10 +00:00
void stopTx(void){
inTx = 0;
digitalWrite(TX_RX, 0); //turn off the tx
2018-03-19 12:35:41 +00:00
SetCarrierFreq();
if (ritOn)
setFrequency(ritRxFrequency);
2018-03-19 12:35:41 +00:00
else
{
if (splitOn == 1) {
2018-01-30 03:13:52 +00:00
//vfo Change
if (vfoActive == VFO_B){
vfoActive = VFO_A;
frequency = vfoA;
2018-02-03 07:35:27 +00:00
byteToMode(vfoA_mode, 0);
2018-01-30 03:13:52 +00:00
}
else if (vfoActive == VFO_A){
vfoActive = VFO_B;
frequency = vfoB;
2018-02-03 07:35:27 +00:00
byteToMode(vfoB_mode, 0);
2018-01-30 03:13:52 +00:00
}
2018-03-19 12:35:41 +00:00
}
setFrequency(frequency);
2018-03-19 12:35:41 +00:00
} //end of else
updateDisplay();
}
/**
* ritEnable is called with a frequency parameter that determines
* what the tx frequency will be
*/
void ritEnable(unsigned long f){
ritOn = 1;
//save the non-rit frequency back into the VFO memory
//as RIT is a temporary shift, this is not saved to EEPROM
ritTxFrequency = f;
}
// this is called by the RIT menu routine
void ritDisable(){
if (ritOn){
ritOn = 0;
setFrequency(ritTxFrequency);
updateDisplay();
}
}
/**
* Basic User Interface Routines. These check the front panel for any activity
*/
/**
* The PTT is checked only if we are not already in a cw transmit session
* If the PTT is pressed, we shift to the ritbase if the rit was on
* flip the T/R line to T and update the display to denote transmission
*/
void checkPTT(){
//we don't check for ptt when transmitting cw
if (cwTimeout > 0)
return;
if (digitalRead(PTT) == 0 && inTx == 0){
2018-01-10 02:34:15 +00:00
startTx(TX_SSB, 1);
delay(50); //debounce the PTT
}
if (digitalRead(PTT) == 1 && inTx == 1)
stopTx();
}
void checkButton(){
//only if the button is pressed
if (!btnDown())
return;
delay(50);
if (!btnDown()) //debounce
return;
doMenu();
2018-01-10 02:34:15 +00:00
//wait for the button to go up again
2018-01-10 02:34:15 +00:00
while(btnDown()) {
delay(10);
2018-01-10 02:34:15 +00:00
Check_Cat(0);
}
2018-03-05 03:51:14 +00:00
//delay(50);//debounce
}
2018-01-22 10:46:50 +00:00
/************************************
Replace function by KD8CEC
prevent error controls
applied Threshold for reduct errors, dial Lock, dynamic Step
*************************************/
byte threshold = 2; //noe action for count
unsigned long lastEncInputtime = 0;
int encodedSumValue = 0;
unsigned long lastTunetime = 0; //if continous moving, skip threshold processing
byte lastMovedirection = 0; //0 : stop, 1 : cw, 2 : ccw
2018-03-05 03:51:14 +00:00
//#define skipThresholdTime 70
2018-01-22 10:46:50 +00:00
#define encodeTimeOut 1000
void doTuningWithThresHold(){
2018-01-10 02:34:15 +00:00
int s = 0;
unsigned long prev_freq;
2018-01-10 02:34:15 +00:00
2018-01-12 00:54:38 +00:00
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02)))
2018-01-10 02:34:15 +00:00
return;
s = enc_read();
2018-01-22 10:46:50 +00:00
//if time is exceeded, it is recognized as an error,
//ignore exists values, because of errors
if (s == 0) {
if (encodedSumValue != 0 && (millis() - encodeTimeOut) > lastEncInputtime)
encodedSumValue = 0;
lastMovedirection = 0;
2018-01-22 10:46:50 +00:00
return;
}
lastEncInputtime = millis();
2018-01-10 02:34:15 +00:00
2018-01-22 10:46:50 +00:00
//for check moving direction
encodedSumValue += (s > 0 ? 1 : -1);
//check threshold and operator actions (hold dial speed = continous moving, skip threshold check)
2018-03-05 03:51:14 +00:00
//not use continues changing by Threshold
//if ((lastTunetime < (millis() - skipThresholdTime)) && ((encodedSumValue * encodedSumValue) <= (threshold * threshold)))
if (((encodedSumValue * encodedSumValue) <= (threshold * threshold)))
2018-01-22 10:46:50 +00:00
return;
lastTunetime = millis();
2018-01-22 10:46:50 +00:00
//Valid Action without noise
encodedSumValue = 0;
prev_freq = frequency;
//incdecValue = tuningStep * s;
2018-03-05 03:51:14 +00:00
//frequency += (arTuneStep[tuneStepIndex -1] * s * (s * s < 10 ? 1 : 3)); //appield weight (s is speed)
frequency += (arTuneStep[tuneStepIndex -1] * s); //appield weight (s is speed) //if want need more increase size, change step size
2018-01-22 10:46:50 +00:00
if (prev_freq < 10000000l && frequency > 10000000l)
isUSB = true;
if (prev_freq > 10000000l && frequency < 10000000l)
isUSB = false;
2018-01-22 10:46:50 +00:00
setFrequency(frequency);
updateDisplay();
}
/**
* RIT only steps back and forth by 100 hz at a time
*/
void doRIT(){
int knob = enc_read();
unsigned long old_freq = frequency;
if (knob < 0)
2018-02-13 10:54:19 +00:00
frequency -= (arTuneStep[tuneStepIndex -1]); //
else if (knob > 0)
2018-02-13 10:54:19 +00:00
frequency += (arTuneStep[tuneStepIndex -1]); //
if (old_freq != frequency){
setFrequency(frequency);
updateDisplay();
}
}
2018-03-05 03:51:14 +00:00
2018-01-30 09:43:08 +00:00
/*
2018-02-03 07:35:27 +00:00
save Frequency and mode to eeprom for Auto Save with protected eeprom cycle, by kd8cec
2018-01-10 02:34:15 +00:00
*/
void storeFrequencyAndMode(byte saveType)
{
//freqType : 0 Both (vfoA and vfoB), 1 : vfoA, 2 : vfoB
if (saveType == 0 || saveType == 1) //vfoA
{
if (vfoA != vfoA_eeprom) {
EEPROM.put(VFO_A, vfoA);
vfoA_eeprom = vfoA;
}
if (vfoA_mode != vfoA_mode_eeprom) {
EEPROM.put(VFO_A_MODE, vfoA_mode);
vfoA_mode_eeprom = vfoA_mode;
}
}
if (saveType == 0 || saveType == 2) //vfoB
{
if (vfoB != vfoB_eeprom) {
EEPROM.put(VFO_B, vfoB);
vfoB_eeprom = vfoB;
}
if (vfoB_mode != vfoB_mode_eeprom) {
EEPROM.put(VFO_B_MODE, vfoB_mode);
vfoB_mode_eeprom = vfoB_mode;
}
}
}
2018-02-03 07:35:27 +00:00
//calculate step size from 1 byte, compatible uBITX Manager, by KD8CEC
2018-02-02 11:49:00 +00:00
unsigned int byteToSteps(byte srcByte) {
byte powerVal = (byte)(srcByte >> 6);
unsigned int baseVal = srcByte & 0x3F;
if (powerVal == 1)
return baseVal * 10;
else if (powerVal == 2)
return baseVal * 100;
else if (powerVal == 3)
return baseVal * 1000;
else
return baseVal;
}
/**
* The settings are read from EEPROM. The first time around, the values may not be
* present or out of range, in this case, some intelligent defaults are copied into the
* variables.
*/
void initSettings(){
//read the settings from the eeprom and restore them
//if the readings are off, then set defaults
2018-01-13 07:19:23 +00:00
//for original source Section ===========================
EEPROM.get(MASTER_CAL, calibration);
EEPROM.get(USB_CAL, usbCarrier);
EEPROM.get(VFO_A, vfoA);
EEPROM.get(VFO_B, vfoB);
EEPROM.get(CW_SIDETONE, sideTone);
EEPROM.get(CW_SPEED, cwSpeed);
2018-01-26 12:47:15 +00:00
//End of original code
//----------------------------------------------------------------
//Add Lines by KD8CEC
2018-01-13 07:19:23 +00:00
//for custom source Section =============================
//ID & Version Check from EEProm
//if found different firmware, erase eeprom (32
#define FIRMWAR_ID_ADDR 776 //776 : 0x59, 777 :0x58, 778 : 0x68 : Id Number, if not found id, erase eeprom(32~1023) for prevent system error.
if (EEPROM.read(FIRMWAR_ID_ADDR) != 0x59 ||
EEPROM.read(FIRMWAR_ID_ADDR + 1) != 0x58 ||
EEPROM.read(FIRMWAR_ID_ADDR + 2) != 0x68 ) {
printLineF(1, F("Init EEProm..."));
//initial all eeprom
for (unsigned int i = 64; i < 1024; i++) //protect Master_cal, usb_cal
2018-01-13 07:19:23 +00:00
EEPROM.write(i, 0);
//Write Firmware ID
EEPROM.write(FIRMWAR_ID_ADDR, 0x59);
EEPROM.write(FIRMWAR_ID_ADDR + 1, 0x58);
EEPROM.write(FIRMWAR_ID_ADDR + 2, 0x68);
}
//Version Write for Memory Management Software
if (EEPROM.read(VERSION_ADDRESS) != FIRMWARE_VERSION_NUM)
EEPROM.write(VERSION_ADDRESS, FIRMWARE_VERSION_NUM);
2018-01-13 07:19:23 +00:00
2018-01-30 04:20:52 +00:00
EEPROM.get(CW_CAL, cwmCarrier);
2018-01-13 07:19:23 +00:00
2018-01-10 02:34:15 +00:00
//for Save VFO_A_MODE to eeprom
//0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
EEPROM.get(VFO_A_MODE, vfoA_mode);
EEPROM.get(VFO_B_MODE, vfoB_mode);
//CW DelayTime
EEPROM.get(CW_DELAY, cwDelayTime);
//CW interval between TX and CW Start
EEPROM.get(CW_START, delayBeforeCWStartTime);
2018-01-29 09:38:48 +00:00
EEPROM.get(CW_KEY_TYPE, cwKeyType);
if (cwKeyType > 2)
cwKeyType = 0;
if (cwKeyType == 0)
Iambic_Key = false;
else
{
Iambic_Key = true;
2018-01-31 01:44:23 +00:00
if (cwKeyType == 1)
2018-01-29 09:38:48 +00:00
keyerControl &= ~IAMBICB;
else
keyerControl |= IAMBICB;
}
2018-03-20 12:41:24 +00:00
EEPROM.get(COMMON_OPTION0, commonOption0);
2018-01-29 09:38:48 +00:00
EEPROM.get(DISPLAY_OPTION1, displayOption1);
EEPROM.get(DISPLAY_OPTION2, displayOption2);
2018-01-10 02:34:15 +00:00
//User callsign information
if (EEPROM.read(USER_CALLSIGN_KEY) == 0x59)
userCallsignLength = EEPROM.read(USER_CALLSIGN_LEN); //MAXIMUM 18 LENGTH
2018-01-12 00:54:38 +00:00
//Ham Band Count
EEPROM.get(HAM_BAND_COUNT, useHamBandCount);
EEPROM.get(TX_TUNE_TYPE, tuneTXType);
2018-01-22 10:46:50 +00:00
byte findedValidValueCount = 0;
2018-01-12 00:54:38 +00:00
//Read band Information
for (byte i = 0; i < useHamBandCount; i++) {
unsigned int tmpReadValue = 0;
EEPROM.get(HAM_BAND_RANGE + 4 * i, tmpReadValue);