2020-05-17 00:48:39 -04:00
|
|
|
//======================================================================
|
|
|
|
// 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
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
2020-05-18 09:16:54 -04:00
|
|
|
void sendCATMessage(const uint8_t* buf)
|
|
|
|
{
|
|
|
|
MYSERIAL.write(prefixAndLengthToByte(CAT_PREFIX, 5));
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
|
|
MYSERIAL.write(buf[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
|
2020-05-17 00:48:39 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-05-18 09:16:54 -04:00
|
|
|
//======================================================================
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// DIGI STATUS MESSAGE
|
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
void sendIOPDigiStatus(DigiConfig const &c)
|
|
|
|
{
|
|
|
|
IOPMessage m;
|
|
|
|
m.id = IOP_DIGI_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);
|
|
|
|
}
|
|
|
|
|
2020-05-17 00:48:39 -04:00
|
|
|
//======================================================================
|
|
|
|
|
|
|
|
/*
|
|
|
|
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
|
|
|
|
//======================================================================
|