Updated to include iopcomm.h/iopcomm.cpp, common to both the IOP and the

Raduino.  It was intended to be more extensive, but I had to roll some
of it back.  Mostly just sharing of enums/types currently.

Currently in "factory calibration" mode.  Comms (CAT) in normal mode
needs to be re-checked.

Added two tone test mode, with two new modes available via Raduino menu:
TTL and TTU.

Using test mode, I'm thinking that the proper TX output calibration,
assuming a full-scale 700/1900 test tone, is either:

0.061  (which I believe gives a 25 mV RMS output), or
~0.100 (which is just before the audio starts to distort, in terms of
visible harmonics in the spectrum at the 45 MHz IF.
This commit is contained in:
Rob French 2020-05-16 23:48:39 -05:00
parent e9d021835a
commit ccae79925b
9 changed files with 803 additions and 238 deletions

351
iopcomm/iopcomm.cpp Normal file
View File

@ -0,0 +1,351 @@
//======================================================================
// iopcomm.cpp
//======================================================================
#include <Arduino.h>
#include "iopcomm.h"
#if defined(TEENSYDUINO)
// Compiling for the Teensy, so assuming this is IOP code.
#define MYSERIAL Serial1
#else
// Not compiling for the Teensy, so assuming this is Raduino code.
#define MYSERIAL Serial
#endif
//======================================================================
void sendIOPMessage(IOPMessage const& msg)
{
MYSERIAL.write(prefixAndLengthToByte(IOP_PREFIX, msg.len + 1));
MYSERIAL.write(msg.id);
for (int i = 0; i < msg.len; i++) {
MYSERIAL.write(msg.data[i]);
}
}
//======================================================================
void recvIOPMessage(IOPMessage& msg, const uint8_t* buf, int len)
{
msg.id = buf[0];
msg.len = len - 1;
for (int i = 1; i < len; i++) {
msg.data[i-1] = buf[i];
}
}
//======================================================================
void sendIOPModeCommand(RigMode mode)
{
IOPMessage m;
m.id = IOP_MODE_COMMAND;
m.len = 1;
m.data[0] = uint8_t(mode);
sendIOPMessage(m);
}
//======================================================================
void sendIOPStartTxCommand()
{
IOPMessage m;
m.id = IOP_START_TX_COMMAND;
m.len = 0;
sendIOPMessage(m);
}
//======================================================================
void sendIOPStopTxCommand()
{
IOPMessage m;
m.id = IOP_STOP_TX_COMMAND;
m.len = 0;
sendIOPMessage(m);
}
//======================================================================
void sendIOPModeRequest()
{
IOPMessage m;
m.id = IOP_MODE_REQUEST;
m.len = 0;
sendIOPMessage(m);
}
//======================================================================
/*
enum SerialState {
NORMAL = 0,
CAT_MODE,
IOP_MODE,
EEPROM_READ,
EEPROM_WRITE,
};
Translator::Translator(RigMode& m, CWConfig& c, Stream& s = SERIAL):
mode(m), cwConfig(c), serial(s)
{
for (int i = 0; i < NUM_PREFIX_IDS; i++) {
prefixCb[i] = NULL;
}
for (int i = 0; i < NUM_MESSAGE_IDS; i++) {
messageCb[i] = NULL;
}
}
void Translator::sendACK()
{
serial.write(prefixAndLengthToByte(ACK, 0));
}
void Translator::sendCATMessage(byte b, bool continued=false)
{
if (!continued) { // we're starting a CAT transmission sequence
} else { // we're continuing a CAT transmission sequence
}
}
void Translator::sendIOPMessage(IOPMessage const& m)
{
serial.write(prefixAndLengthToByte(IOP_PREFIX, m.len+1));
serial.write(m.id);
for (int i = 0; i < m.len; i++) {
serial.write(m.data[i]);
}
}
static void Translator::receive()
{
static SerialState state;
static PrefixID readPrefix = 0;
static uint8_t readLength = 0;
static IOPMessage iopMsg;
static uint8_t cmdLength = 0;
static byte cmdBuffer[16];
static char cmdString[17]; // added a char for null termination when required
static uint16_t eepromStartIndex;
static uint16_t eepromReadLength;
static int eepromMagicFlag = 0;
int incomingByte;
for (int i = 0; i < serial.available(); i++) {
incomingByte = serial.read();
switch(state) {
case NORMAL:
if (incomingByte == ACK) {
prefixCb[ACK](NULL);
} else {
readPrefix = byteToPrefix(incomingbyte);
readLength = byteToLength(incomingbyte);
if (readLength > 0) {
switch(readPrefix) {
case CAT_PREFIX:
case RAD_EEPROM_WRITE_PREFIX:
state = CAT_MODE;
break;
case IOP_PREFIX:
state = IOP_MODE;
iopMsg.len = readLength - 1;
cmdLength = 0;
break;
case RAD_EEPROM_READ_PREFIX:
state = EEPROM_READ;
readLength = 5;
eepromMagicFlag = 0;
break;
default:
// should never happen
break;
}
}
}
break;
case CAT_MODE:
// In CAT mode, we just pass thru the remaining bytes to the PC.
if
USBSERIAL.write(incomingByte);
readLength--;
if (readLength == 0) {
state = NORMAL;
}
break;
case IOP_MODE:
cmdBuffer[cmdLength] = incomingByte;
cmdLength++;
readLength--;
if (readLength == 0) {
processIOPCommand(cmdBuffer, cmdLength);
state = NORMAL;
}
break;
case EEPROM_READ:
readLength--;
switch(readLength) {
case 4:
eepromStartIndex = incomingByte;
if (incomingByte == 0x16) {
magicFlag++;
}
break;
case 3:
eepromStartIndex += (256 * incomingByte);
if (incomingByte == 0xe8) {
magicFlag++;
}
break;
case 2:
eepromReadLength = incomingByte;
break;
case 1:
eepromReadLength += (256 * incomingByte);
break;
case 0:
USBSERIAL.write(incomingByte);
if (magicFlag == 2) {
readLength = 126 + 2;
} else {
readLength = eepromReadLength + 2;
}
state = CAT_MODE;
break;
default:
// should never happen
break;
}
break;
case EEPROM_WRITE:
// TODO
break;
default:
// should never happen...
break;
}
}
}
void Translator::registerPrefixCb(PrefixID id, void (*func)(void*))
{
if (id >= 0 && id < NUM_PREFIX_IDS) {
prefixCb[id] = func;
}
void Translator::registerMessageCb(MessageID id, void (*func)(void*))
{
if (id >= 0 && id < NUM_MESSAGE_IDS) {
messageCb[id] = func;
}
}
void Translator::pack_ModeCommand(IOPMessage& m, RigMode r)
{
m.id = IOP_MODE_COMMAND;
m.len = 1;
m.data[0] = r;
}
void Translator::unpack_ModeCommand(IOPMessage const& m)
{
*mode = RigMode(m.data[0]);
}
void Translator::pack_CWConfig(IOPMessage &m, CWConfig const& c)
{
m.id = IOP_CW_CONFIG_MSG;
m.len = 6;
// mode
m.data[0] = byte(c.mode);
// flags
m.data[1] = NO_FLAGS;
m.data[1] |= (c.reversed ? REVERSED : 0);
// parameters
m.data[2] = byte(c.wpm);
m.data[3] = byte(c.weight * 10.0);
m.data[4] = byte(c.sidetone >> 8);
m.data[5] = byte(c.sidetone | 0x0F);
}
void Translator::unpack_CWConfig(IOPMessage const &m)
{
//if (m.id != IOP_CW_CONFIG_MSG || m.len != 6) {
// // do some error thing...
//}
//mode
cwConfig->mode = KeyMode(m.data[0]);
// flags
cwConfig->reversed = bool(m.data[1] & REVERSED);
// parameters
cwConfig->wpm = uint8_t(m.data[2]);
cwConfig->weight = float(m.data[3]) / 10.0;
cwConfig->sidetone = (m.data[4] << 8) | m.data[5];
}
void Translator::pack_ModeRequest(IOPMessage& m)
{
m.id = IOP_MODE_REQUEST;
m.len = 0;
}
void Translator::unpack_ModeRequest(IOPMessage const& m)
{
}
void Translator::unpack(IOPMessage const& m)
{
switch (m.id) {
case IOP_MODE_COMMAND:
unpack_ModeCommand(m);
messageCb[m.id](mode);
break;
case IOP_START_TX_COMMAND:
break;
case IOP_STOP_TX_COMMAND:
break;
case IOP_CW_CONFIG_MSG:
unpack_CWConfig(m);
messageCb[m.id](cwConfig);
break;
case IOP_MODE_REQUEST:
unpack_ModeRequest(m);
messageCb[m.id](NULL);
break;
case IOP_CW_STATUS_MSG:
break;
}
}
*/
//======================================================================
// EOF
//======================================================================

211
iopcomm/iopcomm.h Normal file
View File

@ -0,0 +1,211 @@
//======================================================================
// iopcomm.h
//======================================================================
#ifndef __iopcomm_h__
#define __iopcomm_h__
#include <stdint.h>
/* Message prefixes, starting with the ACK message (0). Message format
* consists of 1 or more bytes, where:
* b[0] - leftmost 3 bits == prefix
* - rightmost 5 bits == length of data (0-31)
* b[1]...b[31] (if present) - data bits
*/
enum PrefixID {
ACK = 0,
CAT_PREFIX,
IOP_PREFIX,
RAD_EEPROM_READ_PREFIX,
RAD_EEPROM_WRITE_PREFIX,
IOP_EEPROM_READ_PREFIX,
IOP_EEPROM_WRITE_PREFIX,
NUM_PREFIX_IDS
};
/* Masks for the leftmost 3 bits (prefix) and rightmost 5 bits (length)
* of a message.
*/
#define PREFIX_MASK 0xE0
#define LENGTH_MASK 0x1F
/* Convert a prefix and length to a byte, by shifting the prefix left
* 5 bits and OR-ing with the 5 bits of length.
*/
inline uint8_t prefixAndLengthToByte(PrefixID id, uint8_t len)
{
return (uint8_t(id) << 5) | (len & LENGTH_MASK);
}
/* Extract the prefix (leftmost 3 bits) from a byte.
*/
inline PrefixID byteToPrefix(uint8_t b)
{
return PrefixID(b >> 5);
}
/* Extract the length (rightmost 5 bits) from a byte.
*/
inline uint8_t byteToLength(byte b)
{
return uint8_t(b & LENGTH_MASK);
}
/* Message IDs/types, for IOP messages (messages between the Raduino and
* the IOP, not including CAT messages to be passed through).
*/
enum MessageID {
// Commands
IOP_MODE_COMMAND = 0,
IOP_START_TX_COMMAND,
IOP_STOP_TX_COMMAND,
IOP_CW_CONFIG_MSG,
// Requests
IOP_MODE_REQUEST,
IOP_CW_STATUS_MSG,
// add any new elements here
NUM_MESSAGE_IDS
};
/* Max length of an IOP message payload (data), based on the following
* message format:
*
* byte 0: prefix (3 bits) + length (5 bits)
* byte 1: message ID (type)
* bytes 2-31: data bytes
*/
#define IOP_MESSAGE_MAX_LEN 30
/* Rig modes. Currently just defined as what the IOP cares about, but
* maybe these need to be expanded to encompass all of the rig modes.
* (e.g. USB, LSB, etc.)
*/
enum RigMode {
MODE_SSB = 0,
MODE_DIGI,
MODE_CW,
MODE_TEST,
// add any new elements here
NUM_RIG_MODES
};
/* Keyer modes.
*/
enum KeyMode {
STRAIGHT = 0,
IAMBIC_A,
IAMBIC_B,
//ULTIMATIC,
//BUG,
// add any new elements here
NUM_KEY_MODES
};
const unsigned char MODE_LETTER[3] = {'S', 'A', 'B'};
const uint8_t NO_FLAGS = 0;
const uint8_t REVERSED = 1;
struct IOPMessage {
uint8_t id;
uint8_t len;
uint8_t data[IOP_MESSAGE_MAX_LEN];
};
void sendIOPMessage(IOPMessage const&);
void recvIOPMessage(IOPMessage&, const uint8_t*, int);
void sendIOPModeCommand(RigMode);
void sendIOPStartTxCommand();
void sendIOPStopTxCommand();
void sendIOPModeRequest();
//======================================================================
// CW CONFIGURATION
//======================================================================
struct CWConfig {
// mode
KeyMode mode = IAMBIC_A;
// flags
bool reversed = false;
// parameters
uint8_t wpm = 15;
float weight = 3.0;
uint16_t sidetone = 700;
};
//======================================================================
// TRANSLATOR
//======================================================================
/*
class Translator
{
public:
Translator(RigMode&, CWConfig&, Stream&);
void registerPrefixCb(PrefixID id, void (*func)(void*));
void registerMessageCb(MessageID id, void (*func)(void*));
void sendACK();
void sendIOPMessage(IOPMessage const&);
void receive();
void pack_ModeCommand(IOPMessage&, RigMode);
void pack_CWConfig(IOPMessage&, CWConfig const&);
void pack_ModeRequest(IOPMessage&);
void unpack(IOPMessage const&);
protected:
void unpack_ModeCommand(IOPMessage const&);
void unpack_CWConfig(IOPMessage const&);
void unpack_ModeRequest(IOPMessage const&);
private:
RigMode& mode;
CWConfig& cwConfig;
Stream& serial;
void (*prefixCb[NUM_PREFIX_IDS])(void*);
void (*messageCb[NUM_MESSAGE_IDS])(void*);
};
*/
//======================================================================
// CW STATUS MESSAGE
//======================================================================
//void packT_DisplayText(TMessage &m, CWConfig const &c)
//{
// m.id = IOP_CW_STATUS_MSG;
// m.len = 3;
// m.data[0] = ' '; // growth
// m.data[1] = MODE_LETTER[c.mode];
// m.data[2] = ' '; // TODO: RX filter width
//}
// No unpack required: this is a string to put on the display.
//======================================================================
#endif
//======================================================================
// EOF
//======================================================================

View File

@ -22,6 +22,7 @@ enum TxInput {
TX_MIC_IN = -1,
TX_LINE_IN = 0,
TX_USB_IN = 1,
TX_TEST_IN = 2,
};
enum TxOutput {

View File

@ -16,43 +16,49 @@ extern IOPConfig iopConfig;
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// GUItool: begin automatically generated code
AudioInputI2S inLine; //xy=224,194
AudioInputUSB inUSB; //xy=224,303
AudioAnalyzeRMS rmsRX; //xy=399,71
AudioAnalyzePeak peakRX; //xy=403,122
AudioMixer4 mixRX; //xy=460,187
AudioMixer4 mixTX; //xy=460,303
AudioAmplifier calRxUSB; //xy=650,189
AudioAmplifier calRxSpkr; //xy=654,79
AudioAmplifier calRxLine; //xy=657,136
AudioAmplifier calTxLine; //xy=669,272
AudioAmplifier calTxUSB; //xy=670,329
AudioAnalyzePeak peakTX; //xy=685,402
AudioAnalyzeRMS rmsTX; //xy=699,457
AudioOutputAnalog outSpkr; //xy=830,79
AudioOutputUSB outUSB; //xy=839,279
AudioOutputI2S outLine; //xy=842,228
AudioConnection patchCord1(inLine, 0, rmsRX, 0);
AudioConnection patchCord2(inLine, 0, peakRX, 0);
AudioConnection patchCord3(inLine, 0, mixRX, 0);
AudioConnection patchCord4(inLine, 1, mixTX, 0);
AudioConnection patchCord5(inUSB, 0, mixRX, 1);
AudioConnection patchCord6(inUSB, 1, mixTX, 1);
AudioConnection patchCord7(mixRX, calRxSpkr);
AudioConnection patchCord8(mixRX, calRxLine);
AudioConnection patchCord9(mixRX, calRxUSB);
AudioConnection patchCord10(mixTX, calTxLine);
AudioConnection patchCord11(mixTX, calTxUSB);
AudioConnection patchCord12(mixTX, peakTX);
AudioConnection patchCord13(mixTX, rmsTX);
AudioConnection patchCord14(calRxUSB, 0, outUSB, 0);
AudioConnection patchCord15(calRxSpkr, outSpkr);
AudioConnection patchCord16(calRxLine, 0, outLine, 0);
AudioConnection patchCord17(calTxLine, 0, outLine, 1);
AudioConnection patchCord18(calTxUSB, 0, outUSB, 1);
AudioControlSGTL5000 audioCtrl; //xy=407,467
AudioSynthWaveformSine sideTone; //xy=204,221
AudioInputI2S inLine; //xy=208,170
AudioSynthWaveformSine sine2; //xy=207,423
AudioInputUSB inUSB; //xy=208,279
AudioSynthWaveformSine sine1; //xy=208,382
AudioAnalyzeRMS rmsRX; //xy=383,47
AudioAnalyzePeak peakRX; //xy=387,98
AudioMixer4 mixRX; //xy=444,163
AudioMixer4 mixTX; //xy=444,279
AudioAmplifier calRxUSB; //xy=634,165
AudioAmplifier calRxSpkr; //xy=638,55
AudioAmplifier calRxLine; //xy=641,112
AudioAmplifier calTxLine; //xy=653,248
AudioAmplifier calTxUSB; //xy=654,305
AudioAnalyzePeak peakTX; //xy=669,378
AudioAnalyzeRMS rmsTX; //xy=683,433
AudioOutputAnalog outSpkr; //xy=814,55
AudioOutputUSB outUSB; //xy=823,255
AudioOutputI2S outLine; //xy=826,204
AudioConnection patchCord1(sideTone, 0, mixRX, 2);
AudioConnection patchCord2(inLine, 0, rmsRX, 0);
AudioConnection patchCord3(inLine, 0, peakRX, 0);
AudioConnection patchCord4(inLine, 0, mixRX, 0);
AudioConnection patchCord5(inLine, 1, mixTX, 0);
AudioConnection patchCord6(sine2, 0, mixTX, 3);
AudioConnection patchCord7(inUSB, 0, mixRX, 1);
AudioConnection patchCord8(inUSB, 1, mixTX, 1);
AudioConnection patchCord9(sine1, 0, mixTX, 2);
AudioConnection patchCord10(mixRX, calRxSpkr);
AudioConnection patchCord11(mixRX, calRxLine);
AudioConnection patchCord12(mixRX, calRxUSB);
AudioConnection patchCord13(mixTX, calTxLine);
AudioConnection patchCord14(mixTX, calTxUSB);
AudioConnection patchCord15(mixTX, peakTX);
AudioConnection patchCord16(mixTX, rmsTX);
AudioConnection patchCord17(calRxUSB, 0, outUSB, 0);
AudioConnection patchCord18(calRxSpkr, outSpkr);
AudioConnection patchCord19(calRxLine, 0, outLine, 0);
AudioConnection patchCord20(calTxLine, 0, outLine, 1);
AudioConnection patchCord21(calTxUSB, 0, outUSB, 1);
AudioControlSGTL5000 audioCtrl; //xy=391,443
// GUItool: end automatically generated code
RxInput audioRxInput;
@ -75,11 +81,30 @@ void audioInit()
//audioCtrl.dacVolumeRamp(); // if this seems too slow, might try dacVolumeRampLinear().
//audioCtrl.dacVolume(1.0, 0.0); // we're going to mute TX audio via the DAC unless we're transmitting
updateRxRigIn();
updateRxSpkrOut();
updateRxLineOut();
updateRxUSBOut();
// Note - these really just need to be init functions; keep things muted while setting them up.
updateTxMicIn();
updateTxLineIn();
updateTxUSBIn();
updateTxTwoToneIn();
updateTxRigOut();
audioSelectRxInput(RX_RIG_IN);
audioSelectTxInput(TX_MIC_IN); // superfluous I think
//audioCtrl.adcHighPassFilterDisable();
audioCtrl.audioPreProcessorEnable();
// setup the two-tone generator
sine1.frequency(700);
sine2.frequency(1900);
sine1.amplitude(0);
sine2.amplitude(0);
}
inline void updateRxRigIn()
@ -180,6 +205,30 @@ inline void restoreTxUSBIn()
mixTX.gain(TX_USB_IN, iopConfig.txUSBInVol * iopConfig.txUSBInCal);
}
inline void updateTxTwoToneIn()
{
sine1.amplitude(0.5);
sine2.amplitude(0.5);
mixTX.gain(TX_TEST_IN, iopConfig.txSine1Vol);
mixTX.gain(TX_TEST_IN + 1, iopConfig.txSine2Vol);
}
inline void muteTxTwoToneIn()
{
mixTX.gain(TX_TEST_IN, 0.0);
mixTX.gain(TX_TEST_IN + 1, 0.0);
sine1.amplitude(0);
sine2.amplitude(0);
}
inline void restoreTxTwoToneIn()
{
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 updateTxRigOut()
{
calTxLine.gain(iopConfig.txRigOutCal);
@ -224,8 +273,7 @@ void audioSelectTxInput(TxInput input)
//muteTxMicIn(); // redundant w/ Line-In
muteTxLineIn();
muteTxUSBIn();
mixTX.gain(2, 0);
mixTX.gain(3, 0);
muteTxTwoToneIn();
/* switch(input) {
case TX_MIC_IN:
muteTxUSBIn();
@ -293,6 +341,11 @@ void audioTransmit()
muteRxRigIn();
updateTxUSBIn();
break;
case MODE_TEST:
muteRxRigIn();
updateTxTwoToneIn();
break;
}
}
@ -323,6 +376,11 @@ void audioReceive()
muteTxUSBIn();
restoreRxRigIn();
break;
case MODE_TEST:
muteTxTwoToneIn();
restoreRxRigIn();
break;
}
}

View File

@ -5,134 +5,18 @@
#ifndef __iop_cat_h__
#define __iop_cat_h__
#define ACK 0
#define CAT_PREFIX 0xC0
#define IOP_PREFIX 0xD0
#define EEPROM_READ_PREFIX 0xE0
#define EEPROM_WRITE_PREFIX 0xF0
#define IOP_MODE_COMMAND 0x00
#define IOP_START_TX_COMMAND 0x01
#define IOP_STOP_TX_COMMAND 0x02
#define IOP_CW_CONFIG_MSG 0x03
#define IOP_MODE_REQUEST 0x00
#define IOP_CW_STATUS_MSG 0x03
#define IOP_MODE_SSB 0x00
#define IOP_MODE_DIGI 0x01
#define IOP_MODE_CW 0x02
//#define ACK 0
//#define CAT_PREFIX 0xC0
//#define IOP_PREFIX 0xD0
//#define EEPROM_READ_PREFIX 0xE0
//#define EEPROM_WRITE_PREFIX 0xF0
#include <iopcomm.h>
#include "config.h"
#define USBSERIAL Serial
#define HWSERIAL Serial1
/*struct IOPTMsg {
};
*/
enum KeyMode {
STRAIGHT = 0,
IAMBIC_A,
IAMBIC_B,
//ULTIMATIC,
//BUG,
};
const byte MODE_LETTER[3] = {'S', 'A', 'B'};
const byte NO_FLAGS = 0;
const byte REVERSED = 1;
#define R_MESSAGE_MAX_LEN 32
#define T_MESSAGE_MAX_LEN 32
struct RMessage {
uint8_t id;
uint8_t len;
byte data[R_MESSAGE_MAX_LEN];
};
struct TMessage {
uint8_t id;
uint8_t len;
byte data[T_MESSAGE_MAX_LEN];
};
//======================================================================
// CW CONFIGURATION MESSAGE
//======================================================================
struct CWConfig {
// mode
KeyMode mode = IAMBIC_A;
// flags
bool reversed = false;
// parameters
uint8_t wpm = 15;
float weight = 3.0;
uint16_t sidetone = 700;
};
void packR_CWConfig(RMessage &m, CWConfig const &c)
{
m.id = IOP_CW_CONFIG_MSG;
m.len = 6;
// mode
m.data[0] = byte(c.mode);
// flags
m.data[1] = NO_FLAGS;
m.data[1] |= (c.reversed ? REVERSED : 0);
// parameters
m.data[2] = byte(c.wpm);
m.data[3] = byte(c.weight * 10.0);
m.data[4] = byte(c.sidetone >> 8);
m.data[5] = byte(c.sidetone | 0x0F);
}
void unpackR_CWConfig(CWConfig &c, RMessage const &m)
{
//if (m.id != IOP_CW_CONFIG_MSG || m.len != 6) {
// // do some error thing...
//}
//mode
c.mode = KeyMode(m.data[0]);
// flags
c.reversed = bool(m.data[1] & REVERSED);
// parameters
c.wpm = uint8_t(m.data[2]);
c.weight = float(m.data[3]) / 10.0;
c.sidetone = (m.data[4] << 8) | m.data[5];
}
//======================================================================
// MODE REQUEST MESSAGE
//======================================================================
void packT_ModeRequest(TMessage &m)
{
m.id = IOP_MODE_REQUEST;
m.len = 0;
}
//======================================================================
// CW STATUS MESSAGE
//======================================================================
//void packT_DisplayText(TMessage &m, CWConfig const &c)
//{
// m.id = IOP_CW_STATUS_MSG;
// m.len = 3;
// m.data[0] = ' '; // growth
// m.data[1] = MODE_LETTER[c.mode];
// m.data[2] = ' '; // TODO: RX filter width
//}
// No unpack required: this is a string to put on the display.
//======================================================================
void initCAT(long, int);
void serviceCAT();

View File

@ -4,18 +4,9 @@
#include "cat.h"
//#define ACK 0
//#define CAT_PREFIX 0xC0
//#define IOP_PREFIX 0xD0
//#define EEPROM_READ_PREFIX 0xE0
//#define EEPROM_WRITE_PREFIX 0xF0
//
//#define IOP_MODE_COMMAND 0x00
//#define IOP_START_TX_COMMAND 0x01
//#define IOP_STOP_TX_COMMAND 0x02
//#define IOP_MODE_SSB 0x00
//#define IOP_MODE_DIGI 0x01
//#define IOP_MODE_CW 0x02
// make these messages static inside a function
IOPMessage inBuf; // input message buffer
IOPMessage outBuf; // output message buffer
//======================================================================
// CAT from PC-to-IOP
@ -39,50 +30,60 @@ void initCAT(long baud, int portConfig)
// CAT with PC via USB
USBSERIAL.begin(baud);
USBSERIAL.flush();
#if not defined(FACTORY_CALIBRATION)
// CAT with Raduino via UART
HWSERIAL.begin(baud, portConfig);
USBSERIAL.flush();
#if defined(DEBUG)
USBSERIAL.println("IOP: opened USB serial port (to PC)");
#endif
// Comm (including CAT passthru) with Raduino via UART
HWSERIAL.begin(baud, portConfig);
HWSERIAL.flush();
#if defined(DEBUG)
USBSERIAL.println("IOP: opened H/W serial port (to Raduino)");
#endif
//sendIOPModeRequest(); // Raduino doesn't support this yet
}
//======================================================================
void processIOPCommand(const byte* buf, int len)
void processIOPCommand(IOPMessage const& m)
{
if (len > 0) {
switch(buf[0]) {
case IOP_MODE_COMMAND:
if (len < 2) {
return;
} else {
setRigMode(RigMode(buf[1]));
#if defined(DEBUG)
USBSERIAL.print("DEBUG: mode ");
switch(rigMode) {
case MODE_CW:
USBSERIAL.println("CW");
break;
case MODE_SSB:
USBSERIAL.println("SSB");
break;
case MODE_DIGI:
USBSERIAL.println("DIGI");
break;
}
#endif
}
break;
case IOP_START_TX_COMMAND:
catPTTOn();
break;
case IOP_STOP_TX_COMMAND:
catPTTOff();
break;
switch(inBuf.id) {
case IOP_MODE_COMMAND:
USBDEBUG("IOP_MODE_COMMAND received (from Raduino)");
if (m.len < 1) {
return;
} else {
setRigMode(m.data[0]);
#if defined(DEBUG)
switch(rigMode) {
case MODE_CW:
USBDEBUG("new mode - CW");
break;
case MODE_SSB:
USBDEBUG("new mode - SSB");
break;
case MODE_DIGI:
USBDEBUG("new mode - DIGI");
break;
case MODE_TEST:
USBDEBUG("new mode - TEST");
break;
}
#endif
}
break;
case IOP_START_TX_COMMAND:
catPTTOn();
break;
case IOP_STOP_TX_COMMAND:
catPTTOff();
break;
case IOP_CW_CONFIG_MSG:
break;
}
}
@ -117,15 +118,16 @@ void processCalCommand(const char* buf)
//======================================================================
enum serial_mode_t {
enum SerialState {
NORMAL = 0,
CAT_MODE,
IOP_MODE,
EEPROM_READ,
EEPROM_WRITE,
} serialMode = NORMAL;
} serialState = NORMAL;
int readLength = 0;
uint8_t readPrefix = 0;
uint8_t readLength = 0;
int cmdLength = 0;
byte cmdBuffer[16];
@ -139,7 +141,7 @@ int magicFlag = 0;
void serviceCAT()
{
int incomingByte;
uint8_t incomingByte;
// read from the USB serial, pass through to UART serial
for (int i = 0; i < USBSERIAL.available(); i++) {
@ -172,33 +174,56 @@ void serviceCAT()
}
}
#else
// Don't pass CAT commands through if in DEBUG mode.
#if not defined(DEBUG)
HWSERIAL.write(incomingByte);
#endif
}
// read from the UART serial, see what we need to do with it
for (int i = 0; i < HWSERIAL.available(); i++) {
incomingByte = HWSERIAL.read();
#if defined(DEBUG)
char ibBuff[20];
itoa(serialState, ibBuff, 10);
USBSERIAL.print("IOP: serialState = ");
USBSERIAL.print(ibBuff);
itoa(incomingByte, ibBuff, 10);
USBSERIAL.print("; incomingByte = ");
USBSERIAL.println(ibBuff);
#endif
switch(serialMode) {
switch(serialState) {
case NORMAL:
if (incomingByte == ACK) {
USBSERIAL.write(incomingByte);
} else {
readLength = incomingByte & 0x0F;
} else {
readPrefix = byteToPrefix(incomingByte);
readLength = byteToLength(incomingByte);
#if defined(DEBUG)
itoa(readPrefix, ibBuff, 10);
USBSERIAL.print("IOP: readPrefix = ");
USBSERIAL.print(ibBuff);
itoa(readLength, ibBuff, 10);
USBSERIAL.print("; readLength = ");
USBSERIAL.println(ibBuff);
#endif
if (readLength > 0) {
switch(incomingByte & 0xF0) {
USBDEBUG("readLength > 0");
switch(readPrefix) {
case CAT_PREFIX:
case EEPROM_WRITE_PREFIX:
serialMode = CAT_MODE;
case RAD_EEPROM_WRITE_PREFIX:
serialState = CAT_MODE;
break;
case IOP_PREFIX:
serialMode = IOP_MODE;
cmdLength = 0;
USBDEBUG("entering IOP_MODE");
serialState = IOP_MODE;
cmdLength = 0;
break;
case EEPROM_READ_PREFIX:
serialMode = EEPROM_READ;
case RAD_EEPROM_READ_PREFIX:
serialState = EEPROM_READ;
readLength = 5;
magicFlag = 0;
break;
@ -216,7 +241,7 @@ void serviceCAT()
USBSERIAL.write(incomingByte);
readLength--;
if (readLength == 0) {
serialMode = NORMAL;
serialState = NORMAL;
}
break;
@ -225,8 +250,9 @@ void serviceCAT()
cmdLength++;
readLength--;
if (readLength == 0) {
processIOPCommand(cmdBuffer, cmdLength);
serialMode = NORMAL;
recvIOPMessage(inBuf, cmdBuffer, cmdLength);
processIOPCommand(inBuf);
serialState = NORMAL;
}
break;
@ -262,7 +288,7 @@ void serviceCAT()
} else {
readLength = eepromReadLength + 2;
}
serialMode = CAT_MODE;
serialState = CAT_MODE;
break;
default:

View File

@ -5,13 +5,15 @@
#ifndef __iop_config_h__
#define __iop_config_h__
#include <iopcomm.h>
#define KEYER_LEFT_PADDLE_PIN 16
#define KEYER_RIGHT_PADDLE_PIN 17
// Uncomment to use the "factory" calibration mode. This is intended to
// allow calibration of IOP settings, separately from the uBITX/Raduino.
// There will be no pass-thru of any CAT.
//#define FACTORY_CALIBRATION
#define FACTORY_CALIBRATION
// IOPConfig
// Used to store configuration parameters during runtime, as well as to
@ -22,7 +24,7 @@ struct IOPConfig {
// rig-in parameters (RX)
uint8_t rxRigInLevel = 5;
float rxRigInVol = 0.7;
float rxRigInVol = 1.0; //0.7;
float rxRigInCal = 1.0;
// USB-in parameters (RX) - debug/monitor use only
bool rxUSBInEnable = false;
@ -68,21 +70,27 @@ struct IOPConfig {
// microphone-in parameters (TX)
uint8_t txMicInGain = 12;
float txMicInVol = 0.7;
float txMicInVol = 1.0; //0.7;
float txMicInCal = 1.0;
// line-in parameters (TX)
uint8_t txLineInLevel = 5;
float txLineInVol = 0.7;
float txLineInVol = 1.0; //0.7;
float txLineInCal = 1.30;
// USB-in parameters (TX)
float txUSBInVol = 0.7;
float txUSBInVol = 1.0; //0.7;
float txUSBInCal = 1.0;
// two-tone parameters (TX)
float txSine1Vol = 1.0;
float txSine2Vol = 1.0;
// rig-out parameters (TX) - default settings are based on hitting 70% of 25mVrms w/ mic
uint8_t txRigOutLevel = 31;
float txRigOutCal = 0.043;
float txRigOutCal = 0.043;
// USB-out parameters (TX)- debug/monitor use only
bool txUSBOutEnable = true;
float txUSBOutCal = 1.0;
// CW configuration
CWConfig cw;
};
extern IOPConfig iopConfig;

View File

@ -14,11 +14,17 @@
// comment this out to disable debugging code
//#define DEBUG
enum RigMode {
MODE_SSB = 0,
MODE_DIGI = 1,
MODE_CW = 2,
};
#if defined(DEBUG)
#define USBDEBUG(x) USBSERIAL.print("IOP: "); USBSERIAL.println(x);
#else
#define USBDEBUG(x)
#endif
//enum RigMode {
// MODE_SSB = 0,
// MODE_DIGI = 1,
// MODE_CW = 2,
//};
enum TxState {
TX_OFF = 0,

View File

@ -2,6 +2,7 @@
// ubitx_iop.ino
//======================================================================
#include <iopcomm.h>
#include "ubitx_iop.h"
#include <Bounce2.h>
@ -145,6 +146,13 @@ void checkMicPTT()
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;
}
}
}
@ -186,6 +194,13 @@ void checkLinePTT()
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;
}
}
}
@ -198,6 +213,7 @@ void setRigMode(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);
@ -244,7 +260,11 @@ void setup() {
digitalWrite(PTT_KEY_OUT_PIN, HIGH);
audioInit();
#if defined(FACTORY_CALIBRATION)
setRigMode(MODE_TEST);
#else
setRigMode(MODE_SSB);
#endif
}
//======================================================================