firmware/src/mesh/StreamAPI.cpp

112 lines
3.7 KiB
C++
Raw Normal View History

2020-04-27 15:10:17 +00:00
#include "StreamAPI.h"
#include "configuration.h"
2020-04-27 15:45:39 +00:00
#define START1 0x94
#define START2 0xc3
#define HEADER_LEN 4
int32_t StreamAPI::runOnce()
2020-04-27 15:45:39 +00:00
{
auto result = readStream();
2020-04-27 15:45:39 +00:00
writeStream();
checkConnectionTimeout();
return result;
2020-04-27 15:45:39 +00:00
}
/**
* Read any rx chars from the link and call handleToRadio
*/
int32_t StreamAPI::readStream()
2020-04-27 15:45:39 +00:00
{
uint32_t now = millis();
if (!stream->available()) {
// Nothing available this time, if the computer has talked to us recently, poll often, otherwise let CPU sleep a long time
bool recentRx = (now - lastRxMsec) < 2000;
return recentRx ? 5 : 250;
} else {
while (stream->available()) { // Currently we never want to block
uint8_t c = stream->read();
2020-04-27 15:45:39 +00:00
// Use the read pointer for a little state machine, first look for framing, then length bytes, then payload
size_t ptr = rxPtr++; // assume we will probably advance the rxPtr
2020-04-27 15:45:39 +00:00
rxBuf[ptr] = c; // store all bytes (including framing)
2020-04-27 15:45:39 +00:00
if (ptr == 0) { // looking for START1
if (c != START1)
rxPtr = 0; // failed to find framing
} else if (ptr == 1) { // looking for START2
if (c != START2)
rxPtr = 0; // failed to find framing
} else if (ptr >= HEADER_LEN) { // we have at least read our 4 byte framing
uint32_t len = (rxBuf[2] << 8) + rxBuf[3]; // big endian 16 bit length follows framing
2020-04-27 15:45:39 +00:00
if (ptr == HEADER_LEN) {
// we _just_ finished our 4 byte header, validate length now (note: a length of zero is a valid
// protobuf also)
if (len > MAX_TO_FROM_RADIO_SIZE)
rxPtr = 0; // length is bogus, restart search for framing
}
if (rxPtr != 0 && ptr + 1 == len + HEADER_LEN) {
rxPtr = 0; // start over again on the next packet
2020-04-27 15:45:39 +00:00
// If we didn't just fail the packet and we now have the right # of bytes, parse it
if (handleToRadio(rxBuf + HEADER_LEN, len))
return 0; // we want to be called again ASAP because we still have more work to do
}
2020-04-27 15:45:39 +00:00
}
}
// we had packets available this time, so assume we might have them next time also
lastRxMsec = now;
return 0;
2020-04-27 15:45:39 +00:00
}
}
/**
* call getFromRadio() and deliver encapsulated packets to the Stream
*/
void StreamAPI::writeStream()
{
if (canWrite) {
uint32_t len;
do {
// Send every packet we can
len = getFromRadio(txBuf + HEADER_LEN);
emitTxBuffer(len);
} while (len);
}
}
/**
* Send the current txBuffer over our stream
*/
void StreamAPI::emitTxBuffer(size_t len)
{
if (len != 0) {
// DEBUG_MSG("emit tx %d\n", len);
txBuf[0] = START1;
txBuf[1] = START2;
txBuf[2] = (len >> 8) & 0xff;
txBuf[3] = len & 0xff;
2021-03-12 07:47:00 +00:00
auto totalLen = len + HEADER_LEN;
stream->write(txBuf, totalLen);
/* for(size_t i = 0; i < totalLen; i++) {
stream->write(txBuf[i]);
// stream->flush();
} */
}
}
void StreamAPI::emitRebooted()
{
// In case we send a FromRadio packet
memset(&fromRadioScratch, 0, sizeof(fromRadioScratch));
fromRadioScratch.which_payloadVariant = FromRadio_rebooted_tag;
fromRadioScratch.rebooted = true;
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
2020-04-27 15:45:39 +00:00
}