mirror of
https://codeberg.org/mclemens/ubitxv6.git
synced 2024-06-13 05:30:43 +00:00
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6dceffd993 | ||
|
36cd505e8e | ||
|
6d4fc996d9 | ||
|
6c9e759901 | ||
|
4918670eaa | ||
|
4eecda170d | ||
|
50381da6de | ||
|
b136f5e43c | ||
|
a4f5f4b3cb | ||
|
ab678f3e8b | ||
|
c62eaaba2e | ||
|
c11c8bfbe3 | ||
|
84f47b0a23 | ||
|
740e881d28 | ||
|
71e5f877da | ||
|
e6fa6f935b | ||
|
b3a7e34d1b | ||
|
d282062eef | ||
|
f76b50fcc3 | ||
|
488e462c6c | ||
|
c323cec0cb | ||
|
f541ff8928 | ||
|
e7748d2878 | ||
|
e168a4d5b0 | ||
|
e3f23ae755 | ||
|
0b65559e97 | ||
|
2a412fd34a | ||
|
a138490dcc | ||
|
4cf8f7a840 | ||
|
6a6dc2a29a | ||
|
a7cbf50384 | ||
|
e809b37e29 | ||
|
e770230d14 |
52
README.md
52
README.md
|
@ -7,10 +7,62 @@ It was forked from https://github.com/afarhan/ubitxv6/
|
|||
The purpose of this project is to clean up (modularize) the source code, and add features that were not present
|
||||
in Ashhar's original version of the project, without requiring any hardware modifications to a stock uBiTXv6.
|
||||
|
||||
New features include:
|
||||
|
||||
* Much faster screen refresh (vs Ashhar's 6.3.1 aka 6.0 release)
|
||||
* Morse code readback for sightless operation
|
||||
* Save/recall your favorite frequencies
|
||||
* When adjusting settings, the existing/current setting is shown as reference
|
||||
* Cancel touch recalibration
|
||||
|
||||
User Manual: https://docs.google.com/document/d/1jlllZbvFMCzO1MJLzlJDGb10HXSehlFNMDPsxGJZtvY/edit?usp=drivesdk
|
||||
|
||||
# Installing on Your Radio
|
||||
|
||||
There are plenty of tutorials on how to upload sketches to Arduino Nanos. Just search for them. Addtionally,
|
||||
Ashhar created a video explaining the process specifically for uBiTX v6: https://www.youtube.com/watch?v=3n_V3prSJ_E
|
||||
|
||||
I developed this code using the Arduino IDE 1.8.9 toolchain, with -Wall and -Wextra compiler options turned on.
|
||||
Arduino IDE 1.8.13 was reported to compile too big (see https://groups.io/g/BITX20/topic/75008576), but this
|
||||
should be resolved in this project's tag R1.5.1.
|
||||
|
||||
# Personalized Callsign
|
||||
|
||||
To edit the callsign displayed, open the file `callsign.cpp` and change the string. Then re-compile and upload.
|
||||
|
||||
# Future Features/Modifications
|
||||
|
||||
There are some features that would be good to add, but I just didn't get around to.
|
||||
|
||||
* Setting to choose the tuning step size
|
||||
* Setting to choose whether or not the knob tuning should accelerate (current behavior) or have a fixed interval
|
||||
* Provide an option in each menu screen to load the default option for each setting
|
||||
|
||||
While the current code (as of 2020-05-05) is ~100 bytes shy of the full 30720 available on the nano, there's still
|
||||
opportunity to add new features by "creating" room. Below is a list of places you might create room:
|
||||
|
||||
I added lots of bounds checking, especially on string writes, that, if removed, could free a good number of bytes.
|
||||
While keeping them is best practice, for a non-IoT, non-critical piece of hardware, it shouldn't be a huge issue.
|
||||
|
||||
I added the RACK to the CAT to better emulate the FT-817 (I hope, at least!). Removing the RACK's and just leaving
|
||||
the default ACK's will also free up bytes.
|
||||
|
||||
I added a bunch of strings to the menuing with the intention of helping people understand their functions, but
|
||||
technically they're not necessary, and could all be removed.
|
||||
|
||||
I switched to a smaller footprint font than Ashhar's original code, but there are MUCH smaller fonts out there.
|
||||
Changing to a lower resolution, scaled up font can save hundreds or thousands of bytes, but won't look as pretty.
|
||||
Also, the star, gear, and numpad icons will need to be either added to the new font, or replaced with characters.
|
||||
|
||||
The first change I made to this fork was to replace Ashhar's original (incredibly slow) screen drawing routines
|
||||
with PDQ. Since that change, Ashhar has updated his drawing routine to be MUCH faster than his original, but
|
||||
still slightly slower than PDQ. It may be that Ashhar's new routines are smaller that PDQ, but I don't actually
|
||||
know that for certain.
|
||||
|
||||
There are a good number of instances of back-to-back calls of strncpy_P and displayText. Creating a single
|
||||
function that performs these operations together, and then calling that new function instead of the
|
||||
back-to-back calls everywhere may save space.
|
||||
|
||||
# License
|
||||
|
||||
The majority of this code is released under GPL v3 license, per Ashhar's original code.
|
||||
|
|
17
bands.cpp
17
bands.cpp
|
@ -16,19 +16,19 @@ struct Band_t {
|
|||
const char UNKNOWN_BAND_NAME [] PROGMEM = "??";
|
||||
|
||||
constexpr Band_t bands [] PROGMEM {
|
||||
{ 0UL, 255UL, 255, "U8"},//Utility conversion option
|
||||
{ 0UL, 65535UL, 254, "UF"},//Utility conversion option
|
||||
{ 530000UL, 1700000UL, 253, "AM"},//Broadcast AM, actually centers at 268, but uint8 can't do that
|
||||
{ 1800000UL, 2000000UL, 160, "A0"},//0xA0 is 160
|
||||
{ 3500000UL, 4000000UL, 80, "80"},
|
||||
{ 5330500UL, 5403500UL, 60, "60"},
|
||||
{ 7000000UL, 7300000UL, 40, "40"},
|
||||
// { 0UL, 255UL, 255, "U8"},//Utility conversion option
|
||||
// { 0UL, 65535UL, 254, "UF"},//Utility conversion option
|
||||
// { 530000UL, 1700000UL, 253, "AM"},//Broadcast AM, actually centers at 268, but uint8 can't do that
|
||||
// { 1800000UL, 2000000UL, 160, "A0"},//0xA0 is 160
|
||||
{ 3500000UL, 3800000UL, 80, "80"},
|
||||
// { 5330500UL, 5403500UL, 60, "60"},
|
||||
{ 7000000UL, 7200000UL, 40, "40"},
|
||||
{10100000UL, 10150000UL, 30, "30"},
|
||||
{14000000UL, 14350000UL, 20, "20"},
|
||||
{18068000UL, 18168000UL, 17, "17"},
|
||||
{21000000UL, 21450000UL, 15, "15"},
|
||||
{24890000UL, 24990000UL, 12, "12"},
|
||||
{26965000UL, 27405000UL, 11, "CB"},//Citizen's Band
|
||||
// {26965000UL, 27405000UL, 11, "CB"},//Citizen's Band
|
||||
{28000000UL, 29700000UL, 10, "10"},
|
||||
};
|
||||
constexpr uint8_t NUM_BANDS = sizeof(bands)/sizeof(bands[0]);
|
||||
|
@ -127,4 +127,3 @@ bool isFreqInBand(const uint32_t frequency,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "callsign.h"
|
||||
|
||||
const char CALLSIGN_STRING_PRIVATE [] PROGMEM = "CALLSIGN";
|
||||
const char* const CALLSIGN_STRING = CALLSIGN_STRING_PRIVATE;
|
||||
const char CALLSIGN_STRING_PRIVATE [] PROGMEM = "DL6MHC";
|
||||
const char* const CALLSIGN_STRING = CALLSIGN_STRING_PRIVATE;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "colors.h"
|
||||
|
||||
static const unsigned int COLOR_TEXT = DISPLAY_WHITE;
|
||||
static const unsigned int COLOR_BACKGROUND = DISPLAY_NAVY;
|
||||
static const unsigned int COLOR_BACKGROUND = DISPLAY_BLACK;
|
||||
|
||||
static const unsigned int COLOR_ACTIVE_VFO_TEXT = DISPLAY_WHITE;
|
||||
static const unsigned int COLOR_ACTIVE_VFO_BACKGROUND = DISPLAY_BLACK;
|
||||
|
@ -16,7 +16,7 @@ static const unsigned int COLOR_INACTIVE_BACKGROUND = DISPLAY_BLACK;
|
|||
static const unsigned int COLOR_INACTIVE_BORDER = DISPLAY_DARKGREY;
|
||||
|
||||
static const unsigned int COLOR_ACTIVE_TEXT = DISPLAY_BLACK;
|
||||
static const unsigned int COLOR_ACTIVE_BACKGROUND = DISPLAY_ORANGE;
|
||||
static const unsigned int COLOR_ACTIVE_BACKGROUND = DISPLAY_GREEN;
|
||||
static const unsigned int COLOR_ACTIVE_BORDER = DISPLAY_WHITE;
|
||||
|
||||
static const unsigned int COLOR_VERSION_TEXT = DISPLAY_LIGHTGREY;
|
||||
static const unsigned int COLOR_VERSION_TEXT = DISPLAY_GREEN;
|
||||
|
|
38
colors.h
38
colors.h
|
@ -1,20 +1,20 @@
|
|||
// Color definitions
|
||||
#define DISPLAY_BLACK 0x0000 ///< 0, 0, 0
|
||||
#define DISPLAY_NAVY 0x000F ///< 0, 0, 123
|
||||
#define DISPLAY_DARKGREEN 0x03E0 ///< 0, 125, 0
|
||||
#define DISPLAY_DARKCYAN 0x03EF ///< 0, 125, 123
|
||||
#define DISPLAY_MAROON 0x7800 ///< 123, 0, 0
|
||||
#define DISPLAY_PURPLE 0x780F ///< 123, 0, 123
|
||||
#define DISPLAY_OLIVE 0x7BE0 ///< 123, 125, 0
|
||||
#define DISPLAY_LIGHTGREY 0xC618 ///< 198, 195, 198
|
||||
#define DISPLAY_DARKGREY 0x7BEF ///< 123, 125, 123
|
||||
#define DISPLAY_BLUE 0x001F ///< 0, 0, 255
|
||||
#define DISPLAY_GREEN 0x07E0 ///< 0, 255, 0
|
||||
#define DISPLAY_CYAN 0x07FF ///< 0, 255, 255
|
||||
#define DISPLAY_RED 0xF800 ///< 255, 0, 0
|
||||
#define DISPLAY_MAGENTA 0xF81F ///< 255, 0, 255
|
||||
#define DISPLAY_YELLOW 0xFFE0 ///< 255, 255, 0
|
||||
#define DISPLAY_WHITE 0xFFFF ///< 255, 255, 255
|
||||
#define DISPLAY_ORANGE 0xFD20 ///< 255, 165, 0
|
||||
#define DISPLAY_GREENYELLOW 0xAFE5 ///< 173, 255, 41
|
||||
#define DISPLAY_PINK 0xFC18 ///< 255, 130, 198
|
||||
static const uint16_t DISPLAY_BLACK = 0x0000; ///< 0, 0, 0
|
||||
static const uint16_t DISPLAY_NAVY = 0x000F; ///< 0, 0, 123
|
||||
static const uint16_t DISPLAY_DARKGREEN = 0x03E0; ///< 0, 125, 0
|
||||
static const uint16_t DISPLAY_DARKCYAN = 0x03EF; ///< 0, 125, 123
|
||||
static const uint16_t DISPLAY_MAROON = 0x7800; ///< 123, 0, 0
|
||||
static const uint16_t DISPLAY_PURPLE = 0x780F; ///< 123, 0, 123
|
||||
static const uint16_t DISPLAY_OLIVE = 0x7BE0; ///< 123, 125, 0
|
||||
static const uint16_t DISPLAY_LIGHTGREY = 0xC618; ///< 198, 195, 198
|
||||
static const uint16_t DISPLAY_DARKGREY = 0x7BEF; ///< 123, 125, 123
|
||||
static const uint16_t DISPLAY_BLUE = 0x001F; ///< 0, 0, 255
|
||||
static const uint16_t DISPLAY_GREEN = 0x07E0; ///< 0, 255, 0
|
||||
static const uint16_t DISPLAY_CYAN = 0x07FF; ///< 0, 255, 255
|
||||
static const uint16_t DISPLAY_RED = 0xF800; ///< 255, 0, 0
|
||||
static const uint16_t DISPLAY_MAGENTA = 0xF81F; ///< 255, 0, 255
|
||||
static const uint16_t DISPLAY_YELLOW = 0xFFE0; ///< 255, 255, 0
|
||||
static const uint16_t DISPLAY_WHITE = 0xFFFF; ///< 255, 255, 255
|
||||
static const uint16_t DISPLAY_ORANGE = 0xFD20; ///< 255, 165, 0
|
||||
static const uint16_t DISPLAY_GREENYELLOW = 0xAFE5; ///< 173, 255, 41
|
||||
static const uint16_t DISPLAY_PINK = 0xFC18; ///< 255, 130, 198
|
||||
|
|
|
@ -16,7 +16,7 @@ static const uint8_t MOMENTUM_MULTIPLIER = 1;
|
|||
|
||||
uint8_t enc_state (void)
|
||||
{
|
||||
return (digitalRead(PIN_ENC_A)?1:0 + digitalRead(PIN_ENC_B)?2:0);
|
||||
return (digitalRead(PIN_ENC_B) << 1) + (digitalRead(PIN_ENC_A) << 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
72
keyer.cpp
72
keyer.cpp
|
@ -77,13 +77,8 @@ uint8_t keyerControl = 0;
|
|||
//create by KD8CEC for compatible with new CW Logic
|
||||
char update_PaddleLatch(bool isUpdateKeyState) {
|
||||
unsigned char tmpKeyerControl = 0;
|
||||
|
||||
unsigned int paddle = analogRead(PIN_ANALOG_KEYER);
|
||||
|
||||
//use the PTT as the key for tune up, quick QSOs
|
||||
if (digitalRead(PIN_PTT) == 0)
|
||||
tmpKeyerControl |= DIT_L;
|
||||
else if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
|
||||
if (paddle >= cwAdcDashFrom && paddle <= cwAdcDashTo)
|
||||
tmpKeyerControl |= DAH_L;
|
||||
else if (paddle >= cwAdcDotFrom && paddle <= cwAdcDotTo)
|
||||
tmpKeyerControl |= DIT_L;
|
||||
|
@ -110,9 +105,41 @@ char update_PaddleLatch(bool isUpdateKeyState) {
|
|||
******************************************************************************/
|
||||
void cwKeyer(void){
|
||||
bool continue_loop = true;
|
||||
unsigned tmpKeyControl = 0;
|
||||
char tmpKeyControl = 0;
|
||||
|
||||
if(KeyerMode_e::KEYER_STRAIGHT != globalSettings.keyerMode){
|
||||
if((KeyerMode_e::KEYER_STRAIGHT == globalSettings.keyerMode)
|
||||
|| (digitalRead(PIN_PTT) == 0)){//use the PTT as the key for tune up, quick QSOs
|
||||
while(1){
|
||||
tmpKeyControl = update_PaddleLatch(0) | (digitalRead(PIN_PTT)?0:DIT_L);
|
||||
//Serial.println((int)tmpKeyControl);
|
||||
if ((tmpKeyControl & DIT_L) == DIT_L) {
|
||||
// if we are here, it is only because the key is pressed
|
||||
if (!globalSettings.txActive){
|
||||
startTx(TuningMode_e::TUNE_CW);
|
||||
globalSettings.cwExpirationTimeMs = millis() + globalSettings.cwActiveTimeoutMs;
|
||||
}
|
||||
cwKeydown();
|
||||
|
||||
while ( tmpKeyControl & DIT_L == DIT_L){
|
||||
tmpKeyControl = update_PaddleLatch(0) | (digitalRead(PIN_PTT)?0:DIT_L);
|
||||
//Serial.println((int)tmpKeyControl);
|
||||
}
|
||||
|
||||
cwKeyUp();
|
||||
}
|
||||
else{
|
||||
if (0 < globalSettings.cwExpirationTimeMs && globalSettings.cwExpirationTimeMs < millis()){
|
||||
globalSettings.cwExpirationTimeMs = 0;
|
||||
stopTx();
|
||||
}
|
||||
return;//Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
checkCAT();
|
||||
} //end of while
|
||||
|
||||
}
|
||||
else{//KEYER_IAMBIC_*
|
||||
while(continue_loop){
|
||||
switch(keyerState){
|
||||
case IDLE:
|
||||
|
@ -193,34 +220,7 @@ void cwKeyer(void){
|
|||
|
||||
checkCAT();
|
||||
} //end of while
|
||||
}
|
||||
else{//KEYER_STRAIGHT
|
||||
while(1){
|
||||
char state = update_PaddleLatch(0);
|
||||
// Serial.println((int)state);
|
||||
if (state == DIT_L) {
|
||||
// if we are here, it is only because the key is pressed
|
||||
if (!globalSettings.txActive){
|
||||
startTx(TuningMode_e::TUNE_CW);
|
||||
globalSettings.cwExpirationTimeMs = millis() + globalSettings.cwActiveTimeoutMs;
|
||||
}
|
||||
cwKeydown();
|
||||
|
||||
while ( update_PaddleLatch(0) == DIT_L );
|
||||
|
||||
cwKeyUp();
|
||||
}
|
||||
else{
|
||||
if (0 < globalSettings.cwExpirationTimeMs && globalSettings.cwExpirationTimeMs < millis()){
|
||||
globalSettings.cwExpirationTimeMs = 0;
|
||||
stopTx();
|
||||
}
|
||||
return;//Tx stop control by Main Loop
|
||||
}
|
||||
|
||||
checkCAT();
|
||||
} //end of while
|
||||
}//end of else KEYER_STRAIGHT
|
||||
}//end of KEYER_IAMBIC_*
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -46,35 +46,65 @@ void drawMainMenu(void)
|
|||
morseText(b);
|
||||
}
|
||||
|
||||
void drawMainMenuIncrement()
|
||||
{
|
||||
//State variables
|
||||
static uint32_t last_freq = 0;
|
||||
static Vfo_e last_vfo = Vfo_e::VFO_A;
|
||||
static VfoMode_e last_mode = VfoMode_e::VFO_MODE_LSB;
|
||||
static bool last_split = false;
|
||||
static bool last_rit = false;
|
||||
static TuningMode_e last_tuning = TuningMode_e::TUNE_SSB;
|
||||
|
||||
Button button;
|
||||
|
||||
if((last_freq != GetActiveVfoFreq())
|
||||
||(last_vfo != globalSettings.activeVfo)){
|
||||
extractAndDrawButton(&button,&bVfoA);
|
||||
extractAndDrawButton(&button,&bVfoB);
|
||||
updateBandButtons(last_freq);
|
||||
last_freq = GetActiveVfoFreq();
|
||||
last_vfo = globalSettings.activeVfo;
|
||||
|
||||
//We set this here so that we're always hearing what's displayed
|
||||
setFrequency(last_freq);
|
||||
}
|
||||
|
||||
if(last_mode != GetActiveVfoMode()){
|
||||
updateSidebandButtons();
|
||||
last_mode = GetActiveVfoMode();
|
||||
}
|
||||
|
||||
if(last_split != globalSettings.splitOn){
|
||||
extractAndDrawButton(&button,&bVfoA);
|
||||
extractAndDrawButton(&button,&bVfoB);
|
||||
extractAndDrawButton(&button,&bSpl);
|
||||
last_split = globalSettings.splitOn;
|
||||
}
|
||||
|
||||
if(last_rit != globalSettings.ritOn){
|
||||
extractAndDrawButton(&button,&bRit);
|
||||
last_rit = globalSettings.ritOn;
|
||||
}
|
||||
|
||||
if(last_tuning != globalSettings.tuningMode){
|
||||
extractAndDrawButton(&button,&bCw);
|
||||
last_tuning = globalSettings.tuningMode;
|
||||
}
|
||||
}
|
||||
|
||||
void mainMenuTune(int16_t knob)
|
||||
{
|
||||
static uint32_t current_freq = 0;
|
||||
|
||||
if((0 == knob) && (GetActiveVfoFreq() == current_freq)){
|
||||
if(0 == knob){
|
||||
//Nothing to do - we're already set!
|
||||
return;
|
||||
}
|
||||
|
||||
current_freq = GetActiveVfoFreq();
|
||||
const uint32_t current_freq = GetActiveVfoFreq();
|
||||
const uint32_t new_freq = current_freq + (50 * knob);
|
||||
|
||||
setFrequency(new_freq);
|
||||
|
||||
if(autoSelectSidebandChanged(current_freq)){
|
||||
updateSidebandButtons();
|
||||
}
|
||||
|
||||
const uint32_t old_freq = current_freq;
|
||||
current_freq = new_freq;
|
||||
|
||||
Button button;
|
||||
if(Vfo_e::VFO_A == globalSettings.activeVfo){
|
||||
extractAndDrawButton(&button,&bVfoA);
|
||||
}
|
||||
else{
|
||||
extractAndDrawButton(&button,&bVfoB);
|
||||
}
|
||||
updateBandButtons(old_freq);
|
||||
SetActiveVfoFreq(new_freq);
|
||||
autoSelectSidebandChanged(current_freq);
|
||||
}
|
||||
|
||||
MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
|
||||
|
@ -156,7 +186,7 @@ MenuReturn_e runMainMenu(const ButtonPress_e tuner_button,
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
drawMainMenuIncrement();
|
||||
|
||||
return MenuReturn_e::StillActive;//main menu always returns StillActive
|
||||
}
|
|
@ -9,6 +9,9 @@ extern const uint8_t MAIN_MENU_NUM_BUTTONS;
|
|||
|
||||
extern const Button bVfoA;
|
||||
extern const Button bVfoB;
|
||||
extern const Button bRit;
|
||||
extern const Button bCw;
|
||||
extern const Button bSpl;
|
||||
void updateBandButtons(const uint32_t old_freq);
|
||||
void updateSidebandButtons();
|
||||
void drawTx();
|
||||
|
|
18
nano_gui.cpp
18
nano_gui.cpp
|
@ -2,6 +2,7 @@
|
|||
#include "nano_gui.h"
|
||||
#include "colors.h"
|
||||
#include "pin_definitions.h"
|
||||
#include "push_button.h"
|
||||
#include "scratch_space.h"
|
||||
#include "settings.h"
|
||||
#include "touch.h"
|
||||
|
@ -116,7 +117,7 @@ void setupTouch(){
|
|||
};
|
||||
|
||||
displayClear(DISPLAY_BLACK);
|
||||
strncpy_P(b,(const char*)F("Click on the cross"),sizeof(b));
|
||||
strncpy_P(b,(const char*)F("Click on the cross\nPush tune to cancel"),sizeof(b));
|
||||
displayText(b, 20,100, 200, 50, DISPLAY_WHITE, DISPLAY_BLACK, DISPLAY_BLACK);
|
||||
|
||||
Point cal_points[sizeof(CROSS_CORNER_POINTS)/sizeof(CROSS_CORNER_POINTS[0])];
|
||||
|
@ -124,6 +125,9 @@ void setupTouch(){
|
|||
for(uint8_t i = 0; i < sizeof(CROSS_CORNER_POINTS)/sizeof(CROSS_CORNER_POINTS[0]); ++i){
|
||||
drawCross(CROSS_CORNER_POINTS[i].x,CROSS_CORNER_POINTS[i].y,DISPLAY_WHITE);
|
||||
while(!readTouch(&cal_points[i])){
|
||||
if(ButtonPress_e::NotPressed != CheckTunerButton()){
|
||||
return;
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
while(readTouch(&cal_points[i])){
|
||||
|
@ -153,20 +157,20 @@ void setupTouch(){
|
|||
globalSettings.touchOffsetX = cal_points[0].x - ((CROSS_CORNER_OFFSET * globalSettings.touchSlopeX)/SCALE_SENSITIVITY_MULTIPLIER);
|
||||
globalSettings.touchOffsetY = cal_points[0].y - ((CROSS_CORNER_OFFSET * globalSettings.touchSlopeY)/SCALE_SENSITIVITY_MULTIPLIER);
|
||||
|
||||
|
||||
/*
|
||||
Serial.print(x1);Serial.print(':');Serial.println(y1);
|
||||
Serial.print(x2);Serial.print(':');Serial.println(y2);
|
||||
Serial.print(x3);Serial.print(':');Serial.println(y3);
|
||||
Serial.print(x4);Serial.print(':');Serial.println(y4);
|
||||
for(uint8_t i = 0; i < sizeof(cal_points)/sizeof(cal_points[0]); ++i){
|
||||
Serial.print(cal_points[i].x);Serial.print(':');Serial.println(cal_points[i].y);
|
||||
}
|
||||
|
||||
//for debugging
|
||||
Serial.print(globalSettings.touchSlopeX); Serial.print(' ');
|
||||
Serial.print(globalSettings.touchSlopeY); Serial.print(' ');
|
||||
Serial.print(globalSettings.touchOffsetX); Serial.print(' ');
|
||||
Serial.println(globalSettings.touchOffsetY); Serial.println(' ');
|
||||
*/
|
||||
*/
|
||||
|
||||
SaveSettingsToEeprom();
|
||||
displayClear(DISPLAY_BLACK);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@ void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t
|
|||
void displayText(const char *const text, int x1, int y1, int w, int h, int color, int background, int border, TextJustification_e justification = TextJustification_e::Center);
|
||||
|
||||
/* these functions are called universally to update the display */
|
||||
void updateDisplay(); //updates just the VFO frequency to show what is in 'frequency' variable
|
||||
void redrawVFOs(); //redraws only the changed digits of the vfo
|
||||
void drawTx();
|
||||
|
||||
#define TEXT_LINE_HEIGHT 18
|
||||
|
|
|
@ -26,8 +26,9 @@ static const uint16_t EEPROM_ADDR_CW_DELAYTIME = 48;//uint16_t
|
|||
static const uint16_t EEPROM_ADDR_VFO_A_MODE = 256;//uint8_t
|
||||
static const uint16_t EEPROM_ADDR_VFO_B_MODE = 257;//uint8_t
|
||||
static const uint16_t EEPROM_ADDR_CW_KEY_TYPE = 358;//uint8_t
|
||||
static const uint16_t EEPROM_ADDR_QUICKLIST_FREQ = 630;//uint32_t array
|
||||
static const uint16_t EEPROM_ADDR_QUICKLIST_MODE = 710;//uint8_t array
|
||||
static const uint16_t EEPROM_ADDR_QUICKLIST_FREQ = 630;//uint32_t array of size NUM_QUICKLIST_SETTINGS
|
||||
static const uint16_t EEPROM_ADDR_QUICKLIST_MODE = 710;//uint8_t array of size NUM_QUICKLIST_SETTINGS
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool LoadSane(T& dest,uint16_t addr, T min, T max)
|
||||
|
@ -189,5 +190,4 @@ void SetActiveVfoMode(VfoMode_e mode)
|
|||
else{
|
||||
globalSettings.vfoB.mode = mode;
|
||||
}
|
||||
redrawVFOs();
|
||||
}
|
||||
|
|
11
setup.cpp
11
setup.cpp
|
@ -539,16 +539,23 @@ MenuReturn_e runSetupMenu(const MenuItem_t* const menu_items,
|
|||
enterSubmenu(&setupMenu##menu_name);\
|
||||
}\
|
||||
|
||||
const char MT_CAL [] PROGMEM = "Calibrations";
|
||||
const char MI_TOUCH [] PROGMEM = "Touch Screen";
|
||||
void setupTouchSetting();
|
||||
|
||||
const char MT_CAL [] PROGMEM = "Calibrations";
|
||||
const MenuItem_t menuItemsCalibration [] PROGMEM {
|
||||
{MT_CAL,nullptr},//Title
|
||||
{SS_LOCAL_OSC_T,runLocalOscSetting},
|
||||
{SS_BFO_T,runBfoSetting},
|
||||
{MI_TOUCH,setupTouch},
|
||||
{MI_TOUCH,setupTouchSetting},
|
||||
};
|
||||
GENERATE_MENU_T(Calibration);
|
||||
|
||||
void setupTouchSetting(){
|
||||
setupTouch();
|
||||
initSetupMenuCalibration();
|
||||
}
|
||||
|
||||
const char MT_CW [] PROGMEM = "CW Setup";
|
||||
const MenuItem_t menuItemsCw [] PROGMEM {
|
||||
{MT_CW,nullptr},//Title
|
||||
|
|
77
touch.cpp
77
touch.cpp
|
@ -6,7 +6,28 @@
|
|||
#include "settings.h"
|
||||
|
||||
constexpr int16_t Z_THRESHOLD = 400;
|
||||
constexpr uint8_t MSEC_THRESHOLD = 3;
|
||||
constexpr uint8_t MSEC_THRESHOLD = 3;//Max sample rate is 125kHz, but we'll limit ourselves conservatively
|
||||
|
||||
constexpr uint8_t START_COMMAND = 1 << 7;
|
||||
constexpr uint8_t CHANNEL_Y = 1 << 4;
|
||||
constexpr uint8_t CHANNEL_Z1 = 3 << 4;
|
||||
constexpr uint8_t CHANNEL_Z2 = 4 << 4;
|
||||
constexpr uint8_t CHANNEL_X = 5 << 4;
|
||||
constexpr uint8_t CHANNEL_TEMPERATURE = 7 << 4;
|
||||
constexpr uint8_t USE_8_INSTEAD_OF_12_BIT = 1 << 3;
|
||||
constexpr uint8_t USE_SINGLE_ENDED_MEASUREMENT = 1 << 2;
|
||||
constexpr uint8_t POWER_OFF = 0 << 0;
|
||||
constexpr uint8_t POWER_ADC = 1 << 0;
|
||||
constexpr uint8_t POWER_REF = 2 << 0;
|
||||
constexpr uint8_t POWER_ADC_REF = 3 << 0;
|
||||
|
||||
constexpr uint16_t MEASURE_X = START_COMMAND | POWER_ADC | CHANNEL_Y;//X and Y channel labelling flip due to screen orientation
|
||||
constexpr uint16_t MEASURE_Y = START_COMMAND | POWER_ADC | CHANNEL_X;//X and Y channel labelling flip due to screen orientation
|
||||
constexpr uint16_t MEASURE_Z1 = START_COMMAND | POWER_ADC | CHANNEL_Z1;
|
||||
constexpr uint16_t MEASURE_Z2 = START_COMMAND | POWER_ADC | CHANNEL_Z2;
|
||||
|
||||
constexpr uint8_t RAW_READ_TO_12BIT_VALUE_SHIFT = 3;//16 bits read, zero-padded, but the MSB of the 16 is where the "BUSY" signal is asserted, so only need to shift by 3 instead of 4
|
||||
|
||||
|
||||
uint32_t msraw=0x80000000;
|
||||
int16_t xraw=0, yraw=0, zraw=0;
|
||||
|
@ -28,44 +49,51 @@ int16_t touch_besttwoavg( int16_t x , int16_t y , int16_t z ) {
|
|||
return (reta);
|
||||
}
|
||||
|
||||
void touch_update(){
|
||||
int16_t data[6];
|
||||
uint16_t touchReadChannel(uint8_t channel_command){
|
||||
//We assume that SPI.beginTransaction has already been called, and CS is LOW
|
||||
SPI.transfer(channel_command);//Throw away any bytes here
|
||||
const uint16_t tmpH = SPI.transfer(0) & 0x7F;//Leading 0 (during "busy" signal), followed by bits 11-5
|
||||
const uint16_t tmpL = SPI.transfer(0);//Bits 4-0, followed by 0s
|
||||
return tmpH << 5 | tmpL >> 3;
|
||||
}
|
||||
|
||||
void touch_update(){
|
||||
uint32_t now = millis();
|
||||
if (now - msraw < MSEC_THRESHOLD) return;
|
||||
if (now - msraw < MSEC_THRESHOLD){
|
||||
return;
|
||||
}
|
||||
|
||||
SPI.beginTransaction(spiSettingsTouch);
|
||||
digitalWrite(PIN_TOUCH_CS, LOW);
|
||||
SPI.transfer(0xB1 /* Z1 */);
|
||||
int16_t z1 = SPI.transfer16(0xC1 /* Z2 */) >> 3;
|
||||
int z = z1 + 4095;
|
||||
int16_t z2 = SPI.transfer16(0x91 /* X */) >> 3;
|
||||
z -= z2;
|
||||
if (z < 0) z = 0;
|
||||
if (z < Z_THRESHOLD) { // if ( !touched ) {
|
||||
// Serial.println();
|
||||
zraw = 0;
|
||||
|
||||
int16_t z1 = touchReadChannel(MEASURE_Z1);//~0 when not pressed, increases with pressure
|
||||
int32_t z = z1;
|
||||
int16_t z2 = touchReadChannel(MEASURE_Z2);//~4095 when not pressed, decreases with pressure
|
||||
z += (4095 - z2);
|
||||
//Serial.print(F("z1:"));Serial.print(z1);Serial.print(F(" z2:"));Serial.print(z2);Serial.print(F(" z:"));Serial.println(z);
|
||||
|
||||
zraw = z;
|
||||
if (zraw < Z_THRESHOLD) {//Don't bother reading x/y if we're not being touched
|
||||
digitalWrite(PIN_TOUCH_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
return;
|
||||
}
|
||||
zraw = z;
|
||||
|
||||
SPI.transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy
|
||||
data[0] = SPI.transfer16(0xD1 /* Y */) >> 3;
|
||||
data[1] = SPI.transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements
|
||||
data[2] = SPI.transfer16(0xD1 /* Y */) >> 3;
|
||||
data[3] = SPI.transfer16(0x91 /* X */) >> 3;
|
||||
data[4] = SPI.transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down
|
||||
data[5] = SPI.transfer16(0) >> 3;
|
||||
// make 3 x-y measurements
|
||||
int16_t data[6];
|
||||
data[0] = touchReadChannel(MEASURE_X);
|
||||
data[1] = touchReadChannel(MEASURE_Y);
|
||||
data[2] = touchReadChannel(MEASURE_X);
|
||||
data[3] = touchReadChannel(MEASURE_Y);
|
||||
data[4] = touchReadChannel(MEASURE_X);
|
||||
data[5] = touchReadChannel(MEASURE_Y & ~POWER_ADC_REF);//Turn off sensor
|
||||
|
||||
digitalWrite(PIN_TOUCH_CS, HIGH);
|
||||
SPI.endTransaction();
|
||||
|
||||
int16_t x = touch_besttwoavg( data[0], data[2], data[4] );
|
||||
int16_t y = touch_besttwoavg( data[1], data[3], data[5] );
|
||||
|
||||
//Serial.printf(" %d,%d", x, y);
|
||||
//Serial.println();
|
||||
|
||||
msraw = now; // good read completed, set wait
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
|
@ -93,6 +121,7 @@ void initTouch(){
|
|||
|
||||
bool readTouch(Point *const touch_point_out){
|
||||
touch_update();
|
||||
//Serial.print(F("readTouch found zraw of "));Serial.println(zraw);
|
||||
if (zraw >= Z_THRESHOLD) {
|
||||
touch_point_out->x = xraw;
|
||||
touch_point_out->y = yraw;
|
||||
|
|
|
@ -19,7 +19,6 @@ void switchVFO(Vfo_e new_vfo){
|
|||
|
||||
globalSettings.activeVfo = new_vfo;
|
||||
setFrequency(GetActiveVfoFreq());
|
||||
redrawVFOs();
|
||||
saveVFOs();
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,6 @@ void ritDisable(){
|
|||
if(globalSettings.ritOn){
|
||||
globalSettings.ritOn = false;
|
||||
setFrequency(globalSettings.ritFrequency);
|
||||
updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
222
ubitx_cat.cpp
222
ubitx_cat.cpp
|
@ -17,6 +17,9 @@
|
|||
|
||||
static const uint8_t FT817_MESSAGE_SIZE = 5;
|
||||
|
||||
static const uint8_t ACK = 0x00;
|
||||
static const uint8_t RACK = 0xF0;//Re-Acknowledge sent when the state requests is already active
|
||||
|
||||
//Data is ordered parameters 1-4, then command code last
|
||||
enum CatDataIndex_e : uint8_t {
|
||||
P1 = 0,
|
||||
|
@ -98,7 +101,7 @@ struct ReadTxStatus_t {
|
|||
};
|
||||
|
||||
//Values based on http://www.ka7oei.com/ft817_memmap.html
|
||||
//hamlib likes to read addresses 0x0064 and 0x007A, but including support for some others
|
||||
//hamlib likes to read addresses 0x0065 (read as 0x0064) and 0x007A, but including support for some others
|
||||
enum Ft817Eeprom_e : uint16_t {
|
||||
VfoAndBankSelect = 0x0055,
|
||||
TuningModes = 0x0057,
|
||||
|
@ -123,8 +126,6 @@ enum Ft817Eeprom_e : uint16_t {
|
|||
//for broken protocol
|
||||
static const uint16_t CAT_RECEIVE_TIMEOUT_MS = 500;
|
||||
|
||||
static const uint8_t ACK = 0;
|
||||
|
||||
uint8_t setHighNibble(uint8_t b, uint8_t v) {
|
||||
// Clear the high nibble
|
||||
b &= 0x0f;
|
||||
|
@ -271,120 +272,117 @@ void catReadEEPRom(uint8_t* cmd, uint8_t* response)
|
|||
}
|
||||
|
||||
void processCatCommand(uint8_t* cmd) {
|
||||
uint8_t response[FT817_MESSAGE_SIZE] = {0};
|
||||
uint8_t response_length = 0;
|
||||
//A response of a single byte, 0x00, is an ACK, so default to that
|
||||
uint8_t response[FT817_MESSAGE_SIZE] = {ACK};
|
||||
uint8_t response_length = 1;
|
||||
|
||||
switch(cmd[CMD]){
|
||||
case Ft817Command_e::SetFrequency:
|
||||
{
|
||||
uint32_t f = readFreq(cmd);
|
||||
setFrequency(f);
|
||||
updateDisplay();
|
||||
response[0] = 0x00;
|
||||
response_length = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case Ft817Command_e::SplitOn:
|
||||
globalSettings.splitOn = true;
|
||||
break;
|
||||
case Ft817Command_e::SplitOff:
|
||||
globalSettings.splitOn = false;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadFreqAndMode:
|
||||
//First 4 bytes are the frequency
|
||||
writeFreq(GetActiveVfoFreq(),response);//bytes 0-3
|
||||
//Last byte is the mode
|
||||
if (VfoMode_e::VFO_MODE_USB == GetActiveVfoMode()){
|
||||
response[4] = OperatingMode_e::USB;
|
||||
case Ft817Command_e::SetFrequency:
|
||||
{
|
||||
uint32_t f = readFreq(cmd);
|
||||
setFrequency(f);
|
||||
break;
|
||||
}
|
||||
else{
|
||||
response[4] = OperatingMode_e::LSB;
|
||||
|
||||
case Ft817Command_e::SplitOn:
|
||||
if(globalSettings.splitOn){
|
||||
response[0] = RACK;
|
||||
}
|
||||
globalSettings.splitOn = true;
|
||||
break;
|
||||
case Ft817Command_e::SplitOff:
|
||||
if(!globalSettings.splitOn){
|
||||
response[0] = RACK;
|
||||
}
|
||||
globalSettings.splitOn = false;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadFreqAndMode:
|
||||
//First 4 bytes are the frequency
|
||||
writeFreq(GetActiveVfoFreq(),response);//bytes 0-3
|
||||
//Last byte is the mode
|
||||
if (VfoMode_e::VFO_MODE_USB == GetActiveVfoMode()){
|
||||
response[4] = OperatingMode_e::USB;
|
||||
}
|
||||
else{
|
||||
response[4] = OperatingMode_e::LSB;
|
||||
}
|
||||
response_length = 5;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::OperatingMode:
|
||||
if(OperatingMode_e::LSB == cmd[P1] || OperatingMode_e::CWR == cmd[P1]){
|
||||
SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB);
|
||||
}
|
||||
else{
|
||||
SetActiveVfoMode(VfoMode_e::VFO_MODE_USB);
|
||||
}
|
||||
|
||||
setFrequency(GetActiveVfoFreq());//Refresh frequency to get new mode to take effect
|
||||
break;
|
||||
|
||||
case Ft817Command_e::PttOn:
|
||||
if (!globalSettings.txActive) {
|
||||
globalSettings.txCatActive = true;
|
||||
startTx(globalSettings.tuningMode);
|
||||
}
|
||||
else {
|
||||
response[0] = RACK;
|
||||
}
|
||||
break;
|
||||
|
||||
case Ft817Command_e::PttOff:
|
||||
if (globalSettings.txActive) {
|
||||
stopTx();
|
||||
}
|
||||
else{
|
||||
response[0] = RACK;
|
||||
}
|
||||
globalSettings.txCatActive = false;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::VfoToggle:
|
||||
if (Vfo_e::VFO_A == globalSettings.activeVfo){
|
||||
globalSettings.activeVfo = Vfo_e::VFO_B;
|
||||
}
|
||||
else{
|
||||
globalSettings.activeVfo = Vfo_e::VFO_A;
|
||||
}
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadEeprom:
|
||||
catReadEEPRom(cmd,response);
|
||||
response_length = 2;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadRxStatus:
|
||||
//We don't have visibility into these values, so just hard code stuff
|
||||
ReadRxStatus_t reply_status;
|
||||
reply_status.Dummy = 0;
|
||||
reply_status.Smeter = 9;//S9
|
||||
reply_status.SquelchSuppressionActive = 0;
|
||||
reply_status.DiscriminatorCenteringOff = 1;
|
||||
reply_status.CodeUnmatched = 0;
|
||||
response[0] = *(uint8_t*)&reply_status;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadTxStatus:
|
||||
{
|
||||
//We don't have visibility into some of these values, so just hard code stuff
|
||||
ReadTxStatus_t reply_status;
|
||||
reply_status.Dummy = 0;
|
||||
reply_status.HighSwrDetected = 0;
|
||||
reply_status.PowerOutputMeter = 0xF;
|
||||
reply_status.PttOff = !globalSettings.txActive;
|
||||
reply_status.SplitOff = globalSettings.splitOn;//Yaesu's documentation says that 1 = split off, but as of 2020-05-04 hamlib reads (*split = (p->tx_status & 0x20) ? RIG_SPLIT_ON : RIG_SPLIT_OFF), so do what hamlib wants
|
||||
|
||||
response[0] = *(uint8_t*)&reply_status;
|
||||
break;
|
||||
}
|
||||
Serial.write(response,5);
|
||||
break;
|
||||
|
||||
case Ft817Command_e::OperatingMode:
|
||||
if(OperatingMode_e::LSB == cmd[P1] || OperatingMode_e::CWR == cmd[P1]){
|
||||
SetActiveVfoMode(VfoMode_e::VFO_MODE_LSB);
|
||||
}
|
||||
else{
|
||||
SetActiveVfoMode(VfoMode_e::VFO_MODE_USB);
|
||||
}
|
||||
response_length = 1;
|
||||
|
||||
setFrequency(GetActiveVfoFreq());//Refresh frequency to get new mode to take effect
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case Ft817Command_e::PttOn:
|
||||
if (!globalSettings.txActive) {
|
||||
globalSettings.txCatActive = true;
|
||||
startTx(globalSettings.tuningMode);
|
||||
}
|
||||
else {
|
||||
response[0] = 0xF0;
|
||||
}
|
||||
response_length = 1;
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case Ft817Command_e::PttOff:
|
||||
if (globalSettings.txActive) {
|
||||
stopTx();
|
||||
}
|
||||
globalSettings.txCatActive = false;
|
||||
response_length = 1;
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case Ft817Command_e::VfoToggle:
|
||||
if (Vfo_e::VFO_A == globalSettings.activeVfo){
|
||||
globalSettings.activeVfo = Vfo_e::VFO_B;
|
||||
}
|
||||
else{
|
||||
globalSettings.activeVfo = Vfo_e::VFO_A;
|
||||
}
|
||||
response_length = 1;
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadEeprom:
|
||||
catReadEEPRom(cmd,response);
|
||||
response_length = 2;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadRxStatus:
|
||||
//We don't have visibility into these values, so just hard code stuff
|
||||
ReadRxStatus_t reply_status;
|
||||
reply_status.Dummy = 0;
|
||||
reply_status.Smeter = 9;//S9
|
||||
reply_status.SquelchSuppressionActive = 0;
|
||||
reply_status.DiscriminatorCenteringOff = 1;
|
||||
reply_status.CodeUnmatched = 0;
|
||||
response[0] = *(uint8_t*)&reply_status;
|
||||
response_length = 1;
|
||||
break;
|
||||
|
||||
case Ft817Command_e::ReadTxStatus:
|
||||
{
|
||||
//We don't have visibility into some of these values, so just hard code stuff
|
||||
ReadTxStatus_t reply_status;
|
||||
reply_status.Dummy = 0;
|
||||
reply_status.HighSwrDetected = 0;
|
||||
reply_status.PowerOutputMeter = 0xF;
|
||||
reply_status.PttOff = !globalSettings.txActive;
|
||||
reply_status.SplitOff = !globalSettings.splitOn;
|
||||
|
||||
response[0] = *(uint8_t*)&reply_status;
|
||||
response_length = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
response_length = 1;
|
||||
break;
|
||||
default:
|
||||
//Do something?
|
||||
break;
|
||||
}
|
||||
|
||||
Serial.write(response, response_length);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "version.h"
|
||||
|
||||
const char VERSION_STRING_PRIVATE [] PROGMEM = "R1.3.0";
|
||||
const char VERSION_STRING_PRIVATE [] PROGMEM = "R1.5.1";
|
||||
const char* const VERSION_STRING = VERSION_STRING_PRIVATE;
|
Loading…
Reference in New Issue
Block a user