Multiple updates.

Support for full 16-char status line to be sent to the Raduino.

Added rotary encoder support.

Everything above has been tested and works.

Added rudimentary top-level menu.  Compiles, but not tested yet.
This commit is contained in:
Rob French 2020-06-06 00:06:45 -05:00
parent c5a7592346
commit e27c15d56a
9 changed files with 266 additions and 143 deletions

View File

@ -151,6 +151,28 @@ void sendIOPTestStatus()
sendIOPMessage(m);
}
//======================================================================
// TEST STATUS MESSAGE
//======================================================================
void sendIOPMenuDisplay(const char* text, int8_t secs)
{
IOPMessage m;
int l = strlen(text);
m.id = IOP_MENU_DISPLAY_MSG;
m.len = 17;
m.data[0] = uint8_t(secs);
for (int i = 0; i < 16; i++) {
if (i < l) {
m.data[i+1] = text[i];
} else {
m.data[i+1] = ' ';
}
}
m.data[17] = '\0';
sendIOPMessage(m);
}
//======================================================================
/*

View File

@ -74,6 +74,7 @@ enum MessageID {
IOP_DGT_STATUS_MSG,
IOP_CW_STATUS_MSG,
IOP_TEST_STATUS_MSG,
IOP_MENU_DISPLAY_MSG,
// add any new elements here
NUM_MESSAGE_IDS
@ -220,6 +221,7 @@ void sendIOPSSBStatus(SSBConfig const&);
void sendIOPDGTStatus(DGTConfig const&);
void sendIOPCWStatus(CWConfig const&);
void sendIOPTestStatus();
void sendIOPMenuDisplay(const char*, int8_t);
//======================================================================
// TRANSLATOR

View File

@ -37,6 +37,9 @@ class IMode {
inline IFilter& filter() { return _filter; }
virtual const char* rxInfo() = 0;
virtual const char* txInfo() = 0;
// Called upon mode entry. Should assume that the rig's state is
// "clean", i.e. that it still needs to enable anything it needs for
// use in the mode.
@ -102,11 +105,11 @@ class IMode {
inline bool isTx() const { return _transmitting; }
inline bool isRx() const { return !_transmitting; }
virtual void setWideRxFilter()= 0;
virtual void setWideRxFilter() = 0;
virtual void setMediumRxFilter()= 0;
virtual void setMediumRxFilter() = 0;
virtual void setNarrowRxFilter()= 0;
virtual void setNarrowRxFilter() = 0;
private:
@ -129,7 +132,10 @@ class SSBMode : public IMode
IMode(c, a, f), _use_mic(default_mic)
{
}
virtual const char* rxInfo() { return _rx_info; };
virtual const char* txInfo() { return _tx_info; };
virtual void onEntry()
{
setWideRxFilter();
@ -184,19 +190,22 @@ class SSBMode : public IMode
USBDEBUG("SSB mode - Line In set");
}
virtual void setWideRxFilter(){
virtual void setWideRxFilter() {
_rx_info = "R:2.8k";
((BPFilter&)filter()).setBand(300.0, 3100.0);
filter().enable();
USBDEBUG("set wide RX SSB filter");
}
virtual void setMediumRxFilter(){
virtual void setMediumRxFilter() {
_rx_info = "R:2.4k";
((BPFilter&)filter()).setBand(500.0, 2900.0);
filter().enable();
USBDEBUG("set medium RX SSB filter");
}
virtual void setNarrowRxFilter(){
virtual void setNarrowRxFilter() {
_rx_info = "R:1.8k";
((BPFilter&)filter()).setBand(700.0, 2500.0);
filter().enable();
USBDEBUG("set narrow RX SSB filter");
@ -205,6 +214,8 @@ class SSBMode : public IMode
private:
bool _use_mic;
const char* _rx_info;
const char* _tx_info;
};
//======================================================================
@ -219,7 +230,10 @@ class DGTMode : public IMode
IMode(c, a, f)
{
}
virtual const char* rxInfo() { return _rx_info; };
virtual const char* txInfo() { return _tx_info; };
virtual void onEntry()
{
setWideRxFilter();
@ -249,22 +263,29 @@ class DGTMode : public IMode
}
virtual void setWideRxFilter(){
_rx_info = "R:2.8k";
((BPFilter&)filter()).setBand(300.0, 3100.0);
filter().enable();
USBDEBUG("set wide RX DGT filter");
}
virtual void setMediumRxFilter(){
_rx_info = "R:2.4k";
((BPFilter&)filter()).setBand(500.0, 2900.0);
filter().enable();
USBDEBUG("set medium RX DGT filter");
}
virtual void setNarrowRxFilter(){
_rx_info = "R:500 ";
((BPFilter&)filter()).setCenterAndWidth(1500.0, 500.0);
filter().enable();
USBDEBUG("set narrow RX DGT filter");
}
private:
const char* _rx_info;
const char* _tx_info;
};
@ -280,7 +301,10 @@ class CWMode : public IMode
IMode(c, a, f)
{
}
virtual const char* rxInfo() { return _rx_info; };
virtual const char* txInfo() { return _tx_info; };
virtual void onEntry()
{
setWideRxFilter();
@ -317,6 +341,7 @@ class CWMode : public IMode
}
((BPFilter&)filter()).setBand(low, low + width);
filter().enable();
_rx_info = "R:1.0k";
USBDEBUG("set wide RX CW filter");
}
@ -329,6 +354,7 @@ class CWMode : public IMode
}
((BPFilter&)filter()).setBand(low, low + width);
filter().enable();
_rx_info = "R:500 ";
USBDEBUG("set medium RX CW filter");
}
@ -341,8 +367,13 @@ class CWMode : public IMode
}
((BPFilter&)filter()).setBand(low, low + width);
filter().enable();
_rx_info = "R:250 ";
USBDEBUG("set narrow RX CW filter");
}
private:
const char* _rx_info;
const char* _tx_info;
};
//======================================================================
@ -357,7 +388,10 @@ class TTMode : public IMode
IMode(c, a, f)
{
}
virtual const char* rxInfo() { return _rx_info; };
virtual const char* txInfo() { return _tx_info; };
virtual void onEntry()
{
setWideRxFilter();
@ -387,22 +421,29 @@ class TTMode : public IMode
}
virtual void setWideRxFilter(){
_rx_info = "R:2.8k";
((BPFilter&)filter()).setBand(300.0, 3100.0);
filter().enable();
USBDEBUG("set wide RX TT filter");
}
virtual void setMediumRxFilter(){
_rx_info = "R:2.4k";
((BPFilter&)filter()).setBand(500.0, 2900.0);
filter().enable();
USBDEBUG("set medium RX TT filter");
}
virtual void setNarrowRxFilter(){
_rx_info = "R:1.8k";
((BPFilter&)filter()).setBand(700.0, 2500.0);
filter().enable();
USBDEBUG("set narrow RX TT filter");
}
private:
const char* _rx_info;
const char* _tx_info;
};
#endif

View File

@ -53,7 +53,7 @@ class IFilter {
public:
virtual ~IFilter() {}
virtual void enable() = 0;
virtual void disable()= 0;
virtual void disable() = 0;
};
class BPFilter : public IFilter {

View File

@ -5,9 +5,87 @@
#ifndef __menu_h__
#define __menu_h__
#include "rig.h"
// 16 characters on display
#define MAX_TEXT_LEN 16
#define MENU_SELECTED_CHAR '>'
class MenuItem {
public:
virtual ~MenuItem() {}
virtual void update() = 0;
virtual MenuItem* select() = 0;
virtual MenuItem* altSelect() = 0;
virtual MenuItem* exit() = 0;
virtual MenuItem* prev() = 0;
virtual MenuItem* next() = 0;
};
class TopMenu : public MenuItem {
public:
TopMenu(Rig& rig): _rig(rig), _visible(false), _adjust_tx(false) {}
virtual void update() {
strcpy(_buffer, _rig.modeText());
if (_adjust_tx) {
_buffer[2] = MENU_SELECTED_CHAR;
} else {
_buffer[9] = MENU_SELECTED_CHAR;
}
if (_visible) {
sendIOPMenuDisplay(_buffer, 0);
} else {
sendIOPMenuDisplay(_buffer, -1);
}
}
virtual MenuItem* select() {
if (!_visible) {
_visible = true;
} else {
_adjust_tx = !_adjust_tx;
}
return this;
}
virtual MenuItem* altSelect() {
if (_visible) {
_visible = false;
}
return this;
}
virtual MenuItem* exit() {
if (_visible) {
_visible = false;
}
return this;
}
virtual MenuItem* prev() {
if (_adjust_tx) {
} else {
_rig.switchRxFilter(true);
}
return this;
}
virtual MenuItem* next() {
if (_adjust_tx) {
} else {
_rig.switchRxFilter();
}
return this;
}
private:
Rig& _rig;
bool _visible;
bool _adjust_tx;
char _buffer[MAX_TEXT_LEN+1];
};
/*
public class MenuItem {
public:

View File

@ -2,138 +2,9 @@
// menu.ino
//======================================================================
#include <iopcomm.h>
#include "menu.h"
/*
CW mode:
WPM (although we can get this from Raduino)
WPM: # (L/R, select/abort)
FILT
WIDE NORM NARR
SSB mode:
TX LVL
COMP
FILT
WIDE NORM NARR
Digi mode:
TX LVL
*/
class MenuItem {
public:
MenuItem() {}
virtual MenuItem* next() = 0;
virtual MenuItem* prev() = 0;
char text[MAX_TEXT_LEN + 1];
};
class TextMenu : public MenuItem {
public:
TextMenu(int num_entries, int entry_len): MenuItem(), _num_entries(num_entries), _entry_len(entry_len), _selected(0), _leftmost(0) {
text[0] = '\0';
_entries = new MenuItem*[_num_entries];
_labels = new char*[_num_entries];
for (int i = 0; i < _num_entries; i++) {
_labels[i] = NULL;
}
}
~TextMenu() {
for (int i = 0; i < _num_entries; i++) {
if (_labels[i] != NULL) {
delete _labels[i];
}
}
delete _labels;
delete _entries;
}
virtual MenuItem* next() {
bool dirty = false;
if (++_selected == _num_entries) {
_selected = 0;
}
if (_selected < _leftmost) {
_leftmost = _selected;
dirty = true;
} else {
while ((_selected - _leftmost) * _entry_len >= MAX_TEXT_LEN) {
_leftmost++;
dirty = true;
}
}
if (dirty) {
for (int i = _leftmost; i < _num_entries; i++) {
strncpy(&text[i - _leftmost], _labels[i], _entry_len);
}
}
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
return this;
}
virtual MenuItem* prev() {
bool dirty = false;
if (_selected-- == 0) {
_selected += _num_entries;
}
if (_selected < _leftmost) {
_leftmost = _selected;
dirty = true;
} else {
while ((_selected - _leftmost) * _entry_len >= MAX_TEXT_LEN) {
_leftmost++;
dirty = true;
}
}
if (dirty) {
updateText();
} else {
updateCursor();
}
return this;
}
void addEntry(int i, const char* label, MenuItem* entry) {
if (i < _num_entries) {
_labels[i] = new char[strlen(label) + 1]; // I need to learn to do strings the C++ way.
strcpy(_labels[i], label); // Ditto.
_entries[i] = entry;
}
}
void updateText() {
for (int i = _leftmost; i < _num_entries; i++) {
strncpy(&text[i - _leftmost], _labels[i], _entry_len);
}
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
}
void updateCursor() {
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
}
/*MenuItem* operator[](int i) {
return this->entries[i];
}*/
private:
int _num_entries;
int _entry_len;
int _selected;
int _leftmost;
char** _labels;
MenuItem** _entries;
};
//======================================================================
// EOF
//======================================================================

View File

@ -8,11 +8,14 @@
#include <iopcomm.h>
#include "audio.h"
#include "RigMode.h"
//#include "menu.h"
//======================================================================
// Rig class
//======================================================================
const char * const modeID[] = {"s", "S", "c", "C", "d", "D", "t", "T"};
class Rig {
public:
@ -20,7 +23,7 @@ class Rig {
// Constructor/destructor.
//--------------------------------------------------------------------
Rig(RigConfig& c, RigAudio& a): _config(c), _audio(a)
Rig(RigConfig& c, RigAudio& a): _config(c), _audio(a), _filter(RX_FILTER_WIDE)
{
_modes = new IMode*[c.numModes];
_modesLen = c.numModes;
@ -51,10 +54,21 @@ class Rig {
delete _modes;
}
void init() {
switchRxFilter(_filter);
}
//--------------------------------------------------------------------
// Mode control.
//--------------------------------------------------------------------
const char* modeText() {
strcpy(&_modeText[0], modeID[_modesIndex]);
strcpy(&_modeText[3], mode()->rxInfo());
strcpy(&_modeText[10], mode()->txInfo());
return _modeText;
}
inline bool isSSBMode() const { return (_modesIndex == RIG_MODE_USB || _modesIndex == RIG_MODE_LSB); }
inline bool isUSBMode() const { return (_modesIndex == RIG_MODE_USB); }
inline bool isLSBMode() const { return (_modesIndex == RIG_MODE_LSB); }
@ -156,16 +170,43 @@ class Rig {
//--------------------------------------------------------------------
inline void setWideRxFilter() {
_filter = RX_FILTER_WIDE;
mode()->setWideRxFilter();
}
inline void setMediumRxFilter() {
_filter = RX_FILTER_MEDIUM;
mode()->setMediumRxFilter();
}
inline void setNarrowRxFilter() {
_filter = RX_FILTER_NARROW;
mode()->setNarrowRxFilter();
}
void switchRxFilter(RxFilter i) {
switch(i) {
case RX_FILTER_WIDE:
setWideRxFilter();
break;
case RX_FILTER_MEDIUM:
setMediumRxFilter();
break;
case RX_FILTER_NARROW:
setNarrowRxFilter();
break;
}
}
void switchRxFilter(bool prev=false) {
if (prev) {
_filter = RxFilter((_filter - 1) % NUM_RX_FILTERS);
} else {
_filter = RxFilter((_filter + 1) % NUM_RX_FILTERS);
}
}
/*
// Returns a pointer to the current RX filter.
@ -273,6 +314,10 @@ class Rig {
RigMode _modesLen;
RigMode _modesIndex;
RxFilter _filter;
char _modeText[17];
/*
IFilter** _rxFilters;
uint8_t _rxFiltersLen;

View File

@ -12,9 +12,12 @@
#include "keyer.h"
#define PTT_KEY_OUT_PIN 2
#define ENCODER_A_PIN 5
#define ENCODER_B_PIN 4
#define ENCODER_SW_PIN 3
// comment this out to disable debugging code
//#define DEBUG
#define DEBUG
#if defined(DEBUG)
#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x);

View File

@ -2,11 +2,13 @@
// ubitx_iop.ino
//======================================================================
#include <Encoder.h>
#include <iopcomm.h>
#include "audio.h"
#include "config.h"
#include "ubitx_iop.h"
#include "keyer.h"
#include "menu.h"
#include "rig.h"
#include "TxSwitch.h"
@ -33,6 +35,15 @@ GPIOSwitch micPTT(true, MIC_PTT_PIN);
//LineSwitch linePTTHelper;
GPIOSwitch linePTT(false, LINE_PTT_PIN);
Encoder knob(ENCODER_A_PIN, ENCODER_B_PIN);
long knobPos = 0;
Bounce btn;
elapsedMillis btnMillis;
TopMenu topMenu(rig);
MenuItem* menu = &topMenu;
elapsedMillis frameMillis;
unsigned frameTime;
unsigned frameCounter;
@ -67,6 +78,13 @@ void setup() {
frameCounter = 0;
frameMillis = 0;
knob.write(0);
btn.attach(ENCODER_SW_PIN, INPUT_PULLUP);
btn.interval(25);
rig.init();
USBDEBUG("setup completed");
// audioInit();
/*
@ -84,6 +102,7 @@ void loop()
{
static char frame_status[100];
static bool paddle_loop = false;
// long oldPos = knobPos;
RigMode oldRigMode;
@ -191,6 +210,48 @@ void loop()
//frame10Hz = 0;
}
btn.update();
if (btn.fell()) {
//sendIOPMenuDisplay("PRESSED ", 2);
btnMillis = 0;
USBDEBUG("button pressed");
} else if (btn.rose()) {
if (btnMillis > 1000) {
// long press - exit
//sendIOPMenuDisplay("REL-LONG ", 2);
menu->exit();
USBDEBUG("button released - long");
} if (btnMillis > 500) {
// medium press - altSelect
menu->altSelect();
} else {
// short press - select
//sendIOPMenuDisplay("REL-SHORT ", 2);
menu->select();
USBDEBUG("button released - short");
}
menu->update();
}
knobPos = knob.read();
// wait til we turn greater than 3 pos in either direction, for "debouncing"
if (knobPos > 3) {
// left
//sendIOPMenuDisplay("LEFT ", 5);
menu->prev();
menu->update();
knob.write(0);
USBDEBUG("knob turned left");
} else if (knobPos < -3) {
// right
//sendIOPMenuDisplay("RIGHT ", 5);
menu->next();
menu->update();
knob.write(0);
USBDEBUG("knob turned right");
}
if (frameMillis > 5000) {
#if defined(DEBUG)
frameTime = frameMillis;