Compare commits
135 Commits
v1.061
...
new-main-d
Author | SHA1 | Date | |
---|---|---|---|
295b99ef36 | |||
|
e6009989db | ||
|
1f3585d8e4 | ||
|
c8aecdfb0d | ||
|
f724142fca | ||
|
869e47d430 | ||
|
20b475dace | ||
|
962a3ce80f | ||
|
86ae1ddb2f | ||
|
119902b1e0 | ||
|
1bca18c3e1 | ||
|
f3887e7950 | ||
|
2cbc9abae8 | ||
|
8a416608a1 | ||
|
e5de516633 | ||
|
5b395cd922 | ||
|
47840e09dd | ||
|
d2213e34ff | ||
|
814fe6c733 | ||
|
c3cc9a7cf7 | ||
|
aeeec69daf | ||
|
702f370d1b | ||
|
b9be616361 | ||
|
4186fdcdd4 | ||
|
e62e3ef548 | ||
|
deb0aca5fe | ||
|
04d5f3ba12 | ||
|
ba744f5b7a | ||
|
4e818b6a89 | ||
|
b2cb1a26ba | ||
|
da58606409 | ||
|
091f414409 | ||
|
6b365beac0 | ||
|
87b6e3fbde | ||
|
48cb6cf304 | ||
|
c59d53fb9e | ||
|
16b350cb0f | ||
|
bb31ccfbe4 | ||
|
c1c4dd3f19 | ||
|
88143f57a2 | ||
|
d97f282f7b | ||
|
c93e191dfd | ||
|
b50ad3275a | ||
|
04b70450ae | ||
|
3364cb78d5 | ||
|
cfa6f8699d | ||
|
48344923cc | ||
|
dec1d1edec | ||
|
e77a3715a8 | ||
|
1a60adaf2f | ||
|
02c0066df4 | ||
|
262ef3947a | ||
|
a4d9f6e6c5 | ||
|
395dd42459 | ||
|
f25bf57556 | ||
|
171f889f4a | ||
|
05de66a038 | ||
|
2c075d5236 | ||
|
37fcc5975a | ||
|
450f57ae0f | ||
|
c34e798313 | ||
|
df2c493700 | ||
|
9ff8365c3f | ||
|
948267bb39 | ||
|
e79dbdbbe7 | ||
|
265188dc86 | ||
|
aee410fd19 | ||
|
16e173b109 | ||
|
d5db04ff0e | ||
|
0586bb75a7 | ||
|
7c1ee29500 | ||
|
4ee3631db0 | ||
|
c27bbf1b6b | ||
|
b984f62dfd | ||
|
41548163cf | ||
|
1ce889eef0 | ||
|
dd43ba4c33 | ||
|
fe44c703c5 | ||
|
22bb9ee112 | ||
|
c73fffb25b | ||
|
82177199c4 | ||
|
0e13dd0267 | ||
|
c602fdde7c | ||
|
edadce7d89 | ||
|
9da71429cb | ||
|
3050374504 | ||
|
152b63a9ed | ||
|
72ccd3b0e4 | ||
|
e81413fa02 | ||
|
c6b020fa70 | ||
|
2e8c97f19b | ||
|
337320b433 | ||
|
7c8088f753 | ||
|
b172527d00 | ||
|
67cdd14945 | ||
|
b375b7e9e4 | ||
|
27092d23e0 | ||
|
8a6e01e289 | ||
|
83dc1de18e | ||
|
2de1c873a1 | ||
|
4d97ac2283 | ||
|
65d21aba77 | ||
|
6a2369bc27 | ||
|
76d5c362d0 | ||
|
70fc6aeba8 | ||
|
75d952718b | ||
|
1d28f3e7e9 | ||
|
51f690ef85 | ||
|
12984486a6 | ||
|
e961cd8ac9 | ||
|
5c40718bec | ||
|
6add092391 | ||
|
3b4bdafacc | ||
|
82d9682ee9 | ||
|
6be127d811 | ||
|
5b13ede65b | ||
|
0aafe32e27 | ||
|
289ae1bd77 | ||
|
5611e1c0ff | ||
|
86797181cf | ||
|
f600c18541 | ||
|
11b6fbc1f4 | ||
|
0e245fc488 | ||
|
d721816039 | ||
|
34be2d0845 | ||
|
0996870154 | ||
|
689cfda09e | ||
|
23f1b7cd5c | ||
|
d4ed0589e5 | ||
|
5f906a4497 | ||
|
1210f56cd1 | ||
|
e8d6792073 | ||
|
02f22d66e5 | ||
|
11e47fdccc | ||
|
7aafed9e95 |
208
README.md
208
README.md
@@ -1,207 +1,3 @@
|
||||
#IMPORTANT INFORMATION
|
||||
----------------------------------------------------------------------------
|
||||
- Now Release Version 1.061 on my blog (http://www.hamskey.com)
|
||||
- You can download and compiled hex file and uBITX Manager application on my blog (http://www.hamskey.com)
|
||||
# ubitx-v5x
|
||||
|
||||
#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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
- Reduce Program size
|
||||
- uBITX with RTL-SDR
|
||||
- Direct control for Student
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
## REVISION RECORD
|
||||
1.07 (Working...)
|
||||
- Please do not download it yet. The code will continue to change for the time being.
|
||||
- BetaVersion for Reduce program size
|
||||
|
||||
1.061
|
||||
- Added WSPR
|
||||
You only need uBITX to use WSPR. No external devices are required.
|
||||
Added Si5351 module for WSPR
|
||||
- Update uBITX Manager to Version 1.0
|
||||
- Reduce program size
|
||||
for WSPR
|
||||
for other Module
|
||||
- Fixed IF Shift Bug
|
||||
Disable IF Shift on TX
|
||||
IF shift available in USB mode
|
||||
Fixed cat routine in IF Shift setup
|
||||
- Bugs fixed
|
||||
cw start delay option
|
||||
Auto key Bug
|
||||
(found bug : LZ1LDO)
|
||||
Message selection when Auto Key is used in RIT mode
|
||||
(found bug : gerald)
|
||||
- Improve CW Keying (start TX)
|
||||
|
||||
1.05
|
||||
- include 1.05W, 1.051, 1.051W
|
||||
- for WSPR Beta Test Version
|
||||
|
||||
1.04
|
||||
- Optimized from Version1.03
|
||||
- Reduce program size (97% -> 95%)
|
||||
|
||||
1.03
|
||||
- Change eBFO Calibration Step (50 to 5)
|
||||
- Change CW Frequency Display type
|
||||
|
||||
1.02
|
||||
- Applied CW Start Delay to New CW Key logic (This is my mistake when applying the new CW Key Logic.Since uBITX operations are not significantly affected, this does not create a separate Release, It will be reflected in the next release.) - complete
|
||||
- Modified CW Key Logic for Auto Key, (available AutoKey function by any cw keytype) - complete
|
||||
- reduce cpu use usage (working)
|
||||
- reduce (working)
|
||||
|
||||
1.01
|
||||
- Fixed Cat problem with (IAMBIC A or B Selected)
|
||||
1.0
|
||||
- rename 0.30 to 1.0
|
||||
|
||||
0.35
|
||||
- vfo to channel bug fixed (not saved mode -> fixed, channel has frequency and mode)
|
||||
- add Channel tag (ch.1 ~ 10) by uBITX Manager
|
||||
- add VFO to Channel, Channel To VFO
|
||||
|
||||
0.34
|
||||
- TX Status check in auto Keysend logic
|
||||
- optimize codes
|
||||
- change default tune step size, and fixed bug
|
||||
- change IF shift step (1Hz -> 50Hz)
|
||||
|
||||
0.33
|
||||
- Added CWL, CWU Mode, (dont complete test yet)
|
||||
- fixed VFO changed bug.
|
||||
- Added Additional BFO for CWL, CWL
|
||||
- Added IF Shift
|
||||
- Change confirmation key PTT -> function key (not critical menus)
|
||||
- Change CW Key Select type, (toggle -> select by dial)
|
||||
|
||||
0.32
|
||||
- Added function Scroll Frequencty on upper line
|
||||
- Added Example code for Draw meter and remarked (you can see and use this code in source codes)
|
||||
- Added Split function, just toggle VFOs when TX/RX
|
||||
|
||||
0.31
|
||||
- Fixed CW ADC Range error
|
||||
- Display Message on Upper Line (anothor VFO Frequency, Tune Step, Selected Key Type)
|
||||
|
||||
0.30
|
||||
- implemented the function to monitor the value of all analog inputs. This allows you to monitor the status of the CW keys connected to your uBITX.
|
||||
- possible to set the ADC range for CW Keying. If no setting is made, it will have the same range as the original code. If you set the CW Keying ADC Values using uBITX Manager 0.3, you can reduce the key error.
|
||||
- Added the function to select Straight Key, IAMBICA, IAMBICB key from the menu.
|
||||
- default Band select is Ham Band mode, if you want common type, long press function key at band select menu, uBITX Manager can be used to modify frequencies to suit your country.
|
||||
|
||||
0.29
|
||||
- Remove the use of initialization values in BFO settings - using crruent value, if factory reset
|
||||
- Select Tune Step, default 0, 20, 50, 100, 200, Use the uBITX Manager to set the steps value you want. You can select Step by pressing and holding the Function Key (1sec ~ 2sec).
|
||||
- Modify Dial Lock Function, Press the Function key for more than 3 seconds to toggle dial lock.
|
||||
- created a new frequency tune method. remove original source codes, Threshold has been applied to reduce malfunction. checked the continuity of the user operating to make natural tune possible.
|
||||
- stabilize and remove many warning messages - by Pullrequest and merge
|
||||
- Changed cw keying method. removed the original code and applied Ron's code and Improved compatibility with original hardware and CAT commnication. It can be used without modification of hardware.
|
||||
|
||||
0.28
|
||||
- Fixed CAT problem with hamlib on Linux
|
||||
- restore Protocol autorecovery logic
|
||||
|
||||
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/>.
|
||||
"Extended" version of the uBITX v5, including both a Teensy-based DSP as well as a Nextion 3.2" display.
|
0
Raduino/Debug.h
Executable file
0
Raduino/Debug.h
Executable file
File diff suppressed because it is too large
Load Diff
0
Raduino/RigState.cpp
Executable file
0
Raduino/RigState.cpp
Executable file
0
Raduino/RigState.h
Executable file
0
Raduino/RigState.h
Executable file
334
Raduino/softserial_tiny.cpp
Normal file
334
Raduino/softserial_tiny.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
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 <Arduino.h>
|
||||
|
||||
//================================================================
|
||||
//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;
|
||||
uint8_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);
|
||||
}
|
343
Raduino/ubitx.h
Normal file
343
Raduino/ubitx.h
Normal file
@@ -0,0 +1,343 @@
|
||||
/*************************************************************************
|
||||
header file for C++ by KD8CEC
|
||||
-----------------------------------------------------------------------------
|
||||
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/>.
|
||||
**************************************************************************/
|
||||
#ifndef _UBITX_HEADER__
|
||||
#define _UBITX_HEADER__
|
||||
|
||||
#include <Arduino.h> //for Linux, On Linux it is case sensitive.
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
//==============================================================================
|
||||
// Compile Option
|
||||
//==============================================================================
|
||||
//Ubitx Board Version
|
||||
#define UBITX_BOARD_VERSION 5 //v1 ~ v4 : 4, v5: 5
|
||||
|
||||
//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below.
|
||||
//You must select only one.
|
||||
//#define UBITX_DISPLAY_LCD1602P //LCD mounted on unmodified uBITX (Parallel)
|
||||
//#define UBITX_DISPLAY_LCD1602I //I2C type 16 x 02 LCD
|
||||
//#define UBITX_DISPLAY_LCD1602I_DUAL //I2C type 16 x02 LCD Dual
|
||||
//#define UBITX_DISPLAY_LCD2004P //24 x 04 LCD (Parallel)
|
||||
//#define UBITX_DISPLAY_LCD2004I //I2C type 24 x 04 LCD
|
||||
#define UBITX_DISPLAY_NEXTION //NEXTION LCD
|
||||
|
||||
//#define UBITX_DISPLAY_NEXTION_SAFE //Only EEProm Write 770~775
|
||||
#define I2C_LCD_MASTER_ADDRESS_DEFAULT 0x27 //0x27 //DEFAULT, if Set I2C Address by uBITX Manager, read from EEProm
|
||||
#define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode
|
||||
|
||||
//Select betwen Analog S-Meter and DSP (I2C) Meter
|
||||
#define USE_I2CSMETER
|
||||
|
||||
#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP
|
||||
//#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x
|
||||
|
||||
//Custom LPF Filter Mod
|
||||
//#define USE_CUSTOM_LPF_FILTER //LPF FILTER MOD
|
||||
|
||||
//#define ENABLE_FACTORYALIGN
|
||||
//#define FACTORY_RECOVERY_BOOTUP //Whether to enter Factory Recovery mode by pressing FKey and turning on power
|
||||
//#define ENABLE_ADCMONITOR //Starting with Version 1.07, you can read ADC values directly from uBITX Manager. So this function is not necessary.
|
||||
|
||||
extern byte I2C_LCD_MASTER_ADDRESS; //0x27 //if Set I2C Address by uBITX Manager, read from EEProm
|
||||
extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
|
||||
#define SMeterLatency 3 //1 is 0.25 sec
|
||||
|
||||
//==============================================================================
|
||||
// User Select feather list
|
||||
//==============================================================================
|
||||
//Enable all features
|
||||
#define FN_BAND 1 //592
|
||||
#define FN_VFO_TOGGLE 1 //78
|
||||
#define FN_MODE 1 //20
|
||||
#define FN_RIT 1 //58
|
||||
#define FN_SPLIT 1 //62
|
||||
#define FN_IFSHIFT 1 //238
|
||||
#define FN_ATT 1 //128
|
||||
#define FN_CW_SPEED 1 //152
|
||||
#define FN_VFOTOMEM 1 //254
|
||||
#define FN_MEMTOVFO 1 //188
|
||||
#define FN_MEMORYKEYER 1 //156
|
||||
#define FN_WSPR 1 //1044
|
||||
#define FN_SDRMODE 1 //68
|
||||
#define FN_CALIBRATION 1 //666
|
||||
#define FN_CARRIER 1 //382
|
||||
#define FN_CWCARRIER 1 //346
|
||||
#define FN_CWTONE 1 //148
|
||||
#define FN_CWDELAY 1 //98
|
||||
#define FN_TXCWDELAY 1 //94
|
||||
#define FN_KEYTYPE 1 //168
|
||||
#define FN_ADCMONITOR 1 //516
|
||||
#define FN_TXONOFF 1 //58
|
||||
|
||||
/*
|
||||
//Test Configuration (88%)
|
||||
#define FN_BAND 0 //592
|
||||
#define FN_VFO_TOGGLE 0 //78
|
||||
#define FN_MODE 0 //20
|
||||
#define FN_RIT 0 //58
|
||||
#define FN_SPLIT 0 //62
|
||||
#define FN_IFSHIFT 0 //238
|
||||
#define FN_ATT 0 //128
|
||||
#define FN_CW_SPEED 1 //152
|
||||
#define FN_VFOTOMEM 0 //254
|
||||
#define FN_MEMTOVFO 0 //188
|
||||
#define FN_MEMORYKEYER 1 //156
|
||||
#define FN_WSPR 0 //1044
|
||||
#define FN_SDRMODE 1 //68
|
||||
#define FN_CALIBRATION 1 //666
|
||||
#define FN_CARRIER 1 //382
|
||||
#define FN_CWCARRIER 1 //346
|
||||
#define FN_CWTONE 1 //148
|
||||
#define FN_CWDELAY 1 //98
|
||||
#define FN_TXCWDELAY 1 //94
|
||||
#define FN_KEYTYPE 1 //168
|
||||
#define FN_ADCMONITOR 1 //516
|
||||
#define FN_TXONOFF 1 //58
|
||||
*/
|
||||
|
||||
/*
|
||||
//Recommended Character LCD Developer 87%
|
||||
#define FN_BAND 1 //592
|
||||
#define FN_VFO_TOGGLE 1 //78
|
||||
#define FN_MODE 1 //20
|
||||
#define FN_RIT 1 //58
|
||||
#define FN_SPLIT 1 //62
|
||||
#define FN_IFSHIFT 1 //238
|
||||
#define FN_ATT 0 //128
|
||||
#define FN_CW_SPEED 0 //152 //using MM
|
||||
#define FN_VFOTOMEM 1 //254
|
||||
#define FN_MEMTOVFO 1 //188
|
||||
#define FN_MEMORYKEYER 1 //156
|
||||
#define FN_WSPR 1 //1044
|
||||
#define FN_SDRMODE 1 //68
|
||||
#define FN_CALIBRATION 0 //667 //using MM
|
||||
#define FN_CARRIER 0 //382 //using MM
|
||||
#define FN_CWCARRIER 0 //346 //using MM
|
||||
#define FN_CWTONE 0 //148 //using MM
|
||||
#define FN_CWDELAY 0 //98 //using MM
|
||||
#define FN_TXCWDELAY 0 //94 //using MM
|
||||
#define FN_KEYTYPE 0 //168 //using MM
|
||||
#define FN_ADCMONITOR 0 //516 //using MM
|
||||
#define FN_TXONOFF 1 //58
|
||||
*/
|
||||
|
||||
/*
|
||||
//Recommended for Nextion, TJC LCD 88%
|
||||
#define FN_BAND 1 //600
|
||||
#define FN_VFO_TOGGLE 1 //90
|
||||
#define FN_MODE 1 //318
|
||||
#define FN_RIT 1 //62
|
||||
#define FN_SPLIT 1 //2
|
||||
#define FN_IFSHIFT 1 //358
|
||||
#define FN_ATT 1 //250
|
||||
#define FN_CW_SPEED 0 //286
|
||||
#define FN_VFOTOMEM 0 //276
|
||||
#define FN_MEMTOVFO 0 //234
|
||||
#define FN_MEMORYKEYER 1 //168
|
||||
#define FN_WSPR 1 //1130
|
||||
#define FN_SDRMODE 1 //70
|
||||
#define FN_CALIBRATION 0 //790
|
||||
#define FN_CARRIER 0 //500
|
||||
#define FN_CWCARRIER 0 //464
|
||||
#define FN_CWTONE 0 //158
|
||||
#define FN_CWDELAY 0 //108
|
||||
#define FN_TXCWDELAY 0 //106
|
||||
#define FN_KEYTYPE 0 //294
|
||||
#define FN_ADCMONITOR 0 //526 //not available with Nextion or Serial UI
|
||||
#define FN_TXONOFF 1 //70
|
||||
*/
|
||||
//==============================================================================
|
||||
// End of User Select Mode and Compil options
|
||||
//==============================================================================
|
||||
|
||||
#ifdef UBITX_DISPLAY_LCD1602I
|
||||
#define USE_I2C_LCD
|
||||
#elif defined(UBITX_DISPLAY_LCD1602I_DUAL)
|
||||
#define USE_I2C_LCD
|
||||
#elif defined(UBITX_DISPLAY_LCD2004I)
|
||||
#define USE_I2C_LCD
|
||||
#endif
|
||||
|
||||
#ifdef UBITX_DISPLAY_NEXTION
|
||||
#define USE_SW_SERIAL
|
||||
#undef ENABLE_ADCMONITOR
|
||||
#undef FACTORY_RECOVERY_BOOTUP
|
||||
#elif defined(UBITX_CONTROL_MCU)
|
||||
#define USE_SW_SERIAL
|
||||
#undef ENABLE_ADCMONITOR
|
||||
#undef FACTORY_RECOVERY_BOOTUP
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// Hardware, Define PIN Usage
|
||||
//==============================================================================
|
||||
/**
|
||||
* 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 => Analog S-Meter
|
||||
* 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)
|
||||
#define ANALOG_SMETER (A7) //by KD8CEC
|
||||
|
||||
/**
|
||||
* 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 CLK2 GND GND CLK1 GND GND CLK0 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) //Relay
|
||||
#define CW_TONE (6)
|
||||
#define TX_LPF_A (5) //Relay
|
||||
#define TX_LPF_B (4) //Relay
|
||||
#define TX_LPF_C (3) //Relay
|
||||
#define CW_KEY (2)
|
||||
|
||||
//******************************************************
|
||||
//DSP (I2C) Meter
|
||||
//******************************************************
|
||||
//S-Meter Address
|
||||
#define I2CMETER_ADDR 0x58
|
||||
//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
|
||||
|
||||
// Raduino<=>TeensyDSP data exchange
|
||||
#define I2CMETER_RIGINF 0x50
|
||||
|
||||
// Raduino requests any CAT updates from TeensyDSP
|
||||
//#define I2CMETER_REQCAT 0x51
|
||||
|
||||
//==============================================================================
|
||||
// for public, Variable, functions
|
||||
//==============================================================================
|
||||
#define WSPR_BAND_COUNT 3
|
||||
#define TX_SSB 0
|
||||
#define TX_CW 1
|
||||
#define printLineF1(x) (printLineF(1, x))
|
||||
#define printLineF2(x) (printLineF(0, x))
|
||||
|
||||
//0x00 : None, 0x01 : MODE, 0x02:BAND+, 0x03:BAND-, 0x04:TUNE_STEP, 0x05:VFO Toggle, 0x06:SplitOn/Off, 0x07:TX/ON-OFF, 0x08:SDR Mode On / Off, 0x09:Rit Toggle
|
||||
#define FUNCTION_KEY_ADC 80 //MODE, BAND(-), BAND(+), STEP
|
||||
#define FKEY_PRESS 0x78
|
||||
#define FKEY_MODE 0x01
|
||||
#define FKEY_BANDUP 0x02
|
||||
#define FKEY_BANDDOWN 0x03
|
||||
#define FKEY_STEP 0x04
|
||||
#define FKEY_VFOCHANGE 0x05
|
||||
#define FKEY_SPLIT 0x06
|
||||
#define FKEY_TXOFF 0x07
|
||||
#define FKEY_SDRMODE 0x08
|
||||
#define FKEY_RIT 0x09
|
||||
|
||||
#define FKEY_ENTER 0x0A
|
||||
#define FKEY_POINT 0x0B
|
||||
#define FKEY_DELETE 0x0C
|
||||
#define FKEY_CANCEL 0x0D
|
||||
|
||||
#define FKEY_NUM0 0x10
|
||||
#define FKEY_NUM1 0x11
|
||||
#define FKEY_NUM2 0x12
|
||||
#define FKEY_NUM3 0x13
|
||||
#define FKEY_NUM4 0x14
|
||||
#define FKEY_NUM5 0x15
|
||||
#define FKEY_NUM6 0x16
|
||||
#define FKEY_NUM7 0x17
|
||||
#define FKEY_NUM8 0x18
|
||||
#define FKEY_NUM9 0x19
|
||||
|
||||
#define FKEY_TYPE_MAX 0x1F
|
||||
|
||||
extern uint8_t SI5351BX_ADDR; //change typical -> variable at Version 1.097, address read from eeprom, default value is 0x60
|
||||
//EEProm Address : 63
|
||||
extern unsigned long frequency;
|
||||
extern byte WsprMSGCount;
|
||||
extern byte sMeterLevels[9];
|
||||
extern int currentSMeter; //ADC Value for S.Meter
|
||||
extern byte scaledSMeter; //Calculated S.Meter Level
|
||||
|
||||
extern byte KeyValues[16][3]; //Set : Start Value, End Value, Key Type, 16 Set (3 * 16 = 48)
|
||||
extern byte TriggerBySW; //Action Start from Nextion LCD, Other MCU
|
||||
|
||||
extern void printLine1(const char *c);
|
||||
extern void printLine2(const char *c);
|
||||
extern void printLineF(char linenmbr, const __FlashStringHelper *c);
|
||||
extern void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetType);
|
||||
extern byte delay_background(unsigned delayTime, byte fromType);
|
||||
extern int btnDown(void);
|
||||
extern char c[30];
|
||||
extern char b[30];
|
||||
extern int enc_read(void);
|
||||
extern void si5351bx_init(void);
|
||||
extern void si5351bx_setfreq(uint8_t clknum, uint32_t fout);
|
||||
extern void si5351_set_calibration(int32_t cal);
|
||||
extern void initOscillators(void);
|
||||
extern void Set_WSPR_Param(void);
|
||||
extern void TXSubFreq(unsigned long P2);
|
||||
|
||||
extern void startTx(byte txMode, byte isDisplayUpdate);
|
||||
extern void stopTx(void);
|
||||
extern void setTXFilters(unsigned long freq);
|
||||
|
||||
extern void SendWSPRManage(void);
|
||||
extern char byteToChar(byte srcByte);
|
||||
extern void DisplayCallsign(byte callSignLength);
|
||||
extern void DisplayVersionInfo(const char* fwVersionInfo);
|
||||
|
||||
//I2C Signal Meter, Version 1.097
|
||||
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
|
||||
|
||||
#endif //end of if header define
|
152
Raduino/ubitx_eemap.h
Normal file
152
Raduino/ubitx_eemap.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*************************************************************************
|
||||
header file for EEProm Address Map by KD8CEC
|
||||
It must be protected to protect the factory calibrated calibration.
|
||||
-----------------------------------------------------------------------------
|
||||
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/>.
|
||||
**************************************************************************/
|
||||
#ifndef _UBITX_EEPOM_HEADER__
|
||||
#define _UBITX_EEPOM_HEADER__
|
||||
|
||||
//==============================================================================
|
||||
// Factory-shipped EEProm address
|
||||
// (factory Firmware)
|
||||
// Address : 0 ~ 31
|
||||
//==============================================================================
|
||||
#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
|
||||
|
||||
//==============================================================================
|
||||
// The spare space available in the original firmware #1
|
||||
// Address : 32 ~ 62
|
||||
//==============================================================================
|
||||
#define RESERVE_FOR_FACTORY1 32
|
||||
|
||||
//==============================================================================
|
||||
// custom LPF Filter
|
||||
// 48 : Using Custom LPF Filter (48 = 0x57 or 0x58 => Using Custom LPF Filter, 0x58 = using A7 IO
|
||||
// 49, 50 : LPF1 (49 : MHz (~ Mhz), 50 : Enabled PIN
|
||||
// 51, 52 : LPF2
|
||||
// 53, 54 : LPF3
|
||||
// 55, 56 : LPF4
|
||||
// 57, 58 : LPF5
|
||||
// 59, 60 : LPF6
|
||||
// 61, 62 : LPF7
|
||||
//==============================================================================
|
||||
#define CUST_LPF_ENABLED 48
|
||||
#define CUST_LPF_START 49
|
||||
|
||||
//SI5351 I2C Address (Version 1.097)
|
||||
#define I2C_ADDR_SI5351 63
|
||||
|
||||
//==============================================================================
|
||||
// The spare space available in the original firmware #2
|
||||
// (Enabled if the EEProm address is insufficient)
|
||||
// Address : 64 ~ 100
|
||||
//==============================================================================
|
||||
#define RESERVE_FOR_FACTORY2 64 //use Factory backup from Version 1.075
|
||||
#define FACTORY_BACKUP_YN 64 //Check Backup //Magic : 0x13
|
||||
#define FACTORY_VALUES 65 //65 ~ 65 + 32
|
||||
|
||||
//==============================================================================
|
||||
// KD8CEC EEPROM MAP
|
||||
// Address : 101 ~ 1023
|
||||
// 256 is the base address
|
||||
// 256 ~ 1023 (EEProm Section #1)
|
||||
// 255 ~ 101 (EEProm Section #2)
|
||||
//==============================================================================
|
||||
|
||||
//0x00 : None, 0x01 : MODE, 0x02:BAND+, 0x03:BAND-, 0x04:TUNE_STEP, 0x05:VFO Toggle, 0x06:SplitOn/Off, 0x07:TX/ON-OFF, 0x08:SDR Mode On / Off, 0x09:Rit Toggle
|
||||
#define EXTENDED_KEY_RANGE 140 //Extended Key => Set : Start Value, End Value, Key Type, 16 Set (3 * 16 = 48)
|
||||
|
||||
#define I2C_LCD_MASTER 190
|
||||
#define I2C_LCD_SECOND 191
|
||||
|
||||
#define S_METER_LEVELS 230 //LEVEL0 ~ LEVEL7
|
||||
|
||||
#define ADVANCED_FREQ_OPTION1 240 //Bit0: use IFTune_Value, Bit1 : use Stored enabled SDR Mode, Bit2 : dynamic sdr frequency
|
||||
#define IF1_CAL 241
|
||||
#define ENABLE_SDR 242
|
||||
#define SDR_FREQUNCY 243
|
||||
#define CW_CAL 252
|
||||
|
||||
#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
|
||||
#define TUNING_STEP 342 //TUNING STEP * 6 (index 1 + STEPS 5) //1STEP :
|
||||
|
||||
//for reduce cw key error, eeprom address
|
||||
#define CW_ADC_MOST_BIT1 348 //most 2bits of DOT_TO , DOT_FROM, ST_TO, ST_FROM
|
||||
#define CW_ADC_ST_FROM 349 //CW ADC Range STRAIGHT KEY from (Lower 8 bit)
|
||||
#define CW_ADC_ST_TO 350 //CW ADC Range STRAIGHT KEY to (Lower 8 bit)
|
||||
#define CW_ADC_DOT_FROM 351 //CW ADC Range DOT from (Lower 8 bit)
|
||||
#define CW_ADC_DOT_TO 352 //CW ADC Range DOT to (Lower 8 bit)
|
||||
|
||||
#define CW_ADC_MOST_BIT2 353 //most 2bits of BOTH_TO, BOTH_FROM, DASH_TO, DASH_FROM
|
||||
#define CW_ADC_DASH_FROM 354 //CW ADC Range DASH from (Lower 8 bit)
|
||||
#define CW_ADC_DASH_TO 355 //CW ADC Range DASH to (Lower 8 bit)
|
||||
#define CW_ADC_BOTH_FROM 356 //CW ADC Range BOTH from (Lower 8 bit)
|
||||
#define CW_ADC_BOTH_TO 357 //CW ADC Range BOTH to (Lower 8 bit)
|
||||
#define CW_KEY_TYPE 358
|
||||
#define CW_DISPLAY_SHIFT 359 //Transmits on CWL, CWU Mode, LCD Frequency shifts Sidetone Frequency.
|
||||
//(7:Enable / Disable //0: enable, 1:disable, (default is applied shift)
|
||||
//6 : 0 : Adjust Pulus, 1 : Adjust Minus
|
||||
//0~5: Adjust Value : * 10 = Adjust Value (0~300)
|
||||
#define COMMON_OPTION0 360 //0: Confirm : CW Frequency Shift
|
||||
//1 : IF Shift Save
|
||||
#define IF_SHIFTVALUE 363
|
||||
|
||||
#define DISPLAY_OPTION1 361 //Display Option1
|
||||
#define DISPLAY_OPTION2 362 //Display Option2
|
||||
|
||||
#define WSPR_COUNT 443 //WSPR_MESSAGE_COUNT
|
||||
#define WSPR_MESSAGE1 444 //
|
||||
#define WSPR_MESSAGE2 490 //
|
||||
#define WSPR_MESSAGE3 536 //
|
||||
#define WSPR_MESSAGE4 582 //
|
||||
|
||||
#define CHANNEL_FREQ 630 //Channel 1 ~ 20, 1 Channel = 4 bytes
|
||||
#define CHANNEL_DESC 710 //Channel 1 ~ 20, 1 Channel = 4 bytes
|
||||
#define EXTERNAL_DEVICE_OPT1 770 //for External Deivce 4byte
|
||||
#define EXTERNAL_DEVICE_OPT2 774 //for External Deivce 2byte
|
||||
|
||||
//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
|
||||
|
||||
#endif //end of if header define
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#include "ubitx.h"
|
||||
|
||||
/**
|
||||
* This procedure is only for those who have a signal generator/transceiver tuned to exactly 7.150 and a dummy load
|
||||
@@ -27,14 +28,25 @@ void factory_alignment(){
|
||||
printLine2("#2 BFO");
|
||||
delay(1000);
|
||||
|
||||
#if UBITX_BOARD_VERSION == 5
|
||||
usbCarrier = 11053000l;
|
||||
menuSetupCarrier(1);
|
||||
if (usbCarrier == 11053000l){
|
||||
printLine2("Setup Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
usbCarrier = 11994999l;
|
||||
menuSetupCarrier(1);
|
||||
|
||||
if (usbCarrier == 11994999l){
|
||||
printLine2("Setup Aborted");
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
printLine2("#3:Test 3.5MHz");
|
||||
cwMode = 0;
|
||||
@@ -88,4 +100,3 @@ void factory_alignment(){
|
||||
updateDisplay();
|
||||
|
||||
}
|
||||
|
@@ -39,6 +39,22 @@ char lastPaddle = 0;
|
||||
|
||||
//reads the analog keyer pin and reports the paddle
|
||||
byte getPaddle(){
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* (1) It uses the PTT input line.
|
||||
*
|
||||
* (2) It's always "straight key" mode (the IOP provides the keyer).
|
||||
*/
|
||||
|
||||
if (digitalRead(PTT) == 1) // key/PTT is up
|
||||
return 0;
|
||||
else
|
||||
return PADDLE_STRAIGHT;
|
||||
|
||||
/*
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
|
||||
if (paddle > 800) // above 4v is up
|
||||
@@ -52,6 +68,7 @@ byte getPaddle(){
|
||||
return PADDLE_BOTH; //both are between 1 and 2v
|
||||
else
|
||||
return PADDLE_STRAIGHT; //less than 1v is the straight key
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,9 +113,20 @@ unsigned char keyerState = IDLE;
|
||||
//Below is a test to reduce the keying error. do not delete lines
|
||||
//create by KD8CEC for compatible with new CW Logic
|
||||
char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* No iambic keyer. It's always "straight key" based on the IOP.
|
||||
*
|
||||
* It uses the PTT line.
|
||||
*/
|
||||
return (digitalRead(PTT) ? 0 : DIT_L);
|
||||
/*
|
||||
unsigned char tmpKeyerControl = 0;
|
||||
int paddle = analogRead(ANALOG_KEYER);
|
||||
|
||||
|
||||
if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
|
||||
tmpKeyerControl |= DAH_L;
|
||||
else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
|
||||
@@ -119,6 +147,7 @@ char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
keyerControl |= tmpKeyerControl;
|
||||
|
||||
return tmpKeyerControl;
|
||||
*/
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -126,106 +155,113 @@ char update_PaddleLatch(byte isUpdateKeyState) {
|
||||
// modified by KD8CEC
|
||||
******************************************************************************/
|
||||
void cwKeyer(void){
|
||||
lastPaddle = 0;
|
||||
bool continue_loop = true;
|
||||
unsigned tmpKeyControl = 0;
|
||||
|
||||
if( Iambic_Key ) {
|
||||
while(continue_loop) {
|
||||
switch (keyerState) {
|
||||
case IDLE:
|
||||
tmpKeyControl = update_PaddleLatch(0);
|
||||
if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
|
||||
tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
|
||||
update_PaddleLatch(1);
|
||||
keyerState = CHK_DIT;
|
||||
}else{
|
||||
if (0 < cwTimeout && cwTimeout < millis()){
|
||||
cwTimeout = 0;
|
||||
stopTx();
|
||||
}
|
||||
continue_loop = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHK_DIT:
|
||||
if (keyerControl & DIT_L) {
|
||||
keyerControl |= DIT_PROC;
|
||||
ktimer = cwSpeed;
|
||||
keyerState = KEYED_PREP;
|
||||
}else{
|
||||
keyerState = CHK_DAH;
|
||||
}
|
||||
break;
|
||||
|
||||
case CHK_DAH:
|
||||
if (keyerControl & DAH_L) {
|
||||
ktimer = cwSpeed*3;
|
||||
keyerState = KEYED_PREP;
|
||||
}else{
|
||||
keyerState = IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEYED_PREP:
|
||||
//modified KD8CEC
|
||||
/*
|
||||
ktimer += millis(); // set ktimer to interval end time
|
||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
keyerState = KEYED; // next state
|
||||
if (!inTx){
|
||||
//DelayTime Option
|
||||
delay_background(delayBeforeCWStartTime * 2, 2);
|
||||
|
||||
keyDown = 0;
|
||||
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
startTx(TX_CW, 1);
|
||||
}
|
||||
*/
|
||||
if (!inTx){
|
||||
//DelayTime Option
|
||||
delay_background(delayBeforeCWStartTime * 2, 2);
|
||||
|
||||
keyDown = 0;
|
||||
cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
startTx(TX_CW, 1);
|
||||
}
|
||||
ktimer += millis(); // set ktimer to interval end time
|
||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
keyerState = KEYED; // next state
|
||||
|
||||
cwKeydown();
|
||||
break;
|
||||
|
||||
case KEYED:
|
||||
if (millis() > ktimer) { // are we at end of key down ?
|
||||
cwKeyUp();
|
||||
ktimer = millis() + cwSpeed; // inter-element time
|
||||
keyerState = INTER_ELEMENT; // next state
|
||||
}else if (keyerControl & IAMBICB) {
|
||||
update_PaddleLatch(1); // early paddle latch in Iambic B mode
|
||||
}
|
||||
break;
|
||||
|
||||
case INTER_ELEMENT:
|
||||
// Insert time between dits/dahs
|
||||
update_PaddleLatch(1); // latch paddle state
|
||||
if (millis() > ktimer) { // are we at end of inter-space ?
|
||||
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
|
||||
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
|
||||
keyerState = CHK_DAH; // dit done, check for dah
|
||||
}else{
|
||||
keyerControl &= ~(DAH_L); // clear dah latch
|
||||
keyerState = IDLE; // go idle
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Check_Cat(2);
|
||||
} //end of while
|
||||
}
|
||||
else{
|
||||
/*
|
||||
* KC4UPR - IOP update, 2020-05-03
|
||||
*
|
||||
* Modifying this for the uBITX IOP. Big picture:
|
||||
*
|
||||
* No iambic keyer. It's always "straight key" based on the IOP.
|
||||
*/
|
||||
// lastPaddle = 0;
|
||||
// bool continue_loop = true;
|
||||
// unsigned tmpKeyControl = 0;
|
||||
//
|
||||
// if( Iambic_Key ) {
|
||||
// while(continue_loop) {
|
||||
// switch (keyerState) {
|
||||
// case IDLE:
|
||||
// tmpKeyControl = update_PaddleLatch(0);
|
||||
// if ( tmpKeyControl == DAH_L || tmpKeyControl == DIT_L ||
|
||||
// tmpKeyControl == (DAH_L | DIT_L) || (keyerControl & 0x03)) {
|
||||
// update_PaddleLatch(1);
|
||||
// keyerState = CHK_DIT;
|
||||
// }else{
|
||||
// if (0 < cwTimeout && cwTimeout < millis()){
|
||||
// cwTimeout = 0;
|
||||
// stopTx();
|
||||
// }
|
||||
// continue_loop = false;
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case CHK_DIT:
|
||||
// if (keyerControl & DIT_L) {
|
||||
// keyerControl |= DIT_PROC;
|
||||
// ktimer = cwSpeed;
|
||||
// keyerState = KEYED_PREP;
|
||||
// }else{
|
||||
// keyerState = CHK_DAH;
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case CHK_DAH:
|
||||
// if (keyerControl & DAH_L) {
|
||||
// ktimer = cwSpeed*3;
|
||||
// keyerState = KEYED_PREP;
|
||||
// }else{
|
||||
// keyerState = IDLE;
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case KEYED_PREP:
|
||||
// //modified KD8CEC
|
||||
// /*
|
||||
// ktimer += millis(); // set ktimer to interval end time
|
||||
// keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
// keyerState = KEYED; // next state
|
||||
// if (!inTx){
|
||||
// //DelayTime Option
|
||||
// delay_background(delayBeforeCWStartTime * 2, 2);
|
||||
//
|
||||
// keyDown = 0;
|
||||
// cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
// startTx(TX_CW, 1);
|
||||
// }
|
||||
// */
|
||||
// if (!inTx){
|
||||
// //DelayTime Option
|
||||
// delay_background(delayBeforeCWStartTime * 2, 2);
|
||||
//
|
||||
// keyDown = 0;
|
||||
// cwTimeout = millis() + cwDelayTime * 10; //+ CW_TIMEOUT;
|
||||
// startTx(TX_CW, 1);
|
||||
// }
|
||||
// ktimer += millis(); // set ktimer to interval end time
|
||||
// keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
// keyerState = KEYED; // next state
|
||||
//
|
||||
// cwKeydown();
|
||||
// break;
|
||||
//
|
||||
// case KEYED:
|
||||
// if (millis() > ktimer) { // are we at end of key down ?
|
||||
// cwKeyUp();
|
||||
// ktimer = millis() + cwSpeed; // inter-element time
|
||||
// keyerState = INTER_ELEMENT; // next state
|
||||
// }else if (keyerControl & IAMBICB) {
|
||||
// update_PaddleLatch(1); // early paddle latch in Iambic B mode
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case INTER_ELEMENT:
|
||||
// // Insert time between dits/dahs
|
||||
// update_PaddleLatch(1); // latch paddle state
|
||||
// if (millis() > ktimer) { // are we at end of inter-space ?
|
||||
// if (keyerControl & DIT_PROC) { // was it a dit or dah ?
|
||||
// keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
|
||||
// keyerState = CHK_DAH; // dit done, check for dah
|
||||
// }else{
|
||||
// keyerControl &= ~(DAH_L); // clear dah latch
|
||||
// keyerState = IDLE; // go idle
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// Check_Cat(2);
|
||||
// } //end of while
|
||||
// }
|
||||
// else{
|
||||
while(1){
|
||||
if (update_PaddleLatch(0) == DIT_L) {
|
||||
// if we are here, it is only because the key is pressed
|
||||
@@ -260,9 +296,9 @@ void cwKeyer(void){
|
||||
return; //Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
Check_Cat(2);
|
||||
//Check_Cat(2);
|
||||
} //end of while
|
||||
} //end of elese
|
||||
// } //end of elese
|
||||
}
|
||||
|
||||
|
||||
@@ -365,5 +401,3 @@ void cwKeyer(){
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
64
Raduino/ubitx_lcd.h
Normal file
64
Raduino/ubitx_lcd.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*************************************************************************
|
||||
header file for LCD by KD8CEC
|
||||
-----------------------------------------------------------------------------
|
||||
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/>.
|
||||
**************************************************************************/
|
||||
#ifndef _UBITX_LCD_HEADER__
|
||||
#define _UBITX_LCD_HEADER__
|
||||
|
||||
//Common Defines *********************************************************
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
// flags for backlight control
|
||||
#define LCD_BACKLIGHT 0x08
|
||||
#define LCD_NOBACKLIGHT 0x00
|
||||
|
||||
#endif //end of if header define
|
||||
|
||||
|
790
Raduino/ubitx_lcd_1602.ino
Normal file
790
Raduino/ubitx_lcd_1602.ino
Normal file
@@ -0,0 +1,790 @@
|
||||
/*************************************************************************
|
||||
KD8CEC's uBITX Display Routine for LCD1602 Parrel
|
||||
1.This is the display code for the default LCD mounted in uBITX.
|
||||
2.Some functions moved from uBITX_Ui.
|
||||
-----------------------------------------------------------------------------
|
||||
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 "ubitx.h"
|
||||
#include "ubitx_lcd.h"
|
||||
|
||||
//========================================================================
|
||||
//Begin of TinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
#ifdef UBITX_DISPLAY_LCD1602P
|
||||
/*************************************************************************
|
||||
LCD1602_TINY Library for 16 x 2 LCD
|
||||
Referecnce Source : LiquidCrystal.cpp
|
||||
KD8CEC
|
||||
|
||||
This source code is modified version for small program memory
|
||||
from Arduino LiquidCrystal Library
|
||||
|
||||
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.
|
||||
DE Ian KD8CEC
|
||||
**************************************************************************/
|
||||
|
||||
#define LCD_Command(x) (LCD_Send(x, LOW))
|
||||
#define LCD_Write(x) (LCD_Send(x, HIGH))
|
||||
|
||||
#define UBITX_DISPLAY_LCD1602_BASE
|
||||
|
||||
//Define connected PIN
|
||||
#define LCD_PIN_RS 8
|
||||
#define LCD_PIN_EN 9
|
||||
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
|
||||
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
|
||||
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(LCD_PIN_EN, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LCD_Send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
digitalWrite(LCD_PIN_RS, mode);
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
|
||||
void LCD1602_Init()
|
||||
{
|
||||
pinMode(LCD_PIN_RS, OUTPUT);
|
||||
pinMode(LCD_PIN_EN, OUTPUT);
|
||||
for (int i = 0; i < 4; i++)
|
||||
pinMode(LCD_PIN_DAT[i], OUTPUT);
|
||||
|
||||
delayMicroseconds(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(LCD_PIN_RS, LOW);
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
}
|
||||
|
||||
#endif
|
||||
//========================================================================
|
||||
//End of TinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
|
||||
//========================================================================
|
||||
//Begin of I2CTinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
#ifdef UBITX_DISPLAY_LCD1602I
|
||||
#include <Wire.h>
|
||||
/*************************************************************************
|
||||
I2C Tiny LCD Library
|
||||
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
|
||||
KD8CEC
|
||||
|
||||
This source code is modified version for small program memory
|
||||
from Arduino LiquidCrystal_I2C Library
|
||||
|
||||
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.
|
||||
Ian KD8CEC
|
||||
**************************************************************************/
|
||||
#define UBITX_DISPLAY_LCD1602_BASE
|
||||
|
||||
#define En B00000100 // Enable bit
|
||||
#define Rw B00000010 // Read/Write bit
|
||||
#define Rs B00000001 // Register select bit
|
||||
|
||||
#define LCD_Command(x) (LCD_Send(x, 0))
|
||||
#define LCD_Write(x) (LCD_Send(x, Rs))
|
||||
|
||||
uint8_t _Addr;
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
|
||||
#define printIIC(args) Wire.write(args)
|
||||
|
||||
void expanderWrite(uint8_t _data)
|
||||
{
|
||||
Wire.beginTransmission(_Addr);
|
||||
printIIC((int)(_data) | _backlightval);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void pulseEnable(uint8_t _data){
|
||||
expanderWrite(_data | En); // En high
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
|
||||
expanderWrite(_data & ~En); // En low
|
||||
delayMicroseconds(50); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
expanderWrite(value);
|
||||
pulseEnable(value);
|
||||
}
|
||||
|
||||
void LCD_Send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
uint8_t highnib=value&0xf0;
|
||||
uint8_t lownib=(value<<4)&0xf0;
|
||||
write4bits((highnib)|mode);
|
||||
write4bits((lownib)|mode);
|
||||
}
|
||||
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void noBacklight(void) {
|
||||
_backlightval=LCD_NOBACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void backlight(void) {
|
||||
_backlightval=LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void LCD1602_Init()
|
||||
{
|
||||
//I2C Init
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
_cols = 16;
|
||||
_rows = 2;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
Wire.begin();
|
||||
|
||||
delay(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
||||
delay(1000);
|
||||
//put the LCD into 4 bit mode
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
//delayMicroseconds(2000); // this command takes a long time!
|
||||
delayMicroseconds(1000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
|
||||
backlight();
|
||||
}
|
||||
|
||||
/*
|
||||
void LCD_Print(const char *c)
|
||||
{
|
||||
for (uint8_t i = 0; i < strlen(c); i++)
|
||||
{
|
||||
if (*(c + i) == 0x00) return;
|
||||
LCD_Write(*(c + i));
|
||||
}
|
||||
}
|
||||
|
||||
void LCD_SetCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
|
||||
}
|
||||
|
||||
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
|
||||
{
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++)
|
||||
LCD_Write(charmap[i]);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
//========================================================================
|
||||
//End of I2CTinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
|
||||
//========================================================================
|
||||
// 16 X 02 LCD Routines
|
||||
//Begin of Display Base Routines (Init, printLine..)
|
||||
//========================================================================
|
||||
#ifdef UBITX_DISPLAY_LCD1602_BASE
|
||||
|
||||
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
|
||||
#define OPTION_SKINNYBARS
|
||||
|
||||
char c[30], b[30];
|
||||
char printBuff[2][17]; //mirrors what is showing on the two lines of the display
|
||||
|
||||
|
||||
void LCD_Print(const char *c)
|
||||
{
|
||||
for (uint8_t i = 0; i < strlen(c); i++)
|
||||
{
|
||||
if (*(c + i) == 0x00) return;
|
||||
LCD_Write(*(c + i));
|
||||
}
|
||||
}
|
||||
|
||||
void LCD_SetCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
|
||||
}
|
||||
|
||||
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
|
||||
{
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++)
|
||||
LCD_Write(charmap[i]);
|
||||
}
|
||||
|
||||
void LCD_Init(void)
|
||||
{
|
||||
LCD1602_Init();
|
||||
initMeter(); //for Meter Display
|
||||
}
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(unsigned char linenmbr, const char *c) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
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_Write(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, char offsetTtype) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
|
||||
LCD_SetCursor(lcdColumn, linenmbr);
|
||||
|
||||
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
|
||||
{
|
||||
if (++lcdColumn <= LCD_MAX_COLUMN)
|
||||
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + 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(const char *c)
|
||||
{
|
||||
printLine(1,c);
|
||||
}
|
||||
// short cut to print to the first line
|
||||
void printLine2(const char *c)
|
||||
{
|
||||
printLine(0,c);
|
||||
}
|
||||
|
||||
void clearLine2()
|
||||
{
|
||||
printLine2("");
|
||||
line2DisplayStatus = 0;
|
||||
}
|
||||
|
||||
// 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, "");
|
||||
line2DisplayStatus = 0;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
//End of Display Base Routines
|
||||
//==================================================================================
|
||||
|
||||
|
||||
//==================================================================================
|
||||
//Begin of User Interface Routines
|
||||
//==================================================================================
|
||||
|
||||
//Main Display
|
||||
// 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 (cwMode == 0)
|
||||
{
|
||||
if (isUSB)
|
||||
strcpy(c, "USB ");
|
||||
else
|
||||
strcpy(c, "LSB ");
|
||||
}
|
||||
else if (cwMode == 1)
|
||||
{
|
||||
strcpy(c, "CWL ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(c, "CWU ");
|
||||
}
|
||||
}
|
||||
if (vfoActive == VFO_A) // VFO A is active
|
||||
strcat(c, "A:");
|
||||
else
|
||||
strcat(c, "B:");
|
||||
}
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
byte diplayVFOLine = 1;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayVFOLine = 0;
|
||||
|
||||
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
|
||||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write((uint8_t)0);
|
||||
}
|
||||
else if (isCWAutoMode == 2){
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(0x7E);
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(':');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char line2Buffer[17];
|
||||
//KD8CEC 200Hz ST
|
||||
//L14.150 200Hz ST
|
||||
//U14.150 +150khz
|
||||
int freqScrollPosition = 0;
|
||||
|
||||
//Example Line2 Optinal Display
|
||||
//immediate execution, not call by scheulder
|
||||
//warning : unused parameter 'displayType' <-- ignore, this is reserve
|
||||
void updateLine2Buffer(char displayType)
|
||||
{
|
||||
unsigned long tmpFreq = 0;
|
||||
if (ritOn)
|
||||
{
|
||||
strcpy(line2Buffer, "RitTX:");
|
||||
|
||||
//display frequency
|
||||
tmpFreq = ritTxFrequency;
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
for (int i = 15; i >= 6; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 12 || i == 8) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
return;
|
||||
} //end of ritOn display
|
||||
|
||||
//other VFO display
|
||||
if (vfoActive == VFO_B)
|
||||
{
|
||||
tmpFreq = vfoA;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpFreq = vfoB;
|
||||
}
|
||||
|
||||
// EXAMPLE 1 & 2
|
||||
//U14.150.100
|
||||
//display frequency
|
||||
for (int i = 9; i >= 0; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 2 || i == 6) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
//EXAMPLE #1
|
||||
if ((displayOption1 & 0x04) == 0x00) //none scroll display
|
||||
line2Buffer[6] = 'M';
|
||||
else
|
||||
{
|
||||
//example #2
|
||||
if (freqScrollPosition++ > 18) //none scroll display time
|
||||
{
|
||||
line2Buffer[6] = 'M';
|
||||
if (freqScrollPosition > 25)
|
||||
freqScrollPosition = -1;
|
||||
}
|
||||
else //scroll frequency
|
||||
{
|
||||
line2Buffer[10] = 'H';
|
||||
line2Buffer[11] = 'z';
|
||||
|
||||
if (freqScrollPosition < 7)
|
||||
{
|
||||
for (int i = 11; i >= 0; i--)
|
||||
if (i - (7 - freqScrollPosition) >= 0)
|
||||
line2Buffer[i] = line2Buffer[i - (7 - freqScrollPosition)];
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 11; i++)
|
||||
if (i + (freqScrollPosition - 7) <= 11)
|
||||
line2Buffer[i] = line2Buffer[i + (freqScrollPosition - 7)];
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
} //scroll
|
||||
|
||||
line2Buffer[7] = ' ';
|
||||
|
||||
if (isIFShift)
|
||||
{
|
||||
// if (isDirectCall == 1)
|
||||
// for (int i = 0; i < 16; i++)
|
||||
// line2Buffer[i] = ' ';
|
||||
|
||||
//IFShift Offset Value
|
||||
line2Buffer[8] = 'I';
|
||||
line2Buffer[9] = 'F';
|
||||
|
||||
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
|
||||
line2Buffer[11] = 0;
|
||||
line2Buffer[12] = ' ';
|
||||
|
||||
//11, 12, 13, 14, 15
|
||||
memset(b, 0, sizeof(b));
|
||||
ltoa(ifShiftValue, b, DEC);
|
||||
strncat(line2Buffer, b, 5);
|
||||
|
||||
//if (isDirectCall == 1) //if call by encoder (not scheduler), immediate print value
|
||||
printLine2(line2Buffer);
|
||||
} // end of display IF
|
||||
else // step & Key Type display
|
||||
{
|
||||
//if (isDirectCall != 0)
|
||||
// return;
|
||||
|
||||
memset(&line2Buffer[8], ' ', 8);
|
||||
//Step
|
||||
long tmpStep = arTuneStep[tuneStepIndex -1];
|
||||
|
||||
byte isStepKhz = 0;
|
||||
if (tmpStep >= 1000)
|
||||
{
|
||||
isStepKhz = 2;
|
||||
}
|
||||
|
||||
for (int i = 10; i >= 8 - isStepKhz; i--) {
|
||||
if (tmpStep > 0) {
|
||||
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
|
||||
tmpStep /= 10;
|
||||
}
|
||||
else
|
||||
line2Buffer[i +isStepKhz] = ' ';
|
||||
}
|
||||
|
||||
if (isStepKhz == 0)
|
||||
{
|
||||
line2Buffer[11] = 'H';
|
||||
line2Buffer[12] = 'z';
|
||||
}
|
||||
|
||||
line2Buffer[13] = ' ';
|
||||
|
||||
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
if (sdrModeOn == 1)
|
||||
{
|
||||
line2Buffer[13] = 'S';
|
||||
line2Buffer[14] = 'D';
|
||||
line2Buffer[15] = 'R';
|
||||
}
|
||||
else if (cwKeyType == 0)
|
||||
{
|
||||
line2Buffer[14] = 'S';
|
||||
line2Buffer[15] = 'T';
|
||||
}
|
||||
else if (cwKeyType == 1)
|
||||
{
|
||||
line2Buffer[14] = 'I';
|
||||
line2Buffer[15] = 'A';
|
||||
}
|
||||
else
|
||||
{
|
||||
line2Buffer[14] = 'I';
|
||||
line2Buffer[15] = 'B';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//meterType : 0 = S.Meter, 1 : P.Meter
|
||||
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
|
||||
{
|
||||
if (meterType == 0 || meterType == 1 || meterType == 2)
|
||||
{
|
||||
drawMeter(meterValue);
|
||||
int lineNumber = 0;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
lineNumber = 1;
|
||||
|
||||
LCD_SetCursor(drawPosition, lineNumber);
|
||||
|
||||
LCD_Write(lcdMeter[0]);
|
||||
LCD_Write(lcdMeter[1]);
|
||||
LCD_Write(lcdMeter[2]);
|
||||
}
|
||||
}
|
||||
|
||||
char checkCount = 0;
|
||||
char checkCountSMeter = 0;
|
||||
|
||||
void idle_process()
|
||||
{
|
||||
//space for user graphic display
|
||||
if (menuOn == 0)
|
||||
{
|
||||
if ((displayOption1 & 0x10) == 0x10) //always empty topline
|
||||
return;
|
||||
|
||||
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
|
||||
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
|
||||
if (checkCount++ > 1)
|
||||
{
|
||||
updateLine2Buffer(0); //call by scheduler
|
||||
printLine2(line2Buffer);
|
||||
line2DisplayStatus = 2;
|
||||
checkCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//S-Meter Display
|
||||
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
|
||||
{
|
||||
int newSMeter;
|
||||
|
||||
#ifdef USE_I2CSMETER
|
||||
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
|
||||
#else
|
||||
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
|
||||
newSMeter = analogRead(ANALOG_SMETER) / 4;
|
||||
|
||||
//Faster attack, Slower release
|
||||
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10) / 4;
|
||||
currentSMeter = newSMeter;
|
||||
|
||||
scaledSMeter = 0;
|
||||
for (byte s = 8; s >= 1; s--) {
|
||||
if (currentSMeter > sMeterLevels[s]) {
|
||||
scaledSMeter = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DisplayMeter(0, scaledSMeter, 13);
|
||||
checkCountSMeter = 0; //Reset Latency time
|
||||
} //end of S-Meter
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//AutoKey LCD Display Routine
|
||||
void Display_AutoKeyTextIndex(byte textIndex)
|
||||
{
|
||||
byte diplayAutoCWLine = 0;
|
||||
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayAutoCWLine = 1;
|
||||
LCD_SetCursor(0, diplayAutoCWLine);
|
||||
LCD_Write(byteToChar(textIndex));
|
||||
LCD_Write(':');
|
||||
}
|
||||
|
||||
void DisplayCallsign(byte callSignLength)
|
||||
{
|
||||
printLineFromEEPRom(0, 0, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
|
||||
//delay(500);
|
||||
}
|
||||
|
||||
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
|
||||
{
|
||||
printLineF(1, fwVersionInfo);
|
||||
}
|
||||
|
||||
#endif
|
727
Raduino/ubitx_lcd_1602Dual.ino
Normal file
727
Raduino/ubitx_lcd_1602Dual.ino
Normal file
@@ -0,0 +1,727 @@
|
||||
/*************************************************************************
|
||||
KD8CEC's uBITX Display Routine for LCD1602 Dual LCD
|
||||
1.This is the display code for the 16x02 Dual LCD
|
||||
2.Some functions moved from uBITX_Ui.
|
||||
-----------------------------------------------------------------------------
|
||||
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 "ubitx.h"
|
||||
#include "ubitx_lcd.h"
|
||||
|
||||
//========================================================================
|
||||
//Begin of I2CTinyLCD Library for Dual LCD by KD8CEC
|
||||
//========================================================================
|
||||
#ifdef UBITX_DISPLAY_LCD1602I_DUAL
|
||||
|
||||
#include <Wire.h>
|
||||
/*************************************************************************
|
||||
I2C Tiny LCD Library
|
||||
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
|
||||
KD8CEC
|
||||
|
||||
This source code is modified version for small program memory
|
||||
from Arduino LiquidCrystal_I2C Library
|
||||
|
||||
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.
|
||||
Ian KD8CEC
|
||||
**************************************************************************/
|
||||
#define UBITX_DISPLAY_LCD1602_BASE
|
||||
|
||||
#define En B00000100 // Enable bit
|
||||
#define Rw B00000010 // Read/Write bit
|
||||
#define Rs B00000001 // Register select bit
|
||||
|
||||
#define LCD_Command(x) (LCD_Send(x, 0))
|
||||
#define LCD_Write(x) (LCD_Send(x, Rs))
|
||||
|
||||
uint8_t _Addr;
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
|
||||
#define printIIC(args) Wire.write(args)
|
||||
|
||||
void expanderWrite(uint8_t _data)
|
||||
{
|
||||
Wire.beginTransmission(_Addr);
|
||||
printIIC((int)(_data) | _backlightval);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void pulseEnable(uint8_t _data){
|
||||
expanderWrite(_data | En); // En high
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
|
||||
expanderWrite(_data & ~En); // En low
|
||||
delayMicroseconds(50); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
expanderWrite(value);
|
||||
pulseEnable(value);
|
||||
}
|
||||
|
||||
void LCD_Send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
uint8_t highnib=value&0xf0;
|
||||
uint8_t lownib=(value<<4)&0xf0;
|
||||
write4bits((highnib)|mode);
|
||||
write4bits((lownib)|mode);
|
||||
}
|
||||
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void noBacklight(void) {
|
||||
_backlightval=LCD_NOBACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void backlight(void) {
|
||||
_backlightval=LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void LCD1602_Dual_Init()
|
||||
{
|
||||
//I2C Init
|
||||
_cols = 16;
|
||||
_rows = 2;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
Wire.begin();
|
||||
|
||||
delay(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
||||
delay(1000);
|
||||
//put the LCD into 4 bit mode
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
//delayMicroseconds(2000); // this command takes a long time!
|
||||
delayMicroseconds(1000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
|
||||
backlight();
|
||||
|
||||
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
//delayMicroseconds(2000); // this command takes a long time!
|
||||
delayMicroseconds(1000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
|
||||
backlight();
|
||||
|
||||
//Change to Default LCD (Master)
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// 16 X 02 LCD Routines
|
||||
//Begin of Display Base Routines (Init, printLine..)
|
||||
//========================================================================
|
||||
|
||||
void LCD_Print(const char *c)
|
||||
{
|
||||
for (uint8_t i = 0; i < strlen(c); i++)
|
||||
{
|
||||
if (*(c + i) == 0x00) return;
|
||||
LCD_Write(*(c + i));
|
||||
}
|
||||
}
|
||||
|
||||
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
void LCD_SetCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
|
||||
}
|
||||
|
||||
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
|
||||
{
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++)
|
||||
LCD_Write(charmap[i]);
|
||||
}
|
||||
|
||||
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
|
||||
//#define OPTION_SKINNYBARS
|
||||
|
||||
char c[30], b[30];
|
||||
char printBuff[4][20]; //mirrors what is showing on the two lines of the display
|
||||
|
||||
void LCD_Init(void)
|
||||
{
|
||||
LCD1602_Dual_Init();
|
||||
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
initMeter(); //for Meter Display //when dual LCD, S.Meter on second LCD
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(unsigned char linenmbr, const char *c) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
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 < 20; i++) { // add white spaces until the end of the 20 characters line is reached
|
||||
LCD_Write(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printLineF(char linenmbr, const __FlashStringHelper *c)
|
||||
{
|
||||
int i;
|
||||
char tmpBuff[21];
|
||||
PGM_P p = reinterpret_cast<PGM_P>(c);
|
||||
|
||||
for (i = 0; i < 21; i++){
|
||||
unsigned char fChar = pgm_read_byte(p++);
|
||||
tmpBuff[i] = fChar;
|
||||
if (fChar == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
printLine(linenmbr, tmpBuff);
|
||||
}
|
||||
|
||||
#define LCD_MAX_COLUMN 20
|
||||
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
|
||||
LCD_SetCursor(lcdColumn, linenmbr);
|
||||
|
||||
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
|
||||
{
|
||||
if (++lcdColumn <= LCD_MAX_COLUMN)
|
||||
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
|
||||
LCD_Write(' ');
|
||||
}
|
||||
|
||||
// short cut to print to the first line
|
||||
void printLine1(const char *c)
|
||||
{
|
||||
printLine(1,c);
|
||||
}
|
||||
// short cut to print to the first line
|
||||
void printLine2(const char *c)
|
||||
{
|
||||
printLine(0,c);
|
||||
}
|
||||
|
||||
void clearLine2()
|
||||
{
|
||||
printLine2("");
|
||||
line2DisplayStatus = 0;
|
||||
}
|
||||
|
||||
// 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, "");
|
||||
line2DisplayStatus = 0;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
//End of Display Base Routines
|
||||
//==================================================================================
|
||||
|
||||
|
||||
//==================================================================================
|
||||
//Begin of User Interface Routines
|
||||
//==================================================================================
|
||||
|
||||
//Main Display
|
||||
// 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
|
||||
// i also Very TNX Purdum for good source code
|
||||
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 (cwMode == 0)
|
||||
{
|
||||
if (isUSB)
|
||||
strcpy(c, "USB ");
|
||||
else
|
||||
strcpy(c, "LSB ");
|
||||
}
|
||||
else if (cwMode == 1)
|
||||
{
|
||||
strcpy(c, "CWL ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(c, "CWU ");
|
||||
}
|
||||
}
|
||||
|
||||
if (vfoActive == VFO_A) // VFO A is active
|
||||
strcat(c, "A:");
|
||||
else
|
||||
strcat(c, "B:");
|
||||
}
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
//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)
|
||||
printLine(1, c);
|
||||
|
||||
byte diplayVFOLine = 1;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayVFOLine = 0;
|
||||
|
||||
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
|
||||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write((uint8_t)0);
|
||||
}
|
||||
else if (isCWAutoMode == 2){
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(0x7E);
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(':');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char line2Buffer[20];
|
||||
//KD8CEC 200Hz ST
|
||||
//L14.150 200Hz ST
|
||||
//U14.150 +150khz
|
||||
int freqScrollPosition = 0;
|
||||
|
||||
//Example Line2 Optinal Display
|
||||
//immediate execution, not call by scheulder
|
||||
//warning : unused parameter 'displayType' <-- ignore, this is reserve
|
||||
void updateLine2Buffer(char displayType)
|
||||
{
|
||||
unsigned long tmpFreq = 0;
|
||||
if (ritOn)
|
||||
{
|
||||
strcpy(line2Buffer, "RitTX:");
|
||||
|
||||
//display frequency
|
||||
tmpFreq = ritTxFrequency;
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
for (int i = 15; i >= 6; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 12 || i == 8) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
return;
|
||||
} //end of ritOn display
|
||||
|
||||
//other VFO display
|
||||
if (vfoActive == VFO_B)
|
||||
{
|
||||
tmpFreq = vfoA;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpFreq = vfoB;
|
||||
}
|
||||
|
||||
// EXAMPLE 1 & 2
|
||||
//U14.150.100
|
||||
//display frequency
|
||||
for (int i = 9; i >= 0; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 2 || i == 6) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
memset(&line2Buffer[10], ' ', 10);
|
||||
|
||||
if (isIFShift)
|
||||
{
|
||||
line2Buffer[6] = 'M';
|
||||
line2Buffer[7] = ' ';
|
||||
//IFShift Offset Value
|
||||
line2Buffer[8] = 'I';
|
||||
line2Buffer[9] = 'F';
|
||||
|
||||
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
|
||||
line2Buffer[11] = 0;
|
||||
line2Buffer[12] = ' ';
|
||||
|
||||
//11, 12, 13, 14, 15
|
||||
memset(b, 0, sizeof(b));
|
||||
ltoa(ifShiftValue, b, DEC);
|
||||
strncat(line2Buffer, b, 5);
|
||||
|
||||
for (int i = 12; i < 17; i++)
|
||||
{
|
||||
if (line2Buffer[i] == 0)
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
} // end of display IF
|
||||
else // step & Key Type display
|
||||
{
|
||||
//Step
|
||||
long tmpStep = arTuneStep[tuneStepIndex -1];
|
||||
|
||||
byte isStepKhz = 0;
|
||||
if (tmpStep >= 1000)
|
||||
{
|
||||
isStepKhz = 2;
|
||||
}
|
||||
|
||||
for (int i = 13; i >= 11 - isStepKhz; i--) {
|
||||
if (tmpStep > 0) {
|
||||
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
|
||||
tmpStep /= 10;
|
||||
}
|
||||
else
|
||||
line2Buffer[i +isStepKhz] = ' ';
|
||||
}
|
||||
|
||||
if (isStepKhz == 0)
|
||||
{
|
||||
line2Buffer[14] = 'H';
|
||||
line2Buffer[15] = 'z';
|
||||
}
|
||||
}
|
||||
|
||||
//line2Buffer[17] = ' ';
|
||||
/* ianlee
|
||||
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
if (cwKeyType == 0)
|
||||
{
|
||||
line2Buffer[18] = 'S';
|
||||
line2Buffer[19] = 'T';
|
||||
}
|
||||
else if (cwKeyType == 1)
|
||||
{
|
||||
line2Buffer[18] = 'I';
|
||||
line2Buffer[19] = 'A';
|
||||
}
|
||||
else
|
||||
{
|
||||
line2Buffer[18] = 'I';
|
||||
line2Buffer[19] = 'B';
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
//meterType : 0 = S.Meter, 1 : P.Meter
|
||||
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
|
||||
{
|
||||
if (meterType == 0 || meterType == 1 || meterType == 2)
|
||||
{
|
||||
drawMeter(meterValue);
|
||||
|
||||
LCD_SetCursor(drawPosition, 0);
|
||||
LCD_Write('S');
|
||||
|
||||
LCD_Write(':');
|
||||
for (int i = 0; i < 7; i++)
|
||||
LCD_Write(lcdMeter[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char checkCount = 0;
|
||||
char checkCountSMeter = 0;
|
||||
|
||||
char beforeKeyType = -1;
|
||||
char displaySDRON = 0;
|
||||
|
||||
//execute interval : 0.25sec
|
||||
void idle_process()
|
||||
{
|
||||
//space for user graphic display
|
||||
if (menuOn == 0)
|
||||
{
|
||||
if ((displayOption1 & 0x10) == 0x10) //always empty topline
|
||||
return;
|
||||
|
||||
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
|
||||
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
|
||||
if (checkCount++ > 1)
|
||||
{
|
||||
updateLine2Buffer(0); //call by scheduler
|
||||
printLine2(line2Buffer);
|
||||
line2DisplayStatus = 2;
|
||||
checkCount = 0;
|
||||
|
||||
//check change CW Key Type
|
||||
if (beforeKeyType != cwKeyType)
|
||||
{
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
LCD_SetCursor(10, 0);
|
||||
LCD_Write('K');
|
||||
LCD_Write('E');
|
||||
LCD_Write('Y');
|
||||
LCD_Write(':');
|
||||
|
||||
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
if (cwKeyType == 0)
|
||||
{
|
||||
LCD_Write('S');
|
||||
LCD_Write('T');
|
||||
}
|
||||
else if (cwKeyType == 1)
|
||||
{
|
||||
LCD_Write('I');
|
||||
LCD_Write('A');
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_Write('I');
|
||||
LCD_Write('B');
|
||||
}
|
||||
|
||||
beforeKeyType = cwKeyType;
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
} //Display Second Screen
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//EX for Meters
|
||||
|
||||
//S-Meter Display
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
if (sdrModeOn == 1)
|
||||
{
|
||||
if (displaySDRON == 0) //once display
|
||||
{
|
||||
displaySDRON = 1;
|
||||
LCD_SetCursor(0, 0);
|
||||
LCD_Write('S');
|
||||
LCD_Write('D');
|
||||
LCD_Write('R');
|
||||
LCD_Write(' ');
|
||||
LCD_Write('M');
|
||||
LCD_Write('O');
|
||||
LCD_Write('D');
|
||||
LCD_Write('E');
|
||||
}
|
||||
}
|
||||
else if (((displayOption1 & 0x08) == 0x08) && (++checkCountSMeter > 3))
|
||||
{
|
||||
int newSMeter;
|
||||
displaySDRON = 0;
|
||||
|
||||
#ifdef USE_I2CSMETER
|
||||
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
|
||||
#else
|
||||
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
|
||||
newSMeter = analogRead(ANALOG_SMETER) / 4;
|
||||
|
||||
//Faster attack, Slower release
|
||||
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
|
||||
//currentSMeter = (currentSMeter * 3 + newSMeter * 7) / 10; //remarked becaused of have already Latency time
|
||||
currentSMeter = newSMeter;
|
||||
|
||||
scaledSMeter = 0;
|
||||
for (byte s = 8; s >= 1; s--) {
|
||||
if (currentSMeter > sMeterLevels[s]) {
|
||||
scaledSMeter = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DisplayMeter(0, scaledSMeter, 0);
|
||||
checkCountSMeter = 0;
|
||||
} //end of S-Meter
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//AutoKey LCD Display Routine
|
||||
void Display_AutoKeyTextIndex(byte textIndex)
|
||||
{
|
||||
byte diplayAutoCWLine = 0;
|
||||
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayAutoCWLine = 1;
|
||||
LCD_SetCursor(0, diplayAutoCWLine);
|
||||
LCD_Write(byteToChar(textIndex));
|
||||
LCD_Write(':');
|
||||
}
|
||||
|
||||
void DisplayCallsign(byte callSignLength)
|
||||
{
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
printLineFromEEPRom(1, 16 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
}
|
||||
|
||||
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
|
||||
{
|
||||
_Addr = I2C_LCD_SECOND_ADDRESS;
|
||||
printLineF(1, fwVersionInfo);
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
}
|
||||
|
||||
#endif
|
743
Raduino/ubitx_lcd_2004.ino
Normal file
743
Raduino/ubitx_lcd_2004.ino
Normal file
@@ -0,0 +1,743 @@
|
||||
/*************************************************************************
|
||||
KD8CEC's uBITX Display Routine for LCD2004 Parrel & I2C
|
||||
1.This is the display code for the 20x04 LCD
|
||||
2.Some functions moved from uBITX_Ui.
|
||||
-----------------------------------------------------------------------------
|
||||
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 "ubitx.h"
|
||||
#include "ubitx_lcd.h"
|
||||
|
||||
//========================================================================
|
||||
//Begin of TinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
#ifdef UBITX_DISPLAY_LCD2004P
|
||||
/*************************************************************************
|
||||
LCD2004TINY Library for 20 x 4 LCD
|
||||
Referecnce Source : LiquidCrystal.cpp
|
||||
KD8CEC
|
||||
|
||||
This source code is modified version for small program memory
|
||||
from Arduino LiquidCrystal Library
|
||||
|
||||
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.
|
||||
DE Ian KD8CEC
|
||||
**************************************************************************/
|
||||
#define LCD_Command(x) (LCD_Send(x, LOW))
|
||||
#define LCD_Write(x) (LCD_Send(x, HIGH))
|
||||
|
||||
#define UBITX_DISPLAY_LCD2004_BASE
|
||||
|
||||
//Define connected PIN
|
||||
#define LCD_PIN_RS 8
|
||||
#define LCD_PIN_EN 9
|
||||
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
|
||||
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
|
||||
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(LCD_PIN_EN, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LCD_Send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
digitalWrite(LCD_PIN_RS, mode);
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
|
||||
void LCD2004_Init()
|
||||
{
|
||||
pinMode(LCD_PIN_RS, OUTPUT);
|
||||
pinMode(LCD_PIN_EN, OUTPUT);
|
||||
for (int i = 0; i < 4; i++)
|
||||
pinMode(LCD_PIN_DAT[i], OUTPUT);
|
||||
|
||||
delayMicroseconds(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(LCD_PIN_RS, LOW);
|
||||
digitalWrite(LCD_PIN_EN, LOW);
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
}
|
||||
#endif
|
||||
//========================================================================
|
||||
//End of TinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
|
||||
|
||||
//========================================================================
|
||||
//Begin of I2CTinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
#ifdef UBITX_DISPLAY_LCD2004I
|
||||
|
||||
#include <Wire.h>
|
||||
/*************************************************************************
|
||||
I2C Tiny LCD Library
|
||||
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
|
||||
KD8CEC
|
||||
|
||||
This source code is modified version for small program memory
|
||||
from Arduino LiquidCrystal_I2C Library
|
||||
|
||||
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.
|
||||
Ian KD8CEC
|
||||
**************************************************************************/
|
||||
#define UBITX_DISPLAY_LCD2004_BASE
|
||||
|
||||
#define En B00000100 // Enable bit
|
||||
#define Rw B00000010 // Read/Write bit
|
||||
#define Rs B00000001 // Register select bit
|
||||
|
||||
#define LCD_Command(x) (LCD_Send(x, 0))
|
||||
#define LCD_Write(x) (LCD_Send(x, Rs))
|
||||
|
||||
uint8_t _Addr;
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
uint8_t _numlines;
|
||||
uint8_t _cols;
|
||||
uint8_t _rows;
|
||||
uint8_t _backlightval;
|
||||
|
||||
#define printIIC(args) Wire.write(args)
|
||||
|
||||
void expanderWrite(uint8_t _data)
|
||||
{
|
||||
Wire.beginTransmission(_Addr);
|
||||
printIIC((int)(_data) | _backlightval);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
void pulseEnable(uint8_t _data){
|
||||
expanderWrite(_data | En); // En high
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
|
||||
expanderWrite(_data & ~En); // En low
|
||||
delayMicroseconds(50); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void write4bits(uint8_t value)
|
||||
{
|
||||
expanderWrite(value);
|
||||
pulseEnable(value);
|
||||
}
|
||||
|
||||
void LCD_Send(uint8_t value, uint8_t mode)
|
||||
{
|
||||
uint8_t highnib=value&0xf0;
|
||||
uint8_t lownib=(value<<4)&0xf0;
|
||||
write4bits((highnib)|mode);
|
||||
write4bits((lownib)|mode);
|
||||
}
|
||||
|
||||
|
||||
// Turn the (optional) backlight off/on
|
||||
void noBacklight(void) {
|
||||
_backlightval=LCD_NOBACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void backlight(void) {
|
||||
_backlightval=LCD_BACKLIGHT;
|
||||
expanderWrite(0);
|
||||
}
|
||||
|
||||
void LCD2004_Init()
|
||||
{
|
||||
//I2C Init
|
||||
_Addr = I2C_LCD_MASTER_ADDRESS;
|
||||
_cols = 20;
|
||||
_rows = 4;
|
||||
_backlightval = LCD_NOBACKLIGHT;
|
||||
Wire.begin();
|
||||
|
||||
delay(50);
|
||||
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
||||
delay(1000);
|
||||
//put the LCD into 4 bit mode
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03 << 4);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02 << 4);
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
|
||||
|
||||
// clear it off
|
||||
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
//delayMicroseconds(2000); // this command takes a long time!
|
||||
delayMicroseconds(1000); // this command takes a long time!
|
||||
|
||||
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
|
||||
|
||||
backlight();
|
||||
}
|
||||
#endif
|
||||
//========================================================================
|
||||
//End of I2CTinyLCD Library by KD8CEC
|
||||
//========================================================================
|
||||
|
||||
|
||||
//========================================================================
|
||||
// 20 X 04 LCD Routines
|
||||
//Begin of Display Base Routines (Init, printLine..)
|
||||
//========================================================================
|
||||
#ifdef UBITX_DISPLAY_LCD2004_BASE
|
||||
|
||||
void LCD_Print(const char *c)
|
||||
{
|
||||
for (uint8_t i = 0; i < strlen(c); i++)
|
||||
{
|
||||
if (*(c + i) == 0x00) return;
|
||||
LCD_Write(*(c + i));
|
||||
}
|
||||
}
|
||||
|
||||
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
void LCD_SetCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
|
||||
}
|
||||
|
||||
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
|
||||
{
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++)
|
||||
LCD_Write(charmap[i]);
|
||||
}
|
||||
|
||||
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
|
||||
//#define OPTION_SKINNYBARS
|
||||
|
||||
char c[30], b[30];
|
||||
char printBuff[4][21]; //mirrors what is showing on the two lines of the display
|
||||
|
||||
void LCD_Init(void)
|
||||
{
|
||||
LCD2004_Init();
|
||||
initMeter(); //for Meter Display
|
||||
}
|
||||
|
||||
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(unsigned char linenmbr, const char *c) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
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 < 20; i++) { // add white spaces until the end of the 20 characters line is reached
|
||||
LCD_Write(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printLineF(char linenmbr, const __FlashStringHelper *c)
|
||||
{
|
||||
int i;
|
||||
char tmpBuff[21];
|
||||
PGM_P p = reinterpret_cast<PGM_P>(c);
|
||||
|
||||
for (i = 0; i < 21; i++){
|
||||
unsigned char fChar = pgm_read_byte(p++);
|
||||
tmpBuff[i] = fChar;
|
||||
if (fChar == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
printLine(linenmbr, tmpBuff);
|
||||
}
|
||||
|
||||
#define LCD_MAX_COLUMN 20
|
||||
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
|
||||
LCD_SetCursor(lcdColumn, linenmbr);
|
||||
|
||||
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
|
||||
{
|
||||
if (++lcdColumn <= LCD_MAX_COLUMN)
|
||||
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
|
||||
LCD_Write(' ');
|
||||
}
|
||||
|
||||
// short cut to print to the first line
|
||||
void printLine1(const char *c)
|
||||
{
|
||||
printLine(1,c);
|
||||
}
|
||||
// short cut to print to the first line
|
||||
void printLine2(const char *c)
|
||||
{
|
||||
printLine(0,c);
|
||||
}
|
||||
|
||||
void clearLine2()
|
||||
{
|
||||
printLine2("");
|
||||
line2DisplayStatus = 0;
|
||||
}
|
||||
|
||||
// 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, "");
|
||||
line2DisplayStatus = 0;
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
//==================================================================================
|
||||
//End of Display Base Routines
|
||||
//==================================================================================
|
||||
|
||||
|
||||
//==================================================================================
|
||||
//Begin of User Interface Routines
|
||||
//==================================================================================
|
||||
|
||||
//Main Display
|
||||
// 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
|
||||
// i also Very TNX Purdum for good source code
|
||||
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 (cwMode == 0)
|
||||
{
|
||||
if (isUSB)
|
||||
strcpy(c, "USB ");
|
||||
else
|
||||
strcpy(c, "LSB ");
|
||||
}
|
||||
else if (cwMode == 1)
|
||||
{
|
||||
strcpy(c, "CWL ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(c, "CWU ");
|
||||
}
|
||||
}
|
||||
|
||||
if (vfoActive == VFO_A) // VFO A is active
|
||||
strcat(c, "A:");
|
||||
else
|
||||
strcat(c, "B:");
|
||||
}
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
//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] = ' ';
|
||||
}
|
||||
|
||||
if (sdrModeOn)
|
||||
strcat(c, " SDR");
|
||||
else
|
||||
strcat(c, " SPK");
|
||||
|
||||
//remarked by KD8CEC
|
||||
//already RX/TX status display, and over index (20 x 4 LCD)
|
||||
//if (inTx)
|
||||
// strcat(c, " TX");
|
||||
printLine(1, c);
|
||||
|
||||
byte diplayVFOLine = 1;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayVFOLine = 0;
|
||||
|
||||
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
|
||||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write((uint8_t)0);
|
||||
}
|
||||
else if (isCWAutoMode == 2){
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(0x7E);
|
||||
}
|
||||
else
|
||||
{
|
||||
LCD_SetCursor(5,diplayVFOLine);
|
||||
LCD_Write(':');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char line2Buffer[20];
|
||||
//KD8CEC 200Hz ST
|
||||
//L14.150 200Hz ST
|
||||
//U14.150 +150khz
|
||||
int freqScrollPosition = 0;
|
||||
|
||||
//Example Line2 Optinal Display
|
||||
//immediate execution, not call by scheulder
|
||||
//warning : unused parameter 'displayType' <-- ignore, this is reserve
|
||||
void updateLine2Buffer(char displayType)
|
||||
{
|
||||
unsigned long tmpFreq = 0;
|
||||
if (ritOn)
|
||||
{
|
||||
strcpy(line2Buffer, "RitTX:");
|
||||
|
||||
//display frequency
|
||||
tmpFreq = ritTxFrequency;
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
for (int i = 15; i >= 6; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 12 || i == 8) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
return;
|
||||
} //end of ritOn display
|
||||
|
||||
//other VFO display
|
||||
if (vfoActive == VFO_B)
|
||||
{
|
||||
tmpFreq = vfoA;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpFreq = vfoB;
|
||||
}
|
||||
|
||||
// EXAMPLE 1 & 2
|
||||
//U14.150.100
|
||||
//display frequency
|
||||
for (int i = 9; i >= 0; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 2 || i == 6) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
memset(&line2Buffer[10], ' ', 10);
|
||||
|
||||
if (isIFShift)
|
||||
{
|
||||
line2Buffer[6] = 'M';
|
||||
line2Buffer[7] = ' ';
|
||||
//IFShift Offset Value
|
||||
line2Buffer[8] = 'I';
|
||||
line2Buffer[9] = 'F';
|
||||
|
||||
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
|
||||
line2Buffer[11] = 0;
|
||||
line2Buffer[12] = ' ';
|
||||
|
||||
//11, 12, 13, 14, 15
|
||||
memset(b, 0, sizeof(b));
|
||||
ltoa(ifShiftValue, b, DEC);
|
||||
strncat(line2Buffer, b, 5);
|
||||
|
||||
for (int i = 12; i < 17; i++)
|
||||
{
|
||||
if (line2Buffer[i] == 0)
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
} // end of display IF
|
||||
else // step & Key Type display
|
||||
{
|
||||
//Step
|
||||
long tmpStep = arTuneStep[tuneStepIndex -1];
|
||||
|
||||
byte isStepKhz = 0;
|
||||
if (tmpStep >= 1000)
|
||||
{
|
||||
isStepKhz = 2;
|
||||
}
|
||||
|
||||
for (int i = 14; i >= 12 - isStepKhz; i--) {
|
||||
if (tmpStep > 0) {
|
||||
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
|
||||
tmpStep /= 10;
|
||||
}
|
||||
else
|
||||
line2Buffer[i +isStepKhz] = ' ';
|
||||
}
|
||||
|
||||
if (isStepKhz == 0)
|
||||
{
|
||||
line2Buffer[15] = 'H';
|
||||
line2Buffer[16] = 'z';
|
||||
}
|
||||
}
|
||||
|
||||
line2Buffer[17] = ' ';
|
||||
|
||||
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
if (cwKeyType == 0)
|
||||
{
|
||||
line2Buffer[18] = 'S';
|
||||
line2Buffer[19] = 'T';
|
||||
}
|
||||
else if (cwKeyType == 1)
|
||||
{
|
||||
line2Buffer[18] = 'I';
|
||||
line2Buffer[19] = 'A';
|
||||
}
|
||||
else
|
||||
{
|
||||
line2Buffer[18] = 'I';
|
||||
line2Buffer[19] = 'B';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//meterType : 0 = S.Meter, 1 : P.Meter
|
||||
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
|
||||
{
|
||||
if (meterType == 0 || meterType == 1 || meterType == 2)
|
||||
{
|
||||
drawMeter(meterValue);
|
||||
|
||||
LCD_SetCursor(drawPosition, 2);
|
||||
LCD_Write('S');
|
||||
LCD_Write(':');
|
||||
for (int i = 0; i < 7; i++) //meter 5 + +db 1 = 6
|
||||
LCD_Write(lcdMeter[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char checkCount = 0;
|
||||
char checkCountSMeter = 0;
|
||||
|
||||
//execute interval : 0.25sec
|
||||
void idle_process()
|
||||
{
|
||||
//space for user graphic display
|
||||
if (menuOn == 0)
|
||||
{
|
||||
if ((displayOption1 & 0x10) == 0x10) //always empty topline
|
||||
return;
|
||||
|
||||
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
|
||||
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
|
||||
if (checkCount++ > 1)
|
||||
{
|
||||
updateLine2Buffer(0); //call by scheduler
|
||||
printLine2(line2Buffer);
|
||||
line2DisplayStatus = 2;
|
||||
checkCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//EX for Meters
|
||||
/*
|
||||
DisplayMeter(0, testValue++, 0);
|
||||
if (testValue > 30)
|
||||
testValue = 0;
|
||||
*/
|
||||
|
||||
//Sample
|
||||
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 30, 0);
|
||||
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 10, 0);
|
||||
//delay_background(10, 0);
|
||||
//DisplayMeter(0, analogRead(ANALOG_SMETER), 0);
|
||||
//if (testValue > 30)
|
||||
// testValue = 0;
|
||||
|
||||
//S-Meter Display
|
||||
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
|
||||
{
|
||||
int newSMeter;
|
||||
|
||||
#ifdef USE_I2CSMETER
|
||||
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
|
||||
#else
|
||||
//VK2ETA S-Meter from MAX9814 TC pin
|
||||
newSMeter = analogRead(ANALOG_SMETER) / 4;
|
||||
|
||||
//Faster attack, Slower release
|
||||
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
|
||||
//currentSMeter = ((currentSMeter * 7 + newSMeter * 3) + 5) / 10;
|
||||
currentSMeter = newSMeter;
|
||||
|
||||
scaledSMeter = 0;
|
||||
for (byte s = 8; s >= 1; s--) {
|
||||
if (currentSMeter > sMeterLevels[s]) {
|
||||
scaledSMeter = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DisplayMeter(0, scaledSMeter, 0);
|
||||
checkCountSMeter = 0; //Reset Latency time
|
||||
} //end of S-Meter
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//AutoKey LCD Display Routine
|
||||
void Display_AutoKeyTextIndex(byte textIndex)
|
||||
{
|
||||
byte diplayAutoCWLine = 0;
|
||||
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayAutoCWLine = 1;
|
||||
LCD_SetCursor(0, diplayAutoCWLine);
|
||||
LCD_Write(byteToChar(textIndex));
|
||||
LCD_Write(':');
|
||||
}
|
||||
|
||||
void DisplayCallsign(byte callSignLength)
|
||||
{
|
||||
printLineFromEEPRom(3, 20 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
|
||||
}
|
||||
|
||||
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
|
||||
{
|
||||
printLineF(3, fwVersionInfo);
|
||||
}
|
||||
|
||||
#endif
|
1115
Raduino/ubitx_lcd_nextion.ino
Normal file
1115
Raduino/ubitx_lcd_nextion.ino
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,9 +13,9 @@
|
||||
* The output clock channel that controls the frequency is connected to the PLL-B.
|
||||
* The WSPR protocol is generated by changing the clock of the PLL-B.
|
||||
************************************************************************************/
|
||||
#include "ubitx.h"
|
||||
|
||||
// ************* 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
|
||||
@@ -48,7 +48,8 @@
|
||||
#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_ADDR 0x60 // I2C address of Si5351 (typical)
|
||||
uint8_t SI5351BX_ADDR; // I2C address of Si5351 (variable from Version 1.097)
|
||||
#define SI5351BX_XTALPF 2 // 1:6pf 2:8pf 3:10pf
|
||||
|
||||
// If using 27mhz crystal, set XTAL=27000000, MSA=33. Then vco=891mhz
|
||||
@@ -58,7 +59,13 @@
|
||||
// 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)
|
||||
|
||||
#if UBITX_BOARD_VERSION == 5
|
||||
uint8_t si5351bx_drive[3] = {3, 3, 3}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
|
||||
#else
|
||||
uint8_t si5351bx_drive[3] = {1, 1, 1}; // 0=2ma 1=4ma 2=6ma 3=8ma for CLK 0,1,2
|
||||
#endif
|
||||
|
||||
uint8_t si5351bx_clken = 0xFF; // Private, all CLK output drivers off
|
||||
int32_t calibration = 0;
|
||||
|
||||
@@ -92,6 +99,18 @@ void si5351bx_init() { // Call once at power-up, start PLLA
|
||||
|
||||
i2cWriten(26, si5351Val, 8); // Write to 8 PLLA msynth regs
|
||||
i2cWrite(177, 0x20); // Reset PLLA (0x80 resets PLLB)
|
||||
|
||||
|
||||
#if UBITX_BOARD_VERSION == 5
|
||||
//why? TODO : CHECK by KD8CEC
|
||||
//initializing the ppl2 as well
|
||||
i2cWriten(34, si5351Val, 8); // Write to 8 PLLA msynth regs
|
||||
i2cWrite(177, 0xa0); // Reset PLLA & PPLB (0x80 resets PLLB)
|
||||
#else
|
||||
//
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
void si5351bx_setfreq(uint8_t clknum, uint32_t fout) { // Set a CLK to fout Hz
|
||||
@@ -127,7 +146,9 @@ void si5351_set_calibration(int32_t cal){
|
||||
void SetCarrierFreq()
|
||||
{
|
||||
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (inTx == 0) ? ifShiftValue : 0));
|
||||
si5351bx_setfreq(0, appliedCarrier);
|
||||
//si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier));
|
||||
si5351bx_setfreq(0, ((sdrModeOn && (inTx == 0)) ? 0 : appliedCarrier)); //found bug by KG4GEK
|
||||
|
||||
|
||||
/*
|
||||
if (cwMode == 0)
|
||||
@@ -167,6 +188,3 @@ void TXSubFreq(unsigned long P2)
|
||||
i2cWrite(40, (P2 & 65280) >> 8);
|
||||
i2cWrite(41, P2 & 255);
|
||||
}
|
||||
|
||||
|
||||
|
301
Raduino/ubitx_ui.ino
Normal file
301
Raduino/ubitx_ui.ino
Normal file
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
const PROGMEM uint8_t meters_bitmap[] = {
|
||||
B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 , //custom 1
|
||||
B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 , //custom 2
|
||||
B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 , //custom 3
|
||||
B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 , //custom 4
|
||||
B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 , //custom 5
|
||||
B01000, B11100, B01000, B00000, B10111, B10101, B10101, B10111 //custom 6
|
||||
};
|
||||
*/
|
||||
|
||||
//#include "RigState.h"
|
||||
|
||||
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
|
||||
|
||||
#ifdef OPTION_SKINNYBARS //We want skninny bars with more text
|
||||
//VK2ETA modded "Skinny" bitmaps
|
||||
const PROGMEM uint8_t meters_bitmap[] = {
|
||||
// B01110, B10001, B10001, B11111, B11011, B11011, B11111, B00000, //Padlock Symbol, for merging. Not working, see below
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B00000, B10000, //shortest bar
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B00100, B10100,
|
||||
B00000, B00000, B00000, B00000, B00000, B00001, B00101, B10101,
|
||||
B00000, B00000, B00000, B00000, B10000, B10000, B10000, B10000,
|
||||
B00000, B00000, B00000, B00100, B10100, B10100, B10100, B10100,
|
||||
B00000, B00000, B00001, B00101, B10101, B10101, B10101, B10101, //tallest bar
|
||||
B00000, B00010, B00111, B00010, B01000, B11100, B01000, B00000, // ++ sign
|
||||
};
|
||||
#else
|
||||
//VK2ETA "Fat" bars, easy to read, with less text
|
||||
const PROGMEM uint8_t meters_bitmap[] = {
|
||||
// B01110, B10001, B10001, B11111, B11011, B11011, B11111, B00000, //Padlock Symbol, for merging. Not working, see below
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B00000, B11111, //shortest bar
|
||||
B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111,
|
||||
B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111,
|
||||
B00000, B00000, B00000, B00000, B11111, B11111, B11111, B11111,
|
||||
B00000, B00000, B00000, B11111, B11111, B11111, B11111, B11111,
|
||||
B00000, B00000, B11111, B11111, B11111, B11111, B11111, B11111, //tallest bar
|
||||
B00000, B00010, B00111, B00010, B01000, B11100, B01000, B00000, // ++ sign
|
||||
};
|
||||
#endif //OPTION_SKINNYBARS
|
||||
PGM_P p_metes_bitmap = reinterpret_cast<PGM_P>(meters_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(p_metes_bitmap + i);
|
||||
LCD_CreateChar(1, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 8);
|
||||
LCD_CreateChar(2, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 16);
|
||||
LCD_CreateChar(3, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 24);
|
||||
LCD_CreateChar(4, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 32);
|
||||
LCD_CreateChar(5, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 40);
|
||||
LCD_CreateChar(6, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 48);
|
||||
LCD_CreateChar(7, tmpbytes);
|
||||
}
|
||||
|
||||
|
||||
//by KD8CEC
|
||||
//0 ~ 25 : 30 over : + 10
|
||||
/*
|
||||
void drawMeter(int needle) {
|
||||
//5Char + O over
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (needle >= 5)
|
||||
lcdMeter[i] = 5; //full
|
||||
else if (needle > 0)
|
||||
lcdMeter[i] = needle; //full
|
||||
else //0
|
||||
lcdMeter[i] = 0x20;
|
||||
|
||||
needle -= 5;
|
||||
}
|
||||
|
||||
if (needle > 0)
|
||||
lcdMeter[5] = 6;
|
||||
else
|
||||
lcdMeter[5] = 0x20;
|
||||
}
|
||||
*/
|
||||
//VK2ETA meter for S.Meter, power and SWR
|
||||
void drawMeter(int needle)
|
||||
{
|
||||
#ifdef OPTION_SKINNYBARS
|
||||
//Fill buffer with growing set of bars, up to needle value
|
||||
lcdMeter[0] = 0x20;
|
||||
lcdMeter[1] = 0x20;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (needle > i)
|
||||
lcdMeter[i / 3] = byte(i + 1); //Custom characters above
|
||||
//else if (i == 1 || i == 4) {
|
||||
// lcdMeter[i / 3] = 0x20; //blank
|
||||
//}
|
||||
}
|
||||
|
||||
if (needle > 7) {
|
||||
lcdMeter[2] = byte(7); //Custom character "++"
|
||||
} else if (needle > 6) {
|
||||
lcdMeter[2] = '+'; //"+"
|
||||
} else lcdMeter[2] = 0x20;
|
||||
|
||||
|
||||
#else //Must be "fat" bars
|
||||
//Fill buffer with growing set of bars, up to needle value
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (needle > i)
|
||||
lcdMeter[i] = byte(i + 1); //Custom characters above
|
||||
else
|
||||
lcdMeter[i] = 0x20; //blank
|
||||
}
|
||||
|
||||
if (needle > 7) {
|
||||
lcdMeter[6] = byte(7); //Custom character "++"
|
||||
} else if (needle > 6) {
|
||||
lcdMeter[6] = '+'; //"+"
|
||||
} else lcdMeter[6] = 0x20;
|
||||
|
||||
#endif //OPTION_FATBARS
|
||||
}
|
||||
|
||||
|
||||
|
||||
char byteToChar(byte srcByte){
|
||||
if (srcByte < 10)
|
||||
return 0x30 + srcByte;
|
||||
else
|
||||
return 'A' + srcByte - 10;
|
||||
}
|
||||
|
||||
//returns true if the button is pressed
|
||||
int btnDown(void){
|
||||
#ifdef EXTEND_KEY_GROUP1
|
||||
if (analogRead(FBUTTON) > FUNCTION_KEY_ADC)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
|
||||
#else
|
||||
if (digitalRead(FBUTTON) == HIGH)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef EXTEND_KEY_GROUP1
|
||||
int getBtnStatus(void){
|
||||
int readButtonValue = analogRead(FBUTTON);
|
||||
|
||||
if (analogRead(FBUTTON) < FUNCTION_KEY_ADC)
|
||||
return FKEY_PRESS;
|
||||
else
|
||||
{
|
||||
readButtonValue = readButtonValue / 4;
|
||||
//return FKEY_VFOCHANGE;
|
||||
for (int i = 0; i < 16; i++)
|
||||
if (KeyValues[i][2] != 0 && KeyValues[i][0] <= readButtonValue && KeyValues[i][1] >= readButtonValue)
|
||||
return KeyValues[i][2];
|
||||
//return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
unsigned long start_at = millis();
|
||||
|
||||
while (millis() - start_at < 50) { // 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);
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
//I2C Signal Meter, Version 1.097
|
||||
//===================================================================
|
||||
|
||||
// 0xA0 ~ 0xCF : CW Decode Mode + 100Hz ~
|
||||
// 0xD0 ~ 0xF3 : RTTY Decode Mode + 100Hz ~
|
||||
// 0x10 ~ 0x30 : Spectrum Mode
|
||||
int GetI2CSmeterValue(int valueType)
|
||||
{
|
||||
if (valueType > 0)
|
||||
{
|
||||
Wire.beginTransmission(I2CMETER_ADDR); //j : S-Meter
|
||||
Wire.write(valueType); //Y : Get Value Type
|
||||
Wire.endTransmission();
|
||||
}
|
||||
|
||||
Wire.requestFrom(I2CMETER_ADDR, 1);
|
||||
|
||||
if (Wire.available() > 0)
|
||||
{
|
||||
return Wire.read();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
@@ -6,8 +6,6 @@ Thanks to G3ZIL for sharing great code.
|
||||
Due to the limited memory of uBITX, I have implemented at least only a few of the codes in uBITX.
|
||||
|
||||
Thanks for testing
|
||||
Beta Tester :
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
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
|
||||
@@ -23,21 +21,19 @@ Beta Tester :
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**********************************************************************************/
|
||||
|
||||
#include <arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include "ubitx.h"
|
||||
|
||||
//begin of test
|
||||
byte WsprToneCode[164];
|
||||
|
||||
long lastTime=0;
|
||||
unsigned long lastTime=0;
|
||||
unsigned long TX_MSNB_P2; // Si5351 register MSNB_P2 PLLB for Tx
|
||||
unsigned long TX_P2; // Variable values for MSNB_P2 which defines the frequencies for the data
|
||||
|
||||
extern int enc_read(void);
|
||||
|
||||
byte WsprMSGCount = 0;
|
||||
#define PTT (A3)
|
||||
|
||||
#define WSPR_BAND1 401
|
||||
|
||||
@@ -48,7 +44,7 @@ void SendWSPRManage()
|
||||
{
|
||||
int knob = 0;
|
||||
byte knobPosition = 0;
|
||||
char isNeedDisplayInfo = 0;
|
||||
//char isNeedDisplayInfo = 0;
|
||||
char nowSelectedIndex = 0;
|
||||
char nowWsprStep = 0; //0 : select Message, 1 : select band, 2 : send
|
||||
char selectedWsprMessageIndex = -1;
|
||||
@@ -56,8 +52,8 @@ void SendWSPRManage()
|
||||
|
||||
unsigned long WsprTXFreq = 0;
|
||||
unsigned int WsprMultiChan = 0;
|
||||
unsigned long prevFreq;
|
||||
char loopIndex;
|
||||
//unsigned long prevFreq;
|
||||
byte loopIndex;
|
||||
|
||||
delay_background(500, 0);
|
||||
|
||||
@@ -75,13 +71,14 @@ void SendWSPRManage()
|
||||
|
||||
if (nowWsprStep == 0) //select Message status
|
||||
{
|
||||
printLineF2(F("WSPR:"));
|
||||
//printLineF2(F("WSPR:"));
|
||||
|
||||
if (selectedWsprMessageIndex != nowSelectedIndex)
|
||||
{
|
||||
selectedWsprMessageIndex = nowSelectedIndex;
|
||||
int wsprMessageBuffIndex = selectedWsprMessageIndex * 46;
|
||||
|
||||
printLineF2(F("WSPR:"));
|
||||
//Display WSPR Name tag
|
||||
printLineFromEEPRom(0, 6, wsprMessageBuffIndex, wsprMessageBuffIndex + 4, 1);
|
||||
|
||||
@@ -115,22 +112,9 @@ void SendWSPRManage()
|
||||
EEPROM.get(bandBuffIndex, WsprTXFreq);
|
||||
EEPROM.get(bandBuffIndex + 4, WsprMultiChan);
|
||||
|
||||
/*
|
||||
//3, 4, 5, 6, 7
|
||||
Wspr_Reg1[3] = EEPROM.read(bandBuffIndex + 6);
|
||||
Wspr_Reg1[4] = EEPROM.read(bandBuffIndex + 7);
|
||||
Wspr_Reg1[5] = EEPROM.read(bandBuffIndex + 8);
|
||||
Wspr_Reg1[6] = EEPROM.read(bandBuffIndex + 9);
|
||||
Wspr_Reg1[7] = EEPROM.read(bandBuffIndex + 10);
|
||||
*/
|
||||
for (loopIndex = 3; loopIndex < 8; loopIndex++)
|
||||
Wspr_Reg1[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 3);
|
||||
|
||||
/*
|
||||
Wspr_Reg2[2] = EEPROM.read(bandBuffIndex + 11);
|
||||
Wspr_Reg2[3] = EEPROM.read(bandBuffIndex + 12);
|
||||
Wspr_Reg2[4] = EEPROM.read(bandBuffIndex + 13);
|
||||
*/
|
||||
//2, 3, 4
|
||||
for (loopIndex = 2; loopIndex < 5; loopIndex++)
|
||||
Wspr_Reg2[loopIndex] = EEPROM.read(bandBuffIndex + loopIndex + 9);
|
||||
@@ -138,18 +122,39 @@ void SendWSPRManage()
|
||||
TX_MSNB_P2 = ((unsigned long)Wspr_Reg1[5] & 0x0F) << 16 | ((unsigned long)Wspr_Reg1[6]) << 8 | Wspr_Reg1[7];
|
||||
}
|
||||
|
||||
ltoa(WsprTXFreq, b, DEC);
|
||||
if (digitalRead(PTT) == 0)
|
||||
strcpy(c, "SEND:");
|
||||
strcpy(c, "SEND: ");
|
||||
else
|
||||
strcpy(c, "PTT->");
|
||||
strcpy(c, "PTT-> ");
|
||||
|
||||
//ltoa(WsprTXFreq, b, DEC);
|
||||
//strcat(c, b);
|
||||
|
||||
//display frequency, Frequency to String for KD8CEC
|
||||
unsigned long tmpFreq = WsprTXFreq;
|
||||
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] = ' ';
|
||||
}
|
||||
|
||||
strcat(c, b);
|
||||
printLine1(c);
|
||||
|
||||
|
||||
#ifdef USE_SW_SERIAL
|
||||
SWS_Process();
|
||||
if ((digitalRead(PTT) == 0) || (TriggerBySW == 1))
|
||||
{
|
||||
TriggerBySW = 0;
|
||||
#else
|
||||
if (digitalRead(PTT) == 0)
|
||||
{
|
||||
//printLineF1(F("Transmitting"));
|
||||
#endif
|
||||
//SEND WSPR
|
||||
//If you need to consider the Rit and Sprite modes, uncomment them below.
|
||||
//remark = To reduce the size of the program
|
BIN
References/B5A-0180-20.pdf
Normal file
BIN
References/B5A-0180-20.pdf
Normal file
Binary file not shown.
BIN
References/ts_590_g_pc_command_e.pdf
Normal file
BIN
References/ts_590_g_pc_command_e.pdf
Normal file
Binary file not shown.
BIN
Schematics/IO_Board-ADC_Buffer.xcf
Normal file
BIN
Schematics/IO_Board-ADC_Buffer.xcf
Normal file
Binary file not shown.
342
Schematics/IO_Board/IO_Board-cache.lib
Normal file
342
Schematics/IO_Board/IO_Board-cache.lib
Normal file
@@ -0,0 +1,342 @@
|
||||
EESchema-LIBRARY Version 2.4
|
||||
#encoding utf-8
|
||||
#
|
||||
# Amplifier_Operational_LM324A
|
||||
#
|
||||
DEF Amplifier_Operational_LM324A U 0 5 Y Y 5 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_LM324A" 0 -200 50 H V L CNN
|
||||
F2 "" -50 100 50 H I C CNN
|
||||
F3 "" 50 200 50 H I C CNN
|
||||
ALIAS LM324 TLC274 TLC279 TL074 LM324A MCP6004 TL084 TL064 LMV324 LMC6484 MCP604 MC33079 MC33174 MC33179 OPA1604 OPA1679 OPA4134 OPA4340UA OPA4376 MCP6L94 TSV914 ADA4807-4 TSV994
|
||||
$FPLIST
|
||||
SOIC*3.9x8.7mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TSSOP*4.4x5mm*P0.65mm*
|
||||
SSOP*5.3x6.2mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.5mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 3 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 4 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X + 10 -300 100 100 R 50 50 3 1 I
|
||||
X ~ 8 300 0 100 L 50 50 3 1 O
|
||||
X - 9 -300 -100 100 R 50 50 3 1 I
|
||||
X + 12 -300 100 100 R 50 50 4 1 I
|
||||
X - 13 -300 -100 100 R 50 50 4 1 I
|
||||
X ~ 14 300 0 100 L 50 50 4 1 O
|
||||
X V- 11 -100 -300 150 U 50 50 5 1 W
|
||||
X V+ 4 -100 300 150 D 50 50 5 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Amplifier_Operational_LM358
|
||||
#
|
||||
DEF Amplifier_Operational_LM358 U 0 5 Y Y 3 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_LM358" 0 -200 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
SOIC*3.9x4.9mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TO*99*
|
||||
OnSemi*Micro8*
|
||||
TSSOP*3x3mm*P0.65mm*
|
||||
TSSOP*4.4x3mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.65mm*
|
||||
SSOP*3.9x4.9mm*P0.635mm*
|
||||
LFCSP*2x2mm*P0.5mm*
|
||||
*SIP*
|
||||
SOIC*5.3x6.2mm*P1.27mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X V- 4 -100 -300 150 U 50 50 3 1 W
|
||||
X V+ 8 -100 300 150 D 50 50 3 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Amplifier_Operational_TL072
|
||||
#
|
||||
DEF Amplifier_Operational_TL072 U 0 5 Y Y 3 L N
|
||||
F0 "U" 0 200 50 H V L CNN
|
||||
F1 "Amplifier_Operational_TL072" 0 -200 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
ALIAS LM358 AD8620 LMC6062 LMC6082 TL062 TL072 TL082 NE5532 SA5532 RC4558 RC4560 RC4580 LMV358 TS912 TSV912IDT TSV912IST TLC272 TLC277 MCP602 OPA1678 OPA2134 OPA2340 OPA2376xxD OPA2376xxDGK MC33078 MC33178 LM4562 OP249 OP275 ADA4075-2 MCP6002-xP MCP6002-xSN MCP6002-xMS LM7332 OPA2333xxD OPA2333xxDGK LMC6482 LT1492 LTC6081xMS8 LM6172 MCP6L92 NJM2043 NJM2114 NJM4556A NJM4558 NJM4559 NJM4560 NJM4580 NJM5532 ADA4807-2ARM OPA2691 LT6234 OPA2356xxD OPA2356xxDGK OPA1612AxD MC33172 OPA1602 TLV2372 LT6237 OPA2277
|
||||
$FPLIST
|
||||
SOIC*3.9x4.9mm*P1.27mm*
|
||||
DIP*W7.62mm*
|
||||
TO*99*
|
||||
OnSemi*Micro8*
|
||||
TSSOP*3x3mm*P0.65mm*
|
||||
TSSOP*4.4x3mm*P0.65mm*
|
||||
MSOP*3x3mm*P0.65mm*
|
||||
SSOP*3.9x4.9mm*P0.635mm*
|
||||
LFCSP*2x2mm*P0.5mm*
|
||||
*SIP*
|
||||
SOIC*5.3x6.2mm*P1.27mm*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 4 1 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
P 4 2 1 10 -200 200 200 0 -200 -200 -200 200 f
|
||||
X ~ 1 300 0 100 L 50 50 1 1 O
|
||||
X - 2 -300 -100 100 R 50 50 1 1 I
|
||||
X + 3 -300 100 100 R 50 50 1 1 I
|
||||
X + 5 -300 100 100 R 50 50 2 1 I
|
||||
X - 6 -300 -100 100 R 50 50 2 1 I
|
||||
X ~ 7 300 0 100 L 50 50 2 1 O
|
||||
X V- 4 -100 -300 150 U 50 50 3 1 W
|
||||
X V+ 8 -100 300 150 D 50 50 3 1 W
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x02_Male
|
||||
#
|
||||
DEF Connector_Conn_01x02_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 100 50 H V C CNN
|
||||
F1 "Connector_Conn_01x02_Male" 0 -200 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
X Pin_1 1 200 0 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 -100 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x03_Male
|
||||
#
|
||||
DEF Connector_Conn_01x03_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 200 50 H V C CNN
|
||||
F1 "Connector_Conn_01x03_Male" 0 -200 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
S 34 105 0 95 1 1 6 F
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
P 2 1 1 6 50 100 34 100 N
|
||||
X Pin_1 1 200 100 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 0 150 L 50 50 1 1 P
|
||||
X Pin_3 3 200 -100 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Connector_Conn_01x06_Male
|
||||
#
|
||||
DEF Connector_Conn_01x06_Male J 0 40 Y N 1 F N
|
||||
F0 "J" 0 300 50 H V C CNN
|
||||
F1 "Connector_Conn_01x06_Male" 0 -400 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Connector*:*_1x??_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
S 34 -295 0 -305 1 1 6 F
|
||||
S 34 -195 0 -205 1 1 6 F
|
||||
S 34 -95 0 -105 1 1 6 F
|
||||
S 34 5 0 -5 1 1 6 F
|
||||
S 34 105 0 95 1 1 6 F
|
||||
S 34 205 0 195 1 1 6 F
|
||||
P 2 1 1 6 50 -300 34 -300 N
|
||||
P 2 1 1 6 50 -200 34 -200 N
|
||||
P 2 1 1 6 50 -100 34 -100 N
|
||||
P 2 1 1 6 50 0 34 0 N
|
||||
P 2 1 1 6 50 100 34 100 N
|
||||
P 2 1 1 6 50 200 34 200 N
|
||||
X Pin_1 1 200 200 150 L 50 50 1 1 P
|
||||
X Pin_2 2 200 100 150 L 50 50 1 1 P
|
||||
X Pin_3 3 200 0 150 L 50 50 1 1 P
|
||||
X Pin_4 4 200 -100 150 L 50 50 1 1 P
|
||||
X Pin_5 5 200 -200 150 L 50 50 1 1 P
|
||||
X Pin_6 6 200 -300 150 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_C
|
||||
#
|
||||
DEF Device_C C 0 10 N Y 1 F N
|
||||
F0 "C" 25 100 50 H V L CNN
|
||||
F1 "Device_C" 25 -100 50 H V L CNN
|
||||
F2 "" 38 -150 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
C_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 20 -80 -30 80 -30 N
|
||||
P 2 0 1 20 -80 30 80 30 N
|
||||
X ~ 1 0 150 110 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 110 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_CP1
|
||||
#
|
||||
DEF Device_CP1 C 0 10 N N 1 F N
|
||||
F0 "C" 25 100 50 H V L CNN
|
||||
F1 "Device_CP1" 25 -100 50 H V L CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
CP_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
A 0 -150 128 1287 513 0 1 20 N -80 -50 80 -50
|
||||
P 2 0 1 20 -80 30 80 30 N
|
||||
P 2 0 1 0 -70 90 -30 90 N
|
||||
P 2 0 1 0 -50 70 -50 110 N
|
||||
X ~ 1 0 150 110 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 130 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_D
|
||||
#
|
||||
DEF Device_D D 0 40 N N 1 F N
|
||||
F0 "D" 0 100 50 H V C CNN
|
||||
F1 "Device_D" 0 -100 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
TO-???*
|
||||
*_Diode_*
|
||||
*SingleDiode*
|
||||
D_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 8 -50 50 -50 -50 N
|
||||
P 2 0 1 0 50 0 -50 0 N
|
||||
P 4 0 1 8 50 50 50 -50 -50 0 50 50 N
|
||||
X K 1 -150 0 100 R 50 50 1 1 P
|
||||
X A 2 150 0 100 L 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_R_POT_US
|
||||
#
|
||||
DEF Device_R_POT_US RV 0 40 Y N 1 F N
|
||||
F0 "RV" -175 0 50 V V C CNN
|
||||
F1 "Device_R_POT_US" -100 0 50 V V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
Potentiometer*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 0 0 -90 0 -100 N
|
||||
P 2 0 1 0 0 100 0 90 N
|
||||
P 2 0 1 0 100 0 60 0 N
|
||||
P 4 0 1 0 45 0 90 20 90 -20 45 0 F
|
||||
P 5 0 1 0 0 -30 40 -45 0 -60 -40 -75 0 -90 N
|
||||
P 5 0 1 0 0 30 40 15 0 0 -40 -15 0 -30 N
|
||||
P 5 0 1 0 0 90 40 75 0 60 -40 45 0 30 N
|
||||
X 1 1 0 150 50 D 50 50 1 1 P
|
||||
X 2 2 150 0 50 L 50 50 1 1 P
|
||||
X 3 3 0 -150 50 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Device_R_US
|
||||
#
|
||||
DEF Device_R_US R 0 0 N Y 1 F N
|
||||
F0 "R" 100 0 50 V V C CNN
|
||||
F1 "Device_R_US" -100 0 50 V V C CNN
|
||||
F2 "" 40 -10 50 V I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
R_*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
P 2 0 1 0 0 -90 0 -100 N
|
||||
P 2 0 1 0 0 90 0 100 N
|
||||
P 5 0 1 0 0 -30 40 -45 0 -60 -40 -75 0 -90 N
|
||||
P 5 0 1 0 0 30 40 15 0 0 -40 -15 0 -30 N
|
||||
P 5 0 1 0 0 90 40 75 0 60 -40 45 0 30 N
|
||||
X ~ 1 0 150 50 D 50 50 1 1 P
|
||||
X ~ 2 0 -150 50 U 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Transistor_BJT_PN2222A
|
||||
#
|
||||
DEF Transistor_BJT_PN2222A Q 0 0 Y N 1 F N
|
||||
F0 "Q" 200 75 50 H V L CNN
|
||||
F1 "Transistor_BJT_PN2222A" 200 0 50 H V L CNN
|
||||
F2 "Package_TO_SOT_THT:TO-92_Inline" 200 -75 50 H I L CIN
|
||||
F3 "" 0 0 50 H I L CNN
|
||||
$FPLIST
|
||||
TO?92*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
C 50 0 111 0 1 10 N
|
||||
P 2 0 1 0 0 0 25 0 N
|
||||
P 2 0 1 0 100 -100 25 -25 N
|
||||
P 2 0 1 0 100 100 25 25 N
|
||||
P 3 0 1 20 25 75 25 -75 25 -75 N
|
||||
P 3 0 1 0 95 -95 75 -75 75 -75 N
|
||||
P 5 0 1 0 45 -65 65 -45 85 -85 45 -65 45 -65 F
|
||||
X E 1 100 -200 100 U 50 50 1 1 P
|
||||
X B 2 -200 0 200 R 50 50 1 1 I
|
||||
X C 3 100 200 100 D 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# power_+5V
|
||||
#
|
||||
DEF power_+5V #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -150 50 H I C CNN
|
||||
F1 "power_+5V" 0 140 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
P 2 0 1 0 -30 50 0 100 N
|
||||
P 2 0 1 0 0 0 0 100 N
|
||||
P 2 0 1 0 0 100 30 50 N
|
||||
X +5V 1 0 0 0 U 50 50 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# power_GND
|
||||
#
|
||||
DEF power_GND #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -250 50 H I C CNN
|
||||
F1 "power_GND" 0 -150 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N
|
||||
X GND 1 0 0 0 D 50 50 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
1
Schematics/IO_Board/IO_Board.kicad_pcb
Normal file
1
Schematics/IO_Board/IO_Board.kicad_pcb
Normal file
@@ -0,0 +1 @@
|
||||
(kicad_pcb (version 4) (host kicad "dummy file") )
|
33
Schematics/IO_Board/IO_Board.pro
Normal file
33
Schematics/IO_Board/IO_Board.pro
Normal file
@@ -0,0 +1,33 @@
|
||||
update=22/05/2015 07:44:53
|
||||
version=1
|
||||
last_client=kicad
|
||||
[general]
|
||||
version=1
|
||||
RootSch=
|
||||
BoardNm=
|
||||
[pcbnew]
|
||||
version=1
|
||||
LastNetListRead=
|
||||
UseCmpFile=1
|
||||
PadDrill=0.600000000000
|
||||
PadDrillOvalY=0.600000000000
|
||||
PadSizeH=1.500000000000
|
||||
PadSizeV=1.500000000000
|
||||
PcbTextSizeV=1.500000000000
|
||||
PcbTextSizeH=1.500000000000
|
||||
PcbTextThickness=0.300000000000
|
||||
ModuleTextSizeV=1.000000000000
|
||||
ModuleTextSizeH=1.000000000000
|
||||
ModuleTextSizeThickness=0.150000000000
|
||||
SolderMaskClearance=0.000000000000
|
||||
SolderMaskMinWidth=0.000000000000
|
||||
DrawSegmentWidth=0.200000000000
|
||||
BoardOutlineThickness=0.100000000000
|
||||
ModuleOutlineThickness=0.150000000000
|
||||
[cvpcb]
|
||||
version=1
|
||||
NetIExt=net
|
||||
[eeschema]
|
||||
version=1
|
||||
LibDir=
|
||||
[eeschema/libraries]
|
1111
Schematics/IO_Board/IO_Board.sch
Normal file
1111
Schematics/IO_Board/IO_Board.sch
Normal file
File diff suppressed because it is too large
Load Diff
1105
Schematics/IO_Board/IO_Board.sch-bak
Normal file
1105
Schematics/IO_Board/IO_Board.sch-bak
Normal file
File diff suppressed because it is too large
Load Diff
16
Schematics/IO_Board/IO_Board_Wiring.sch
Normal file
16
Schematics/IO_Board/IO_Board_Wiring.sch
Normal file
@@ -0,0 +1,16 @@
|
||||
EESchema Schematic File Version 4
|
||||
EELAYER 30 0
|
||||
EELAYER END
|
||||
$Descr A4 11693 8268
|
||||
encoding utf-8
|
||||
Sheet 2 2
|
||||
Title ""
|
||||
Date ""
|
||||
Rev ""
|
||||
Comp ""
|
||||
Comment1 ""
|
||||
Comment2 ""
|
||||
Comment3 ""
|
||||
Comment4 ""
|
||||
$EndDescr
|
||||
$EndSCHEMATC
|
BIN
Schematics/SW_Architecture.odg
Normal file
BIN
Schematics/SW_Architecture.odg
Normal file
Binary file not shown.
480
TeensyDSP/DSP.cpp
Normal file
480
TeensyDSP/DSP.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
//======================================================================
|
||||
// DSP.cpp
|
||||
//======================================================================
|
||||
|
||||
#include "DSP.h"
|
||||
|
||||
#include <i2c_t3.h>
|
||||
//#include <Wire.h>
|
||||
//#include <SPI.h>
|
||||
//#include <SD.h>
|
||||
//#include <SerialFlash.h>
|
||||
|
||||
// GUItool: begin automatically generated code
|
||||
AudioInputUSB usbIn; //xy=63,305
|
||||
AudioInputI2S lineIn; //xy=71,197
|
||||
AudioSynthWaveformSine tone1; //xy=111,369
|
||||
AudioSynthWaveformSine tone2; //xy=111,410
|
||||
AudioMixer4 rxAudio; //xy=328,111
|
||||
AudioMixer4 txAudio; //xy=332,299
|
||||
AudioAnalyzeRMS txVoxLevel; //xy=490,340
|
||||
AudioFilterFIR rxFilter; //xy=493,103
|
||||
AudioAmplifier usbOutAmp; //xy=658,99
|
||||
AudioAmplifier lineOutAmp; //xy=659,162
|
||||
AudioAmplifier usbBypassAmp; //xy=666,225
|
||||
AudioAmplifier txOutAmp; //xy=713,301
|
||||
AudioOutputI2S lineOut; //xy=876,294
|
||||
AudioOutputUSB usbOut; //xy=878,255
|
||||
AudioConnection patchCord1(usbIn, 0, txAudio, 1);
|
||||
AudioConnection patchCord2(lineIn, 0, rxAudio, 0);
|
||||
AudioConnection patchCord3(lineIn, 1, txAudio, 0);
|
||||
AudioConnection patchCord4(tone1, 0, txAudio, 2);
|
||||
AudioConnection patchCord5(tone1, 0, rxAudio, 2);
|
||||
AudioConnection patchCord6(tone2, 0, txAudio, 3);
|
||||
AudioConnection patchCord7(tone2, 0, rxAudio, 3);
|
||||
AudioConnection patchCord8(rxAudio, rxFilter);
|
||||
AudioConnection patchCord9(rxAudio, usbBypassAmp);
|
||||
AudioConnection patchCord10(txAudio, txVoxLevel);
|
||||
AudioConnection patchCord11(txAudio, txOutAmp);
|
||||
AudioConnection patchCord12(rxFilter, usbOutAmp);
|
||||
AudioConnection patchCord13(rxFilter, lineOutAmp);
|
||||
AudioConnection patchCord14(usbOutAmp, 0, usbOut, 0);
|
||||
AudioConnection patchCord15(lineOutAmp, 0, lineOut, 0);
|
||||
AudioConnection patchCord16(usbBypassAmp, 0, usbOut, 1);
|
||||
AudioConnection patchCord17(txOutAmp, 0, lineOut, 1);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=337,440
|
||||
// GUItool: end automatically generated code
|
||||
|
||||
void UBitxDSP::begin() {
|
||||
|
||||
// Basic audio setup
|
||||
AudioMemory(16); // TODO: optimize this
|
||||
audioCtrl.enable();
|
||||
audioCtrl.volume(0.0); // headphone volume...
|
||||
audioCtrl.muteHeadphone(); // ...not used by UBitxDSP
|
||||
|
||||
setupRxAudio();
|
||||
setupTxAudio();
|
||||
|
||||
// Default to RX.
|
||||
muteRxIn(); // redundant?
|
||||
muteTxIn(); // redundant?
|
||||
isTx = true; // so that rx() call works
|
||||
rx();
|
||||
|
||||
// Setup the VOX - TBD
|
||||
|
||||
// Setup the RX Filter.
|
||||
setRxFilter(300.0, 3000.0);
|
||||
|
||||
sinceLastUpdate = 0;
|
||||
}
|
||||
|
||||
void UBitxDSP::update() {
|
||||
// Update the USB volume (level of TX USB output) periodically.
|
||||
if (sinceLastUpdate > DSP_MILLIS_PER_UPDATE) {
|
||||
float vol = usbIn.volume();
|
||||
if (vol != usbVol) {
|
||||
setTxInLevel(TX_USB, vol);
|
||||
usbVol = vol;
|
||||
}
|
||||
sinceLastUpdate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::end() {
|
||||
bypassRxFilter();
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Transmit/Receive switching
|
||||
**********************************************************************/
|
||||
|
||||
/*!
|
||||
* Return to receive (RX) mode from transmit (TX) mode.
|
||||
* First the transmit audio output is muted, to ensure that no more
|
||||
* audio goes to the rig. Then we check to see if the latched TX audio
|
||||
* source was different than the selected TX audio source; this happens
|
||||
* if the radio is currently set for a particular input (which
|
||||
* determines what is monitored by the VOX), but then is commanded to
|
||||
* transmit a different source (e.g. based on a CAT command). The
|
||||
* actual transmit audio source is latched during transmit, but upon
|
||||
* returning to receive, we restore the selected transmit audio.
|
||||
*/
|
||||
void UBitxDSP::rx() {
|
||||
if (isTx) {
|
||||
muteTxOut();
|
||||
if (txSrcLatched != txSrc) {
|
||||
setTxAudioIn(txSrc);
|
||||
}
|
||||
if (txSrcLatched == MIC_IN) {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
}
|
||||
unmuteRxIn(RX_AUDIO);
|
||||
isTx = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enter transmit (TX) mode from receive (RX) mode.
|
||||
*/
|
||||
void UBitxDSP::tx(TxAudioIn src) {
|
||||
if (!isTx) {
|
||||
muteRxIn(RX_AUDIO);
|
||||
|
||||
txSrcLatched = src;
|
||||
if (txSrcLatched != txSrc) {
|
||||
setTxAudioIn(txSrcLatched, true);
|
||||
}
|
||||
|
||||
if (txSrcLatched == MIC_IN) {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||
audioCtrl.micGain(micGain);
|
||||
}
|
||||
|
||||
unmuteTxOut();
|
||||
isTx = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* General audio setup -- called via begin()
|
||||
**********************************************************************/
|
||||
|
||||
void UBitxDSP::setupRxAudio() {
|
||||
for (int i = 0; i < NUM_RX_AUDIO_CH; i++) {
|
||||
if (i == RX_AUDIO)
|
||||
rxAudio.gain(i, 1.0);
|
||||
else
|
||||
rxAudio.gain(i, 0.0);
|
||||
}
|
||||
|
||||
// Rig (Line) Input (RX)
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
audioCtrl.unmuteLineout();
|
||||
audioCtrl.lineInLevel(9, 5); // RX, TX
|
||||
audioCtrl.lineOutLevel(29, 31); // RX, TX
|
||||
|
||||
// Line Output (RX)
|
||||
setLineOutLevel(1.0);
|
||||
|
||||
// USB Output (RX)
|
||||
setUSBOutLevel(1.0);
|
||||
}
|
||||
|
||||
void UBitxDSP::setupTxAudio() {
|
||||
for (int i = 0; i < NUM_TX_AUDIO_CH; i++) {
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
|
||||
// Mic Input (TX)
|
||||
audioCtrl.micGain(0); // TODO: set value
|
||||
// Line Input (TX)
|
||||
|
||||
// USB Input (TX)
|
||||
|
||||
// Rig (Line) Output (TX)
|
||||
txOutAmp.gain(1.0);
|
||||
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.frequency(1500); // TODO: Make this dynamic based on CW (sidetone freq) versus data (1500 Hz)
|
||||
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.frequency(700);
|
||||
tone2.frequency(1900);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Receive audio chain
|
||||
**********************************************************************/
|
||||
|
||||
void UBitxDSP::setRxInLevel(RxAudioCh ch, float level) {
|
||||
if (ch < NUM_RX_AUDIO_CH) {
|
||||
state.rxIn[ch].level = level;
|
||||
rxAudio.gain(ch, state.rxIn[ch].mute ? 0.0 : state.rxIn[ch].level);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::muteRxIn() {
|
||||
for (int i = 0; i < NUM_RX_AUDIO_CH; i++) {
|
||||
state.rxIn[RxAudioCh(i)].mute = true;
|
||||
rxAudio.gain(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::muteRxIn(RxAudioCh ch) {
|
||||
if (ch < NUM_RX_AUDIO_CH) {
|
||||
if (!state.rxIn[ch].mute) {
|
||||
state.rxIn[ch].mute = true;
|
||||
rxAudio.gain(ch, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::unmuteRxIn(RxAudioCh ch) {
|
||||
if (ch < NUM_RX_AUDIO_CH) {
|
||||
if (state.rxIn[ch].mute) {
|
||||
state.rxIn[ch].mute = false;
|
||||
rxAudio.gain(ch, state.rxIn[ch].level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::setLineOutLevel(float level) {
|
||||
state.rxOut[LINE_OUT].level = level;
|
||||
lineOutAmp.gain(state.rxOut[LINE_OUT].mute ? 0.0 : state.rxOut[LINE_OUT].level);
|
||||
}
|
||||
|
||||
void UBitxDSP::setUSBOutLevel(float level) {
|
||||
state.rxOut[USB_OUT].level = level;
|
||||
usbOutAmp.gain(state.rxOut[USB_OUT].mute ? 0.0 : state.rxOut[USB_OUT].level);
|
||||
usbBypassAmp.gain(state.rxOut[USB_OUT].mute ? 0.0 : state.rxOut[USB_OUT].level);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Transmit audio chain
|
||||
**********************************************************************/
|
||||
|
||||
void UBitxDSP::setTxInLevel(TxAudioCh ch, float level) {
|
||||
if (ch < NUM_TX_AUDIO_CH) {
|
||||
state.txIn[ch].level = level;
|
||||
txAudio.gain(ch, state.txIn[ch].mute ? 0.0 : state.txIn[ch].level);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::muteTxIn() {
|
||||
for (int i = 0; i < NUM_TX_AUDIO_CH; i++) {
|
||||
state.txIn[TxAudioCh(i)].mute = true;
|
||||
txAudio.gain(i, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::muteTxIn(TxAudioCh ch) {
|
||||
if (ch < NUM_TX_AUDIO_CH) {
|
||||
if (!state.txIn[ch].mute) {
|
||||
state.txIn[ch].mute = true;
|
||||
txAudio.gain(ch, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::unmuteTxIn(TxAudioCh ch) {
|
||||
if (ch < NUM_TX_AUDIO_CH) {
|
||||
if (state.txIn[ch].mute) {
|
||||
state.txIn[ch].mute = false;
|
||||
rxAudio.gain(ch, state.txIn[ch].level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::setTxOutLevel(float level) {
|
||||
state.txOut.level = level;
|
||||
txOutAmp.gain(state.txOut.mute ? 0.0 : state.txOut.level);
|
||||
}
|
||||
|
||||
void UBitxDSP::muteTxOut() {
|
||||
if (!state.txOut.mute) {
|
||||
state.txOut.mute = true;
|
||||
txOutAmp.gain(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::unmuteTxOut() {
|
||||
if (state.txOut.mute) {
|
||||
state.txOut.mute = false;
|
||||
txOutAmp.gain(state.txOut.level);
|
||||
}
|
||||
}
|
||||
|
||||
void UBitxDSP::setLineInLevel(float level) {
|
||||
state.txIn[TX_LINE].level = level;
|
||||
txAudio.gain(TX_LINE, state.txIn[TX_LINE].mute ? 0.0 : state.txIn[TX_LINE].level);
|
||||
}
|
||||
|
||||
void UBitxDSP::setUSBInLevel(float level) {
|
||||
state.txIn[TX_USB].level = level;
|
||||
txAudio.gain(TX_USB, state.txIn[TX_USB].mute ? 0.0 : state.txIn[TX_USB].level);
|
||||
}
|
||||
|
||||
void UBitxDSP::setTxAudioIn(TxAudioIn src, bool isTemp) {
|
||||
if (!isTemp) {
|
||||
txSrc = src;
|
||||
}
|
||||
|
||||
if (!isTx) {
|
||||
muteTxIn(); // Mute all channels, then unmute the desired ones.
|
||||
switch (src) { // Don't switch inputs while transmitting.
|
||||
case MIC_IN:
|
||||
// Note that we can't actually use the VOX code on the mic input,
|
||||
// because we can't make the actual mic input active without
|
||||
// losing our receive audio. So, mic input is never actually
|
||||
// selected until it is time for it to transmit, which makes the
|
||||
// VOX moot. The caller must make use of an external, analog VOX
|
||||
// circuit driving a GPIO pin, or something similar (or the PTT of
|
||||
// course) to begin actually using the mic input. So this case
|
||||
// just falls through to the line input.
|
||||
|
||||
case LINE_IN:
|
||||
unmuteTxIn(TX_LINE);
|
||||
break;
|
||||
|
||||
case USB_IN:
|
||||
unmuteTxIn(TX_USB);
|
||||
break;
|
||||
|
||||
case TUNE_IN:
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.frequency(1500); // TODO: Make this dynamic based on CW (sidetone freq) versus data (1500 Hz)
|
||||
unmuteTxIn(TX_TONE1);
|
||||
break;
|
||||
|
||||
case TWO_TONE_IN:
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.amplitude(1.0); // TODO - just do this once.
|
||||
tone1.frequency(700);
|
||||
tone2.frequency(1900);
|
||||
unmuteTxIn(TX_TONE1);
|
||||
unmuteTxIn(TX_TONE2);
|
||||
break;
|
||||
|
||||
default:
|
||||
// should never happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Receive audio filter (band pass)
|
||||
**********************************************************************/
|
||||
|
||||
const int minRxFilterLo = MIN_RX_FILTER_LO;
|
||||
const int maxRxFilterHi = MAX_RX_FILTER_HI;
|
||||
const int minRxFilterWidth = MIN_RX_FILTER_WIDTH;
|
||||
const int maxRxFilterWidth = MAX_RX_FILTER_WIDTH;
|
||||
const int minRxFilterCenter = MIN_RX_FILTER_CENTER;
|
||||
const int maxRxFilterCenter = MAX_RX_FILTER_CENTER;
|
||||
|
||||
/*!
|
||||
* @brief Bypass the RX audio filter.
|
||||
*/
|
||||
void UBitxDSP::bypassRxFilter() {
|
||||
rxFilter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Update the RX audio filter using the currently set low and
|
||||
high frequencies. This is called by each of the public
|
||||
filter methods to update the filter with new frequencies.
|
||||
*/
|
||||
void UBitxDSP::updateRxFilter() {
|
||||
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, double(state.rxFilterLo), double(state.rxFilterHi));
|
||||
rxFilter.begin(coefficients, NUM_COEFFICIENTS);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilter(int lo, int hi) {
|
||||
if (hi < lo + minRxFilterWidth) {
|
||||
hi = lo + minRxFilterWidth;
|
||||
}
|
||||
if (hi > maxRxFilterHi) {
|
||||
hi = maxRxFilterHi;
|
||||
}
|
||||
if (lo > hi - minRxFilterWidth) {
|
||||
lo = hi - minRxFilterWidth;
|
||||
}
|
||||
if (lo < minRxFilterLo) {
|
||||
lo = minRxFilterLo;
|
||||
}
|
||||
state.rxFilterHi = hi;
|
||||
state.rxFilterLo = lo;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterLo(int lo) {
|
||||
if (lo > state.rxFilterHi - minRxFilterWidth) {
|
||||
lo = state.rxFilterHi - minRxFilterWidth;
|
||||
}
|
||||
if (lo < minRxFilterLo) {
|
||||
lo = minRxFilterLo;
|
||||
}
|
||||
state.rxFilterLo = lo;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterHi(int hi) {
|
||||
if (hi < state.rxFilterLo + minRxFilterWidth) {
|
||||
hi = state.rxFilterLo + minRxFilterWidth;
|
||||
}
|
||||
if (hi > maxRxFilterHi) {
|
||||
hi = maxRxFilterHi;
|
||||
}
|
||||
state.rxFilterHi = hi;
|
||||
updateRxFilter();
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterWidth(int width) {
|
||||
if (width < minRxFilterWidth) {
|
||||
width = minRxFilterWidth;
|
||||
} else if (width > maxRxFilterWidth) {
|
||||
width = maxRxFilterWidth;
|
||||
}
|
||||
int center = (state.rxFilterHi + state.rxFilterLo) / 2;
|
||||
int lo = center - (width / 2);
|
||||
int hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
void UBitxDSP::setRxFilterCenter(int center) {
|
||||
if (center < minRxFilterCenter) {
|
||||
center = minRxFilterCenter;
|
||||
} else if (center > maxRxFilterCenter) {
|
||||
center = maxRxFilterCenter;
|
||||
}
|
||||
int width = state.rxFilterHi - state.rxFilterLo;
|
||||
int lo = center - (width / 2);
|
||||
int hi = center + (width / 2);
|
||||
setRxFilter(lo, hi);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Transmit Voice-Operated-Switch (VOX)
|
||||
**********************************************************************/
|
||||
|
||||
float UBitxDSP::getVoxLevel() const {
|
||||
if (return txVoxLevel.available()) {
|
||||
prevVox = txVoxLevel.read();
|
||||
}
|
||||
return prevVox;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Singleton - the DSP instance
|
||||
**********************************************************************/
|
||||
|
||||
// TODO: Fix this. This won't work... this compilation unit won't be
|
||||
// able to instantiate a class it doesn't know about.
|
||||
|
||||
#ifndef UBITXDSP_CLASS
|
||||
#define UBITXDSP_CLASS UBitxDSP
|
||||
#endif
|
||||
|
||||
UBITXDSP_CLASS theDSP;
|
||||
UBitxDSP& DSP = theDSP;
|
||||
|
||||
/*
|
||||
NOTES
|
||||
|
||||
Major functions:
|
||||
- tx() - start transmitting / pause receiving
|
||||
- rx() - stop transmitting / resume receiving
|
||||
- setTxSource() - set the TX audio source to MIC_IN, LINE_IN, or USB_IN
|
||||
- also sets the relevant VOX source/parameters (as applicable)
|
||||
|
||||
Receive audio chain:
|
||||
-
|
||||
*/
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
283
TeensyDSP/DSP.h
Normal file
283
TeensyDSP/DSP.h
Normal file
@@ -0,0 +1,283 @@
|
||||
//======================================================================
|
||||
// DSP.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __DSP_h__
|
||||
#define __DSP_h__
|
||||
|
||||
#include <Audio.h>
|
||||
#include <dynamicFilters.h>
|
||||
#include "Debug.h"
|
||||
|
||||
/**********************************************************************
|
||||
* Macros
|
||||
**********************************************************************/
|
||||
|
||||
#define MIN_RX_FILTER_LO (0.0) //! Min allowable value of the RX filter low-cut frequency
|
||||
#define MAX_RX_FILTER_HI (5000.0) //! Max allowable value of the RX filter hi-cut frequency
|
||||
#define MIN_RX_FILTER_WIDTH (0.0) //! Min allowable value of the RX filter bandwidth
|
||||
#define MAX_RX_FILTER_WIDTH (5000.0) //! Max allowable value of the RX filter bandwidth
|
||||
#define MIN_RX_FILTER_CENTER (0.0) //! Min allowable value of the RX filter center frequency
|
||||
#define MAX_RX_FILTER_CENTER (5000.0) //! Max allowable value of the RX filter center frequency
|
||||
|
||||
#define DSP_MILLIS_PER_UPDATE (100) //! Number of milliseconds between update of the DSP object
|
||||
|
||||
#define TX_VOX_MIC_THRESH (0.0) //! Threshold for mic VOX (not implemented, since mic requires special handling)
|
||||
#define TX_VOX_LINE_THRESH (0.25) //! Threshold for line in VOX
|
||||
#define TX_VOX_USB_THRESH (0.25) //! Threshold for USB VOX
|
||||
#define TX_VOX_TUNE_THRESH (0.0) //! Threshold for tune (single tone) VOX (not expected to be used)
|
||||
#define TX_VOX_TT_THRESH (0.0) //! Threshold for two-tone VOX (not expected to be used)
|
||||
#define TX_VOX_DELAY (500) //! VOX delay in milliseconds
|
||||
|
||||
/**********************************************************************
|
||||
* Enumerations
|
||||
**********************************************************************/
|
||||
|
||||
//! Defines the four separate RX audio input channels available.
|
||||
enum RxAudioCh {
|
||||
RX_AUDIO = 0, // Normal receiver audio input channel
|
||||
RX_SPARE, // Not used
|
||||
RX_TONE1 , // Optional tone #1 input channel (currently not used)
|
||||
RX_TONE2, // Optional tone #2 input channel (currently not used)
|
||||
NUM_RX_AUDIO_CH // Total number of channels
|
||||
};
|
||||
|
||||
//! Defines the different RX audio inputs (not channels).
|
||||
enum RxAudioIn {
|
||||
RIG_IN = 0, // Normal rig input (receiver audio)
|
||||
NUM_RX_AUDIO_IN // Total number of inputs
|
||||
};
|
||||
|
||||
//! Defines the different RX audio outputs.
|
||||
enum RxAudioOut {
|
||||
LINE_OUT = 0, // Line audio out (and speaker)
|
||||
USB_OUT, // USB audio out
|
||||
NUM_RX_AUDIO_OUT
|
||||
};
|
||||
|
||||
//! Defines the four separate TX audio input channels available.
|
||||
enum TxAudioCh {
|
||||
TX_LINE = 0, // Line and/or mic audio input channel
|
||||
TX_USB, // USB audio input channel
|
||||
TX_TONE1, // Audio tone #1 input channel
|
||||
TX_TONE2, // Audio tone #2 input channel
|
||||
NUM_TX_AUDIO_CH // Toal number of channels
|
||||
};
|
||||
|
||||
//! Defines the different TX audio input sources (not channels!).
|
||||
enum TxAudioIn {
|
||||
MIC_IN = 0, // Microphone transmit audio input
|
||||
LINE_IN, // Line ("AUX") transmit audio input
|
||||
USB_IN, // USB transmit audio input
|
||||
TUNE_IN, // Tune input (transmits a single tone)
|
||||
TWO_TONE_IN, // Two tone audio input (transmits two tones)
|
||||
NUM_TX_AUDIO_IN // Total number of inputs
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* Classes
|
||||
**********************************************************************/
|
||||
|
||||
//! Defines parameters for a simple audio channel that can be muted.
|
||||
struct AudioChannel {
|
||||
bool mute = false;
|
||||
float level = 0.0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contains the current 'persistent' state of the DSP.
|
||||
* This includes all audio-specific state that can be saved to, or
|
||||
* restored from, EEPROM. It does not include 'transient' state (such
|
||||
* as whether we're currently transmitting or receiving).
|
||||
*/
|
||||
struct DSPState {
|
||||
|
||||
//! Receiver audio inputs; all default to muted.
|
||||
AudioChannel rxIn[NUM_RX_AUDIO_CH] = {
|
||||
{true, 1.0}, // audio
|
||||
{true, 0.0}, // spare 1
|
||||
{true, 0.0}, // spare 2
|
||||
{true, 0.0} // spare 3
|
||||
};
|
||||
|
||||
//! Receiver audio output; defaults to un
|
||||
muted.
|
||||
AudioChannel rxOut[NUM_RX_AUDIO_OUT] = {
|
||||
{false, 1.0}, // line
|
||||
{false, 1.0} // USB
|
||||
};
|
||||
|
||||
//! Transmitter audio inputs; all default to muted.
|
||||
AudioChannel txIn[NUM_TX_AUDIO_CH] = {
|
||||
{true, 0.1}, // line
|
||||
{true, 0.1}, // USB
|
||||
{true, 0.1}, // tone 1
|
||||
{true, 0.1} // tone 2
|
||||
};
|
||||
|
||||
//! Tranmitter audio output; defaults to muted.
|
||||
AudioChannel txOut = {true, 1.0};
|
||||
|
||||
//! Current RX filter settings
|
||||
float rxFilterLo = 300.0;
|
||||
float rxFilterHi = 3000.0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Defines the DSP subsystem of the UBitx V5X.
|
||||
* The DSP subsystem, which relies on the Teensy Audio Library, is
|
||||
* responsible for setting up the audio inputs and outputs for both
|
||||
* receive (RX) and transmit (TX) audio, maintaining the correct path
|
||||
* between inputs and outputs based on current TX/RX state, and setting
|
||||
* up audio filters and other audio-based modules for the RX and TX
|
||||
* audio paths.
|
||||
*/
|
||||
class UBitxDSP {
|
||||
|
||||
/********************************************************************
|
||||
* Object creation/deletion
|
||||
********************************************************************/
|
||||
|
||||
public:
|
||||
UBitxDSP() {}
|
||||
|
||||
/********************************************************************
|
||||
* Basic administration
|
||||
********************************************************************/
|
||||
|
||||
public:
|
||||
void begin();
|
||||
void update();
|
||||
void end();
|
||||
|
||||
/********************************************************************
|
||||
* Transmit/Receive switching
|
||||
********************************************************************/
|
||||
|
||||
public:
|
||||
void rx();
|
||||
inline void tx() { tx(txSrc); }
|
||||
void tx(TxAudioIn src);
|
||||
|
||||
/********************************************************************
|
||||
* General audio setup -- called via begin()
|
||||
********************************************************************/
|
||||
|
||||
protected:
|
||||
virtual void setupRxAudio();
|
||||
virtual void setupTxAudio();
|
||||
|
||||
/********************************************************************
|
||||
* Receive audio chain
|
||||
********************************************************************/
|
||||
|
||||
// Basic control of RX audio inputs and outputs.
|
||||
public:
|
||||
void setRxInLevel(RxAudioCh ch, float level); // Set the audio input level for a given channel.
|
||||
void muteRxIn(); // Mute all RX audio input channels.
|
||||
void muteRxIn(RxAudioCh ch); // Mute a specific RX audio input channel.
|
||||
void unmuteRxIn(RxAudioCh ch); // Un-mute a specific RX audio input channel.
|
||||
|
||||
void setLineOutLevel(float level); // Set the line output level (0.0 - 1.0).
|
||||
void setUSBOutLevel(float level); // Set the USB output level (0.0 - 1.0).
|
||||
|
||||
/********************************************************************
|
||||
* Transmit audio chain
|
||||
********************************************************************/
|
||||
|
||||
// Basic control of TX audio inputs and outputs.
|
||||
public:
|
||||
void setTxInLevel(TxAudioCh ch, float level); // Set the audio input level for a given channel.
|
||||
void muteTxIn(); // Mute all TX audio input channels.
|
||||
void muteTxIn(TxAudioCh ch); // Mute a specific TX audio input channel.
|
||||
void unmuteTxIn(TxAudioCh ch); // Un-mute a specific TX audio input channel.
|
||||
|
||||
void setTxOutLevel(float level); // Set the TX audio output level.
|
||||
void muteTxOut(); // Mute the TX audio output.
|
||||
void unmuteTxOut(); // Un-mute the TX audio output.
|
||||
|
||||
void setLineInLevel(float level); // Set the line input level (0.0 - 1.0).
|
||||
void setUSBInLevel(float level); // Set the USB input level (0.0 - 1.0).
|
||||
|
||||
// Transmit audio selection (may be overriden at actual transmit time).
|
||||
public:
|
||||
void setTxAudioIn(TxAudioIn src, bool isTemp = false); // Select a specific TX audio input path, and identify it as permanent or temporary.
|
||||
inline TxAudioIn getTxAudioIn() const { return txSrc; } // Return the current TX audio input.
|
||||
|
||||
// Mic input controls.
|
||||
public:
|
||||
inline void setMicGain(float level) { micGain = static_cast<unsigned>(level * 63.0); } // Set the mic gain.
|
||||
|
||||
/********************************************************************
|
||||
* Receive audio filter (band pass)
|
||||
********************************************************************/
|
||||
|
||||
public:
|
||||
void bypassRxFilter();
|
||||
void updateRxFilter();
|
||||
|
||||
void setRxFilter(float lo, float hi);
|
||||
void setRxFilterLo(float lo);
|
||||
void setRxFilterHi(float hi);
|
||||
void setRxFilterWidth(float width);
|
||||
void setRxFilterCenter(float center);
|
||||
|
||||
/*!
|
||||
* Get the current low frequency bound of the RX band pass filter.
|
||||
* @return The low frequency bound.
|
||||
*/
|
||||
inline float getRxFilterLo() const { return state.rxFilterLo; }
|
||||
|
||||
/*!
|
||||
* Get the current high frequency bound of the RX band pass filter.
|
||||
* @return The high frequency bound.
|
||||
*/
|
||||
inline float getRxFilterHi() const { return state.rxFilterHi; }
|
||||
|
||||
/*!
|
||||
* Get the current width of the RX band pass filter.
|
||||
* @return The filter width.
|
||||
*/
|
||||
inline float getRxFilterWidth() const { return state.rxFilterHi - state.rxFilterLo; }
|
||||
|
||||
/*!
|
||||
* Get the current center frequency of the RX band pass filter.
|
||||
* @return The center frequency.
|
||||
*/
|
||||
inline float getRxFilterCenter() const { return (state.rxFilterHi + state.rxFilterLo) / 2.0; }
|
||||
|
||||
/********************************************************************
|
||||
* Transmit Voice-Operated-Switch (VOX)
|
||||
********************************************************************/
|
||||
|
||||
public:
|
||||
float getVoxLevel() const;
|
||||
|
||||
/********************************************************************
|
||||
* Private state
|
||||
********************************************************************/
|
||||
|
||||
private:
|
||||
DSPState state;
|
||||
|
||||
bool isTx = false;
|
||||
TxAudioIn txSrc = MIC_IN;
|
||||
TxAudioIn txSrcLatched = MIC_IN;
|
||||
|
||||
short coefficients[NUM_COEFFICIENTS] = {0};
|
||||
|
||||
elapsedMillis sinceLastUpdate = 0;
|
||||
float usbVol = 0.0;
|
||||
|
||||
unsigned micGain = 0;
|
||||
|
||||
float prevVox = 0.0;
|
||||
};
|
||||
|
||||
extern UBitxDSP& DSP;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
20
TeensyDSP/Debug.h
Normal file
20
TeensyDSP/Debug.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __Debug_h__
|
||||
#define __Debug_h__
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBGPRINT(MSG) do { Serial.print("DBG: "); Serial.print(MSG); } while (0)
|
||||
#define DBGPRINTLN(MSG) do { Serial.print("DBG: "); Serial.println(MSG); } while (0)
|
||||
#define DBGNEWLINE() do { Serial.println(); } while (0)
|
||||
#define DBGCMD(CMD) do { Serial.print("DBG: "); Serial.println(#CMD); CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do { CMD; } while (0)
|
||||
#else
|
||||
#define DBGPRINT(MSG) do {} while (0)
|
||||
#define DBGPRINTLN(MSG) do {} while (0)
|
||||
#define DBGNEWLINE() do {} while (0)
|
||||
#define DBGCMD(CMD) do { CMD; } while (0)
|
||||
#define IFDEBUG(CMD) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
186
TeensyDSP/HamFuncs.h
Normal file
186
TeensyDSP/HamFuncs.h
Normal file
@@ -0,0 +1,186 @@
|
||||
#ifndef __HamFuncs_h__
|
||||
#define __HamFuncs_h__
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef HF_PWR_DEFAULT_LOAD
|
||||
#define HF_PWR_DEFAULT_LOAD 50.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_VSWR_MAX_REPORTED
|
||||
#define HF_VSWR_MAX_REPORTED 9.9
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_FWD_VRECT
|
||||
#define HF_BRIDGE_FWD_VRECT 0.25
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_FWD_TURNS
|
||||
#define HF_BRIDGE_FWD_TURNS 10.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_REV_VRECT
|
||||
#define HF_BRIDGE_REV_VRECT 0.25
|
||||
#endif
|
||||
|
||||
#ifndef HF_BRIDGE_REV_TURNS
|
||||
#define HF_BRIDGE_REV_TURNS 10.0
|
||||
#endif
|
||||
|
||||
#ifndef HF_ADC_DEFAULT_BITS
|
||||
#define HF_ADC_DEFAULT_BITS 10
|
||||
#endif
|
||||
|
||||
#ifndef HF_ADC_DEFAULT_VREF
|
||||
#define HF_ADC_DEFAULT_VREF 3.3
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
namespace HF {
|
||||
|
||||
const float pwrDefaultLoad = HF_PWR_DEFAULT_LOAD;
|
||||
const float vswrMaxReported = HF_VSWR_MAX_REPORTED;
|
||||
const float bridgeFwdVrect = HF_BRIDGE_FWD_VRECT;
|
||||
const float bridgeFwdTurns = HF_BRIDGE_FWD_TURNS;
|
||||
const float bridgeRevVrect = HF_BRIDGE_REV_VRECT;
|
||||
const float bridgeRevTurns = HF_BRIDGE_REV_TURNS;
|
||||
const unsigned adcDefaultBits = HF_ADC_DEFAULT_BITS;
|
||||
const float adcDefaultVref = HF_ADC_DEFAULT_VREF;
|
||||
|
||||
const float rms = sqrt(2.0) / 2.0;
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Calculate the output voltage of a resistive divider
|
||||
* network, given the input voltage and the values of the
|
||||
* resistors. The input voltage is applied to R1, the output
|
||||
* voltage is taken from the junction of R1 and R2, and R2 is
|
||||
* connected to ground.
|
||||
* @param Vin
|
||||
* Input voltage.
|
||||
* @param R1
|
||||
* Input resistor (ohms). Input voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @param R2
|
||||
* Output resistor (ohms). Output voltage is measured
|
||||
* between the top of this resistor and ground.
|
||||
* @return Output voltage.
|
||||
*/
|
||||
inline float divOut(float Vin, float R1, float R2) {
|
||||
return Vin * R2 / (R1 + R2);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate the input voltage of a resistive divider
|
||||
* network, given the output voltage and the values of the
|
||||
* resistors. The input voltage is applied to R1, the output
|
||||
* voltage is taken from the junction of R1 and R2, and R2 is
|
||||
* connected to ground.
|
||||
* @param Vout
|
||||
* Output voltage.
|
||||
* @param R1
|
||||
* Input resistor (ohms). Input voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @param R2
|
||||
* Output resistor (ohms). Output voltage is measured between
|
||||
* the top of this resistor and ground.
|
||||
* @return Input voltage.
|
||||
*/
|
||||
inline float divIn(float Vout, float R1, float R2) {
|
||||
return Vout * (R1 + R2) / R2;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the power in watts, given a
|
||||
* resistance and the voltage across the resistance.
|
||||
* @param V
|
||||
* Voltage across the load.
|
||||
* @param R
|
||||
* (optional) Resistance of the load (ohms). If not provided,
|
||||
* a default is used (HF_PWR_DEFAULT_LOAD).
|
||||
* @return Power dissipated (watts). This is calculated as
|
||||
* P = V^2/R.
|
||||
*/
|
||||
inline float P(float V, float R = pwrDefaultLoad) {
|
||||
return (V * V) / R;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the Voltage Standing Wave Ratio
|
||||
* (VSWR) based on the given forward and reverse voltages.
|
||||
* @param Vfwd
|
||||
* Measured forward voltage.
|
||||
* @param Vrev
|
||||
* Measured reverse voltage.
|
||||
* @param VSWRmax
|
||||
* (optional) Maximum reported VSWR. The output will be
|
||||
* clamped to this value if necessary (HF_VSWR_MAX_REPORTED).
|
||||
* @return Voltage Standing Wave Ratio (VSWR). This is calculated
|
||||
* as VSWR = (Vfwd + Vrev) / (Vfwd - Vrev).
|
||||
*/
|
||||
inline float VSWR(float Vfwd, float Vrev, float VSWRmax = vswrMaxReported) {
|
||||
if (Vfwd - Vrev == 0.0) {
|
||||
return VSWRmax;
|
||||
} else {
|
||||
float swr = (Vfwd + Vrev) / (Vfwd - Vrev);
|
||||
return (swr > VSWRmax ? VSWRmax : swr);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the forward RMS input voltage across
|
||||
* a Stockton bridge.
|
||||
* @param Vout
|
||||
* Rectified output voltage (e.g. read via an ADC).
|
||||
* @param Vrect
|
||||
* (optional) Voltage drop across the rectifier diode. If
|
||||
* not provided, a default is used (HF_BRIDGE_FWD_VRECT).
|
||||
* @param turns
|
||||
* (optional) Coupling transformer turns ratio. If not
|
||||
* provided, a default is used (HF_BRIDGE_FWD_TURNS).
|
||||
* @return Input voltage (i.e. the actual forward voltage).
|
||||
*/
|
||||
inline float bridgeFwd(float Vout, float Vrect = bridgeFwdVrect, float turns = bridgeFwdTurns) {
|
||||
return (Vout + Vrect) * turns * rms;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the reverse RMS input voltage across
|
||||
* a Stockton bridge.
|
||||
* @param Vout
|
||||
* Rectified output voltage (e.g. read via an ADC).
|
||||
* @param Vrect
|
||||
* (optional) Voltage drop across the rectifier diode. If
|
||||
* not provided, a default is used (HF_BRIDGE_REV_VRECT).
|
||||
* @param turns
|
||||
* (optional) Coupling transformer turns ratio. If not
|
||||
* provided, a default is used (HF_BRIDGE_REV_TURNS).
|
||||
* @return Input voltage (i.e. the actual reverse voltage).
|
||||
*/
|
||||
inline float bridgeRev(float Vout, float Vrect = bridgeRevVrect, float turns = bridgeRevTurns) {
|
||||
return (Vout + Vrect) * turns * rms;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate and return the input voltage to an Analog-to-
|
||||
* Digital Converter (ADC) given the resolution (number of
|
||||
* bits) and the voltage reference of the ADC.
|
||||
* @param counts
|
||||
* Value of the ADC measurement (in unitless counts).
|
||||
* @param res
|
||||
* (optional) Resolution (in bits) of the ADC. If not
|
||||
* provided, the default is used (HF_ADC_DEFAULT_BITS).
|
||||
* @param Vref
|
||||
* (optional) Voltage reference of the ADC. If not
|
||||
* provided, the default is used (HF_ADC_DEFAULT_VREF).
|
||||
* @return Input voltage to the ADC.
|
||||
*/
|
||||
inline float adcIn(unsigned counts, unsigned res = adcDefaultBits, float Vref = adcDefaultVref) {
|
||||
return float(counts) * Vref / float(1 << res);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
185
TeensyDSP/Keyer.cpp
Normal file
185
TeensyDSP/Keyer.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
//======================================================================
|
||||
//
|
||||
// nanoIO paddle keyer (c) 2018, David Freese, W1HKJ
|
||||
//
|
||||
// based on code from Iambic Keyer Code Keyer Sketch
|
||||
// Copyright (c) 2009 Steven T. Elliott
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details:
|
||||
//
|
||||
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
// Boston, MA 02111-1307 USA
|
||||
//
|
||||
//======================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
//#include "TimerOne.h"
|
||||
//#include "config.h"
|
||||
#include "Keyer.h"
|
||||
|
||||
const uint8_t LP_in = KEYER_LEFT_PADDLE_PIN;
|
||||
const uint8_t RP_in = KEYER_RIGHT_PADDLE_PIN;
|
||||
|
||||
//#define ST_Freq 600 // Set the Sidetone Frequency to 600 Hz
|
||||
|
||||
//======================================================================
|
||||
// keyerControl bit definitions
|
||||
//
|
||||
#define DIT_L 0x01 // Dit latch
|
||||
#define DAH_L 0x02 // Dah latch
|
||||
#define DIT_PROC 0x04 // Dit is being processed
|
||||
#define PDLSWAP 0x08 // 0 for normal, 1 for swap
|
||||
//======================================================================
|
||||
//
|
||||
// State Machine Defines
|
||||
|
||||
enum KSTYPE { IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
|
||||
|
||||
UBitxKeyer::UBitxKeyer(int wpm, float weight):
|
||||
speed(wpm), symWeight(weight)
|
||||
{
|
||||
// Setup outputs
|
||||
pinMode(LP_in, INPUT_PULLUP); // sets Left Paddle digital pin as input
|
||||
pinMode(RP_in, INPUT_PULLUP); // sets Right Paddle digital pin as input
|
||||
|
||||
keyerState = IDLE;
|
||||
keyerControl = 0;
|
||||
keyMode = IAMBICA;
|
||||
keyDown = false;
|
||||
|
||||
calcRatio();
|
||||
}
|
||||
|
||||
// Calculate the length of dot, dash and silence
|
||||
void UBitxKeyer::calcRatio()
|
||||
{
|
||||
float w = (1 + symWeight) / (symWeight -1);
|
||||
spaceLen = (1200 / speed);
|
||||
dotLen = spaceLen * (w - 1);
|
||||
dashLen = (1 + w) * spaceLen;
|
||||
}
|
||||
|
||||
void UBitxKeyer::setWPM(int wpm)
|
||||
{
|
||||
speed = wpm;
|
||||
calcRatio();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Latch paddle press
|
||||
//======================================================================
|
||||
|
||||
void UBitxKeyer::updatePaddleLatch()
|
||||
{
|
||||
if (digitalRead(LP_in) == LOW) {
|
||||
keyerControl |= DIT_L;
|
||||
}
|
||||
if (digitalRead(RP_in) == LOW) {
|
||||
keyerControl |= DAH_L;
|
||||
}
|
||||
}
|
||||
|
||||
bool UBitxKeyer::doPaddles()
|
||||
{
|
||||
if (keyMode == STRAIGHT) { // Straight Key
|
||||
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW)) {
|
||||
keyDown = true;
|
||||
return true;
|
||||
} else {
|
||||
keyDown = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// keyerControl contains processing flags and keyer mode bits
|
||||
// Supports Iambic A and B
|
||||
// State machine based, uses calls to millis() for timing.
|
||||
switch (keyerState) {
|
||||
case IDLE: // Wait for direct or latched paddle press
|
||||
if ((digitalRead(LP_in) == LOW) || (digitalRead(RP_in) == LOW) || (keyerControl & 0x03)) {
|
||||
updatePaddleLatch();
|
||||
keyerState = CHK_DIT;
|
||||
// letting this fall through // return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// break;
|
||||
|
||||
case CHK_DIT: // See if the dit paddle was pressed
|
||||
if (keyerControl & DIT_L) {
|
||||
keyerControl |= DIT_PROC;
|
||||
ktimer = dotLen;
|
||||
keyerState = KEYED_PREP;
|
||||
return true;
|
||||
} else { // fall through
|
||||
keyerState = CHK_DAH;
|
||||
}
|
||||
|
||||
case CHK_DAH: // See if dah paddle was pressed
|
||||
if (keyerControl & DAH_L) {
|
||||
ktimer = dashLen;
|
||||
keyerState = KEYED_PREP;
|
||||
// letting this fall through // return true;
|
||||
} else {
|
||||
keyerState = IDLE;
|
||||
return false;
|
||||
}
|
||||
// break;
|
||||
|
||||
case KEYED_PREP: // Assert key down, start timing
|
||||
// state shared for dit or dah
|
||||
keyDown = true;
|
||||
ktimer += millis(); // set ktimer to interval end time
|
||||
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
|
||||
keyerState = KEYED; // next state
|
||||
// letting this fall through // return true;
|
||||
// break;
|
||||
|
||||
case KEYED: // Wait for timer to expire
|
||||
if (millis() > ktimer) { // are we at end of key down ?
|
||||
keyDown = false;
|
||||
ktimer = millis() + spaceLen; // inter-element time
|
||||
keyerState = INTER_ELEMENT; // next state
|
||||
// letting this fall through // return true;
|
||||
} else if (keyMode == IAMBICB) { // Iambic B Mode ?
|
||||
updatePaddleLatch(); // yes, early paddle latch in Iambic B mode
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// break;
|
||||
|
||||
case INTER_ELEMENT: // Insert time between dits/dahs
|
||||
updatePaddleLatch(); // latch paddle state
|
||||
if (millis() > ktimer) { // are we at end of inter-space ?
|
||||
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
|
||||
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
|
||||
keyerState = CHK_DAH; // dit done, check for dah
|
||||
return true;
|
||||
} else {
|
||||
keyerControl &= ~(DAH_L); // clear dah latch
|
||||
keyerState = IDLE; // go idle
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// break;
|
||||
}
|
||||
|
||||
return false; // resolve compiler warning; do we ever get here?
|
||||
}
|
||||
|
||||
UBitxKeyer basicKeyer(15, 3.0);
|
||||
UBitxKeyer& Keyer = basicKeyer;
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
79
TeensyDSP/Keyer.h
Normal file
79
TeensyDSP/Keyer.h
Normal file
@@ -0,0 +1,79 @@
|
||||
//**********************************************************************
|
||||
//
|
||||
// Keyer, a part of nanoIO
|
||||
//
|
||||
// nanoIO paddle keyer (c) 2018, David Freese, W1HKJ
|
||||
//
|
||||
// based on code from Iambic Keyer Code Keyer Sketch
|
||||
// Copyright (c) 2009 Steven T. Elliott
|
||||
//
|
||||
// nanoIO is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// nanoIO is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with fldigi. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//Revisions:
|
||||
//
|
||||
//1.0.0: Initial release
|
||||
//
|
||||
//**********************************************************************
|
||||
|
||||
|
||||
#ifndef __Keyer_h__
|
||||
#define __Keyer_h__
|
||||
|
||||
#define IAMBICA 0
|
||||
#define IAMBICB 1
|
||||
#define STRAIGHT 2
|
||||
|
||||
#define KEYER_LEFT_PADDLE_PIN 17
|
||||
#define KEYER_RIGHT_PADDLE_PIN 16
|
||||
|
||||
class UBitxKeyer
|
||||
{
|
||||
public:
|
||||
UBitxKeyer(int wpm, float weight);
|
||||
//void cw_pin(int pin);
|
||||
//void ptt_pin(int pin);
|
||||
void setWPM(int wpm);
|
||||
inline void setMode(int mode) { keyMode = mode; }
|
||||
inline int getMode() { return keyMode; }
|
||||
inline bool isDown() { return keyDown; }
|
||||
// void setWeight();
|
||||
|
||||
bool doPaddles();
|
||||
|
||||
private:
|
||||
void calcRatio();
|
||||
void updatePaddleLatch();
|
||||
|
||||
bool keyDown;
|
||||
|
||||
long ktimer;
|
||||
|
||||
int speed;
|
||||
int dashLen; // Length of dash
|
||||
int dotLen; // Length of dot
|
||||
int spaceLen; // Length of space
|
||||
float symWeight;
|
||||
|
||||
char keyerControl;
|
||||
char keyerState;
|
||||
int keyMode;
|
||||
};
|
||||
|
||||
extern UBitxKeyer& Keyer;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
141
TeensyDSP/Nextion.cpp
Normal file
141
TeensyDSP/Nextion.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "Nextion.h"
|
||||
|
||||
char L_nowdisp = -1; //Sended nowdisp
|
||||
char L_vfoActive; //vfoActive
|
||||
unsigned long L_vfoCurr; //vfoA
|
||||
byte L_vfoCurr_mode; //vfoA_mode
|
||||
unsigned long L_vfoA; //vfoA
|
||||
byte L_vfoA_mode; //vfoA_mode
|
||||
unsigned long L_vfoB; //vfoB
|
||||
byte L_vfoB_mode; //vfoB_mode
|
||||
char L_ritOn;
|
||||
unsigned long L_ritTxFrequency; //ritTxFrequency
|
||||
char L_inTx;
|
||||
byte L_isDialLock; //byte isDialLock
|
||||
byte L_Split; //isTxType
|
||||
byte L_TXStop; //isTxType
|
||||
byte L_tuneStepIndex; //byte tuneStepIndex
|
||||
byte L_scaledSMeter; //scaledSMeter
|
||||
unsigned long L_sideTone; //sideTone
|
||||
byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
|
||||
unsigned int L_cwSpeed; //cwSpeed
|
||||
byte L_cwDelayTime; //cwDelayTime
|
||||
byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
|
||||
byte L_attLevel;
|
||||
byte L_isIFShift; //1 = ifShift, 2 extend
|
||||
int L_ifShiftValue;
|
||||
byte L_sdrModeOn;
|
||||
byte scaledSMeter = 0;
|
||||
float calcVSWR = 0.0;
|
||||
float L_calcVSWR = 0.0;
|
||||
byte scaledVSWR = 0;
|
||||
byte L_scaledVSWR = 0;
|
||||
float fwdPower = 0;
|
||||
float L_fwdPower = 0;
|
||||
float revPower = 0;
|
||||
float L_revPower = 0;
|
||||
|
||||
|
||||
//Control must have prefix 'v' or 's'
|
||||
char softSTRHeader[11] = {'p', 'm', '.', 's', '0', '.', 't', 'x', 't', '=', '\"'};
|
||||
char softINTHeader[10] = {'p', 'm', '.', 'v', '0', '.', 'v', 'a', 'l', '='};
|
||||
|
||||
char softTemp[20];
|
||||
|
||||
/*!
|
||||
@brief Send a string or numeric variable to the Nextion LCD.
|
||||
@param varType
|
||||
The type of the variable being sent to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendHeader(char varType, char varIndex)
|
||||
{
|
||||
if (varType == SWS_HEADER_STR_TYPE)
|
||||
{
|
||||
softSTRHeader[4] = varIndex;
|
||||
for (unsigned i = 0; i < sizeof(softSTRHeader)/sizeof(softSTRHeader[0]); i++)
|
||||
Serial1.write(softSTRHeader[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
softINTHeader[4] = varIndex;
|
||||
for (unsigned i = 0; i < sizeof(softINTHeader)/sizeof(softINTHeader[0]); i++)
|
||||
Serial1.write(softINTHeader[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send an unsigned long variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandUL(char varIndex, unsigned long sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
|
||||
|
||||
memset(softTemp, 0, 20);
|
||||
ultoa(sendValue, softTemp, DEC);
|
||||
Serial1.print(softTemp);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send a (signed) long variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandL(char varIndex, long sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_INT_TYPE, varIndex);
|
||||
|
||||
memset(softTemp, 0, 20);
|
||||
ltoa(sendValue, softTemp, DEC);
|
||||
Serial1.print(softTemp);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
Serial1.write(0xff);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Send a string variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommandStr(char varIndex, const char* sendValue)
|
||||
{
|
||||
sendHeader(SWS_HEADER_STR_TYPE, varIndex);
|
||||
|
||||
Serial1.print(sendValue);
|
||||
Serial1.write('\"');
|
||||
Serial1.write(0xFF);
|
||||
Serial1.write(0xFF);
|
||||
Serial1.write(0xFF);
|
||||
}
|
||||
|
||||
unsigned char softBuff1Num[14] = {'p', 'm', '.', 'c', '0', '.', 'v', 'a', 'l', '=', 0, 0xFF, 0xFF, 0xFF};
|
||||
|
||||
/*!
|
||||
@brief Send a single digit variable to the Nextion LCD.
|
||||
@param varIndex
|
||||
The index (ID) of the variable being sent to the Nextion LCD.
|
||||
Values 0~9 are: Mode, nowDisp, ActiveVFO, IsDialLock, IsTxtType, IsSplitType.
|
||||
@param sendValue
|
||||
The value of the variable being sent to the Nextion LCD.
|
||||
*/
|
||||
void sendCommand1Num(char varIndex, char sendValue)
|
||||
{
|
||||
softBuff1Num[4] = varIndex;
|
||||
softBuff1Num[10] = sendValue + 0x30; // convert to character digit
|
||||
|
||||
for (unsigned i = 0; i < sizeof(softBuff1Num)/sizeof(softBuff1Num[0]); i++)
|
||||
Serial1.write(softBuff1Num[i]);
|
||||
}
|
126
TeensyDSP/Nextion.h
Normal file
126
TeensyDSP/Nextion.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef __Nextion_h__
|
||||
#define __Nextion_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Debug.h"
|
||||
|
||||
#define SWS_HEADER_CHAR_TYPE 'c' //1Byte Protocol Prefix
|
||||
#define SWS_HEADER_INT_TYPE 'v' //Numeric Protocol Prefex
|
||||
#define SWS_HEADER_STR_TYPE 's' //for TEXT Line compatiable Character LCD Control
|
||||
|
||||
//===================================================================
|
||||
//Begin of Nextion LCD Protocol
|
||||
//
|
||||
// v0~v9, va~vz : Numeric (Transceiver -> Nextion LCD)
|
||||
// s0~s9 : String (Text) (Transceiver -> Nextion LCD)
|
||||
// vlSendxxx, vloxxx: Reserve for Nextion (Nextion LCD -> Transceiver)
|
||||
//
|
||||
//===================================================================
|
||||
|
||||
#define CMD_NOW_DISP '0' //c0
|
||||
extern char L_nowdisp; //Sended nowdisp
|
||||
|
||||
#define CMD_VFO_TYPE 'v' //cv
|
||||
extern char L_vfoActive; //vfoActive
|
||||
|
||||
#define CMD_CURR_FREQ 'c' //vc
|
||||
extern unsigned long L_vfoCurr; //vfoA
|
||||
#define CMD_CURR_MODE 'c' //cc
|
||||
extern byte L_vfoCurr_mode; //vfoA_mode
|
||||
|
||||
#define CMD_VFOA_FREQ 'a' //va
|
||||
extern unsigned long L_vfoA; //vfoA
|
||||
#define CMD_VFOA_MODE 'a' //ca
|
||||
extern byte L_vfoA_mode; //vfoA_mode
|
||||
|
||||
#define CMD_VFOB_FREQ 'b' //vb
|
||||
extern unsigned long L_vfoB; //vfoB
|
||||
#define CMD_VFOB_MODE 'b' //cb
|
||||
extern byte L_vfoB_mode; //vfoB_mode
|
||||
|
||||
#define CMD_IS_RIT 'r' //cr
|
||||
extern char L_ritOn;
|
||||
#define CMD_RIT_FREQ 'r' //vr
|
||||
extern unsigned long L_ritTxFrequency; //ritTxFrequency
|
||||
|
||||
#define CMD_IS_TX 't' //ct
|
||||
extern char L_inTx;
|
||||
|
||||
#define CMD_IS_DIALLOCK 'l' //cl
|
||||
extern byte L_isDialLock; //byte isDialLock
|
||||
|
||||
#define CMD_IS_SPLIT 's' //cs
|
||||
extern byte L_Split; //isTxType
|
||||
#define CMD_IS_TXSTOP 'x' //cx
|
||||
extern byte L_TXStop; //isTxType
|
||||
|
||||
#define CMD_TUNEINDEX 'n' //cn
|
||||
extern byte L_tuneStepIndex; //byte tuneStepIndex
|
||||
|
||||
#define CMD_SMETER 'p' //cs
|
||||
extern byte L_scaledSMeter; //scaledSMeter
|
||||
|
||||
#define CMD_SIDE_TONE 't' //vt
|
||||
extern unsigned long L_sideTone; //sideTone
|
||||
#define CMD_KEY_TYPE 'k' //ck
|
||||
extern byte L_cwKeyType; //L_cwKeyType 0: straight, 1 : iambica, 2: iambicb
|
||||
|
||||
#define CMD_CW_SPEED 's' //vs
|
||||
extern unsigned int L_cwSpeed; //cwSpeed
|
||||
|
||||
#define CMD_CW_DELAY 'y' //vy
|
||||
extern byte L_cwDelayTime; //cwDelayTime
|
||||
|
||||
#define CMD_CW_STARTDELAY 'e' //ve
|
||||
extern byte L_delayBeforeCWStartTime; //byte delayBeforeCWStartTime
|
||||
|
||||
#define CMD_ATT_LEVEL 'f' //vf
|
||||
extern byte L_attLevel;
|
||||
|
||||
extern byte L_isIFShift; //1 = ifShift, 2 extend
|
||||
#define CMD_IS_IFSHIFT 'i' //ci
|
||||
|
||||
extern int L_ifShiftValue;
|
||||
#define CMD_IFSHIFT_VALUE 'i' //vi
|
||||
|
||||
extern byte L_sdrModeOn;
|
||||
#define CMD_SDR_MODE 'j' //cj
|
||||
|
||||
#define CMD_UBITX_INFO 'm' //cm Complete Send uBITX Information
|
||||
|
||||
//Once Send Data, When boot
|
||||
//arTuneStep, When boot, once send
|
||||
//long arTuneStep[5];
|
||||
|
||||
#define CMD_AR_TUNE1 '1' //v1
|
||||
#define CMD_AR_TUNE2 '2' //v2
|
||||
#define CMD_AR_TUNE3 '3' //v3
|
||||
#define CMD_AR_TUNE4 '4' //v4
|
||||
#define CMD_AR_TUNE5 '5' //v5
|
||||
|
||||
//int idleStep = 0;
|
||||
extern byte scaledSMeter;
|
||||
|
||||
extern float calcVSWR;
|
||||
extern float L_calcVSWR;
|
||||
|
||||
extern byte scaledVSWR;
|
||||
extern byte L_scaledVSWR;
|
||||
|
||||
extern float fwdPower;
|
||||
extern float L_fwdPower;
|
||||
|
||||
extern float revPower;
|
||||
extern float L_revPower;
|
||||
|
||||
void sendHeader(char varType, char varIndex);
|
||||
void sendCommandUL(char varIndex, unsigned long sendValue);
|
||||
void sendCommandL(char varIndex, long sendValue);
|
||||
void sendCommandStr(char varIndex, const char* sendValue);
|
||||
void sendCommand1Num(char varIndex, char sendValue);
|
||||
|
||||
//=======================================================
|
||||
//END OF Nextion Protocol
|
||||
//=======================================================
|
||||
|
||||
#endif
|
3
TeensyDSP/Rig.cpp
Normal file
3
TeensyDSP/Rig.cpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "Rig.h"
|
||||
|
||||
UBitxRig Rig;
|
73
TeensyDSP/Rig.h
Normal file
73
TeensyDSP/Rig.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef __Rig_h__
|
||||
#define __Rig_h__
|
||||
|
||||
#include "RigState.h"
|
||||
|
||||
struct RigState {
|
||||
};
|
||||
|
||||
class UBitxRig {
|
||||
public:
|
||||
inline void begin() {}
|
||||
inline void update() {}
|
||||
|
||||
inline unsigned getFreqA() const { return radState.getFreqA(); }
|
||||
inline unsigned getFreqB() const { return radState.getFreqB(); }
|
||||
inline int getRIT() const { return radState.getRIT(); }
|
||||
inline int getXIT() const { return radState.getXIT(); }
|
||||
inline bool isVFOA() const { return radState.isVFOA(); }
|
||||
inline bool isVFOB() const { return radState.isVFOB(); }
|
||||
inline bool isSplit() const { return radState.isSplit(); }
|
||||
inline bool isRIT() const { return radState.isRIT(); }
|
||||
inline bool isXIT() const { return radState.isXIT(); }
|
||||
inline bool isModeCWAny() const { return radState.isModeCWAny(); }
|
||||
inline bool isModeCW() const { return radState.isModeCW(); }
|
||||
inline bool isModeCWR() const { return radState.isModeCWR(); }
|
||||
inline bool isModeUSB() const { return radState.isModeUSB(); }
|
||||
inline bool isModeLSB() const { return radState.isModeLSB(); }
|
||||
inline bool isAI() const { return autoInfo; }
|
||||
|
||||
inline void setFreqA(unsigned freq) { catState.setFreqA(freq); }
|
||||
inline void setFreqB(unsigned freq) { catState.setFreqB(freq); }
|
||||
inline void setRIT(int freq) { catState.setRIT(freq); }
|
||||
inline void setXIT(int freq) { catState.setXIT(freq); }
|
||||
inline void setVFOA() { catState.setVFOA(); }
|
||||
inline void setVFOB() { catState.setVFOB(); }
|
||||
inline void setSplitOn() { catState.setSplitOn(); }
|
||||
inline void setSplitOff() { catState.setSplitOff(); }
|
||||
inline void setRITOn() { catState.setRITOn(); }
|
||||
inline void setRITOff() { catState.setRITOff(); }
|
||||
inline void setXITOn() { catState.setXITOn(); }
|
||||
inline void setXITOff() { catState.setXITOff(); }
|
||||
inline void setCW() { catState.setCW(); }
|
||||
inline void setCWR() { catState.setCWR(); }
|
||||
inline void setUSB() { catState.setUSB(); }
|
||||
inline void setLSB() { catState.setLSB(); }
|
||||
|
||||
inline void setAI(bool on) { autoInfo = on; }
|
||||
inline void aiOn() { autoInfo = true; }
|
||||
inline void aiOff() { autoInfo = false; }
|
||||
|
||||
inline UBitxRigState& cat() { return catState; }
|
||||
inline UBitxRigState& rad() { return radState; }
|
||||
|
||||
/********************************************************************/
|
||||
// New functional/mode-based Rig methods
|
||||
|
||||
// AG
|
||||
//void setVolOut(uint8_t level);
|
||||
//uint8_t getVolOut();
|
||||
|
||||
// BD/BU
|
||||
//void setBand();
|
||||
//void getBand();
|
||||
|
||||
private:
|
||||
UBitxRigState catState;
|
||||
UBitxRigState radState;
|
||||
bool autoInfo = false; // TODO: Move this to rig state struct
|
||||
};
|
||||
|
||||
extern UBitxRig Rig;
|
||||
|
||||
#endif
|
416
TeensyDSP/RigState.cpp
Normal file
416
TeensyDSP/RigState.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
/*!
|
||||
* @file RigState.cpp
|
||||
*
|
||||
* @mainpage uBITX V5X Software - RigState
|
||||
*
|
||||
* @section introsec Introduction
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section dependencies Dependencies
|
||||
*
|
||||
* TBD
|
||||
*
|
||||
* @section author Author
|
||||
*
|
||||
* Written by Rob "Scrape" French, KC4UPR
|
||||
*
|
||||
* @section license License
|
||||
*
|
||||
* TBD
|
||||
*/
|
||||
|
||||
#include "Debug.h"
|
||||
#include "RigState.h"
|
||||
|
||||
/***********************************************************************
|
||||
* COMMON FUNCTIONS
|
||||
*
|
||||
* The following are all common to RigState objects, whether on the
|
||||
* Raduino or on the TeensyDSP.
|
||||
**********************************************************************/
|
||||
|
||||
static uint32_t zeroes[1] = {0}; // used to transmit zeroes
|
||||
|
||||
/*!
|
||||
* @brief Begin using the RigState object. In order to force an
|
||||
* initial update (i.e. sending current state to the remote
|
||||
* device), all fields are initially marked dirty.
|
||||
*/
|
||||
void UBitxRigState::begin() {
|
||||
setDirty();
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RADUINO FUNCTIONS
|
||||
*
|
||||
* The following are specific to the Raduino implementation. Note that
|
||||
* this depends on the use of the TEENSYDUINO #define, which may result
|
||||
* in a fragile implementation for other development environments (e.g.
|
||||
* if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
#include <Wire.h>
|
||||
#include "ubitx.h"
|
||||
#include "ubitx_eemap.h"
|
||||
|
||||
extern unsigned long frequency, ritRxFrequency, ritTxFrequency;
|
||||
extern unsigned long vfoA;
|
||||
extern unsigned long vfoB;
|
||||
extern char cwMode;
|
||||
extern char isUSB;
|
||||
extern char vfoActive;
|
||||
extern char ritOn;
|
||||
extern char splitOn;
|
||||
extern char inTx;
|
||||
void setFrequency(unsigned long);
|
||||
|
||||
/*!
|
||||
* @brief Send the RigState from the Raduino to the TeensyDSP. The
|
||||
* basic process is: (1) read in any updated (dirty) data
|
||||
* from the Raduino's state variables; (2) transmit the dirty
|
||||
* data to the TeensyDSP; (2a) for clean data, zeroes are
|
||||
* transmitted; (3) mark all data as clean.
|
||||
*/
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
readDirty();
|
||||
Wire.beginTransmission(I2CMETER_ADDR);
|
||||
Wire.write(I2CMETER_RIGINF);
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
// otherwise, send out zeroes
|
||||
Wire.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
Wire.endTransmission();
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
//IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean();
|
||||
}
|
||||
|
||||
// delay(1); // 1ms - some delay required between ending transmission and requesting?
|
||||
|
||||
/*!
|
||||
* @brief Receive the RigState from the TeensyDSP. This generally
|
||||
* reflects changes due to CAT transmission to the TeensyDSP.
|
||||
* @param numBytes
|
||||
* Number of bytes received from the TeensyDSP.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
// Retrieve all of the deltas. Mark any received fields as dirty. It
|
||||
// is assumed that send_RIGINF() was called immedaitely before this,
|
||||
// so the fields are already clean.
|
||||
byte* ptr = (byte*)&data;
|
||||
Wire.requestFrom(I2CMETER_ADDR, sizeof(data));
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire.available(); j++) {
|
||||
byte incomingByte = Wire.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
writeDirty();
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
//IFDEBUG( serialPrettyState("Rcvd") );
|
||||
setClean(); // They get marked dirty as req'd during readDirty().
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Write dirty fields from the RigState out to the Raduino
|
||||
* variables.
|
||||
*/
|
||||
void UBitxRigState::writeDirty() {
|
||||
// VFO A frequency
|
||||
if (isDirty(VFOA_WORD)) {
|
||||
if (vfoActive == VFO_A) {
|
||||
setFrequency(getFreqA());
|
||||
} else {
|
||||
vfoA = getFreqA();
|
||||
}
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
if (isDirty(VFOB_WORD)) {
|
||||
if (vfoActive == VFO_B) {
|
||||
setFrequency(getFreqB());
|
||||
} else {
|
||||
vfoB = getFreqB();
|
||||
}
|
||||
}
|
||||
|
||||
// RIT and XIT frequencies
|
||||
if (isDirty(OFFSETS_WORD)) {
|
||||
// RIT
|
||||
ritRxFrequency = getRIT() + ritTxFrequency;
|
||||
if (ritOn == 1) {
|
||||
if (inTx == 0) {
|
||||
setFrequency(ritRxFrequency);
|
||||
} else {
|
||||
setFrequency(ritTxFrequency);
|
||||
}
|
||||
}
|
||||
// XIT - TODO
|
||||
}
|
||||
|
||||
// VFO A/B selection
|
||||
if (isDirty(FLAGS_WORD)) {
|
||||
char prev = vfoActive;
|
||||
vfoActive = isVFOA() ? VFO_A : VFO_B;
|
||||
if (vfoActive != prev) {
|
||||
if (vfoActive == VFO_A) {
|
||||
if (vfoA != frequency) {
|
||||
setFrequency(vfoA);
|
||||
}
|
||||
} else if (vfoActive == VFO_B) {
|
||||
if (vfoB != frequency) {
|
||||
setFrequency(vfoB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split on/off
|
||||
splitOn = isSplit() ? 1 : 0;
|
||||
|
||||
// RIT on/off
|
||||
prev = ritOn;
|
||||
ritOn = isRIT() ? 1 : 0;
|
||||
if (ritOn != prev) {
|
||||
if ((ritOn == 1) && (inTx == 0)) {
|
||||
setFrequency(ritRxFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// XIT on/off
|
||||
// TODO
|
||||
|
||||
// Mode
|
||||
prev = (cwMode << 1) | isUSB;
|
||||
isUSB = isModeUSB() ? 1 : 0;
|
||||
if (isModeCW()) {
|
||||
cwMode = 2; // 2 = cwu
|
||||
} else if (isModeCWR()) {
|
||||
cwMode = 1; // 1 = cwl
|
||||
} else {
|
||||
cwMode = 0; // 0 = no cw
|
||||
}
|
||||
if ((cwMode << 1) | isUSB != prev) {
|
||||
setFrequency(frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Read current Raduino variables into the RigState
|
||||
* (if they are changed) and set the appropriate dirty flags.
|
||||
* @param r
|
||||
* RigState reference to put the values into.
|
||||
*/
|
||||
void UBitxRigState::readDirty() {
|
||||
unsigned long freq;
|
||||
short offset;
|
||||
|
||||
// VFO A frequency
|
||||
freq = (vfoActive == VFO_A) ? frequency : vfoA;
|
||||
if (getFreqA() != freq) {
|
||||
setFreqA(freq);
|
||||
}
|
||||
|
||||
// VFO B frequency
|
||||
freq = (vfoActive == VFO_B) ? frequency : vfoB;
|
||||
if (getFreqB() != freq) {
|
||||
setFreqB(freq);
|
||||
}
|
||||
|
||||
// RIT frequency
|
||||
if (inTx) {
|
||||
offset = ritRxFrequency - ritTxFrequency;
|
||||
} else {
|
||||
offset = frequency - ritTxFrequency;
|
||||
}
|
||||
if (getRIT() != offset) {
|
||||
setRIT(offset);
|
||||
}
|
||||
|
||||
// XIT frequency
|
||||
offset = 0; // xitRxFrequency - frequency;
|
||||
if (getXIT() != offset) {
|
||||
setXIT(offset);
|
||||
}
|
||||
|
||||
// VFO A/B selection
|
||||
if (isVFOA() && vfoActive == VFO_B) {
|
||||
setVFOB();
|
||||
} else if (isVFOB() && vfoActive == VFO_A) {
|
||||
setVFOA();
|
||||
}
|
||||
|
||||
// Split selection
|
||||
if (isSplit() && splitOn == 0) {
|
||||
setSplitOff();
|
||||
} else if (!isSplit() && splitOn != 0) {
|
||||
setSplitOn();
|
||||
}
|
||||
|
||||
// RIT selection
|
||||
if (isRIT() && ritOn == 0) {
|
||||
setRITOff();
|
||||
} else if (!isRIT() && ritOn != 0) {
|
||||
setRITOn();
|
||||
}
|
||||
|
||||
// XIT selection
|
||||
//setXITOff();
|
||||
// TODO
|
||||
|
||||
// Mode
|
||||
char prev = (isModeCW() ? 4 : 0) | (isModeCWR() ? 2 : 0) | (isModeUSB() ? 1 : 0);
|
||||
char curr = (cwMode << 1) | isUSB;
|
||||
if (curr != prev) {
|
||||
if (cwMode == 2) {
|
||||
setCW();
|
||||
} else if (cwMode == 1) {
|
||||
setCWR();
|
||||
} else {
|
||||
if (isUSB) {
|
||||
setUSB();
|
||||
} else {
|
||||
setLSB();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* TEENSYDSP FUNCTIONS
|
||||
*
|
||||
* The following are specific to the TeensyDSP implementation. Note
|
||||
* that this depends on the use of the TEENSYDUINO #define, which may
|
||||
* result in a fragile implementation for other development environments
|
||||
* (e.g. if the normal Arduino IDE is not being used).
|
||||
**********************************************************************/
|
||||
|
||||
#else
|
||||
|
||||
#include <i2c_t3.h>
|
||||
|
||||
/*!
|
||||
* @brief Receive RIGINF data from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'radState' (Raduino state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* receives the incoming data from the Raduino and updates the
|
||||
* state.
|
||||
*/
|
||||
void UBitxRigState::receive_RIGINF(int numBytes) {
|
||||
byte* ptr = (byte*)&data;
|
||||
setClean(); // we'll get new dirty bits via the I2C message
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS && Wire1.available(); i++) {
|
||||
for (size_t j = 0; j < sizeof(uint32_t) && Wire1.available(); j++) {
|
||||
byte incomingByte = Wire1.read();
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always overwrite the dirty bits
|
||||
// and, update bytes for fields marked dirty
|
||||
*ptr = incomingByte;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
IFDEBUG( serialHexState("Rcvd") );
|
||||
IFDEBUG( serialPrettyState("Rcvd") );
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
/*!
|
||||
* @brief Handle a RIGINF signal from the Raduino. This method should
|
||||
* be called on the TeensyDSP 'catState' (CAT state)
|
||||
* instance, when a RIGINF signal is received via I2C. It
|
||||
* sends a response to the Raduino via I2C, using the Wire1
|
||||
* interface.
|
||||
*/
|
||||
void UBitxRigState::send_RIGINF() {
|
||||
for (RigStateWord i = DIRTY_WORD; i < NUM_WORDS; i++) {
|
||||
if (i == DIRTY_WORD || isDirty(i)) {
|
||||
// always send the current dirty bits
|
||||
// or, bytes for updated (dirty) fields
|
||||
Wire1.write((byte*)&data[i], sizeof(uint32_t));
|
||||
} else {
|
||||
// otherwise, send out zeroes
|
||||
Wire1.write((byte*)&zeroes, sizeof(uint32_t));
|
||||
//----------------------------------------------------------------
|
||||
// NOTE: I am sending these zeroed out fields under a possibly
|
||||
// mistaken assumption that in doing so, I will be sending a
|
||||
// constant voltage on the SDA line most of the time, i.e. no
|
||||
// bit changes, and so this will help reduce noise generated by
|
||||
// I2C traffic (since most of the time there will be no updates.)
|
||||
//----------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
IFDEBUG( serialHexState("Sent") );
|
||||
IFDEBUG( serialPrettyState("Sent") );
|
||||
setClean(); // now that we've sent them, they're clean
|
||||
//--------------------------------------------------------------------
|
||||
// TODO: Need to look at possibly merging the two states together at
|
||||
// this point. The purpose would be to minimize the turnaround time
|
||||
// for getting the most recent data to a CAT response.
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
char debugString[81] = {'\0'};
|
||||
|
||||
void UBitxRigState::serialHexState(const char* label = "RigState") {
|
||||
Serial.print(label);
|
||||
sprintf(debugString, ": %#010lx, %#010lx, %#010lx, %#010lx, %#010lx",
|
||||
data[DIRTY_WORD], data[VFOA_WORD], data[VFOB_WORD], data[OFFSETS_WORD], data[FLAGS_WORD]);
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
void UBitxRigState::serialPrettyState(const char* label = "RigState") {
|
||||
Serial.println(label);
|
||||
sprintf(debugString, "VFO A : %011ld %1c / VFO B : %011ld %1c",
|
||||
getFreqA(), isDirty(VFOA_WORD) ? 'D' : ' ', getFreqB(), isDirty(VFOB_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "RIT : %011ld %1c / XIT : %011ld %1c",
|
||||
getRIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ', getXIT(), isDirty(OFFSETS_WORD) ? 'D' : ' ');
|
||||
Serial.println(debugString);
|
||||
sprintf(debugString, "Split? %1c / VFO? %1c / RIT? %1c / XIT? %1c / Mode? %3s",
|
||||
isSplit() ? 'Y' : 'N', isVFOA() ? 'A' : 'B', isRIT() ? 'Y' : 'N', isXIT() ? 'Y' : 'N',
|
||||
isModeUSB() ? "USB" : (isModeLSB() ? "LSB" : (isModeCW() ? "CW " : (isModeCWR() ? "CWR" : " "))));
|
||||
Serial.println(debugString);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
UBitxRigState _rigState;
|
||||
UBitxRigState& rigState = _rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
372
TeensyDSP/RigState.h
Normal file
372
TeensyDSP/RigState.h
Normal file
@@ -0,0 +1,372 @@
|
||||
/*!
|
||||
* @file RigState.h
|
||||
*/
|
||||
|
||||
#ifndef __RigState_h__
|
||||
#define __RigState_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define UBITX_VFOB_FLAG 0x00000001
|
||||
#define UBITX_SPLIT_FLAG 0x00000002
|
||||
#define UBITX_RIT_FLAG 0x00000004
|
||||
#define UBITX_XIT_FLAG 0x00000008
|
||||
#define UBITX_CW_FLAG 0x00000010
|
||||
#define UBITX_USB_FLAG 0x00000020
|
||||
#define UBITX_TX_FLAG 0x00000040
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#define DISABLEINTS(CMD) do { noInterrupts(); CMD; interrupts(); } while (0)
|
||||
#else
|
||||
#define DISABLEINTS(CMD) do { CMD; } while (0)
|
||||
#endif
|
||||
|
||||
enum RigStateWord {
|
||||
DIRTY_WORD = 0,
|
||||
VFOA_WORD,
|
||||
VFOB_WORD,
|
||||
OFFSETS_WORD,
|
||||
FLAGS_WORD,
|
||||
NUM_WORDS
|
||||
};
|
||||
|
||||
inline RigStateWord& operator++(RigStateWord& orig) {
|
||||
orig = static_cast<RigStateWord>(orig + 1);
|
||||
// NOTE: Will overflow...
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline RigStateWord operator++(RigStateWord& orig, int) {
|
||||
RigStateWord rVal = orig;
|
||||
++orig;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
struct UBitxRigState {
|
||||
volatile uint32_t data[NUM_WORDS] = {0};
|
||||
|
||||
void begin();
|
||||
|
||||
void send_RIGINF();
|
||||
void receive_RIGINF(int numBytes = sizeof(data));
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as dirty.
|
||||
*/
|
||||
inline void setDirty(RigStateWord w) {
|
||||
data[DIRTY_WORD] |= w < NUM_WORDS ? 1 << w : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the dirty bits for all words.
|
||||
*/
|
||||
inline void setDirty() { DISABLEINTS( data[DIRTY_WORD] = 0xFFFFFFFF ); }
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bit for the specified word.
|
||||
*
|
||||
* @param w
|
||||
* The word to mark as clean.
|
||||
*/
|
||||
inline void setClean(RigStateWord w) {
|
||||
data[DIRTY_WORD] &= ~(w < NUM_WORDS ? 1 << w : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Clear the dirty bits for all words.
|
||||
*/
|
||||
inline void setClean() { DISABLEINTS( data[DIRTY_WORD] = 0 ); }
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is clean.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for clean status.
|
||||
*
|
||||
* @return True if the word is clean.
|
||||
*/
|
||||
inline bool isClean(RigStateWord w) {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = ((1 << w) & data[DIRTY_WORD]) > 0 ? false : true );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is clean (as a whole).
|
||||
*
|
||||
* @return True if the data is clean (no dirty fields).
|
||||
*/
|
||||
inline bool isClean() {
|
||||
bool clean;
|
||||
DISABLEINTS( clean = data[DIRTY_WORD] == 0 );
|
||||
return clean;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the specified word is dirty.
|
||||
*
|
||||
* @param w
|
||||
* The word to check for dirty status.
|
||||
*
|
||||
* @return True if the word is dirty.
|
||||
*/
|
||||
inline bool isDirty(RigStateWord w) {
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = ((1 << w) & data[DIRTY_WORD]) > 0 ? true : false );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Check whether the data is dirty (as a whole).
|
||||
*
|
||||
* @return True if the data is dirty (at least one dirty field).
|
||||
*/
|
||||
inline bool isDirty() {
|
||||
bool dirty;
|
||||
DISABLEINTS( dirty = data[DIRTY_WORD] != 0 );
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the VFO A frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqA(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOA_WORD] = freq;
|
||||
if (mark) setDirty(VFOA_WORD) );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqA() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOA_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the VFO B frequency.
|
||||
*
|
||||
* @param freq
|
||||
* The new frequency in Hz.
|
||||
*/
|
||||
inline void setFreqB(uint32_t freq, bool mark = true) {
|
||||
DISABLEINTS( data[VFOB_WORD] = freq );
|
||||
}
|
||||
|
||||
inline uint32_t getFreqB() const {
|
||||
uint32_t result;
|
||||
DISABLEINTS( result = data[VFOB_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (int32_t(offset) << 16) | (0x0000FFFF & data[OFFSETS_WORD]);
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getRIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = data[OFFSETS_WORD] >> 16 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXIT(int16_t offset, bool mark = true) {
|
||||
DISABLEINTS( data[OFFSETS_WORD] = (0xFFFF0000 & data[OFFSETS_WORD]) | offset;
|
||||
if (mark) setDirty(OFFSETS_WORD) );
|
||||
}
|
||||
|
||||
inline int16_t getXIT() const {
|
||||
int16_t result;
|
||||
DISABLEINTS( result = 0x0000FFFF & data[OFFSETS_WORD] );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setVFOA(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setVFOB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_VFOB_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isVFOA() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? false : true );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isVFOB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_VFOB_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setSplitOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setSplitOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_SPLIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isSplit() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_SPLIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setRITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setRITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_RIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isRIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_RIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setXITOn(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setXITOff(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_XIT_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isXIT() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = data[FLAGS_WORD] & UBITX_XIT_FLAG ? true : false );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void setUSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setLSB(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] &= ~UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCW(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] |= UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline void setCWR(bool mark = true) {
|
||||
DISABLEINTS( data[FLAGS_WORD] &= ~UBITX_USB_FLAG;
|
||||
data[FLAGS_WORD] |= UBITX_CW_FLAG;
|
||||
if (mark) setDirty(FLAGS_WORD) );
|
||||
}
|
||||
|
||||
inline bool isModeUSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeLSB() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) == 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWAny() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = (data[FLAGS_WORD] & UBITX_CW_FLAG) > 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCW() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) > 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool isModeCWR() const {
|
||||
bool result;
|
||||
DISABLEINTS( result = ((data[FLAGS_WORD] & UBITX_USB_FLAG) == 0) && ((data[FLAGS_WORD] & UBITX_CW_FLAG) > 0) );
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void serialHexState(const char* label);
|
||||
void serialPrettyState(const char* label);
|
||||
#endif
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
// These methods are only defined in the Raduino (Arduino) case of the
|
||||
// RigState, not in the TeensyDSP (Teensy) case.
|
||||
void writeDirty(); // write fields FROM RigState TO Raduino
|
||||
void readDirty(); // read variables FROM Raduino TO RigState
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef TEENSYDUINO
|
||||
|
||||
extern UBitxRigState& rigState;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
NOTE: This is all currently OBE, leaving it here for reference/future cleanup.
|
||||
|
||||
Protocol discussion:
|
||||
- I2C master: Raduino
|
||||
- I2C slave: TeensyDSP
|
||||
|
||||
Raduino state:
|
||||
- Baseline uBITX variables
|
||||
- I2C buffer
|
||||
- On I2C transmit: make updates based on current variables
|
||||
- On I2C receive:
|
||||
- Update based on received I2C responses
|
||||
- Update associated variables
|
||||
|
||||
TeensyDSP state:
|
||||
- CAT buffer
|
||||
- Used to receive command from CAT (when commands arrive via Serial)
|
||||
- Used to transmit state to Raduino (when requested via Wire1)
|
||||
- Raduino buffer
|
||||
- Used to receive state from Raduino (when received via Wire1)
|
||||
- Used to transmit responses to CAT (over Serial)
|
||||
- Questions
|
||||
- How can these be synchronized?
|
||||
- At the tail end of an I2C request handler. Before sending the response to the Raduino via I2C:
|
||||
- Copy updated CAT buffer items to the Raduino buffer.
|
||||
- Copy updated Raduino buffer items to the CAT buffer.
|
||||
- In the case of conflicts, CAT wins.
|
||||
- Transmit the CAT buffer state to the Raduino.
|
||||
- TeensyDSP updates 'outgoing' state based on CAT inputs.
|
||||
- Make change to data.
|
||||
- Mark data as dirty, if different than incoming state.
|
||||
- When requested, Teensy DSP sends 'outgoing' state to Raduino.
|
||||
- Send dirty data over I2C.
|
||||
- Mark data as clean.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* EOF
|
||||
**********************************************************************/
|
5
TeensyDSP/Sensors.cpp
Normal file
5
TeensyDSP/Sensors.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "Sensors.h"
|
||||
|
||||
UBitxSensors Sensors;
|
||||
|
||||
ADC adc;
|
363
TeensyDSP/Sensors.h
Normal file
363
TeensyDSP/Sensors.h
Normal file
@@ -0,0 +1,363 @@
|
||||
#ifndef __Sensor_h__
|
||||
#define __Sensor_h__
|
||||
|
||||
#include <ADC.h>
|
||||
#include "Debug.h"
|
||||
#include "HamFuncs.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_PIN
|
||||
#define UBITX_SENSORS_S_METER_PIN 28
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_PIN
|
||||
#define UBITX_SENSORS_FWD_PWR_PIN 26
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_PIN
|
||||
#define UBITX_SENSORS_REV_PWR_PIN 20
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_PIN
|
||||
#define UBITX_SENSORS_SUPPLY_PIN 21
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SPARE1_PIN
|
||||
#define UBITX_SENSORS_SPARE1_PIN 27
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SPARE2_PIN
|
||||
#define UBITX_SENSORS_SPARE2_PIN 31
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_AVG_SAMPLES
|
||||
#define UBITX_SENSORS_AVG_SAMPLES 16
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_R1
|
||||
#define UBITX_SENSORS_S_METER_R1 0.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_R2
|
||||
#define UBITX_SENSORS_S_METER_R2 1.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_R1
|
||||
#define UBITX_SENSORS_FWD_PWR_R1 22000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_FWD_PWR_R2
|
||||
#define UBITX_SENSORS_FWD_PWR_R2 33000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_R1
|
||||
#define UBITX_SENSORS_REV_PWR_R1 22000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_REV_PWR_R2
|
||||
#define UBITX_SENSORS_REV_PWR_R2 33000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_R1
|
||||
#define UBITX_SENSORS_SUPPLY_R1 56000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_SUPPLY_R2
|
||||
#define UBITX_SENSORS_SUPPLY_R2 10000.0
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL0
|
||||
#define UBITX_SENSORS_S_METER_LVL0 2
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL1
|
||||
#define UBITX_SENSORS_S_METER_LVL1 4
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL2
|
||||
#define UBITX_SENSORS_S_METER_LVL2 8
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL3
|
||||
#define UBITX_SENSORS_S_METER_LVL3 16
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL4
|
||||
#define UBITX_SENSORS_S_METER_LVL4 32
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL5
|
||||
#define UBITX_SENSORS_S_METER_LVL5 64
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL6
|
||||
#define UBITX_SENSORS_S_METER_LVL6 128
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL7
|
||||
#define UBITX_SENSORS_S_METER_LVL7 256
|
||||
#endif
|
||||
|
||||
#ifndef UBITX_SENSORS_S_METER_LVL8
|
||||
#define UBITX_SENSORS_S_METER_LVL8 512
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
const int uBitxSensorsSMeterPin = UBITX_SENSORS_S_METER_PIN;
|
||||
const int uBitxSensorsFwdPwrPin = UBITX_SENSORS_FWD_PWR_PIN;
|
||||
const int uBitxSensorsRevPwrPin = UBITX_SENSORS_REV_PWR_PIN;
|
||||
const int uBitxSensorsSupplyPin = UBITX_SENSORS_SUPPLY_PIN;
|
||||
const int uBitxSensorsSpare1Pin = UBITX_SENSORS_SPARE1_PIN;
|
||||
const int uBitxSensorsSpare2Pin = UBITX_SENSORS_SPARE2_PIN;
|
||||
const int uBitxSensorsAvgSamples = UBITX_SENSORS_AVG_SAMPLES;
|
||||
const float uBitxSensorsSMeterR1 = UBITX_SENSORS_S_METER_R1;
|
||||
const float uBitxSensorsSMeterR2 = UBITX_SENSORS_S_METER_R2;
|
||||
const float uBitxSensorsFwdPwrR1 = UBITX_SENSORS_FWD_PWR_R1;
|
||||
const float uBitxSensorsFwdPwrR2 = UBITX_SENSORS_FWD_PWR_R2;
|
||||
const float uBitxSensorsRevPwrR1 = UBITX_SENSORS_REV_PWR_R1;
|
||||
const float uBitxSensorsRevPwrR2 = UBITX_SENSORS_REV_PWR_R2;
|
||||
const float uBitxSensorsSupplyR1 = UBITX_SENSORS_SUPPLY_R1;
|
||||
const float uBitxSensorsSupplyR2 = UBITX_SENSORS_SUPPLY_R2;
|
||||
|
||||
const int uBitxSensorsSMeterValues[] = {
|
||||
UBITX_SENSORS_S_METER_LVL0,
|
||||
UBITX_SENSORS_S_METER_LVL1,
|
||||
UBITX_SENSORS_S_METER_LVL2,
|
||||
UBITX_SENSORS_S_METER_LVL3,
|
||||
UBITX_SENSORS_S_METER_LVL4,
|
||||
UBITX_SENSORS_S_METER_LVL5,
|
||||
UBITX_SENSORS_S_METER_LVL6,
|
||||
UBITX_SENSORS_S_METER_LVL7,
|
||||
UBITX_SENSORS_S_METER_LVL8
|
||||
};
|
||||
|
||||
const int uBitxSensorsSMeterLevels = sizeof(uBitxSensorsSMeterValues) /
|
||||
sizeof(uBitxSensorsSMeterValues[0]);
|
||||
|
||||
extern ADC adc;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Class that maintains a "trailing average" of the last X
|
||||
* samples provided. It is a template that can be instantiated
|
||||
* with both the (numeric) data type that is being stored and
|
||||
* averaged, as well as the number of samples to maintain the
|
||||
* trailing average across.
|
||||
*/
|
||||
template <typename T, int N>
|
||||
class TrailingAverage {
|
||||
public:
|
||||
/*!
|
||||
* @brief Create a new TrailingAverage object. Data type averaged,
|
||||
* and number of elements to average, are determined when the
|
||||
* template is instantiated.
|
||||
*/
|
||||
TrailingAverage():
|
||||
average(T(0)),
|
||||
current(0),
|
||||
divisor(T(N))
|
||||
{
|
||||
for (int i = 0; i < N; i++) {
|
||||
data[i] = T(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Add a new element to the average. The current last (Nth)
|
||||
* element is removed, and the new element is added.
|
||||
* @param val
|
||||
* The new element/value to incorporate into the average.
|
||||
*/
|
||||
inline void add(T val) {
|
||||
//int last = (current - 1) % N;
|
||||
//average -= data[last];
|
||||
//current = (current + 1) % N;
|
||||
//data[current] = val / divisor;
|
||||
//average += data[current];
|
||||
average -= data[current];
|
||||
data[current] = val / divisor;
|
||||
average += data[current];
|
||||
current = (current + 1) % N;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Read the current value of the average.
|
||||
* @return The current average.
|
||||
*/
|
||||
inline T read() {
|
||||
return average;
|
||||
}
|
||||
|
||||
private:
|
||||
T data[N];
|
||||
T average;
|
||||
int current;
|
||||
T divisor;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Class that handles the various sensors in the uBitx:
|
||||
* S-Meter, forward/reverse power and SWR, and supply voltage.
|
||||
*/
|
||||
class UBitxSensors {
|
||||
public:
|
||||
/*!
|
||||
* @brief Create a new UBitxSensors object. It uses the default
|
||||
* S-Meter, Forward Power, Reverse Power, and Supply Voltage
|
||||
* ADC pins.
|
||||
*/
|
||||
UBitxSensors():
|
||||
sMeterPin(uBitxSensorsSMeterPin),
|
||||
fwdPwrPin(uBitxSensorsFwdPwrPin),
|
||||
revPwrPin(uBitxSensorsRevPwrPin),
|
||||
supplyPin(uBitxSensorsSupplyPin),
|
||||
spare1Pin(uBitxSensorsSpare1Pin),
|
||||
spare2Pin(uBitxSensorsSpare2Pin)
|
||||
{
|
||||
pinMode(sMeterPin, INPUT); // analog
|
||||
pinMode(fwdPwrPin, INPUT); // analog
|
||||
pinMode(revPwrPin, INPUT); // analog
|
||||
pinMode(supplyPin, INPUT); // analog
|
||||
pinMode(spare1Pin, INPUT); // analog
|
||||
pinMode(spare2Pin, INPUT); // analog
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the S-Meter by reading the associated
|
||||
* ADC pin.
|
||||
*/
|
||||
inline void updateSMeter() {
|
||||
int value = adc.analogRead(sMeterPin);
|
||||
sMeter.add(value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the Forward and Reverse Power
|
||||
* measurements by reading the associated ADC pin.
|
||||
*/
|
||||
void updatePower() {
|
||||
ADC::Sync_result value = adc.analogSyncRead(revPwrPin, fwdPwrPin);
|
||||
|
||||
float fwdV = HF::adcIn(value.result_adc0);
|
||||
float revV = HF::adcIn(value.result_adc1);
|
||||
|
||||
fwdV = HF::divIn(fwdV, uBitxSensorsFwdPwrR1, uBitxSensorsFwdPwrR2);
|
||||
fwdV = HF::bridgeFwd(fwdV);
|
||||
|
||||
revV = HF::divIn(revV, uBitxSensorsRevPwrR1, uBitxSensorsRevPwrR2);
|
||||
revV = HF::bridgeFwd(revV);
|
||||
|
||||
fwdPwr.add(HF::P(fwdV));
|
||||
revPwr.add(HF::P(revV));
|
||||
vswr.add(HF::VSWR(fwdV, revV));
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Update the value of the Supply Voltage measurement by
|
||||
* reading the associated ADC pin.
|
||||
*/
|
||||
inline void updateSupply() {
|
||||
float value = HF::adcIn(adc.analogRead(supplyPin));
|
||||
value = HF::divIn(value, uBitxSensorsSupplyR1, uBitxSensorsSupplyR2);
|
||||
supply.add(value);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the unscaled value of the S-Meter reading.
|
||||
* @return Unscaled S-Meter reading.
|
||||
*/
|
||||
inline int sMeterUnscaled() {
|
||||
return sMeter.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the scaled value of the S-Meter reading. This
|
||||
* is the value that is used to directly control the S-Meter
|
||||
* display on the Nextion LCD.
|
||||
* @return Scaled S-Meter reading.
|
||||
*/
|
||||
int sMeterScaled() {
|
||||
int sig = sMeter.read() >> 2;
|
||||
// small number of elements; just doing a linear search
|
||||
for (int i = uBitxSensorsSMeterLevels; i > 0; i--) {
|
||||
if (sig > uBitxSensorsSMeterValues[i - 1]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Forward Power measurement.
|
||||
* @return Forward Power measurement.
|
||||
*/
|
||||
inline float Pfwd() {
|
||||
return fwdPwr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Reverse Power measurement.
|
||||
* @return Reverse Power measurement.
|
||||
*/
|
||||
inline float Prev() {
|
||||
return revPwr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Voltage Standing Wave Ration (VSWR).
|
||||
* @return Current VSWR calculation.
|
||||
*/
|
||||
inline float VSWR() {
|
||||
return vswr.read();
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Voltage Standing Wave Ration (VSWR),
|
||||
* scaled for the Nextion display protocol.
|
||||
* @return Current VSWR calculation (scaled).
|
||||
*/
|
||||
float scaledVSWR() {
|
||||
int val = int(vswr.read());
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > uBitxSensorsSMeterLevels) {
|
||||
return uBitxSensorsSMeterLevels;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Return the current Supply Voltage measurement.
|
||||
* @return Current Supply Voltage.
|
||||
*/
|
||||
inline float supplyVoltage() {
|
||||
return supply.read();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Pins
|
||||
int sMeterPin;
|
||||
int fwdPwrPin;
|
||||
int revPwrPin;
|
||||
int supplyPin;
|
||||
int spare1Pin;
|
||||
int spare2Pin;
|
||||
|
||||
// Buffers for averages
|
||||
TrailingAverage<int, uBitxSensorsAvgSamples> sMeter;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> fwdPwr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> revPwr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> vswr;
|
||||
TrailingAverage<float, uBitxSensorsAvgSamples> supply;
|
||||
};
|
||||
|
||||
extern UBitxSensors Sensors;
|
||||
|
||||
#endif
|
57
TeensyDSP/TR.cpp
Normal file
57
TeensyDSP/TR.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
//======================================================================
|
||||
// TR.cpp
|
||||
//======================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "TR.h"
|
||||
|
||||
UBitxTR TR(DSP);
|
||||
|
||||
void UBitxTR::update(bool cw, bool extKey) {
|
||||
updateLinePTT();
|
||||
|
||||
if (cw) {
|
||||
if ((keyEnable && keyDown) || extKey) {
|
||||
setTX();
|
||||
} else {
|
||||
setRX();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
updateMicPTT();
|
||||
updateMicVOX();
|
||||
updateDataVOX();
|
||||
|
||||
if (isTX) {
|
||||
// If we are currently transmitting, then ANY T/R release (key
|
||||
// release) will result in exiting transmit... except for VOX
|
||||
// and CAT which can only function as a release if it was enabled.
|
||||
if (micPTTReleased() || linePTTReleased() ||
|
||||
(micVOXEnabled() && micVOXDeactivated()) ||
|
||||
(catEnabled() && catDeactivated()) ||
|
||||
(dataVOXEnabled() && dataVOXDeactivated())) {
|
||||
// first, stop transmitting; then, setup RX audio
|
||||
DBGCMD( setRX() );
|
||||
DBGCMD( dsp.rx() );
|
||||
}
|
||||
} else {
|
||||
if ((micPTTEnabled() && micPTTPressed()) || (micVOXEnabled() && micVOXActivated())) {
|
||||
// first, setup TX audio; then, start transmitting (from Mic)
|
||||
DBGCMD( dsp.tx(MIC_IN) );
|
||||
DBGCMD( setTX() );
|
||||
} else if ((linePTTEnabled() && linePTTPressed())) {
|
||||
// first, setup TX audio; then, start transmitting (from Line In)
|
||||
DBGCMD( dsp.tx(LINE_IN) );
|
||||
DBGCMD( setTX() );
|
||||
} else if (catEnable && catActivated()) {
|
||||
// first, setup TX audio; then, start transmitting (USB)
|
||||
DBGCMD( dsp.tx(USB_IN) );
|
||||
DBGCMD( setTX() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
178
TeensyDSP/TR.h
Normal file
178
TeensyDSP/TR.h
Normal file
@@ -0,0 +1,178 @@
|
||||
//======================================================================
|
||||
// TR.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __TR_h__
|
||||
#define __TR_h__
|
||||
|
||||
#include <Bounce2.h>
|
||||
#include "Debug.h"
|
||||
#include "DSP.h"
|
||||
|
||||
#define UBITX_TR_OUT_PIN 2
|
||||
#define UBITX_TR_PTT_PIN 3
|
||||
#define UBITX_TR_VOX_PIN 4
|
||||
#define UBITX_TR_KEY_PIN 5
|
||||
|
||||
const int uBitxTROutPin = UBITX_TR_OUT_PIN;
|
||||
const int uBitxTRPttPin = UBITX_TR_PTT_PIN;
|
||||
const int uBitxTRVoxPin = UBITX_TR_VOX_PIN;
|
||||
const int uBitxTRKeyPin = UBITX_TR_KEY_PIN;
|
||||
|
||||
class UBitxTR {
|
||||
public:
|
||||
UBitxTR(UBitxDSP& d, int out = uBitxTROutPin, int p = uBitxTRPttPin, int v = uBitxTRVoxPin, int k = uBitxTRKeyPin):
|
||||
dsp(d), outPin(out), pttPin(p), voxPin(v), keyPin(k) {}
|
||||
|
||||
void begin() {
|
||||
pinMode(outPin, OUTPUT);
|
||||
pinMode(voxPin, INPUT_PULLUP);
|
||||
pinMode(keyPin, INPUT_PULLUP);
|
||||
ptt.attach(pttPin, INPUT_PULLUP);
|
||||
ptt.interval(5);
|
||||
|
||||
// default configuration: PTT, key, and CAT enabled; VOX disabled
|
||||
DBGCMD( enableMicPTT() );
|
||||
DBGCMD( disableMicVOX() );
|
||||
DBGCMD( enableLinePTT() );
|
||||
DBGCMD( enableCAT() );
|
||||
|
||||
DBGCMD( setRX() );
|
||||
}
|
||||
|
||||
inline void enableMicPTT() { pttEnable = true; }
|
||||
inline void enableLinePTT() { keyEnable = true; }
|
||||
inline void enableMicVOX() { voxEnable = true; }
|
||||
inline void enableDataVOX() { dvoxEnable = true; }
|
||||
inline void enableCAT() { catEnable = true; }
|
||||
|
||||
inline void disableMicPTT() { pttEnable = false; }
|
||||
inline void disableLinePTT() { keyEnable = false; }
|
||||
inline void disableMicVOX() { voxEnable = false; }
|
||||
inline void disableDataVOX() { dvoxEnable = false; }
|
||||
inline void disableCAT() { catEnable = false; }
|
||||
|
||||
inline bool micPTTEnabled() const { return pttEnable; }
|
||||
inline bool linePTTEnabled() const { return keyEnable; }
|
||||
inline bool micVOXEnabled() const { return voxEnable; }
|
||||
inline bool dataVOXEnabled() const { return dvoxEnable; }
|
||||
inline bool catEnabled() const { return catEnable; }
|
||||
|
||||
inline bool micPTTPressed() { return ptt.fell(); }
|
||||
inline bool micPTTReleased() { return ptt.rose(); }
|
||||
inline bool linePTTPressed() { return (L_keyDown != keyDown) && L_keyDown; }
|
||||
inline bool linePTTReleased() { return (L_keyDown != keyDown) && keyDown; }
|
||||
inline bool micVOXActivated() { return (L_voxActive != voxActive) && L_voxActive; }
|
||||
inline bool micVOXDeactivated() { return (L_voxActive != voxActive) && voxActive; }
|
||||
inline bool dataVOXActivated() { return (L_dvoxActive != dvoxActive) && L_dvoxActive; }
|
||||
inline bool dataVOXDeactivated() { return (L_dvoxActive != dvoxActive) && dvoxActive; }
|
||||
inline bool catActivated() { return (L_catActive != catActive) && L_catActive; }
|
||||
inline bool catDeactivated() { return (L_catActive != catActive) && catActive; }
|
||||
|
||||
inline void catTX() {
|
||||
L_catActive = catActive;
|
||||
catActive = true;
|
||||
}
|
||||
|
||||
inline void catRX() {
|
||||
L_catActive = catActive;
|
||||
catActive = false;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
inline bool transmitting() { return isTX; }
|
||||
inline bool receiving() { return !isTX; }
|
||||
|
||||
/*!
|
||||
* @brief Check if any of the PTT's have been pressed or released
|
||||
* since the last update. Only one thing is allowed to occur
|
||||
* based on an order of precedence. The highest priority is
|
||||
* to stop transmitting.
|
||||
*
|
||||
* @param cw
|
||||
* True if CW mode is currently active; false otherwise.
|
||||
* Different/faster logic is used in CW mode.
|
||||
*
|
||||
* @param extKey
|
||||
* True if an external keying signal (ie. CW keyer) is
|
||||
* currently active (ie. key down).
|
||||
*/
|
||||
void update(bool cw = false, bool extKey = false);
|
||||
|
||||
void end() {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline void setTX() {
|
||||
digitalWrite(outPin, LOW);
|
||||
isTX = true;
|
||||
}
|
||||
|
||||
inline void setRX() {
|
||||
isTX = false;
|
||||
digitalWrite(outPin, HIGH);
|
||||
}
|
||||
|
||||
inline void updateMicPTT() {
|
||||
ptt.update();
|
||||
}
|
||||
|
||||
inline void updateLinePTT() {
|
||||
L_keyDown = keyDown;
|
||||
keyDown = (digitalRead(keyPin) == LOW);
|
||||
}
|
||||
|
||||
inline void updateMicVOX() {
|
||||
L_voxActive = voxActive;
|
||||
voxActive = (digitalRead(voxPin) == LOW);
|
||||
}
|
||||
|
||||
inline void updateDataVOX() {
|
||||
L_dvoxActive = dvoxActive;
|
||||
if (dsp.getVoxLevel() > dvoxThreshold) {
|
||||
dvoxActive = true;
|
||||
dvoxElapsed = 0;
|
||||
} else if (dvoxActive && (dvoxElapsed > dvoxDelay)) {
|
||||
dvoxActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
UBitxDSP& dsp;
|
||||
|
||||
Bounce ptt;
|
||||
|
||||
int pttPin;
|
||||
int voxPin;
|
||||
int keyPin;
|
||||
int outPin;
|
||||
|
||||
bool isTX = false;
|
||||
|
||||
bool pttEnable = false;
|
||||
bool voxEnable = false;
|
||||
bool dvoxEnable = false;
|
||||
bool keyEnable = false;
|
||||
bool catEnable = false;
|
||||
|
||||
bool voxActive = false;
|
||||
bool L_voxActive = false;
|
||||
bool dvoxActive = false;
|
||||
bool L_dvoxActive = false;
|
||||
bool keyDown = false;
|
||||
bool L_keyDown = false;
|
||||
bool catActive = false;
|
||||
bool L_catActive = false;
|
||||
|
||||
elapsedMillis dvoxElapsed = 0;
|
||||
unsigned dvoxDelay = 250; // TODO: make dynamic
|
||||
};
|
||||
|
||||
extern UBitxTR TR;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
510
TeensyDSP/TS590.cpp
Normal file
510
TeensyDSP/TS590.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
#include <Arduino.h>
|
||||
#include "TS590.h"
|
||||
#include "Debug.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Send a command to the PC via CAT. Note that the command
|
||||
* should not include the trailing terminator (;). That will
|
||||
* be automatically added.
|
||||
* @param format
|
||||
* A printf-style format string.
|
||||
* @param args
|
||||
* Zero or more arguments to include in the command.
|
||||
*/
|
||||
void ts590SendCommand(const char* format, ...) {
|
||||
static char outBuf[ts590CommandMaxLength];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsprintf(outBuf, format, args);
|
||||
va_end(args);
|
||||
Serial.print(outBuf);
|
||||
Serial.print(";");
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief Create a new CAT command. It should be initialized with
|
||||
* a 2-character command prefix.
|
||||
* @param pre
|
||||
* A 2-character command prefix. If more than 2 characters
|
||||
* are supplied, only the first two will be used. If less
|
||||
* than two are supplied, then the command will be
|
||||
* initialized with a null prefix.
|
||||
*/
|
||||
TS590Command::TS590Command(const char* pre)
|
||||
: myPrefix(pre), prefixLength(strlen(pre))
|
||||
{}
|
||||
|
||||
TS590Command::~TS590Command() {}
|
||||
|
||||
/*!
|
||||
* @brief Determine whether this is a Read command or not. by
|
||||
* default, if it's a 2-letter command, it's a Read.
|
||||
* @return True if a Read command; false otherwise.
|
||||
*/
|
||||
bool TS590Command::isReadCommand(const char* cmd) const {
|
||||
if (strlen(cmd) == prefixLength) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Process the provided command. If the command is a Set
|
||||
* command, it calls handleCommand(). If Auto Information
|
||||
* is eet (by the rig), sendResponse() is called at the end.
|
||||
* If the command is a Read command, it also calls
|
||||
* sendResponse(). Finally, if necessary, it will return
|
||||
* any error codes to the PC.
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
void TS590Command::process(const char* cmd) {
|
||||
theError = NoError;
|
||||
|
||||
if (isReadCommand(cmd)) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
} else {
|
||||
DBGCMD( handleCommand(cmd) );
|
||||
switch(theError) {
|
||||
case NoError:
|
||||
if (theRig->isAI()) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxError:
|
||||
DBGCMD( ts590SyntaxError() );
|
||||
break;
|
||||
|
||||
case CommError:
|
||||
DBGCMD( ts590CommError() );
|
||||
break;
|
||||
|
||||
case ProcessError:
|
||||
DBGCMD( ts590ProcessError() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the syntax error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setSyntaxError() {
|
||||
theError = SyntaxError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the comms error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setCommError() {
|
||||
theError = CommError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the process error flag. This is cleared at the
|
||||
* beginning of each call to process().
|
||||
*/
|
||||
void TS590Command::setProcessError() {
|
||||
theError = ProcessError;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the rig that will be used to process commands.
|
||||
* @param r
|
||||
* Pointer to the UBitxRig object.
|
||||
*/
|
||||
void TS590Command::setRig(UBitxRig* r) {
|
||||
theRig = r;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Set the DSP that will be used to process commands.
|
||||
* @param d
|
||||
* Pointer to the UBitxDSP object.
|
||||
*/
|
||||
void TS590Command::setDSP(UBitxDSP* d) {
|
||||
theDSP = d;
|
||||
}
|
||||
|
||||
UBitxRig* TS590Command::theRig = &Rig;
|
||||
UBitxDSP* TS590Command::theDSP = &DSP;
|
||||
TS590Error TS590Command::theError = NoError;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590Command_Bool::handleCommand(const char* cmd) {
|
||||
setter(cmd[length()] == '0' ? false : true);
|
||||
}
|
||||
|
||||
void TS590Command_Bool::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("%s%s", prefix(), getter() ? "1" : "0");
|
||||
}
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590Command_UL::handleCommand(const char* cmd) {
|
||||
unsigned val = static_cast<unsigned>(strtoul(&cmd[length()], NULL, 10));
|
||||
if (val < myMin) {
|
||||
val = myMin;
|
||||
} else if (val > myMax) {
|
||||
val = myMax;
|
||||
}
|
||||
val = (val * mySlope) + myIntercept;
|
||||
setter(val);
|
||||
}
|
||||
|
||||
void TS590Command_UL::sendResponse(const char* cmd) {
|
||||
unsigned val = getter();
|
||||
val = (val - myIntercept) / mySlope;
|
||||
if (val < myMin) {
|
||||
val = myMin;
|
||||
} else if (val > myMax) {
|
||||
val = myMax;
|
||||
}
|
||||
ts590SendCommand("%s%0*u", prefix(), myWidth, getter());
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FR::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
rig()->setVFOA();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '1':
|
||||
rig()->setVFOB();
|
||||
rig()->setSplitOff();
|
||||
break;
|
||||
|
||||
case '2':
|
||||
// TODO: Need to add something for channel mode.
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FR::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand("FR0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand("FR1");
|
||||
} else {
|
||||
ts590SendCommand("FR2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_FT::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->setSplitOff();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->setSplitOn();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
case '1':
|
||||
if (rig()->isVFOA()) {
|
||||
rig()->setSplitOn();
|
||||
} else if (rig()->isVFOB()) {
|
||||
rig()->setSplitOff();
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_FT::sendResponse(const char* cmd) {
|
||||
if (rig()->isVFOA()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT1" : "FT0");
|
||||
} else if (rig()->isVFOB()) {
|
||||
ts590SendCommand(rig()->isSplit() ? "FT0" : "FT1");
|
||||
} else {
|
||||
ts590SendCommand("FT2");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_MD::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 3) {
|
||||
switch (cmd[2]) {
|
||||
case '0': // None (setting failure)
|
||||
case '4': // FM - not supported
|
||||
case '5': // AM - not supported
|
||||
case '6': // FSK - not supported
|
||||
case '8': // None (setting failure)
|
||||
case '9': // FSK-R - not supported
|
||||
setProcessError();
|
||||
break;
|
||||
|
||||
case '1': // LSB
|
||||
rig()->setLSB();
|
||||
break;
|
||||
|
||||
case '2': // USB
|
||||
rig()->setUSB();
|
||||
break;
|
||||
|
||||
case '3': // CW
|
||||
rig()->setCW();
|
||||
break;
|
||||
|
||||
case '7': // CW-R
|
||||
rig()->setCWR();
|
||||
break;
|
||||
|
||||
default:
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_MD::sendResponse(const char* cmd) {
|
||||
if (rig()->isModeCW()) {
|
||||
ts590SendCommand("MD3");
|
||||
} else if (rig()->isModeCWR()) {
|
||||
ts590SendCommand("MD7");
|
||||
} else if (rig()->isModeUSB()) {
|
||||
ts590SendCommand("MD2");
|
||||
} else if (rig()->isModeLSB()) {
|
||||
ts590SendCommand("MD1");
|
||||
} else {
|
||||
ts590SendCommand("MD0");
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
int ssbHiCut[14] = {1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800, 3000, 3400, 4000, 5000};
|
||||
int ssbLoCut[12] = {0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
|
||||
|
||||
int ssbWidth[14] = {50, 80, 100, 150, 200, 250, 300, 400, 500, 600, 1000, 1500, 2000, 2500};
|
||||
int ssbCenter[14] = {1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1750, 1800, 1900, 2000, 2100, 2210};
|
||||
|
||||
void TS590_SH::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 4) {
|
||||
index = strtoul(&cmd[2], NULL, 10);
|
||||
if (index < sizeof(ssbHiCut) / sizeof(ssbHiCut[0])) {
|
||||
dsp()->setRxFilterHi(ssbHiCut[index]);
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_SH::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("SH%02u", index);
|
||||
}
|
||||
|
||||
void TS590_SL::handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 4) {
|
||||
index = strtoul(&cmd[2], NULL, 10);
|
||||
if (index < sizeof(ssbLoCut) / sizeof(ssbLoCut[0])) {
|
||||
dsp()->setRxFilterLo(ssbLoCut[index]);
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
void TS590_SL::sendResponse(const char* cmd) {
|
||||
ts590SendCommand("SL%02u", index);
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void TS590_VX::handleCommand(const char* cmd) {
|
||||
|
||||
}
|
||||
|
||||
void TS590_VX::sendResponse(const char* cmd) {
|
||||
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void nullSetFunc(unsigned x) { return; }
|
||||
unsigned getIDFunc() {
|
||||
#ifndef USE_TS590SG_CAT
|
||||
return 021;
|
||||
#else
|
||||
return 023;
|
||||
#endif
|
||||
}
|
||||
|
||||
SetUL setAG = SetUL::create<UBitxDSP, &UBitxDSP::setLineOut255>(DSP);
|
||||
GetUL getAG = GetUL::create<UBitxDSP, &UBitxDSP::getLineOut255>(DSP);
|
||||
SetUL setAI = [](unsigned v) -> void { v == 0 ? Rig.aiOff() : Rig.aiOn(); };
|
||||
GetUL getAI = []() -> unsigned { return Rig.isAI() ? 4 : 0; };
|
||||
//SetUL setSidetone = SetUL::create<UBitxDSP, ...>(...);
|
||||
//GetUL getSidetone = GetUL::create<UBitxDSP, ...>(...);
|
||||
SetUL setUSBin = SetUL::create<UBitxDSP, &UBitxDSP::setUSBIn9>(DSP);
|
||||
GetUL getUSBin = GetUL::create<UBitxDSP, &UBitxDSP::getUSBIn9>(DSP);
|
||||
SetUL setUSBout = SetUL::create<UBitxDSP, &UBitxDSP::setUSBOut9>(DSP);
|
||||
GetUL getUSBout = GetUL::create<UBitxDSP, &UBitxDSP::getUSBOut9>(DSP);
|
||||
SetUL setACC2in = SetUL::create<UBitxDSP, &UBitxDSP::setLineIn9>(DSP);
|
||||
GetUL getACC2in = GetUL::create<UBitxDSP, &UBitxDSP::getLineIn9>(DSP);
|
||||
SetUL setACC2out = SetUL::create<UBitxDSP, &UBitxDSP::setLineOut9>(DSP);
|
||||
GetUL getACC2out = GetUL::create<UBitxDSP, &UBitxDSP::getLineOut9>(DSP);
|
||||
SetUL setVoxDelay = SetUL::create<UBitxDSP, &UBitxDSP::setDataVoxDelay>(DSP);
|
||||
GetUL getVoxDelay = GetUL::create<UBitxDSP, &UBitxDSP::getDataVoxDelay>(DSP);
|
||||
SetUL setUSBvox = SetUL::create<UBitxDSP, &UBitxDSP::setUSBVOXThresh9>(DSP);
|
||||
GetUL getUSBvox = GetUL::create<UBitxDSP, &UBitxDSP::getUSBVOXThresh9>(DSP);
|
||||
SetUL setACC2vox = SetUL::create<UBitxDSP, &UBitxDSP::setLineVOXThresh9>(DSP);
|
||||
GetUL getACC2vox = GetUL::create<UBitxDSP, &UBitxDSP::getLineVOXThresh9>(DSP);
|
||||
SetUL setID = SetUL::create<nullSetFunc>();
|
||||
GetUL getID = GetUL::create<getIDFunc>();
|
||||
|
||||
TS590Command_UL TS590_AG("AG0", 3, 0, 255, setAG, getAG);
|
||||
TS590Command_UL TS590_AI("AI", 1, 0, 4, setAI, getAI);
|
||||
// TS590_AS
|
||||
// TS590_BD
|
||||
// TS590_BU
|
||||
// TS590_CA
|
||||
// TS590_CD0
|
||||
// TS590_CD1
|
||||
// TS590_CD2
|
||||
// TS590_CH
|
||||
#ifndef USE_TS590SG_CAT
|
||||
//TS590Command_UL TS590_EX034("EX0340000", 2, 0, 14, 50, 300, setSideTone, getSideTone);
|
||||
TS590Command_UL TS590_EX064("EX0640000", 1, 0, 9, setUSBin, getUSBin);
|
||||
TS590Command_UL TS590_EX065("EX0650000", 1, 0, 9, setUSBout, getUSBout);
|
||||
TS590Command_UL TS590_EX066("EX0660000", 1, 0, 9, setACC2in, getACC2in);
|
||||
TS590Command_UL TS590_EX067("EX0670000", 1, 0, 9, setACC2out, getACC2out);
|
||||
TS590Command_UL TS590_EX070("EX0700000", 2, 0, 20, 5, 0, setVoxDelay, getVoxDelay);
|
||||
TS590Command_UL TS590_EX071("EX0710000", 1, 0, 9, setUSBvox, getUSBvox);
|
||||
TS590Command_UL TS590_EX072("EX0720000", 1, 0, 9, setACC2vox, getACC2vox);
|
||||
#else
|
||||
//TS590Command_UL TS590_EX040("EX0400000", 2, 0, 14, 50, 300, setSideTone, getSideTone);
|
||||
TS590Command_UL TS590_EX071("EX0710000", 1, 0, 9, setUSBin, getUSBin);
|
||||
TS590Command_UL TS590_EX072("EX0720000", 1, 0, 9, setUSBout, getUSBout);
|
||||
TS590Command_UL TS590_EX073("EX0730000", 1, 0, 9, setACC2in, getACC2in);
|
||||
TS590Command_UL TS590_EX074("EX0740000", 1, 0, 9, setACC2out, getACC2out);
|
||||
TS590Command_UL TS590_EX077("EX0770000", 2, 0, 20, 5, 0, setVoxDelay, getVoxDelay);
|
||||
TS590Command_UL TS590_EX078("EX0780000", 1, 0, 9, setUSBvox, getUSBvox);
|
||||
TS590Command_UL TS590_EX079("EX0790000", 1, 0, 9, setACC2vox, getACC2vox);
|
||||
#endif
|
||||
TS590Command_UL TS590_ID("ID", 3, 21, 23, setID, getID);
|
||||
|
||||
TS590_FA cmdFA;
|
||||
TS590_FB cmdFB;
|
||||
TS590_FR cmdFR;
|
||||
TS590_FT cmdFT;
|
||||
TS590_MD cmdMD;
|
||||
TS590_SH cmdSH;
|
||||
TS590_SL cmdSL;
|
||||
|
||||
TS590Command* catCommands[] = {
|
||||
&cmdFA,
|
||||
&cmdFB,
|
||||
&cmdFR,
|
||||
&cmdFT,
|
||||
&cmdMD,
|
||||
&cmdSH,
|
||||
&cmdSL
|
||||
};
|
||||
int numCatCommands = sizeof(catCommands) / sizeof(catCommands[0]);
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void UBitxTS590::begin() {
|
||||
Serial.begin(9600); // USB is always 12 Mbit/sec
|
||||
#ifdef DEBUG
|
||||
delay(500);
|
||||
Serial.print("DBG: Number of CAT commands: ");
|
||||
Serial.println(numCommands);
|
||||
for (int i = 0; i < numCommands; i++) {
|
||||
Serial.print(" ");
|
||||
Serial.println(commands[i]->prefix());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void UBitxTS590::update() {
|
||||
char incomingChar;
|
||||
|
||||
while (Serial.available()) {
|
||||
if (bufLen < ts590CommandMaxLength) {
|
||||
incomingChar = Serial.read();
|
||||
if (incomingChar == ';') {
|
||||
buf[bufLen++] = '\0';
|
||||
strupr(buf);
|
||||
processCommand();
|
||||
} else if (incomingChar == '\n' && bufLen == 0) {
|
||||
;
|
||||
} else {
|
||||
buf[bufLen++] = incomingChar;
|
||||
}
|
||||
} else {
|
||||
// too long... we're going to bail on this.
|
||||
ts590SyntaxError();
|
||||
bufLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef class TS590Command* PCmd;
|
||||
|
||||
int compareCATCommands(const void* a, const void* b) {
|
||||
TS590Command const *B = *(TS590Command const **)b;
|
||||
int cmp = strncmp((char*)a, (char*)B->prefix(), B->length());
|
||||
#ifdef DEBUG
|
||||
Serial.print("Comparison: ");
|
||||
Serial.print((char*)a);
|
||||
Serial.print(" ? ");
|
||||
Serial.print((char*)B->prefix());
|
||||
Serial.print(" --> ");
|
||||
Serial.println(cmp);
|
||||
#endif
|
||||
return cmp;
|
||||
}
|
||||
|
||||
void UBitxTS590::processCommand() {
|
||||
TS590Command** cmd = (TS590Command**)bsearch(buf, commands, numCommands, sizeof(TS590Command*), compareCATCommands);
|
||||
if (cmd == NULL) {
|
||||
ts590SyntaxError();
|
||||
} else {
|
||||
(*cmd)->process(buf);
|
||||
}
|
||||
bufLen = 0;
|
||||
}
|
||||
|
||||
UBitxTS590 TS590(catCommands, numCatCommands);
|
||||
|
||||
/**********************************************************************/
|
362
TeensyDSP/TS590.h
Normal file
362
TeensyDSP/TS590.h
Normal file
@@ -0,0 +1,362 @@
|
||||
#ifndef __TS590_h__
|
||||
#define __TS590_h__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Embedded_Template_Library.h>
|
||||
#include <etl/delegate.h>
|
||||
#include "DSP.h"
|
||||
#include "Rig.h"
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
#define TS590_COMMAND_MAX_LENGTH 50 // including terminator (which will get converted to null)
|
||||
|
||||
const int ts590CommandMaxLength = TS590_COMMAND_MAX_LENGTH;
|
||||
|
||||
void ts590SendCommand(const char*, ...);
|
||||
|
||||
/*!
|
||||
* @brief Send a syntax error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590SyntaxError() { ts590SendCommand("?"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a communications error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590CommError() { ts590SendCommand("E"); }
|
||||
|
||||
/*!
|
||||
* @brief Send a processing error response to the PC via CAT.
|
||||
*/
|
||||
inline void ts590ProcessError() { ts590SendCommand("O"); }
|
||||
|
||||
enum TS590Error {
|
||||
NoError,
|
||||
SyntaxError,
|
||||
CommError,
|
||||
ProcessError
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************/
|
||||
/*
|
||||
class TS590BaseCommand {
|
||||
public:
|
||||
TS590BaseCommand(const char* prefix)
|
||||
: myPrefix(prefix), prefixLength(strlen(prefix))
|
||||
{}
|
||||
virtual ~TS590BaseCommand() = 0;
|
||||
|
||||
inline const char* prefix() { return &myPrefix[0]; }
|
||||
inline size_t length() { return prefixLength; }
|
||||
|
||||
virtual void handleCommand(const char* cmd) = 0;
|
||||
virtual void sendResponse(const char* cmd) = 0;
|
||||
virtual bool isReadCommand(const char* cmd) const;
|
||||
|
||||
inline void process(const char* cmd) {
|
||||
theError = NoError;
|
||||
|
||||
if (isReadCommand(cmd)) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
} else {
|
||||
DBGCMD( handleCommand(cmd) );
|
||||
switch(theError) {
|
||||
case NoError:
|
||||
if (theRig->isAI()) {
|
||||
DBGCMD( sendResponse(cmd) );
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxError:
|
||||
DBGCMD( ts590SyntaxError() );
|
||||
break;
|
||||
|
||||
case CommError:
|
||||
DBGCMD( ts590CommError() );
|
||||
break;
|
||||
|
||||
case ProcessError:
|
||||
DBGCMD( ts590ProcessError() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const char* myPrefix;
|
||||
size_t prefixLength;
|
||||
};
|
||||
*/
|
||||
typedef etl::delegate<bool(const char*)> ValidateFunc;
|
||||
typedef etl::delegate<bool(const char*)> IsReadFunc;
|
||||
typedef etl::delegate<void(bool)> ToggleFunc;
|
||||
|
||||
/*
|
||||
class TS590ToggleCommand : public TS590BaseCommand {
|
||||
TS590ToggleCommand(const char* prefix, ToggleFunc& setter, ToggleFunc& getter)
|
||||
: TS590BaseCommand(prefix)
|
||||
{}
|
||||
|
||||
private:
|
||||
ToggleFunc& mySetter;
|
||||
ToggleFunc& myGetter;
|
||||
};
|
||||
*/
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief A TS590S/SG "CAT" command. This is the base class for all
|
||||
* CAT commands.
|
||||
*/
|
||||
class TS590Command {
|
||||
public:
|
||||
TS590Command(const char* pre);
|
||||
virtual ~TS590Command();
|
||||
|
||||
/*!
|
||||
* @brief Return the 2-character prefix for the command.
|
||||
* @return The 2-character prefix for the command.
|
||||
*/
|
||||
inline const char* prefix() const { return &myPrefix[0]; }
|
||||
|
||||
inline size_t length() const { return prefixLength; }
|
||||
|
||||
/*!
|
||||
* @brief Return the rig that this command will be used to control.
|
||||
*/
|
||||
inline UBitxRig* rig() const { return theRig; }
|
||||
|
||||
/*!
|
||||
* @brief Return the DSP that this command will be used to control.
|
||||
*/
|
||||
inline UBitxDSP* dsp() const { return theDSP; }
|
||||
|
||||
/*!
|
||||
* @brief Handle the provided Set command. If the Set command
|
||||
* results in an error, then set the appropriate flag with
|
||||
* setSyntaxError(), setCommError(), or setProcessError().
|
||||
* @param cmd
|
||||
* The current command string received from the PC via CAT.
|
||||
* It should be null-terminated, and should no longer have
|
||||
* the terminator (;).
|
||||
*/
|
||||
virtual void handleCommand(const char* cmd) = 0;
|
||||
|
||||
/*!
|
||||
* @brief Send a response back to the PC. This assumes a
|
||||
* successful command (no errors).
|
||||
*/
|
||||
virtual void sendResponse(const char* cmd) = 0;
|
||||
|
||||
virtual bool isReadCommand(const char* cmd) const;
|
||||
|
||||
void process(const char* cmd);
|
||||
|
||||
static void setSyntaxError();
|
||||
static void setCommError();
|
||||
static void setProcessError();
|
||||
static void setRig(UBitxRig* r);
|
||||
static void setDSP(UBitxDSP* d);
|
||||
|
||||
private:
|
||||
const char* myPrefix;
|
||||
size_t prefixLength;
|
||||
static TS590Error theError;
|
||||
static UBitxRig* theRig;
|
||||
static UBitxDSP* theDSP;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
typedef etl::delegate<void(bool)> SetBool;
|
||||
typedef etl::delegate<bool(void)> GetBool;
|
||||
|
||||
class TS590Command_Bool : public TS590Command {
|
||||
public:
|
||||
TS590Command_Bool(const char* prefix, SetBool set, GetBool get)
|
||||
: TS590Command(prefix), setter(set), getter(get) {}
|
||||
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
|
||||
private:
|
||||
SetBool setter;
|
||||
GetBool getter;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
typedef etl::delegate<void(unsigned)> SetUL;
|
||||
typedef etl::delegate<unsigned(void)> GetUL;
|
||||
|
||||
class TS590Command_UL : public TS590Command {
|
||||
public:
|
||||
TS590Command_UL(const char* prefix, size_t width, unsigned min, unsigned max, SetUL set, GetUL get)
|
||||
: TS590Command(prefix), myWidth(width), myMin(min), myMax(max), mySlope(1), myIntercept(0), setter(set), getter(get) {}
|
||||
|
||||
TS590Command_UL(const char* prefix, size_t width, unsigned min, unsigned max, unsigned slope, unsigned intercept, SetUL set, GetUL get)
|
||||
: TS590Command(prefix), myWidth(width), myMin(min), myMax(max), mySlope(slope), myIntercept(intercept), setter(set), getter(get) {}
|
||||
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
|
||||
private:
|
||||
size_t myWidth;
|
||||
unsigned myMin;
|
||||
unsigned myMax;
|
||||
unsigned mySlope;
|
||||
unsigned myIntercept;
|
||||
SetUL setter;
|
||||
GetUL getter;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
/*
|
||||
typedef etl::delegate<void(bool)> SetULArray;
|
||||
typedef etl::delegate<bool(void)> GetULArray;
|
||||
|
||||
class TS590Command_ULArray : public TS590Command {
|
||||
public:
|
||||
TS590Command_ULArray(const char* prefix, SetUL set, GetUL get)
|
||||
: TS590Command(prefix), setter(set), getter(get) {}
|
||||
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
|
||||
private:
|
||||
SetUL setter;
|
||||
GetUL getter;
|
||||
};
|
||||
*/
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting or reading the VFO A/B frequency.
|
||||
*/
|
||||
template<bool VFOA>
|
||||
class TS590_FAB : public TS590Command {
|
||||
public:
|
||||
TS590_FAB(): TS590Command(VFOA ? "FA" : "FB") {}
|
||||
|
||||
virtual void handleCommand(const char* cmd) {
|
||||
if (strlen(cmd) == 13) {
|
||||
unsigned long freq = strtoul(&cmd[2], NULL, 10);
|
||||
if (VFOA) {
|
||||
rig()->setFreqA(freq);
|
||||
} else {
|
||||
rig()->setFreqB(freq);
|
||||
}
|
||||
} else {
|
||||
setSyntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void sendResponse(const char* cmd) {
|
||||
ts590SendCommand(VFOA ? "FA%011u" : "FB%011u", VFOA ? rig()->getFreqA() : rig()->getFreqB());
|
||||
}
|
||||
};
|
||||
|
||||
typedef TS590_FAB<true> TS590_FA;
|
||||
typedef TS590_FAB<false> TS590_FB;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver VFO. This will always
|
||||
* disable split mode, if it was previously enabled.
|
||||
*/
|
||||
class TS590_FR : public TS590Command {
|
||||
public:
|
||||
TS590_FR(): TS590Command("FR") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the transmitter VFO. If it is
|
||||
* different than the receiver VFO, then split mode will be
|
||||
* automatically enabled.
|
||||
*/
|
||||
class TS590_FT : public TS590Command {
|
||||
public:
|
||||
TS590_FT(): TS590Command("FT") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the mode.
|
||||
*/
|
||||
class TS590_MD : public TS590Command {
|
||||
public:
|
||||
TS590_MD(): TS590Command("MD") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver high-cut frequency.
|
||||
*/
|
||||
class TS590_SH : public TS590Command {
|
||||
public:
|
||||
TS590_SH(): TS590Command("SH") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
private:
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief CAT command for setting the receiver low-cut frequency.
|
||||
*/
|
||||
class TS590_SL : public TS590Command {
|
||||
public:
|
||||
TS590_SL(): TS590Command("SL") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
private:
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/*!
|
||||
* CAT command for enabling or disabling the mic VOX.
|
||||
*/
|
||||
class TS590_VX : public TS590Command {
|
||||
public:
|
||||
TS590_VX(): TS590Command("VX") {}
|
||||
virtual void handleCommand(const char* cmd);
|
||||
virtual void sendResponse(const char* cmd);
|
||||
private:
|
||||
unsigned index;
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
class UBitxTS590 {
|
||||
public:
|
||||
UBitxTS590(TS590Command** cmds, int len): commands(cmds), numCommands(len) {}
|
||||
|
||||
void begin();
|
||||
void update();
|
||||
|
||||
private:
|
||||
void processCommand();
|
||||
|
||||
char buf[ts590CommandMaxLength] = {0};
|
||||
int bufLen = 0;
|
||||
TS590Command** commands;
|
||||
int numCommands;
|
||||
};
|
||||
|
||||
extern UBitxTS590 TS590;
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
75
TeensyDSP/TeensyDSP.h
Normal file
75
TeensyDSP/TeensyDSP.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Configuration file for Nextion LCD and Control MCU
|
||||
The parameter can be set according to the CPU used.
|
||||
|
||||
KD8CEC, Ian Lee
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Debug.h"
|
||||
#include "DSP.h"
|
||||
#include "Keyer.h"
|
||||
#include "Nextion.h"
|
||||
#include "Rig.h"
|
||||
#include "RigState.h"
|
||||
#include "Sensors.h"
|
||||
#include "TR.h"
|
||||
#include "TS590.h"
|
||||
|
||||
//================================================================
|
||||
//COMMUNICATION SECTION
|
||||
//================================================================
|
||||
|
||||
//================================================================
|
||||
// FFT and Decode Morse
|
||||
//================================================================
|
||||
|
||||
#define FFTSIZE 64
|
||||
#define SAMPLE_FREQUENCY 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
|
||||
|
||||
// Raduino<=>TeensyDSP data exchange
|
||||
#define I2CMETER_RIGINF 0x50
|
||||
|
||||
// Raduino requests any CAT updates from TeensyDSP
|
||||
//#define I2CMETER_REQCAT 0x51
|
779
TeensyDSP/TeensyDSP.ino
Normal file
779
TeensyDSP/TeensyDSP.ino
Normal file
@@ -0,0 +1,779 @@
|
||||
/*
|
||||
FFT, CW Decode for uBITX
|
||||
KD8CEC, Ian Lee
|
||||
|
||||
Version : 0.8
|
||||
-----------------------------------------------------------------------
|
||||
License : See fftfunctions.cpp for FFT and CW Decode.
|
||||
**********************************************************************/
|
||||
|
||||
#include <ADC.h>
|
||||
#include <i2c_t3.h> // using i2c_t3 library for multiple I2C busses
|
||||
#include <EEPROM.h>
|
||||
#include "TeensyDSP.h"
|
||||
|
||||
//const uint8_t responseHeader[11]={'p', 'm', '.', 's', 'p', '.', 't', 'x', 't', '=', '"'}; //for Spectrum from DSP
|
||||
//const uint8_t responseFooter[4]={'"', 0xFF, 0xFF, 0xFF};
|
||||
//const char hexCodes[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', };
|
||||
|
||||
#ifdef DEBUG
|
||||
int i2cCmdCounter[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
int i2cRespCounter[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
#endif
|
||||
|
||||
unsigned long SAMPLE_INTERVAL = 0;
|
||||
|
||||
int i2cCommand = 0;
|
||||
//void calculateCoeff(uint8_t freqIndex);
|
||||
uint8_t cwDecodeHz = 9;
|
||||
int magnitudelimit_low = 30;
|
||||
|
||||
char forwardBuff[MAX_FORWARD_BUFF_LENGTH + 1];
|
||||
static int nowBuffIndex = 0;
|
||||
static char etxCount = 0;
|
||||
static char nowSendingProtocol = 0;
|
||||
|
||||
uint8_t SMeterToUartSend = 0; //0 : Send, 1: Idle
|
||||
uint8_t SMeterToUartIdleCount = 0;
|
||||
#define SMeterToUartInterval 4
|
||||
|
||||
char DSPType = 1; //0 : Not Use, 1 : FFT, 2 : Morse Decoder, 3 : RTTY Decoder
|
||||
char FFTToUartIdleCount = 0;
|
||||
#define FFTToUartInterval 2
|
||||
|
||||
elapsedMillis sinceForward = 0;
|
||||
uint8_t responseCommand = 0; //
|
||||
bool isTX = false;
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void responseConfig()
|
||||
{
|
||||
if (responseCommand == 2)
|
||||
{
|
||||
unsigned long returnValue = 0;
|
||||
if (DSPType == 0)
|
||||
{
|
||||
returnValue = 94; //None
|
||||
}
|
||||
else if (DSPType == 1)
|
||||
{
|
||||
returnValue = 95; //Spectrum (FFT) mode
|
||||
}
|
||||
else if (DSPType == 2)
|
||||
{
|
||||
returnValue = 100 + cwDecodeHz;
|
||||
}
|
||||
|
||||
returnValue = returnValue << 8;
|
||||
returnValue = returnValue | (SMeterToUartSend & 0xFF);
|
||||
returnValue = returnValue << 8;
|
||||
uint8_t tmpValue = 0;
|
||||
if (magnitudelimit_low > 255)
|
||||
tmpValue = 255;
|
||||
else if (magnitudelimit_low < 1)
|
||||
tmpValue = 0;
|
||||
else
|
||||
tmpValue = magnitudelimit_low;
|
||||
returnValue = returnValue | (tmpValue & 0xFF);
|
||||
|
||||
sendCommandUL('v', returnValue); //Return data
|
||||
sendCommandUL('g', 0x6A); //Return data
|
||||
}
|
||||
responseCommand = 0;
|
||||
}
|
||||
|
||||
//Result : if found .val=, 1 else 0
|
||||
/*!
|
||||
@brief Parse commands...
|
||||
*/
|
||||
|
||||
char commandParser(int lastIndex)
|
||||
{
|
||||
//Analysing Forward data
|
||||
//59 58 68 4A 1C 5F 6A E5 FF FF 73
|
||||
//Find Loopback protocol
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
||||
//70 6D 2E 76 76 2E 76 61 6C 3D 33 38 34 38 39 35 33 36 32 38 FF FF FF
|
||||
//pm.vv.val=3848953628\xFF\xFF\xFF
|
||||
//1234567890XXX
|
||||
//
|
||||
int startIndex = 0;
|
||||
|
||||
//Loop back command has 13 ~ 23
|
||||
if (lastIndex < 13)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Protocol MAX Length : 22
|
||||
if (lastIndex >= 22)
|
||||
{
|
||||
startIndex = lastIndex - 22;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
for (int i = lastIndex - 3; i >= startIndex + 7; i--)
|
||||
{
|
||||
//Find =
|
||||
if (forwardBuff[i - 3] == 'v' && forwardBuff[i - 2] == 'a' && forwardBuff[i - 1] == 'l' && forwardBuff[i] == '=') //0x3D
|
||||
{
|
||||
uint8_t command1 = forwardBuff[i - 6]; //v
|
||||
uint8_t command2 = forwardBuff[i - 5]; //v
|
||||
// i-4 //.
|
||||
forwardBuff[lastIndex - 2] = 0;
|
||||
long commandVal = atol(&forwardBuff[i + 1]);
|
||||
uint8_t *readBuff = (uint8_t *)&commandVal;
|
||||
|
||||
//Loop Back
|
||||
if (command1 == 'v' && command2 == 'v')
|
||||
{
|
||||
int calcChecksum = readBuff[0] + readBuff[1] + readBuff[2];
|
||||
calcChecksum = calcChecksum % 256;
|
||||
|
||||
//Correct Checksum and Receiver is DSP Moudle protocol v1.0
|
||||
if (calcChecksum == readBuff[3] && readBuff[2] == 0x6A)
|
||||
{
|
||||
//Serial1.print("Correct Checksum Command : ");
|
||||
//Serial1.println(readBuff[1]);
|
||||
uint8_t cmd1 = readBuff[1];
|
||||
if (cmd1 == 94)
|
||||
{
|
||||
DSPType = 0;
|
||||
EEPROM.put(EEPROM_DSPTYPE, DSPType);
|
||||
}
|
||||
else if (cmd1 == 95)
|
||||
{
|
||||
//Serial1.println("Spectrum Mode");
|
||||
DSPType = 1;
|
||||
EEPROM.put(EEPROM_DSPTYPE, DSPType);
|
||||
}
|
||||
else if (cmd1 >= 100 && cmd1 <= 145)
|
||||
{
|
||||
cwDecodeHz = cmd1 - 100;
|
||||
//calculateCoeff(cwDecodeHz);
|
||||
DSPType = 2;
|
||||
EEPROM.put(EEPROM_DSPTYPE, DSPType);
|
||||
EEPROM.put(EEPROM_CW_FREQ, cwDecodeHz);
|
||||
}
|
||||
else if (cmd1 > 1 && cmd1 <= 5) //2~5 : Request Configuration
|
||||
{
|
||||
responseCommand = cmd1;
|
||||
}
|
||||
else if (cmd1 == 50 || cmd1 == 51) //Set Configuration
|
||||
{
|
||||
SMeterToUartSend = (cmd1 == 51);
|
||||
EEPROM.put(EEPROM_SMETER_UART, SMeterToUartSend);
|
||||
}
|
||||
else if (cmd1 >= 146 && cmd1 <= 156 )
|
||||
{
|
||||
//Save Mode
|
||||
magnitudelimit_low = (cmd1 - 146) * 10;
|
||||
EEPROM.put(EEPROM_CW_MAG_LOW, magnitudelimit_low);
|
||||
} //end of if
|
||||
} //end of check Checksum
|
||||
} //end of check Protocol (vv)
|
||||
else if (command1 == 'c' && command2 == 't') //TX, RX
|
||||
{
|
||||
if (commandVal == 0) //RX
|
||||
{
|
||||
isTX = false;
|
||||
SMeterToUartIdleCount = 0;
|
||||
}
|
||||
else if (commandVal == 1) //TX
|
||||
{
|
||||
isTX = true;
|
||||
SMeterToUartIdleCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
} //end of check Protocol (.val)
|
||||
} //end of for
|
||||
|
||||
//Not found Protocol (.val=
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//#define PROTOCOL_TIMEOUT = 100
|
||||
|
||||
/*!
|
||||
@brief Forwards serial data from the RX line to the TX line.
|
||||
*/
|
||||
|
||||
void forwardData(void)
|
||||
{
|
||||
char recvChar;
|
||||
|
||||
if (Serial1.available() > 0)
|
||||
{
|
||||
Serial1.flush();
|
||||
|
||||
// Check RX buffer for available data.
|
||||
while (Serial1.available() > 0)
|
||||
{
|
||||
recvChar = char(Serial1.read());
|
||||
|
||||
forwardBuff[nowBuffIndex] = recvChar;
|
||||
|
||||
if (recvChar == 0xFF) // found ETX
|
||||
{
|
||||
etxCount++; // Nextion protocol, ETX: 0xFF, 0xFF, 0xFF
|
||||
if (etxCount >= 3)
|
||||
{
|
||||
// Finished Protocol
|
||||
if (commandParser(nowBuffIndex) == 1)
|
||||
{
|
||||
nowSendingProtocol = 0; // finished 1 set command
|
||||
etxCount = 0;
|
||||
nowBuffIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nowSendingProtocol = 1; // sending data
|
||||
etxCount = 0;
|
||||
}
|
||||
|
||||
Serial1.write(recvChar);
|
||||
sinceForward = 0;
|
||||
nowBuffIndex++;
|
||||
|
||||
if (nowBuffIndex > MAX_FORWARD_BUFF_LENGTH - 2)
|
||||
{
|
||||
nowBuffIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Serial1.flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
// check timeout
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void sendMeterData(uint8_t isSend)
|
||||
{
|
||||
scaledSMeter = Sensors.sMeterScaled();
|
||||
|
||||
/*
|
||||
1 : with noise (not use 0 ~ S3)
|
||||
2 : -93 ~ -89
|
||||
3 : -88 ~ -81
|
||||
4 : -80 ~ -78
|
||||
5 : -77 ~ -72
|
||||
6 : -71 ~ -69
|
||||
*/
|
||||
|
||||
if (isSend == 1)
|
||||
{
|
||||
if (L_scaledSMeter != scaledSMeter)
|
||||
{
|
||||
L_scaledSMeter = scaledSMeter;
|
||||
sendCommand1Num(CMD_SMETER, L_scaledSMeter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
//void sendFFTData(void)
|
||||
//{
|
||||
// int readValue = 0;
|
||||
// for (int i = 0; i < 11; i++)
|
||||
// Serial1.write(responseHeader[i]);
|
||||
//
|
||||
// for(int i = 1; i < 64; i++)
|
||||
// {
|
||||
// readValue = (int)(FFTReal[i]);
|
||||
// if (readValue < 0)
|
||||
// {
|
||||
// readValue = 0;
|
||||
// }
|
||||
// else if (readValue>255)
|
||||
// {
|
||||
// readValue=255;
|
||||
// }
|
||||
// Serial1.write(hexCodes[readValue >> 4]);
|
||||
// Serial1.write(hexCodes[readValue & 0xf]);
|
||||
// }
|
||||
//
|
||||
// for (int i = 0; i < 4; i++)
|
||||
// Serial1.write(responseFooter[i]);
|
||||
//}
|
||||
|
||||
void setup()
|
||||
{
|
||||
// Startup each of the subsystems, beginning with CAT.
|
||||
DBGCMD( TS590.begin() );
|
||||
DBGCMD( TR.begin() );
|
||||
DBGCMD( Rig.begin() );
|
||||
DBGCMD( DSP.begin() );
|
||||
|
||||
// load configuration
|
||||
EEPROM.get(EEPROM_DSPTYPE, DSPType);
|
||||
if (DSPType > 5)
|
||||
{
|
||||
DSPType = 1;
|
||||
}
|
||||
|
||||
// signal meter
|
||||
EEPROM.get(EEPROM_SMETER_UART, SMeterToUartSend);
|
||||
if (SMeterToUartSend > 2)
|
||||
{
|
||||
SMeterToUartSend = 1;
|
||||
}
|
||||
|
||||
// something with CW decoding...
|
||||
EEPROM.get(EEPROM_CW_FREQ, cwDecodeHz);
|
||||
if (cwDecodeHz > 40 || cwDecodeHz < 1)
|
||||
{
|
||||
cwDecodeHz = 9;
|
||||
}
|
||||
|
||||
// EEPROM_CW_MAG_LOW
|
||||
EEPROM.get(EEPROM_CW_MAG_LOW, magnitudelimit_low);
|
||||
if (magnitudelimit_low > 1000 || magnitudelimit_low < 1)
|
||||
{
|
||||
magnitudelimit_low = 50;
|
||||
}
|
||||
|
||||
// put your setup code here, to run once:
|
||||
|
||||
// slave Wire1 configuration for communication with the Raduino
|
||||
Wire1.begin(I2CMETER_ADDR);
|
||||
Wire1.onReceive(i2cReceiveEvent);
|
||||
Wire1.onRequest(i2cRequestEvent);
|
||||
|
||||
// Serial1 configuration for communication with Raduino (RX) and Nextion (TX)
|
||||
Serial1.begin(9600, SERIAL_8N1);
|
||||
Serial1.flush();
|
||||
|
||||
SAMPLE_INTERVAL = round(1000000 * (1.0 / SAMPLE_FREQUENCY));
|
||||
//calculateCoeff(cwDecodeHz); //Set 750Hz //9 * 50 + 300 = 750Hz
|
||||
//Serial1.println("Start...");
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Receive a command via I2C. The most recent command will be received, which will
|
||||
indicate which data the DSP should be preparing to return.
|
||||
@param numBytes
|
||||
Number of bytes received--not used in this procedure.
|
||||
*/
|
||||
void i2cReceiveEvent(size_t numBytes)
|
||||
{
|
||||
int readCommand = 0;
|
||||
bool exitLoop = false;
|
||||
|
||||
// Does this really need to be a while loop? Don't we know the number of bytes?
|
||||
while (Wire1.available() > 0 && !exitLoop) {
|
||||
readCommand = Wire1.read();
|
||||
if (readCommand == I2CMETER_RIGINF) {
|
||||
Rig.rad().receive_RIGINF(numBytes - 1);
|
||||
exitLoop = true;
|
||||
}
|
||||
}
|
||||
|
||||
// while (Wire1.available() > 0) // for Last command
|
||||
// {
|
||||
// readCommand = Wire1.read();
|
||||
// // KC4UPR: Note that this looks to be only reading the last command, i.e.
|
||||
// // if multiple commands have been queued up, only the last will get executed.
|
||||
// }
|
||||
|
||||
if (0x50 <= readCommand && readCommand <= 0x59)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
i2cCmdCounter[readCommand - 0x50]++;
|
||||
#endif
|
||||
i2cCommand = readCommand;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Respond to a request from the I2C Master (Raduino). Returns the appropriate data
|
||||
based on whatever command was previously issued.
|
||||
*/
|
||||
void i2cRequestEvent(void)
|
||||
{
|
||||
//int maxValue = 0;
|
||||
//int minValue = 30000;
|
||||
//int readValue = 0;
|
||||
//unsigned long curr = 0;
|
||||
|
||||
switch (i2cCommand) {
|
||||
case I2CMETER_CALCS:
|
||||
// Returns an already-calculated S-meter value.
|
||||
Wire1.write(scaledSMeter);
|
||||
break;
|
||||
|
||||
case I2CMETER_UNCALCS:
|
||||
// Returns a raw signal strength value.
|
||||
Wire1.write(Sensors.sMeterUnscaled() >> 2); // divided by 4... do we want this?
|
||||
break;
|
||||
|
||||
case I2CMETER_CALCP:
|
||||
// Returns a raw forward power value.
|
||||
Wire1.write(int(fwdPower * 100.0));
|
||||
break;
|
||||
|
||||
case I2CMETER_CALCR:
|
||||
// Returns a raw reverse power value.
|
||||
Wire1.write(int(revPower * 100.0));
|
||||
break;
|
||||
|
||||
case I2CMETER_RIGINF:
|
||||
// Receive current rig state; transmit any CAT updates, if required.
|
||||
Rig.cat().send_RIGINF();
|
||||
//Wire1.write(catState.header); // temporary - just writing a single, null byte
|
||||
// NEEDS TO GET UPDATED
|
||||
break;
|
||||
|
||||
/*
|
||||
case I2CMETER_REQCAT:
|
||||
// Provide latest CAT updates, if any.
|
||||
//Wire1.write(catState.header); // temporary - just writing a single, null byte
|
||||
// NEEDS TO GET UPDATED
|
||||
if (Rig.updatedByCAT()) {
|
||||
if (sentRigInfFlag) {
|
||||
DBGPRINTLN("I2CMETER_REQCAT -- updated by CAT");
|
||||
Wire1.write(Rig.stateAsBytes(), sizeof(UBitxRigState));
|
||||
Rig.clearUpdate();
|
||||
} else {
|
||||
Wire1.write(1);
|
||||
sentRigInfFlag = true;
|
||||
}
|
||||
} else {
|
||||
DBGPRINTLN("I2CMETER_REQCAT -- NOT updated by CAT");
|
||||
//Wire1.write(Rig.stateAsBytes(), sizeof(uint8_t));
|
||||
Wire1.write(0);
|
||||
}
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (0x50 <= i2cCommand && i2cCommand <= 0x59)
|
||||
{
|
||||
i2cRespCounter[i2cCommand - 0x50]++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//extern void Decode_Morse(float magnitude);
|
||||
//extern double coeff;
|
||||
|
||||
#define LAST_TIME_INTERVAL 159
|
||||
|
||||
// for boot delay, a lot of data to transfer
|
||||
// Delay 2.5 Sec
|
||||
byte isBooted = 0;
|
||||
|
||||
//======================================================================
|
||||
// ADC PROCESSES
|
||||
//======================================================================
|
||||
|
||||
elapsedMillis sinceFrameMillis = 0;
|
||||
elapsedMillis sinceADCMillis = 0;
|
||||
|
||||
#define FRAME_RATE 40
|
||||
#define FRAME_INTERVAL_MS (1000/FRAME_RATE)
|
||||
|
||||
const int frameIntervalMillis = FRAME_INTERVAL_MS;
|
||||
|
||||
#define ADC_SAMPLE_RATE 120
|
||||
#define ADC_INTERVAL_MS (1000/ADC_SAMPLE_RATE)
|
||||
|
||||
const int adcIntervalMillis = ADC_INTERVAL_MS;
|
||||
|
||||
//======================================================================
|
||||
// MAIN LOOP
|
||||
//======================================================================
|
||||
|
||||
#ifdef DEBUG
|
||||
int frameCounter = 0;
|
||||
#endif
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
void loop()
|
||||
{
|
||||
//char isProcess = 0; // 0: init, 1: complete ADC sampling, 2: complete FFT
|
||||
//isProcess = 0;
|
||||
|
||||
// One-shot delay to ensure everything is booted up (primarily, the
|
||||
// Nextion, and secondarily the Raduino.
|
||||
if (isBooted < 100)
|
||||
{
|
||||
// delay 20msec
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
forwardData();
|
||||
delay(1);
|
||||
}
|
||||
isBooted++;
|
||||
return;
|
||||
}
|
||||
|
||||
// If CW mode, we need to update keying a lot...
|
||||
if (Rig.isModeCWAny()) {
|
||||
if (Rig.isModeCWAny()) Keyer.doPaddles();
|
||||
TR.update(Rig.isModeCWAny(), Keyer.isDown());
|
||||
//if (TR.transmitting()) return;
|
||||
}
|
||||
|
||||
// Start out by forwarding any data sitting in the RX buffer. We will
|
||||
// do this as often as possible.
|
||||
forwardData();
|
||||
|
||||
if (sinceFrameMillis > frameIntervalMillis) {
|
||||
// Do stuff that we do once per frame--I/O.
|
||||
// TODO: debug output (frame skipping / utilization).
|
||||
sinceFrameMillis = 0;
|
||||
|
||||
// Update each of the subsystems, beginning with CAT control.
|
||||
TS590.update();
|
||||
TR.update(Rig.isModeCWAny(), Keyer.isDown());
|
||||
Rig.update();
|
||||
DSP.update();
|
||||
|
||||
//if (Rig.isModeCWAny()) return;
|
||||
|
||||
#ifdef DEBUG
|
||||
// For debugging, output some debug info every 1.0" (40 frames @ 40 Hz).
|
||||
frameCounter++;
|
||||
if (frameCounter % 40 == 0) {
|
||||
Serial.println("======================================================================");
|
||||
Serial.print("DBG: Frame: ");
|
||||
Serial.print(frameCounter);
|
||||
if (isTX) {
|
||||
Serial.print(", Loop State: TX");
|
||||
} else {
|
||||
Serial.print(", Loop State: RX");
|
||||
}
|
||||
if (TR.transmitting()) {
|
||||
Serial.println(", TR State: TX");
|
||||
} else {
|
||||
Serial.println(", TR State: RX");
|
||||
}
|
||||
Serial.print("VFO A: ");
|
||||
Serial.print(Rig.getFreqA());
|
||||
Serial.print(", VFO B: ");
|
||||
Serial.print(Rig.getFreqB());
|
||||
Serial.print(", Data Size: ");
|
||||
Serial.print(sizeof(UBitxRigState));
|
||||
Serial.println();
|
||||
Serial.println("----------------------------------------------------------------------");
|
||||
Serial.print("DBG: S-Meter Raw: ");
|
||||
Serial.print(Sensors.sMeterUnscaled());
|
||||
Serial.print(", S-Meter Scaled: ");
|
||||
Serial.println(scaledSMeter);
|
||||
Serial.print("DBG: VSWR Calc: ");
|
||||
Serial.print(calcVSWR, 2);
|
||||
Serial.print(", VSWR Scaled: ");
|
||||
Serial.print(scaledVSWR);
|
||||
Serial.print(", FWD PWR: ");
|
||||
Serial.print(fwdPower, 2);
|
||||
Serial.print(", REV PWR: ");
|
||||
Serial.println(revPower, 2);
|
||||
Serial.print("Audio Memory: ");
|
||||
Serial.print(AudioMemoryUsage());
|
||||
Serial.print(",");
|
||||
Serial.println(AudioMemoryUsageMax());
|
||||
Serial.println("----------------------------------------------------------------------");
|
||||
Serial.print("Enabled/Active: PTT: ");
|
||||
Serial.print(TR.micPTTEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.micPTTPressed() ? "Y" : "N");
|
||||
Serial.print(", VOX: ");
|
||||
Serial.print(TR.micVOXEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.micVOXActivated() ? "Y" : "N");
|
||||
Serial.print(", Key: ");
|
||||
Serial.print(TR.linePTTEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.linePTTPressed() ? "Y" : "N");
|
||||
Serial.print(", CAT: ");
|
||||
Serial.print(TR.catEnabled() ? "Y" : "N"); Serial.print("/"); Serial.print(TR.catActivated() ? "Y" : "N");
|
||||
Serial.println();
|
||||
Serial.print("I2C Command/Response: ");
|
||||
for (int i = 0x50; i <= 0x59; i++) {
|
||||
Serial.print(i, HEX); Serial.print(": ");
|
||||
Serial.print(i2cCmdCounter[i - 0x50]); Serial.print("/");
|
||||
Serial.print(i2cRespCounter[i - 0x50]); Serial.print(", ");
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isTX) {
|
||||
calcVSWR = Sensors.VSWR();
|
||||
scaledVSWR = byte(Sensors.scaledVSWR());
|
||||
fwdPower = Sensors.Pfwd();
|
||||
revPower = Sensors.Prev();
|
||||
|
||||
// Send SWR meter information.
|
||||
if (L_scaledVSWR != scaledVSWR) {
|
||||
L_scaledVSWR = scaledVSWR;
|
||||
sendCommand1Num(CMD_SMETER, scaledVSWR);
|
||||
}
|
||||
|
||||
// Send forward power.
|
||||
if (L_fwdPower != fwdPower) {
|
||||
L_fwdPower = fwdPower;
|
||||
sendCommandL('m', int(fwdPower * 100.0)); // watts x 100?
|
||||
sendCommand1Num('m', 2);
|
||||
}
|
||||
|
||||
// Send reverse power.
|
||||
//if (L_revPower != revPower) {
|
||||
// L_revPower = revPower;
|
||||
// sendCommandL('m', int(revPower * 100.0)); // watts x 100?
|
||||
// sendCommand1Num('m', 2);
|
||||
//}
|
||||
|
||||
// Does there need to be some kind of 250-500ms delay after this???
|
||||
// Delay 250msec ~ 500msec for Nextion LCD Processing (using m protocol)
|
||||
//for (int i = 0; i < 10; i++) {
|
||||
// forwardData();
|
||||
// if (!isTX) { //if TX -> RX break
|
||||
// break;
|
||||
// }
|
||||
// delay(25);
|
||||
//} //end of delay time
|
||||
|
||||
// Send SWR.
|
||||
if (L_calcVSWR != calcVSWR) {
|
||||
L_calcVSWR = calcVSWR;
|
||||
sendCommandL('m', int(calcVSWR * 100.0)); // SWR x 100?
|
||||
sendCommand1Num('m', 3);
|
||||
}
|
||||
|
||||
} else { // RX
|
||||
|
||||
// Send Signal Meter to UART
|
||||
if (SMeterToUartSend == 1 && nowSendingProtocol == 0) //SMeter To Uart Send
|
||||
{
|
||||
//nowSendingProtocol -> not finished data forward, (not found 0xff, 0xff, 0xff yet)
|
||||
sendMeterData(1);
|
||||
} else {
|
||||
sendMeterData(0); //only calculate Signal Level
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Forward any data that came in while we were updating stuff.
|
||||
forwardData();
|
||||
}
|
||||
|
||||
if (Rig.isModeCWAny()) return; // In CW, the ADC measurement messes with the timing. So need to use interrupts on the Keyer, and/or continuous ADC.
|
||||
|
||||
if (sinceADCMillis > adcIntervalMillis) {
|
||||
// Do stuff that we do once per ADC interval--ADC colllection.
|
||||
// TODO: debug output (frame skipping / utilization).
|
||||
sinceADCMillis = 0;
|
||||
|
||||
if (isTX) {
|
||||
Sensors.updatePower();
|
||||
} else { // RX
|
||||
Sensors.updateSMeter();
|
||||
Sensors.updateSupply();
|
||||
}
|
||||
|
||||
// Forward any data that came in while we were reading sensors.
|
||||
//forwardData();
|
||||
}
|
||||
|
||||
//if (Rig.isModeCWAny()) return;
|
||||
|
||||
// Check Response Command
|
||||
if (responseCommand > 0 && sinceForward > LAST_TIME_INTERVAL)
|
||||
{
|
||||
responseConfig();
|
||||
}
|
||||
|
||||
// //===========================================
|
||||
// //TRANSCEIVER STATUS : RX
|
||||
// //===========================================
|
||||
// //===================================================================================
|
||||
// // DSP Routine
|
||||
// //===================================================================================
|
||||
// if (DSPType == 1 && sinceForward > LAST_TIME_INTERVAL) // spectrum: FFT => send To UART
|
||||
// {
|
||||
// FFTToUartIdleCount = 0;
|
||||
//
|
||||
// if (isProcess == 1)
|
||||
// {
|
||||
// FFT(FFTReal, FFTImag, SAMPLESIZE, 7);
|
||||
// isProcess = 2;
|
||||
// }
|
||||
//
|
||||
// forwardData();
|
||||
//
|
||||
// if (isProcess == 2)
|
||||
// {
|
||||
// for (uint16_t k = 0; k < SAMPLESIZE; k++)
|
||||
// {
|
||||
// FFTReal[k] = sqrt(FFTReal[k] * FFTReal[k] + FFTImag[k] * FFTImag[k]);
|
||||
// }
|
||||
//
|
||||
// isProcess = 3;
|
||||
// }
|
||||
//
|
||||
// forwardData();
|
||||
//
|
||||
// if (isProcess == 3)
|
||||
// {
|
||||
// if (nowSendingProtocol == 0) //Idle Status
|
||||
// {
|
||||
// sendFFTData();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (DSPType == 2) //Decode Morse
|
||||
// {
|
||||
// //Implement Goertzel_algorithm
|
||||
// //https://en.wikipedia.org/wiki/Goertzel_algorithm
|
||||
//
|
||||
// /*
|
||||
// ω = 2 * π * Kterm / Nterms;
|
||||
// cr = cos(ω);
|
||||
// ci = sin(ω);
|
||||
// coeff = 2 * cr;
|
||||
//
|
||||
// sprev = 0;
|
||||
// sprev2 = 0;
|
||||
// for each index n in range 0 to Nterms-1
|
||||
// s = x[n] + coeff * sprev - sprev2;
|
||||
// sprev2 = sprev;
|
||||
// sprev = s;
|
||||
// end
|
||||
//
|
||||
// power = sprev2 * sprev2 + sprev * sprev - coeff * sprev * sprev2;
|
||||
// */
|
||||
// double Q1 = 0;
|
||||
// double Q2 = 0;
|
||||
//
|
||||
// for (unsigned index = 0; index < DECODE_MORSE_SAMPLESIZE; index++)
|
||||
// {
|
||||
// float Q0;
|
||||
// Q0 = coeff * Q1 - Q2 + FFTReal[index];
|
||||
// Q2 = Q1;
|
||||
// Q1 = Q0;
|
||||
// }
|
||||
// double magnitudeSquared = (Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff; // we do only need the real part //
|
||||
// double magnitude = sqrt(magnitudeSquared);
|
||||
//
|
||||
// Decode_Morse(magnitude);
|
||||
// } //end of if
|
||||
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
240
raduino-tmp/README.md
Normal file
240
raduino-tmp/README.md
Normal file
@@ -0,0 +1,240 @@
|
||||
<<<<<<< HEAD
|
||||
Stand-in README.md while I merge several repos into this project.
|
||||
=======
|
||||
#NOTICE
|
||||
----------------------------------------------------------------------------
|
||||
- Now Release Version 1.20 on my blog (http://www.hamskey.com)
|
||||
- You can download and compiled hex file and uBITX Manager application on release section (https://github.com/phdlee/ubitx/releases)
|
||||
- For more information, see my blog (http://www.hamskey.com)
|
||||
|
||||
http://www.hamskey.com
|
||||
|
||||
Ian 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
|
||||
- Add TTS module
|
||||
- Direct control for Student
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
## REVISION RECORD
|
||||
1.20
|
||||
- Support uBITX V5
|
||||
- Change to SDR Frequency (Remove just RTL-SDR's error Frequency (2390Hz))
|
||||
1.12
|
||||
- Support Custom LPF Control
|
||||
- Other Minor Bugs
|
||||
1.1
|
||||
- Support Nextion LCD, TJC LCD
|
||||
- Read & Backup uBITX, ADC Monitoring, ATT, IF-Shift and more on Nextion LCD (TJC LCD)
|
||||
- Factory Reset (Both Character LCD and Nextion LCD are applicable)
|
||||
- Support Signal Meter using ADC (A7 Port)
|
||||
- Supoort I2C Signal Meter
|
||||
- Spectrum
|
||||
- Band Scan
|
||||
- Memory Control on Nextion LCD (TJC LCD)
|
||||
- Speed Change CW-Option on Nextion LCD
|
||||
- Fixed Band Change Bug (Both Character LCD and Nextion LCD are applicable)
|
||||
- uBITX Manager removed the Encode and Decode buttons. The procedure has become a bit easier.
|
||||
- I2C Device Scan on uBITX Manager ( Both Character LCD and Nextion LCD are applicable)
|
||||
- Si5351 I2C Address can be changed
|
||||
- Recovery using QR-Code Data from Server
|
||||
- Nextion LCD and TJC LCD can display Spectrum and CW Decode (using Stand alone S-Meter)
|
||||
- Other Minor Bugs
|
||||
|
||||
1.09 (Beta)
|
||||
- include 1.094 beta, 1.095 beta, 1.097 beta
|
||||
|
||||
1.08
|
||||
- Receive performance is improved compared to the original firmware or version 1.061
|
||||
- ATT function has been added to reduce RF gain (Shift 45Mhz IF)
|
||||
- Added the ability to connect SDR. (Low cost RTL-SDR available)
|
||||
- Added a protocol to ADC Monitoring in CAT communications
|
||||
- Various LCD support, 16x02 Parallel LCD - It is the LCD equipped with uBITX, 16x02 I2C LCD, 20x04 Parallel LCD, 20x04 I2C LCD, 16x02 I2C Dual LCD
|
||||
- Added Extended Switch Support
|
||||
- Support S Meter
|
||||
- Added S-Meter setting assistant to uBITX Manager
|
||||
- Add recovery mode (such as Factory Reset)
|
||||
- There have been many other improvements and fixes. More information is available on the blog. (http://www.hamskey.com)
|
||||
|
||||
1.07 (Beta)
|
||||
- include 1.071 beta, 1.073 beta, 1.075 beta
|
||||
- Features implemented in the beta version have been applied to Version 1.08 above.
|
||||
|
||||
1.061
|
||||
- Added WSPR
|
||||
You only need uBITX to use WSPR. No external devices are required.
|
||||
Added Si5351 module for WSPR
|
||||
- Update uBITX Manager to Version 1.0
|
||||
- Reduce program size
|
||||
for WSPR
|
||||
for other Module
|
||||
- Fixed IF Shift Bug
|
||||
Disable IF Shift on TX
|
||||
IF shift available in USB mode
|
||||
Fixed cat routine in IF Shift setup
|
||||
- Bugs fixed
|
||||
cw start delay option
|
||||
Auto key Bug
|
||||
(found bug : LZ1LDO)
|
||||
Message selection when Auto Key is used in RIT mode
|
||||
(found bug : gerald)
|
||||
- Improve CW Keying (start TX)
|
||||
|
||||
1.05
|
||||
- include 1.05W, 1.051, 1.051W
|
||||
- for WSPR Beta Test Version
|
||||
|
||||
1.04
|
||||
- Optimized from Version1.03
|
||||
- Reduce program size (97% -> 95%)
|
||||
|
||||
1.03
|
||||
- Change eBFO Calibration Step (50 to 5)
|
||||
- Change CW Frequency Display type
|
||||
|
||||
1.02
|
||||
- Applied CW Start Delay to New CW Key logic (This is my mistake when applying the new CW Key Logic.Since uBITX operations are not significantly affected, this does not create a separate Release, It will be reflected in the next release.) - complete
|
||||
- Modified CW Key Logic for Auto Key, (available AutoKey function by any cw keytype) - complete
|
||||
- reduce cpu use usage (working)
|
||||
- reduce (working)
|
||||
|
||||
1.01
|
||||
- Fixed Cat problem with (IAMBIC A or B Selected)
|
||||
1.0
|
||||
- rename 0.30 to 1.0
|
||||
|
||||
0.35
|
||||
- vfo to channel bug fixed (not saved mode -> fixed, channel has frequency and mode)
|
||||
- add Channel tag (ch.1 ~ 10) by uBITX Manager
|
||||
- add VFO to Channel, Channel To VFO
|
||||
|
||||
0.34
|
||||
- TX Status check in auto Keysend logic
|
||||
- optimize codes
|
||||
- change default tune step size, and fixed bug
|
||||
- change IF shift step (1Hz -> 50Hz)
|
||||
|
||||
0.33
|
||||
- Added CWL, CWU Mode, (dont complete test yet)
|
||||
- fixed VFO changed bug.
|
||||
- Added Additional BFO for CWL, CWL
|
||||
- Added IF Shift
|
||||
- Change confirmation key PTT -> function key (not critical menus)
|
||||
- Change CW Key Select type, (toggle -> select by dial)
|
||||
|
||||
0.32
|
||||
- Added function Scroll Frequencty on upper line
|
||||
- Added Example code for Draw meter and remarked (you can see and use this code in source codes)
|
||||
- Added Split function, just toggle VFOs when TX/RX
|
||||
|
||||
0.31
|
||||
- Fixed CW ADC Range error
|
||||
- Display Message on Upper Line (anothor VFO Frequency, Tune Step, Selected Key Type)
|
||||
|
||||
0.30
|
||||
- implemented the function to monitor the value of all analog inputs. This allows you to monitor the status of the CW keys connected to your uBITX.
|
||||
- possible to set the ADC range for CW Keying. If no setting is made, it will have the same range as the original code. If you set the CW Keying ADC Values using uBITX Manager 0.3, you can reduce the key error.
|
||||
- Added the function to select Straight Key, IAMBICA, IAMBICB key from the menu.
|
||||
- default Band select is Ham Band mode, if you want common type, long press function key at band select menu, uBITX Manager can be used to modify frequencies to suit your country.
|
||||
|
||||
0.29
|
||||
- Remove the use of initialization values in BFO settings - using crruent value, if factory reset
|
||||
- Select Tune Step, default 0, 20, 50, 100, 200, Use the uBITX Manager to set the steps value you want. You can select Step by pressing and holding the Function Key (1sec ~ 2sec).
|
||||
- Modify Dial Lock Function, Press the Function key for more than 3 seconds to toggle dial lock.
|
||||
- created a new frequency tune method. remove original source codes, Threshold has been applied to reduce malfunction. checked the continuity of the user operating to make natural tune possible.
|
||||
- stabilize and remove many warning messages - by Pullrequest and merge
|
||||
- Changed cw keying method. removed the original code and applied Ron's code and Improved compatibility with original hardware and CAT commnication. It can be used without modification of hardware.
|
||||
|
||||
0.28
|
||||
- Fixed CAT problem with hamlib on Linux
|
||||
- restore Protocol autorecovery logic
|
||||
|
||||
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/>.
|
||||
>>>>>>> raduino/master
|
30
raduino-tmp/VersionInfo.txt
Normal file
30
raduino-tmp/VersionInfo.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
This file will guide you to change the source code file.
|
||||
For Windows-based Arduino IDE users, the directory name and the Main source file name must be the same.
|
||||
You do not need to learn github to download .hex files or source code that I release.
|
||||
However, if you want to see what I'm doing right now, you should use the github homepage.
|
||||
|
||||
You do not need to learn git to suggest source code. If you give me an e-mail, I will correct it at any time.
|
||||
If you have not joined the BITX Group, join group. There will be discussions on various topics every day.
|
||||
I am getting a lot of hints from the group.
|
||||
|
||||
Ian KD8CEC
|
||||
kd8cec@gmail.com
|
||||
==================================================================
|
||||
Files modified in Version1.08 Beta
|
||||
|
||||
1.Delted Files.
|
||||
|
||||
2.Added Files
|
||||
|
||||
3.Modified Files
|
||||
- ubitx_20.ino
|
||||
- ubitx_ui.ino
|
||||
- cat_libs.ino
|
||||
- ubitx.h
|
||||
- ubitx_eemap.h
|
||||
- ubitx_lcd_1602.ino
|
||||
- ubitx_lcd_1602Dual.ino
|
||||
- ubitx_lcd_2004.ino
|
||||
- ubitx_wspr.ino
|
||||
|
||||
|
@@ -31,8 +31,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
**************************************************************************/
|
||||
#define printLineF1(x) (printLineF(1, x))
|
||||
#define printLineF2(x) (printLineF(0, x))
|
||||
|
||||
#include "ubitx.h"
|
||||
|
||||
//for broken protocol
|
||||
#define CAT_RECEIVE_TIMEOUT 500
|
||||
@@ -252,12 +252,35 @@ void ReadEEPRom() //for remove warnings.
|
||||
|
||||
Serial.write(0x02); //STX
|
||||
checkSum = 0x02;
|
||||
for (uint16_t i = 0; i < eepromReadLength; i++)
|
||||
//I2C Scanner
|
||||
//Magic Key Start 59414, Length : 48583
|
||||
//if (eepromStartIndex == 59414 && eepromReadLength == 48583)
|
||||
if (CAT_BUFF[0] == 0x16 && CAT_BUFF[1] == 0xe8)
|
||||
{
|
||||
read1Byte = EEPROM.read(eepromStartIndex + i);
|
||||
checkSum += read1Byte;
|
||||
Serial.write(read1Byte);
|
||||
for (uint8_t i = 1; i < 127; i++)
|
||||
{
|
||||
Wire.beginTransmission(i);
|
||||
read1Byte = Wire.endTransmission();
|
||||
if (read1Byte == 0)
|
||||
{
|
||||
Serial.write(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint16_t i = 0; i < eepromReadLength; i++)
|
||||
{
|
||||
read1Byte = EEPROM.read(eepromStartIndex + i);
|
||||
checkSum += read1Byte;
|
||||
Serial.write(read1Byte);
|
||||
}
|
||||
}
|
||||
|
||||
Serial.write(checkSum);
|
||||
Serial.write(ACK);
|
||||
}
|
||||
@@ -278,7 +301,19 @@ void WriteEEPRom(void) //for remove warning
|
||||
}
|
||||
else
|
||||
{
|
||||
EEPROM.write(eepromStartIndex, write1Byte);
|
||||
//Special Command
|
||||
if (eepromStartIndex == 13131) //Magic Key
|
||||
{
|
||||
if (write1Byte == 0x51) //Restart
|
||||
{
|
||||
asm volatile (" jmp 0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EEPROM.write(eepromStartIndex, write1Byte);
|
||||
}
|
||||
|
||||
Serial.write(0x77); //OK
|
||||
Serial.write(ACK);
|
||||
}
|
||||
@@ -611,10 +646,38 @@ void WriteEEPRom_FT817(byte fromType)
|
||||
Serial.write(ACK);
|
||||
}
|
||||
|
||||
const byte anlogPinIndex[6] = {A0, A1, A2, A3, A6, A7};
|
||||
|
||||
//Read ADC Value by uBITX Manager Software
|
||||
void ReadADCValue(void)
|
||||
{
|
||||
//ADC MAP for uBITX
|
||||
int readedADCValue;
|
||||
//5BYTES
|
||||
//CAT_BUFF[0] [1] [2] [3] [4] //4 COMMAND
|
||||
//0 READ ADDRESS
|
||||
readedADCValue = analogRead(anlogPinIndex[CAT_BUFF[0]]);
|
||||
CAT_BUFF[0] = readedADCValue >> 8;
|
||||
CAT_BUFF[1] = readedADCValue;
|
||||
SendCatData(2);
|
||||
Serial.write(ACK);
|
||||
}
|
||||
|
||||
void SetIFSValue(void)
|
||||
{
|
||||
//Set IFShift Value
|
||||
isIFShift = CAT_BUFF[0];
|
||||
ifShiftValue = CAT_BUFF[1] + CAT_BUFF[2] * 256;
|
||||
setFrequency(frequency);
|
||||
SetCarrierFreq();
|
||||
updateLine2Buffer(1); //option, perhap not need
|
||||
Serial.write(ACK);
|
||||
}
|
||||
|
||||
//void CatRxStatus(byte fromType)
|
||||
void CatRxStatus(void) //for remove warning
|
||||
{
|
||||
byte sMeterValue = 1;
|
||||
byte sMeterValue = 0;
|
||||
|
||||
/*
|
||||
http://www.ka7oei.com/ft817_meow.html
|
||||
@@ -627,6 +690,33 @@ void CatRxStatus(void) //for remove warning
|
||||
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.
|
||||
//0~8
|
||||
switch (scaledSMeter)
|
||||
{
|
||||
case 8 : sMeterValue = 0x0B;
|
||||
break;
|
||||
case 7 : sMeterValue = 0x0A;
|
||||
break;
|
||||
case 6 : sMeterValue = 0x09;
|
||||
break;
|
||||
case 5 : sMeterValue = 0x07;
|
||||
break;
|
||||
case 4 : sMeterValue = 0x05;
|
||||
break;
|
||||
case 3 : sMeterValue = 0x04;
|
||||
break;
|
||||
case 2 : sMeterValue = 0x02;
|
||||
break;
|
||||
case 1 : sMeterValue = 0x01;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
sMeterValue = (scaledSMeter * 2) -1;
|
||||
if (sMeterValue > 0)
|
||||
sMeterValue--;
|
||||
*/
|
||||
|
||||
CAT_BUFF[0] = sMeterValue & 0b00001111;
|
||||
SendCatData(1);
|
||||
}
|
||||
@@ -768,6 +858,14 @@ void Check_Cat(byte fromType)
|
||||
WriteEEPRom_FT817(fromType);
|
||||
break;
|
||||
|
||||
case 0xDD: //Read uBITX ADC Data
|
||||
ReadADCValue(); //Call by uBITX Manager Program
|
||||
break;
|
||||
|
||||
case 0xDE: //IF-Shift Control by CAT
|
||||
SetIFSValue(); //
|
||||
break;
|
||||
|
||||
case 0xE7 : //Read RX Status
|
||||
CatRxStatus();
|
||||
break;
|
@@ -235,30 +235,6 @@ void sendCWChar(char cwKeyChar)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
@@ -296,17 +272,19 @@ void controlAutoCW(){
|
||||
{
|
||||
displayScrolStep = 0;
|
||||
}
|
||||
|
||||
printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0);
|
||||
|
||||
byte diplayAutoCWLine = 0;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayAutoCWLine = 1;
|
||||
|
||||
lcd.setCursor(0, diplayAutoCWLine);
|
||||
lcd.write(byteToChar(selectedCWTextIndex));
|
||||
lcd.write(':');
|
||||
#ifdef USE_SW_SERIAL
|
||||
//Not need Scroll
|
||||
//Display_AutoKeyTextIndex(selectedCWTextIndex);
|
||||
SendCommand1Num('w', selectedCWTextIndex); //Index
|
||||
SendEEPromData('a', cwStartIndex + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0) ; //Data
|
||||
SendCommand1Num('y', 1); //Send YN
|
||||
isNeedScroll = 0;
|
||||
#else
|
||||
printLineFromEEPRom(0, 2, cwStartIndex + displayScrolStep + CW_DATA_OFSTADJ, cwEndIndex + CW_DATA_OFSTADJ, 0);
|
||||
isNeedScroll = (cwEndIndex - cwStartIndex) > 14 ? 1 : 0;
|
||||
Display_AutoKeyTextIndex(selectedCWTextIndex);
|
||||
#endif
|
||||
scrollDispayTime = millis() + scrollSpeed;
|
||||
beforeCWTextIndex = selectedCWTextIndex;
|
||||
}
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
674
teensydsp-tmp/LICENSE
Normal file
674
teensydsp-tmp/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
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.
|
||||
|
||||
<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
|
||||
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/>.
|
||||
|
||||
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:
|
||||
|
||||
<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.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
14
teensydsp-tmp/README.md
Normal file
14
teensydsp-tmp/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# dspmeterv1
|
||||
|
||||
Please also refer to the site below.
|
||||
https://github.com/soligen2010/dspmeterv1
|
||||
|
||||
-------------------------------------------
|
||||
|
||||
Standalone Signal Analyzer (I2C Type Signal-Meter) for uBITX - Arduino Nano Version
|
||||
|
||||
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.
|
||||
|
||||
Ian KD8CEC
|
@@ -1,80 +0,0 @@
|
||||
/*************************************************************************
|
||||
header file for C++ by KD8CEC
|
||||
-----------------------------------------------------------------------------
|
||||
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 WSPR_COUNT 443 //WSPR_MESSAGE_COUNT
|
||||
#define WSPR_MESSAGE1 444 //
|
||||
#define WSPR_MESSAGE2 490 //
|
||||
#define WSPR_MESSAGE3 536 //
|
||||
#define WSPR_MESSAGE4 582 //
|
||||
|
||||
#define WSPR_BAND_COUNT 3
|
||||
|
||||
#define TX_SSB 0
|
||||
#define TX_CW 1
|
||||
|
||||
|
||||
extern void printLine1(const char *c);
|
||||
extern void printLine2(const char *c);
|
||||
extern void printLineF(char linenmbr, const __FlashStringHelper *c);
|
||||
extern void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetType);
|
||||
extern byte delay_background(unsigned delayTime, byte fromType);
|
||||
extern int btnDown(void);
|
||||
extern char c[30];
|
||||
extern char b[30];
|
||||
|
||||
extern unsigned long frequency;
|
||||
|
||||
#define printLineF1(x) (printLineF(1, x))
|
||||
#define printLineF2(x) (printLineF(0, x))
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
//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
|
||||
|
||||
extern void si5351bx_init(void);
|
||||
extern void si5351bx_setfreq(uint8_t clknum, uint32_t fout);
|
||||
extern void si5351_set_calibration(int32_t cal);
|
||||
extern void initOscillators(void);
|
||||
extern void Set_WSPR_Param(void);
|
||||
extern void TXSubFreq(unsigned long P2);
|
||||
|
||||
extern void startTx(byte txMode, byte isDisplayUpdate);
|
||||
extern void stopTx(void);
|
||||
extern void setTXFilters(unsigned long freq);
|
||||
|
||||
extern void SendWSPRManage(void);
|
||||
extern byte WsprMSGCount;
|
||||
|
||||
|
@@ -1,254 +0,0 @@
|
||||
/*************************************************************************
|
||||
KD8CEC's uBITX Idle time Processing
|
||||
Functions that run at times that do not affect TX, CW, and CAT
|
||||
It is called in 1/10 time unit.
|
||||
-----------------------------------------------------------------------------
|
||||
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/>.
|
||||
|
||||
**************************************************************************/
|
||||
char line2Buffer[16];
|
||||
//KD8CEC 200Hz ST
|
||||
//L14.150 200Hz ST
|
||||
//U14.150 +150khz
|
||||
int freqScrollPosition = 0;
|
||||
//Example Line2 Optinal Display
|
||||
//immediate execution, not call by scheulder
|
||||
void updateLine2Buffer(char isDirectCall)
|
||||
{
|
||||
unsigned long tmpFreq = 0;
|
||||
if (isDirectCall == 0)
|
||||
{
|
||||
if (ritOn)
|
||||
{
|
||||
strcpy(line2Buffer, "RitTX:");
|
||||
|
||||
//display frequency
|
||||
tmpFreq = ritTxFrequency;
|
||||
for (int i = 15; i >= 6; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 12 || i == 8) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
return;
|
||||
} //end of ritOn display
|
||||
|
||||
//======================================================
|
||||
//other VFO display
|
||||
//======================================================
|
||||
if (vfoActive == VFO_B)
|
||||
{
|
||||
tmpFreq = vfoA;
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpFreq = vfoB;
|
||||
}
|
||||
|
||||
// EXAMPLE 1 & 2
|
||||
//U14.150.100
|
||||
//display frequency
|
||||
for (int i = 9; i >= 0; i--) {
|
||||
if (tmpFreq > 0) {
|
||||
if (i == 2 || i == 6) line2Buffer[i] = '.';
|
||||
else {
|
||||
line2Buffer[i] = tmpFreq % 10 + 0x30;
|
||||
tmpFreq /= 10;
|
||||
}
|
||||
}
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
|
||||
//EXAMPLE #1
|
||||
if ((displayOption1 & 0x04) == 0x00) //none scroll display
|
||||
line2Buffer[6] = 'k';
|
||||
else
|
||||
{
|
||||
//example #2
|
||||
if (freqScrollPosition++ > 18) //none scroll display time
|
||||
{
|
||||
line2Buffer[6] = 'k';
|
||||
if (freqScrollPosition > 25)
|
||||
freqScrollPosition = -1;
|
||||
}
|
||||
else //scroll frequency
|
||||
{
|
||||
line2Buffer[10] = 'H';
|
||||
line2Buffer[11] = 'z';
|
||||
|
||||
if (freqScrollPosition < 7)
|
||||
{
|
||||
for (int i = 11; i >= 0; i--)
|
||||
if (i - (7 - freqScrollPosition) >= 0)
|
||||
line2Buffer[i] = line2Buffer[i - (7 - freqScrollPosition)];
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 11; i++)
|
||||
if (i + (freqScrollPosition - 7) <= 11)
|
||||
line2Buffer[i] = line2Buffer[i + (freqScrollPosition - 7)];
|
||||
else
|
||||
line2Buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
} //scroll
|
||||
|
||||
line2Buffer[7] = ' ';
|
||||
} //check direct call by encoder
|
||||
|
||||
if (isIFShift)
|
||||
{
|
||||
if (isDirectCall == 1)
|
||||
for (int i = 0; i < 16; i++)
|
||||
line2Buffer[i] = ' ';
|
||||
|
||||
//IFShift Offset Value
|
||||
line2Buffer[8] = 'I';
|
||||
line2Buffer[9] = 'F';
|
||||
|
||||
//if (ifShiftValue == 0)
|
||||
//{
|
||||
/*
|
||||
line2Buffer[10] = 'S';
|
||||
line2Buffer[11] = ':';
|
||||
line2Buffer[12] = 'O';
|
||||
line2Buffer[13] = 'F';
|
||||
line2Buffer[14] = 'F';
|
||||
*/
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
|
||||
line2Buffer[11] = 0;
|
||||
line2Buffer[12] = ' ';
|
||||
|
||||
//11, 12, 13, 14, 15
|
||||
memset(b, 0, sizeof(b));
|
||||
ltoa(ifShiftValue, b, DEC);
|
||||
strncat(line2Buffer, b, 5);
|
||||
//}
|
||||
|
||||
if (isDirectCall == 1) //if call by encoder (not scheduler), immediate print value
|
||||
printLine2(line2Buffer);
|
||||
} // end of display IF
|
||||
else // step display
|
||||
{
|
||||
if (isDirectCall != 0)
|
||||
return;
|
||||
|
||||
memset(&line2Buffer[8], ' ', 8);
|
||||
//Step
|
||||
long tmpStep = arTuneStep[tuneStepIndex -1];
|
||||
|
||||
byte isStepKhz = 0;
|
||||
if (tmpStep >= 1000)
|
||||
{
|
||||
isStepKhz = 2;
|
||||
}
|
||||
|
||||
for (int i = 10; i >= 8 - isStepKhz; i--) {
|
||||
if (tmpStep > 0) {
|
||||
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
|
||||
tmpStep /= 10;
|
||||
}
|
||||
else
|
||||
line2Buffer[i +isStepKhz] = ' ';
|
||||
}
|
||||
//if (isStepKhz == 1)
|
||||
// line2Buffer[10] = 'k';
|
||||
|
||||
if (isStepKhz == 0)
|
||||
{
|
||||
line2Buffer[11] = 'H';
|
||||
line2Buffer[12] = 'z';
|
||||
}
|
||||
|
||||
line2Buffer[13] = ' ';
|
||||
//if (
|
||||
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
|
||||
if (cwKeyType == 0)
|
||||
{
|
||||
line2Buffer[14] = 'S';
|
||||
line2Buffer[15] = 'T';
|
||||
}
|
||||
else if (cwKeyType == 1)
|
||||
{
|
||||
line2Buffer[14] = 'I';
|
||||
line2Buffer[15] = 'A';
|
||||
}
|
||||
else
|
||||
{
|
||||
line2Buffer[14] = 'I';
|
||||
line2Buffer[15] = 'B';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//meterType : 0 = S.Meter, 1 : P.Meter
|
||||
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
|
||||
{
|
||||
if (meterType == 0 || meterType == 1 || meterType == 2)
|
||||
{
|
||||
drawMeter(meterValue); //call original source code
|
||||
int lineNumber = 0;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
lineNumber = 1;
|
||||
|
||||
lcd.setCursor(drawPosition, lineNumber);
|
||||
|
||||
for (int i = 0; i < 6; i++) //meter 5 + +db 1 = 6
|
||||
lcd.write(lcdMeter[i]);
|
||||
}
|
||||
}
|
||||
|
||||
byte testValue = 0;
|
||||
char checkCount = 0;
|
||||
void idle_process()
|
||||
{
|
||||
//space for user graphic display
|
||||
if (menuOn == 0)
|
||||
{
|
||||
if ((displayOption1 & 0x10) == 0x10) //always empty topline
|
||||
return;
|
||||
|
||||
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
|
||||
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
|
||||
if (checkCount++ > 1)
|
||||
{
|
||||
updateLine2Buffer(0); //call by scheduler
|
||||
printLine2(line2Buffer);
|
||||
line2DisplayStatus = 2;
|
||||
checkCount = 0;
|
||||
}
|
||||
|
||||
//EX for Meters
|
||||
/*
|
||||
DisplayMeter(0, testValue++, 7);
|
||||
if (testValue > 30)
|
||||
testValue = 0;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,392 +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(void){
|
||||
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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
};
|
||||
*/
|
||||
|
||||
const PROGMEM uint8_t meters_bitmap[] = {
|
||||
B10000, B10000, B10000, B10000, B10000, B10000, B10000, B10000 , //custom 1
|
||||
B11000, B11000, B11000, B11000, B11000, B11000, B11000, B11000 , //custom 2
|
||||
B11100, B11100, B11100, B11100, B11100, B11100, B11100, B11100 , //custom 3
|
||||
B11110, B11110, B11110, B11110, B11110, B11110, B11110, B11110 , //custom 4
|
||||
B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 , //custom 5
|
||||
B01000, B11100, B01000, B00000, B10111, B10101, B10101, B10111 //custom 6
|
||||
};
|
||||
|
||||
PGM_P p_metes_bitmap = reinterpret_cast<PGM_P>(meters_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(p_metes_bitmap + i);
|
||||
lcd.createChar(1, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 8);
|
||||
lcd.createChar(2, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 16);
|
||||
lcd.createChar(3, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 24);
|
||||
lcd.createChar(4, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 32);
|
||||
lcd.createChar(5, tmpbytes);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
tmpbytes[i] = pgm_read_byte(p_metes_bitmap + i + 40);
|
||||
lcd.createChar(6, tmpbytes);
|
||||
}
|
||||
|
||||
//by KD8CEC
|
||||
//0 ~ 25 : 30 over : + 10
|
||||
void drawMeter(int needle) {
|
||||
//5Char + O over
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (needle >= 5)
|
||||
lcdMeter[i] = 5; //full
|
||||
else if (needle > 0)
|
||||
lcdMeter[i] = needle; //full
|
||||
else //0
|
||||
lcdMeter[i] = 0x20;
|
||||
|
||||
needle -= 5;
|
||||
}
|
||||
|
||||
if (needle > 0)
|
||||
lcdMeter[5] = 6;
|
||||
else
|
||||
lcdMeter[5] = 0x20;
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
lcdMeter[i] = 1;
|
||||
else if (s >= 0)
|
||||
lcdMeter[i] = 2 + s;
|
||||
else
|
||||
lcdMeter[i] = 1;
|
||||
s = s - 5;
|
||||
}
|
||||
if (needle >= 40)
|
||||
lcdMeter[i-1] = 6;
|
||||
lcdMeter[i] = 0;
|
||||
}
|
||||
*/
|
||||
// The generic routine to display one line on the LCD
|
||||
void printLine(unsigned char linenmbr, const char *c) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
|
||||
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, char offsetTtype) {
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
|
||||
|
||||
lcd.setCursor(lcdColumn, linenmbr);
|
||||
|
||||
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
|
||||
{
|
||||
if (++lcdColumn <= LCD_MAX_COLUMN)
|
||||
lcd.write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + 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(const char *c){
|
||||
printLine(1,c);
|
||||
}
|
||||
// short cut to print to the first line
|
||||
void printLine2(const char *c){
|
||||
printLine(0,c);
|
||||
}
|
||||
|
||||
void clearLine2()
|
||||
{
|
||||
printLine2("");
|
||||
line2DisplayStatus = 0;
|
||||
}
|
||||
|
||||
// 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, "");
|
||||
line2DisplayStatus = 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 (cwMode == 0)
|
||||
{
|
||||
if (isUSB)
|
||||
strcpy(c, "USB ");
|
||||
else
|
||||
strcpy(c, "LSB ");
|
||||
}
|
||||
else if (cwMode == 1)
|
||||
{
|
||||
strcpy(c, "CWL ");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(c, "CWU ");
|
||||
}
|
||||
}
|
||||
if (vfoActive == VFO_A) // VFO A is active
|
||||
strcat(c, "A:");
|
||||
else
|
||||
strcat(c, "B:");
|
||||
}
|
||||
|
||||
//Fixed by Mitani Massaru (JE4SMQ)
|
||||
if (isShiftDisplayCWFreq == 1)
|
||||
{
|
||||
if (cwMode == 1) //CWL
|
||||
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
|
||||
else if (cwMode == 2) //CWU
|
||||
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
byte diplayVFOLine = 1;
|
||||
if ((displayOption1 & 0x01) == 0x01)
|
||||
diplayVFOLine = 0;
|
||||
|
||||
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
|
||||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
|
||||
lcd.setCursor(5,diplayVFOLine);
|
||||
lcd.write((uint8_t)0);
|
||||
}
|
||||
else if (isCWAutoMode == 2){
|
||||
lcd.setCursor(5,diplayVFOLine);
|
||||
lcd.write(0x7E);
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd.setCursor(5,diplayVFOLine);
|
||||
lcd.write(":");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
unsigned long start_at = millis();
|
||||
|
||||
while (millis() - start_at < 50) { // 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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user