Compare commits
22 Commits
working-00
...
master
Author | SHA1 | Date | |
---|---|---|---|
fea6b7d435 | |||
|
bd97aa0545 | ||
|
110918079b | ||
|
926b8d3600 | ||
|
6581a5f2a4 | ||
|
2da162f7c2 | ||
|
28cbb0363f | ||
|
0a8e91c4a7 | ||
|
2ea9c96e47 | ||
|
66d1924685 | ||
|
2e115e363b | ||
|
bebd5ad78e | ||
|
c27e2eddd6 | ||
|
e27c15d56a | ||
|
c5a7592346 | ||
|
519a208508 | ||
|
5e16a49859 | ||
|
322909c6f2 | ||
|
564c35f397 | ||
|
9b7095a6e3 | ||
|
7aa2cbc1c4 | ||
|
9c1a490963 |
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
NOTE: This project is no longer maintained. I do not have a uBITX configured to use this code, and so am unable to provide any assistance regarding use of the code. I will note that this code is intended for use with a Teensy 3.2 microcontroller, although there are probably good things to be had for other microcontrollers as well. Also, at the point where this project left off, it might or might not have been functional... a hardware failure precluded further testing.
|
||||
|
||||
This project implements an additional processor in the uBITX V5 transceiver, which was used to implement the following functions:
|
||||
|
||||
- Wide, medium, and narrow audio filters for each mode (SSB, CW, digital)
|
||||
- A new CW keyer based on the NanoIO codebase (I think... would have to double check the source markings)
|
||||
- A single USB interface providing both serial CAT control as well as digital audio I/O
|
||||
|
||||
Communication between the Teensy and the Raduino occurs over serial (UART) communication.
|
||||
|
||||
This Teensy code depends on a modified version of the KD8CEC firmware for the Raduino; reference the ubitx-v5d repository.
|
@@ -16,6 +16,16 @@
|
||||
|
||||
//======================================================================
|
||||
|
||||
void sendCATMessage(const uint8_t* buf)
|
||||
{
|
||||
MYSERIAL.write(prefixAndLengthToByte(CAT_PREFIX, 5));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
MYSERIAL.write(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void sendIOPMessage(IOPMessage const& msg)
|
||||
{
|
||||
MYSERIAL.write(prefixAndLengthToByte(IOP_PREFIX, msg.len + 1));
|
||||
@@ -38,12 +48,12 @@ void recvIOPMessage(IOPMessage& msg, const uint8_t* buf, int len)
|
||||
|
||||
//======================================================================
|
||||
|
||||
void sendIOPModeCommand(RigMode mode)
|
||||
void sendIOPModeCommand(rig_mode mode)
|
||||
{
|
||||
IOPMessage m;
|
||||
m.id = IOP_MODE_COMMAND;
|
||||
m.len = 1;
|
||||
m.data[0] = uint8_t(mode);
|
||||
m.data[0] = static_cast<uint8_t>(mode);
|
||||
sendIOPMessage(m);
|
||||
}
|
||||
|
||||
@@ -73,7 +83,118 @@ void sendIOPModeRequest()
|
||||
{
|
||||
IOPMessage m;
|
||||
m.id = IOP_MODE_REQUEST;
|
||||
m.len = 0;
|
||||
m.len = 4; // NOTE: LEN = 4 for padding only... temporary
|
||||
sendIOPMessage(m);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void sendIOPDebugMessage(const char* text)
|
||||
{
|
||||
IOPMessage m;
|
||||
m.id = IOP_DEBUG_MSG;
|
||||
m.len = strlen(text);
|
||||
if (m.len > IOP_MESSAGE_MAX_LEN) {
|
||||
m.len = IOP_MESSAGE_MAX_LEN;
|
||||
}
|
||||
strncpy(m.data, text, m.len);
|
||||
sendIOPMessage(m);
|
||||
};
|
||||
|
||||
////======================================================================
|
||||
//// SSB STATUS MESSAGE
|
||||
////======================================================================
|
||||
|
||||
//void sendIOPSSBStatus(SSBConfig const &c)
|
||||
//{
|
||||
//IOPMessage m;
|
||||
//m.id = IOP_SSB_STATUS_MSG;
|
||||
//m.len = 4;
|
||||
//m.data[0] = 'S'; // current mode; redundant w/ Raduino mode, but maybe useful for debugging
|
||||
//m.data[1] = '-'; // placeholder for transmit filter/compressor
|
||||
//m.data[2] = RX_FILTER_LETTER[c.filter];
|
||||
//m.data[3] = '\0';
|
||||
//sendIOPMessage(m);
|
||||
//}
|
||||
|
||||
////======================================================================
|
||||
//// DGT STATUS MESSAGE
|
||||
////======================================================================
|
||||
|
||||
//void sendIOPDGTStatus(DGTConfig const &c)
|
||||
//{
|
||||
//IOPMessage m;
|
||||
//m.id = IOP_DGT_STATUS_MSG;
|
||||
//m.len = 4;
|
||||
//m.data[0] = 'D'; // current mode; redundant w/ Raduino mode, but maybe useful for debugging
|
||||
//m.data[1] = '-'; // placeholder for future digital submodes?
|
||||
//m.data[2] = RX_FILTER_LETTER[c.filter];
|
||||
//m.data[3] = '\0';
|
||||
//sendIOPMessage(m);
|
||||
//}
|
||||
|
||||
////======================================================================
|
||||
//// CW STATUS MESSAGE
|
||||
////======================================================================
|
||||
|
||||
//void sendIOPCWStatus(CWConfig const &c)
|
||||
//{
|
||||
//IOPMessage m;
|
||||
//m.id = IOP_CW_STATUS_MSG;
|
||||
//m.len = 4;
|
||||
//m.data[0] = 'C'; // current mode; redundant w/ Raduino mode, but maybe useful for debugging
|
||||
//m.data[1] = KEYER_MODE_LETTER[c.mode];
|
||||
//m.data[2] = RX_FILTER_LETTER[c.filter];
|
||||
//m.data[3] = '\0';
|
||||
//sendIOPMessage(m);
|
||||
//}
|
||||
|
||||
////======================================================================
|
||||
//// TEST STATUS MESSAGE
|
||||
////======================================================================
|
||||
|
||||
//void sendIOPTestStatus()
|
||||
//{
|
||||
//IOPMessage m;
|
||||
//m.id = IOP_TEST_STATUS_MSG;
|
||||
//m.len = 4;
|
||||
//m.data[0] = ' ';
|
||||
//m.data[1] = 'T';
|
||||
//m.data[2] = 'T';
|
||||
//m.data[3] = '\0';
|
||||
//sendIOPMessage(m);
|
||||
//}
|
||||
|
||||
//======================================================================
|
||||
// MENU DISPLAY MESSAGE
|
||||
//======================================================================
|
||||
|
||||
void sendIOPMenuDisplay(const char* text)
|
||||
{
|
||||
IOPMessage m;
|
||||
int l = strlen(text);
|
||||
m.id = IOP_MENU_DISPLAY_MSG;
|
||||
m.len = 16;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i < l) {
|
||||
m.data[i] = text[i];
|
||||
} else {
|
||||
m.data[i] = ' ';
|
||||
}
|
||||
}
|
||||
m.data[16] = '\0';
|
||||
sendIOPMessage(m);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// MENU INACTIVE MESSAGE
|
||||
//======================================================================
|
||||
|
||||
void sendIOPMenuInactive()
|
||||
{
|
||||
IOPMessage m;
|
||||
m.id = IOP_MENU_INACTIVE_MSG;
|
||||
m.len = 4; // NOTE: LEN = 4 for padding only... temporary
|
||||
sendIOPMessage(m);
|
||||
}
|
||||
|
||||
|
@@ -67,10 +67,16 @@ enum MessageID {
|
||||
IOP_START_TX_COMMAND,
|
||||
IOP_STOP_TX_COMMAND,
|
||||
IOP_CW_CONFIG_MSG,
|
||||
IOP_DEBUG_MSG,
|
||||
|
||||
// Requests
|
||||
IOP_MODE_REQUEST,
|
||||
IOP_SSB_STATUS_MSG,
|
||||
IOP_DGT_STATUS_MSG,
|
||||
IOP_CW_STATUS_MSG,
|
||||
IOP_TEST_STATUS_MSG,
|
||||
IOP_MENU_DISPLAY_MSG,
|
||||
IOP_MENU_INACTIVE_MSG,
|
||||
|
||||
// add any new elements here
|
||||
NUM_MESSAGE_IDS
|
||||
@@ -91,118 +97,164 @@ enum MessageID {
|
||||
* (e.g. USB, LSB, etc.)
|
||||
*/
|
||||
|
||||
enum RigMode {
|
||||
MODE_SSB = 0,
|
||||
MODE_DIGI,
|
||||
MODE_CW,
|
||||
MODE_TEST,
|
||||
// add any new elements here
|
||||
NUM_RIG_MODES
|
||||
enum struct rig_mode {
|
||||
ssb = 0,
|
||||
cw,
|
||||
digi,
|
||||
// add new items here
|
||||
count
|
||||
};
|
||||
|
||||
/* Keyer modes.
|
||||
*/
|
||||
|
||||
enum KeyMode {
|
||||
STRAIGHT = 0,
|
||||
IAMBIC_A,
|
||||
IAMBIC_B,
|
||||
//ULTIMATIC,
|
||||
//BUG,
|
||||
// add any new elements here
|
||||
NUM_KEY_MODES
|
||||
enum struct keyer_mode {
|
||||
straight = 0,
|
||||
iambic_a,
|
||||
iambic_b,
|
||||
//ultimatic,
|
||||
//bug,
|
||||
// add any new items here
|
||||
count
|
||||
};
|
||||
|
||||
const unsigned char MODE_LETTER[3] = {'S', 'A', 'B'};
|
||||
enum struct rx_filter {
|
||||
wide = 0,
|
||||
medium,
|
||||
narrow,
|
||||
count
|
||||
};
|
||||
|
||||
enum struct digi_submode {
|
||||
rtty = 0,
|
||||
psk31,
|
||||
user_defined,
|
||||
count
|
||||
};
|
||||
|
||||
//const unsigned char RIG_MODE_LETTER[num_rig_modes] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'};
|
||||
//const unsigned char KEYER_MODE_LETTER[num_keyer_modes] = {'S', 'A', 'B'};
|
||||
//const unsigned char RX_FILTER_LETTER[num_rx_filters] = {'W', 'M', 'N'};
|
||||
|
||||
const uint8_t NO_FLAGS = 0;
|
||||
const uint8_t REVERSED = 1;
|
||||
|
||||
struct IOPMessage {
|
||||
uint8_t id;
|
||||
uint8_t len;
|
||||
uint8_t data[IOP_MESSAGE_MAX_LEN];
|
||||
IOPMessage() { memset(data, 0, IOP_MESSAGE_MAX_LEN); }
|
||||
uint8_t id;
|
||||
uint8_t len;
|
||||
uint8_t data[IOP_MESSAGE_MAX_LEN];
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// IConfig
|
||||
//
|
||||
// Interface to a configuration object.
|
||||
//======================================================================
|
||||
|
||||
void sendIOPMessage(IOPMessage const&);
|
||||
void recvIOPMessage(IOPMessage&, const uint8_t*, int);
|
||||
struct bpf_config {
|
||||
float lo_freq;
|
||||
float hi_freq;
|
||||
float gain;
|
||||
};
|
||||
|
||||
void sendIOPModeCommand(RigMode);
|
||||
void sendIOPStartTxCommand();
|
||||
void sendIOPStopTxCommand();
|
||||
void sendIOPModeRequest();
|
||||
struct mode_config {
|
||||
mode_config(bool usb, rx_filter f, const bpf_config *fc) : is_usb(usb), filter(f) {
|
||||
for (int i = 0; i < static_cast<int>(rx_filter::count); i++) {
|
||||
filter_cfg[i] = fc[i];
|
||||
}
|
||||
}
|
||||
bool is_usb;
|
||||
rx_filter filter;
|
||||
bpf_config filter_cfg[static_cast<size_t>(rx_filter::count)];
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// SSB CONFIGURATION
|
||||
//======================================================================
|
||||
|
||||
const bpf_config ssb_filter_config[] =
|
||||
{bpf_config{ 300.0, 3100.0, 1.0},
|
||||
bpf_config{ 500.0, 2900.0, 1.0},
|
||||
bpf_config{ 700.0, 2500.0, 1.0}};
|
||||
|
||||
struct comp_config {
|
||||
bool enabled = false;
|
||||
float threshold = 0.1;
|
||||
float ratio = 20.0;
|
||||
float gain = 2.0;
|
||||
};
|
||||
|
||||
struct ssb_config : public mode_config {
|
||||
ssb_config() : mode_config(true, rx_filter::wide, ssb_filter_config) {}
|
||||
comp_config comp;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// DIGI CONFIGURATION
|
||||
//======================================================================
|
||||
|
||||
const bpf_config digi_filter_config[] =
|
||||
{bpf_config{ 300.0, 3100.0, 1.0},
|
||||
bpf_config{ 500.0, 2900.0, 1.0},
|
||||
bpf_config{1250.0, 1750.0, 1.0}};
|
||||
|
||||
struct digi_config : public mode_config {
|
||||
digi_config() : mode_config(true, rx_filter::wide, digi_filter_config) {}
|
||||
digi_submode submode = digi_submode::user_defined;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// CW CONFIGURATION
|
||||
//======================================================================
|
||||
|
||||
struct CWConfig {
|
||||
// mode
|
||||
KeyMode mode = IAMBIC_A;
|
||||
// flags
|
||||
bool reversed = false;
|
||||
// parameters
|
||||
uint8_t wpm = 15;
|
||||
float weight = 3.0;
|
||||
uint16_t sidetone = 700;
|
||||
const bpf_config cw_filter_config[] =
|
||||
{bpf_config{ 300.0, 1300.0, 1.0},
|
||||
bpf_config{ 450.0, 950.0, 1.0},
|
||||
bpf_config{ 575.0, 825.0, 1.0}};
|
||||
|
||||
struct cw_config : public mode_config {
|
||||
cw_config() : mode_config(true, rx_filter::wide, cw_filter_config) {}
|
||||
keyer_mode mode = keyer_mode::iambic_a;
|
||||
// flags
|
||||
bool reversed = false;
|
||||
// parameters
|
||||
uint8_t wpm = 15;
|
||||
float weight = 3.0;
|
||||
uint16_t sidetone = 700;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// TRANSLATOR
|
||||
// TT CONFIGURATION
|
||||
//======================================================================
|
||||
|
||||
/*
|
||||
class Translator
|
||||
{
|
||||
struct TTConfig : public IConfig {
|
||||
public:
|
||||
Translator(RigMode&, CWConfig&, Stream&);
|
||||
|
||||
void registerPrefixCb(PrefixID id, void (*func)(void*));
|
||||
void registerMessageCb(MessageID id, void (*func)(void*));
|
||||
|
||||
void sendACK();
|
||||
void sendIOPMessage(IOPMessage const&);
|
||||
|
||||
void receive();
|
||||
|
||||
void pack_ModeCommand(IOPMessage&, RigMode);
|
||||
void pack_CWConfig(IOPMessage&, CWConfig const&);
|
||||
void pack_ModeRequest(IOPMessage&);
|
||||
|
||||
void unpack(IOPMessage const&);
|
||||
|
||||
protected:
|
||||
void unpack_ModeCommand(IOPMessage const&);
|
||||
void unpack_CWConfig(IOPMessage const&);
|
||||
void unpack_ModeRequest(IOPMessage const&);
|
||||
|
||||
private:
|
||||
RigMode& mode;
|
||||
CWConfig& cwConfig;
|
||||
Stream& serial;
|
||||
|
||||
void (*prefixCb[NUM_PREFIX_IDS])(void*);
|
||||
void (*messageCb[NUM_MESSAGE_IDS])(void*);
|
||||
TTConfig(RxFilter f): filter(f) {}
|
||||
// parameters
|
||||
RxFilter filter = RX_FILTER_MEDIUM;
|
||||
};
|
||||
*/
|
||||
|
||||
//======================================================================
|
||||
// CW STATUS MESSAGE
|
||||
// FUNCTION PROTOTYPES
|
||||
//======================================================================
|
||||
|
||||
//void packT_DisplayText(TMessage &m, CWConfig const &c)
|
||||
//{
|
||||
// m.id = IOP_CW_STATUS_MSG;
|
||||
// m.len = 3;
|
||||
// m.data[0] = ' '; // growth
|
||||
// m.data[1] = MODE_LETTER[c.mode];
|
||||
// m.data[2] = ' '; // TODO: RX filter width
|
||||
//}
|
||||
void sendCATMessage(const uint8_t*);
|
||||
void sendIOPMessage(IOPMessage const&);
|
||||
void recvIOPMessage(IOPMessage&, const uint8_t*, int);
|
||||
|
||||
// No unpack required: this is a string to put on the display.
|
||||
void sendIOPModeCommand(rig_mode);
|
||||
void sendIOPStartTxCommand();
|
||||
void sendIOPStopTxCommand();
|
||||
void sendIOPDebugMessage(const char*);
|
||||
|
||||
//======================================================================
|
||||
void sendIOPModeRequest();
|
||||
//void sendIOPSSBStatus(SSBConfig const&);
|
||||
//void sendIOPDGTStatus(DGTConfig const&);
|
||||
//void sendIOPCWStatus(CWConfig const&);
|
||||
//void sendIOPTestStatus();
|
||||
void sendIOPMenuDisplay(const char*);
|
||||
void sendIOPMenuInactive();
|
||||
|
||||
#endif
|
||||
|
||||
|
293
ubitx_iop/RigMode.h
Normal file
293
ubitx_iop/RigMode.h
Normal file
@@ -0,0 +1,293 @@
|
||||
//======================================================================
|
||||
// RigMode.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __RigMode_h__
|
||||
#define __RigMode_h__
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
//======================================================================
|
||||
// basic_mode
|
||||
//
|
||||
// A basic rig mode. It can perform actions on_entry() and on_exit(),
|
||||
// as well as on_tx() and on_rx(). These actions are defined in an
|
||||
// appropriate subclass. In addition, the basic mode support an audio
|
||||
// audio band pass filter with wide, medium, and narrow modes.
|
||||
//======================================================================
|
||||
|
||||
class basic_mode {
|
||||
public:
|
||||
|
||||
basic_mode(mode_config& c, RigAudio& a, bp_filter& f) :
|
||||
config_(c), audio_(a), filter_(f), active_(false), transmitting_(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~basic_mode() {}
|
||||
|
||||
inline mode_config& config() { return config_; }
|
||||
|
||||
inline RigAudio& audio() { return audio_; }
|
||||
|
||||
inline bp_filter& filter() { return filter_; }
|
||||
|
||||
// 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.
|
||||
virtual void on_entry() = 0;
|
||||
|
||||
// Called upon mode exit. Should clean everything up that it used,
|
||||
// and not make assumptions about which mode is being entered next.
|
||||
virtual void on_exit() = 0;
|
||||
|
||||
// Called when transmitting.
|
||||
virtual void on_tx() = 0;
|
||||
|
||||
// Called when receiving.
|
||||
virtual void on_rx() = 0;
|
||||
|
||||
inline void enter() {
|
||||
if (active_) {
|
||||
// Do nothing. Exceptions not active (for Arduino, I assume?).
|
||||
//throw MODE_ALREADY_ACTIVE;
|
||||
USBDEBUG("ERROR - tried to enter mode, but it's already active");
|
||||
} else {
|
||||
active_ = true;
|
||||
on_entry();
|
||||
}
|
||||
}
|
||||
|
||||
inline void exit() {
|
||||
if (transmitting_) {
|
||||
// Do nothing. Exceptions not active (for Arduino, I assume?).
|
||||
//throw MODE_STILL_TRANSMITTING;
|
||||
USBDEBUG("ERROR - tried to exit mode, but it's transmitting");
|
||||
} else {
|
||||
active_ = false;
|
||||
on_exit();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_active() { return active_; }
|
||||
inline bool is_inactive() { return !active_; }
|
||||
|
||||
inline void tx() {
|
||||
if (transmitting_) {
|
||||
// Do nothing. Exceptions not active (for Arduino, I assume?).
|
||||
//throw MODE_ALREADY_TRANSMITTING;
|
||||
USBDEBUG("ERROR - tried to start transmitting, but mode already is transmitting");
|
||||
} else {
|
||||
transmitting_ = true;
|
||||
on_tx();
|
||||
}
|
||||
}
|
||||
|
||||
inline void rx() {
|
||||
if (!transmitting_) {
|
||||
// Do nothing. Exceptions not active (for Arduino, I assume?).
|
||||
//throw MODE_NOT_TRANSMITTING;
|
||||
USBDEBUG("ERROR - tried to start receiving, but mode already is receiving");
|
||||
} else {
|
||||
transmitting_ = false;
|
||||
on_rx();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_tx() const { return transmitting_; }
|
||||
inline bool is_rx() const { return !transmitting_; }
|
||||
|
||||
inline void set_rx_filter(rx_filter f) {
|
||||
filter_.disable();
|
||||
config_.filter = f;
|
||||
filter_.init(config_.filter_cfg[static_cast<int>(config_.filter)]);
|
||||
filter_.enable();
|
||||
#if defined(DEBUG)
|
||||
switch(config_.filter) {
|
||||
case rx_filter::wide:
|
||||
USBDEBUG("selected wide filter");
|
||||
break;
|
||||
|
||||
case rx_filter::medium:
|
||||
USBDEBUG("selected medium filter");
|
||||
break;
|
||||
|
||||
case rx_filter::narrow:
|
||||
USBDEBUG("selected narrow filter");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mode_config& config_;
|
||||
RigAudio& audio_;
|
||||
bp_filter& filter_;
|
||||
bool active_;
|
||||
bool transmitting_;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// ssb_mode
|
||||
//======================================================================
|
||||
|
||||
class ssb_mode : public basic_mode
|
||||
{
|
||||
public:
|
||||
|
||||
ssb_mode(ssb_config& c, RigAudio& a, bp_filter& f, speech_comp& s, bool default_mic=true) :
|
||||
basic_mode(c, a, f), use_mic_(default_mic), comp_(s) {}
|
||||
|
||||
virtual void on_entry()
|
||||
{
|
||||
set_rx_filter(config().filter);
|
||||
if (comp_.is_enabled()) {
|
||||
enable_comp();
|
||||
}
|
||||
audio().unmuteRx();
|
||||
audio().muteAllTx();
|
||||
USBDEBUG("SSB mode entered");
|
||||
}
|
||||
|
||||
virtual void on_exit() {
|
||||
audio().muteAllTx();
|
||||
audio().muteRx();
|
||||
disable_comp();
|
||||
USBDEBUG("SSB mode exited");
|
||||
}
|
||||
|
||||
virtual void on_tx()
|
||||
{
|
||||
audio().muteRx();
|
||||
if (use_mic_) {
|
||||
audio().unmuteMicIn();
|
||||
} else {
|
||||
audio().unmuteLineIn();
|
||||
}
|
||||
USBDEBUG("SSB mode transmitting");
|
||||
}
|
||||
|
||||
virtual void on_rx()
|
||||
{
|
||||
if (use_mic_) {
|
||||
audio().muteMicIn();
|
||||
} else {
|
||||
audio().muteLineIn();
|
||||
}
|
||||
audio().unmuteRx();
|
||||
USBDEBUG("SSB mode receiving");
|
||||
}
|
||||
|
||||
void set_mic_in()
|
||||
{
|
||||
if (is_rx()) {
|
||||
// can't switch inputs while already transmitting
|
||||
use_mic_ = true;
|
||||
}
|
||||
USBDEBUG("SSB mode - Mic In set");
|
||||
}
|
||||
|
||||
void set_line_in()
|
||||
{
|
||||
if (is_rx()) {
|
||||
// can't switch inputs while already transmitting
|
||||
use_mic_ = false;
|
||||
}
|
||||
USBDEBUG("SSB mode - Line In set");
|
||||
}
|
||||
|
||||
inline void enable_comp() { comp_.enable(); }
|
||||
inline void disable_comp() { comp_.disable(); }
|
||||
|
||||
private:
|
||||
|
||||
bool use_mic_;
|
||||
speech_comp& comp_;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// digi_mode
|
||||
//======================================================================
|
||||
|
||||
class digi_mode : public basic_mode
|
||||
{
|
||||
public:
|
||||
|
||||
digi_mode(digi_config& c, RigAudio& a, bp_filter& f) :
|
||||
basic_mode(c, a, f) {}
|
||||
|
||||
virtual void on_entry()
|
||||
{
|
||||
set_rx_filter(config().filter);
|
||||
audio().unmuteRx();
|
||||
audio().muteAllTx();
|
||||
USBDEBUG("Digi mode entered");
|
||||
}
|
||||
|
||||
virtual void on_exit() {
|
||||
audio().muteAllTx();
|
||||
audio().muteRx();
|
||||
USBDEBUG("Digi mode exited");
|
||||
}
|
||||
|
||||
virtual void on_tx()
|
||||
{
|
||||
audio().muteRx();
|
||||
audio().unmuteUSBIn();
|
||||
USBDEBUG("Digi mode transmitting");
|
||||
}
|
||||
|
||||
virtual void on_rx()
|
||||
{
|
||||
audio().muteUSBIn();
|
||||
audio().unmuteRx();
|
||||
USBDEBUG("Digi mode receiving");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//======================================================================
|
||||
// cw_mode
|
||||
//======================================================================
|
||||
|
||||
class cw_mode : public basic_mode
|
||||
{
|
||||
public:
|
||||
|
||||
cw_mode(cw_config& c, RigAudio& a, bp_filter& f):
|
||||
basic_mode(c, a, f) {}
|
||||
|
||||
virtual void on_entry()
|
||||
{
|
||||
set_rx_filter(config().filter);
|
||||
audio().unmuteRx();
|
||||
audio().muteAllTx();
|
||||
USBDEBUG("CW mode entered");
|
||||
}
|
||||
|
||||
virtual void on_exit() {
|
||||
audio().muteAllTx();
|
||||
audio().muteRx();
|
||||
USBDEBUG("CW mode exited");
|
||||
}
|
||||
|
||||
virtual void on_tx()
|
||||
{
|
||||
// Currently not muting Rx, since the uBITX produces it's own
|
||||
// sidetone... but I'm probably going to replace that with a S/W-
|
||||
// generated sidetone.
|
||||
USBDEBUG("CW mode transmitting");
|
||||
}
|
||||
|
||||
virtual void on_rx()
|
||||
{
|
||||
USBDEBUG("CW mode receiving");
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
165
ubitx_iop/TxSwitch.h
Normal file
165
ubitx_iop/TxSwitch.h
Normal file
@@ -0,0 +1,165 @@
|
||||
//======================================================================
|
||||
// TxSwitch.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __TxSwitch_h__
|
||||
#define __TxSwitch_h__
|
||||
|
||||
#include <Bounce2.h>
|
||||
#define BOUNCE_WITH_PROMPT_DETECTION
|
||||
|
||||
#include "ubitx_iop.h"
|
||||
#include "rig.h"
|
||||
|
||||
#define MIC_PTT_PIN 21
|
||||
#define LINE_PTT_PIN 20
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ITxSwitch
|
||||
//
|
||||
// Interface for transmit (PTT, Key) switches. onPress() is called
|
||||
// before transmission begins, and should return true if transmission
|
||||
// should start. onRelease() is called before transmission ends, and
|
||||
// should return true if transmission should in fact end.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class ITxSwitch
|
||||
{
|
||||
public:
|
||||
virtual ~ITxSwitch() {}
|
||||
|
||||
// Called before beginning transmit; if false, transmit aborts before starting.
|
||||
virtual bool onPress(basic_mode* m) = 0;
|
||||
|
||||
// Called before stopping tranmit; if false, transmit continues.
|
||||
virtual bool onRelease(basic_mode* m) = 0;
|
||||
|
||||
void press(basic_mode* m, bool output_enable=true) {
|
||||
if (onPress(m)) {
|
||||
USBDEBUG("PTT pressed");
|
||||
m->tx();
|
||||
if (output_enable) {
|
||||
setKeyDown(); // NOTE: could still make this more configurable...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void release(basic_mode* m, bool output_enable=true) {
|
||||
if (onRelease(m)) {
|
||||
USBDEBUG("PTT released");
|
||||
if (output_enable) {
|
||||
setKeyUp(); // NOTE: could still make this more configurable...
|
||||
}
|
||||
m->rx();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// CATSwitch
|
||||
//
|
||||
// Implementation of the ITxSwitch interface for the CAT control. In
|
||||
// general, CAT cannot override any existing transmission, and cannot
|
||||
// terminate an existing transmission.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class CATSwitch : public ITxSwitch
|
||||
{
|
||||
public:
|
||||
CATSwitch(): _transmitting(false) {}
|
||||
|
||||
virtual bool onPress(basic_mode* m) {
|
||||
// If another transmission is already occuring, abort... CAT can't
|
||||
// interrupt transmissions already ongoing.
|
||||
if (m->is_rx()) {
|
||||
USBDEBUG("CAT PTT pressed");
|
||||
_transmitting = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool onRelease(basic_mode* m) {
|
||||
// If CAT transmission is not occurring, abort... CAT can't stop
|
||||
// transmissions initiated by other sources. We don't check if
|
||||
// the mode is already transmitting, because it could be
|
||||
// transmitting because of CAT.
|
||||
if (_transmitting) {
|
||||
USBDEBUG("CAT PTT released");
|
||||
_transmitting = false;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _transmitting; // CAT-specific transmission
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// GPIOSwitch
|
||||
//
|
||||
// Class used to implement the physical transmit switches (i.e. the
|
||||
// Mic and Line input PTTs which are connected to GPIO pins). Takes
|
||||
// an object implementing the ITxSwitch interface, as well as info for
|
||||
// setting up a debounced pin.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class GPIOSwitch : public ITxSwitch
|
||||
{
|
||||
public:
|
||||
GPIOSwitch(bool is_mic, int pin, int msec=25): _is_mic(is_mic), _ssb_mode(false), _bounce() {
|
||||
_bounce.attach(pin, INPUT_PULLUP);
|
||||
_bounce.interval(msec);
|
||||
}
|
||||
|
||||
inline void setSSBMode(bool flag) { _ssb_mode = flag; }
|
||||
|
||||
virtual bool onPress(basic_mode* m) {
|
||||
if (m->is_rx()) {
|
||||
if (_ssb_mode) {
|
||||
if (_is_mic) {
|
||||
USBDEBUG("Mic PTT pressed");
|
||||
((ssb_mode*)m)->set_mic_in();
|
||||
} else {
|
||||
USBDEBUG("Line PTT pressed");
|
||||
((ssb_mode*)m)->set_line_in();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool onRelease(basic_mode* m) {
|
||||
if (m->is_tx()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void update(basic_mode* m, bool output_enable=true) {
|
||||
_bounce.update();
|
||||
|
||||
if (_bounce.fell()) {
|
||||
press(m, output_enable);
|
||||
} else if (_bounce.rose()) {
|
||||
release(m, output_enable);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool _is_mic;
|
||||
bool _ssb_mode;
|
||||
Bounce _bounce;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
@@ -1,40 +1,118 @@
|
||||
//======================================================================
|
||||
// audio.h
|
||||
//
|
||||
// NOTE: Let's change the name of this file to RigAudio.h.
|
||||
//======================================================================
|
||||
|
||||
#ifndef __iop_audio_h__
|
||||
#define __iop_audio_h__
|
||||
|
||||
#include <Audio.h>
|
||||
#include <dynamicFilters.h>
|
||||
#include <effect_compressor_fb.h>
|
||||
#include "config.h"
|
||||
|
||||
enum RxInput {
|
||||
RX_RIG_IN = 0,
|
||||
RX_USB_IN = 1,
|
||||
class RigAudio
|
||||
{
|
||||
public:
|
||||
RigAudio(AudioConfig& c): _config(c) {}
|
||||
|
||||
void init() const;
|
||||
|
||||
void muteRx() const;
|
||||
void unmuteRx() const;
|
||||
|
||||
void muteAllTx() const;
|
||||
|
||||
void muteMicIn() const;
|
||||
void unmuteMicIn() const;
|
||||
|
||||
void muteLineIn() const;
|
||||
void unmuteLineIn() const;
|
||||
|
||||
void muteUSBIn() const;
|
||||
void unmuteUSBIn() const;
|
||||
|
||||
void muteTTIn() const;
|
||||
void unmuteTTIn() const;
|
||||
|
||||
void muteSpkrOut() const;
|
||||
void unmuteSpkrOut() const;
|
||||
|
||||
void muteLineOut() const;
|
||||
void unmuteLineOut() const;
|
||||
|
||||
void muteUSBOut() const;
|
||||
void unmuteUSBOut() const;
|
||||
|
||||
private:
|
||||
AudioConfig _config;
|
||||
};
|
||||
|
||||
enum RxOutput {
|
||||
RX_SPEAKER_OUT = 0,
|
||||
RX_LINE_OUT = 1,
|
||||
RX_USB_OUT = 2,
|
||||
//======================================================================
|
||||
|
||||
class bp_filter {
|
||||
|
||||
public:
|
||||
//bp_filter(double f1, double f2, bool use_center, short int window=-1, short int coeff=-1);
|
||||
bp_filter();
|
||||
bp_filter(AudioFilterFIR& f, AudioAmplifier& a);
|
||||
void init(const bpf_config& cfg);
|
||||
//void init(AudioFilterFIR* filter=NULL, short* coefficients=NULL);
|
||||
void set_band(double f1, double f2);
|
||||
void set_freq_lo(double f);
|
||||
void set_freq_hi(double f);
|
||||
void set_center_and_width(double c, double w);
|
||||
void set_center(double c);
|
||||
void set_width(double w);
|
||||
void set_gain(double g);
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
private:
|
||||
|
||||
double freq_lo;
|
||||
double freq_hi;
|
||||
short int window;
|
||||
short int coeff;
|
||||
float recovery; // recovery amplifier value
|
||||
|
||||
AudioFilterFIR& filter; // = &filterRX;
|
||||
AudioAmplifier& amp;
|
||||
short coefficients[NUM_COEFFICIENTS];
|
||||
bool setup_complete;
|
||||
};
|
||||
|
||||
enum TxInput {
|
||||
TX_MIC_IN = -1,
|
||||
TX_LINE_IN = 0,
|
||||
TX_USB_IN = 1,
|
||||
TX_TEST_IN = 2,
|
||||
//======================================================================
|
||||
|
||||
class speech_comp
|
||||
{
|
||||
public:
|
||||
speech_comp(comp_config* cfg);
|
||||
// speech_comp(AudioEffectCompressor&, AudioAmplifier&, AudioAnalyzeRMS&);
|
||||
void update();
|
||||
void enable();
|
||||
void disable();
|
||||
inline bool is_enabled() const { return config_->enabled; }
|
||||
|
||||
private:
|
||||
comp_config* config_;
|
||||
AudioEffectCompressor& comp_;
|
||||
AudioAmplifier& amp_;
|
||||
AudioAnalyzeRMS& rms_;
|
||||
float env_ = 1.0;
|
||||
float alpha_ = 0.8;
|
||||
};
|
||||
|
||||
enum TxOutput {
|
||||
TX_RIG_OUT = 0,
|
||||
TX_USB_OUT = 1,
|
||||
};
|
||||
//======================================================================
|
||||
|
||||
/*
|
||||
void audioInit();
|
||||
void audioSelectTxInput(TxInput);
|
||||
void audioTransmit();
|
||||
void audioReceive();
|
||||
void audioCalibrate(IOPConfig *, char, char, char, float, bool);
|
||||
void audioCalibrate(AudioConfig *, char, char, char, float, bool);
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,15 +1,34 @@
|
||||
//======================================================================
|
||||
// audio.ino
|
||||
//
|
||||
// NOTE: Let's change the name of this file to Rigconfig.cc. Will need
|
||||
// to ensure that "Arduino-isms" are resolved if it's converted to .cc
|
||||
// from .ino, however.
|
||||
//======================================================================
|
||||
|
||||
#include <dynamicFilters.h>
|
||||
#include <effect_compressor_fb.h>
|
||||
#include "audio.h"
|
||||
|
||||
extern IOPConfig iopConfig;
|
||||
//short firActive[NUM_COEFFICIENTS];
|
||||
|
||||
#define RX_RIG_IN 0
|
||||
#define RX_USB_IN 1
|
||||
#define RX_ST_IN 2 // sidetone
|
||||
|
||||
#define TX_MIC_IN 0
|
||||
#define TX_LINE_IN 0
|
||||
#define TX_USB_IN 1
|
||||
#define TX_TEST_IN 2
|
||||
|
||||
//extern RigConfig rigConfig;
|
||||
|
||||
/*
|
||||
#define DEFAULT_RX_INPUT RIG
|
||||
#define DEFAULT_RX_OUTPUT SPKR
|
||||
#define DEFAULT_TX_INPUT MIC
|
||||
#define DEFAULT_TX_OUTPUT RIG
|
||||
*/
|
||||
|
||||
#include <Audio.h>
|
||||
#include <Wire.h>
|
||||
@@ -18,674 +37,332 @@ extern IOPConfig iopConfig;
|
||||
#include <SerialFlash.h>
|
||||
|
||||
// GUItool: begin automatically generated code
|
||||
AudioSynthWaveformSine sideTone; //xy=204,221
|
||||
AudioInputI2S inLine; //xy=208,170
|
||||
AudioSynthWaveformSine sine2; //xy=207,423
|
||||
AudioInputUSB inUSB; //xy=208,279
|
||||
AudioSynthWaveformSine sine1; //xy=208,382
|
||||
AudioAnalyzeRMS rmsRX; //xy=383,47
|
||||
AudioAnalyzePeak peakRX; //xy=387,98
|
||||
AudioInputI2S inLine; //xy=134,131
|
||||
AudioInputUSB inUSB; //xy=134,303
|
||||
AudioSynthWaveformSine sideTone; //xy=136,214
|
||||
AudioSynthWaveformSine sine2; //xy=323,482
|
||||
AudioSynthWaveformSine sine1; //xy=324,428
|
||||
AudioAnalyzeRMS rmsRX; //xy=362,20
|
||||
AudioAnalyzePeak peakRX; //xy=362,65
|
||||
AudioEffectCompressor compTX; //xy=383,256
|
||||
AudioAnalyzeRMS compRMS; //xy=388,224
|
||||
AudioMixer4 mixRX; //xy=444,163
|
||||
AudioMixer4 mixTX; //xy=444,279
|
||||
AudioAmplifier calRxUSB; //xy=634,165
|
||||
AudioAmplifier calRxSpkr; //xy=638,55
|
||||
AudioAmplifier calRxLine; //xy=641,112
|
||||
AudioAmplifier calTxLine; //xy=653,248
|
||||
AudioAmplifier calTxUSB; //xy=654,305
|
||||
AudioAnalyzePeak peakTX; //xy=669,378
|
||||
AudioAnalyzeRMS rmsTX; //xy=683,433
|
||||
AudioOutputAnalog outSpkr; //xy=814,55
|
||||
AudioOutputUSB outUSB; //xy=823,255
|
||||
AudioOutputI2S outLine; //xy=826,204
|
||||
AudioConnection patchCord1(sideTone, 0, mixRX, 2);
|
||||
AudioConnection patchCord2(inLine, 0, rmsRX, 0);
|
||||
AudioConnection patchCord3(inLine, 0, peakRX, 0);
|
||||
AudioConnection patchCord4(inLine, 0, mixRX, 0);
|
||||
AudioConnection patchCord5(inLine, 1, mixTX, 0);
|
||||
AudioConnection patchCord6(sine2, 0, mixTX, 3);
|
||||
AudioConnection patchCord7(inUSB, 0, mixRX, 1);
|
||||
AudioConnection patchCord8(inUSB, 1, mixTX, 1);
|
||||
AudioConnection patchCord9(sine1, 0, mixTX, 2);
|
||||
AudioConnection patchCord10(mixRX, calRxSpkr);
|
||||
AudioConnection patchCord11(mixRX, calRxLine);
|
||||
AudioConnection patchCord12(mixRX, calRxUSB);
|
||||
AudioConnection patchCord13(mixTX, calTxLine);
|
||||
AudioConnection patchCord14(mixTX, calTxUSB);
|
||||
AudioConnection patchCord15(mixTX, peakTX);
|
||||
AudioConnection patchCord16(mixTX, rmsTX);
|
||||
AudioConnection patchCord17(calRxUSB, 0, outUSB, 0);
|
||||
AudioConnection patchCord18(calRxSpkr, outSpkr);
|
||||
AudioConnection patchCord19(calRxLine, 0, outLine, 0);
|
||||
AudioConnection patchCord20(calTxLine, 0, outLine, 1);
|
||||
AudioConnection patchCord21(calTxUSB, 0, outUSB, 1);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=391,443
|
||||
AudioAmplifier compAmp; //xy=514,257
|
||||
AudioFilterFIR filterRX; //xy=577,161
|
||||
AudioMixer4 mixTX; //xy=652,321
|
||||
AudioAmplifier filterAmp; //xy=700,160
|
||||
AudioAnalyzeRMS rmsTX; //xy=841,449
|
||||
AudioAnalyzePeak peakTX; //xy=843,393
|
||||
AudioAmplifier calRxUSB; //xy=873,172
|
||||
AudioAmplifier calRxSpkr; //xy=877,62
|
||||
AudioAmplifier calRxLine; //xy=880,119
|
||||
AudioAmplifier calTxLine; //xy=892,255
|
||||
AudioAmplifier calTxUSB; //xy=893,312
|
||||
AudioOutputAnalog outSpkr; //xy=1053,62
|
||||
AudioOutputUSB outUSB; //xy=1066,307
|
||||
AudioOutputI2S outLine; //xy=1070,192
|
||||
AudioConnection patchCord1(inLine, 0, rmsRX, 0);
|
||||
AudioConnection patchCord2(inLine, 0, peakRX, 0);
|
||||
AudioConnection patchCord3(inLine, 0, mixRX, 0);
|
||||
AudioConnection patchCord4(inLine, 1, compTX, 0);
|
||||
AudioConnection patchCord5(inLine, 1, compRMS, 0);
|
||||
AudioConnection patchCord6(inUSB, 0, mixRX, 1);
|
||||
AudioConnection patchCord7(inUSB, 1, mixTX, 1);
|
||||
AudioConnection patchCord8(sideTone, 0, mixRX, 2);
|
||||
AudioConnection patchCord9(sine2, 0, mixTX, 3);
|
||||
AudioConnection patchCord10(sine1, 0, mixTX, 2);
|
||||
AudioConnection patchCord11(compTX, compAmp);
|
||||
AudioConnection patchCord12(mixRX, filterRX);
|
||||
AudioConnection patchCord13(compAmp, 0, mixTX, 0);
|
||||
AudioConnection patchCord14(filterRX, filterAmp);
|
||||
AudioConnection patchCord15(mixTX, calTxLine);
|
||||
AudioConnection patchCord16(mixTX, calTxUSB);
|
||||
AudioConnection patchCord17(mixTX, peakTX);
|
||||
AudioConnection patchCord18(mixTX, rmsTX);
|
||||
AudioConnection patchCord19(filterAmp, calRxSpkr);
|
||||
AudioConnection patchCord20(filterAmp, calRxLine);
|
||||
AudioConnection patchCord21(filterAmp, calRxUSB);
|
||||
AudioConnection patchCord22(calRxUSB, 0, outUSB, 0);
|
||||
AudioConnection patchCord23(calRxSpkr, outSpkr);
|
||||
AudioConnection patchCord24(calRxLine, 0, outLine, 0);
|
||||
AudioConnection patchCord25(calTxLine, 0, outLine, 1);
|
||||
AudioConnection patchCord26(calTxUSB, 0, outUSB, 1);
|
||||
AudioControlSGTL5000 audioCtrl; //xy=648,517
|
||||
// GUItool: end automatically generated code
|
||||
|
||||
RxInput audioRxInput;
|
||||
RxOutput audioRxOutput;
|
||||
TxInput audioTxInput;
|
||||
TxOutput audioTxOutput;
|
||||
|
||||
// audioInit()
|
||||
// Setup the audio subsystem.
|
||||
void audioInit()
|
||||
{
|
||||
void RigAudio::init() const {
|
||||
USBDEBUG("audio initialization started");
|
||||
|
||||
audioCtrl.enable();
|
||||
audioCtrl.adcHighPassFilterEnable(); // default
|
||||
audioCtrl.dacVolume(1.0); // default
|
||||
audioCtrl.dacVolumeRampDisable(); // not default; just trying to cull out culprits for my high freq hiss
|
||||
audioCtrl.audioProcessorDisable();
|
||||
audioCtrl.autoVolumeDisable();
|
||||
audioCtrl.surroundSoundDisable();
|
||||
audioCtrl.enhanceBassDisable();
|
||||
audioCtrl.eqSelect(FLAT_FREQUENCY); // eventually, use this to smooth out the normal uBITX passband
|
||||
|
||||
audioCtrl.muteHeadphone(); // not using the headphone output
|
||||
audioCtrl.volume(0.0); // not using the headphone output
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN); // required for RX audio
|
||||
audioCtrl.unmuteLineout(); // required for RX audio
|
||||
audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
|
||||
audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
|
||||
audioCtrl.micGain(iopConfig.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason
|
||||
//audioCtrl.dacVolumeRamp(); // if this seems too slow, might try dacVolumeRampLinear().
|
||||
//audioCtrl.dacVolume(1.0, 0.0); // we're going to mute TX audio via the DAC unless we're transmitting
|
||||
|
||||
updateRxRigIn();
|
||||
updateRxSpkrOut();
|
||||
updateRxLineOut();
|
||||
updateRxUSBOut();
|
||||
|
||||
// Note - these really just need to be init functions; keep things muted while setting them up.
|
||||
updateTxMicIn();
|
||||
updateTxLineIn();
|
||||
updateTxUSBIn();
|
||||
updateTxTwoToneIn();
|
||||
|
||||
updateTxRigOut();
|
||||
|
||||
audioSelectRxInput(RX_RIG_IN);
|
||||
audioSelectTxInput(TX_MIC_IN); // superfluous I think
|
||||
audioCtrl.lineInLevel(_config.rxRigInLevel, _config.txLineInLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
|
||||
audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel); // NOTE: need to see if this persists through input changes (see mic gain...)
|
||||
audioCtrl.micGain(_config.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason
|
||||
|
||||
//audioCtrl.adcHighPassFilterDisable();
|
||||
audioCtrl.audioPreProcessorEnable();
|
||||
// configure line input
|
||||
audioCtrl.lineInLevel(_config.rxRigInLevel, _config.txLineInLevel);
|
||||
|
||||
// configure line output
|
||||
calTxLine.gain(_config.txRigOutCal);
|
||||
audioCtrl.lineOutLevel(_config.rxLineOutLevel, _config.txRigOutLevel);
|
||||
|
||||
// configure "receive" of USB audio input (debug only)
|
||||
if (_config.rxUSBInEnable) {
|
||||
mixRX.gain(RX_USB_IN, _config.rxUSBInVol * _config.rxUSBInCal);
|
||||
} else {
|
||||
mixRX.gain(RX_USB_IN, 0.0);
|
||||
}
|
||||
|
||||
// configure USB audio output of transmit audio (useful for debug)
|
||||
if (_config.txUSBOutEnable) {
|
||||
calTxUSB.gain(_config.txUSBOutCal);
|
||||
} else {
|
||||
calTxUSB.gain(0.0);
|
||||
}
|
||||
|
||||
// setup the two-tone generator
|
||||
sine1.frequency(700);
|
||||
sine2.frequency(1900);
|
||||
sine1.amplitude(0);
|
||||
sine2.amplitude(0);
|
||||
}
|
||||
|
||||
inline void updateRxRigIn()
|
||||
{
|
||||
audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel);
|
||||
mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal);
|
||||
}
|
||||
//audioFilter(firActive, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, 300.0, 3100.0); // 2.8 kHz filter
|
||||
//filterRX.begin(firActive, NUM_COEFFICIENTS);
|
||||
filterAmp.gain(1.0);
|
||||
|
||||
inline void muteRxRigIn()
|
||||
{
|
||||
mixRX.gain(RX_RIG_IN, 0.0);
|
||||
}
|
||||
// for now, just pass through the compressor
|
||||
compTX.disable();
|
||||
compAmp.gain(1.0);
|
||||
|
||||
inline void restoreRxRigIn()
|
||||
{
|
||||
mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal);
|
||||
}
|
||||
|
||||
inline void updateRxUSBIn()
|
||||
{
|
||||
if (iopConfig.rxUSBInEnable) {
|
||||
mixRX.gain(RX_USB_IN, iopConfig.rxUSBInVol * iopConfig.rxUSBInCal);
|
||||
} else {
|
||||
mixRX.gain(RX_USB_IN, 0.0);
|
||||
// Hardware should be all setup... now we're going to mute everything
|
||||
// and let the modes take care of enabling/disabling what they should.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mixRX.gain(i, 0.0);
|
||||
mixTX.gain(i, 0.0);
|
||||
}
|
||||
|
||||
audioEqualizer();
|
||||
|
||||
USBDEBUG("audio initialization completed");
|
||||
}
|
||||
|
||||
inline void muteRxUSBIn()
|
||||
{
|
||||
mixRX.gain(RX_USB_IN, 0.0);
|
||||
void RigAudio::muteRx() const {
|
||||
mixRX.gain(RX_RIG_IN, 0.0);
|
||||
USBDEBUG("RX audio muted");
|
||||
}
|
||||
|
||||
inline void restoreRxUSBIn()
|
||||
{
|
||||
updateRxUSBIn();
|
||||
void RigAudio::unmuteRx() const {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
mixRX.gain(RX_RIG_IN, _config.rxRigInVol * _config.rxRigInCal);
|
||||
USBDEBUG("RX audio unmuted");
|
||||
}
|
||||
|
||||
inline void updateRxSpkrOut()
|
||||
{
|
||||
calRxSpkr.gain(iopConfig.rxSpkrOutCal);
|
||||
void RigAudio::muteAllTx() const {
|
||||
muteMicIn();
|
||||
muteLineIn();
|
||||
muteUSBIn();
|
||||
muteTTIn();
|
||||
USBDEBUG("all TX audio muted");
|
||||
}
|
||||
|
||||
inline void updateRxLineOut()
|
||||
{
|
||||
calRxLine.gain(iopConfig.rxLineOutCal);
|
||||
audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel);
|
||||
}
|
||||
|
||||
inline void updateRxUSBOut()
|
||||
{
|
||||
calRxUSB.gain(iopConfig.rxUSBOutCal);
|
||||
}
|
||||
|
||||
inline void updateTxMicIn()
|
||||
{
|
||||
audioCtrl.micGain(iopConfig.txMicInGain);
|
||||
mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal);
|
||||
}
|
||||
|
||||
inline void muteTxMicIn()
|
||||
{
|
||||
void RigAudio::muteMicIn() const {
|
||||
mixTX.gain(TX_LINE_IN, 0.0);
|
||||
USBDEBUG("Mic In audio muted");
|
||||
}
|
||||
|
||||
inline void restoreTxMicIn()
|
||||
{
|
||||
mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal);
|
||||
void RigAudio::unmuteMicIn() const {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||
audioCtrl.micGain(_config.txMicInGain);
|
||||
mixTX.gain(TX_LINE_IN, _config.txMicInVol * _config.txMicInCal);
|
||||
USBDEBUG("Mic In audio unmuted");
|
||||
}
|
||||
|
||||
inline void updateTxLineIn()
|
||||
{
|
||||
audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel);
|
||||
mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal);
|
||||
}
|
||||
|
||||
inline void muteTxLineIn()
|
||||
{
|
||||
void RigAudio::muteLineIn() const {
|
||||
mixTX.gain(TX_LINE_IN, 0.0);
|
||||
USBDEBUG("Line In audio muted");
|
||||
}
|
||||
|
||||
inline void restoreTxLineIn()
|
||||
{
|
||||
mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal);
|
||||
void RigAudio::unmuteLineIn() const {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
mixTX.gain(TX_LINE_IN, _config.txLineInVol * _config.txLineInCal);
|
||||
USBDEBUG("Line In audio unmuted");
|
||||
}
|
||||
|
||||
inline void updateTxUSBIn()
|
||||
{
|
||||
mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal);
|
||||
}
|
||||
|
||||
inline void muteTxUSBIn()
|
||||
{
|
||||
void RigAudio::muteUSBIn() const {
|
||||
mixTX.gain(TX_USB_IN, 0.0);
|
||||
USBDEBUG("USB In audio muted");
|
||||
}
|
||||
void RigAudio::unmuteUSBIn() const {
|
||||
mixTX.gain(TX_USB_IN, _config.txUSBInVol * _config.txUSBInCal);
|
||||
USBDEBUG("USB In audio unmuted");
|
||||
}
|
||||
|
||||
inline void restoreTxUSBIn()
|
||||
{
|
||||
mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal);
|
||||
}
|
||||
|
||||
inline void updateTxTwoToneIn()
|
||||
{
|
||||
sine1.amplitude(0.5);
|
||||
sine2.amplitude(0.5);
|
||||
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
|
||||
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
|
||||
}
|
||||
|
||||
inline void muteTxTwoToneIn()
|
||||
{
|
||||
void RigAudio::muteTTIn() const {
|
||||
mixTX.gain(TX_TEST_IN, 0.0);
|
||||
mixTX.gain(TX_TEST_IN + 1, 0.0);
|
||||
sine1.amplitude(0);
|
||||
sine2.amplitude(0);
|
||||
sine1.amplitude(0.0);
|
||||
sine2.amplitude(0.0);
|
||||
USBDEBUG("Two Tone audio muted");
|
||||
}
|
||||
|
||||
inline void restoreTxTwoToneIn()
|
||||
{
|
||||
void RigAudio::unmuteTTIn() const {
|
||||
sine1.amplitude(0.5);
|
||||
sine2.amplitude(0.5);
|
||||
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
|
||||
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
|
||||
mixTX.gain(TX_TEST_IN, _config.txSine1Vol);
|
||||
mixTX.gain(TX_TEST_IN + 1, _config.txSine2Vol);
|
||||
USBDEBUG("Two Tone audio unmuted");
|
||||
}
|
||||
|
||||
inline void updateTxRigOut()
|
||||
{
|
||||
calTxLine.gain(iopConfig.txRigOutCal);
|
||||
audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel);
|
||||
void RigAudio::muteSpkrOut() const {
|
||||
calRxSpkr.gain(0.0);
|
||||
USBDEBUG("Speaker Out audio muted");
|
||||
}
|
||||
|
||||
inline void updateTxUSBOut()
|
||||
{
|
||||
if (iopConfig.txUSBOutEnable) {
|
||||
calTxUSB.gain(iopConfig.txUSBOutCal);
|
||||
} else {
|
||||
calTxUSB.gain(0.0);
|
||||
}
|
||||
void RigAudio::unmuteSpkrOut() const {
|
||||
calRxSpkr.gain(_config.rxSpkrOutCal);
|
||||
USBDEBUG("Speaker Out audio unmuted");
|
||||
}
|
||||
|
||||
void audioSelectRxInput(RxInput input)
|
||||
{
|
||||
if (audioRxInput != input) {
|
||||
audioRxInput = input;
|
||||
switch(input) {
|
||||
case RX_RIG_IN:
|
||||
muteRxUSBIn();
|
||||
restoreRxRigIn();
|
||||
mixRX.gain(2, 0);
|
||||
mixRX.gain(3, 0);
|
||||
break;
|
||||
|
||||
case RX_USB_IN:
|
||||
muteRxRigIn();
|
||||
restoreRxUSBIn();
|
||||
mixRX.gain(2, 0);
|
||||
mixRX.gain(3, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void RigAudio::muteLineOut() const {
|
||||
calRxLine.gain(0.0);
|
||||
USBDEBUG("Line Out audio muted");
|
||||
}
|
||||
|
||||
void audioSelectTxInput(TxInput input)
|
||||
void RigAudio::unmuteLineOut() const {
|
||||
calRxLine.gain(_config.rxLineOutCal);
|
||||
USBDEBUG("Line Out audio unmuted");
|
||||
}
|
||||
|
||||
void RigAudio::muteUSBOut() const {
|
||||
calRxUSB.gain(0.0);
|
||||
USBDEBUG("USB Out audio muted");
|
||||
}
|
||||
|
||||
void RigAudio::unmuteUSBOut() const {
|
||||
calRxUSB.gain(_config.rxUSBOutCal);
|
||||
USBDEBUG("USB Out audio unmuted");
|
||||
}
|
||||
|
||||
/*
|
||||
RxInput audioRxInput;
|
||||
RxOutput audioRxOutput;
|
||||
TxInput audioTxInput;
|
||||
TxOutput audioTxOutput;
|
||||
*/
|
||||
|
||||
//======================================================================
|
||||
// bp_filter
|
||||
//
|
||||
// Band Pass Filter methods.
|
||||
//======================================================================
|
||||
|
||||
bp_filter::bp_filter(): filter(filterRX), amp(filterAmp) {}
|
||||
|
||||
bp_filter::bp_filter(AudioFilterFIR& f, AudioAmplifier& a): filter(f), amp(a) {}
|
||||
|
||||
void bp_filter::init(const bpf_config& cfg) {
|
||||
set_band(cfg.lo_freq, cfg.hi_freq);
|
||||
set_gain(cfg.gain);
|
||||
}
|
||||
|
||||
void bp_filter::set_band(double f1, double f2) {
|
||||
freq_lo = f1;
|
||||
freq_hi = f2;
|
||||
}
|
||||
|
||||
void bp_filter::set_freq_lo(double f) { freq_lo = f; }
|
||||
|
||||
void bp_filter::set_freq_hi(double f) { freq_hi = f; }
|
||||
|
||||
void bp_filter::set_center_and_width(double c, double w) {
|
||||
freq_lo = c - (0.5 * w);
|
||||
freq_hi = c + (0.5 * w);
|
||||
}
|
||||
|
||||
void bp_filter::set_center(double c) {
|
||||
double w = freq_hi - freq_lo;
|
||||
set_center_and_width(c, w);
|
||||
}
|
||||
|
||||
void bp_filter::set_width(double w) {
|
||||
double c = (freq_lo + freq_hi) * 0.5;
|
||||
set_center_and_width(c, w);
|
||||
}
|
||||
|
||||
void bp_filter::set_gain(double g) { recovery = g; }
|
||||
|
||||
void bp_filter::enable() {
|
||||
audioFilter(coefficients, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, freq_lo, freq_hi);
|
||||
filter.begin(coefficients, NUM_COEFFICIENTS);
|
||||
amp.gain(recovery);
|
||||
}
|
||||
|
||||
void bp_filter::disable() {
|
||||
filter.begin(FIR_PASSTHRU, NUM_COEFFICIENTS);
|
||||
amp.gain(1.0);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
speech_comp::speech_comp(comp_config* cfg) :
|
||||
config_(cfg), comp_(compTX), amp_(compAmp), rms_(compRMS) {}
|
||||
|
||||
void speech_comp::enable()
|
||||
{
|
||||
if (audioTxInput != input) {
|
||||
audioTxInput = input;
|
||||
//muteTxMicIn(); // redundant w/ Line-In
|
||||
muteTxLineIn();
|
||||
muteTxUSBIn();
|
||||
muteTxTwoToneIn();
|
||||
/* switch(input) {
|
||||
case TX_MIC_IN:
|
||||
muteTxUSBIn();
|
||||
restoreTxMicIn();
|
||||
break;
|
||||
|
||||
case TX_LINE_IN:
|
||||
muteTxUSBIn();
|
||||
restoreTxLineIn();
|
||||
break;
|
||||
|
||||
case TX_USB_IN:
|
||||
muteTxLineIn();
|
||||
restoreTxUSBIn();
|
||||
break;
|
||||
}*/
|
||||
config_->enabled = true;
|
||||
comp_.begin(1, config_->threshold, config_->ratio); // Need to make configurable
|
||||
amp_.gain(config_->gain);
|
||||
}
|
||||
|
||||
void speech_comp::disable()
|
||||
{
|
||||
config_->enabled = false;
|
||||
comp_.disable();
|
||||
amp_.gain(1.0);
|
||||
}
|
||||
|
||||
// Speech compressor code based on post by 'hyperdyne': https://forum.pjrc.com/threads/36245-Changing-Pitch-of-Voice
|
||||
|
||||
void speech_comp::update()
|
||||
{
|
||||
float rms_cur;
|
||||
if (config_->enabled && rms_.available()) {
|
||||
rms_cur = rms_.read();
|
||||
env_ = rms_cur + (alpha_ * (env_ - rms_cur));
|
||||
comp_.update_pwr(env_);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
// audioTransmit()
|
||||
// This should be called anytime transmit mode is entered. It should
|
||||
// in theory be called BEFORE the actual transmit signal (key/PTT) is
|
||||
// sent to the Raduino, in order to ensure that any audio source
|
||||
// transitions occur before transmission begins.
|
||||
void audioTransmit()
|
||||
{
|
||||
switch(rigMode) {
|
||||
// Nothing special for CW, TX audio inputs are already muted.
|
||||
//case MODE_CW:
|
||||
//break;
|
||||
|
||||
case MODE_SSB:
|
||||
// Mute the incoming RX audio. Can't think of a good reason
|
||||
// to let RX audio in while we're transmitting.
|
||||
muteRxRigIn();
|
||||
|
||||
if (audioTxInput == TX_MIC_IN) {
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||
updateTxMicIn();
|
||||
#if defined(FACTORY_CALIBRATION)
|
||||
USBSERIAL.println("==============================");
|
||||
USBSERIAL.println("Transmitting with Mic input");
|
||||
USBSERIAL.print("Mic gain: ");
|
||||
USBSERIAL.println(iopConfig.txMicInGain);
|
||||
USBSERIAL.print("Mic volume: ");
|
||||
USBSERIAL.println(iopConfig.txMicInVol);
|
||||
USBSERIAL.print("Mic calibration: ");
|
||||
USBSERIAL.println(iopConfig.txMicInCal);
|
||||
USBSERIAL.print("TX audio level: ");
|
||||
USBSERIAL.println(iopConfig.txRigOutLevel);
|
||||
USBSERIAL.print("TX audio calibration: ");
|
||||
USBSERIAL.println(iopConfig.txRigOutCal);
|
||||
USBSERIAL.println("==============================");
|
||||
#endif
|
||||
} else if (audioTxInput == TX_LINE_IN) {
|
||||
updateTxLineIn();
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// Mute the incoming RX audio. Can't think of a good reason
|
||||
// to let RX audio in while we're transmitting.
|
||||
muteRxRigIn();
|
||||
updateTxUSBIn();
|
||||
break;
|
||||
|
||||
case MODE_TEST:
|
||||
muteRxRigIn();
|
||||
updateTxTwoToneIn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
// audioReceive()
|
||||
// This should be called anytime receive mode is entered. It should
|
||||
// in theory be called AFTER the actual transmit signal (key/PTT) is
|
||||
// removed from the Raduino, in order to ensure that any audio source
|
||||
// transitions occur before receive begins.
|
||||
void audioReceive()
|
||||
{
|
||||
switch(rigMode) {
|
||||
//case MODE_CW:
|
||||
//break;
|
||||
|
||||
case MODE_SSB:
|
||||
if (audioTxInput == TX_MIC_IN) {
|
||||
muteTxMicIn();
|
||||
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||
} else if (audioTxInput == TX_LINE_IN) {
|
||||
muteTxLineIn();
|
||||
}
|
||||
restoreRxRigIn();
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
muteTxUSBIn();
|
||||
restoreRxRigIn();
|
||||
break;
|
||||
|
||||
case MODE_TEST:
|
||||
muteTxTwoToneIn();
|
||||
restoreRxRigIn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void audioCalibrate(IOPConfig* c, char cmd, char subcmd, char parm, float value, bool set_value=true)
|
||||
{
|
||||
switch(cmd) {
|
||||
case 'r':
|
||||
case 'R':
|
||||
// RX audio parameters
|
||||
switch(subcmd) {
|
||||
case 'r':
|
||||
case 'R':
|
||||
// Rig input
|
||||
switch(parm) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
// level
|
||||
if (set_value) {
|
||||
c->rxRigInLevel = int(value);
|
||||
updateRxRigIn();
|
||||
}
|
||||
USBSERIAL.print("rxRigInLevel: ");
|
||||
USBSERIAL.println(c->rxRigInLevel);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
// volume
|
||||
if (set_value) {
|
||||
c->rxRigInVol = value;
|
||||
updateRxRigIn();
|
||||
}
|
||||
USBSERIAL.print("rxRigInVol: ");
|
||||
USBSERIAL.println(c->rxRigInVol);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->rxRigInCal = value;
|
||||
updateRxRigIn();
|
||||
}
|
||||
USBSERIAL.print("rxRigInCal: ");
|
||||
USBSERIAL.println(c->rxRigInCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
case 'S':
|
||||
// Speaker output
|
||||
switch(parm) {
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->rxSpkrOutCal = value;
|
||||
updateRxSpkrOut();
|
||||
}
|
||||
USBSERIAL.print("rxSpkrOutCal: ");
|
||||
USBSERIAL.println(c->rxSpkrOutCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'L':
|
||||
// Line output
|
||||
switch(parm) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
// level
|
||||
if (set_value) {
|
||||
c->rxLineOutLevel = int(value);
|
||||
updateRxLineOut();
|
||||
}
|
||||
USBSERIAL.print("rxLineOutLevel: ");
|
||||
USBSERIAL.println(c->rxLineOutLevel);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->rxLineOutCal = value;
|
||||
updateRxLineOut();
|
||||
}
|
||||
USBSERIAL.print("rxLineOutCal: ");
|
||||
USBSERIAL.println(c->rxLineOutCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
// USB output
|
||||
switch(parm) {
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->rxUSBOutCal = value;
|
||||
updateRxUSBOut();
|
||||
}
|
||||
USBSERIAL.print("rxUSBOutCal: ");
|
||||
USBSERIAL.println(c->rxUSBOutCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
case 'T':
|
||||
//TX audio parameters
|
||||
switch(subcmd) {
|
||||
case 'm':
|
||||
case 'M':
|
||||
// Mic input
|
||||
switch(parm) {
|
||||
case 'g':
|
||||
case 'G':
|
||||
// mic gain
|
||||
if (set_value) {
|
||||
c->txMicInGain = int(value);
|
||||
updateTxMicIn();
|
||||
}
|
||||
USBSERIAL.print("txMicInGain: ");
|
||||
USBSERIAL.println(c->txMicInGain);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
// volume
|
||||
if (set_value) {
|
||||
c->txMicInVol = value;
|
||||
updateTxMicIn();
|
||||
}
|
||||
USBSERIAL.print("txMicInVol: ");
|
||||
USBSERIAL.println(c->txMicInVol);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->txMicInCal = value;
|
||||
updateTxMicIn();
|
||||
}
|
||||
USBSERIAL.print("txMicInCal: ");
|
||||
USBSERIAL.println(c->txMicInCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'L':
|
||||
// Line input
|
||||
switch(parm) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
// level
|
||||
if (set_value) {
|
||||
c->txLineInLevel = int(value);
|
||||
updateTxLineIn();
|
||||
}
|
||||
USBSERIAL.print("txLineInLevel: ");
|
||||
USBSERIAL.println(c->txLineInLevel);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
// volume
|
||||
if (set_value) {
|
||||
c->txLineInVol = value;
|
||||
updateTxLineIn();
|
||||
}
|
||||
USBSERIAL.print("txLineInVol: ");
|
||||
USBSERIAL.println(c->txLineInVol);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->txLineInCal = value;
|
||||
updateTxLineIn();
|
||||
}
|
||||
USBSERIAL.print("txLineInCal: ");
|
||||
USBSERIAL.println(c->txLineInCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
// USB input
|
||||
switch(parm) {
|
||||
case 'v':
|
||||
case 'V':
|
||||
// volume
|
||||
if (set_value) {
|
||||
c->txUSBInVol = value;
|
||||
updateTxUSBIn();
|
||||
}
|
||||
USBSERIAL.print("txUSBInVol: ");
|
||||
USBSERIAL.println(c->txUSBInVol);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->txUSBInCal = value;
|
||||
updateTxUSBIn();
|
||||
}
|
||||
USBSERIAL.print("txUSBInCal: ");
|
||||
USBSERIAL.println(c->txUSBInCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
case 'R':
|
||||
// Rig output
|
||||
switch(parm) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
// level
|
||||
if (set_value) {
|
||||
c->txRigOutLevel = int(value);
|
||||
updateTxRigOut();
|
||||
}
|
||||
USBSERIAL.print("txRigOutLevel: ");
|
||||
USBSERIAL.println(c->txRigOutLevel);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
case 'C':
|
||||
// calibration
|
||||
if (set_value) {
|
||||
c->txRigOutCal = value;
|
||||
updateTxRigOut();
|
||||
}
|
||||
USBSERIAL.print("txRigOutCal: ");
|
||||
USBSERIAL.println(c->txRigOutCal);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int lpFilter[5];
|
||||
int hpFilter[5];
|
||||
|
||||
void audioSSBFilter()
|
||||
int eqFilter1[5];
|
||||
|
||||
void audioEqualizer()
|
||||
{
|
||||
audioCtrl.audioPreProcessorEnable();
|
||||
audioCtrl.eqSelect(PARAMETRIC_EQUALIZER);
|
||||
// calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*);
|
||||
calcBiquad(FILTER_LOPASS, 3300, 0, 0.707, 524288, 44100, lpFilter);
|
||||
calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
||||
audioCtrl.eqFilter(0, lpFilter);
|
||||
audioCtrl.eqFilter(1, hpFilter);
|
||||
audioCtrl.eqFilter(2, lpFilter);
|
||||
audioCtrl.eqFilter(3, hpFilter);
|
||||
audioCtrl.eqFilter(4, lpFilter);
|
||||
audioCtrl.eqFilter(5, hpFilter);
|
||||
}
|
||||
|
||||
void audioCWFilter()
|
||||
{
|
||||
// calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*);
|
||||
calcBiquad(FILTER_LOPASS, 1300, 0, 0.707, 524288, 44100, lpFilter);
|
||||
calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
||||
audioCtrl.eqFilter(0, lpFilter);
|
||||
audioCtrl.eqFilter(1, hpFilter);
|
||||
audioCtrl.eqFilter(2, lpFilter);
|
||||
audioCtrl.eqFilter(3, hpFilter);
|
||||
audioCtrl.eqFilter(4, lpFilter);
|
||||
audioCtrl.eqFilter(5, hpFilter);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// audioDigiFilter()
|
||||
// Create a very wide filter for digital modes... wider than the uBITX
|
||||
// needs, but just want to make sure we leave the full audio bandwidth
|
||||
// open for digimodes, while ensuring we've cut down any extraneous
|
||||
// noise outside the normal band.
|
||||
//======================================================================
|
||||
|
||||
void audioDigiFilter()
|
||||
{
|
||||
// calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*);
|
||||
calcBiquad(FILTER_LOPASS, 5000, 0, 0.707, 524288, 44100, lpFilter);
|
||||
calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
||||
audioCtrl.eqFilter(0, lpFilter);
|
||||
audioCtrl.eqFilter(1, hpFilter);
|
||||
audioCtrl.eqFilter(2, lpFilter);
|
||||
audioCtrl.eqFilter(3, hpFilter);
|
||||
audioCtrl.eqFilter(4, lpFilter);
|
||||
audioCtrl.eqFilter(5, hpFilter);
|
||||
calcBiquad(FILTER_PARAEQ, 2700, 6, 0.707, 524288, 44100, eqFilter1);
|
||||
// calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
||||
audioCtrl.eqFilter(0, eqFilter1);
|
||||
// audioCtrl.eqFilter(1, hpFilter);
|
||||
// audioCtrl.eqFilter(2, lpFilter);
|
||||
// audioCtrl.eqFilter(3, hpFilter);
|
||||
// audioCtrl.eqFilter(4, lpFilter);
|
||||
// audioCtrl.eqFilter(5, hpFilter);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
@@ -3,11 +3,17 @@
|
||||
//======================================================================
|
||||
|
||||
#include "cat.h"
|
||||
#include "TxSwitch.h"
|
||||
|
||||
// make these messages static inside a function
|
||||
IOPMessage inBuf; // input message buffer
|
||||
IOPMessage outBuf; // output message buffer
|
||||
|
||||
extern CATSwitch catPTT;
|
||||
extern basic_rig rig;
|
||||
|
||||
int received_mode = 0;
|
||||
|
||||
//======================================================================
|
||||
// CAT from PC-to-IOP
|
||||
//
|
||||
@@ -30,16 +36,12 @@ void initCAT(long baud, int portConfig)
|
||||
// CAT with PC via USB
|
||||
USBSERIAL.begin(baud);
|
||||
USBSERIAL.flush();
|
||||
#if defined(DEBUG)
|
||||
USBSERIAL.println("IOP: opened USB serial port (to PC)");
|
||||
#endif
|
||||
USBDEBUG("opened USB serial port (to PC)");
|
||||
|
||||
// Comm (including CAT passthru) with Raduino via UART
|
||||
HWSERIAL.begin(baud, portConfig);
|
||||
HWSERIAL.flush();
|
||||
#if defined(DEBUG)
|
||||
USBSERIAL.println("IOP: opened H/W serial port (to Raduino)");
|
||||
#endif
|
||||
USBDEBUG("opened H/W serial port (to Raduino)");
|
||||
|
||||
//sendIOPModeRequest(); // Raduino doesn't support this yet
|
||||
}
|
||||
@@ -50,40 +52,47 @@ void processIOPCommand(IOPMessage const& m)
|
||||
{
|
||||
switch(inBuf.id) {
|
||||
case IOP_MODE_COMMAND:
|
||||
received_mode = 2;
|
||||
USBDEBUG("IOP_MODE_COMMAND received (from Raduino)");
|
||||
if (m.len < 1) {
|
||||
return;
|
||||
} else {
|
||||
setRigMode(m.data[0]);
|
||||
rig.set_rig_mode(static_cast<rig_mode>(m.data[0]));
|
||||
#if defined(DEBUG)
|
||||
switch(rigMode) {
|
||||
case MODE_CW:
|
||||
switch(rig.get_rig_mode()) {
|
||||
case rig_mode::cw:
|
||||
USBDEBUG("new mode - CW");
|
||||
break;
|
||||
case MODE_SSB:
|
||||
case rig_mode::ssb:
|
||||
USBDEBUG("new mode - SSB");
|
||||
break;
|
||||
case MODE_DIGI:
|
||||
USBDEBUG("new mode - DIGI");
|
||||
break;
|
||||
case MODE_TEST:
|
||||
USBDEBUG("new mode - TEST");
|
||||
case rig_mode::digi:
|
||||
USBDEBUG("new mode - DIG");
|
||||
break;
|
||||
default:
|
||||
char errormessage[32];
|
||||
sprintf(errormessage, "unknown mode command - %3d", rig.get_rig_mode());
|
||||
USBDEBUG("mode command not recognized");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case IOP_START_TX_COMMAND:
|
||||
catPTTOn();
|
||||
catPTT.press(rig.mode());
|
||||
break;
|
||||
|
||||
case IOP_STOP_TX_COMMAND:
|
||||
catPTTOff();
|
||||
catPTT.release(rig.mode());
|
||||
break;
|
||||
|
||||
case IOP_CW_CONFIG_MSG:
|
||||
break;
|
||||
|
||||
case IOP_DEBUG_MSG:
|
||||
USBDEBUG("IOP_DEBUG_MSG");
|
||||
USBDEBUG((const char*)m.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +116,7 @@ void processCalCommand(const char* buf)
|
||||
case 'R':
|
||||
case 't':
|
||||
case 'T':
|
||||
audioCalibrate(&iopConfig, cmd, subcmd, parm, value, (count == 4));
|
||||
//audioCalibrate(&rigConfig.audio, cmd, subcmd, parm, value, (count == 4));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -126,8 +135,8 @@ enum SerialState {
|
||||
EEPROM_WRITE,
|
||||
} serialState = NORMAL;
|
||||
|
||||
uint8_t readPrefix = 0;
|
||||
uint8_t readLength = 0;
|
||||
PrefixID readPrefix;
|
||||
uint8_t readLength;
|
||||
|
||||
int cmdLength = 0;
|
||||
byte cmdBuffer[16];
|
||||
@@ -139,13 +148,44 @@ int magicFlag = 0;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
uint8_t usbCatLength = 0;
|
||||
byte usbCatBuffer[5];
|
||||
elapsedMillis usbCatTimer;
|
||||
|
||||
#define CAT_RECEIVE_TIMEOUT 500
|
||||
|
||||
void serviceCAT()
|
||||
{
|
||||
uint8_t incomingByte;
|
||||
|
||||
// First, if we've never received or requested a mode command from the Raduino, send a request.
|
||||
if (received_mode == 0) {
|
||||
USBDEBUG("requesting mode");
|
||||
sendIOPModeRequest();
|
||||
received_mode = 1;
|
||||
}
|
||||
|
||||
if ((usbCatLength > 0) && (usbCatTimer > CAT_RECEIVE_TIMEOUT)) {
|
||||
// timeout... clear the buffer and start over
|
||||
usbCatLength = 0;
|
||||
usbCatTimer = 0;
|
||||
}
|
||||
|
||||
// read from the USB serial, pass through to UART serial
|
||||
for (int i = 0; i < USBSERIAL.available(); i++) {
|
||||
for (int i = 0; i < USBSERIAL.available(); i++) {
|
||||
incomingByte = USBSERIAL.read();
|
||||
usbCatTimer = 0;
|
||||
|
||||
#if not defined(FACTORY_CALIBRATION)
|
||||
usbCatBuffer[usbCatLength++] = incomingByte;
|
||||
if (usbCatLength == 5) {
|
||||
sendCATMessage(usbCatBuffer);
|
||||
usbCatLength = 0;
|
||||
}
|
||||
|
||||
// NOTE: This code does NOT handle any interrupts in COMMS from the PC...
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FACTORY_CALIBRATION)
|
||||
// unless we're in factory calibration mode, in which case we're going
|
||||
@@ -176,7 +216,7 @@ void serviceCAT()
|
||||
#else
|
||||
// Don't pass CAT commands through if in DEBUG mode.
|
||||
#if not defined(DEBUG)
|
||||
HWSERIAL.write(incomingByte);
|
||||
//HWSERIAL.write(incomingByte);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1,11 +1,14 @@
|
||||
//======================================================================
|
||||
// config.h
|
||||
//
|
||||
// NOTE: Let's change the name of this file to RigConfig.h.
|
||||
//======================================================================
|
||||
|
||||
#ifndef __iop_config_h__
|
||||
#define __iop_config_h__
|
||||
|
||||
#include <iopcomm.h>
|
||||
//#include "rig.h"
|
||||
|
||||
#define KEYER_LEFT_PADDLE_PIN 16
|
||||
#define KEYER_RIGHT_PADDLE_PIN 17
|
||||
@@ -13,19 +16,23 @@
|
||||
// Uncomment to use the "factory" calibration mode. This is intended to
|
||||
// allow calibration of IOP settings, separately from the uBITX/Raduino.
|
||||
// There will be no pass-thru of any CAT.
|
||||
#define FACTORY_CALIBRATION
|
||||
//#define FACTORY_CALIBRATION
|
||||
|
||||
// IOPConfig
|
||||
// Used to store configuration parameters during runtime, as well as to
|
||||
// save them to EEPROM.
|
||||
struct IOPConfig {
|
||||
//======================================================================
|
||||
// AudioConfig
|
||||
//======================================================================
|
||||
|
||||
class AudioConfig {
|
||||
public:
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// RECEIVE PARAMETERS
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// rig-in parameters (RX)
|
||||
uint8_t rxRigInLevel = 5;
|
||||
uint8_t rxRigInLevel = 8; //5;
|
||||
float rxRigInVol = 1.0; //0.7;
|
||||
float rxRigInCal = 1.0;
|
||||
float rxRigInCal = 8.0; //1.0;
|
||||
// USB-in parameters (RX) - debug/monitor use only
|
||||
bool rxUSBInEnable = false;
|
||||
float rxUSBInVol = 1.0;
|
||||
@@ -37,36 +44,46 @@ struct IOPConfig {
|
||||
float rxLineOutCal = 1.0;
|
||||
// USB-out parameters (RX)
|
||||
float rxUSBOutCal = 1.0;
|
||||
// sidetone parameters (really a TX thing, but "RX" side of audio)
|
||||
float sideToneVol = 1.0;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// TRANSMIT PARAMETERS
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// NOTE: Default rig-out parameters are based on trying to hit a 25mVrms output to the
|
||||
// rig. This is based on some discussion at the following URL:
|
||||
//--------------------------------------------------------------------
|
||||
// NOTE: Default rig-out parameters are based on trying to hit a
|
||||
// 25mVrms output to the rig. This is based on some discussion at the
|
||||
// following URL:
|
||||
//
|
||||
// https://groups.io/g/BITX20/message/58951
|
||||
//
|
||||
// This may or may not be totally applicable. I believe it was for IMD/spurs on a pre-V5
|
||||
// version of the uBITX. So it may be OBE for my V5. It also alludes to modifications
|
||||
// to the transmit audio chain, which may be something I need to look into (i.e. increasing
|
||||
// This may or may not be totally applicable. I believe it was for
|
||||
// IMD/spurs on a pre-V5 version of the uBITX. So it may be OBE for
|
||||
// my V5. It also alludes to modifications to the transmit audio
|
||||
// chain, which may be something I need to look into (i.e. increasing
|
||||
// the gain on the initial mic pre-amp).
|
||||
//
|
||||
// Specifically, for the rig-out parameters:
|
||||
// line out level 31 = 1.16 V p-p
|
||||
// = 0.58 V peak
|
||||
// = 0.41 V rms = 410 mV rms
|
||||
// so output calibration needs to reduce that to 17.5 mV rms (70% of 25 mV rms)
|
||||
// so output calibration needs to reduce that to 17.5 mV rms (70%
|
||||
// of 25 mV rms)
|
||||
// txMicInCal = 0.043 ... seems pretty low...
|
||||
//
|
||||
// Likewise, default line-in (TX) parameters assume consumer line level
|
||||
// input, but with the default audio adaptor line-in level setting (5 = 1.33V p-p).
|
||||
// Likewise, default line-in (TX) parameters assume consumer line
|
||||
// level input, but with the default audio adaptor line-in level
|
||||
// setting (5 = 1.33V p-p).
|
||||
// line in level 5 = 1.33 V p-p
|
||||
// signal in = 0.894 V p-p
|
||||
// = 0.447 V peak
|
||||
// = 0.316 V rms = 316 mV rms
|
||||
// so input calibration needs to convert that to the 410 mV noted above (equivalent
|
||||
// for the microphone), so that when that signal gets to the rig-out, it gets
|
||||
// treated the same as the mic input.
|
||||
// so input calibration needs to convert that to the 410 mV noted
|
||||
// above (equivalent for the microphone), so that when that signal
|
||||
// gets to the rig-out, it gets treated the same as the mic input.
|
||||
// txLineInCal = 1.30
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// microphone-in parameters (TX)
|
||||
uint8_t txMicInGain = 12;
|
||||
@@ -84,16 +101,34 @@ struct IOPConfig {
|
||||
float txSine2Vol = 1.0;
|
||||
// rig-out parameters (TX) - default settings are based on hitting 70% of 25mVrms w/ mic
|
||||
uint8_t txRigOutLevel = 31;
|
||||
float txRigOutCal = 0.043;
|
||||
float txRigOutCal = 0.1; // 0.061;
|
||||
// USB-out parameters (TX)- debug/monitor use only
|
||||
bool txUSBOutEnable = true;
|
||||
float txUSBOutCal = 1.0;
|
||||
|
||||
// CW configuration
|
||||
CWConfig cw;
|
||||
};
|
||||
|
||||
extern IOPConfig iopConfig;
|
||||
//======================================================================
|
||||
// RigConfig
|
||||
// Used to store configuration parameters during runtime, as well as to
|
||||
// save them to EEPROM.
|
||||
//======================================================================
|
||||
|
||||
class RigConfig {
|
||||
public:
|
||||
RigConfig() {}
|
||||
// audio configuration
|
||||
AudioConfig audio;
|
||||
|
||||
// mode configuration
|
||||
ssb_config ssb;
|
||||
digi_config digi;
|
||||
cw_config cw;
|
||||
|
||||
// General rig configuration entries.
|
||||
rig_mode mode = rig_mode::ssb;
|
||||
};
|
||||
|
||||
extern RigConfig rigConfig;
|
||||
|
||||
#endif
|
||||
|
||||
|
9
ubitx_iop/config.ino
Normal file
9
ubitx_iop/config.ino
Normal file
@@ -0,0 +1,9 @@
|
||||
//======================================================================
|
||||
// config.ino
|
||||
//======================================================================
|
||||
|
||||
#include "config.h"
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
0
ubitx_iop/etl
Executable file
0
ubitx_iop/etl
Executable file
11
ubitx_iop/etl_profile.h
Normal file
11
ubitx_iop/etl_profile.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef __ETL_PROFILE_H__
|
||||
#define __ETL_PROFILE_H__
|
||||
|
||||
//#define ETL_THROW_EXCEPTIONS
|
||||
//#define ETL_VERBOSE_ERRORS
|
||||
#define ETL_CHECK_PUSH_POP
|
||||
|
||||
#define ETL_TARGET_OS_FREERTOS // Placeholder. Not currently utilised in the ETL
|
||||
#define ETL_TARGET_DEVICE_ARM // Placeholder. Not currently utilised in the ETL
|
||||
|
||||
#endif
|
299
ubitx_iop/menu.h
299
ubitx_iop/menu.h
@@ -5,46 +5,293 @@
|
||||
#ifndef __menu_h__
|
||||
#define __menu_h__
|
||||
|
||||
//#include "etl_profile.h"
|
||||
//#include <ArduinoSTL.h>
|
||||
#include "etl/array.h"
|
||||
#include "etl/cstring.h"
|
||||
#include "etl/delegate.h"
|
||||
//#include <vector>
|
||||
#include <initializer_list>
|
||||
#include "rig.h"
|
||||
|
||||
// 16 characters on display
|
||||
#define MAX_TEXT_LEN 16
|
||||
#define MENU_SELECTED_CHAR '>'
|
||||
/*
|
||||
public class MenuItem {
|
||||
const int MAX_TEXT_LEN = 16;
|
||||
const int max_text_len = 16;
|
||||
const char MENU_SELECTED_CHAR = '>';
|
||||
const char menu_selection_char = '>';
|
||||
|
||||
const char blankLine[17] = " ";
|
||||
|
||||
typedef etl::string<max_text_len> Menu_string;
|
||||
|
||||
//======================================================================
|
||||
// Menu_item
|
||||
//======================================================================
|
||||
|
||||
class Menu_item {
|
||||
public:
|
||||
MenuItem(bool active = true, int timeout = 0): _active(active), _timeout(timeout), _elapsed(0) {}
|
||||
void update() {
|
||||
if ((_timeout > 0) && (_elapsed > _timeout)) {
|
||||
_active = false;
|
||||
Menu_item(): parent_link(nullptr) {}
|
||||
virtual ~Menu_item() {}
|
||||
|
||||
virtual const Menu_string& title() const = 0;
|
||||
virtual void get_title(Menu_string& outstr) const = 0;
|
||||
virtual void get_text(Menu_string& outstr) const = 0;
|
||||
|
||||
virtual Menu_item* select() = 0;
|
||||
virtual Menu_item* altSelect() = 0;
|
||||
virtual Menu_item* exit() = 0;
|
||||
virtual Menu_item* prev() = 0;
|
||||
virtual Menu_item* next() = 0;
|
||||
|
||||
void set_parent(Menu_item* item) {
|
||||
parent_link = item;
|
||||
}
|
||||
|
||||
const Menu_item* parent() const {
|
||||
return parent_link;
|
||||
}
|
||||
|
||||
private:
|
||||
Menu_item* parent_link;
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// List_menu
|
||||
//======================================================================
|
||||
|
||||
const int MAX_LISTMENU_TITLE_LEN = 15;
|
||||
|
||||
//const int max_size_of_list_menu = 20; // arbitrary...
|
||||
|
||||
template <const size_t SIZE>
|
||||
class List_menu : public Menu_item {
|
||||
public:
|
||||
List_menu(const char* title, etl::array<const Menu_item*, SIZE> items):
|
||||
Menu_item(), list_title(title), list_items(items), index(0) {
|
||||
for (auto element : list_items) {
|
||||
element->set_parent(this);
|
||||
}
|
||||
}
|
||||
inline void activate() { _active = true; _elapsed = 0; }
|
||||
inline void deactivate() { _active = false; }
|
||||
virtual MenuItem* accept();
|
||||
virtual MenuItem* reject();
|
||||
virtual MenuItem* next();
|
||||
virtual MenuItem* prev();
|
||||
|
||||
virtual const Menu_string& title() const {
|
||||
return list_title;
|
||||
}
|
||||
|
||||
virtual void get_title(Menu_string& outstr) const {
|
||||
outstr.assign(list_title);
|
||||
}
|
||||
|
||||
virtual void get_text(Menu_string& outstr) const {
|
||||
list_items[index]->get_text(outstr);
|
||||
}
|
||||
|
||||
virtual Menu_item* select()
|
||||
{
|
||||
return list_items[index];
|
||||
}
|
||||
|
||||
virtual Menu_item* altSelect()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* exit()
|
||||
{
|
||||
return parent();
|
||||
}
|
||||
|
||||
virtual Menu_item* prev()
|
||||
{
|
||||
if (--index < 0) {
|
||||
index += list_items.size();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* next()
|
||||
{
|
||||
index = ++index % list_items.size();
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _active;
|
||||
int _timeout;
|
||||
elapsedMillis _elapsed;
|
||||
Menu_string list_title;
|
||||
etl::array<const Menu_item*, SIZE> list_items;
|
||||
int index;
|
||||
};
|
||||
|
||||
public class SSBMenu {
|
||||
//======================================================================
|
||||
// Config_parm
|
||||
//======================================================================
|
||||
|
||||
typedef etl::delegate<void(void)> Update_func;
|
||||
|
||||
template<typename T>
|
||||
class Config_parm : public Menu_item {
|
||||
public:
|
||||
Config_parm(const char* title, T& parm, T min, T max, T step, Update_func f):
|
||||
Menu_item(), parm_title(title), parameter(parm), min_val(min), max_val(max), step_val(step), on_update(f) {}
|
||||
|
||||
virtual const Menu_string& title() const {
|
||||
return parm_title;
|
||||
}
|
||||
|
||||
virtual void get_title(Menu_string& outstr) const {
|
||||
outstr.assign(parm_title);
|
||||
}
|
||||
|
||||
virtual void get_text(Menu_string& outstr) const = 0;
|
||||
|
||||
virtual Menu_item* select() {
|
||||
on_update();
|
||||
return parent();
|
||||
}
|
||||
|
||||
virtual Menu_item* altSelect() {
|
||||
on_update();
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* exit() {
|
||||
return parent();
|
||||
}
|
||||
|
||||
virtual Menu_item* prev() {
|
||||
parameter -= step_val;
|
||||
if (parameter < min_val) {
|
||||
parameter = min_val;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* next() {
|
||||
parameter += step_val;
|
||||
if (parameter > max_val) {
|
||||
parameter = max_val;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
const T& value() const {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
private:
|
||||
Menu_string parm_title;
|
||||
T& parameter;
|
||||
T min_val;
|
||||
T max_val;
|
||||
T step_val;
|
||||
Update_func on_update;
|
||||
};
|
||||
|
||||
public class DigiMenu {
|
||||
class Parm_uint8 : public Config_parm<uint8_t> {
|
||||
public:
|
||||
private:
|
||||
}
|
||||
|
||||
public class CWMenu {
|
||||
public:
|
||||
private:
|
||||
Parm_uint8(const char* title, uint8_t& parm, uint8_t min, uint8_t max, uint8_t step, Update_func f):
|
||||
Config_parm<uint8_t>(title, parm, min, max, step, f) {}
|
||||
|
||||
virtual void get_text(Menu_string& outstr) const {
|
||||
snprintf(outstr.data(), max_text_len+1, "%-*.*s %3d", max_text_len-4, max_text_len-4, title().data(), value());
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
class Parm_float : public Config_parm<float> {
|
||||
public:
|
||||
Parm_float(const char* title, float& parm, float min, float max, float step, Update_func f):
|
||||
Config_parm<float>(title, parm, min, max, step, f) {}
|
||||
|
||||
virtual void get_text(Menu_string& outstr) const {
|
||||
snprintf(outstr.data(), max_text_len+1, "%-*.*s %5.2f", max_text_len-6, max_text_len-6, title().data(), value());
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
const char modeID[] = {'s', 'S', 'c', 'C', 'd', 'D', 't', 'T'};
|
||||
const char* const filterID[static_cast<int>(rig_mode::count)][static_cast<int>(rx_filter::count)] = {
|
||||
{"2.8", "2.4", "1.8"}, // SSB
|
||||
{"1.0", "500", "250"}, // CW
|
||||
{"2.8", "2.4", "500"}, // DIG
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// Top_menu
|
||||
//======================================================================
|
||||
|
||||
|
||||
class Main_menu : public Menu_item {
|
||||
public:
|
||||
Main_menu(basic_rig& rig): menu_title("Main Menu"), rig_(rig), adjust_tx(false) {}
|
||||
|
||||
virtual const Menu_string& title() const {
|
||||
return menu_title;
|
||||
}
|
||||
|
||||
virtual void get_title(Menu_string& outstr) const {
|
||||
outstr.assign(menu_title);
|
||||
}
|
||||
|
||||
virtual void get_text(Menu_string& outstr) const {
|
||||
char text[max_text_len+1];
|
||||
sprintf(text, "%1cR:%3s %1cT:%3s ",
|
||||
adjust_tx ? ' ' : menu_selection_char,
|
||||
filterID[static_cast<size_t>(rig_.get_rig_mode())][static_cast<size_t>(rig_.get_rx_filter())],
|
||||
adjust_tx ? menu_selection_char : ' ',
|
||||
rig_.is_ssb_mode() && rig_.config().ssb.comp.enabled ? "CMP" : " ");
|
||||
outstr.assign(text);
|
||||
}
|
||||
|
||||
virtual Menu_item* select() {
|
||||
adjust_tx = !adjust_tx;
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* altSelect() {
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* exit() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual Menu_item* prev() {
|
||||
if (adjust_tx) {
|
||||
if (rig_.is_ssb_mode()) {
|
||||
rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled;
|
||||
if (rig_.config().ssb.comp.enabled)
|
||||
rig_.enable_comp();
|
||||
else
|
||||
rig_.disable_comp();
|
||||
}
|
||||
} else {
|
||||
rig_.prev_rx_filter();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
virtual Menu_item* next() {
|
||||
if (adjust_tx) {
|
||||
if (rig_.is_ssb_mode()) {
|
||||
rig_.config().ssb.comp.enabled = !rig_.config().ssb.comp.enabled;
|
||||
if (rig_.config().ssb.comp.enabled)
|
||||
rig_.enable_comp();
|
||||
else
|
||||
rig_.disable_comp();
|
||||
}
|
||||
} else {
|
||||
rig_.next_rx_filter();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
Menu_string menu_title;
|
||||
basic_rig& rig_;
|
||||
bool adjust_tx;
|
||||
};
|
||||
|
||||
extern const Menu_item* audio_config_menu;
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
@@ -2,137 +2,93 @@
|
||||
// menu.ino
|
||||
//======================================================================
|
||||
|
||||
#include <iopcomm.h>
|
||||
#include "config.h"
|
||||
#include "menu.h"
|
||||
|
||||
/*
|
||||
CW mode:
|
||||
WPM (although we can get this from Raduino)
|
||||
WPM: # (L/R, select/abort)
|
||||
FILT
|
||||
WIDE NORM NARR
|
||||
void do_nothing_func() {}
|
||||
Update_func do_nothing = Update_func::create<do_nothing_func>();
|
||||
|
||||
SSB mode:
|
||||
TX LVL
|
||||
COMP
|
||||
FILT
|
||||
WIDE NORM NARR
|
||||
List_menu<7> audio_config_menu_("Audio Config", {
|
||||
new Parm_uint8 ("RX ADC Lvl", rigConfig.audio.rxRigInLevel, 0, 15, 1, do_nothing),
|
||||
new Parm_uint8 ("RX DAC Lvl", rigConfig.audio.rxLineOutLevel, 13, 31, 1, do_nothing),
|
||||
new Parm_float ("RX Inp Lvl", rigConfig.audio.rxRigInVol, 0.0, 1.0, 0.1, do_nothing),
|
||||
new Parm_float ("RX Inp Cal", rigConfig.audio.rxRigInCal, 0.0, 99.9, 0.1, do_nothing),
|
||||
new Parm_float ("RX Spkr Cal", rigConfig.audio.rxSpkrOutCal, 0.0, 99.9, 0.1, do_nothing),
|
||||
new Parm_float ("RX Line Cal", rigConfig.audio.rxLineOutCal, 0.0, 99.9, 0.1, do_nothing),
|
||||
new Parm_float ("RX USB Cal", rigConfig.audio.rxUSBOutCal, 0.0, 99.9, 0.1, do_nothing),
|
||||
});
|
||||
|
||||
Digi mode:
|
||||
TX LVL
|
||||
const Menu_item* audio_config_menu = &audio_config_menu_;
|
||||
|
||||
/* commented out til I go back and fix SSBConfig class
|
||||
List_menu<3> ssb_config_menu("SSB Config", {
|
||||
Parm_float("Comp Thresh", rigConfig.lsb.comp_threshold, 0.0, 1.0, 0.1, do_nothing),
|
||||
Parm_float("Comp Ratio", rigConfig.lsb.comp_ratio, 0.0, 50.0, 1.0, do_nothing),
|
||||
Parm_float("Comp Gain", rigConfig.lsb.comp_gain, 0.0, 99.9, 0.1, do_nothing)
|
||||
});
|
||||
*/
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
ListMenu("Configuration",
|
||||
ListMenu("LSB Mode",
|
||||
ParameterFilter("Filter", c.lsb.filter),
|
||||
ParameterOnOff ("Compressor", c.lsb.comp_enable),
|
||||
ParameterFloat ("Comp Thresh", c.lsb.comp_threshold, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("Comp Ratio", c.lsb.comp_ratio, 0.0, 50.0, 1.0),
|
||||
ParameterFloat ("Comp Gain", c.lsb.comp_gain, 0.0, 99.9, 0.1)),
|
||||
ListMenu("USB Mode",
|
||||
ParameterFilter("Filter", c.usb.filter),
|
||||
ParameterOnOff ("Compressor", c.usb.comp_enable),
|
||||
ParameterFloat ("Comp Thresh", c.usb.comp_threshold, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("Comp Ratio", c.usb.comp_ratio, 0.0, 50.0, 1.0),
|
||||
ParameterFloat ("Comp Gain", c.usb.comp_gain, 0.0, 99.9, 0.1)),
|
||||
ListMenu("CWL Mode",
|
||||
ParameterFilter("Filter", c.cwl.filter),
|
||||
ParameterKeyer ("Keyer Mode", c.cwl.mode),
|
||||
ParameterOnOff ("Keyer Rev?", c.cwl.reversed),
|
||||
ParameterInt ("Keyer WPM", c.cwl.wpm, 0, 60, 1),
|
||||
ParameterFloat ("Keyer Weight", c.cwl.weight, 0.0, 9.9, 0.1),
|
||||
ParameterInt ("ST Freq", c.sidetone, 300, 3000, 10)),
|
||||
ListMenu("CWU Mode",
|
||||
ParameterFilter("Filter", c.cwl.filter),
|
||||
ParameterKeyer ("Keyer Mode", c.cwl.mode),
|
||||
ParameterOnOff ("Keyer Rev?", c.cwl.reversed),
|
||||
ParameterInt ("Keyer WPM", c.cwl.wpm, 0, 60, 1),
|
||||
ParameterFloat ("Keyer Weight", c.cwl.weight, 0.0, 9.9, 0.1),
|
||||
ParameterInt ("ST Freq", c.sidetone, 300, 3000, 10)),
|
||||
ListMenu("DGL Mode",
|
||||
ParameterFilter("Filter", c.dgl.filter)),
|
||||
ListMenu("DGU Mode",
|
||||
ParameterFilter("Filter", c.dgu.filter)),
|
||||
ListMenu("TTL Mode",
|
||||
ParameterFilter("Filter", c.dgl.filter)),
|
||||
ListMenu("TTU Mode",
|
||||
ParameterFilter("Filter", c.dgu.filter)),
|
||||
ListMenu("Audio",
|
||||
ParameterInt ("RX ADC Lvl", c.rxRigInLevel, 0, 15, 1),
|
||||
ParameterInt ("RX DAC Lvl", c.rxLineOutLevel, 13, 31, 1),
|
||||
ParameterFloat ("RX Inp Lvl", c.rxRigInVol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("RX Inp Cal", c.rxRigInCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("RX Spkr Cal", c.rxSpkrOutCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("RX Line Cal", c.rxLineOutCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("RX USB Cal", c.rxUSBOutCal, 0.0, 99.9, 0.1),
|
||||
ParameterOnOff ("RX USB Dbg", c.rxUSBInEnable),
|
||||
ParameterInt ("TX Mic Gain", c.txMicInGain, 0, 63, 1),
|
||||
ParameterInt ("TX ADC Lvl", c.txLineInLevel, 0, 15, 1),
|
||||
ParameterInt ("TX DAC Lvl", c.txRigOutLevel, 13, 31, 1),
|
||||
ParameterFloat ("TX Out Cal", c.txRigOutCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("TX Mic Lvl", c.txMicInVol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("TX Mic Cal", c.txMicInCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("TX Line Lvl", c.txLineInVol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("TX Line Cal", c.txLineInCal, 0.0, 99.9, 0.1),
|
||||
ParameterFloat ("TX USB Lvl", c.txUSBInVol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("TX USB Cal", c.txUSBInCal, 0.0, 99.9, 0.1),
|
||||
ParameterOnOff ("TX USB Dbg", c.txUSBOutEnable),
|
||||
ParameterFloat ("Tone 1 Lvl", c.txSine1Vol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("Tone 2 Lvl", c.txSine2Vol, 0.0, 1.0, 0.1),
|
||||
ParameterFloat ("ST Lvl", c.sideToneVol, 0.0, 1.0, 0.1)));
|
||||
*/
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
|
240
ubitx_iop/rig.h
Normal file
240
ubitx_iop/rig.h
Normal file
@@ -0,0 +1,240 @@
|
||||
//======================================================================
|
||||
// rig.h
|
||||
//======================================================================
|
||||
|
||||
#ifndef __rig_h__
|
||||
#define __rig_h__
|
||||
|
||||
#include <iopcomm.h>
|
||||
#include "audio.h"
|
||||
#include "RigMode.h"
|
||||
|
||||
//======================================================================
|
||||
// basic_rig
|
||||
//======================================================================
|
||||
|
||||
class basic_rig {
|
||||
public:
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Constructor/destructor.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
basic_rig(RigConfig& c, RigAudio& a) :
|
||||
config_(c), audio_(a),
|
||||
bpf_(),
|
||||
comp_(&config_.ssb.comp),
|
||||
ssb_ (config_.ssb, audio_, bpf_, comp_),
|
||||
cw_ (config_.cw, audio_, bpf_),
|
||||
digi_(config_.digi, audio_, bpf_) { set_rig_mode(config_.mode); }
|
||||
|
||||
void init() {}
|
||||
|
||||
RigConfig& config() { return config_; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Mode control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
inline bool is_ssb_mode() const { return (config_.mode == rig_mode::ssb ); }
|
||||
inline bool is_digi_mode() const { return (config_.mode == rig_mode::digi); }
|
||||
inline bool is_cw_mode() const { return (config_.mode == rig_mode::cw ); }
|
||||
|
||||
// Switch to the specified mode. Returns a pointer to the new mode.
|
||||
basic_mode* set_rig_mode(rig_mode m) {
|
||||
// exit the previous mode
|
||||
current_mode_->exit(); // NOTE: This could currently occur during TX, which is NOT desirable.
|
||||
|
||||
// select the new mode
|
||||
config_.mode = m;
|
||||
|
||||
switch(config_.mode) {
|
||||
case rig_mode::ssb:
|
||||
current_mode_ = &ssb_;
|
||||
break;
|
||||
|
||||
case rig_mode::cw:
|
||||
current_mode_ = &cw_;
|
||||
break;
|
||||
|
||||
case rig_mode::digi:
|
||||
current_mode_ = &digi_;
|
||||
break;
|
||||
}
|
||||
|
||||
//enter the new mode
|
||||
current_mode_->enter();
|
||||
|
||||
// return a pointer to the new mode
|
||||
return current_mode_;
|
||||
}
|
||||
|
||||
// Returns the rig_mode (enum) of the current mode object.
|
||||
inline rig_mode get_rig_mode() const { return config_.mode; }
|
||||
|
||||
|
||||
// Returns a pointer to the current mode object.
|
||||
inline basic_mode* mode() const { return current_mode_; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Transmit/Receive (T/R) control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
inline bool is_tx() const { return mode()->is_tx(); }
|
||||
inline bool is_rx() const { return mode()->is_rx(); }
|
||||
|
||||
// Enter the transmit state. This is delegated to the mode.
|
||||
inline void tx() { mode()->tx(); }
|
||||
|
||||
// Enter the receive state. This is delegated to the mode.
|
||||
inline void rx() { mode()->rx(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Transmit processor control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
inline void enable_comp() {
|
||||
if (is_ssb_mode()) ((ssb_mode*)mode())->enable_comp();
|
||||
}
|
||||
|
||||
inline void disable_comp() {
|
||||
if (is_ssb_mode()) ((ssb_mode*)mode())->disable_comp();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// RX filter control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Set the RX filter. This is delegated to the mode.
|
||||
inline void set_rx_filter(rx_filter f) { mode()->set_rx_filter(f); }
|
||||
|
||||
// Returns the rx_filter (enum) of the RX filter currently being used.
|
||||
inline rx_filter get_rx_filter() const { return mode()->config().filter; }
|
||||
|
||||
void next_rx_filter() {
|
||||
switch(mode()->config().filter) {
|
||||
case rx_filter::wide:
|
||||
set_rx_filter(rx_filter::medium);
|
||||
break;
|
||||
|
||||
case rx_filter::medium:
|
||||
set_rx_filter(rx_filter::narrow);
|
||||
break;
|
||||
|
||||
case rx_filter::narrow:
|
||||
set_rx_filter(rx_filter::wide);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void prev_rx_filter() {
|
||||
switch(mode()->config().filter) {
|
||||
case rx_filter::wide:
|
||||
set_rx_filter(rx_filter::narrow);
|
||||
break;
|
||||
|
||||
case rx_filter::medium:
|
||||
set_rx_filter(rx_filter::wide);
|
||||
break;
|
||||
|
||||
case rx_filter::narrow:
|
||||
set_rx_filter(rx_filter::medium);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Audio output control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
inline void muteSpkrOut() const {
|
||||
audio_.muteSpkrOut();
|
||||
}
|
||||
|
||||
inline void unmuteSpkrOut() const {
|
||||
audio_.unmuteSpkrOut();
|
||||
}
|
||||
|
||||
inline void muteLineOut() const {
|
||||
audio_.muteLineOut();
|
||||
}
|
||||
|
||||
inline void unmuteLineOut() const {
|
||||
audio_.unmuteLineOut();
|
||||
}
|
||||
|
||||
inline void muteUSBOut() const {
|
||||
audio_.muteUSBOut();
|
||||
}
|
||||
|
||||
inline void unmuteUSBOut() const {
|
||||
audio_.unmuteUSBOut();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Audio input control.
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
inline void muteAllTx() const {
|
||||
audio_.muteAllTx();
|
||||
}
|
||||
|
||||
inline void muteMicIn() const {
|
||||
audio_.muteMicIn();
|
||||
}
|
||||
|
||||
inline void unmuteMicIn() const {
|
||||
audio_.unmuteMicIn();
|
||||
}
|
||||
|
||||
inline void muteLineIn() const {
|
||||
audio_.muteLineIn();
|
||||
}
|
||||
|
||||
inline void unmuteLineIn() const {
|
||||
audio_.unmuteLineIn();
|
||||
}
|
||||
|
||||
inline void muteUSBIn() const {
|
||||
audio_.muteUSBIn();
|
||||
}
|
||||
|
||||
inline void unmuteUSBIn() const {
|
||||
audio_.unmuteUSBOut();
|
||||
}
|
||||
|
||||
inline void muteTTIn() const {
|
||||
audio_.muteTTIn();
|
||||
}
|
||||
|
||||
inline void unmuteTTIn() const {
|
||||
audio_.unmuteTTIn();
|
||||
}
|
||||
|
||||
// Update the rig state. This should be called once each time through
|
||||
// the main loop.
|
||||
void update()
|
||||
{
|
||||
comp_.update(); // It checks if it's enabled on its own.
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
RigConfig& config_;
|
||||
RigAudio& audio_;
|
||||
|
||||
bp_filter bpf_;
|
||||
speech_comp comp_;
|
||||
|
||||
ssb_mode ssb_;
|
||||
cw_mode cw_;
|
||||
digi_mode digi_;
|
||||
|
||||
basic_mode* current_mode_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// EOF
|
||||
//======================================================================
|
@@ -11,8 +11,13 @@
|
||||
#include "eeprom.h"
|
||||
#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);
|
||||
@@ -34,10 +39,35 @@ enum TxState {
|
||||
TX_KEYER,
|
||||
};
|
||||
|
||||
extern RigMode rigMode;
|
||||
//extern RigMode rigMode;
|
||||
|
||||
extern bool keyerKeyDown;
|
||||
|
||||
//======================================================================
|
||||
// Keying functions.
|
||||
//
|
||||
// These are simple functions to assert the key line from the IOP to the
|
||||
// Raduino.
|
||||
//======================================================================
|
||||
|
||||
inline void initKeyLine()
|
||||
{
|
||||
pinMode(PTT_KEY_OUT_PIN, OUTPUT);
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
}
|
||||
|
||||
inline void setKeyDown()
|
||||
{
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
}
|
||||
|
||||
inline void setKeyUp()
|
||||
{
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
@@ -2,315 +2,232 @@
|
||||
// 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"
|
||||
|
||||
#include <Bounce2.h>
|
||||
#define BOUNCE_WITH_PROMPT_DETECTION
|
||||
Keyer keyer{15, 3.0}; // NOTE: make configurable
|
||||
|
||||
RigMode rigMode = MODE_SSB;
|
||||
IOPConfig iopConfig;
|
||||
RigConfig rigConfig;
|
||||
RigAudio rigAudio{rigConfig.audio};
|
||||
basic_rig rig{rigConfig, rigAudio};
|
||||
|
||||
#define MIC_PTT_PIN 21
|
||||
#define LINE_PTT_PIN 20
|
||||
#define PTT_KEY_OUT_PIN 2
|
||||
CATSwitch catPTT;
|
||||
//MicSwitch micPTTHelper;
|
||||
GPIOSwitch micPTT(true, MIC_PTT_PIN);
|
||||
//LineSwitch linePTTHelper;
|
||||
GPIOSwitch linePTT(false, LINE_PTT_PIN);
|
||||
|
||||
Bounce micPTT = Bounce();
|
||||
Bounce linePTT = Bounce();
|
||||
Encoder knob(ENCODER_A_PIN, ENCODER_B_PIN);
|
||||
long knobPos = 0;
|
||||
|
||||
TxState txState = TX_OFF;
|
||||
Bounce btn;
|
||||
elapsedMillis btnMillis;
|
||||
|
||||
Keyer keyer(15, 3.0); // need to make configurable
|
||||
Main_menu main_menu(rig);
|
||||
Menu_item* menu_item = &main_menu;
|
||||
|
||||
//SSBMenu ssbMenu();
|
||||
//DigiMenu digiMenu();
|
||||
//CWMenu cwMenu();
|
||||
//MenuItem* dspMenu = &ssbMenu;
|
||||
|
||||
//======================================================================
|
||||
// catPTTOn()
|
||||
//
|
||||
// NOTE: Should probably move this to cat.ino.
|
||||
//======================================================================
|
||||
|
||||
void catPTTOn()
|
||||
{
|
||||
// Check if we're already transmitting. If so, then this command
|
||||
// does nothing: existing transmission, from existing source and PTT,
|
||||
// will continue.
|
||||
if (txState != TX_OFF) return;
|
||||
|
||||
switch(rigMode) {
|
||||
// CAT should not start or stop TX in CW mode... we really should
|
||||
// not even get this command. But maybe the rig control software is
|
||||
// doing it (but then, we should inhibit this in the Raduino).
|
||||
//case MODE_CW:
|
||||
//break;
|
||||
|
||||
case MODE_SSB:
|
||||
// In SSB mode, CAT-PTT will always (de-)activate the Line-In TX
|
||||
// audio source.
|
||||
txState = TX_CAT;
|
||||
audioSelectTxInput(TX_LINE_IN); // in case Mic-In is selected
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// In Digital (USB) mode, CAT-PTT will always (de-)activate the
|
||||
// USB-In TX audio source.
|
||||
txState = TX_CAT;
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// catPTTOff()
|
||||
//
|
||||
// NOTE: Should probably move this to cat.ino.
|
||||
//======================================================================
|
||||
|
||||
void catPTTOff()
|
||||
{
|
||||
// If we're not transmitting, or the active PTT is not CAT, then this
|
||||
// command does nothing: CAT cannot interrupt other transmissions.
|
||||
if (txState != TX_CAT) return;
|
||||
|
||||
switch(rigMode) {
|
||||
// CAT should not start or stop TX in CW mode... we really should
|
||||
// not even get this command. But maybe the rig control software is
|
||||
// doing it (but then, we should inhibit this in the Raduino).
|
||||
//case MODE_CW:
|
||||
//break;
|
||||
|
||||
case MODE_SSB:
|
||||
// In SSB mode, CAT-PTT will always (de-)activate the Line-In TX
|
||||
// audio source.
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
audioReceive();
|
||||
txState = TX_OFF;
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// In Digital (USB) mode, CAT-PTT will always (de-)activate the
|
||||
// USB-In TX audio source.
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
audioReceive();
|
||||
txState = TX_OFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// checkMicPTT()
|
||||
//======================================================================
|
||||
|
||||
void checkMicPTT()
|
||||
{
|
||||
micPTT.update();
|
||||
|
||||
// If we're transmitting, then we're just going to check if Mic-PTT
|
||||
// was released--the Mic-PTT can always be used to terminate a
|
||||
// transmission from another source.
|
||||
if ((txState != TX_OFF) && micPTT.rose()) {
|
||||
#if defined(DEBUG)
|
||||
USBSERIAL.println("DEBUG: mic PTT released");
|
||||
#endif
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
// In CW mode, we get a sidetone from the uBITX, so we don't mute
|
||||
// the receive audio.
|
||||
if (rigMode != MODE_CW) audioReceive();
|
||||
txState = TX_OFF;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((txState == TX_OFF) && micPTT.fell()) {
|
||||
#if defined(DEBUG)
|
||||
USBSERIAL.println("DEBUG: mic PTT depressed");
|
||||
#endif
|
||||
switch(rigMode) {
|
||||
case MODE_CW:
|
||||
txState = TX_MIC;
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
|
||||
case MODE_SSB:
|
||||
txState = TX_MIC;
|
||||
audioSelectTxInput(TX_MIC_IN);
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// Mic PTT actuation during Digital does nothing.
|
||||
break;
|
||||
|
||||
case MODE_TEST:
|
||||
txState = TX_MIC;
|
||||
audioSelectTxInput(TX_TEST_IN);
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// checkLinePTT()
|
||||
//======================================================================
|
||||
|
||||
void checkLinePTT()
|
||||
{
|
||||
linePTT.update();
|
||||
|
||||
// If we're transmitting, then we're just going to check if Line-PTT
|
||||
// was released--the Line-PTT can always be used to terminate a
|
||||
// transmission from another source.
|
||||
if ((txState != TX_OFF) && linePTT.rose()) {
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
// In CW mode, we get a sidetone from the uBITX, so we don't mute
|
||||
// the receive audio.
|
||||
if (rigMode != MODE_CW) audioReceive();
|
||||
txState = TX_OFF;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((txState == TX_OFF) && linePTT.fell()) {
|
||||
switch(rigMode) {
|
||||
case MODE_CW:
|
||||
txState = TX_LINE;
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
|
||||
case MODE_SSB:
|
||||
txState = TX_LINE;
|
||||
audioSelectTxInput(TX_LINE_IN);
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// Line PTT actuation during Digital does nothing.
|
||||
break;
|
||||
|
||||
case MODE_TEST:
|
||||
txState = TX_LINE;
|
||||
audioSelectTxInput(TX_TEST_IN);
|
||||
audioTransmit();
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void setRigMode(RigMode m)
|
||||
{
|
||||
rigMode = m;
|
||||
|
||||
switch(rigMode) {
|
||||
case MODE_SSB:
|
||||
case MODE_TEST:
|
||||
// SSB sets the TX audio input to line-in. Note that this will be
|
||||
// automatically overridden by mic-in, if the mic PTT is pressed.
|
||||
audioSelectTxInput(TX_LINE_IN);
|
||||
audioSSBFilter();
|
||||
// dspMenu = &ssbMenu;
|
||||
break;
|
||||
|
||||
case MODE_DIGI:
|
||||
// Digi sets the TX audio input to USB-in. Keying in this case must
|
||||
// be via CAT control. Digital modes can also be used through the
|
||||
// line-in, but the rig mode should be set to SSB in that case, and
|
||||
// the rig could be keyed either via the line-in PTT, or via CAT.
|
||||
// Digimodes could also be used through the mic-in, but in that case,
|
||||
// the mic PTT line would need to be keyed by the computer rather
|
||||
// than using CAT for PTT control.
|
||||
audioSelectTxInput(TX_USB_IN);
|
||||
audioDigiFilter();
|
||||
// dspMenu = &digiMenu;
|
||||
break;
|
||||
|
||||
case MODE_CW:
|
||||
// CW just gets the radio off of Mic-In; but it won't use Line-In.
|
||||
audioSelectTxInput(TX_LINE_IN);
|
||||
audioCWFilter();
|
||||
// dspMenu = &cwMenu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
elapsedMillis frameMillis;
|
||||
unsigned frameTime;
|
||||
unsigned frameCounter;
|
||||
unsigned audioProcUsage;
|
||||
unsigned audioMemUsage;
|
||||
|
||||
//======================================================================
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
initCAT(38400, SERIAL_8N1);
|
||||
USBDEBUG("setup started");
|
||||
|
||||
AudioMemory(12);
|
||||
AudioMemory(16); // NOTE: Need to fine tune this. Have had errors due to this being too low.
|
||||
|
||||
micPTT.attach(MIC_PTT_PIN, INPUT_PULLUP);
|
||||
micPTT.interval(25);
|
||||
linePTT.attach(LINE_PTT_PIN, INPUT_PULLUP);
|
||||
linePTT.interval(25);
|
||||
initKeyLine();
|
||||
rigAudio.init();
|
||||
|
||||
pinMode(PTT_KEY_OUT_PIN, OUTPUT);
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
frameCounter = 0;
|
||||
frameMillis = 0;
|
||||
|
||||
audioInit();
|
||||
#if defined(FACTORY_CALIBRATION)
|
||||
setRigMode(MODE_TEST);
|
||||
#else
|
||||
setRigMode(MODE_SSB);
|
||||
#endif
|
||||
knob.write(0);
|
||||
|
||||
btn.attach(ENCODER_SW_PIN, INPUT_PULLUP);
|
||||
btn.interval(25);
|
||||
|
||||
rig.init();
|
||||
|
||||
USBDEBUG("setup completed");
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void loop() {
|
||||
elapsedMillis elapsed = 0;
|
||||
void update_io_menu(Menu_item* item, bool is_active)
|
||||
{
|
||||
Menu_string text;
|
||||
|
||||
if (!is_active || (is_active && item == nullptr)) {
|
||||
sendIOPMenuInactive();
|
||||
} else {
|
||||
item->get_text(text);
|
||||
sendIOPMenuDisplay(text.data());
|
||||
}
|
||||
}
|
||||
|
||||
switch(rigMode) {
|
||||
case MODE_CW:
|
||||
//======================================================================
|
||||
|
||||
void loop()
|
||||
{
|
||||
static bool menu_is_active = false;
|
||||
static bool menu_updated = false;
|
||||
|
||||
static char frame_status[100];
|
||||
static char old_mode_text[17] = " ";
|
||||
static bool paddle_loop = false;
|
||||
// long oldPos = knobPos;
|
||||
|
||||
rig_mode oldRigMode;
|
||||
|
||||
frameCounter++;
|
||||
|
||||
if (rig.is_cw_mode()) {
|
||||
if (keyer.do_paddles()) {
|
||||
if (keyer.is_down()) {
|
||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
||||
} else {
|
||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
||||
|
||||
// Checking for T/R separately from the paddle loop, because it's
|
||||
// possible we're already transmitting (PTT/Key being held), and
|
||||
// we don't want to run the tx() actions if we're already in TX.
|
||||
if (rig.is_rx()) {
|
||||
USBDEBUG("entered TX via paddles");
|
||||
rig.tx();
|
||||
}
|
||||
// No break... if the paddle is not active, I want this to fall
|
||||
// through to checkMicPTT etc... but return early if the paddle is
|
||||
// active, to maximize responsiveness. Probably could just use
|
||||
// 'if' statements here instead of the 'switch'.
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
checkMicPTT();
|
||||
checkLinePTT();
|
||||
serviceCAT();
|
||||
paddle_loop = true;
|
||||
|
||||
if (keyer.is_down()) {
|
||||
setKeyDown();
|
||||
} else {
|
||||
setKeyUp();
|
||||
}
|
||||
|
||||
return; // return early for paddle responsiveness
|
||||
} else {
|
||||
if (paddle_loop) {
|
||||
// If we exit the paddle loop (i.e. keyer completes its keying
|
||||
// sequence), then we'll go back to receive, even if one of the
|
||||
// PTT/Key lines is still held separately. General principle is
|
||||
// that if "something" stops transmitting, then the rig will
|
||||
// stop transmitting.
|
||||
paddle_loop = false;
|
||||
rig.rx();
|
||||
USBDEBUG("exited TX from paddles");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//dspMenu->update();
|
||||
rig.update();
|
||||
|
||||
/*
|
||||
#if defined(DEBUG)
|
||||
int frame_skews = 0; // for debugging; see how often we skew frames
|
||||
#endif
|
||||
oldRigMode = rig.get_rig_mode();
|
||||
|
||||
// put your main code here, to run repeatedly:
|
||||
// Update the mic PTT. We need to tell it if we're in SSB mode, so that
|
||||
// it knows if it should switch to the mic input if pressed. We also
|
||||
// need to make it inactive if we're in DGT mode, since only CAT will be
|
||||
// used to start transmitting in that case.
|
||||
micPTT.setSSBMode(rig.is_ssb_mode());
|
||||
micPTT.update(rig.mode(), !rig.is_digi_mode());
|
||||
|
||||
// Update the line PTT. We need to tell it if we're in SSB mode, so that
|
||||
// it knows if it should switch to the line input if pressed. We also
|
||||
// need to make it inactive if we're in DGT mode, since only CAT will be
|
||||
// used to start transmitting in that case.
|
||||
linePTT.setSSBMode(rig.is_ssb_mode());
|
||||
linePTT.update(rig.mode(), !rig.is_digi_mode());
|
||||
|
||||
// Run at a nominal 20 Hz frame rate.
|
||||
#if defined(DEBUG)
|
||||
if (frame_timer > 50) {
|
||||
frame_skews += 1;
|
||||
}
|
||||
#endif
|
||||
while (frame_timer < 50) { // this doesn't seem like a good way to do this
|
||||
serviceCAT();
|
||||
|
||||
menu_updated = false;
|
||||
btn.update();
|
||||
knobPos = knob.read();
|
||||
|
||||
if (btn.fell()) {
|
||||
btnMillis = 0;
|
||||
USBDEBUG("button pressed");
|
||||
// cancel out any knob rotation that occurred during in conjunction with press/release
|
||||
knob.write(0);
|
||||
|
||||
} else if (btn.rose()) {
|
||||
menu_updated = true;
|
||||
if (btnMillis > 1000) {
|
||||
// long press - exit
|
||||
menu_item = menu_item->exit();
|
||||
USBDEBUG("button released - long (exit)");
|
||||
} else if (btnMillis > 500) {
|
||||
// medium press - altSelect
|
||||
if (menu_is_active) {
|
||||
menu_item = menu_item->altSelect();
|
||||
} else {
|
||||
menu_item = audio_config_menu;
|
||||
menu_is_active = true;
|
||||
}
|
||||
USBDEBUG("button released - medium (altSelect)");
|
||||
} else {
|
||||
// short press - select
|
||||
if (menu_is_active) {
|
||||
menu_item = menu_item->select();
|
||||
} else {
|
||||
menu_item = &main_menu;
|
||||
menu_is_active = true;
|
||||
}
|
||||
USBDEBUG("button released - short (select)");
|
||||
}
|
||||
// cancel out any knob rotation that occurred during in conjunction with press/release
|
||||
knob.write(0);
|
||||
|
||||
} else if (knobPos > 3 && menu_is_active) {
|
||||
// left
|
||||
menu_item = menu_item->prev();
|
||||
knob.write(0);
|
||||
menu_updated = true;
|
||||
USBDEBUG("knob turned left");
|
||||
|
||||
} else if (knobPos < -3 && menu_is_active) {
|
||||
// right
|
||||
menu_item = menu_item->next();
|
||||
knob.write(0);
|
||||
menu_updated = true;
|
||||
USBDEBUG("knob turned right");
|
||||
}
|
||||
*/
|
||||
|
||||
if (menu_item == nullptr) {
|
||||
menu_item = &main_menu;
|
||||
menu_is_active = false;
|
||||
menu_updated = true;
|
||||
USBDEBUG("null menu - reset to main menu");
|
||||
}
|
||||
|
||||
if (menu_updated) {
|
||||
update_io_menu(menu_item, menu_is_active);
|
||||
USBDEBUG("updated main menu");
|
||||
}
|
||||
|
||||
rig.update();
|
||||
|
||||
if (frameMillis > 5000) {
|
||||
#if defined(DEBUG)
|
||||
frameTime = frameMillis;
|
||||
audioProcUsage = AudioProcessorUsageMax();
|
||||
audioMemUsage = AudioMemoryUsageMax();
|
||||
sprintf(frame_status, "update: %u ms, %u frames, %d %% CPU max, %d %% mem max\n", frameTime, frameCounter, audioProcUsage, audioMemUsage);
|
||||
USBDEBUG(frame_status);
|
||||
#endif
|
||||
frameMillis = 0;
|
||||
frameCounter = 0;
|
||||
}
|
||||
|
||||
//audioUpdate(); // was used to update the speech compressor
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
Reference in New Issue
Block a user