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)
|
void sendIOPMessage(IOPMessage const& msg)
|
||||||
{
|
{
|
||||||
MYSERIAL.write(prefixAndLengthToByte(IOP_PREFIX, msg.len + 1));
|
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;
|
IOPMessage m;
|
||||||
m.id = IOP_MODE_COMMAND;
|
m.id = IOP_MODE_COMMAND;
|
||||||
m.len = 1;
|
m.len = 1;
|
||||||
m.data[0] = uint8_t(mode);
|
m.data[0] = static_cast<uint8_t>(mode);
|
||||||
sendIOPMessage(m);
|
sendIOPMessage(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +83,118 @@ void sendIOPModeRequest()
|
|||||||
{
|
{
|
||||||
IOPMessage m;
|
IOPMessage m;
|
||||||
m.id = IOP_MODE_REQUEST;
|
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);
|
sendIOPMessage(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -67,10 +67,16 @@ enum MessageID {
|
|||||||
IOP_START_TX_COMMAND,
|
IOP_START_TX_COMMAND,
|
||||||
IOP_STOP_TX_COMMAND,
|
IOP_STOP_TX_COMMAND,
|
||||||
IOP_CW_CONFIG_MSG,
|
IOP_CW_CONFIG_MSG,
|
||||||
|
IOP_DEBUG_MSG,
|
||||||
|
|
||||||
// Requests
|
// Requests
|
||||||
IOP_MODE_REQUEST,
|
IOP_MODE_REQUEST,
|
||||||
|
IOP_SSB_STATUS_MSG,
|
||||||
|
IOP_DGT_STATUS_MSG,
|
||||||
IOP_CW_STATUS_MSG,
|
IOP_CW_STATUS_MSG,
|
||||||
|
IOP_TEST_STATUS_MSG,
|
||||||
|
IOP_MENU_DISPLAY_MSG,
|
||||||
|
IOP_MENU_INACTIVE_MSG,
|
||||||
|
|
||||||
// add any new elements here
|
// add any new elements here
|
||||||
NUM_MESSAGE_IDS
|
NUM_MESSAGE_IDS
|
||||||
@@ -91,118 +97,164 @@ enum MessageID {
|
|||||||
* (e.g. USB, LSB, etc.)
|
* (e.g. USB, LSB, etc.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum RigMode {
|
enum struct rig_mode {
|
||||||
MODE_SSB = 0,
|
ssb = 0,
|
||||||
MODE_DIGI,
|
cw,
|
||||||
MODE_CW,
|
digi,
|
||||||
MODE_TEST,
|
// add new items here
|
||||||
// add any new elements here
|
count
|
||||||
NUM_RIG_MODES
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keyer modes.
|
/* Keyer modes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum KeyMode {
|
enum struct keyer_mode {
|
||||||
STRAIGHT = 0,
|
straight = 0,
|
||||||
IAMBIC_A,
|
iambic_a,
|
||||||
IAMBIC_B,
|
iambic_b,
|
||||||
//ULTIMATIC,
|
//ultimatic,
|
||||||
//BUG,
|
//bug,
|
||||||
// add any new elements here
|
// add any new items here
|
||||||
NUM_KEY_MODES
|
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 NO_FLAGS = 0;
|
||||||
const uint8_t REVERSED = 1;
|
const uint8_t REVERSED = 1;
|
||||||
|
|
||||||
struct IOPMessage {
|
struct IOPMessage {
|
||||||
uint8_t id;
|
IOPMessage() { memset(data, 0, IOP_MESSAGE_MAX_LEN); }
|
||||||
uint8_t len;
|
uint8_t id;
|
||||||
uint8_t data[IOP_MESSAGE_MAX_LEN];
|
uint8_t len;
|
||||||
|
uint8_t data[IOP_MESSAGE_MAX_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// IConfig
|
||||||
|
//
|
||||||
|
// Interface to a configuration object.
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
void sendIOPMessage(IOPMessage const&);
|
struct bpf_config {
|
||||||
void recvIOPMessage(IOPMessage&, const uint8_t*, int);
|
float lo_freq;
|
||||||
|
float hi_freq;
|
||||||
|
float gain;
|
||||||
|
};
|
||||||
|
|
||||||
void sendIOPModeCommand(RigMode);
|
struct mode_config {
|
||||||
void sendIOPStartTxCommand();
|
mode_config(bool usb, rx_filter f, const bpf_config *fc) : is_usb(usb), filter(f) {
|
||||||
void sendIOPStopTxCommand();
|
for (int i = 0; i < static_cast<int>(rx_filter::count); i++) {
|
||||||
void sendIOPModeRequest();
|
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
|
// CW CONFIGURATION
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
struct CWConfig {
|
const bpf_config cw_filter_config[] =
|
||||||
// mode
|
{bpf_config{ 300.0, 1300.0, 1.0},
|
||||||
KeyMode mode = IAMBIC_A;
|
bpf_config{ 450.0, 950.0, 1.0},
|
||||||
// flags
|
bpf_config{ 575.0, 825.0, 1.0}};
|
||||||
bool reversed = false;
|
|
||||||
// parameters
|
struct cw_config : public mode_config {
|
||||||
uint8_t wpm = 15;
|
cw_config() : mode_config(true, rx_filter::wide, cw_filter_config) {}
|
||||||
float weight = 3.0;
|
keyer_mode mode = keyer_mode::iambic_a;
|
||||||
uint16_t sidetone = 700;
|
// 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:
|
public:
|
||||||
Translator(RigMode&, CWConfig&, Stream&);
|
TTConfig(RxFilter f): filter(f) {}
|
||||||
|
// parameters
|
||||||
void registerPrefixCb(PrefixID id, void (*func)(void*));
|
RxFilter filter = RX_FILTER_MEDIUM;
|
||||||
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*);
|
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// CW STATUS MESSAGE
|
// FUNCTION PROTOTYPES
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
//void packT_DisplayText(TMessage &m, CWConfig const &c)
|
void sendCATMessage(const uint8_t*);
|
||||||
//{
|
void sendIOPMessage(IOPMessage const&);
|
||||||
// m.id = IOP_CW_STATUS_MSG;
|
void recvIOPMessage(IOPMessage&, const uint8_t*, int);
|
||||||
// m.len = 3;
|
|
||||||
// m.data[0] = ' '; // growth
|
|
||||||
// m.data[1] = MODE_LETTER[c.mode];
|
|
||||||
// m.data[2] = ' '; // TODO: RX filter width
|
|
||||||
//}
|
|
||||||
|
|
||||||
// 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
|
#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
|
// audio.h
|
||||||
|
//
|
||||||
|
// NOTE: Let's change the name of this file to RigAudio.h.
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#ifndef __iop_audio_h__
|
#ifndef __iop_audio_h__
|
||||||
#define __iop_audio_h__
|
#define __iop_audio_h__
|
||||||
|
|
||||||
|
#include <Audio.h>
|
||||||
|
#include <dynamicFilters.h>
|
||||||
|
#include <effect_compressor_fb.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
enum RxInput {
|
class RigAudio
|
||||||
RX_RIG_IN = 0,
|
{
|
||||||
RX_USB_IN = 1,
|
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,
|
class bp_filter {
|
||||||
RX_USB_OUT = 2,
|
|
||||||
|
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,
|
class speech_comp
|
||||||
TX_USB_IN = 1,
|
{
|
||||||
TX_TEST_IN = 2,
|
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 audioInit();
|
||||||
void audioSelectTxInput(TxInput);
|
void audioSelectTxInput(TxInput);
|
||||||
void audioTransmit();
|
void audioTransmit();
|
||||||
void audioReceive();
|
void audioReceive();
|
||||||
void audioCalibrate(IOPConfig *, char, char, char, float, bool);
|
void audioCalibrate(AudioConfig *, char, char, char, float, bool);
|
||||||
|
*/
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -1,15 +1,34 @@
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// audio.ino
|
// 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"
|
#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_INPUT RIG
|
||||||
#define DEFAULT_RX_OUTPUT SPKR
|
#define DEFAULT_RX_OUTPUT SPKR
|
||||||
#define DEFAULT_TX_INPUT MIC
|
#define DEFAULT_TX_INPUT MIC
|
||||||
#define DEFAULT_TX_OUTPUT RIG
|
#define DEFAULT_TX_OUTPUT RIG
|
||||||
|
*/
|
||||||
|
|
||||||
#include <Audio.h>
|
#include <Audio.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
@@ -18,674 +37,332 @@ extern IOPConfig iopConfig;
|
|||||||
#include <SerialFlash.h>
|
#include <SerialFlash.h>
|
||||||
|
|
||||||
// GUItool: begin automatically generated code
|
// GUItool: begin automatically generated code
|
||||||
AudioSynthWaveformSine sideTone; //xy=204,221
|
AudioInputI2S inLine; //xy=134,131
|
||||||
AudioInputI2S inLine; //xy=208,170
|
AudioInputUSB inUSB; //xy=134,303
|
||||||
AudioSynthWaveformSine sine2; //xy=207,423
|
AudioSynthWaveformSine sideTone; //xy=136,214
|
||||||
AudioInputUSB inUSB; //xy=208,279
|
AudioSynthWaveformSine sine2; //xy=323,482
|
||||||
AudioSynthWaveformSine sine1; //xy=208,382
|
AudioSynthWaveformSine sine1; //xy=324,428
|
||||||
AudioAnalyzeRMS rmsRX; //xy=383,47
|
AudioAnalyzeRMS rmsRX; //xy=362,20
|
||||||
AudioAnalyzePeak peakRX; //xy=387,98
|
AudioAnalyzePeak peakRX; //xy=362,65
|
||||||
|
AudioEffectCompressor compTX; //xy=383,256
|
||||||
|
AudioAnalyzeRMS compRMS; //xy=388,224
|
||||||
AudioMixer4 mixRX; //xy=444,163
|
AudioMixer4 mixRX; //xy=444,163
|
||||||
AudioMixer4 mixTX; //xy=444,279
|
AudioAmplifier compAmp; //xy=514,257
|
||||||
AudioAmplifier calRxUSB; //xy=634,165
|
AudioFilterFIR filterRX; //xy=577,161
|
||||||
AudioAmplifier calRxSpkr; //xy=638,55
|
AudioMixer4 mixTX; //xy=652,321
|
||||||
AudioAmplifier calRxLine; //xy=641,112
|
AudioAmplifier filterAmp; //xy=700,160
|
||||||
AudioAmplifier calTxLine; //xy=653,248
|
AudioAnalyzeRMS rmsTX; //xy=841,449
|
||||||
AudioAmplifier calTxUSB; //xy=654,305
|
AudioAnalyzePeak peakTX; //xy=843,393
|
||||||
AudioAnalyzePeak peakTX; //xy=669,378
|
AudioAmplifier calRxUSB; //xy=873,172
|
||||||
AudioAnalyzeRMS rmsTX; //xy=683,433
|
AudioAmplifier calRxSpkr; //xy=877,62
|
||||||
AudioOutputAnalog outSpkr; //xy=814,55
|
AudioAmplifier calRxLine; //xy=880,119
|
||||||
AudioOutputUSB outUSB; //xy=823,255
|
AudioAmplifier calTxLine; //xy=892,255
|
||||||
AudioOutputI2S outLine; //xy=826,204
|
AudioAmplifier calTxUSB; //xy=893,312
|
||||||
AudioConnection patchCord1(sideTone, 0, mixRX, 2);
|
AudioOutputAnalog outSpkr; //xy=1053,62
|
||||||
AudioConnection patchCord2(inLine, 0, rmsRX, 0);
|
AudioOutputUSB outUSB; //xy=1066,307
|
||||||
AudioConnection patchCord3(inLine, 0, peakRX, 0);
|
AudioOutputI2S outLine; //xy=1070,192
|
||||||
AudioConnection patchCord4(inLine, 0, mixRX, 0);
|
AudioConnection patchCord1(inLine, 0, rmsRX, 0);
|
||||||
AudioConnection patchCord5(inLine, 1, mixTX, 0);
|
AudioConnection patchCord2(inLine, 0, peakRX, 0);
|
||||||
AudioConnection patchCord6(sine2, 0, mixTX, 3);
|
AudioConnection patchCord3(inLine, 0, mixRX, 0);
|
||||||
AudioConnection patchCord7(inUSB, 0, mixRX, 1);
|
AudioConnection patchCord4(inLine, 1, compTX, 0);
|
||||||
AudioConnection patchCord8(inUSB, 1, mixTX, 1);
|
AudioConnection patchCord5(inLine, 1, compRMS, 0);
|
||||||
AudioConnection patchCord9(sine1, 0, mixTX, 2);
|
AudioConnection patchCord6(inUSB, 0, mixRX, 1);
|
||||||
AudioConnection patchCord10(mixRX, calRxSpkr);
|
AudioConnection patchCord7(inUSB, 1, mixTX, 1);
|
||||||
AudioConnection patchCord11(mixRX, calRxLine);
|
AudioConnection patchCord8(sideTone, 0, mixRX, 2);
|
||||||
AudioConnection patchCord12(mixRX, calRxUSB);
|
AudioConnection patchCord9(sine2, 0, mixTX, 3);
|
||||||
AudioConnection patchCord13(mixTX, calTxLine);
|
AudioConnection patchCord10(sine1, 0, mixTX, 2);
|
||||||
AudioConnection patchCord14(mixTX, calTxUSB);
|
AudioConnection patchCord11(compTX, compAmp);
|
||||||
AudioConnection patchCord15(mixTX, peakTX);
|
AudioConnection patchCord12(mixRX, filterRX);
|
||||||
AudioConnection patchCord16(mixTX, rmsTX);
|
AudioConnection patchCord13(compAmp, 0, mixTX, 0);
|
||||||
AudioConnection patchCord17(calRxUSB, 0, outUSB, 0);
|
AudioConnection patchCord14(filterRX, filterAmp);
|
||||||
AudioConnection patchCord18(calRxSpkr, outSpkr);
|
AudioConnection patchCord15(mixTX, calTxLine);
|
||||||
AudioConnection patchCord19(calRxLine, 0, outLine, 0);
|
AudioConnection patchCord16(mixTX, calTxUSB);
|
||||||
AudioConnection patchCord20(calTxLine, 0, outLine, 1);
|
AudioConnection patchCord17(mixTX, peakTX);
|
||||||
AudioConnection patchCord21(calTxUSB, 0, outUSB, 1);
|
AudioConnection patchCord18(mixTX, rmsTX);
|
||||||
AudioControlSGTL5000 audioCtrl; //xy=391,443
|
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
|
// GUItool: end automatically generated code
|
||||||
|
|
||||||
RxInput audioRxInput;
|
void RigAudio::init() const {
|
||||||
RxOutput audioRxOutput;
|
USBDEBUG("audio initialization started");
|
||||||
TxInput audioTxInput;
|
|
||||||
TxOutput audioTxOutput;
|
|
||||||
|
|
||||||
// audioInit()
|
|
||||||
// Setup the audio subsystem.
|
|
||||||
void audioInit()
|
|
||||||
{
|
|
||||||
audioCtrl.enable();
|
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.muteHeadphone(); // not using the headphone output
|
||||||
audioCtrl.volume(0.0); // 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.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();
|
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...)
|
||||||
audioSelectRxInput(RX_RIG_IN);
|
audioCtrl.micGain(_config.txMicInGain); // superfluous, as I have to do this anytime I switch to mic for some reason
|
||||||
audioSelectTxInput(TX_MIC_IN); // superfluous I think
|
|
||||||
|
|
||||||
//audioCtrl.adcHighPassFilterDisable();
|
// configure line input
|
||||||
audioCtrl.audioPreProcessorEnable();
|
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
|
// setup the two-tone generator
|
||||||
sine1.frequency(700);
|
sine1.frequency(700);
|
||||||
sine2.frequency(1900);
|
sine2.frequency(1900);
|
||||||
sine1.amplitude(0);
|
sine1.amplitude(0);
|
||||||
sine2.amplitude(0);
|
sine2.amplitude(0);
|
||||||
}
|
|
||||||
|
|
||||||
inline void updateRxRigIn()
|
//audioFilter(firActive, NUM_COEFFICIENTS, ID_BANDPASS, W_HAMMING, 300.0, 3100.0); // 2.8 kHz filter
|
||||||
{
|
//filterRX.begin(firActive, NUM_COEFFICIENTS);
|
||||||
audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel);
|
filterAmp.gain(1.0);
|
||||||
mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void muteRxRigIn()
|
// for now, just pass through the compressor
|
||||||
{
|
compTX.disable();
|
||||||
mixRX.gain(RX_RIG_IN, 0.0);
|
compAmp.gain(1.0);
|
||||||
}
|
|
||||||
|
|
||||||
inline void restoreRxRigIn()
|
// Hardware should be all setup... now we're going to mute everything
|
||||||
{
|
// and let the modes take care of enabling/disabling what they should.
|
||||||
mixRX.gain(RX_RIG_IN, iopConfig.rxRigInVol * iopConfig.rxRigInCal);
|
for (int i = 0; i < 4; i++) {
|
||||||
}
|
mixRX.gain(i, 0.0);
|
||||||
|
mixTX.gain(i, 0.0);
|
||||||
inline void updateRxUSBIn()
|
|
||||||
{
|
|
||||||
if (iopConfig.rxUSBInEnable) {
|
|
||||||
mixRX.gain(RX_USB_IN, iopConfig.rxUSBInVol * iopConfig.rxUSBInCal);
|
|
||||||
} else {
|
|
||||||
mixRX.gain(RX_USB_IN, 0.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audioEqualizer();
|
||||||
|
|
||||||
|
USBDEBUG("audio initialization completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void muteRxUSBIn()
|
void RigAudio::muteRx() const {
|
||||||
{
|
mixRX.gain(RX_RIG_IN, 0.0);
|
||||||
mixRX.gain(RX_USB_IN, 0.0);
|
USBDEBUG("RX audio muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void restoreRxUSBIn()
|
void RigAudio::unmuteRx() const {
|
||||||
{
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||||
updateRxUSBIn();
|
mixRX.gain(RX_RIG_IN, _config.rxRigInVol * _config.rxRigInCal);
|
||||||
|
USBDEBUG("RX audio unmuted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateRxSpkrOut()
|
void RigAudio::muteAllTx() const {
|
||||||
{
|
muteMicIn();
|
||||||
calRxSpkr.gain(iopConfig.rxSpkrOutCal);
|
muteLineIn();
|
||||||
|
muteUSBIn();
|
||||||
|
muteTTIn();
|
||||||
|
USBDEBUG("all TX audio muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateRxLineOut()
|
void RigAudio::muteMicIn() const {
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
mixTX.gain(TX_LINE_IN, 0.0);
|
mixTX.gain(TX_LINE_IN, 0.0);
|
||||||
|
USBDEBUG("Mic In audio muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void restoreTxMicIn()
|
void RigAudio::unmuteMicIn() const {
|
||||||
{
|
audioCtrl.inputSelect(AUDIO_INPUT_MIC);
|
||||||
mixTX.gain(TX_LINE_IN, iopConfig.txMicInVol * iopConfig.txMicInCal);
|
audioCtrl.micGain(_config.txMicInGain);
|
||||||
|
mixTX.gain(TX_LINE_IN, _config.txMicInVol * _config.txMicInCal);
|
||||||
|
USBDEBUG("Mic In audio unmuted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateTxLineIn()
|
void RigAudio::muteLineIn() const {
|
||||||
{
|
|
||||||
audioCtrl.lineInLevel(iopConfig.rxRigInLevel, iopConfig.txLineInLevel);
|
|
||||||
mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void muteTxLineIn()
|
|
||||||
{
|
|
||||||
mixTX.gain(TX_LINE_IN, 0.0);
|
mixTX.gain(TX_LINE_IN, 0.0);
|
||||||
|
USBDEBUG("Line In audio muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void restoreTxLineIn()
|
void RigAudio::unmuteLineIn() const {
|
||||||
{
|
audioCtrl.inputSelect(AUDIO_INPUT_LINEIN);
|
||||||
mixTX.gain(TX_LINE_IN, iopConfig.txLineInVol * iopConfig.txLineInCal);
|
mixTX.gain(TX_LINE_IN, _config.txLineInVol * _config.txLineInCal);
|
||||||
|
USBDEBUG("Line In audio unmuted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateTxUSBIn()
|
void RigAudio::muteUSBIn() const {
|
||||||
{
|
|
||||||
mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void muteTxUSBIn()
|
|
||||||
{
|
|
||||||
mixTX.gain(TX_USB_IN, 0.0);
|
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()
|
void RigAudio::muteTTIn() const {
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
mixTX.gain(TX_TEST_IN, 0.0);
|
mixTX.gain(TX_TEST_IN, 0.0);
|
||||||
mixTX.gain(TX_TEST_IN + 1, 0.0);
|
mixTX.gain(TX_TEST_IN + 1, 0.0);
|
||||||
sine1.amplitude(0);
|
sine1.amplitude(0.0);
|
||||||
sine2.amplitude(0);
|
sine2.amplitude(0.0);
|
||||||
|
USBDEBUG("Two Tone audio muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void restoreTxTwoToneIn()
|
void RigAudio::unmuteTTIn() const {
|
||||||
{
|
|
||||||
sine1.amplitude(0.5);
|
sine1.amplitude(0.5);
|
||||||
sine2.amplitude(0.5);
|
sine2.amplitude(0.5);
|
||||||
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
|
mixTX.gain(TX_TEST_IN, _config.txSine1Vol);
|
||||||
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
|
mixTX.gain(TX_TEST_IN + 1, _config.txSine2Vol);
|
||||||
|
USBDEBUG("Two Tone audio unmuted");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateTxRigOut()
|
void RigAudio::muteSpkrOut() const {
|
||||||
{
|
calRxSpkr.gain(0.0);
|
||||||
calTxLine.gain(iopConfig.txRigOutCal);
|
USBDEBUG("Speaker Out audio muted");
|
||||||
audioCtrl.lineOutLevel(iopConfig.rxLineOutLevel, iopConfig.txRigOutLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void updateTxUSBOut()
|
void RigAudio::unmuteSpkrOut() const {
|
||||||
{
|
calRxSpkr.gain(_config.rxSpkrOutCal);
|
||||||
if (iopConfig.txUSBOutEnable) {
|
USBDEBUG("Speaker Out audio unmuted");
|
||||||
calTxUSB.gain(iopConfig.txUSBOutCal);
|
|
||||||
} else {
|
|
||||||
calTxUSB.gain(0.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioSelectRxInput(RxInput input)
|
void RigAudio::muteLineOut() const {
|
||||||
{
|
calRxLine.gain(0.0);
|
||||||
if (audioRxInput != input) {
|
USBDEBUG("Line Out audio muted");
|
||||||
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 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) {
|
config_->enabled = true;
|
||||||
audioTxInput = input;
|
comp_.begin(1, config_->threshold, config_->ratio); // Need to make configurable
|
||||||
//muteTxMicIn(); // redundant w/ Line-In
|
amp_.gain(config_->gain);
|
||||||
muteTxLineIn();
|
}
|
||||||
muteTxUSBIn();
|
|
||||||
muteTxTwoToneIn();
|
void speech_comp::disable()
|
||||||
/* switch(input) {
|
{
|
||||||
case TX_MIC_IN:
|
config_->enabled = false;
|
||||||
muteTxUSBIn();
|
comp_.disable();
|
||||||
restoreTxMicIn();
|
amp_.gain(1.0);
|
||||||
break;
|
}
|
||||||
|
|
||||||
case TX_LINE_IN:
|
// Speech compressor code based on post by 'hyperdyne': https://forum.pjrc.com/threads/36245-Changing-Pitch-of-Voice
|
||||||
muteTxUSBIn();
|
|
||||||
restoreTxLineIn();
|
void speech_comp::update()
|
||||||
break;
|
{
|
||||||
|
float rms_cur;
|
||||||
case TX_USB_IN:
|
if (config_->enabled && rms_.available()) {
|
||||||
muteTxLineIn();
|
rms_cur = rms_.read();
|
||||||
restoreTxUSBIn();
|
env_ = rms_cur + (alpha_ * (env_ - rms_cur));
|
||||||
break;
|
comp_.update_pwr(env_);
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
// audioTransmit()
|
int eqFilter1[5];
|
||||||
// This should be called anytime transmit mode is entered. It should
|
|
||||||
// in theory be called BEFORE the actual transmit signal (key/PTT) is
|
void audioEqualizer()
|
||||||
// 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()
|
|
||||||
{
|
{
|
||||||
|
audioCtrl.audioPreProcessorEnable();
|
||||||
|
audioCtrl.eqSelect(PARAMETRIC_EQUALIZER);
|
||||||
// calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*);
|
// calcBiquad(FilterType,FrequencyC,dBgain,Q,QuantizationUnit,SampleRate,int*);
|
||||||
calcBiquad(FILTER_LOPASS, 3300, 0, 0.707, 524288, 44100, lpFilter);
|
calcBiquad(FILTER_PARAEQ, 2700, 6, 0.707, 524288, 44100, eqFilter1);
|
||||||
calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
// calcBiquad(FILTER_HIPASS, 100, 0, 0.707, 524288, 44100, hpFilter);
|
||||||
audioCtrl.eqFilter(0, lpFilter);
|
audioCtrl.eqFilter(0, eqFilter1);
|
||||||
audioCtrl.eqFilter(1, hpFilter);
|
// audioCtrl.eqFilter(1, hpFilter);
|
||||||
audioCtrl.eqFilter(2, lpFilter);
|
// audioCtrl.eqFilter(2, lpFilter);
|
||||||
audioCtrl.eqFilter(3, hpFilter);
|
// audioCtrl.eqFilter(3, hpFilter);
|
||||||
audioCtrl.eqFilter(4, lpFilter);
|
// audioCtrl.eqFilter(4, lpFilter);
|
||||||
audioCtrl.eqFilter(5, hpFilter);
|
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
@@ -3,11 +3,17 @@
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#include "cat.h"
|
#include "cat.h"
|
||||||
|
#include "TxSwitch.h"
|
||||||
|
|
||||||
// make these messages static inside a function
|
// make these messages static inside a function
|
||||||
IOPMessage inBuf; // input message buffer
|
IOPMessage inBuf; // input message buffer
|
||||||
IOPMessage outBuf; // output message buffer
|
IOPMessage outBuf; // output message buffer
|
||||||
|
|
||||||
|
extern CATSwitch catPTT;
|
||||||
|
extern basic_rig rig;
|
||||||
|
|
||||||
|
int received_mode = 0;
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// CAT from PC-to-IOP
|
// CAT from PC-to-IOP
|
||||||
//
|
//
|
||||||
@@ -30,16 +36,12 @@ void initCAT(long baud, int portConfig)
|
|||||||
// CAT with PC via USB
|
// CAT with PC via USB
|
||||||
USBSERIAL.begin(baud);
|
USBSERIAL.begin(baud);
|
||||||
USBSERIAL.flush();
|
USBSERIAL.flush();
|
||||||
#if defined(DEBUG)
|
USBDEBUG("opened USB serial port (to PC)");
|
||||||
USBSERIAL.println("IOP: opened USB serial port (to PC)");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Comm (including CAT passthru) with Raduino via UART
|
// Comm (including CAT passthru) with Raduino via UART
|
||||||
HWSERIAL.begin(baud, portConfig);
|
HWSERIAL.begin(baud, portConfig);
|
||||||
HWSERIAL.flush();
|
HWSERIAL.flush();
|
||||||
#if defined(DEBUG)
|
USBDEBUG("opened H/W serial port (to Raduino)");
|
||||||
USBSERIAL.println("IOP: opened H/W serial port (to Raduino)");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//sendIOPModeRequest(); // Raduino doesn't support this yet
|
//sendIOPModeRequest(); // Raduino doesn't support this yet
|
||||||
}
|
}
|
||||||
@@ -50,40 +52,47 @@ void processIOPCommand(IOPMessage const& m)
|
|||||||
{
|
{
|
||||||
switch(inBuf.id) {
|
switch(inBuf.id) {
|
||||||
case IOP_MODE_COMMAND:
|
case IOP_MODE_COMMAND:
|
||||||
|
received_mode = 2;
|
||||||
USBDEBUG("IOP_MODE_COMMAND received (from Raduino)");
|
USBDEBUG("IOP_MODE_COMMAND received (from Raduino)");
|
||||||
if (m.len < 1) {
|
if (m.len < 1) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
setRigMode(m.data[0]);
|
rig.set_rig_mode(static_cast<rig_mode>(m.data[0]));
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
switch(rigMode) {
|
switch(rig.get_rig_mode()) {
|
||||||
case MODE_CW:
|
case rig_mode::cw:
|
||||||
USBDEBUG("new mode - CW");
|
USBDEBUG("new mode - CW");
|
||||||
break;
|
break;
|
||||||
case MODE_SSB:
|
case rig_mode::ssb:
|
||||||
USBDEBUG("new mode - SSB");
|
USBDEBUG("new mode - SSB");
|
||||||
break;
|
break;
|
||||||
case MODE_DIGI:
|
case rig_mode::digi:
|
||||||
USBDEBUG("new mode - DIGI");
|
USBDEBUG("new mode - DIG");
|
||||||
break;
|
|
||||||
case MODE_TEST:
|
|
||||||
USBDEBUG("new mode - TEST");
|
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
char errormessage[32];
|
||||||
|
sprintf(errormessage, "unknown mode command - %3d", rig.get_rig_mode());
|
||||||
|
USBDEBUG("mode command not recognized");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOP_START_TX_COMMAND:
|
case IOP_START_TX_COMMAND:
|
||||||
catPTTOn();
|
catPTT.press(rig.mode());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOP_STOP_TX_COMMAND:
|
case IOP_STOP_TX_COMMAND:
|
||||||
catPTTOff();
|
catPTT.release(rig.mode());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IOP_CW_CONFIG_MSG:
|
case IOP_CW_CONFIG_MSG:
|
||||||
break;
|
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 'R':
|
||||||
case 't':
|
case 't':
|
||||||
case 'T':
|
case 'T':
|
||||||
audioCalibrate(&iopConfig, cmd, subcmd, parm, value, (count == 4));
|
//audioCalibrate(&rigConfig.audio, cmd, subcmd, parm, value, (count == 4));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -126,8 +135,8 @@ enum SerialState {
|
|||||||
EEPROM_WRITE,
|
EEPROM_WRITE,
|
||||||
} serialState = NORMAL;
|
} serialState = NORMAL;
|
||||||
|
|
||||||
uint8_t readPrefix = 0;
|
PrefixID readPrefix;
|
||||||
uint8_t readLength = 0;
|
uint8_t readLength;
|
||||||
|
|
||||||
int cmdLength = 0;
|
int cmdLength = 0;
|
||||||
byte cmdBuffer[16];
|
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()
|
void serviceCAT()
|
||||||
{
|
{
|
||||||
uint8_t incomingByte;
|
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
|
// 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();
|
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)
|
#if defined(FACTORY_CALIBRATION)
|
||||||
// unless we're in factory calibration mode, in which case we're going
|
// unless we're in factory calibration mode, in which case we're going
|
||||||
@@ -176,7 +216,7 @@ void serviceCAT()
|
|||||||
#else
|
#else
|
||||||
// Don't pass CAT commands through if in DEBUG mode.
|
// Don't pass CAT commands through if in DEBUG mode.
|
||||||
#if not defined(DEBUG)
|
#if not defined(DEBUG)
|
||||||
HWSERIAL.write(incomingByte);
|
//HWSERIAL.write(incomingByte);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// config.h
|
// config.h
|
||||||
|
//
|
||||||
|
// NOTE: Let's change the name of this file to RigConfig.h.
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#ifndef __iop_config_h__
|
#ifndef __iop_config_h__
|
||||||
#define __iop_config_h__
|
#define __iop_config_h__
|
||||||
|
|
||||||
#include <iopcomm.h>
|
#include <iopcomm.h>
|
||||||
|
//#include "rig.h"
|
||||||
|
|
||||||
#define KEYER_LEFT_PADDLE_PIN 16
|
#define KEYER_LEFT_PADDLE_PIN 16
|
||||||
#define KEYER_RIGHT_PADDLE_PIN 17
|
#define KEYER_RIGHT_PADDLE_PIN 17
|
||||||
@@ -13,19 +16,23 @@
|
|||||||
// Uncomment to use the "factory" calibration mode. This is intended to
|
// Uncomment to use the "factory" calibration mode. This is intended to
|
||||||
// allow calibration of IOP settings, separately from the uBITX/Raduino.
|
// allow calibration of IOP settings, separately from the uBITX/Raduino.
|
||||||
// There will be no pass-thru of any CAT.
|
// 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
|
// AudioConfig
|
||||||
// save them to EEPROM.
|
//======================================================================
|
||||||
struct IOPConfig {
|
|
||||||
|
|
||||||
|
class AudioConfig {
|
||||||
|
public:
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
// RECEIVE PARAMETERS
|
// RECEIVE PARAMETERS
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
// rig-in parameters (RX)
|
// rig-in parameters (RX)
|
||||||
uint8_t rxRigInLevel = 5;
|
uint8_t rxRigInLevel = 8; //5;
|
||||||
float rxRigInVol = 1.0; //0.7;
|
float rxRigInVol = 1.0; //0.7;
|
||||||
float rxRigInCal = 1.0;
|
float rxRigInCal = 8.0; //1.0;
|
||||||
// USB-in parameters (RX) - debug/monitor use only
|
// USB-in parameters (RX) - debug/monitor use only
|
||||||
bool rxUSBInEnable = false;
|
bool rxUSBInEnable = false;
|
||||||
float rxUSBInVol = 1.0;
|
float rxUSBInVol = 1.0;
|
||||||
@@ -37,36 +44,46 @@ struct IOPConfig {
|
|||||||
float rxLineOutCal = 1.0;
|
float rxLineOutCal = 1.0;
|
||||||
// USB-out parameters (RX)
|
// USB-out parameters (RX)
|
||||||
float rxUSBOutCal = 1.0;
|
float rxUSBOutCal = 1.0;
|
||||||
|
// sidetone parameters (really a TX thing, but "RX" side of audio)
|
||||||
|
float sideToneVol = 1.0;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
// TRANSMIT PARAMETERS
|
// 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
|
// 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
|
// This may or may not be totally applicable. I believe it was for
|
||||||
// version of the uBITX. So it may be OBE for my V5. It also alludes to modifications
|
// IMD/spurs on a pre-V5 version of the uBITX. So it may be OBE for
|
||||||
// to the transmit audio chain, which may be something I need to look into (i.e. increasing
|
// 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).
|
// the gain on the initial mic pre-amp).
|
||||||
//
|
//
|
||||||
// Specifically, for the rig-out parameters:
|
// Specifically, for the rig-out parameters:
|
||||||
// line out level 31 = 1.16 V p-p
|
// line out level 31 = 1.16 V p-p
|
||||||
// = 0.58 V peak
|
// = 0.58 V peak
|
||||||
// = 0.41 V rms = 410 mV rms
|
// = 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...
|
// txMicInCal = 0.043 ... seems pretty low...
|
||||||
//
|
//
|
||||||
// Likewise, default line-in (TX) parameters assume consumer line level
|
// Likewise, default line-in (TX) parameters assume consumer line
|
||||||
// input, but with the default audio adaptor line-in level setting (5 = 1.33V p-p).
|
// 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
|
// line in level 5 = 1.33 V p-p
|
||||||
// signal in = 0.894 V p-p
|
// signal in = 0.894 V p-p
|
||||||
// = 0.447 V peak
|
// = 0.447 V peak
|
||||||
// = 0.316 V rms = 316 mV rms
|
// = 0.316 V rms = 316 mV rms
|
||||||
// so input calibration needs to convert that to the 410 mV noted above (equivalent
|
// so input calibration needs to convert that to the 410 mV noted
|
||||||
// for the microphone), so that when that signal gets to the rig-out, it gets
|
// above (equivalent for the microphone), so that when that signal
|
||||||
// treated the same as the mic input.
|
// gets to the rig-out, it gets treated the same as the mic input.
|
||||||
// txLineInCal = 1.30
|
// txLineInCal = 1.30
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
// microphone-in parameters (TX)
|
// microphone-in parameters (TX)
|
||||||
uint8_t txMicInGain = 12;
|
uint8_t txMicInGain = 12;
|
||||||
@@ -84,16 +101,34 @@ struct IOPConfig {
|
|||||||
float txSine2Vol = 1.0;
|
float txSine2Vol = 1.0;
|
||||||
// rig-out parameters (TX) - default settings are based on hitting 70% of 25mVrms w/ mic
|
// rig-out parameters (TX) - default settings are based on hitting 70% of 25mVrms w/ mic
|
||||||
uint8_t txRigOutLevel = 31;
|
uint8_t txRigOutLevel = 31;
|
||||||
float txRigOutCal = 0.043;
|
float txRigOutCal = 0.1; // 0.061;
|
||||||
// USB-out parameters (TX)- debug/monitor use only
|
// USB-out parameters (TX)- debug/monitor use only
|
||||||
bool txUSBOutEnable = true;
|
bool txUSBOutEnable = true;
|
||||||
float txUSBOutCal = 1.0;
|
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
|
#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__
|
#ifndef __menu_h__
|
||||||
#define __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
|
// 16 characters on display
|
||||||
#define MAX_TEXT_LEN 16
|
const int MAX_TEXT_LEN = 16;
|
||||||
#define MENU_SELECTED_CHAR '>'
|
const int max_text_len = 16;
|
||||||
/*
|
const char MENU_SELECTED_CHAR = '>';
|
||||||
public class MenuItem {
|
const char menu_selection_char = '>';
|
||||||
|
|
||||||
|
const char blankLine[17] = " ";
|
||||||
|
|
||||||
|
typedef etl::string<max_text_len> Menu_string;
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Menu_item
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
class Menu_item {
|
||||||
public:
|
public:
|
||||||
MenuItem(bool active = true, int timeout = 0): _active(active), _timeout(timeout), _elapsed(0) {}
|
Menu_item(): parent_link(nullptr) {}
|
||||||
void update() {
|
virtual ~Menu_item() {}
|
||||||
if ((_timeout > 0) && (_elapsed > _timeout)) {
|
|
||||||
_active = false;
|
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 const Menu_string& title() const {
|
||||||
virtual MenuItem* accept();
|
return list_title;
|
||||||
virtual MenuItem* reject();
|
}
|
||||||
virtual MenuItem* next();
|
|
||||||
virtual MenuItem* prev();
|
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:
|
private:
|
||||||
bool _active;
|
Menu_string list_title;
|
||||||
int _timeout;
|
etl::array<const Menu_item*, SIZE> list_items;
|
||||||
elapsedMillis _elapsed;
|
int index;
|
||||||
};
|
};
|
||||||
|
|
||||||
public class SSBMenu {
|
//======================================================================
|
||||||
|
// Config_parm
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
typedef etl::delegate<void(void)> Update_func;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Config_parm : public Menu_item {
|
||||||
public:
|
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:
|
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:
|
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) {}
|
||||||
|
|
||||||
public class CWMenu {
|
virtual void get_text(Menu_string& outstr) const {
|
||||||
public:
|
snprintf(outstr.data(), max_text_len+1, "%-*.*s %3d", max_text_len-4, max_text_len-4, title().data(), value());
|
||||||
private:
|
}
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
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
|
#endif
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
@@ -2,137 +2,93 @@
|
|||||||
// menu.ino
|
// menu.ino
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
#include <iopcomm.h>
|
||||||
|
#include "config.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
|
||||||
/*
|
void do_nothing_func() {}
|
||||||
CW mode:
|
Update_func do_nothing = Update_func::create<do_nothing_func>();
|
||||||
WPM (although we can get this from Raduino)
|
|
||||||
WPM: # (L/R, select/abort)
|
|
||||||
FILT
|
|
||||||
WIDE NORM NARR
|
|
||||||
|
|
||||||
SSB mode:
|
List_menu<7> audio_config_menu_("Audio Config", {
|
||||||
TX LVL
|
new Parm_uint8 ("RX ADC Lvl", rigConfig.audio.rxRigInLevel, 0, 15, 1, do_nothing),
|
||||||
COMP
|
new Parm_uint8 ("RX DAC Lvl", rigConfig.audio.rxLineOutLevel, 13, 31, 1, do_nothing),
|
||||||
FILT
|
new Parm_float ("RX Inp Lvl", rigConfig.audio.rxRigInVol, 0.0, 1.0, 0.1, do_nothing),
|
||||||
WIDE NORM NARR
|
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:
|
const Menu_item* audio_config_menu = &audio_config_menu_;
|
||||||
TX LVL
|
|
||||||
|
/* 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:
|
ListMenu("Configuration",
|
||||||
MenuItem() {}
|
ListMenu("LSB Mode",
|
||||||
virtual MenuItem* next() = 0;
|
ParameterFilter("Filter", c.lsb.filter),
|
||||||
virtual MenuItem* prev() = 0;
|
ParameterOnOff ("Compressor", c.lsb.comp_enable),
|
||||||
char text[MAX_TEXT_LEN + 1];
|
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)),
|
||||||
class TextMenu : public MenuItem {
|
ListMenu("USB Mode",
|
||||||
public:
|
ParameterFilter("Filter", c.usb.filter),
|
||||||
TextMenu(int num_entries, int entry_len): MenuItem(), _num_entries(num_entries), _entry_len(entry_len), _selected(0), _leftmost(0) {
|
ParameterOnOff ("Compressor", c.usb.comp_enable),
|
||||||
text[0] = '\0';
|
ParameterFloat ("Comp Thresh", c.usb.comp_threshold, 0.0, 1.0, 0.1),
|
||||||
_entries = new MenuItem*[_num_entries];
|
ParameterFloat ("Comp Ratio", c.usb.comp_ratio, 0.0, 50.0, 1.0),
|
||||||
_labels = new char*[_num_entries];
|
ParameterFloat ("Comp Gain", c.usb.comp_gain, 0.0, 99.9, 0.1)),
|
||||||
for (int i = 0; i < _num_entries; i++) {
|
ListMenu("CWL Mode",
|
||||||
_labels[i] = NULL;
|
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),
|
||||||
~TextMenu() {
|
ParameterFloat ("Keyer Weight", c.cwl.weight, 0.0, 9.9, 0.1),
|
||||||
for (int i = 0; i < _num_entries; i++) {
|
ParameterInt ("ST Freq", c.sidetone, 300, 3000, 10)),
|
||||||
if (_labels[i] != NULL) {
|
ListMenu("CWU Mode",
|
||||||
delete _labels[i];
|
ParameterFilter("Filter", c.cwl.filter),
|
||||||
}
|
ParameterKeyer ("Keyer Mode", c.cwl.mode),
|
||||||
}
|
ParameterOnOff ("Keyer Rev?", c.cwl.reversed),
|
||||||
delete _labels;
|
ParameterInt ("Keyer WPM", c.cwl.wpm, 0, 60, 1),
|
||||||
delete _entries;
|
ParameterFloat ("Keyer Weight", c.cwl.weight, 0.0, 9.9, 0.1),
|
||||||
}
|
ParameterInt ("ST Freq", c.sidetone, 300, 3000, 10)),
|
||||||
|
ListMenu("DGL Mode",
|
||||||
virtual MenuItem* next() {
|
ParameterFilter("Filter", c.dgl.filter)),
|
||||||
bool dirty = false;
|
ListMenu("DGU Mode",
|
||||||
|
ParameterFilter("Filter", c.dgu.filter)),
|
||||||
if (++_selected == _num_entries) {
|
ListMenu("TTL Mode",
|
||||||
_selected = 0;
|
ParameterFilter("Filter", c.dgl.filter)),
|
||||||
}
|
ListMenu("TTU Mode",
|
||||||
|
ParameterFilter("Filter", c.dgu.filter)),
|
||||||
if (_selected < _leftmost) {
|
ListMenu("Audio",
|
||||||
_leftmost = _selected;
|
ParameterInt ("RX ADC Lvl", c.rxRigInLevel, 0, 15, 1),
|
||||||
dirty = true;
|
ParameterInt ("RX DAC Lvl", c.rxLineOutLevel, 13, 31, 1),
|
||||||
} else {
|
ParameterFloat ("RX Inp Lvl", c.rxRigInVol, 0.0, 1.0, 0.1),
|
||||||
while ((_selected - _leftmost) * _entry_len >= MAX_TEXT_LEN) {
|
ParameterFloat ("RX Inp Cal", c.rxRigInCal, 0.0, 99.9, 0.1),
|
||||||
_leftmost++;
|
ParameterFloat ("RX Spkr Cal", c.rxSpkrOutCal, 0.0, 99.9, 0.1),
|
||||||
dirty = true;
|
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),
|
||||||
if (dirty) {
|
ParameterInt ("TX ADC Lvl", c.txLineInLevel, 0, 15, 1),
|
||||||
for (int i = _leftmost; i < _num_entries; i++) {
|
ParameterInt ("TX DAC Lvl", c.txRigOutLevel, 13, 31, 1),
|
||||||
strncpy(&text[i - _leftmost], _labels[i], _entry_len);
|
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),
|
||||||
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
|
ParameterFloat ("TX Line Lvl", c.txLineInVol, 0.0, 1.0, 0.1),
|
||||||
return this;
|
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),
|
||||||
virtual MenuItem* prev() {
|
ParameterOnOff ("TX USB Dbg", c.txUSBOutEnable),
|
||||||
bool dirty = false;
|
ParameterFloat ("Tone 1 Lvl", c.txSine1Vol, 0.0, 1.0, 0.1),
|
||||||
|
ParameterFloat ("Tone 2 Lvl", c.txSine2Vol, 0.0, 1.0, 0.1),
|
||||||
if (_selected-- == 0) {
|
ParameterFloat ("ST Lvl", c.sideToneVol, 0.0, 1.0, 0.1)));
|
||||||
_selected += _num_entries;
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
if (_selected < _leftmost) {
|
|
||||||
_leftmost = _selected;
|
|
||||||
dirty = true;
|
|
||||||
} else {
|
|
||||||
while ((_selected - _leftmost) * _entry_len >= MAX_TEXT_LEN) {
|
|
||||||
_leftmost++;
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dirty) {
|
|
||||||
updateText();
|
|
||||||
} else {
|
|
||||||
updateCursor();
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addEntry(int i, const char* label, MenuItem* entry) {
|
|
||||||
if (i < _num_entries) {
|
|
||||||
_labels[i] = new char[strlen(label) + 1]; // I need to learn to do strings the C++ way.
|
|
||||||
strcpy(_labels[i], label); // Ditto.
|
|
||||||
_entries[i] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateText() {
|
|
||||||
for (int i = _leftmost; i < _num_entries; i++) {
|
|
||||||
strncpy(&text[i - _leftmost], _labels[i], _entry_len);
|
|
||||||
}
|
|
||||||
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateCursor() {
|
|
||||||
text[_selected - _leftmost] = MENU_SELECTED_CHAR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*MenuItem* operator[](int i) {
|
|
||||||
return this->entries[i];
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _num_entries;
|
|
||||||
int _entry_len;
|
|
||||||
int _selected;
|
|
||||||
int _leftmost;
|
|
||||||
char** _labels;
|
|
||||||
MenuItem** _entries;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// EOF
|
// 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 "eeprom.h"
|
||||||
#include "keyer.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
|
// comment this out to disable debugging code
|
||||||
//#define DEBUG
|
#define DEBUG
|
||||||
|
|
||||||
#if defined(DEBUG)
|
#if defined(DEBUG)
|
||||||
#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x);
|
#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x);
|
||||||
@@ -34,10 +39,35 @@ enum TxState {
|
|||||||
TX_KEYER,
|
TX_KEYER,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RigMode rigMode;
|
//extern RigMode rigMode;
|
||||||
|
|
||||||
extern bool keyerKeyDown;
|
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
|
#endif
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
@@ -2,315 +2,232 @@
|
|||||||
// ubitx_iop.ino
|
// ubitx_iop.ino
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
#include <Encoder.h>
|
||||||
#include <iopcomm.h>
|
#include <iopcomm.h>
|
||||||
|
#include "audio.h"
|
||||||
|
#include "config.h"
|
||||||
#include "ubitx_iop.h"
|
#include "ubitx_iop.h"
|
||||||
|
#include "keyer.h"
|
||||||
|
#include "menu.h"
|
||||||
|
#include "rig.h"
|
||||||
|
#include "TxSwitch.h"
|
||||||
|
|
||||||
#include <Bounce2.h>
|
Keyer keyer{15, 3.0}; // NOTE: make configurable
|
||||||
#define BOUNCE_WITH_PROMPT_DETECTION
|
|
||||||
|
|
||||||
RigMode rigMode = MODE_SSB;
|
RigConfig rigConfig;
|
||||||
IOPConfig iopConfig;
|
RigAudio rigAudio{rigConfig.audio};
|
||||||
|
basic_rig rig{rigConfig, rigAudio};
|
||||||
|
|
||||||
#define MIC_PTT_PIN 21
|
CATSwitch catPTT;
|
||||||
#define LINE_PTT_PIN 20
|
//MicSwitch micPTTHelper;
|
||||||
#define PTT_KEY_OUT_PIN 2
|
GPIOSwitch micPTT(true, MIC_PTT_PIN);
|
||||||
|
//LineSwitch linePTTHelper;
|
||||||
|
GPIOSwitch linePTT(false, LINE_PTT_PIN);
|
||||||
|
|
||||||
Bounce micPTT = Bounce();
|
Encoder knob(ENCODER_A_PIN, ENCODER_B_PIN);
|
||||||
Bounce linePTT = Bounce();
|
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();
|
elapsedMillis frameMillis;
|
||||||
//DigiMenu digiMenu();
|
unsigned frameTime;
|
||||||
//CWMenu cwMenu();
|
unsigned frameCounter;
|
||||||
//MenuItem* dspMenu = &ssbMenu;
|
unsigned audioProcUsage;
|
||||||
|
unsigned audioMemUsage;
|
||||||
//======================================================================
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
// put your setup code here, to run once:
|
// put your setup code here, to run once:
|
||||||
initCAT(38400, SERIAL_8N1);
|
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);
|
initKeyLine();
|
||||||
micPTT.interval(25);
|
rigAudio.init();
|
||||||
linePTT.attach(LINE_PTT_PIN, INPUT_PULLUP);
|
|
||||||
linePTT.interval(25);
|
|
||||||
|
|
||||||
pinMode(PTT_KEY_OUT_PIN, OUTPUT);
|
frameCounter = 0;
|
||||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
frameMillis = 0;
|
||||||
|
|
||||||
audioInit();
|
knob.write(0);
|
||||||
#if defined(FACTORY_CALIBRATION)
|
|
||||||
setRigMode(MODE_TEST);
|
btn.attach(ENCODER_SW_PIN, INPUT_PULLUP);
|
||||||
#else
|
btn.interval(25);
|
||||||
setRigMode(MODE_SSB);
|
|
||||||
#endif
|
rig.init();
|
||||||
|
|
||||||
|
USBDEBUG("setup completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
void loop() {
|
void update_io_menu(Menu_item* item, bool is_active)
|
||||||
elapsedMillis elapsed = 0;
|
{
|
||||||
|
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.do_paddles()) {
|
||||||
if (keyer.is_down()) {
|
|
||||||
digitalWrite(PTT_KEY_OUT_PIN, LOW);
|
// Checking for T/R separately from the paddle loop, because it's
|
||||||
} else {
|
// possible we're already transmitting (PTT/Key being held), and
|
||||||
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
|
// 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:
|
paddle_loop = true;
|
||||||
checkMicPTT();
|
|
||||||
checkLinePTT();
|
if (keyer.is_down()) {
|
||||||
serviceCAT();
|
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();
|
||||||
|
|
||||||
/*
|
oldRigMode = rig.get_rig_mode();
|
||||||
#if defined(DEBUG)
|
|
||||||
int frame_skews = 0; // for debugging; see how often we skew frames
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 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.
|
serviceCAT();
|
||||||
#if defined(DEBUG)
|
|
||||||
if (frame_timer > 50) {
|
menu_updated = false;
|
||||||
frame_skews += 1;
|
btn.update();
|
||||||
}
|
knobPos = knob.read();
|
||||||
#endif
|
|
||||||
while (frame_timer < 50) { // this doesn't seem like a good way to do this
|
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