ubitx-iop/iopcomm/iopcomm.cpp

473 lines
10 KiB
C++

//======================================================================
// 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 sendCATMessage(const uint8_t* buf)
{
MYSERIAL.write(prefixAndLengthToByte(CAT_PREFIX, 5));
for (int i = 0; i < 5; i++) {
MYSERIAL.write(buf[i]);
}
}
//======================================================================
void sendIOPMessage(IOPMessage const& msg)
{
MYSERIAL.write(prefixAndLengthToByte(IOP_PREFIX, msg.len + 1));
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(rig_mode mode)
{
IOPMessage m;
m.id = IOP_MODE_COMMAND;
m.len = 1;
m.data[0] = static_cast<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 = 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);
}
//======================================================================
/*
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
//======================================================================