2021-02-02 15:53:28 +00:00
|
|
|
#include "kiss_processor.h"
|
|
|
|
|
|
|
|
namespace Kiss {
|
2021-02-12 14:33:25 +00:00
|
|
|
|
|
|
|
CircularBuffer<uint8_t, Processor::CfgSerialToRigQueueSize> Processor::serialToRigQueue_;
|
|
|
|
CircularBuffer<uint8_t, Processor::CfgRigToSerialQueueSize> Processor::rigToSerialQueue_;
|
|
|
|
CircularBuffer<uint8_t, Processor::CfgRigToSerialQueueSize> Processor::rigToSerialQueueIndex_;
|
|
|
|
|
2021-02-02 15:53:28 +00:00
|
|
|
Processor::Processor()
|
2021-10-26 10:09:43 +00:00
|
|
|
: disableKiss_(false)
|
|
|
|
, isRawIdle_(true)
|
|
|
|
, state_(State::GetStart)
|
2021-02-02 15:53:28 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-02-12 14:43:18 +00:00
|
|
|
void Processor::sendRigToSerial(Cmd cmd, const byte *packet, int packetLength) {
|
2021-10-26 10:09:43 +00:00
|
|
|
if (disableKiss_) {
|
|
|
|
for (int i = 0; i < packetLength; i++) {
|
|
|
|
byte rxByte = packet[i];
|
2021-10-26 12:07:27 +00:00
|
|
|
// TNC2 splits on \n
|
|
|
|
if (rxByte == '\0') {
|
|
|
|
onSerialTx('\n');
|
|
|
|
} else {
|
|
|
|
onSerialTx(rxByte);
|
|
|
|
}
|
|
|
|
// append \n for TNC2 compatibility if not there
|
|
|
|
if (rxByte != '\n' && rxByte != '\0' && i == packetLength - 1) {
|
|
|
|
onSerialTx('\n');
|
|
|
|
}
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
2021-10-26 10:09:43 +00:00
|
|
|
} else {
|
|
|
|
onSerialTx((byte)Marker::Fend);
|
|
|
|
onSerialTx((byte)cmd);
|
2021-02-02 15:53:28 +00:00
|
|
|
|
2021-10-26 10:09:43 +00:00
|
|
|
for (int i = 0; i < packetLength; i++) {
|
|
|
|
byte rxByte = packet[i];
|
|
|
|
|
|
|
|
if (rxByte == Marker::Fend) {
|
|
|
|
onSerialTx((byte)Marker::Fesc);
|
|
|
|
onSerialTx((byte)Marker::Tfend);
|
|
|
|
}
|
|
|
|
else if (rxByte == Marker::Fesc) {
|
|
|
|
onSerialTx((byte)Marker::Fesc);
|
|
|
|
onSerialTx((byte)Marker::Tfesc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
onSerialTx(rxByte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onSerialTx((byte)Marker::Fend);
|
|
|
|
}
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
2021-02-12 14:33:25 +00:00
|
|
|
|
2021-02-12 14:43:18 +00:00
|
|
|
void ICACHE_RAM_ATTR Processor::queueRigToSerialIsr(Cmd cmd, const byte *packet, int packetLength) {
|
2021-02-12 14:33:25 +00:00
|
|
|
if (!rigToSerialQueueIndex_.unshift(packetLength)) {
|
2021-10-22 19:09:17 +00:00
|
|
|
LOG_WARN("Rig to serial queue is full!");
|
2021-02-12 14:33:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < packetLength; i++) {
|
|
|
|
if (!rigToSerialQueue_.unshift(packet[i])) {
|
2021-10-22 19:09:17 +00:00
|
|
|
LOG_WARN("Rig to serial queue is full!");
|
2021-02-12 14:33:25 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 14:43:18 +00:00
|
|
|
void Processor::queueSerialToRig(Cmd cmd, const byte *packet, int packetLength) {
|
2021-02-12 14:33:25 +00:00
|
|
|
bool result = 1;
|
2021-10-26 10:09:43 +00:00
|
|
|
if (disableKiss_) {
|
2022-08-25 07:28:35 +00:00
|
|
|
// inject proprietary identifier
|
|
|
|
result &= serialToRigQueue_.unshift('<');
|
|
|
|
result &= serialToRigQueue_.unshift(0xff);
|
|
|
|
result &= serialToRigQueue_.unshift(0x01);
|
2021-10-26 12:07:27 +00:00
|
|
|
// TNC2, send as is, receiveByteRaw will deal with it
|
2021-10-26 10:09:43 +00:00
|
|
|
for (int i = 0; i < packetLength; i++) {
|
|
|
|
byte rxByte = packet[i];
|
2021-02-12 14:33:25 +00:00
|
|
|
result &= serialToRigQueue_.unshift(rxByte);
|
|
|
|
}
|
2021-10-26 13:36:16 +00:00
|
|
|
result &= serialToRigQueue_.unshift('\n');
|
2021-10-26 10:09:43 +00:00
|
|
|
} else {
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Fend);
|
|
|
|
result &= serialToRigQueue_.unshift(cmd);
|
|
|
|
|
|
|
|
for (int i = 0; i < packetLength; i++) {
|
|
|
|
byte rxByte = packet[i];
|
|
|
|
|
|
|
|
if (rxByte == Marker::Fend) {
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Fesc);
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Tfend);
|
|
|
|
}
|
|
|
|
else if (rxByte == Marker::Fesc) {
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Fesc);
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Tfesc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
result &= serialToRigQueue_.unshift(rxByte);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result &= serialToRigQueue_.unshift(Marker::Fend);
|
2021-02-12 14:33:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!result) {
|
2021-10-22 19:09:17 +00:00
|
|
|
LOG_WARN("Serial to rig queue overflow!");
|
2021-02-12 14:33:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Processor::processRigToSerial()
|
|
|
|
{
|
|
|
|
bool isProcessed = false;
|
|
|
|
|
|
|
|
if (rigToSerialQueueIndex_.isEmpty()) {
|
|
|
|
return isProcessed;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!rigToSerialQueueIndex_.isEmpty()) {
|
|
|
|
|
|
|
|
int rxPacketSize = rigToSerialQueueIndex_.pop();
|
|
|
|
byte buf[rxPacketSize];
|
|
|
|
|
2022-08-25 20:37:21 +00:00
|
|
|
int readCnt = rxPacketSize;
|
|
|
|
for (int i = 0, j = 0; i < readCnt; i++) {
|
2022-08-25 20:20:44 +00:00
|
|
|
byte rxByte = rigToSerialQueue_.pop();
|
|
|
|
if (disableKiss_) {
|
|
|
|
// filter out properietary identifier
|
|
|
|
if ((i == 0 && rxByte == '<') ||
|
|
|
|
(i == 1 && rxByte == 0xff) ||
|
|
|
|
(i == 2 && rxByte == 0x01))
|
|
|
|
{
|
|
|
|
rxPacketSize--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
buf[j++] = rxByte;
|
2021-02-12 14:33:25 +00:00
|
|
|
}
|
2021-02-12 14:43:18 +00:00
|
|
|
sendRigToSerial(Cmd::Data, buf, rxPacketSize);
|
2021-02-12 14:33:25 +00:00
|
|
|
onRigPacket(&buf, rxPacketSize);
|
|
|
|
|
|
|
|
isProcessed = true;
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
return isProcessed;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Processor::processSerialToRig()
|
2021-02-02 15:53:28 +00:00
|
|
|
{
|
2021-02-12 14:49:08 +00:00
|
|
|
bool allProcessed = false;
|
2021-02-12 14:33:25 +00:00
|
|
|
|
|
|
|
while (onSerialRxHasData() || !serialToRigQueue_.isEmpty()) {
|
2021-02-02 15:53:28 +00:00
|
|
|
byte rxByte;
|
2021-02-12 14:33:25 +00:00
|
|
|
if (onSerialRxHasData()) {
|
2021-02-02 15:53:28 +00:00
|
|
|
if (onSerialRx(&rxByte)) {
|
2021-02-12 14:33:25 +00:00
|
|
|
if (!serialToRigQueue_.unshift(rxByte)) {
|
2021-10-22 19:09:17 +00:00
|
|
|
LOG_WARN("Serial to rig buffer is full!");
|
2021-02-12 14:33:25 +00:00
|
|
|
}
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-12 14:33:25 +00:00
|
|
|
if (!serialToRigQueue_.isEmpty()) {
|
|
|
|
rxByte = serialToRigQueue_.pop();
|
|
|
|
if (receiveByte(rxByte)) {
|
2021-02-12 14:49:08 +00:00
|
|
|
allProcessed = true;
|
2021-02-12 14:33:25 +00:00
|
|
|
} else {
|
|
|
|
serialToRigQueue_.push(rxByte);
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
yield();
|
|
|
|
}
|
2021-02-12 14:49:08 +00:00
|
|
|
return allProcessed;
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 16:57:06 +00:00
|
|
|
bool Processor::processCommand(byte rxByte) {
|
2021-02-02 15:53:28 +00:00
|
|
|
|
|
|
|
switch (rxByte) {
|
|
|
|
case Cmd::Data:
|
2021-02-06 11:45:24 +00:00
|
|
|
if (!onRigTxBegin()) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-02-02 15:53:28 +00:00
|
|
|
state_ = State::GetData;
|
2021-02-05 16:57:06 +00:00
|
|
|
dataType_ = DataType::Raw;
|
2021-02-02 15:53:28 +00:00
|
|
|
break;
|
2021-02-08 18:30:23 +00:00
|
|
|
case Cmd::SetHardware:
|
2021-02-06 11:45:24 +00:00
|
|
|
state_ = State::GetData;
|
|
|
|
dataType_ = DataType::Control;
|
|
|
|
cmdBuffer_.clear();
|
|
|
|
break;
|
2021-10-20 09:58:43 +00:00
|
|
|
case Cmd::RebootRequested:
|
|
|
|
state_ = State::GetData;
|
|
|
|
dataType_ = DataType::Reboot;
|
|
|
|
cmdBuffer_.clear();
|
|
|
|
break;
|
2021-02-02 15:53:28 +00:00
|
|
|
case Cmd::P:
|
|
|
|
state_ = State::GetP;
|
|
|
|
break;
|
|
|
|
case Cmd::SlotTime:
|
|
|
|
state_ = State::GetSlotTime;
|
|
|
|
break;
|
2021-02-06 11:45:24 +00:00
|
|
|
case Marker::Fend:
|
2021-02-05 16:57:06 +00:00
|
|
|
break;
|
2021-02-02 15:53:28 +00:00
|
|
|
default:
|
|
|
|
// unknown command
|
2021-02-06 11:45:24 +00:00
|
|
|
state_ = State::GetEnd;
|
2021-02-02 15:53:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-02-05 16:57:06 +00:00
|
|
|
void Processor::processData(byte rxByte) {
|
|
|
|
switch (rxByte) {
|
|
|
|
case Marker::Fesc:
|
|
|
|
state_ = State::Escape;
|
|
|
|
break;
|
|
|
|
case Marker::Fend:
|
2021-02-06 11:45:24 +00:00
|
|
|
if (dataType_ == DataType::Raw) {
|
|
|
|
onRigTxEnd();
|
|
|
|
} else if (dataType_ == DataType::Control) {
|
|
|
|
onRadioControlCommand(cmdBuffer_);
|
2021-10-20 09:58:43 +00:00
|
|
|
} else if (dataType_ == DataType::Reboot) {
|
|
|
|
onRebootCommand();
|
2021-02-05 16:57:06 +00:00
|
|
|
}
|
2021-02-06 11:45:24 +00:00
|
|
|
state_ = State::GetStart;
|
2021-02-05 16:57:06 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-02-06 11:45:24 +00:00
|
|
|
if (dataType_ == DataType::Raw) {
|
|
|
|
onRigTx(rxByte);
|
|
|
|
} else if (dataType_ == DataType::Control) {
|
|
|
|
cmdBuffer_.push_back(rxByte);
|
2021-02-05 16:57:06 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-26 10:09:43 +00:00
|
|
|
bool Processor::receiveByteRaw(byte rxByte)
|
|
|
|
{
|
|
|
|
if (isRawIdle_) {
|
|
|
|
if (!onRigTxBegin()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
isRawIdle_ = false;
|
|
|
|
}
|
2021-10-26 12:07:27 +00:00
|
|
|
// NOTE, TNC2 uses \n as a packet delimiter
|
|
|
|
if (rxByte == '\n') {
|
2021-10-26 10:09:43 +00:00
|
|
|
onRigTxEnd();
|
|
|
|
isRawIdle_ = true;
|
2021-10-26 12:34:08 +00:00
|
|
|
} else {
|
|
|
|
onRigTx(rxByte);
|
2021-10-26 10:09:43 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2021-02-02 15:53:28 +00:00
|
|
|
|
2021-10-26 12:07:27 +00:00
|
|
|
bool Processor::receiveByteKiss(byte rxByte)
|
2021-10-26 10:09:43 +00:00
|
|
|
{
|
2021-02-02 15:53:28 +00:00
|
|
|
switch (state_) {
|
2021-02-06 11:45:24 +00:00
|
|
|
case State::GetStart:
|
2021-02-02 15:53:28 +00:00
|
|
|
if (rxByte == Marker::Fend) {
|
|
|
|
state_ = State::GetCmd;
|
|
|
|
}
|
|
|
|
break;
|
2021-02-06 11:45:24 +00:00
|
|
|
case State::GetEnd:
|
|
|
|
if (rxByte == Marker::Fend) {
|
|
|
|
state_ = State::GetStart;
|
|
|
|
}
|
|
|
|
break;
|
2021-02-02 15:53:28 +00:00
|
|
|
case State::GetCmd:
|
2021-02-06 11:45:24 +00:00
|
|
|
if (!processCommand(rxByte)) {
|
|
|
|
return false;
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case State::GetP:
|
|
|
|
onControlCommand(Cmd::P, rxByte);
|
2021-02-06 11:45:24 +00:00
|
|
|
state_ = State::GetEnd;
|
2021-02-02 15:53:28 +00:00
|
|
|
break;
|
|
|
|
case State::GetSlotTime:
|
|
|
|
onControlCommand(Cmd::SlotTime, rxByte);
|
2021-02-06 11:45:24 +00:00
|
|
|
state_ = State::GetEnd;
|
2021-02-02 15:53:28 +00:00
|
|
|
break;
|
|
|
|
case State::GetData:
|
2021-02-05 16:57:06 +00:00
|
|
|
processData(rxByte);
|
2021-02-02 15:53:28 +00:00
|
|
|
break;
|
|
|
|
case State::Escape:
|
|
|
|
if (rxByte == Marker::Tfend) {
|
|
|
|
onRigTx((byte)Marker::Fend);
|
|
|
|
state_ = State::GetData;
|
|
|
|
}
|
|
|
|
else if (rxByte == Marker::Tfesc) {
|
|
|
|
onRigTx((byte)Marker::Fesc);
|
|
|
|
state_ = State::GetData;
|
|
|
|
}
|
2021-02-06 11:45:24 +00:00
|
|
|
else if (rxByte != Marker::Fend) {
|
|
|
|
state_ = State::GetEnd;
|
2021-02-02 15:53:28 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2021-02-06 11:45:24 +00:00
|
|
|
// unknown state
|
|
|
|
state_ = State::GetStart;
|
2021-02-02 15:53:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-26 10:09:43 +00:00
|
|
|
bool Processor::receiveByte(byte rxByte) {
|
|
|
|
|
|
|
|
if (disableKiss_) {
|
|
|
|
return receiveByteRaw(rxByte);
|
|
|
|
}
|
|
|
|
return receiveByteKiss(rxByte);
|
|
|
|
}
|
|
|
|
|
2021-02-02 15:53:28 +00:00
|
|
|
} // kiss
|