Compare commits

...

33 Commits

Author SHA1 Message Date
Michael Clemens
6dceffd993 reactivated 80m, changed to color scheme to green on black 2021-05-17 17:29:57 +02:00
Michael Clemens
36cd505e8e
changed band limits, enabled 12m, disabled 80m 2021-05-13 15:20:01 +02:00
Michael Clemens
6d4fc996d9
Update callsign.cpp 2021-05-13 15:15:19 +02:00
reedbn
6c9e759901
Add user manual link to readme 2021-04-11 18:19:42 -07:00
reedbn
4918670eaa Save 12 bytes by adjusting math, inspried by Jack Purdum 2020-12-13 21:51:46 -08:00
reedbn
4eecda170d Add size to comment 2020-12-13 21:34:55 -08:00
reedbn
50381da6de Adjust keyer behavior to always run PTT button as if in KEYER_STRAIGHT mode 2020-12-13 18:19:13 -08:00
reedbn
b136f5e43c Add parentheses to force correct addition operation. Thanks to Barry Halterman for catching this. 2020-12-13 11:44:40 -08:00
Reed Nightingale
a4f5f4b3cb Update displayed version 2020-07-18 20:43:36 -07:00
reedbn
ab678f3e8b
Merge pull request #13 from reedbn/ide_1_8_13-size-fixes
Arduino IDE 1.8.13 size fixes
2020-07-18 20:30:40 -07:00
Reed Nightingale
c62eaaba2e Update readme with compiler info 2020-07-18 20:28:43 -07:00
Reed Nightingale
c11c8bfbe3 Remove bands that aren't on dial from band lookup struct 2020-07-18 18:58:43 -07:00
Reed Nightingale
84f47b0a23 Bump version 2020-05-05 21:41:45 -07:00
Reed Nightingale
740e881d28 Update readme due to new feature 2020-05-05 21:41:45 -07:00
Reed Nightingale
71e5f877da Add touch cancellation option 2020-05-05 21:32:30 -07:00
Reed Nightingale
e6fa6f935b Fix zraw assignment issue that was preventing touch press-and-hold from working 2020-05-05 21:25:52 -07:00
Reed Nightingale
b3a7e34d1b Replace 16-bit read style with slower, but apparently more reliable 8-bit read style 2020-05-05 20:36:03 -07:00
Reed Nightingale
d282062eef Force redraw after setupTouch is called so that menu is on screen 2020-05-05 20:35:17 -07:00
Reed Nightingale
f76b50fcc3 Update commented out debug print, and remove black screen draw at the end 2020-05-05 20:34:28 -07:00
Reed Nightingale
488e462c6c Debugging checkpoint 2020-05-05 19:54:07 -07:00
Reed Nightingale
c323cec0cb Update readme with lots of information for other prospective developers 2020-05-04 23:17:05 -07:00
Reed Nightingale
f541ff8928 Get rid of do-nothing functions 2020-05-04 23:00:31 -07:00
Reed Nightingale
e7748d2878 Switch colors from defines to consts 2020-05-04 22:53:41 -07:00
Reed Nightingale
e168a4d5b0 Bump version 2020-05-04 22:28:43 -07:00
Reed Nightingale
e3f23ae755 Slight tweak to how frequencies are changed so that quicklist changes will update the actual oscillators 2020-05-04 22:27:37 -07:00
Reed Nightingale
0b65559e97 Revert the previous commit 2020-05-04 22:26:09 -07:00
Reed Nightingale
2a412fd34a Force frequency change after recall. Unfortunately, this puts us just 4 bytes over the limit 2020-05-04 22:06:47 -07:00
Reed Nightingale
a138490dcc Change decision making in main menu loop to ensure display consistency when CAT changes 2020-05-04 21:57:24 -07:00
Reed Nightingale
4cf8f7a840 Use ACK/RACK, and set default response length to 1 so that it usually doesn't have to be re-set. 2020-05-04 01:01:05 -07:00
Reed Nightingale
6a6dc2a29a Remove debug drawing 2020-05-04 00:56:25 -07:00
Reed Nightingale
a7cbf50384 Fix comment based on reviewing hamlib code 2020-05-04 00:43:38 -07:00
Reed Nightingale
e809b37e29 Invert split value from what Yaesu's documentation says, because hamlib reads it inverted 2020-05-04 00:34:15 -07:00
Reed Nightingale
e770230d14 CAT debug stuff added 2020-05-04 00:03:43 -07:00
18 changed files with 363 additions and 247 deletions

View File

@ -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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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_*
}

View File

@ -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
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -1,2 +0,0 @@
void updateDisplay() {}
void redrawVFOs(){}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;