diff --git a/Desktop_Interface/isobuffer.cpp b/Desktop_Interface/isobuffer.cpp index a7df27c0..b07c0cec 100644 --- a/Desktop_Interface/isobuffer.cpp +++ b/Desktop_Interface/isobuffer.cpp @@ -338,18 +338,20 @@ void isoBuffer::serialManage(double baudRate, UartParity parity) { if (m_decoder == NULL) { - m_decoder = new uartStyleDecoder(this); + m_decoder = new uartStyleDecoder(baudRate, this); connect(m_decoder, &uartStyleDecoder::wireDisconnected, m_virtualParent, &isoDriver::serialNeedsDisabling); } if (!m_isDecoding) { - m_decoder->updateTimer->start(CONSOLE_UPDATE_TIMER_PERIOD); + m_decoder->m_updateTimer.start(CONSOLE_UPDATE_TIMER_PERIOD); m_isDecoding = true; } + + m_decoder->m_baudRate = baudRate; m_decoder->setParityMode(parity); - m_decoder->serialDecode(baudRate); + m_decoder->serialDecode(); } void isoBuffer::setTriggerType(TriggerType newType) diff --git a/Desktop_Interface/uartstyledecoder.cpp b/Desktop_Interface/uartstyledecoder.cpp index 39aa1116..86774465 100644 --- a/Desktop_Interface/uartstyledecoder.cpp +++ b/Desktop_Interface/uartstyledecoder.cpp @@ -2,41 +2,40 @@ #include #include -uartStyleDecoder::uartStyleDecoder(QObject *parent_in) : QObject(parent_in) +uartStyleDecoder::uartStyleDecoder(double baudRate, QObject *parent) + : QObject(parent) + , m_parent{static_cast(parent)} + , m_serialBuffer{SERIAL_BUFFER_LENGTH} + , m_baudRate{baudRate} { - parent = (isoBuffer *) parent_in; // Begin decoding SAMPLE_DELAY seconds in the past. - serialPtr_bit = (int)(parent->m_back * 8 - SERIAL_DELAY * parent->m_sampleRate_bit + parent->m_bufferLen * 8) % (parent->m_bufferLen*8); + serialPtr_bit = (int)(m_parent->m_back * 8 - SERIAL_DELAY * m_parent->m_sampleRate_bit + m_parent->m_bufferLen * 8) % (m_parent->m_bufferLen*8); - updateTimer = new QTimer(); - updateTimer->setTimerType(Qt::PreciseTimer); - updateTimer->start(CONSOLE_UPDATE_TIMER_PERIOD); - connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateConsole())); + m_updateTimer.setTimerType(Qt::PreciseTimer); + m_updateTimer.start(CONSOLE_UPDATE_TIMER_PERIOD); + connect(&m_updateTimer, &QTimer::timeout, this, &uartStyleDecoder::updateConsole); - serialBuffer = new isoBufferBuffer(SERIAL_BUFFER_LENGTH); - - if(parent->m_channel == 1) console = parent->m_console1; - else if(parent->m_channel == 2) console = parent->m_console2; - else qFatal("Nonexistant console requested in uartStyleDecoder::serialDecode"); + if (m_parent->m_channel == 1) + console = m_parent->m_console1; + else if (m_parent->m_channel == 2) + console = m_parent->m_console2; + else + qFatal("Nonexistant console requested in uartStyleDecoder::serialDecode"); } -uartStyleDecoder::~uartStyleDecoder() +void uartStyleDecoder::updateConsole() { - std::lock_guard lock(mutex); - delete updateTimer; - delete serialBuffer; -} + if (!newUartSymbol) + return; -void uartStyleDecoder::updateConsole(){ std::lock_guard lock(mutex); - if(!newUartSymbol) return; - //qDebug() << serialBuffer->size(); - console->setPlainText(QString::fromLocal8Bit(serialBuffer->begin(), serialBuffer->size())); - if(parent->m_serialAutoScroll){ + console->setPlainText(QString::fromLocal8Bit(m_serialBuffer.begin(), m_serialBuffer.size())); + if (m_parent->m_serialAutoScroll) + { //http://stackoverflow.com/questions/21059678/how-can-i-set-auto-scroll-for-a-qtgui-qtextedit-in-pyqt4 DANKON - QTextCursor c = console->textCursor(); + QTextCursor c = console->textCursor(); c.movePosition(QTextCursor::End); console->setTextCursor(c); // txtedit.ensureCursorVisible(); // you might need this also @@ -45,20 +44,18 @@ void uartStyleDecoder::updateConsole(){ //charPos = 0; } -void uartStyleDecoder::serialDecode(double baudRate) +void uartStyleDecoder::serialDecode() { - /*if(stopDecoding){ - return; - }*/ - double dist_seconds = (double)serialDistance()/(parent->m_sampleRate_bit); - double bitPeriod_seconds = 1/baudRate; + double dist_seconds = (double)serialDistance()/(m_parent->m_sampleRate_bit); + double bitPeriod_seconds = 1.0 / m_baudRate; // Used to check for wire disconnects. You should get at least one "1" for a stop bit. bool allZeroes = true; - while(dist_seconds > (bitPeriod_seconds + SERIAL_DELAY)){ + while(dist_seconds > (bitPeriod_seconds + SERIAL_DELAY)) + { // Read next uart bit - unsigned char uart_bit = getNextUartBit(); + bool uart_bit = getNextUartBit(); if (uart_bit == 1) allZeroes = false; @@ -70,63 +67,68 @@ void uartStyleDecoder::serialDecode(double baudRate) } else { - uartTransmitting = (uart_bit == 1) ? false : true; // Uart starts transmitting after start bit (logic low). + // Uart starts transmitting after start bit (logic low). + uartTransmitting = uart_bit == false; jitterCompensationNeeded = true; } + // Update the pointer, accounting for jitter - updateSerialPtr(baudRate, uart_bit); + updateSerialPtr(uart_bit); // Calculate stopping condition - dist_seconds = (double)serialDistance()/(parent->m_sampleRate_bit); + dist_seconds = (double)serialDistance()/(m_parent->m_sampleRate_bit); } //Not a single stop bit, or idle bit, in the whole stream. Wire must be disconnected. - if(allZeroes){ + if (allZeroes) + { qDebug() << "Wire Disconnect detected!"; - wireDisconnected(parent->m_channel); - parent->m_isDecoding = false; - updateTimer->stop(); + wireDisconnected(m_parent->m_channel); + m_parent->m_isDecoding = false; + m_updateTimer.stop(); } } -int uartStyleDecoder::serialDistance() +int uartStyleDecoder::serialDistance() const { - int back_bit = parent->m_back * 8; - int bufferEnd_bit = (parent->m_bufferLen-1) * 8; - if(back_bit >= serialPtr_bit){ + int back_bit = m_parent->m_back * 8; + int bufferEnd_bit = (m_parent->m_bufferLen-1) * 8; + if (back_bit >= serialPtr_bit) return back_bit - serialPtr_bit; - }else return bufferEnd_bit - serialPtr_bit + back_bit; + else + return bufferEnd_bit - serialPtr_bit + back_bit; } -void uartStyleDecoder::updateSerialPtr(double baudRate, unsigned char current_bit) +void uartStyleDecoder::updateSerialPtr(bool current_bit) { - if(jitterCompensationNeeded && uartTransmitting){ - jitterCompensationNeeded = jitterCompensationProcedure(baudRate, current_bit); - } + if (jitterCompensationNeeded && uartTransmitting) + jitterCompensationNeeded = jitterCompensationProcedure(current_bit); - int distance_between_bits = (parent->m_sampleRate_bit)/baudRate; - if(uartTransmitting){ + int distance_between_bits = (m_parent->m_sampleRate_bit)/ m_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. + 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->m_bufferLen * 8)){ - serialPtr_bit -= (parent->m_bufferLen * 8); - } + if (serialPtr_bit >= (m_parent->m_bufferLen * 8)) + serialPtr_bit -= (m_parent->m_bufferLen * 8); } -unsigned char uartStyleDecoder::getNextUartBit(){ - int coord_byte = serialPtr_bit/8; - int coord_bit = serialPtr_bit - (8*coord_byte); - unsigned char dataByte = parent->m_buffer[coord_byte]; - unsigned char mask = (0x01 << coord_bit); - return ((dataByte & mask) ? 1 : 0); +bool uartStyleDecoder::getNextUartBit() const +{ + int bitIndex = serialPtr_bit; + + int coord_byte = bitIndex/8; + int coord_bit = bitIndex - (8*coord_byte); + uint8_t dataByte = m_parent->m_buffer[coord_byte]; + uint8_t mask = (0x01 << coord_bit); + return dataByte & mask; } -void uartStyleDecoder::decodeNextUartBit(unsigned char bitValue) +void uartStyleDecoder::decodeNextUartBit(bool bitValue) { if (dataBit_current == parityIndex) { - assert(parity != UartParity::None); - performParityCheck(); + parityCheckFailed = not isParityCorrect(dataBit_current); dataBit_current++; } else if (dataBit_current < dataBit_max) @@ -136,7 +138,16 @@ void uartStyleDecoder::decodeNextUartBit(unsigned char bitValue) } else { - decodeDatabit(dataBit_max + 1); + char decodedDatabit = decodeDatabit(dataBit_max + 1, currentUartSymbol); + + if (parityCheckFailed) + { + m_serialBuffer.insert("\n\n"); + parityCheckFailed = false; + } + + m_serialBuffer.insert(decodedDatabit); + currentUartSymbol = 0; dataBit_current = 0; uartTransmitting = false; @@ -146,33 +157,34 @@ void uartStyleDecoder::decodeNextUartBit(unsigned char bitValue) //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. -bool uartStyleDecoder::jitterCompensationProcedure(double baudRate, unsigned char current_bit){ +bool uartStyleDecoder::jitterCompensationProcedure(bool current_bit) +{ //We only run when the current bit is a "1", to prevent slowdown when there are long breaks between transmissions. - if(current_bit == 0){ + if (current_bit == false) return true; - } //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. - int left_coord = serialPtr_bit - (parent->m_sampleRate_bit)/baudRate; + int left_coord = serialPtr_bit - (m_parent->m_sampleRate_bit)/ m_baudRate; //qDebug() << "left_coord =" << left_coord; - if (left_coord < 0){ + if (left_coord < 0) return true; //Don't want to read out of bounds!! - } //The usual case, when transmitting anyway. - unsigned char left_byte = (parent->m_buffer[left_coord/8] & 0xff); + uint8_t left_byte = (m_parent->m_buffer[left_coord/8] & 0xff); //Only run when a zero is detected in the leftmost symbol. - if(left_byte != 255){ + if (left_byte != 0xff) + { //Step back, one sample at a time, to the 0->1 transition point - unsigned char temp_bit = 1; - while(temp_bit){ + bool temp_bit = 1; + while(temp_bit) + { temp_bit = getNextUartBit(); serialPtr_bit--; } //Jump the pointer forward by half a uart bit period, and return "done!". - serialPtr_bit += (parent->m_sampleRate_bit/baudRate)/2; + serialPtr_bit += (m_parent->m_sampleRate_bit/ m_baudRate)/2; return false; } @@ -180,27 +192,24 @@ bool uartStyleDecoder::jitterCompensationProcedure(double baudRate, unsigned cha } //Basically scaffolding to add character maps for other modes (5 bit, for example). -void uartStyleDecoder::decodeDatabit(int mode){ - char tempchar; - switch(mode){ +char uartStyleDecoder::decodeDatabit(int mode, short symbol) const +{ + switch(mode) + { case 5: - tempchar = decode_baudot(currentUartSymbol); + return decodeBaudot(symbol); break; case 8: //8-bit ASCII; - tempchar = currentUartSymbol; + return symbol; break; default: qDebug() << "uartStyleDecoder::decodeDatabit is failing..."; + return -1; // Garbage } - if (parityCheckFailed) - { - serialBuffer->insert("\n\n"); - parityCheckFailed = false; - } - serialBuffer->insert(tempchar); } -char uartStyleDecoder::decode_baudot(short symbol){ +char uartStyleDecoder::decodeBaudot(short symbol) const +{ return 'a'; } @@ -219,35 +228,21 @@ void uartStyleDecoder::setParityMode(UartParity newParity) parity = newParity; } -void uartStyleDecoder::performParityCheck() +bool uartStyleDecoder::isParityCorrect(uint32_t bitField) const { - 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; - } + if (parity == UartParity::None) + std::terminate(); - return parity == 0; - }; - - switch(parity) - { - case UartParity::None: - assert(false); - return; - case UartParity::Even: - parityCheckFailed = ! isEvenParity(); - case UartParity::Odd: - parityCheckFailed = isEvenParity(); - } - - return; + return parityOf(bitField) == parity; } +UartParity uartStyleDecoder::parityOf(uint32_t bitField) const +{ + bool result = false; + for (uint32_t mask = 1 << (dataBit_max-1); mask != 0; mask >>= 1) + result ^= static_cast(bitField & mask); + + return result ? UartParity::Odd : UartParity::Even; +} diff --git a/Desktop_Interface/uartstyledecoder.h b/Desktop_Interface/uartstyledecoder.h index 84bd3021..c7ad05a0 100644 --- a/Desktop_Interface/uartstyledecoder.h +++ b/Desktop_Interface/uartstyledecoder.h @@ -19,14 +19,16 @@ class uartStyleDecoder : public QObject { Q_OBJECT public: - explicit uartStyleDecoder(QObject *parent_in = NULL); - ~uartStyleDecoder(); - void serialDecode(double baudRate); - int serialDistance(); - QTimer *updateTimer; + explicit uartStyleDecoder(double baudRate, QObject *parent = NULL); + ~uartStyleDecoder() = default; + + private: - isoBuffer *parent; + isoBuffer *m_parent; + + // Indicates the current bit being decoded. int serialPtr_bit; + bool uartTransmitting = false; bool newUartSymbol = false; uint32_t dataBit_current = 0; @@ -34,17 +36,31 @@ private: uint32_t dataBit_max = 7; unsigned short currentUartSymbol = 0; bool jitterCompensationNeeded = true; - void updateSerialPtr(double baudRate, unsigned char current_bit); - unsigned char getNextUartBit(); - void decodeNextUartBit(unsigned char bitValue); - bool jitterCompensationProcedure(double baudRate, unsigned char current_bit); + + void updateSerialPtr(bool current_bit); + bool getNextUartBit() const; + void decodeNextUartBit(bool bitValue); + bool jitterCompensationProcedure(bool current_bit); + QPlainTextEdit *console; - isoBufferBuffer *serialBuffer; - void decodeDatabit(int mode); - char decode_baudot(short symbol); + isoBufferBuffer m_serialBuffer; +public: + double m_baudRate; + QTimer m_updateTimer; // IMPORTANT: must be after m_serialBuffer. construction / destruction order matters + +public: + void serialDecode(); + int serialDistance() const; +private: + char decodeDatabit(int mode, short symbol) const; + char decodeBaudot(short symbol) const; + std::mutex mutex; UartParity parity = UartParity::None; - void performParityCheck(); + + bool isParityCorrect(uint32_t bitField) const; + UartParity parityOf(uint32_t bitField) const; + bool parityCheckFailed = false; signals: void wireDisconnected(int);