7 Commits
Author SHA1 Message Date
phdleeandGitHub 1a60adaf2f Merge pull request #2 from phdlee/version0.8
added SWR, PWR sensor
2019-04-11 22:38:52 +09:00
phdlee 02c0066df4 added SWR, PWR sensor 2019-04-11 22:37:24 +09:00
phdleeandGitHub 265188dc86 Merge pull request #1 from phdlee/version0.7
added delay time at startup
2018-08-06 12:11:41 +09:00
phdlee aee410fd19 added delay time at startup 2018-08-06 11:58:41 +09:00
phdlee 16e173b109 add Init version files 2018-08-04 11:23:20 +09:00
phdlee d5db04ff0e Init and add comment for licnese 2018-08-04 11:04:51 +09:00
phdleeandGitHub 0586bb75a7 Initial commit 2018-08-04 10:55:39 +09:00
16 changed files with 1816 additions and 3806 deletions
+3 -3
View File
@@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
uBITX - An Arduino sketch to control the uBITX transceiver
Copyright (C) 2017, Ashhar Farhan
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
+6 -126
View File
@@ -1,128 +1,8 @@
#IMPORTANT INFORMATION
----------------------------------------------------------------------------
- Beta 0.26 and Beta 0.261, Beta 0.262, Beta 0.27 is complete test
- You can download and use it.
# dspmeterv1
Standalone Signal Analyzer (I2C Type Signal-Meter) for uBITX - Arduino Nano Version
#NOTICE
----------------------------------------------------------------------------
I received uBITX a month ago and found that many features are required, and began coding with the idea of implementing minimal functionality as a general hf transceiver rather than an experimental device.
I do not claim any license for my code.
You may use it in any way. I just hope this will be used for amateur radio.
The other person's source code (CW Morse code) follows the original author's license.
- fixed bugs...
- Diallock for uBITX's sensitive encoders
- built in softare Memory keyer and cw options control for CW communication
- Implementation of CAT communication protocol for Digital Communication (as FT8, JT65, etc)
- Delay Options for external Linear.
- and more...
Most of the basic functions of the HF transceiver I thought were implemented.
The minimum basic specification for uBITX to operate as a radio, I think it is finished.
So I will release the 0.27 version and if I do not see the bug anymore, I will try to change the version name to 1.0.
Now uBITX is an HF radio and will be able to join you in your happy hams life.
Based on this source, you can use it by adding functions.
I am going to do a new project based on this source, linking with WSPR, WSJT-X and so on.
Of course, this repository is still running. If you have any bugs or ideas, please feel free to email me.
http://www.hamskey.com
DE KD8CEC
kd8cec@gmail.com
#uBITX
uBITX firmware, written for the Raduino/Arduino control of uBITX transceivers
This project is based on https://github.com/afarhan/ubitx and all copyright is inherited.
The copyright information of the original is below.
KD8CEC
----------------------------------------------------------------------------
Prepared or finished tasks for the next version
- Most of them are implemented and included in version 0.27.
- User Interface on LCD -> Option by user (not need)
- Include WSPR Beacone function - (implement other new repository)
complete experiment
need solve : Big code size (over 100%, then remove some functions for experment)
need replace Si5351 Library (increase risk and need more beta tester)
W3PM sent me his wonderful source - using BITX, GPS
----------------------------------------------------------------------------
## REVISION RECORD
0.27
(First alpha test version, This will be renamed to the major version 1.0)
- Dual VFO Dial Lock (vfoA Dial lock)
- Support Ham band on uBITX
default Hamband is regeion1 but customize by uBITX Manager Software
- Advanced ham band options (Tx control) for use in all countries. You can adjust it yourself.
- Convenience of band movement
0.26
- only Beta tester released & source code share
- find a bug on none initial eeprom uBITX - Fixed (Check -> initialized & compatible original source code)
- change the version number 0.26 -> 0.27
- Prevent overflow bugs
- bug with linux based Hamlib (raspberry pi), It was perfect for the 0.224 version, but there was a problem for the 0.25 version.
On Windows, ham deluxe, wsjt-x, jt65-hf, and fldigi were successfully run. Problem with Raspberry pi.
0.25
- Beta Version Released
http://www.hamskey.com/2018/01/release-beta-version-of-cat-support.html
- Added CAT Protocol for uBITX
- Modified the default usb carrier value used when the setting is wrong.
- Fixed a routine to repair when the CAT protocol was interrupted.
0.24
- Program optimization
reduce usage ram rate (string with M() optins)
- Optimized CAT protocol for wsjt-x, fldigi
0.23
- added delay_background() , replace almost delay() to delay_background for prevent timeout
- cat library compatible with FT-817 Command
switch VFOA / VFOB,
Read Write CW Speed
Read Write CW Delay Time
Read Write CW Pitch (with sidetone)
All of these can be controlled by Hamradio deluxe.
- modified cat libray function for protocol for CAT communication is not broken in CW or TX mode
- Ability to change CW Delay
- Added Dial Lock function
- Add functions CW Start dely (TX -> CW interval)
- Automatic storage of VFO frequency
It was implemented by storing it only once when the frequency stays 10 seconds or more after the change.
(protect eeprom life)
0.22
- fixed screen Update Problem
- Frequency Display Problem - Problems occur below 1Mhz
- added function Enhanced CAT communication
- replace ubitx_cat.ino to cat_libs.ino
- Save mode when switching to VFOA / VFOB
0.21
- fixed the cw side tone configuration.
- Fix the error that the frequency is over.
- fixed frequency display (alignment, point)
0.20
- original uBITX software (Ashhar Farhan)
## Original README.md
uBITX firmware, written for the Raduino/Arduino control of uBITX transceigers
Copyright (C) 2017, Ashhar Farhan
This program 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.
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
Ian KD8CEC
+362
View File
@@ -0,0 +1,362 @@
/*
FFTFunctions for Nextion LCD and Control MCU
This code is for FFT and CW Decode.
KD8CEC, Ian Lee
-----------------------------------------------------------------------
//The section on CW decode logic is specified at the bottom of this code.
License : I follow the license of the previous code and I do not add any extra constraints.
I hope that the Comment I made or the Comment of OZ1JHM will be maintained.
**********************************************************************/
#include <arduino.h>
#include "i2cmeter1.h"
// Code Referency : http://paulbourke.net/miscellaneous/dft/
// DFT, FFT Wiritten by Paul Bourke, June 1993
void FFT(double *x,double *y, int n, long m)
{
long i,i1,j,k,i2,l,l1,l2;
double c1,c2,tx,ty,t1,t2,u1,u2,z;
short int dir = 0;
/* Do the bit reversal */
i2 = n >> 1;
j = 0;
for (i=0;i<n-1;i++) {
if (i < j) {
tx = x[i];
ty = y[i];
x[i] = x[j];
y[i] = y[j];
x[j] = tx;
y[j] = ty;
}
k = i2;
while (k <= j) {
j -= k;
k >>= 1;
}
j += k;
}
/* Compute the FFT */
c1 = -1.0;
c2 = 0.0;
l2 = 1;
for (l=0;l<m;l++)
{
l1 = l2;
l2 <<= 1;
u1 = 1.0;
u2 = 0.0;
for (j=0;j<l1;j++)
{
for (i=j;i<n;i+=l2)
{
i1 = i + l1;
t1 = u1 * x[i1] - u2 * y[i1];
t2 = u1 * y[i1] + u2 * x[i1];
x[i1] = x[i] - t1;
y[i1] = y[i] - t2;
x[i] += t1;
y[i] += t2;
}
z = u1 * c1 - u2 * c2;
u2 = u1 * c2 + u2 * c1;
u1 = z;
}
c2 = sqrt((1.0 - c1) / 2.0);
if (dir == 1)
c2 = -c2;
c1 = sqrt((1.0 + c1) / 2.0);
}
/* Scaling for forward transform */
/*
if (dir == 1) {
for (i=0;i<n;i++) {
x[i] /= n;
y[i] /= n;
}
}
return 1;
*/
//return(TRUE);
}
double coeff;
void CalculateCoeff(uint8_t freqIndex)
{
float omega;
int targetFrequency = freqIndex * 50 + 300;
int k = (int) (0.5 + ((DECODE_MORSE_SAMPLESIZE * targetFrequency) / SAMPLE_PREQUENCY));
omega = (2.0 * PI * k) / DECODE_MORSE_SAMPLESIZE;
coeff = 2.0 * cos(omega);
}
//=====================================================================
//The CW Decode code refers to the site code below.
//https://k2jji.org/2014/09/18/arduino-base-cw-decoder/
//Some code has been modified, but the original comments remain intact.
// code below is optimal for use in Arduino.
//Thanks to OZ1JHM
//KD8CEC
//=====================================================================
///////////////////////////////////////////////////////////////////////
// CW Decoder made by Hjalmar Skovholm Hansen OZ1JHM VER 1.01 //
// Feel free to change, copy or what ever you like but respect //
// that license is http://www.gnu.org/copyleft/gpl.html //
// Discuss and give great ideas on //
// https://groups.yahoo.com/neo/groups/oz1jhm/conversations/messages //
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Read more here http://en.wikipedia.org/wiki/Goertzel_algorithm //
// if you want to know about FFT the http://www.dspguide.com/pdfbook.htm //
///////////////////////////////////////////////////////////////////////////
//int magnitudelimit = 50;
//int magnitudelimit_low = 50;
int magnitudelimit = 30;
int magnitudelimit_low = 30;
char realstate = LOW;
char realstatebefore = LOW;
char filteredstate = LOW;
char filteredstatebefore = LOW;
long laststarttime = 0;
int nbtime = 6; /// ms noise blanker
long starttimehigh;
long highduration;
long lasthighduration;
long hightimesavg;
long lowtimesavg;
long startttimelow;
long lowduration;
char code[20];
uint8_t stop = LOW;
int wpm;
uint8_t cwDecodeHz = 9;
extern void SendCommandStr(char varIndex, char* sendValue);
void printascii(int asciinumber)
{
char rstDecode[4] = {0, 0, 0, 0};
if (asciinumber == 3)
{
}
else if (asciinumber == 4)
{
}
else if (asciinumber == 6)
{
}
else
{
rstDecode[0] = asciinumber;
}
SendCommandStr('b', rstDecode);
//Serial.write(asciinumber);
//if (writeCount++ > 20)
//{
//writeCount = 0;
//Serial.println("");
//}
}
uint8_t docode()
{
if (strcmp(code,".-") == 0) printascii(65);
if (strcmp(code,"-...") == 0) printascii(66);
if (strcmp(code,"-.-.") == 0) printascii(67);
if (strcmp(code,"-..") == 0) printascii(68);
if (strcmp(code,".") == 0) printascii(69);
if (strcmp(code,"..-.") == 0) printascii(70);
if (strcmp(code,"--.") == 0) printascii(71);
if (strcmp(code,"....") == 0) printascii(72);
if (strcmp(code,"..") == 0) printascii(73);
if (strcmp(code,".---") == 0) printascii(74);
if (strcmp(code,"-.-") == 0) printascii(75);
if (strcmp(code,".-..") == 0) printascii(76);
if (strcmp(code,"--") == 0) printascii(77);
if (strcmp(code,"-.") == 0) printascii(78);
if (strcmp(code,"---") == 0) printascii(79);
if (strcmp(code,".--.") == 0) printascii(80);
if (strcmp(code,"--.-") == 0) printascii(81);
if (strcmp(code,".-.") == 0) printascii(82);
if (strcmp(code,"...") == 0) printascii(83);
if (strcmp(code,"-") == 0) printascii(84);
if (strcmp(code,"..-") == 0) printascii(85);
if (strcmp(code,"...-") == 0) printascii(86);
if (strcmp(code,".--") == 0) printascii(87);
if (strcmp(code,"-..-") == 0) printascii(88);
if (strcmp(code,"-.--") == 0) printascii(89);
if (strcmp(code,"--..") == 0) printascii(90);
if (strcmp(code,".----") == 0) printascii(49);
if (strcmp(code,"..---") == 0) printascii(50);
if (strcmp(code,"...--") == 0) printascii(51);
if (strcmp(code,"....-") == 0) printascii(52);
if (strcmp(code,".....") == 0) printascii(53);
if (strcmp(code,"-....") == 0) printascii(54);
if (strcmp(code,"--...") == 0) printascii(55);
if (strcmp(code,"---..") == 0) printascii(56);
if (strcmp(code,"----.") == 0) printascii(57);
if (strcmp(code,"-----") == 0) printascii(48);
if (strcmp(code,"..--..") == 0) printascii(63);
if (strcmp(code,".-.-.-") == 0) printascii(46);
if (strcmp(code,"--..--") == 0) printascii(44);
if (strcmp(code,"-.-.--") == 0) printascii(33);
if (strcmp(code,".--.-.") == 0) printascii(64);
if (strcmp(code,"---...") == 0) printascii(58);
if (strcmp(code,"-....-") == 0) printascii(45);
if (strcmp(code,"-..-.") == 0) printascii(47);
if (strcmp(code,"-.--.") == 0) printascii(40);
if (strcmp(code,"-.--.-") == 0) printascii(41);
if (strcmp(code,".-...") == 0) printascii(95);
if (strcmp(code,"...-..-") == 0) printascii(36);
if (strcmp(code,"...-.-") == 0) printascii(62);
if (strcmp(code,".-.-.") == 0) printascii(60);
if (strcmp(code,"...-.") == 0) printascii(126);
//////////////////
// The specials //
//////////////////
if (strcmp(code,".-.-") == 0) printascii(3);
if (strcmp(code,"---.") == 0) printascii(4);
if (strcmp(code,".--.-") == 0) printascii(6);
}
void Decode_Morse(float magnitude)
{
//magnitudelimit auto Increase
if (magnitude > magnitudelimit_low)
{
magnitudelimit = (magnitudelimit +((magnitude - magnitudelimit)/6)); /// moving average filter
}
if (magnitudelimit < magnitudelimit_low)
magnitudelimit = magnitudelimit_low;
if(magnitude > magnitudelimit*0.6) // just to have some space up
realstate = HIGH;
else
realstate = LOW;
if (realstate != realstatebefore)
laststarttime = millis();
if ((millis()-laststarttime) > nbtime)
{
if (realstate != filteredstate)
{
filteredstate = realstate;
}
}
if (filteredstate != filteredstatebefore)
{
if (filteredstate == HIGH)
{
starttimehigh = millis();
lowduration = (millis() - startttimelow);
}
if (filteredstate == LOW)
{
startttimelow = millis();
highduration = (millis() - starttimehigh);
if (highduration < (2*hightimesavg) || hightimesavg == 0)
{
hightimesavg = (highduration+hightimesavg+hightimesavg)/3; // now we know avg dit time ( rolling 3 avg)
}
if (highduration > (5*hightimesavg) )
{
hightimesavg = highduration+hightimesavg; // if speed decrease fast ..
}
}
}
///////////////////////////////////////////////////////////////
// now we will check which kind of baud we have - dit or dah //
// and what kind of pause we do have 1 - 3 or 7 pause //
// we think that hightimeavg = 1 bit //
///////////////////////////////////////////////////////////////
if (filteredstate != filteredstatebefore)
{
stop = LOW;
if (filteredstate == LOW)
{
if (highduration < (hightimesavg*2) && highduration > (hightimesavg*0.6)) /// 0.6 filter out false dits
{
strcat(code,".");
}
if (highduration > (hightimesavg*2) && highduration < (hightimesavg*6))
{
strcat(code,"-");
wpm = (wpm + (1200/((highduration)/3)))/2; //// the most precise we can do ;o)
}
}
if (filteredstate == HIGH)
{
float lacktime = 1;
if(wpm > 25)lacktime=1.0; /// when high speeds we have to have a little more pause before new letter or new word
if(wpm > 30)lacktime=1.2;
if(wpm > 35)lacktime=1.5;
if (lowduration > (hightimesavg*(2*lacktime)) && lowduration < hightimesavg*(5*lacktime)) // letter space
{
docode();
code[0] = '\0';
}
if (lowduration >= hightimesavg*(5*lacktime))
{ // word space
docode();
code[0] = '\0';
printascii(32);
}
}
}
if ((millis() - startttimelow) > (highduration * 6) && stop == LOW)
{
docode();
code[0] = '\0';
stop = HIGH;
}
/*
if(filteredstate == HIGH)
{
digitalWrite(ledPin, HIGH);
tone(audioOutPin,target_freq);
}
else
{
digitalWrite(ledPin, LOW);
noTone(audioOutPin);
}
*/
realstatebefore = realstate;
lasthighduration = highduration;
filteredstatebefore = filteredstate;
}
+76
View File
@@ -0,0 +1,76 @@
/*
Configuration file for Nextion LCD and Control MCU
The parameter can be set according to the CPU used.
KD8CEC, Ian Lee
-----------------------------------------------------------------------
**********************************************************************/
#include <arduino.h>
//================================================================
//COMMUNICATION SECTION
//================================================================
#define USE_SW_SERIAL
extern void SWSerial_Write(uint8_t b);
extern void SWSerial_Print(uint8_t *b);
#ifdef USE_SW_SERIAL
extern void SWSerial_Begin(long speedBaud);
extern int SWSerial_Available(void);
extern int SWSerial_Read(void);
#else
#define PRINT_MAX_LENGTH 30
#endif
//================================================================
//FFT and Decode Morse
//================================================================
#define FFTSIZE 64
#define SAMPLE_PREQUENCY 6000
#define SAMPLESIZE (FFTSIZE * 2)
#define DECODE_MORSE_SAMPLESIZE 48
extern uint8_t cwDecodeHz;
extern int magnitudelimit_low;
//================================================================
//EEPROM Section
//================================================================
#define MAX_FORWARD_BUFF_LENGTH 128
#define EEPROM_DSPTYPE 100
#define EEPROM_SMETER_UART 111
#define EEPROM_SMETER_TIME 112
#define EEPROM_CW_FREQ 120
//#define EEPROM_CW_MAG_LIMIT 121
#define EEPROM_CW_MAG_LOW 122
#define EEPROM_CW_NBTIME 126
#define EEPROM_RTTYDECODEHZ 130
//================================================================
//DEFINE for I2C Command
//================================================================
//S-Meter Address
#define I2CMETER_ADDR 0x58 //changed from 0x6A
//VALUE TYPE============================================
//Signal
#define I2CMETER_CALCS 0x59 //Calculated Signal Meter
#define I2CMETER_UNCALCS 0x58 //Uncalculated Signal Meter
//Power
#define I2CMETER_CALCP 0x57 //Calculated Power Meter
#define I2CMETER_UNCALCP 0x56 //UnCalculated Power Meter
//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
File diff suppressed because it is too large Load Diff
+355
View File
@@ -0,0 +1,355 @@
/*
Softserial for Nextion LCD and Control MCU
KD8CEC, Ian Lee
-----------------------------------------------------------------------
It is a library rewritten in C format based on SoftwareSerial.c.
I tried to use as much as possible without modifying the SoftwareSerial.
But eventually I had to modify the code.
I rewrote it in C for the following reasons.
- Problems occurred when increasing Program Size and Program Memory
- We had to reduce the program size.
Of course, Software Serial is limited to one.
- reduce the steps for transmitting and receiving
useage
extern void SWSerial_Begin(long speedBaud);
extern void SWSerial_Write(uint8_t b);
extern int SWSerial_Available(void);
extern int SWSerial_Read(void);
extern void SWSerial_Print(uint8_t *b);
If you use Softwreserial library instead of this library, you can modify the code as shown below.
I kept the function name of SoftwareSerial so you only need to modify a few lines of code.
define top of source code
#include <SoftwareSerial.h>
SoftwareSerial sSerial(10, 11); // RX, TX
replace source code
SWSerial_Begin to sSerial.begin
SWSerial_Write to sSerial.write
SWSerial_Available to sSerial.available
SWSerial_Read to sSerial.read
KD8CEC, Ian Lee
-----------------------------------------------------------------------
License
All licenses for the source code are subject to the license of the original source SoftwareSerial Library.
However, if you use or modify this code, please keep the all comments in this source code.
KD8CEC
-----------------------------------------------------------------------
License from SoftwareSerial
-----------------------------------------------------------------------
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
Multi-instance software serial library for Arduino/Wiring
-- Interrupt-driven receive and other improvements by ladyada
(http://ladyada.net)
-- Tuning, circular buffer, derivation from class Print/Stream,
multi-instance support, porting to 8MHz processors,
various optimizations, PROGMEM delay tables, inverse logic and
direct port writing by Mikal Hart (http://www.arduiniana.org)
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
The latest version of this library can always be found at
http://arduiniana.org.
*/
#include "i2cmeter1.h"
#ifdef USE_SW_SERIAL
//================================================================
//Public Variable
//================================================================
#define TX_PIN 9
#define RX_PIN 8
#define _SS_MAX_RX_BUFF 35 // RX buffer size
#define PRINT_MAX_LENGTH 30
//================================================================
//Internal Variable from SoftwareSerial.c and SoftwareSerial.h
//================================================================
//variable from softwareserial.c and softwareserial.h
static uint8_t swr_receive_buffer[_SS_MAX_RX_BUFF];
volatile uint8_t *_transmitPortRegister; //Write Port Register
uint8_t transmit_RegMask; //use Mask bit 1
uint8_t transmit_InvMask; //use mask bit 0
volatile uint8_t *_receivePortRegister; //Read Port Register
uint8_t _receiveBitMask;
//delay value for Bit
uint16_t _tx_delay;
//delay value for Receive
uint16_t _rx_delay_stopbit;
uint16_t _rx_delay_centering;
uint16_t _rx_delay_intrabit;
//Customize for uBITX Protocol
int8_t receiveIndex = 0;
int8_t receivedCommandLength = 0;
int8_t ffCount = 0;
//Values for Receive Buffer
//uint16_t _buffer_overflow;
//static volatile uint8_t _receive_buffer_head;
//static volatile uint8_t _receive_buffer_tail;
//Values for Interrupt (check Start Bit)
volatile uint8_t *_pcint_maskreg;
uint8_t _pcint_maskvalue;
//================================================================
//Internal Function from SoftwareSerial.c
//================================================================
uint16_t subtract_cap(uint16_t num, uint16_t sub)
{
if (num > sub)
return num - sub;
else
return 1;
}
inline void tunedDelay(uint16_t delay)
{
_delay_loop_2(delay);
}
void setRxIntMsk(bool enable)
{
if (enable)
*_pcint_maskreg |= _pcint_maskvalue;
else
*_pcint_maskreg &= ~_pcint_maskvalue;
}
uint8_t rx_pin_read()
{
return *_receivePortRegister & _receiveBitMask;
}
//
// The receive routine called by the interrupt handler
//
void softSerail_Recv()
{
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Preserve the registers that the compiler misses
// (courtesy of Arduino forum user *etracer*)
asm volatile(
"push r18 \n\t"
"push r19 \n\t"
"push r20 \n\t"
"push r21 \n\t"
"push r22 \n\t"
"push r23 \n\t"
"push r26 \n\t"
"push r27 \n\t"
::);
#endif
uint8_t d = 0;
// If RX line is high, then we don't see any start bit
// so interrupt is probably not for us
if (!rx_pin_read()) //Start Bit
{
// Disable further interrupts during reception, this prevents
// triggering another interrupt directly after we return, which can
// cause problems at higher baudrates.
setRxIntMsk(false);
// Wait approximately 1/2 of a bit width to "center" the sample
tunedDelay(_rx_delay_centering);
// Read each of the 8 bits
for (uint8_t i=8; i > 0; --i)
{
tunedDelay(_rx_delay_intrabit);
d >>= 1;
if (rx_pin_read())
d |= 0x80;
}
if (receivedCommandLength == 0) //check Already Command
{
//Set Received Data
swr_receive_buffer[receiveIndex++] = d;
//Finded Command
if (d == 0x73 && ffCount > 1 && receiveIndex > 6)
{
receivedCommandLength = receiveIndex;
receiveIndex = 0;
ffCount = 0;
}
else if (receiveIndex > _SS_MAX_RX_BUFF)
{
//Buffer Overflow
receiveIndex = 0;
ffCount = 0;
}
else if (d == 0xFF)
{
ffCount++;
}
else
{
ffCount = 0;
}
}
// skip the stop bit
tunedDelay(_rx_delay_stopbit);
// Re-enable interrupts when we're sure to be inside the stop bit
setRxIntMsk(true);
}
#if GCC_VERSION < 40302
// Work-around for avr-gcc 4.3.0 OSX version bug
// Restore the registers that the compiler misses
asm volatile(
"pop r27 \n\t"
"pop r26 \n\t"
"pop r23 \n\t"
"pop r22 \n\t"
"pop r21 \n\t"
"pop r20 \n\t"
"pop r19 \n\t"
"pop r18 \n\t"
::);
#endif
}
ISR(PCINT0_vect)
{
softSerail_Recv();
}
//================================================================
//Public Function from SoftwareSerial.c and modified and create
//================================================================
// Read data from buffer
void SWSerial_Read(uint8_t * receive_cmdBuffer)
{
for (int i = 0; i < receivedCommandLength; i++)
receive_cmdBuffer[i] = swr_receive_buffer[i];
}
void SWSerial_Write(uint8_t b)
{
volatile uint8_t *reg = _transmitPortRegister;
uint8_t oldSREG = SREG;
uint16_t delay = _tx_delay;
cli(); // turn off interrupts for a clean txmit
// Write the start bit
*reg &= transmit_InvMask;
tunedDelay(delay);
// Write each of the 8 bits
for (uint8_t i = 8; i > 0; --i)
{
if (b & 1) // choose bit
*reg |= transmit_RegMask; // send 1
else
*reg &= transmit_InvMask; // send 0
tunedDelay(delay);
b >>= 1;
}
// restore pin to natural state
*reg |= transmit_RegMask;
SREG = oldSREG; // turn interrupts back on
tunedDelay(_tx_delay);
}
void SWSerial_Print(uint8_t *b)
{
for (int i = 0; i < PRINT_MAX_LENGTH; i++)
{
if (b[i] == 0x00)
break;
else
SWSerial_Write(b[i]);
}
}
void SWSerial_Begin(long speedBaud)
{
//INT TX_PIN
digitalWrite(TX_PIN, HIGH);
pinMode(TX_PIN, OUTPUT);
transmit_RegMask = digitalPinToBitMask(TX_PIN); //use Bit 1
transmit_InvMask = ~digitalPinToBitMask(TX_PIN); //use Bit 0
_transmitPortRegister = portOutputRegister(digitalPinToPort(TX_PIN));
//INIT RX_PIN
pinMode(RX_PIN, INPUT);
digitalWrite(RX_PIN, HIGH); // pullup for normal logic!
_receiveBitMask = digitalPinToBitMask(RX_PIN);
_receivePortRegister = portInputRegister(digitalPinToPort(RX_PIN));
//Set Values
uint16_t bit_delay = (F_CPU / speedBaud) / 4;
_tx_delay = subtract_cap(bit_delay, 15 / 4);
if (digitalPinToPCICR(RX_PIN))
{
_rx_delay_centering = subtract_cap(bit_delay / 2, (4 + 4 + 75 + 17 - 23) / 4);
_rx_delay_intrabit = subtract_cap(bit_delay, 23 / 4);
_rx_delay_stopbit = subtract_cap(bit_delay * 3 / 4, (37 + 11) / 4);
*digitalPinToPCICR(RX_PIN) |= _BV(digitalPinToPCICRbit(RX_PIN));
_pcint_maskreg = digitalPinToPCMSK(RX_PIN);
_pcint_maskvalue = _BV(digitalPinToPCMSKbit(RX_PIN));
tunedDelay(_tx_delay); // if we were low this establishes the end
}
//Start Listen
setRxIntMsk(true);
}
#else
void SWSerial_Write(uint8_t b)
{
Serial.write(b);
//Serial.flush();
}
void SWSerial_Print(uint8_t *b)
{
for (int i = 0; i < PRINT_MAX_LENGTH; i++)
{
if (b[i] == 0x00)
break;
else
SWSerial_Write(b[i]);
}
}
#endif
-753
View File
@@ -1,753 +0,0 @@
/*************************************************************************
This source code is written for uBITX, but it can also be used on other radios.
The CAT protocol is used by many radios to provide remote control to comptuers through
the serial port.
it is based on FT-817, uBITX's only protocol has been added and will be added in the future.
In addition, simple things such as FT-857 frequency control and PTT control can also be
transmitted to the FT-857 protocol.
This code refers to the following code.
- FT857D CAT Library, by Pavel Milanes, CO7WT, pavelmc@gmail.com
https://github.com/pavelmc/FT857d/
- Ham Radio Control Libraries, https://sourceforge.net/projects/hamlib/
- Not found protocols decription were analyzed using an RS-232 analyzer.
using FT-817 and
- http://www.ka7oei.com/ft817_meow.html <-- It was a great help here.
-----------------------------------------------------------------------------
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#define printLineF1(x) (printLineF(1, x))
#define printLineF2(x) (printLineF(0, x))
//for broken protocol
#define CAT_RECEIVE_TIMEOUT 500
#define CAT_MODE_LSB 0x00
#define CAT_MODE_USB 0x01
#define CAT_MODE_CW 0x02
#define CAT_MODE_CWR 0x03
#define CAT_MODE_AM 0x04
#define CAT_MODE_FM 0x08
#define CAT_MODE_DIG 0x0A
#define CAT_MODE_PKT 0x0C
#define CAT_MODE_FMN 0x88
#define ACK 0
unsigned int skipTimeCount = 0;
byte CAT_BUFF[5];
byte CAT_SNDBUFF[5];
void SendCatData(byte sendCount)
{
for (byte i = 0; i < sendCount; i++)
Serial.write(CAT_BUFF[i]);
//Serial.flush();
}
//PROTOCOL : 0x01
//Computer ->(frequency)-> TRCV CAT_BUFF
void CatSetFreq(byte fromType)
{
//CAT_BUFF
byte i;
unsigned long tempFreq = 0;
if (fromType == 2 || fromType == 3) {
Serial.write(ACK);
return;
}
//2 digit in 1 byte (4 bit + 4bit) * 4.5 byte
for (i = 0; i < 4; i++)
{
tempFreq *= 10;
tempFreq += CAT_BUFF[i] >> 4;
tempFreq *= 10;
tempFreq += CAT_BUFF[i] & 0x0f;
}
tempFreq *= 10;
tempFreq += CAT_BUFF[4] >> 4;
if (!inTx && (frequency != tempFreq))
{
//Check Frequency Range
if (tempFreq >= LOWEST_FREQ_DIAL && tempFreq <= HIGHEST_FREQ_DIAL)
{
setFrequency(tempFreq);
updateDisplay();
}
else
{
//KD8CEC
//Remark for rduce program size, if you need, you can remove remark,
//however alomost rig control software available 1.0 ~ 50Mhz
//printLine(0, "OUT OF RANGE!!!");
//delay_background(300, 0);
}
}
Serial.write(ACK);
}
//#define BCD_LEN 9
//PROTOCOL : 0x03
//Computer <-(frequency)-> TRCV CAT_BUFF
void CatGetFreqMode(unsigned long freq, byte fromType)
{
int i;
byte tmpValue;
unsigned BCD_LEN = 9;
if (BCD_LEN & 1) {
CAT_BUFF[BCD_LEN / 2] &= 0x0f;
CAT_BUFF[BCD_LEN / 2] |= (freq % 10) << 4;
freq /= 10;
}
for (i = (BCD_LEN / 2) - 1; i >= 0; i--) {
tmpValue = freq % 10;
freq /= 10;
tmpValue |= (freq % 10) << 4;
freq /= 10;
CAT_BUFF[i] = tmpValue;
}
//Mode Check
if (isUSB)
CAT_BUFF[4] = CAT_MODE_USB;
else
CAT_BUFF[4] = CAT_MODE_LSB;
SendCatData(5);
}
void CatSetSplit(boolean isSplit, byte fromType)
{
Serial.write(ACK);
}
void CatSetPTT(boolean isPTTOn, byte fromType)
{
if (fromType == 2 || fromType == 3) {
Serial.write(ACK);
return;
}
// Set PTT Mode
if (isPTTOn)
{
if (!inTx)
{
txCAT = true;
startTx(TX_SSB, 1);
//Exit menu, Memory Keyer... ETC
if (isCWAutoMode > 0) {
isCWAutoMode = 0;
printLineF2(F("AutoKey Exit/CAT"));
//delay_background(1000, 0);
}
}
}
else
{
if (inTx)
{
stopTx();
txCAT = false;
}
}
Serial.write(ACK);
}
void CatVFOToggle(boolean isSendACK, byte fromType)
{
if (fromType != 2 && fromType != 3) {
menuVfoToggle(1, 0);
}
if (isSendACK)
Serial.write(ACK); //Time
}
void CatSetMode(byte tmpMode, byte fromType)
{
if (fromType == 2 || fromType == 3) {
Serial.write(ACK);
return;
}
if (!inTx)
{
if (tmpMode == CAT_MODE_USB)
{
isUSB = true;
}
else
{
isUSB = false;
}
setFrequency(frequency);
updateDisplay();
}
Serial.write(ACK);
}
//Read EEProm by uBITX Manager Software
void ReadEEPRom(byte fromType)
{
//5BYTES
//CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND
//0, 1 START ADDRESS
uint16_t eepromStartIndex = CAT_BUFF[0] + CAT_BUFF[1] * 256;
uint16_t eepromReadLength = CAT_BUFF[2] + CAT_BUFF[3] * 256;;
byte checkSum = 0;
byte read1Byte = 0;
Serial.write(0x02); //STX
checkSum = 0x02;
for (uint16_t i = 0; i < eepromReadLength; i++)
{
read1Byte = EEPROM.read(eepromStartIndex + i);
checkSum += read1Byte;
Serial.write(read1Byte);
}
Serial.write(checkSum);
Serial.write(ACK);
}
//Write just proecess 1byes
void WriteEEPRom(byte fromType)
{
//5BYTES
uint16_t eepromStartIndex = CAT_BUFF[0] + CAT_BUFF[1] * 256;
byte write1Byte = CAT_BUFF[2];
//Check Checksum
if (CAT_BUFF[3] != ((CAT_BUFF[0] + CAT_BUFF[1] + CAT_BUFF[2]) % 256))
{
Serial.write(0x56); //CHECK SUM ERROR
Serial.write(ACK);
}
else
{
EEPROM.write(eepromStartIndex, write1Byte);
Serial.write(0x77); //OK
Serial.write(ACK);
}
}
void ReadEEPRom_FT817(byte fromType)
{
byte temp0 = CAT_BUFF[0];
byte temp1 = CAT_BUFF[1];
CAT_BUFF[0] = 0;
CAT_BUFF[1] = 0;
switch (temp1)
{
case 0x45 : //
if (temp0 == 0x03)
{
CAT_BUFF[0] = 0x00;
CAT_BUFF[1] = 0xD0;
}
break;
case 0x47 : //
if (temp0 == 0x03)
{
CAT_BUFF[0] = 0xDC;
CAT_BUFF[1] = 0xE0;
}
break;
case 0x55 :
//0 : VFO A/B 0 = VFO-A, 1 = VFO-B
//1 : MTQMB Select 0 = (Not MTQMB), 1 = MTQMB ("Memory Tune Quick Memory Bank")
//2 : QMB Select 0 = (Not QMB), 1 = QMB ("Quick Memory Bank")
//3 :
//4 : Home Select 0 = (Not HOME), 1 = HOME memory
//5 : Memory/MTUNE select 0 = Memory, 1 = MTUNE
//6 :
//7 : MEM/VFO Select 0 = Memory, 1 = VFO (A or B - see bit 0)
CAT_BUFF[0] = 0x80 + (vfoActive == VFO_B ? 1 : 0);
CAT_BUFF[1] = 0x00;
break;
case 0x57 : //
//0 : 1-0 AGC Mode 00 = Auto, 01 = Fast, 10 = Slow, 11 = Off
//2 DSP On/Off 0 = Off, 1 = On (Display format)
//4 PBT On/Off 0 = Off, 1 = On (Passband Tuning)
//5 NB On/Off 0 = Off, 1 = On (Noise Blanker)
//6 Lock On/Off 0 = Off, 1 = On (Dial Lock)
//7 FST (Fast Tuning) On/Off 0 = Off, 1 = On (Fast tuning)
CAT_BUFF[0] = 0xC0;
CAT_BUFF[1] = 0x40;
break;
case 0x59 : // band select VFO A Band Select 0000 = 160 M, 0001 = 75 M, 0010 = 40 M, 0011 = 30 M, 0100 = 20 M, 0101 = 17 M, 0110 = 15 M, 0111 = 12 M, 1000 = 10 M, 1001 = 6 M, 1010 = FM BCB, 1011 = Air, 1100 = 2 M, 1101 = UHF, 1110 = (Phantom)
//http://www.ka7oei.com/ft817_memmap.html
//CAT_BUFF[0] = 0xC2;
//CAT_BUFF[1] = 0x82;
break;
case 0x5C : //Beep Volume (0-100) (#13)
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0x42;
break;
case 0x5E :
//3-0 : CW Pitch (300-1000 Hz) (#20) From 0 to E (HEX) with 0 = 300 Hz and each step representing 50 Hz
//5-4 : Lock Mode (#32) 00 = Dial, 01 = Freq, 10 = Panel
//7-6 : Op Filter (#38) 00 = Off, 01 = SSB, 10 = CW
//CAT_BUFF[0] = 0x08;
CAT_BUFF[0] = sideTonePitch;
CAT_BUFF[1] = 0x25;
break;
case 0x61 : //Sidetone (Volume) (#44)
CAT_BUFF[0] = sideToneSub;
CAT_BUFF[1] = 0x08;
break;
case 0x5F : //
//4-0 CW Weight (1.:2.5-1:4.5) (#22) From 0 to 14 (HEX) with 0 = 1:2.5, incrementing in 0.1 weight steps
//5 420 ARS (#2) 0 = Off, 1 = On
//6 144 ARS (#1) 0 = Off, 1 = On
//7 Sql/RF-G (#45) 0 = Off, 1 = On
CAT_BUFF[0] = 0x32;
CAT_BUFF[1] = 0x08;
break;
case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms
CAT_BUFF[0] = cwDelayTime;
CAT_BUFF[1] = 0x32;
break;
case 0x62 : //
//5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
//7-6 Batt-Chg (6/8/10 Hours (#11) 00 = 6 Hours, 01 = 8 Hours, 10 = 10 Hours
//CAT_BUFF[0] = 0x08;
CAT_BUFF[0] = 1200 / cwSpeed - 4;
CAT_BUFF[1] = 0xB2;
break;
case 0x63 : //
//6-0 VOX Gain (#51) Contains 1-100 (decimal) as displayed
//7 Disable AM/FM Dial (#4) 0 = Enable, 1 = Disable
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0xA5;
break;
case 0x64 : //
break;
case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0xB2;
break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
case 0x78 :
if (isUSB)
CAT_BUFF[0] = CAT_MODE_USB;
else
CAT_BUFF[0] = CAT_MODE_LSB;
if (CAT_BUFF[0] != 0) CAT_BUFF[0] = 1 << 5;
break;
case 0x79 : //
//1-0 TX Power (All bands) 00 = High, 01 = L3, 10 = L2, 11 = L1
//3 PRI On/Off 0 = Off, 1 = On
//DW On/Off 0 = Off, 1 = On
//SCN (Scan) Mode 00 = No scan, 10 = Scan up, 11 = Scan down
//ART On/Off 0 = Off, 1 = On
CAT_BUFF[0] = 0x00;
CAT_BUFF[1] = 0x00;
break;
case 0x7A : //SPLIT
//7A 0 HF Antenna Select 0 = Front, 1 = Rear
//7A 1 6 M Antenna Select 0 = Front, 1 = Rear
//7A 2 FM BCB Antenna Select 0 = Front, 1 = Rear
//7A 3 Air Antenna Select 0 = Front, 1 = Rear
//7A 4 2 M Antenna Select 0 = Front, 1 = Rear
//7A 5 UHF Antenna Select 0 = Front, 1 = Rear
//7A 6 ? ?
//7A 7 SPL On/Off 0 = Off, 1 = On
CAT_BUFF[0] = (isSplitOn ? 0xFF : 0x7F);
break;
case 0xB3 : //
CAT_BUFF[0] = 0x00;
CAT_BUFF[1] = 0x4D;
break;
}
// sent the data
SendCatData(2);
}
void WriteEEPRom_FT817(byte fromType)
{
byte temp0 = CAT_BUFF[0];
byte temp1 = CAT_BUFF[1];
CAT_BUFF[0] = 0;
CAT_BUFF[1] = 0;
if (fromType == 2 || fromType == 3) {
SendCatData(2);
Serial.write(ACK);
return;
}
switch (temp1)
{
case 0x55 :
//0 : VFO A/B 0 = VFO-A, 1 = VFO-B
//1 : MTQMB Select 0 = (Not MTQMB), 1 = MTQMB ("Memory Tune Quick Memory Bank")
//2 : QMB Select 0 = (Not QMB), 1 = QMB ("Quick Memory Bank")
//3 :
//4 : Home Select 0 = (Not HOME), 1 = HOME memory
//5 : Memory/MTUNE select 0 = Memory, 1 = MTUNE
//6 :
//7 : MEM/VFO Select 0 = Memory, 1 = VFO (A or B - see bit 0)
if (CAT_BUFF[2] & 0x01) //vfoB
{
//nowVFO Check
if (vfoActive != VFO_B)
{
CatVFOToggle(false, fromType);
}
}
else
{
//vfoA
if (vfoActive != VFO_A)
{
CatVFOToggle(false, fromType);
}
}
break;
/*
case 0x57 : //
//0 : 1-0 AGC Mode 00 = Auto, 01 = Fast, 10 = Slow, 11 = Off
//2 DSP On/Off 0 = Off, 1 = On (Display format)
//4 PBT On/Off 0 = Off, 1 = On (Passband Tuning)
//5 NB On/Off 0 = Off, 1 = On (Noise Blanker)
//6 Lock On/Off 0 = Off, 1 = On (Dial Lock)
//7 FST (Fast Tuning) On/Off 0 = Off, 1 = On (Fast tuning)
CAT_BUFF[0] = 0xC0;
CAT_BUFF[1] = 0x40;
break;
case 0x59 : // band select VFO A Band Select 0000 = 160 M, 0001 = 75 M, 0010 = 40 M, 0011 = 30 M, 0100 = 20 M, 0101 = 17 M, 0110 = 15 M, 0111 = 12 M, 1000 = 10 M, 1001 = 6 M, 1010 = FM BCB, 1011 = Air, 1100 = 2 M, 1101 = UHF, 1110 = (Phantom)
//http://www.ka7oei.com/ft817_memmap.html
//CAT_BUFF[0] = 0xC2;
//CAT_BUFF[1] = 0x82;
break;
case 0x5C : //Beep Volume (0-100) (#13)
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0x42;
break;
*/
case 0x5E :
//3-0 : CW Pitch (300-1000 Hz) (#20) From 0 to E (HEX) with 0 = 300 Hz and each step representing 50 Hz
//5-4 : Lock Mode (#32) 00 = Dial, 01 = Freq, 10 = Panel
//7-6 : Op Filter (#38) 00 = Off, 01 = SSB, 10 = CW
sideTonePitch = (CAT_BUFF[2] & 0x0F);
if (sideTonePitch != 0 || sideToneSub != 0)
{
sideTone = (sideTonePitch * 50 + 300) + sideToneSub;
printLineF2(F("Sidetone set! CAT"));
EEPROM.put(CW_SIDETONE, sideTone);
delay(300); //If timeout errors occur in the calling software, remove them
printLine2(""); //Ham radio deluxe is the only one that supports this feature yet. and ham radio deluxe has wait time as greater than 500ms
}
break;
case 0x61 : //Sidetone (Volume) (#44)
sideToneSub = (CAT_BUFF[2] & 0x7F);
if (sideTonePitch != 0 || sideToneSub != 0)
{
sideTone = (sideTonePitch * 50 + 300) + sideToneSub;
printLineF2(F("Sidetone set! CAT"));
EEPROM.put(CW_SIDETONE, sideTone);
delay(300); //If timeout errors occur in the calling software, remove them
printLine2(""); //Ham radio deluxe is the only one that supports this feature yet. and ham radio deluxe has wait time as greater than 500ms
}
break;
/*
case 0x5F : //
//4-0 CW Weight (1.:2.5-1:4.5) (#22) From 0 to 14 (HEX) with 0 = 1:2.5, incrementing in 0.1 weight steps
//5 420 ARS (#2) 0 = Off, 1 = On
//6 144 ARS (#1) 0 = Off, 1 = On
//7 Sql/RF-G (#45) 0 = Off, 1 = On
CAT_BUFF[0] = 0x32;
CAT_BUFF[1] = 0x08;
break;
*/
case 0x60 : //CW Delay (10-2500 ms) (#17) From 1 to 250 (decimal) with each step representing 10 ms
//CAT_BUFF[0] = 0x19;
cwDelayTime = CAT_BUFF[2];
printLineF2(F("CW Speed set!"));
EEPROM.put(CW_DELAY, cwDelayTime);
delay(300);
printLine2("");
break;
case 0x62 : //
//5-0 CW Speed (4-60 WPM) (#21) From 0 to 38 (HEX) with 0 = 4 WPM and 38 = 60 WPM (1 WPM steps)
//7-6 Batt-Chg (6/8/10 Hours (#11) 00 = 6 Hours, 01 = 8 Hours, 10 = 10 Hours
cwSpeed = 1200 / ((CAT_BUFF[2] & 0x3F) + 4);
printLineF2(F("CW Speed set!"));
EEPROM.put(CW_SPEED, cwSpeed);
delay(300);
printLine2("");
break;
/*
case 0x63 : //
//6-0 VOX Gain (#51) Contains 1-100 (decimal) as displayed
//7 Disable AM/FM Dial (#4) 0 = Enable, 1 = Disable
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0xA5;
break;
case 0x64 : //
//CAT_BUFF[0] = 0xA5;
//CAT_BUFF[1] = 0x00;
break;
case 0x67 : //6-0 SSB Mic (#46) Contains 0-100 (decimal) as displayed
CAT_BUFF[0] = 0xB2;
CAT_BUFF[1] = 0xB2;
//break; case 0x69 : //FM Mic (#29) Contains 0-100 (decimal) as displayed
//CAT_BUFF[0] = 0x32;
//CAT_BUFF[1] = 0x32;
//break;
case 0x78 :
CAT_BUFF[0] = catGetMode();
// check, it must be a bit argument
if (CAT_BUFF[0] != 0) CAT_BUFF[0] = 1<<5;
break;
case 0x79 : //
//1-0 TX Power (All bands) 00 = High, 01 = L3, 10 = L2, 11 = L1
//3 PRI On/Off 0 = Off, 1 = On
//DW On/Off 0 = Off, 1 = On
//SCN (Scan) Mode 00 = No scan, 10 = Scan up, 11 = Scan down
//ART On/Off 0 = Off, 1 = On
CAT_BUFF[0] = 0x00;
CAT_BUFF[1] = 0x00;
break;
case 0x7A : //SPLIT
//7A 0 HF Antenna Select 0 = Front, 1 = Rear
//7A 1 6 M Antenna Select 0 = Front, 1 = Rear
//7A 2 FM BCB Antenna Select 0 = Front, 1 = Rear
//7A 3 Air Antenna Select 0 = Front, 1 = Rear
//7A 4 2 M Antenna Select 0 = Front, 1 = Rear
//7A 5 UHF Antenna Select 0 = Front, 1 = Rear
//7A 6 ? ?
//7A 7 SPL On/Off 0 = Off, 1 = On
CAT_BUFF[0] = (isSplitOn ? 0xFF : 0x7F);
break;
case 0xB3 : //
CAT_BUFF[0] = 0x00;
CAT_BUFF[1] = 0x4D;
break;
*/
}
// sent the data
SendCatData(2);
Serial.write(ACK);
}
void CatRxStatus(byte fromType)
{
byte sMeterValue = 1;
/*
http://www.ka7oei.com/ft817_meow.html
Command E7 - Read Receiver Status: This command returns one byte. Its contents are valid only when the '817 is in receive mode and it should be ignored when transmitting.
The lower 4 bits (0-3) of this byte indicate the current S-meter reading. 00 refers to an S-Zero reading, 04 = S4, 09 = S9, 0A = "10 over," 0B = "20 over" and so on up to 0F.
Bit 4 contains no useful information.
Bit 5 is 0 in non-FM modes, and it is 0 if the discriminator is centered (within 3.5 kHz for standard FM) when in the FM, FMN, or PKT modes, and 1 if the receiver is off-frequency.
Bit 6 is 0 if the CTCSS or DCS is turned off (or in a mode where it is not available.) It is also 0 if there is a signal being receive and the correct CTCSS tone or DCS code is being decoded.
It is 1 if there is a signal and the CTCSS/DCS decoding is enable, but the wrong CTCSS tone, DCS code, or no CTCSS/DCS is present.
Bit 7 is 0 if there is a signal present, or 1 if the receiver is squelched.
*/
// The lower 4 bits (0-3) of this byte indicate the current S-meter reading. 00 refers to an S-Zero reading, 04 = S4, 09 = S9, 0A = "10 over," 0B = "20 over" and so on up to 0F.
CAT_BUFF[0] = sMeterValue & 0b00001111;
SendCatData(1);
}
void CatTxStatus(byte fromType)
{
boolean isHighSWR = false;
boolean isSplitOn = false;
/*
Inverted -> *ptt = ((p->tx_status & 0x80) == 0); <-- souce code in ft817.c (hamlib)
*/
CAT_BUFF[0] = ((inTx ? 0 : 1) << 7) +
((isHighSWR ? 1 : 0) << 6) + //hi swr off / on
((isSplitOn ? 1 : 0) << 5) + //Split on / off
(0 << 4) + //dummy data
0x08; //P0 meter data
SendCatData(1);
}
unsigned long rxBufferArriveTime = 0;
byte rxBufferCheckCount = 0;
//Prevent Stack Overflow
byte isProcessCheck_Cat = 0;
//fromType normal : 0, TX : 1, CW_STRAIGHT : 2, CW_PADDLE : 3, CW_AUTOMODE : 4
//if cw mode, no delay
void Check_Cat(byte fromType)
{
byte i;
//Check Serial Port Buffer
if (Serial.available() == 0)
{
//Set Buffer Clear status
rxBufferCheckCount = 0;
return;
}
else if (Serial.available() < 5)
{
//First Arrived
if (rxBufferCheckCount == 0)
{
rxBufferCheckCount = Serial.available();
rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
}
else if (rxBufferArriveTime < millis()) //timeout
{
//Clear Buffer
for (i = 0; i < Serial.available(); i++)
rxBufferCheckCount = Serial.read();
rxBufferCheckCount = 0;
}
else if (rxBufferCheckCount < Serial.available()) //increase buffer count, slow arrived
{
rxBufferCheckCount = Serial.available();
rxBufferArriveTime = millis() + CAT_RECEIVE_TIMEOUT; //Set time for timeout
}
return;
}
//Arived CAT DATA
for (i = 0; i < 5; i++)
CAT_BUFF[i] = Serial.read();
if (isProcessCheck_Cat == 1)
return;
isProcessCheck_Cat = 1;
//reference : http://www.ka7oei.com/ft817_meow.html
switch(CAT_BUFF[4])
{
//The stability has not been verified and there seems to be no need. so i remarked codes,
//if you need, unmark lines
/*
case 0x00 : //Lock On
if (isDialLock == 1) //This command returns 00 if it was unlocked, and F0 if already locked.
CAT_BUFF[0] = 0xF0;
else {
CAT_BUFF[0] = 0x00;
setDialLock(1, fromType);
}
Serial.write(CAT_BUFF[0]); //Time
break;
case 0x80 : //Lock Off
if (isDialLock == 0) //This command returns 00 if the '817 was already locked, and F0 (HEX) if already unlocked.
CAT_BUFF[0] = 0xF0;
else {
CAT_BUFF[0] = 0x00;
setDialLock(0, fromType);
}
Serial.write(CAT_BUFF[0]); //Time
break;
*/
case 0x01 : //Set Frequency
CatSetFreq(fromType);
break;
case 0x02 : //Split On
case 0x82: //Split Off
CatSetSplit(CAT_BUFF[4] == 0x02, fromType);
break;
case 0x03 : //Read Frequency and mode
CatGetFreqMode(frequency, fromType);
break;
case 0x07 : //Set Operating Mode
CatSetMode(CAT_BUFF[0], fromType);
break;
case 0x08 : //Set PTT_ON
case 0x88: //Set PTT Off
CatSetPTT(CAT_BUFF[4] == 0x08, fromType);
break;
case 0x81: //Toggle VFO
CatVFOToggle(true, fromType);
break;
case 0xDB: //Read uBITX EEPROM Data
ReadEEPRom(fromType); //Call by uBITX Manager Program
break;
case 0xBB: //Read FT-817 EEPROM Data (for comfirtable)
ReadEEPRom_FT817(fromType);
break;
case 0xDC: //Write uBITX EEPROM Data
WriteEEPRom(fromType); //Call by uBITX Manager Program
break;
case 0xBC: //Write FT-817 EEPROM Data (for comfirtable)
WriteEEPRom_FT817(fromType);
break;
case 0xE7 : //Read RX Status
CatRxStatus(fromType);
break;
case 0xF7: //Read TX Status
CatTxStatus(fromType);
break;
default:
/*
char buff[16];
sprintf(buff, "DEFAULT : %x", CAT_BUFF[4]);
printLine2(buff);
*/
Serial.write(ACK);
break;
} //end of switch
isProcessCheck_Cat = 0;
}
void Init_Cat(long baud, int portConfig)
{
Serial.begin(baud, portConfig);
Serial.flush();
}
-406
View File
@@ -1,406 +0,0 @@
/*************************************************************************
This source code is written for All amateur radio operator,
I have not had amateur radio communication for a long time. CW has been
around for a long time, and I do not know what kind of keyer and keying
software is fashionable. So I implemented the functions I need mainly.
To minimize the use of memory space, we used bitwise operations.
For the alphabet, I put Morsecode in 1 byte. The front 4Bit is the length
and the 4Bit is the Morse code. Because the number is fixed in length,
there is no separate length information. The 5Bit on the right side is
the Morse code.
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
-----------------------------------------------------------------------------
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include <avr/pgmspace.h>
//27 + 10 + 18 + 1(SPACE) = //56
const PROGMEM uint8_t cwAZTable[27] = {0b00100100 , 0b01001000 , 0b01001010 , 0b00111000 , 0b00010000, 0b01000010, 0b00111100, 0b01000000 , //A ~ H
0b00100000, 0b01000111 ,0b00111010, 0b01000100, 0b00101100, 0b00101000 , 0b00111110, 0b01000110, 0b01001101, 0b00110100, //I ~ R
0b00110000, 0b00011000, 0b00110010, 0b01000001, 0b00110110, 0b01001001, 0b01001011, 0b00111000}; //S ~ Z
PGM_P pCwAZTable = reinterpret_cast<PGM_P>(cwAZTable);
const PROGMEM uint8_t cw09Table[27] = {0b00011111, 0b00001111, 0b00000111, 0b00000011, 0b00000001, 0b00000000, 0b00010000, 0b00011000, 0b00011100, 0b00011110};
PGM_P pcw09Table = reinterpret_cast<PGM_P>(cw09Table);
//# : AR, ~:BT, [:AS, ]:SK, ^:KN
const PROGMEM uint8_t cwSymbolIndex[] = {'.', ',', '?', '"', '!', '/', '(', ')', '&', ':', ';', '=', '+', '-', '_', '\'', '@', '#', '~', '[', ']', '^' };
PGM_P pCwSymbolIndex = reinterpret_cast<PGM_P>(cwSymbolIndex);
const PROGMEM uint8_t cwSymbolTable[] = {0b11010101, 0b11110011, 0b11001100, 0b11011110, 0b11101011, 0b10100100, 0b10101100, 0b11101101, 0b10010000, 0b11111000, 0b11101010, 0b10100010, 0b10010100, 0b11100001, 0b11001101, 0b11010010, 0b11011010, 0b10010100, 0b10100010, 0b10010000, 0b11000101, 0b10101100};
PGM_P pCwSymbolTable = reinterpret_cast<PGM_P>(cwSymbolTable);
////const PROGMEM uint8_t cwSymbolLength[] = {6, 6, 6, 6, 6, 5, 5, 6, 5, 6, 6, 5, 5, 6, 6, 6, 6, 5, 5, 5, 6, 5};
// ":(Start"), ':(End "), >: My callsign, <:QSO Callsign (Second Callsign), #:AR, ~:BT, [:AS, ]:SK
byte knobPosition = 0;
//byte cwTextData[30]; //Maximum 30 Remarked by KD8CE -> Direct Read EEPROM
byte autoCWSendCharEndIndex = 0;
byte autoCWSendCharIndex = 0;
unsigned long autoCWbeforeTime = 0; //for interval time between chars
byte pttBeforeStatus = 1; //PTT : default high
byte isKeyStatusAfterCWStart = 0; //0 : Init, 1 : Keyup after auto CW Start, 2 : Keydown after
byte selectedCWTextIndex = 0;
unsigned long autoCWKeydownCheckTime = 0; //for interval time between chars
byte changeReserveStatus = 0;
byte isAutoCWHold = 0; //auto CW Pause => Manual Keying => auto
void autoSendPTTCheck()
{
if (isCWAutoMode == 2) { //Sending Mode
//check PTT Button
//short Press => reservation or cancel
//long Press => Hold
if (digitalRead(PTT) == LOW)
{
//if (isKeyStatusAfterCWStart == 0) //Yet Press PTT from start TX
//{
//}
if (isKeyStatusAfterCWStart == 1) //while auto cw send, ptt up and ptt down again
{
//Start Time
autoCWKeydownCheckTime = millis() + 200; //Long push time
isKeyStatusAfterCWStart = 2; //Change status => ptt down agian
}
else if (isKeyStatusAfterCWStart == 2 && autoCWKeydownCheckTime < millis())
{
//Hold Mode
isAutoCWHold = 1;
isKeyStatusAfterCWStart = 3;
}
else if (isKeyStatusAfterCWStart == 3)
{
autoCWKeydownCheckTime = millis() + 200;
}
}
else
{
//PTT UP
if (isKeyStatusAfterCWStart == 2) //0 (down before cw start) -> 1 (up while cw sending) -> 2 (down while cw sending)
{
if (autoCWKeydownCheckTime > millis()) //Short : Reservation or cancel Next Text
{
if (autoCWSendReservCount == 0 ||
(autoCWSendReservCount < AUTO_CW_RESERVE_MAX &&
autoCWSendReserv[autoCWSendReservCount - 1] != selectedCWTextIndex))
{
//Reserve
autoCWSendReserv[autoCWSendReservCount++] = selectedCWTextIndex;
changeReserveStatus = 1;
}
else if (autoCWSendReservCount > 0 && autoCWSendReserv[autoCWSendReservCount - 1] == selectedCWTextIndex)
{
autoCWSendReservCount--;
changeReserveStatus = 1;
}
} // end of Short Key up
}
else if (isKeyStatusAfterCWStart == 3) //play from Hold (pause Auto CW Send)
{
isAutoCWHold = 0;
}
isKeyStatusAfterCWStart = 1; //Change status => ptt up (while cw send mode)
} //end of PTT UP
}
}
//Send 1 char
void sendCWChar(char cwKeyChar)
{
byte sendBuff[7];
byte i, j, charLength;
byte tmpChar;
//For Macrofunction
//replace > and < to My callsign, qso callsign, use recursive function call
if (cwKeyChar == '>' || cwKeyChar == '<')
{
uint16_t callsignStartIndex = 0;
uint16_t callsignEndIndex = 0;
if (cwKeyChar == '>') //replace my callsign
{
if (userCallsignLength > 0)
{
callsignStartIndex = 0;
callsignEndIndex = userCallsignLength;
}
}
else if (cwKeyChar == '<') //replace qso callsign
{
//ReadLength
callsignEndIndex = EEPROM.read(CW_STATION_LEN);
if (callsignEndIndex > 0)
{
callsignStartIndex = CW_STATION_LEN - callsignEndIndex - USER_CALLSIGN_DAT;
callsignEndIndex = callsignStartIndex + callsignEndIndex;
}
}
if (callsignStartIndex == 0 && callsignEndIndex == 0)
return;
for (uint16_t i = callsignStartIndex; i <= callsignEndIndex; i++)
{
sendCWChar(EEPROM.read(USER_CALLSIGN_DAT + i));
autoSendPTTCheck(); //for reserve and cancel next CW Text
if (changeReserveStatus == 1)
{
changeReserveStatus = 0;
updateDisplay();
}
if (i < callsignEndIndex) delay_background(cwSpeed * 3, 4); //
}
return;
}
else if (cwKeyChar >= 'A' && cwKeyChar <= 'Z') //Encode Char by KD8CEC
{
tmpChar = pgm_read_byte(pCwAZTable + (cwKeyChar - 'A'));
charLength = (tmpChar >> 4) & 0x0F;
for (i = 0; i < charLength; i++)
sendBuff[i] = (tmpChar << i) & 0x08;
}
else if (cwKeyChar >= '0' && cwKeyChar <= '9')
{
charLength = 5;
for (i = 0; i < charLength; i++)
sendBuff[i] = (pgm_read_byte(pcw09Table + (cwKeyChar - '0')) << i) & 0x10;
}
else if (cwKeyChar == ' ')
{
charLength = 0;
delay_background(cwSpeed * 4, 4); //7 -> basic interval is 3
}
else if (cwKeyChar == '$') //7 digit
{
charLength = 7;
for (i = 0; i < 7; i++)
sendBuff[i] = (0b00010010 << i) & 0x80; //...1..1
}
else
{
//symbol
for (i = 0; i < 22; i++)
{
if (pgm_read_byte(pCwSymbolIndex + i) == cwKeyChar)
{
tmpChar = pgm_read_byte(pCwSymbolTable + i);
charLength = ((tmpChar >> 6) & 0x03) + 3;
for (j = 0; j < charLength; j++)
sendBuff[j] = (tmpChar << j + 2) & 0x80;
break;
}
}
}
for (i = 0; i < charLength; i++)
{
cwKeydown();
if (sendBuff[i] == 0)
delay_background(cwSpeed, 4);
else
delay_background(cwSpeed * 3, 4);
cwKeyUp();
if (i != charLength -1)
delay_background(cwSpeed, 4);
}
}
/*
void sendAutoCW(int cwSendLength, char *sendString)
{
byte i;
if (!inTx){
keyDown = 0;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
delay_background(delayBeforeCWStartTime * 2, 2);
}
for (i = 0; i < cwSendLength; i++)
{
sendCWChar(sendString[i]);
if (i != cwSendLength -1) delay_background(cwSpeed * 3, 3);
}
delay_background(cwDelayTime * 10, 2);
stopTx();
}
*/
byte isNeedScroll = 0;
unsigned long scrollDispayTime = 0;
#define scrollSpeed 500
byte displayScrolStep = 0;
int controlAutoCW(){
int knob = 0;
byte i;
byte cwStartIndex, cwEndIndex;
if (cwAutoDialType == 0)
knob = enc_read();
if (knob != 0 || beforeCWTextIndex == 255 || isNeedScroll == 1){ //start display
if (knobPosition > 0 && knob < 0)
knobPosition--;
if (knobPosition < cwAutoTextCount * 10 -1 && knob > 0)
knobPosition++;
selectedCWTextIndex = knobPosition / 10;
if ((beforeCWTextIndex != selectedCWTextIndex) ||
(isNeedScroll == 1 && beforeCWTextIndex == selectedCWTextIndex && scrollDispayTime < millis())) {
//Read CW Text Data Position From EEProm
EEPROM.get(CW_AUTO_DATA + (selectedCWTextIndex * 2), cwStartIndex);
EEPROM.get(CW_AUTO_DATA + (selectedCWTextIndex * 2 + 1), cwEndIndex);
if (beforeCWTextIndex == selectedCWTextIndex)
{
if (++displayScrolStep > cwEndIndex - cwStartIndex)
displayScrolStep = 0;
}
else
{
displayScrolStep = 0;
}
printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ);
lcd.setCursor(0,0);
lcd.write(byteToChar(selectedCWTextIndex));
lcd.write(':');
isNeedScroll = (cwEndIndex - cwStartIndex) > 14 ? 1 : 0;
scrollDispayTime = millis() + scrollSpeed;
beforeCWTextIndex = selectedCWTextIndex;
}
} //end of check knob
if (isCWAutoMode == 1) { //ready status
if (digitalRead(PTT) == LOW) //PTT Down : Start Auto CW or DialMode Change
{
if (pttBeforeStatus == 1) //High to Low Change
{
autoCWbeforeTime = millis() + 500; //Long push time
pttBeforeStatus = 0;
}
else if (autoCWbeforeTime < millis()) //while press PTT, OK Long push then Send Auto CW Text
{
sendingCWTextIndex = selectedCWTextIndex;
//Information about Auto Send CW Text
autoCWSendCharEndIndex = cwEndIndex; //length of CW Text //ianlee
autoCWSendCharIndex = cwStartIndex; //position of Sending Char //ianlee
isCWAutoMode = 2; //auto sending start
autoCWbeforeTime = 0; //interval between chars, 0 = always send
isKeyStatusAfterCWStart = 0; //Init PTT Key status
autoCWSendReservCount = 0; //Init Reserve Count
isAutoCWHold = 0;
if (!inTx){ //if not TX Status, change RX -> TX
keyDown = 0;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
delay_background(delayBeforeCWStartTime * 2, 2); //for External AMP or personal situation
}
}
}
else if (pttBeforeStatus == 0 && autoCWbeforeTime > 0) //while reade status LOW -> HIGH (before Auto send Before)
{
pttBeforeStatus = 1; //HIGH
if (autoCWbeforeTime > millis()) //short Press -> ? DialModeChange
{
cwAutoDialType = (cwAutoDialType == 1 ? 0 : 1); //Invert DialMode between select CW Text and Frequency Tune
if (cwAutoDialType == 0)
printLineF1(F("Dial:Select Text"));
else
printLineF1(F("Dial:Freq Tune"));
delay_background(1000, 0);
updateDisplay();
}
}
} //end of isCWAutoMode == 1 condition
if (isCWAutoMode == 2) { //Sending Mode
autoSendPTTCheck();
//check interval time, if you want adjust interval between chars, modify below
if (isAutoCWHold == 0 && (millis() - autoCWbeforeTime > cwSpeed * 3))
{
sendCWChar(EEPROM.read(CW_AUTO_DATA + autoCWSendCharIndex++));
if (autoCWSendCharIndex > autoCWSendCharEndIndex) { //finish auto cw send
//check reserve status
if (autoCWSendReservCount > 0)
{
//prepare
sendingCWTextIndex = autoCWSendReserv[0];
for (i = 0; i < AUTO_CW_RESERVE_MAX -1; i++)
autoCWSendReserv[i] = autoCWSendReserv[i + 1];
EEPROM.get(CW_AUTO_DATA + (sendingCWTextIndex * 2), cwStartIndex);
EEPROM.get(CW_AUTO_DATA + (sendingCWTextIndex * 2 + 1), cwEndIndex);
//Information about Auto Send CW Text
autoCWSendCharEndIndex = cwEndIndex; //length of CW Text //ianlee
autoCWSendCharIndex = cwStartIndex; //position of Sending Char //ianlee
autoCWSendReservCount--; //Decrease
sendCWChar(' '); //APPLY SPACE between CW Texts
changeReserveStatus = 1;
}
else
{
isCWAutoMode = 1; //ready status
delay_background(cwDelayTime * 10, 2);
stopTx();
}
}
autoCWbeforeTime = millis();
if (changeReserveStatus == 1)
{
changeReserveStatus = 0;
updateDisplay();
}
}
}
//abort if this button is down
if (btnDown())
{
isCWAutoMode = 0; //dsiable Auto CW Mode
printLine2ClearAndUpdate();
delay_background(1000, 0);
}
}
-940
View File
@@ -1,940 +0,0 @@
/**
* 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>
/**
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.
We no longer use the standard SI5351 library because of its huge overhead due to many unused
features consuming a lot of program space. Instead of depending on an external library we now use
Jerry Gaffke's, KE7ER, lightweight standalone mimimalist "si5351bx" routines (see further down the
code). Here are some defines and declarations used by Jerry's routines:
*/
/**
* We need to carefully pick assignment of pin for various purposes.
* There are two sets of completely programmable pins on the Raduino.
* First, on the top of the board, in line with the LCD connector is an 8-pin connector
* that is largely meant for analog inputs and front-panel control. It has a regulated 5v output,
* ground and six pins. Each of these six pins can be individually programmed
* either as an analog input, a digital input or a digital output.
* The pins are assigned as follows (left to right, display facing you):
* Pin 1 (Violet), A7, SPARE
* Pin 2 (Blue), A6, KEYER (DATA)
* Pin 3 (Green), +5v
* Pin 4 (Yellow), Gnd
* Pin 5 (Orange), A3, PTT
* Pin 6 (Red), A2, F BUTTON
* Pin 7 (Brown), A1, ENC B
* Pin 8 (Black), A0, ENC A
*Note: A5, A4 are wired to the Si5351 as I2C interface
* *
* Though, this can be assigned anyway, for this application of the Arduino, we will make the following
* assignment
* A2 will connect to the PTT line, which is the usually a part of the mic connector
* A3 is connected to a push button that can momentarily ground this line. This will be used for RIT/Bandswitching, etc.
* A6 is to implement a keyer, it is reserved and not yet implemented
* A7 is connected to a center pin of good quality 100K or 10K linear potentiometer with the two other ends connected to
* ground and +5v lines available on the connector. This implments the tuning mechanism
*/
#define ENC_A (A0)
#define ENC_B (A1)
#define FBUTTON (A2)
#define PTT (A3)
#define ANALOG_KEYER (A6)
#define ANALOG_SPARE (A7)
/**
* The Raduino board is the size of a standard 16x2 LCD panel. It has three connectors:
*
* First, is an 8 pin connector that provides +5v, GND and six analog input pins that can also be
* configured to be used as digital input or output pins. These are referred to as A0,A1,A2,
* A3,A6 and A7 pins. The A4 and A5 pins are missing from this connector as they are used to
* talk to the Si5351 over I2C protocol.
*
* Second is a 16 pin LCD connector. This connector is meant specifically for the standard 16x2
* LCD display in 4 bit mode. The 4 bit mode requires 4 data lines and two control lines to work:
* Lines used are : RESET, ENABLE, D4, D5, D6, D7
* We include the library and declare the configuration of the LCD panel too
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(8,9,10,11,12,13);
#define VERSION_NUM 0x01 //for KD8CEC'S firmware and for memory management software
/**
* The Arduino, unlike C/C++ on a regular computer with gigabytes of RAM, has very little memory.
* We have to be very careful with variables that are declared inside the functions as they are
* created in a memory region called the stack. The stack has just a few bytes of space on the Arduino
* if you declare large strings inside functions, they can easily exceed the capacity of the stack
* and mess up your programs.
* We circumvent this by declaring a few global buffers as kitchen counters where we can
* slice and dice our strings. These strings are mostly used to control the display or handle
* the input and output from the USB port. We must keep a count of the bytes used while reading
* the serial port as we can easily run out of buffer space. This is done in the serial_in_count variable.
*/
char c[30], b[30];
char printBuff[2][17]; //mirrors what is showing on the two lines of the display
int count = 0; //to generally count ticks, loops, etc
/**
* The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
* This assignment is as follows :
* Pin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
* GND +5V CLK0 GND GND CLK1 GND GND CLK2 GND D2 D3 D4 D5 D6 D7
* These too are flexible with what you may do with them, for the Raduino, we use them to :
* - TX_RX line : Switches between Transmit and Receive after sensing the PTT or the morse keyer
* - CW_KEY line : turns on the carrier for CW
*/
#define TX_RX (7)
#define CW_TONE (6)
#define TX_LPF_A (5)
#define TX_LPF_B (4)
#define TX_LPF_C (3)
#define CW_KEY (2)
/**
* These are the indices where these user changable settinngs are stored in the EEPROM
*/
#define MASTER_CAL 0
#define LSB_CAL 4
#define USB_CAL 8
#define SIDE_TONE 12
//these are ids of the vfos as well as their offset into the eeprom storage, don't change these 'magic' values
#define VFO_A 16
#define VFO_B 20
#define CW_SIDETONE 24
#define CW_SPEED 28
//AT328 has 1KBytes EEPROM
#define VFO_A_MODE 256
#define VFO_B_MODE 257
#define CW_DELAY 258
#define CW_START 259
#define HAM_BAND_COUNT 260 //
#define TX_TUNE_TYPE 261 //
#define HAM_BAND_RANGE 262 //FROM (2BYTE) TO (2BYTE) * 10 = 40byte
#define HAM_BAND_FREQS 302 //40, 1 BAND = 4Byte most bit is mode
//Check Firmware type and version
#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.
#define VERSION_ADDRESS 779 //check Firmware version
//USER INFORMATION
#define USER_CALLSIGN_KEY 780 //0x59
#define USER_CALLSIGN_LEN 781 //1BYTE (OPTION + LENGTH) + CALLSIGN (MAXIMUM 18)
#define USER_CALLSIGN_DAT 782 //CALL SIGN DATA //direct EEPROM to LCD basic offset
//AUTO KEY STRUCTURE
//AUTO KEY USE 800 ~ 1023
#define CW_AUTO_MAGIC_KEY 800 //0x73
#define CW_AUTO_COUNT 801 //0 ~ 255
#define CW_AUTO_DATA 803 //[INDEX, INDEX, INDEX,DATA,DATA, DATA (Positon offset is CW_AUTO_DATA
#define CW_DATA_OFSTADJ CW_AUTO_DATA - USER_CALLSIGN_DAT //offset adjust for ditect eeprom to lcd (basic offset is USER_CALLSIGN_DAT
#define CW_STATION_LEN 1023 //value range : 4 ~ 30
/**
* 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)
//When the frequency is moved by the dial, the maximum value by KD8CEC
#define LOWEST_FREQ_DIAL (3000l)
#define HIGHEST_FREQ_DIAL (60000000l)
//we directly generate the CW by programmin the Si5351 to the cw tx frequency, hence, both are different modes
//these are the parameter passed to startTx
#define TX_SSB 0
#define TX_CW 1
char ritOn = 0;
char vfoActive = VFO_A;
int8_t meter_reading = 0; // a -1 on meter makes it invisible
unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier;
unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
int cwSpeed = 100; //this is actuall the dot period in milliseconds
extern int32_t calibration;
//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;
bool isSplitOn = false;
byte cwDelayTime = 60;
byte delayBeforeCWStartTime = 50;
//sideTonePitch + sideToneSub = sideTone
byte sideTonePitch=0;
byte sideToneSub = 0;
//DialLock
byte isDialLock = 0; //000000[0]vfoB [0]vfoA 0Bit : A, 1Bit : B
byte isTxType = 0; //000000[0 - isSplit] [0 - isTXStop]
//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)
char splitOn = 0; //working split, uses VFO B as the transmit frequency, (NOT IMPLEMENTED YET)
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
//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
/**
* Below are the basic functions that control the uBitx. Understanding the functions before
* you start hacking around
*/
//Ham Band
#define MAX_LIMIT_RANGE 10 //because limited eeprom size
byte useHamBandCount = 0; //0 use full range frequency
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))
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);
loadMode = (byte)(resultFreq >> 30);
resultFreq = resultFreq & 0x3FFFFFFF;
if ((resultFreq / 1000) < hamBandRange[findedIndex][0] || (resultFreq / 1000) > hamBandRange[findedIndex][1])
resultFreq = (unsigned long)(hamBandRange[findedIndex][0]) * 1000;
setFrequency(resultFreq);
byteWithFreqToMode(loadMode);
}
void saveBandFreqByIndex(unsigned long f, unsigned long mode, char bandIndex) {
if (bandIndex >= 0)
EEPROM.put(HAM_BAND_FREQS + 4 * bandIndex, (f & 0x3FFFFFFF) | (mode << 30) );
}
/*
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();
while (millis() - delayBeforeTime <= delayTime) {
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){
uint64_t osc_f;
//1 digits discarded
f = (f / 50) * 50;
setTXFilters(f);
if (isUSB){
si5351bx_setfreq(2, SECOND_OSC_USB - usbCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_USB);
}
else{
si5351bx_setfreq(2, SECOND_OSC_LSB + usbCarrier + f);
si5351bx_setfreq(1, SECOND_OSC_LSB);
}
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
*/
void startTx(byte txMode, byte isDisplayUpdate){
unsigned long tx_freq = 0;
//Check Hamband only TX //Not found Hamband index by now frequency
if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) {
//no message
return;
}
if ((isTxType & 0x01) != 0x01)
digitalWrite(TX_RX, 1);
inTx = 1;
if (ritOn){
//save the current as the rx frequency
ritRxFrequency = frequency;
setFrequency(ritTxFrequency);
}
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
if (isUSB)
si5351bx_setfreq(2, frequency + sideTone);
else
si5351bx_setfreq(2, frequency - sideTone);
}
//reduce latency time when begin of CW mode
if (isDisplayUpdate == 1)
updateDisplay();
}
void stopTx(){
inTx = 0;
digitalWrite(TX_RX, 0); //turn off the tx
si5351bx_setfreq(0, usbCarrier); //set back the carrier oscillator anyway, cw tx switches it off
if (ritOn)
setFrequency(ritRxFrequency);
else
setFrequency(frequency);
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){
startTx(TX_SSB, 1);
delay(50); //debounce the PTT
}
if (digitalRead(PTT) == 1 && inTx == 1)
stopTx();
}
void checkButton(){
int i, t1, t2, knob, new_knob;
//only if the button is pressed
if (!btnDown())
return;
delay(50);
if (!btnDown()) //debounce
return;
doMenu();
//wait for the button to go up again
while(btnDown()) {
delay(10);
Check_Cat(0);
}
delay(50);//debounce
}
/**
* The tuning jumps by 50 Hz on each step when you tune slowly
* As you spin the encoder faster, the jump size also increases
* This way, you can quickly move to another band by just spinning the
* tuning knob
*/
void doTuning(){
int s = 0;
unsigned long prev_freq;
int incdecValue = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02)))
return;
if (isCWAutoMode == 0 || cwAutoDialType == 1)
s = enc_read();
if (s){
prev_freq = frequency;
if (s > 10)
incdecValue = 200000l;
if (s > 7)
incdecValue = 10000l;
else if (s > 4)
incdecValue = 1000l;
else if (s > 2)
incdecValue = 500;
else if (s > 0)
incdecValue = 50l;
else if (s > -2)
incdecValue = -50l;
else if (s > -4)
incdecValue = -500l;
else if (s > -7)
incdecValue = -1000l;
else if (s > -9)
incdecValue = -10000l;
else
incdecValue = -200000l;
if (incdecValue > 0 && frequency + incdecValue > HIGHEST_FREQ_DIAL)
frequency = HIGHEST_FREQ_DIAL;
else if (incdecValue < 0 && frequency < -incdecValue + LOWEST_FREQ_DIAL) //for compute and compare based integer type.
frequency = LOWEST_FREQ_DIAL;
else
frequency += incdecValue;
if (prev_freq < 10000000l && frequency > 10000000l)
isUSB = true;
if (prev_freq > 10000000l && frequency < 10000000l)
isUSB = false;
setFrequency(frequency);
updateDisplay();
}
}
/**
* RIT only steps back and forth by 100 hz at a time
*/
void doRIT(){
unsigned long newFreq;
int knob = enc_read();
unsigned long old_freq = frequency;
if (knob < 0)
frequency -= 100l;
else if (knob > 0)
frequency += 100;
if (old_freq != frequency){
setFrequency(frequency);
updateDisplay();
}
}
/**
save Frequency and mode to eeprom
*/
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;
}
}
}
/**
* 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
//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);
//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 = 32; i < 1024; i++) //protect Master_cal, usb_cal
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) != VERSION_NUM)
EEPROM.write(VERSION_ADDRESS, VERSION_NUM);
//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);
//User callsign information
if (EEPROM.read(USER_CALLSIGN_KEY) == 0x59)
userCallsignLength = EEPROM.read(USER_CALLSIGN_LEN); //MAXIMUM 18 LENGTH
//Ham Band Count
EEPROM.get(HAM_BAND_COUNT, useHamBandCount);
EEPROM.get(TX_TUNE_TYPE, tuneTXType);
if ((3 < tuneTXType && tuneTXType < 100) || 103 < tuneTXType || useHamBandCount < 1)
tuneTXType = 0;
//Read band Information
for (byte i = 0; i < useHamBandCount; i++) {
unsigned int tmpReadValue = 0;
EEPROM.get(HAM_BAND_RANGE + 4 * i, tmpReadValue);
hamBandRange[i][0] = tmpReadValue;
EEPROM.get(HAM_BAND_RANGE + 4 * i + 2, tmpReadValue);
hamBandRange[i][1] = tmpReadValue;
}
if (cwDelayTime < 1 || cwDelayTime > 250)
cwDelayTime = 60;
if (vfoA_mode < 2)
vfoA_mode = 2;
if (vfoB_mode < 2)
vfoB_mode = 3;
if (usbCarrier > 12010000l || usbCarrier < 11990000l)
usbCarrier = 11995000l;
if (vfoA > 35000000l || 3500000l > vfoA) {
vfoA = 7150000l;
vfoA_mode = 2;
}
if (vfoB > 35000000l || 3500000l > vfoB) {
vfoB = 14150000l;
vfoB_mode = 3;
}
//for protect eeprom life
vfoA_eeprom = vfoA;
vfoB_eeprom = vfoB;
vfoA_mode_eeprom = vfoA_mode;
vfoB_mode_eeprom = vfoB_mode;
if (sideTone < 100 || 2000 < sideTone)
sideTone = 800;
if (cwSpeed < 10 || 1000 < cwSpeed)
cwSpeed = 100;
if (sideTone < 300 || sideTone > 1000) {
sideTonePitch = 0;
sideToneSub = 0;;
}
else{
sideTonePitch = (sideTone - 300) / 50;
sideToneSub = sideTone % 50;
}
}
void initPorts(){
analogReference(DEFAULT);
//??
pinMode(ENC_A, INPUT_PULLUP);
pinMode(ENC_B, INPUT_PULLUP);
pinMode(FBUTTON, INPUT_PULLUP);
//configure the function button to use the external pull-up
// pinMode(FBUTTON, INPUT);
// digitalWrite(FBUTTON, HIGH);
pinMode(PTT, INPUT_PULLUP);
pinMode(ANALOG_KEYER, INPUT_PULLUP);
pinMode(CW_TONE, OUTPUT);
digitalWrite(CW_TONE, 0);
pinMode(TX_RX,OUTPUT);
digitalWrite(TX_RX, 0);
pinMode(TX_LPF_A, OUTPUT);
pinMode(TX_LPF_B, OUTPUT);
pinMode(TX_LPF_C, OUTPUT);
digitalWrite(TX_LPF_A, 0);
digitalWrite(TX_LPF_B, 0);
digitalWrite(TX_LPF_C, 0);
pinMode(CW_KEY, OUTPUT);
digitalWrite(CW_KEY, 0);
}
void setup()
{
/*
//Init EEProm for Fault EEProm TEST and Factory Reset
//please remove remark for others.
//for (int i = 0; i < 1024; i++)
for (int i = 16; i < 1024; i++) //protect Master_cal, usb_cal
EEPROM.write(i, 0xFF);
lcd.begin(16, 2);
printLineF(1, F("Complete Erase"));
sleep(1000);
//while(1);
//end section of test
*/
//Serial.begin(9600);
lcd.begin(16, 2);
printLineF(1, F("CECBT v0.27"));
Init_Cat(38400, SERIAL_8N1);
initMeter(); //not used in this build
initSettings();
if (userCallsignLength > 0 && ((userCallsignLength & 0x80) == 0x80)) {
userCallsignLength = userCallsignLength & 0x7F;
printLineFromEEPRom(0, 0, 0, userCallsignLength -1); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
delay(500);
}
else {
printLineF(0, F("uBITX v0.20"));
delay(500);
printLine2("");
}
initPorts();
initOscillators();
frequency = vfoA;
saveCheckFreq = frequency; //for auto save frequency
byteToMode(vfoA_mode);
setFrequency(vfoA);
updateDisplay();
if (btnDown())
factory_alignment();
}
/**
* The loop checks for keydown, ptt, function button and tuning.
*/
//for debug
int dbgCnt = 0;
byte flasher = 0;
void checkAutoSaveFreqMode()
{
//when tx or ritOn, disable auto save
if (inTx || ritOn)
return;
//detect change frequency
if (saveCheckFreq != frequency)
{
saveCheckTime = millis();
saveCheckFreq = frequency;
}
else if (saveCheckTime != 0)
{
//check time for Frequency auto save
if (millis() - saveCheckTime > saveIntervalSec * 1000)
{
if (vfoActive == VFO_A)
{
vfoA = frequency;
vfoA_mode = modeToByte();
storeFrequencyAndMode(1);
}
else
{
vfoB = frequency;
vfoB_mode = modeToByte();
storeFrequencyAndMode(2);
}
}
}
}
void loop(){
if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
if (!txCAT)
checkPTT();
checkButton();
}
else
controlAutoCW();
cwKeyer();
//tune only when not tranmsitting
if (!inTx){
if (ritOn)
doRIT();
else
doTuning();
}
//we check CAT after the encoder as it might put the radio into TX
Check_Cat(inTx? 1 : 0);
checkAutoSaveFreqMode();
}
-87
View File
@@ -1,87 +0,0 @@
/**
* This procedure is only for those who have a signal generator/transceiver tuned to exactly 7.150 and a dummy load
*/
void btnWaitForClick(){
while(!btnDown())
delay(50);
while(btnDown())
delay(50);
delay(50);
}
void factory_alignment(){
factoryCalibration(1);
if (calibration == 0){
printLine2("Setup Aborted");
return;
}
//move it away to 7.160 for an LSB signal
setFrequency(7160000l);
updateDisplay();
printLine2("#2 BFO");
delay(1000);
usbCarrier = 11994999l;
menuSetupCarrier(1);
if (usbCarrier == 11994999l){
printLine2("Setup Aborted");
return;
}
printLine2("#3:Test 3.5MHz");
isUSB = false;
setFrequency(3500000l);
updateDisplay();
while (!btnDown()){
checkPTT();
delay(100);
}
btnWaitForClick();
printLine2("#4:Test 7MHz");
setFrequency(7150000l);
updateDisplay();
while (!btnDown()){
checkPTT();
delay(100);
}
btnWaitForClick();
printLine2("#5:Test 14MHz");
isUSB = true;
setFrequency(14000000l);
updateDisplay();
while (!btnDown()){
checkPTT();
delay(100);
}
btnWaitForClick();
printLine2("#6:Test 28MHz");
setFrequency(28000000l);
updateDisplay();
while (!btnDown()){
checkPTT();
delay(100);
}
printLine2("Alignment done");
delay(1000);
isUSB = false;
setFrequency(7150000l);
updateDisplay();
}
-186
View File
@@ -1,186 +0,0 @@
/**
* CW Keyer
*
* The CW keyer handles either a straight key or an iambic / paddle key.
* They all use just one analog input line. This is how it works.
* The analog line has the internal pull-up resistor enabled.
* When a straight key is connected, it shorts the pull-up resistor, analog input is 0 volts
* When a paddle is connected, the dot and the dash are connected to the analog pin through
* a 10K and a 2.2K resistors. These produce a 4v and a 2v input to the analog pins.
* So, the readings are as follows :
* 0v - straight key
* 1-2.5 v - paddle dot
* 2.5 to 4.5 v - paddle dash
* 2.0 to 0.5 v - dot and dash pressed
*
* The keyer is written to transparently handle all these cases
*
* Generating CW
* The CW is cleanly generated by unbalancing the front-end mixer
* and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control
*/
// in milliseconds, this is the parameter that determines how long the tx will hold between cw key downs
//#define CW_TIMEOUT (600l) //Change to CW Delaytime for value save to eeprom
#define PADDLE_DOT 1
#define PADDLE_DASH 2
#define PADDLE_BOTH 3
#define PADDLE_STRAIGHT 4
//we store the last padde's character
//to alternatively send dots and dashes
//when both are simultaneously pressed
char lastPaddle = 0;
//reads the analog keyer pin and reports the paddle
byte getPaddle(){
int paddle = analogRead(ANALOG_KEYER);
if (paddle > 800) // above 4v is up
return 0;
if (paddle > 600) // 4-3v is dot
return PADDLE_DASH;
else if (paddle > 300) //1-2v is dash
return PADDLE_DOT;
else if (paddle > 50)
return PADDLE_BOTH; //both are between 1 and 2v
else
return PADDLE_STRAIGHT; //less than 1v is the straight key
}
/**
* Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future
*/
void cwKeydown(){
keyDown = 1; //tracks the CW_KEY
tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* Stops the cw carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future
*/
void cwKeyUp(){
keyDown = 0; //tracks the CW_KEY
noTone(CW_TONE);
digitalWrite(CW_KEY, 0);
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
}
/**
* The keyer handles the straight key as well as the iambic key
* This module keeps looping until the user stops sending cw
* if the cwTimeout is set to 0, then it means, we have to exit the keyer loop
* Each time the key is hit the cwTimeout is pushed to a time in the future by cwKeyDown()
*/
void cwKeyer(){
byte paddle;
lastPaddle = 0;
while(1){
paddle = getPaddle();
// do nothing if the paddle has not been touched, unless
// we are in the cw mode and we have timed out
if (!paddle){
//modifed by KD8CEC for auto CW Send
if (isCWAutoMode > 1) //if while auto cw sending, dont stop tx by paddle position
return;
if (0 < cwTimeout && cwTimeout < millis()){
cwTimeout = 0;
keyDown = 0;
stopTx();
}
if (!cwTimeout)
return;
//if a paddle was used (not a straight key) we should extend the space to be a full dash
//by adding two more dots long space (one has already been added at the end of the dot or dash)
/*
if (cwTimeout > 0 && lastPaddle != PADDLE_STRAIGHT)
delay_background(cwSpeed * 2, 3);
//delay(cwSpeed * 2);
// got back to the begining of the loop, if no further activity happens on the paddle or the straight key
// we will time out, and return out of this routine
delay(5);
*/
continue;
}
//if while auto cw send, stop auto cw
//but isAutoCWHold for Manual Keying with cwAutoSend
if (isCWAutoMode > 1 && isAutoCWHold == 0)
isCWAutoMode = 1; //read status
//Remoark Debug code / Serial Use by CAT Protocol
//Serial.print("paddle:");Serial.println(paddle);
// if we are here, it is only because the key or the paddle is pressed
if (!inTx){
keyDown = 0;
//Modified by KD8CEC, for CW Delay Time save to eeprom
//cwTimeout = millis() + CW_TIMEOUT;
cwTimeout = millis() + cwDelayTime * 10;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay();
//DelayTime Option
delay_background(delayBeforeCWStartTime * 2, 2);
}
// star the transmission)
// we store the transmitted character in the lastPaddle
cwKeydown();
if (paddle == PADDLE_DOT){
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
else if (paddle == PADDLE_DASH){
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}
else if (paddle == PADDLE_BOTH){ //both paddles down
//depending upon what was sent last, send the other
if (lastPaddle == PADDLE_DOT) {
//delay(cwSpeed * 3);
delay_background(cwSpeed * 3, 3);
lastPaddle = PADDLE_DASH;
}else{
//delay(cwSpeed);
delay_background(cwSpeed, 3);
lastPaddle = PADDLE_DOT;
}
}
else if (paddle == PADDLE_STRAIGHT){
while (getPaddle() == PADDLE_STRAIGHT) {
delay(1);
Check_Cat(2);
}
lastPaddle = PADDLE_STRAIGHT;
}
cwKeyUp();
//introduce a dot long gap between characters if the keyer was used
if (lastPaddle != PADDLE_STRAIGHT)
delay(cwSpeed);
}
}
-843
View File
@@ -1,843 +0,0 @@
/** Menus
* The Radio menus are accessed by tapping on the function button.
* - The main loop() constantly looks for a button press and calls doMenu() when it detects
* a function button press.
* - As the encoder is rotated, at every 10th pulse, the next or the previous menu
* item is displayed. Each menu item is controlled by it's own function.
* - Eache menu function may be called to display itself
* - Each of these menu routines is called with a button parameter.
* - The btn flag denotes if the menu itme was clicked on or not.
* - If the menu item is clicked on, then it is selected,
* - If the menu item is NOT clicked on, then the menu's prompt is to be displayed
*/
#define printLineF1(x) (printLineF(1, x))
#define printLineF2(x) (printLineF(0, x))
int menuBand(int btn){
int knob = 0;
int stepChangeCount = 0;
byte btnPressCount = 0;
if (!btn){
printLineF2(F("Band Select?"));
return;
}
printLineF2(F("Press to confirm"));
//wait for the button menu select button to be lifted)
while (btnDown()) {
delay(50);
Check_Cat(0); //To prevent disconnections
if (btnPressCount++ > 20) {
btnPressCount = 0;
if (tuneTXType > 0) { //Just toggle 0 <-> 2, if tuneTXType is 100, 100 -> 0 -> 2
tuneTXType = 0;
printLineF2(F("Full range mode"));
}
else {
tuneTXType = 2;
//if empty band Information, auto insert default region 1 frequency range
//This part is made temporary for people who have difficulty setting up, so can remove it when you run out of memory.
if (useHamBandCount < 1) {
useHamBandCount = 10;
hamBandRange[0][0] = 1810; hamBandRange[0][1] = 2000;
hamBandRange[1][0] = 3500; hamBandRange[1][1] = 3800;
hamBandRange[2][0] = 5351; hamBandRange[2][1] = 5367;
hamBandRange[3][0] = 7000; hamBandRange[3][1] = 7200;
hamBandRange[4][0] = 10100; hamBandRange[4][1] = 10150;
hamBandRange[5][0] = 14000; hamBandRange[5][1] = 14350;
hamBandRange[6][0] = 18068; hamBandRange[6][1] = 18168;
hamBandRange[7][0] = 21000; hamBandRange[7][1] = 21450;
hamBandRange[8][0] = 24890; hamBandRange[8][1] = 24990;
hamBandRange[9][0] = 28000; hamBandRange[9][1] = 29700;
}
printLineF2(F("Ham band mode"));
}
delay_background(1000, 0);
printLine2ClearAndUpdate();
printLineF2(F("Press to confirm"));
}
}
char currentBandIndex = -1;
//Save Band Information
if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move
//Get Now Band Index
currentBandIndex = getIndexHambanBbyFreq(frequency);
if (currentBandIndex >= 0) {
//Save Frequency to Band Frequncy Record
saveBandFreqByIndex(frequency, modeToByte(), currentBandIndex);
}
}
delay(50);
ritDisable();
while(!btnDown()){
knob = enc_read();
if (knob != 0){
/*
if (band > 3 && knob < 0)
band--;
if (band < 30 && knob > 0)
band++;
if (band > 10)
isUSB = true;
else
isUSB = false;
setFrequency(((unsigned long)band * 1000000l) + offset); */
if (tuneTXType == 2 || tuneTXType == 3 || tuneTXType == 102 || tuneTXType == 103) { //only ham band move
if (knob < 0) {
if (stepChangeCount-- < -3) {
setNextHamBandFreq(frequency, -1); //Prior Band
stepChangeCount = 0;
}
}
else if (knob > 0) {
if (stepChangeCount++ > 3) {
setNextHamBandFreq(frequency, 1); //Next Band
stepChangeCount = 0;
}
}
}
else { //original source
if (knob < 0 && frequency > 3000000l)
setFrequency(frequency - 200000l);
if (knob > 0 && frequency < 30000000l)
setFrequency(frequency + 200000l);
if (frequency > 10000000l)
isUSB = true;
else
isUSB = false;
}
updateDisplay();
}
delay(20);
Check_Cat(0); //To prevent disconnections
}
while(btnDown()) {
delay(50);
Check_Cat(0); //To prevent disconnections
}
delay(50);
printLine2ClearAndUpdate();
menuOn = 0;
}
//0: default, 1:not use, 2:LSB, 3:USB, 4:CW, 5:AM, 6:FM
byte modeToByte(){
if (isUSB)
return 3;
else
return 2;
}
void byteToMode(byte modeValue){
if (modeValue == 3)
isUSB = 1;
else
isUSB = 0;
}
void byteWithFreqToMode(byte modeValue){
if (modeValue == 3)
isUSB = 1;
else if (modeValue == 0) //Not Set
isUSB = (frequency > 10000000l) ? true : false;
else
isUSB = 0;
}
void menuVfoToggle(int btn, char isUseDelayTime)
{
if (!btn){
if (vfoActive == VFO_A)
printLineF2(F("Select VFO B?"));
else
printLineF2(F("Select VFO A?"));
}
else {
if (vfoActive == VFO_B){
vfoB = frequency;
vfoB_mode = modeToByte();
storeFrequencyAndMode(2); //vfoB -> eeprom
vfoActive = VFO_A;
frequency = vfoA;
saveCheckFreq = frequency;
byteToMode(vfoA_mode);
printLineF2(F("Selected VFO A"));
}
else {
vfoA = frequency;
vfoA_mode = modeToByte();
storeFrequencyAndMode(1); //vfoA -> eeprom
vfoActive = VFO_B;
frequency = vfoB;
saveCheckFreq = frequency;
byteToMode(vfoB_mode);
printLineF2(F("Selected VFO B"));
}
ritDisable();
if (isUseDelayTime == 1) //Found Issue in wsjt-x Linux 32bit
delay_background(500, 0);
printLine2ClearAndUpdate();
//exit the menu
menuOn = 0;
}
}
void menuRitToggle(int btn){
if (!btn){
if (ritOn == 1)
printLineF2(F("RIT:On, Off?"));
else
printLineF2(F("RIT:Off, On?"));
}
else {
if (ritOn == 0){
printLineF2(F("RIT is ON"));
//enable RIT so the current frequency is used at transmit
ritEnable(frequency);
}
else{
printLineF2(F("RIT is OFF"));
ritDisable();
}
menuOn = 0;
delay_background(500, 0);
printLine2ClearAndUpdate();
}
}
void menuSidebandToggle(int btn){
if (!btn){
if (isUSB == true)
printLineF2(F("Select LSB?"));
else
printLineF2(F("Select USB?"));
}
else {
if (isUSB == true){
isUSB = false;
printLineF2(F("LSB Selected"));
}
else {
isUSB = true;
printLineF2(F("USB Selected"));
}
setFrequency(frequency);
delay_background(500, 0);
printLine2ClearAndUpdate();
menuOn = 0;
}
}
void menuTxOnOff(int btn, byte optionType){
if (!btn){
if ((isTxType & optionType) == 0)
printLineF2(F("TX OFF?"));
else
printLineF2(F("TX ON?"));
}
else {
if ((isTxType & optionType) == 0){
isTxType |= optionType;
printLineF2(F("TX OFF!"));
}
else {
isTxType &= ~(optionType);
printLineF2(F("TX ON!"));
}
delay_background(500, 0);
printLine2ClearAndUpdate();
menuOn = 0;
}
}
/**
* The calibration routines are not normally shown in the menu as they are rarely used
* They can be enabled by choosing this menu option
*/
void menuSetup(int btn){
if (!btn){
if (!modeCalibrate)
printLineF2(F("Setup On?"));
else
printLineF2(F("Setup Off?"));
}else {
if (!modeCalibrate){
modeCalibrate = true;
printLineF2(F("Setup:On"));
}
else {
modeCalibrate = false;
printLineF2(F("Setup:Off"));
}
delay_background(2000, 0);
printLine2Clear();
menuOn = 0;
}
}
void menuExit(int btn){
if (!btn){
printLineF2(F("Exit Menu?"));
}
else{
printLine2ClearAndUpdate();
menuOn = 0;
}
}
int menuCWSpeed(int btn){
int knob = 0;
int wpm;
wpm = 1200/cwSpeed;
if (!btn){
strcpy(b, "CW:");
itoa(wpm,c, 10);
strcat(b, c);
strcat(b, "WPM Change?");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "WPM:");
itoa(wpm,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (wpm > 3 && knob < 0)
wpm--;
if (wpm < 50 && knob > 0)
wpm++;
strcpy(b, "WPM:");
itoa(wpm,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
//re-enable the clock1 and clock 2
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Speed set!"));
cwSpeed = 1200/wpm;
EEPROM.put(CW_SPEED, cwSpeed);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
int menuCWAutoKey(int btn){
if (!btn){
printLineF2(F("CW AutoKey Mode?"));
return;
}
//Check CW_AUTO_MAGIC_KEY and CW Text Count
EEPROM.get(CW_AUTO_COUNT, cwAutoTextCount);
if (EEPROM.read(CW_AUTO_MAGIC_KEY) != 0x73 || cwAutoTextCount < 1)
{
printLineF2(F("Empty CW data"));
delay_background(2000, 0);
return;
}
printLineF1(F("Press PTT to Send"));
delay_background(500, 0);
updateDisplay();
beforeCWTextIndex = 255; //255 value is for start check
isCWAutoMode = 1;
menuOn = 0;
}
int menuSetupCwDelay(int btn){
int knob = 0;
int tmpCWDelay = cwDelayTime * 10;
if (!btn){
strcpy(b, "CW TX->RX Delay");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "DELAY:");
itoa(tmpCWDelay,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (tmpCWDelay > 3 && knob < 0)
tmpCWDelay -= 10;
if (tmpCWDelay < 2500 && knob > 0)
tmpCWDelay += 10;
strcpy(b, "DELAY:");
itoa(tmpCWDelay,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Delay set!"));
cwDelayTime = tmpCWDelay / 10;
EEPROM.put(CW_DELAY, cwDelayTime);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
int menuSetupTXCWInterval(int btn){
int knob = 0;
int tmpTXCWInterval = delayBeforeCWStartTime * 2;
if (!btn){
strcpy(b, "CW Start Delay");
printLine2(b);
return;
}
printLineF1(F("Press PTT to set"));
strcpy(b, "Start Delay:");
itoa(tmpTXCWInterval,c, 10);
strcat(b, c);
printLine2(b);
delay_background(300, 0);
while(!btnDown() && digitalRead(PTT) == HIGH){
knob = enc_read();
if (knob != 0){
if (tmpTXCWInterval > 0 && knob < 0)
tmpTXCWInterval -= 2;
if (tmpTXCWInterval < 500 && knob > 0)
tmpTXCWInterval += 2;
strcpy(b, "Start Delay:");
itoa(tmpTXCWInterval,c, 10);
strcat(b, c);
printLine2(b);
}
//abort if this button is down
if (btnDown())
break;
Check_Cat(0); //To prevent disconnections
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("CW Start set!"));
delayBeforeCWStartTime = tmpTXCWInterval / 2;
EEPROM.put(CW_START, delayBeforeCWStartTime);
delay_background(2000, 0);
}
printLine2ClearAndUpdate();
menuOn = 0;
}
/**
* Take a deep breath, math(ematics) ahead
* The 25 mhz oscillator is multiplied by 35 to run the vco at 875 mhz
* This is divided by a number to generate different frequencies.
* If we divide it by 875, we will get 1 mhz signal
* So, if the vco is shifted up by 875 hz, the generated frequency of 1 mhz is shifted by 1 hz (875/875)
* At 12 Mhz, the carrier will needed to be shifted down by 12 hz for every 875 hz of shift up of the vco
*
*/
//this is used by the si5351 routines in the ubitx_5351 file
extern int32_t calibration;
extern uint32_t si5351bx_vcoa;
int factoryCalibration(int btn){
int knob = 0;
int32_t prev_calibration;
//keep clear of any previous button press
while (btnDown())
delay(100);
delay(100);
if (!btn){
printLineF2(F("Set Calibration?"));
return 0;
}
prev_calibration = calibration;
calibration = 0;
isUSB = true;
//turn off the second local oscillator and the bfo
si5351_set_calibration(calibration);
startTx(TX_CW, 1);
si5351bx_setfreq(2, 10000000l);
strcpy(b, "#1 10 MHz cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
while (!btnDown())
{
if (digitalRead(PTT) == LOW && !keyDown)
cwKeydown();
if (digitalRead(PTT) == HIGH && keyDown)
cwKeyUp();
knob = enc_read();
if (knob > 0)
calibration += 875;
else if (knob < 0)
calibration -= 875;
else
continue; //don't update the frequency or the display
si5351_set_calibration(calibration);
si5351bx_setfreq(2, 10000000l);
strcpy(b, "#1 10 MHz cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
}
cwTimeout = 0;
keyDown = 0;
stopTx();
printLineF2(F("Calibration set!"));
EEPROM.put(MASTER_CAL, calibration);
initOscillators();
setFrequency(frequency);
updateDisplay();
while(btnDown())
delay(50);
delay(100);
}
int menuSetupCalibration(int btn){
int knob = 0;
int32_t prev_calibration;
if (!btn){
printLineF2(F("Set Calibration?"));
return 0;
}
printLineF1(F("Set to Zero-beat,"));
printLineF2(F("press PTT to save"));
delay_background(1000, 0);
prev_calibration = calibration;
calibration = 0;
si5351_set_calibration(calibration);
setFrequency(frequency);
strcpy(b, "cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0){
calibration += 8750;
usbCarrier += 120;
}
else if (knob < 0){
calibration -= 8750;
usbCarrier -= 120;
}
else
continue; //don't update the frequency or the display
si5351_set_calibration(calibration);
si5351bx_setfreq(0, usbCarrier);
setFrequency(frequency);
strcpy(b, "cal:");
ltoa(calibration/8750, c, 10);
strcat(b, c);
printLine2(b);
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF1(F("Calibration set!"));
printLineF2(F("Set Carrier now"));
EEPROM.put(MASTER_CAL, calibration);
delay_background(2000, 0);
}
else
calibration = prev_calibration;
initOscillators();
//si5351_set_calibration(calibration);
setFrequency(frequency);
printLine2ClearAndUpdate();
menuOn = 0;
}
void printCarrierFreq(unsigned long freq){
memset(c, 0, sizeof(c));
memset(b, 0, sizeof(b));
ultoa(freq, b, DEC);
strncat(c, b, 2);
strcat(c, ".");
strncat(c, &b[2], 3);
strcat(c, ".");
strncat(c, &b[5], 1);
printLine2(c);
}
void menuSetupCarrier(int btn){
int knob = 0;
unsigned long prevCarrier;
if (!btn){
printLineF2(F("Set the BFO"));
return;
}
prevCarrier = usbCarrier;
printLineF1(F("Tune to best Signal"));
printLineF1(F("PTT to confirm. "));
delay_background(1000, 0);
usbCarrier = 11995000l;
si5351bx_setfreq(0, usbCarrier);
printCarrierFreq(usbCarrier);
//disable all clock 1 and clock 2
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0)
usbCarrier -= 50;
else if (knob < 0)
usbCarrier += 50;
else
continue; //don't update the frequency or the display
si5351bx_setfreq(0, usbCarrier);
printCarrierFreq(usbCarrier);
Check_Cat(0); //To prevent disconnections
delay(100);
}
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("Carrier set!"));
EEPROM.put(USB_CAL, usbCarrier);
delay_background(1000, 0);
}
else
usbCarrier = prevCarrier;
si5351bx_setfreq(0, usbCarrier);
setFrequency(frequency);
printLine2ClearAndUpdate();
menuOn = 0;
}
void menuSetupCwTone(int btn){
int knob = 0;
int prev_sideTone;
if (!btn){
printLineF2(F("Change CW Tone"));
return;
}
prev_sideTone = sideTone;
printLineF1(F("Tune CW tone"));
printLineF2(F("PTT to confirm."));
delay_background(1000, 0);
tone(CW_TONE, sideTone);
//disable all clock 1 and clock 2
while (digitalRead(PTT) == HIGH && !btnDown())
{
knob = enc_read();
if (knob > 0 && sideTone < 2000)
sideTone += 10;
else if (knob < 0 && sideTone > 100 )
sideTone -= 10;
else
continue; //don't update the frequency or the display
tone(CW_TONE, sideTone);
itoa(sideTone, b, 10);
printLine2(b);
delay(100);
Check_Cat(0); //To prevent disconnections
}
noTone(CW_TONE);
//save the setting
if (digitalRead(PTT) == LOW){
printLineF2(F("Sidetone set!"));
EEPROM.put(CW_SIDETONE, usbCarrier);
delay_background(2000, 0);
}
else
sideTone = prev_sideTone;
printLine2ClearAndUpdate();
menuOn = 0;
}
void setDialLock(byte tmpLock, byte fromMode) {
if (tmpLock == 1)
isDialLock |= (vfoActive == VFO_A ? 0x01 : 0x02);
else
isDialLock &= ~(vfoActive == VFO_A ? 0x01 : 0x02);
if (fromMode == 2 || fromMode == 3) return;
if (tmpLock == 1)
printLineF2(F("Dial Lock ON"));
else
printLineF2(F("Dial Lock OFF"));
delay_background(1000, 0);
printLine2ClearAndUpdate();
}
int btnDownTimeCount;
void doMenu(){
int select=0, i,btnState;
//for DialLock On/Off function
btnDownTimeCount = 0;
//wait for the button to be raised up
while(btnDown()){
delay(50);
Check_Cat(0); //To prevent disconnections
//btnDownTimeCount++;
//check long time Down Button -> 3 Second
if (btnDownTimeCount++ > (2000 / 50)) {
if (vfoActive == VFO_A)
setDialLock((isDialLock & 0x01) == 0x01 ? 0 : 1, 0); //Reverse Dial lock
else
setDialLock((isDialLock & 0x02) == 0x02 ? 0 : 1, 0); //Reverse Dial lock
return;
}
}
delay(50); //debounce
menuOn = 2;
while (menuOn){
i = enc_read();
btnState = btnDown();
if (i > 0){
if (modeCalibrate && select + i < 150)
select += i;
if (!modeCalibrate && select + i < 80)
select += i;
}
if (i < 0 && select - i >= 0)
select += i; //caught ya, i is already -ve here, so you add it
if (select < 10)
menuBand(btnState);
else if (select < 20)
menuRitToggle(btnState);
else if (select < 30)
menuVfoToggle(btnState, 1);
else if (select < 40)
menuSidebandToggle(btnState);
else if (select < 50)
menuCWSpeed(btnState);
else if (select < 60)
menuCWAutoKey(btnState);
else if (select < 70)
menuSetup(btnState);
else if (select < 80 && !modeCalibrate)
menuExit(btnState);
else if (select < 90 && modeCalibrate)
menuSetupCalibration(btnState); //crystal
else if (select < 100 && modeCalibrate)
menuSetupCarrier(btnState); //lsb
else if (select < 110 && modeCalibrate)
menuSetupCwTone(btnState);
else if (select < 120 && modeCalibrate)
menuSetupCwDelay(btnState);
else if (select < 130 && modeCalibrate)
menuSetupTXCWInterval(btnState);
else if (select < 140 && modeCalibrate)
menuTxOnOff(btnState, 0x01); //TX OFF / ON
else if (select < 150 && modeCalibrate)
menuExit(btnState);
Check_Cat(0); //To prevent disconnections
}
//debounce the button
while(btnDown()){
delay(50);
Check_Cat(0); //To prevent disconnections
}
delay(50);
}
-116
View File
@@ -1,116 +0,0 @@
// ************* SI5315 routines - tks Jerry Gaffke, KE7ER ***********************
// An minimalist standalone set of Si5351 routines.
// VCOA is fixed at 875mhz, VCOB not used.
// The output msynth dividers are used to generate 3 independent clocks
// with 1hz resolution to any frequency between 4khz and 109mhz.
// Usage:
// Call si5351bx_init() once at startup with no args;
// Call si5351bx_setfreq(clknum, freq) each time one of the
// three output CLK pins is to be updated to a new frequency.
// A freq of 0 serves to shut down that output clock.
// The global variable si5351bx_vcoa starts out equal to the nominal VCOA
// frequency of 25mhz*35 = 875000000 Hz. To correct for 25mhz crystal errors,
// the user can adjust this value. The vco frequency will not change but
// the number used for the (a+b/c) output msynth calculations is affected.
// Example: We call for a 5mhz signal, but it measures to be 5.001mhz.
// So the actual vcoa frequency is 875mhz*5.001/5.000 = 875175000 Hz,
// To correct for this error: si5351bx_vcoa=875175000;
// Most users will never need to generate clocks below 500khz.
// But it is possible to do so by loading a value between 0 and 7 into
// the global variable si5351bx_rdiv, be sure to return it to a value of 0
// before setting some other CLK output pin. The affected clock will be
// divided down by a power of two defined by 2**si5351_rdiv
// A value of zero gives a divide factor of 1, a value of 7 divides by 128.
// This lightweight method is a reasonable compromise for a seldom used feature.
#define BB0(x) ((uint8_t)x) // Bust int32 into Bytes
#define BB1(x) ((uint8_t)(x>>8))
#define BB2(x) ((uint8_t)(x>>16))
#define SI5351BX_ADDR 0x60 // I2C address of Si5351 (typical)
#define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf
// If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz
#define SI5351BX_XTAL 25000000 // Crystal freq in Hz
#define SI5351BX_MSA 35 // VCOA is at 25mhz*35 = 875mhz
// User program may have reason to poke new values into these 3 RAM variables
uint32_t si5351bx_vcoa = (SI5351BX_XTAL*SI5351BX_MSA); // 25mhzXtal calibrate
uint8_t si5351bx_rdiv = 0; // 0-7, CLK pin sees fout/(2**rdiv)
uint8_t si5351bx_drive[3] = {1, 1, 1}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off
int32_t calibration = 0;
void i2cWrite(uint8_t reg, uint8_t val) { // write reg via i2c
Wire.beginTransmission(SI5351BX_ADDR);
Wire.write(reg);
Wire.write(val);
Wire.endTransmission();
}
void i2cWriten(uint8_t reg, uint8_t *vals, uint8_t vcnt) { // write array
Wire.beginTransmission(SI5351BX_ADDR);
Wire.write(reg);
while (vcnt--) Wire.write(*vals++);
Wire.endTransmission();
}
void si5351bx_init() { // Call once at power-up, start PLLA
uint8_t reg; uint32_t msxp1;
Wire.begin();
i2cWrite(149, 0); // SpreadSpectrum off
i2cWrite(3, si5351bx_clken); // Disable all CLK output drivers
i2cWrite(183, SI5351BX_XTALPF << 6); // Set 25mhz crystal load capacitance
msxp1 = 128 * SI5351BX_MSA - 512; // and msxp2=0, msxp3=1, not fractional
uint8_t vals[8] = {0, 1, BB2(msxp1), BB1(msxp1), BB0(msxp1), 0, 0, 0};
i2cWriten(26, vals, 8); // Write to 8 PLLA msynth regs
i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB)
// for (reg=16; reg<=23; reg++) i2cWrite(reg, 0x80); // Powerdown CLK's
// i2cWrite(187, 0); // No fannout of clkin, xtal, ms0, ms4
}
void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz
uint32_t msa, msb, msc, msxp1, msxp2, msxp3p2top;
if ((fout < 500000) || (fout > 109000000)) // If clock freq out of range
si5351bx_clken |= 1 << clknum; // shut down the clock
else {
msa = si5351bx_vcoa / fout; // Integer part of vco/fout
msb = si5351bx_vcoa % fout; // Fractional part of vco/fout
msc = fout; // Divide by 2 till fits in reg
while (msc & 0xfff00000) {
msb = msb >> 1;
msc = msc >> 1;
}
msxp1 = (128 * msa + 128 * msb / msc - 512) | (((uint32_t)si5351bx_rdiv) << 20);
msxp2 = 128 * msb - 128 * msb / msc * msc; // msxp3 == msc;
msxp3p2top = (((msc & 0x0F0000) << 4) | msxp2); // 2 top nibbles
uint8_t vals[8] = { BB1(msc), BB0(msc), BB2(msxp1), BB1(msxp1),
BB0(msxp1), BB2(msxp3p2top), BB1(msxp2), BB0(msxp2)
};
i2cWriten(42 + (clknum * 8), vals, 8); // Write to 8 msynth regs
i2cWrite(16 + clknum, 0x0C | si5351bx_drive[clknum]); // use local msynth
si5351bx_clken &= ~(1 << clknum); // Clear bit to enable clock
}
i2cWrite(3, si5351bx_clken); // Enable/disable clock
}
void si5351_set_calibration(int32_t cal){
si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + cal; // apply the calibration correction factor
si5351bx_setfreq(0, usbCarrier);
}
void initOscillators(){
//initialize the SI5351
si5351bx_init();
si5351bx_vcoa = (SI5351BX_XTAL * SI5351BX_MSA) + calibration; // apply the calibration correction factor
si5351bx_setfreq(0, usbCarrier);
}
-346
View File
@@ -1,346 +0,0 @@
/**
* The user interface of the ubitx consists of the encoder, the push-button on top of it
* and the 16x2 LCD display.
* The upper line of the display is constantly used to display frequency and status
* of the radio. Occasionally, it is used to provide a two-line information that is
* quickly cleared up.
*/
//#define printLineF1(x) (printLineF(1, x))
//#define printLineF2(x) (printLineF(0, x))
//returns true if the button is pressed
int btnDown(){
if (digitalRead(FBUTTON) == HIGH)
return 0;
else
return 1;
}
/**
* Meter (not used in this build for anything)
* the meter is drawn using special characters. Each character is composed of 5 x 8 matrix.
* The s_meter array holds the definition of the these characters.
* each line of the array is is one character such that 5 bits of every byte
* makes up one line of pixels of the that character (only 5 bits are used)
* The current reading of the meter is assembled in the string called meter
*/
//char meter[17];
const PROGMEM uint8_t s_meter_bitmap[] = {
B00000,B00000,B00000,B00000,B00000,B00100,B00100,B11011,
B10000,B10000,B10000,B10000,B10100,B10100,B10100,B11011,
B01000,B01000,B01000,B01000,B01100,B01100,B01100,B11011,
B00100,B00100,B00100,B00100,B00100,B00100,B00100,B11011,
B00010,B00010,B00010,B00010,B00110,B00110,B00110,B11011,
B00001,B00001,B00001,B00001,B00101,B00101,B00101,B11011
};
PGM_P ps_meter_bitmap = reinterpret_cast<PGM_P>(s_meter_bitmap);
const PROGMEM uint8_t lock_bitmap[8] = {
0b01110,
0b10001,
0b10001,
0b11111,
0b11011,
0b11011,
0b11111,
0b00000};
PGM_P plock_bitmap = reinterpret_cast<PGM_P>(lock_bitmap);
// initializes the custom characters
// we start from char 1 as char 0 terminates the string!
void initMeter(){
uint8_t tmpbytes[8];
byte i;
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(plock_bitmap + i);
lcd.createChar(0, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i);
lcd.createChar(1, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 8);
lcd.createChar(2, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 16);
lcd.createChar(3, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 24);
lcd.createChar(4, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 28);
lcd.createChar(5, tmpbytes);
for (i = 0; i < 8; i++)
tmpbytes[i] = pgm_read_byte(ps_meter_bitmap + i + 32);
lcd.createChar(6, tmpbytes);
}
/**
* The meter is drawn with special characters.
* character 1 is used to simple draw the blocks of the scale of the meter
* characters 2 to 6 are used to draw the needle in positions 1 to within the block
* This displays a meter from 0 to 100, -1 displays nothing
*/
/*
void drawMeter(int8_t needle){
int16_t best, i, s;
if (needle < 0)
return;
s = (needle * 4)/10;
for (i = 0; i < 8; i++){
if (s >= 5)
meter[i] = 1;
else if (s >= 0)
meter[i] = 2 + s;
else
meter[i] = 1;
s = s - 5;
}
if (needle >= 40)
meter[i-1] = 6;
meter[i] = 0;
}
*/
// The generic routine to display one line on the LCD
void printLine(char linenmbr, char *c) {
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
lcd.setCursor(0, linenmbr); // place the cursor at the beginning of the selected line
lcd.print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached
lcd.print(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[17];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 17; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 16
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex) {
lcd.setCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
lcd.write(EEPROM.read(USER_CALLSIGN_DAT + i));
else
break;
}
for (byte i = lcdColumn; i < 16; i++) //Right Padding by Space
lcd.write(' ');
}
// short cut to print to the first line
void printLine1(char *c){
printLine(1,c);
}
// short cut to print to the first line
void printLine2(char *c){
printLine(0,c);
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
updateDisplay();
}
//012...89ABC...Z
char byteToChar(byte srcByte){
if (srcByte < 10)
return 0x30 + srcByte;
else
return 'A' + srcByte - 10;
}
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
lcd.setCursor(5,1);
lcd.write((uint8_t)0);
}
else if (isCWAutoMode == 2){
lcd.setCursor(5,1);
lcd.write(0x7E);
}
else
{
lcd.setCursor(5,1);
lcd.write(":");
}
/*
//now, the second line
memset(c, 0, sizeof(c));
memset(b, 0, sizeof(b));
if (inTx)
strcat(c, "TX ");
else if (ritOn)
strcpy(c, "RIT");
strcpy(c, " \xff");
drawMeter(meter_reading);
strcat(c, meter);
strcat(c, "\xff");
printLine2(c);*/
}
int enc_prev_state = 3;
/**
* The A7 And A6 are purely analog lines on the Arduino Nano
* These need to be pulled up externally using two 10 K resistors
*
* There are excellent pages on the Internet about how these encoders work
* and how they should be used. We have elected to use the simplest way
* to use these encoders without the complexity of interrupts etc to
* keep it understandable.
*
* The enc_state returns a two-bit number such that each bit reflects the current
* value of each of the two phases of the encoder
*
* The enc_read returns the number of net pulses counted over 50 msecs.
* If the puluses are -ve, they were anti-clockwise, if they are +ve, the
* were in the clockwise directions. Higher the pulses, greater the speed
* at which the enccoder was spun
*/
byte enc_state (void) {
return (analogRead(ENC_A) > 500 ? 1 : 0) + (analogRead(ENC_B) > 500 ? 2: 0);
}
int enc_read(void) {
int result = 0;
byte newState;
int enc_speed = 0;
long stop_by = millis() + 50;
while (millis() < stop_by) { // check if the previous state was stable
newState = enc_state(); // Get current state
if (newState != enc_prev_state)
delay (1);
if (enc_state() != newState || newState == enc_prev_state)
continue;
//these transitions point to the encoder being rotated anti-clockwise
if ((enc_prev_state == 0 && newState == 2) ||
(enc_prev_state == 2 && newState == 3) ||
(enc_prev_state == 3 && newState == 1) ||
(enc_prev_state == 1 && newState == 0)){
result--;
}
//these transitions point o the enccoder being rotated clockwise
if ((enc_prev_state == 0 && newState == 1) ||
(enc_prev_state == 1 && newState == 3) ||
(enc_prev_state == 3 && newState == 2) ||
(enc_prev_state == 2 && newState == 0)){
result++;
}
enc_prev_state = newState; // Record state for next pulse interpretation
enc_speed++;
delay(1);
}
return(result);
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

BIN
View File
Binary file not shown.