2017-11-28 00:17:11 +00:00
|
|
|
#include "uartstyledecoder.h"
|
2018-12-11 09:25:14 +00:00
|
|
|
#include <QDebug>
|
|
|
|
#include <cassert>
|
2017-11-28 00:17:11 +00:00
|
|
|
|
|
|
|
uartStyleDecoder::uartStyleDecoder(QObject *parent_in) : QObject(parent_in)
|
|
|
|
{
|
|
|
|
parent = (isoBuffer *) parent_in;
|
|
|
|
|
2018-07-26 01:16:48 +01:00
|
|
|
// Begin decoding SAMPLE_DELAY seconds in the past.
|
|
|
|
serialPtr_bit = (int)(parent->back * 8 - SERIAL_DELAY * parent->sampleRate_bit + parent->bufferEnd * 8) % (parent->bufferEnd*8);
|
|
|
|
|
2017-11-28 00:17:11 +00:00
|
|
|
updateTimer = new QTimer();
|
|
|
|
updateTimer->setTimerType(Qt::PreciseTimer);
|
|
|
|
updateTimer->start(CONSOLE_UPDATE_TIMER_PERIOD);
|
|
|
|
connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateConsole()));
|
|
|
|
|
2018-11-05 23:15:48 +00:00
|
|
|
serialBuffer = new isoBufferBuffer(SERIAL_BUFFER_LENGTH * 2);
|
2017-11-28 02:09:52 +00:00
|
|
|
|
|
|
|
if(parent->channel == 1) console = parent->console1;
|
|
|
|
else if(parent->channel == 2) console = parent->console2;
|
|
|
|
else qFatal("Nonexistant console requested in uartStyleDecoder::serialDecode");
|
2017-11-28 00:17:11 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 01:16:48 +01:00
|
|
|
uartStyleDecoder::~uartStyleDecoder()
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
delete updateTimer;
|
|
|
|
delete serialBuffer;
|
|
|
|
}
|
2017-11-28 00:17:11 +00:00
|
|
|
|
|
|
|
void uartStyleDecoder::updateConsole(){
|
2018-07-26 01:16:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
if(!newUartSymbol) return;
|
2017-12-01 04:31:21 +00:00
|
|
|
//qDebug() << numCharsInBuffer;
|
2017-11-28 00:17:11 +00:00
|
|
|
|
2018-11-05 23:15:48 +00:00
|
|
|
uint32_t numCharsInBuffer = serialBuffer->getNumCharsInBuffer();
|
2017-11-28 00:17:11 +00:00
|
|
|
console->setPlainText(QString::fromLocal8Bit(serialBuffer->get(numCharsInBuffer), numCharsInBuffer));
|
|
|
|
if(parent->serialAutoScroll){
|
|
|
|
//http://stackoverflow.com/questions/21059678/how-can-i-set-auto-scroll-for-a-qtgui-qtextedit-in-pyqt4 DANKON
|
|
|
|
QTextCursor c = console->textCursor();
|
|
|
|
c.movePosition(QTextCursor::End);
|
|
|
|
console->setTextCursor(c);
|
|
|
|
// txtedit.ensureCursorVisible(); // you might need this also
|
|
|
|
}
|
|
|
|
newUartSymbol = false;
|
|
|
|
//charPos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uartStyleDecoder::serialDecode(double baudRate)
|
|
|
|
{
|
2017-11-28 02:09:52 +00:00
|
|
|
/*if(stopDecoding){
|
|
|
|
return;
|
|
|
|
}*/
|
2017-11-28 00:17:11 +00:00
|
|
|
double dist_seconds = (double)serialDistance()/(parent->sampleRate_bit);
|
|
|
|
double bitPeriod_seconds = 1/baudRate;
|
|
|
|
|
2018-12-11 09:25:14 +00:00
|
|
|
// Used to check for wire disconnects. You should get at least one "1" for a stop bit.
|
2017-11-28 02:09:52 +00:00
|
|
|
bool allZeroes = true;
|
2017-11-28 00:17:11 +00:00
|
|
|
|
|
|
|
while(dist_seconds > (bitPeriod_seconds + SERIAL_DELAY)){
|
2018-12-11 09:25:14 +00:00
|
|
|
// Read next uart bit
|
2017-11-28 00:17:11 +00:00
|
|
|
unsigned char uart_bit = getNextUartBit();
|
2017-11-28 02:09:52 +00:00
|
|
|
|
2018-12-11 09:25:14 +00:00
|
|
|
if (uart_bit == 1)
|
|
|
|
allZeroes = false;
|
|
|
|
|
|
|
|
// Process it
|
|
|
|
if (uartTransmitting)
|
|
|
|
{
|
2017-11-28 00:17:11 +00:00
|
|
|
decodeNextUartBit(uart_bit);
|
2018-12-11 09:25:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
uartTransmitting = (uart_bit == 1) ? false : true; // Uart starts transmitting after start bit (logic low).
|
2017-11-28 00:17:11 +00:00
|
|
|
jitterCompensationNeeded = true;
|
|
|
|
}
|
2018-12-11 09:25:14 +00:00
|
|
|
// Update the pointer, accounting for jitter
|
2017-11-28 00:17:11 +00:00
|
|
|
updateSerialPtr(baudRate, uart_bit);
|
2018-12-11 09:25:14 +00:00
|
|
|
// Calculate stopping condition
|
2017-11-28 00:17:11 +00:00
|
|
|
dist_seconds = (double)serialDistance()/(parent->sampleRate_bit);
|
|
|
|
}
|
2017-11-28 02:09:52 +00:00
|
|
|
|
|
|
|
//Not a single stop bit, or idle bit, in the whole stream. Wire must be disconnected.
|
|
|
|
if(allZeroes){
|
|
|
|
qDebug() << "Wire Disconnect detected!";
|
2017-11-28 04:31:33 +00:00
|
|
|
wireDisconnected(parent->channel);
|
2017-11-28 02:09:52 +00:00
|
|
|
parent->stopDecoding = true;
|
|
|
|
updateTimer->stop();
|
|
|
|
}
|
2017-11-28 00:17:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int uartStyleDecoder::serialDistance()
|
|
|
|
{
|
|
|
|
int back_bit = parent->back * 8;
|
|
|
|
int bufferEnd_bit = parent->bufferEnd * 8;
|
|
|
|
if(back_bit >= serialPtr_bit){
|
|
|
|
return back_bit - serialPtr_bit;
|
|
|
|
}else return bufferEnd_bit - serialPtr_bit + back_bit;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uartStyleDecoder::updateSerialPtr(double baudRate, unsigned char current_bit)
|
|
|
|
{
|
|
|
|
if(jitterCompensationNeeded && uartTransmitting){
|
|
|
|
jitterCompensationNeeded = jitterCompensationProcedure(baudRate, current_bit);
|
|
|
|
}
|
|
|
|
|
|
|
|
int distance_between_bits = (parent->sampleRate_bit)/baudRate;
|
|
|
|
if(uartTransmitting){
|
|
|
|
serialPtr_bit += distance_between_bits;
|
|
|
|
} else serialPtr_bit += (distance_between_bits - 1); //Less than one baud period so that it will always see that start bit.
|
|
|
|
|
|
|
|
if (serialPtr_bit > (parent->bufferEnd * 8)){
|
|
|
|
serialPtr_bit -= (parent->bufferEnd * 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char uartStyleDecoder::getNextUartBit(){
|
|
|
|
int coord_byte = serialPtr_bit/8;
|
|
|
|
int coord_bit = serialPtr_bit - (8*coord_byte);
|
|
|
|
unsigned char dataByte = parent->buffer[coord_byte];
|
2018-11-04 00:31:48 +00:00
|
|
|
unsigned char mask = (0x01 << coord_bit);
|
2017-11-28 00:17:11 +00:00
|
|
|
return ((dataByte & mask) ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void uartStyleDecoder::decodeNextUartBit(unsigned char bitValue)
|
|
|
|
{
|
2018-12-11 09:25:14 +00:00
|
|
|
if (dataBit_current == parityIndex)
|
|
|
|
{
|
|
|
|
assert(parity != UartParity::None);
|
|
|
|
performParityCheck();
|
|
|
|
dataBit_current++;
|
|
|
|
}
|
|
|
|
else if (dataBit_current < dataBit_max)
|
|
|
|
{
|
|
|
|
currentUartSymbol |= (bitValue << dataBit_current);
|
|
|
|
dataBit_current++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
decodeDatabit(dataBit_max + 1);
|
2017-11-28 00:17:11 +00:00
|
|
|
currentUartSymbol = 0;
|
|
|
|
dataBit_current = 0;
|
|
|
|
uartTransmitting = false;
|
|
|
|
newUartSymbol = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-28 02:09:52 +00:00
|
|
|
//This function compensates for jitter by, when the current bit is a "1", and the last bit was a zero, setting the pointer
|
|
|
|
//to the sample at the midpoint between this bit and the last.
|
2017-11-28 00:17:11 +00:00
|
|
|
bool uartStyleDecoder::jitterCompensationProcedure(double baudRate, unsigned char current_bit){
|
|
|
|
|
2017-11-28 02:09:52 +00:00
|
|
|
//We only run when the current bit is a "1", to prevent slowdown when there are long breaks between transmissions.
|
|
|
|
if(current_bit == 0){
|
2017-11-28 00:17:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-28 02:09:52 +00:00
|
|
|
//Can't be bothered dealing with the corner case where the serial pointer is at the very start of the buffer.
|
|
|
|
//Just return and try again next time.
|
2017-11-28 00:17:11 +00:00
|
|
|
int left_coord = serialPtr_bit - (parent->sampleRate_bit)/baudRate;
|
2017-11-28 02:09:52 +00:00
|
|
|
//qDebug() << "left_coord =" << left_coord;
|
2017-11-28 00:17:11 +00:00
|
|
|
if (left_coord < 0){
|
|
|
|
return true; //Don't want to read out of bounds!!
|
|
|
|
}
|
|
|
|
|
2017-11-28 02:09:52 +00:00
|
|
|
//The usual case, when transmitting anyway.
|
2017-11-28 00:17:11 +00:00
|
|
|
unsigned char left_byte = (parent->buffer[left_coord/8] & 0xff);
|
2017-11-28 02:09:52 +00:00
|
|
|
//Only run when a zero is detected in the leftmost symbol.
|
|
|
|
if(left_byte != 255){
|
|
|
|
//Step back, one sample at a time, to the 0->1 transition point
|
|
|
|
unsigned char temp_bit = 1;
|
|
|
|
while(temp_bit){
|
2017-11-28 00:17:11 +00:00
|
|
|
temp_bit = getNextUartBit();
|
|
|
|
serialPtr_bit--;
|
|
|
|
}
|
2017-11-28 02:09:52 +00:00
|
|
|
//Jump the pointer forward by half a uart bit period, and return "done!".
|
2017-11-28 00:17:11 +00:00
|
|
|
serialPtr_bit += (parent->sampleRate_bit/baudRate)/2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2017-12-03 03:11:32 +00:00
|
|
|
|
2018-12-11 09:25:14 +00:00
|
|
|
//Basically scaffolding to add character maps for other modes (5 bit, for example).
|
2017-12-03 03:11:32 +00:00
|
|
|
void uartStyleDecoder::decodeDatabit(int mode){
|
2018-11-05 23:55:45 +00:00
|
|
|
char tempchar;
|
2017-12-03 03:11:32 +00:00
|
|
|
switch(mode){
|
|
|
|
case 5:
|
|
|
|
tempchar = decode_baudot(currentUartSymbol);
|
2018-12-11 09:25:14 +00:00
|
|
|
break;
|
2017-12-03 03:11:32 +00:00
|
|
|
case 8: //8-bit ASCII;
|
|
|
|
tempchar = currentUartSymbol;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
qDebug() << "uartStyleDecoder::decodeDatabit is failing...";
|
|
|
|
}
|
2018-12-11 09:25:14 +00:00
|
|
|
if (parityCheckFailed)
|
|
|
|
{
|
|
|
|
serialBuffer->add("\n<ERROR: Following character contains parity error>\n");
|
|
|
|
parityCheckFailed = false;
|
|
|
|
}
|
2017-12-03 03:11:32 +00:00
|
|
|
serialBuffer->add(tempchar);
|
|
|
|
}
|
|
|
|
|
|
|
|
char uartStyleDecoder::decode_baudot(short symbol){
|
|
|
|
return 'a';
|
|
|
|
}
|
|
|
|
|
2018-12-11 09:25:14 +00:00
|
|
|
void uartStyleDecoder::setParityMode(UartParity newParity)
|
|
|
|
{
|
|
|
|
switch(newParity)
|
|
|
|
{
|
|
|
|
case UartParity::None:
|
|
|
|
parityIndex = UINT_MAX;
|
|
|
|
break;
|
|
|
|
case UartParity::Even:
|
|
|
|
case UartParity::Odd:
|
|
|
|
parityIndex = dataBit_max;
|
|
|
|
}
|
|
|
|
|
|
|
|
parity = newParity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void uartStyleDecoder::performParityCheck()
|
|
|
|
{
|
|
|
|
auto isEvenParity = [=] () -> bool
|
|
|
|
{
|
|
|
|
uint32_t mask = 0x00000001;
|
|
|
|
uint8_t parity = 0;
|
|
|
|
for (int i = 0; i < dataBit_max; i++)
|
|
|
|
{
|
|
|
|
const uint8_t currentBit = (dataBit_current & mask) ? 1 : 0;
|
|
|
|
parity = parity ^ currentBit;
|
|
|
|
mask = mask << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parity == 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
switch(parity)
|
|
|
|
{
|
|
|
|
case UartParity::None:
|
|
|
|
assert(false);
|
|
|
|
return;
|
|
|
|
case UartParity::Even:
|
|
|
|
parityCheckFailed = ! isEvenParity();
|
|
|
|
case UartParity::Odd:
|
|
|
|
parityCheckFailed = isEvenParity();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-03 03:11:32 +00:00
|
|
|
|
|
|
|
|