#include "i2cdecoder.h" using namespace i2c; i2cDecoder::i2cDecoder(isoBuffer* sda_in, isoBuffer* scl_in, QPlainTextEdit* console_in) : QObject(nullptr) , sda(sda_in) , scl(scl_in) , console(console_in) { serialBuffer = new isoBufferBuffer(I2C_BUFFER_LENGTH); updateTimer = new QTimer(); updateTimer->setTimerType(Qt::PreciseTimer); updateTimer->start(CONSOLE_UPDATE_TIMER_PERIOD); connect(updateTimer, &QTimer::timeout, this, &i2cDecoder::updateConsole); } i2cDecoder::~i2cDecoder() { // TODO: Is a lock needed here? Destructors should never be called more than once but... delete updateTimer; delete serialBuffer; } void i2cDecoder::reset() { qDebug () << "Resetting I2C"; if (sda->m_back != scl->m_back) { // Perhaps the data could be saved, but just resetting them seems much safer sda->clearBuffer(); scl->clearBuffer(); } serialPtr_bit = sda->m_back * 8; { std::lock_guard lock(mutex); serialBuffer->clear(); } } void i2cDecoder::run() { // qDebug() << "i2cDecoder::run()"; while (serialDistance(sda) > SERIAL_DELAY * sda->m_sampleRate_bit) { updateBitValues(); runStateMachine(); serialPtr_bit ++; if (serialPtr_bit >= (sda->m_bufferLen * 8)) serialPtr_bit -= (sda->m_bufferLen * 8); } } int i2cDecoder::serialDistance(isoBuffer* buffer) { int back_bit = buffer->m_back * 8; int bufferEnd_bit = buffer->m_bufferLen * 8; if (back_bit >= serialPtr_bit) return back_bit - serialPtr_bit; else return bufferEnd_bit - serialPtr_bit + back_bit; } void i2cDecoder::updateBitValues(){ previousSdaValue = currentSdaValue; previousSclValue = currentSclValue; int coord_byte = serialPtr_bit/8; int coord_bit = serialPtr_bit - (8*coord_byte); unsigned char dataByteSda = sda->m_buffer[coord_byte]; unsigned char dataByteScl = scl->m_buffer[coord_byte]; unsigned char mask = (0x01 << coord_bit); currentSdaValue = dataByteSda & mask; currentSclValue = dataByteScl & mask; } void i2cDecoder::runStateMachine() { edge sdaEdge = edgeDetection(currentSdaValue, previousSdaValue); edge sclEdge = edgeDetection(currentSclValue, previousSclValue); if ((sdaEdge == edge::rising) && (sclEdge == edge::falling)) // INVALID STATE TRANSITION { state = transmissionState::unknown; qDebug() << "Dumping I2C state and aborting..."; for (int i=31; i>=0; i--) qDebug("%02x\t%02x", sda->m_buffer[serialPtr_bit/8 - i] & 0xFF, scl->m_buffer[serialPtr_bit/8 - i] & 0xFF); throw std::runtime_error("unknown i2c transmission state"); return; } if ((sdaEdge == edge::rising) && (sclEdge == edge::held_high)) // START { stopCondition(); return; } if ((sdaEdge == edge::falling) && (sclEdge == edge::held_high)) // STOP { startCondition(); return; } switch (state) { case transmissionState::idle: return; case transmissionState::address: decodeAddress(sdaEdge, sclEdge); break; case transmissionState::data: decodeData(sdaEdge, sclEdge); break; } } edge i2cDecoder::edgeDetection(uint8_t current, uint8_t prev) { if (current && prev) return edge::held_high; if (!current && !prev) return edge::held_low; if (current && !prev) return edge::rising; if (!current && prev) return edge::falling; throw std::runtime_error("i2c Edge Detection critical failure"); } void i2cDecoder::decodeAddress(edge sdaEdge, edge sclEdge) { // Read in the next bit. if (sclEdge == edge::rising && sdaEdge == edge::held_high && currentBitIndex++ < addressBitStreamLength) currentBitStream = (currentBitStream << 1) | 0x0001; else if (sclEdge == edge::rising && sdaEdge == edge::held_low && currentBitIndex++ < addressBitStreamLength) currentBitStream = (currentBitStream << 1) & 0xFFFE; else return; if (currentBitIndex == addressBitStreamLength) { qDebug() << "Finished Address Decode"; if (currentBitStream & 0b0000000000000010) serialBuffer->insert("READ: "); else serialBuffer->insert("WRITE: "); serialBuffer->insert_hex((uint8_t)((currentBitStream & 0b0000000111111100) >> 2)); serialBuffer->insert(' '); if (currentBitStream & 0b0000000000000001) serialBuffer->insert("(NACK)"); consoleStateInvalid = true; // Prepare for next bit currentBitIndex = 0; currentBitStream = 0x0000; state = transmissionState::data; } } void i2cDecoder::decodeData(edge sdaEdge, edge sclEdge) { // Read in the next bit. if (sclEdge == edge::rising && sdaEdge == edge::held_high && currentBitIndex++ < dataBitStreamLength) currentBitStream = (currentBitStream << 1) | 0x0001; else if (sclEdge == edge::rising && sdaEdge == edge::held_low && currentBitIndex++ < dataBitStreamLength) currentBitStream = (currentBitStream << 1) & 0xFFFE; else return; if (currentBitIndex == dataBitStreamLength) { qDebug() << "Finished Data byte Decode"; serialBuffer->insert_hex((uint8_t)((currentBitStream & 0b0000000111111110) >> 1)); serialBuffer->insert(' '); if (currentBitStream & 0b0000000000000001) serialBuffer->insert("(NACK)"); consoleStateInvalid = true; // Prepare for next bit currentBitIndex = 0; currentBitStream = 0x0000; } } void i2cDecoder::startCondition() { currentBitIndex = 0; currentBitStream = 0x0000; state = transmissionState::address; qDebug() << "I2C START"; } void i2cDecoder::stopCondition() { state = transmissionState::idle; serialBuffer->insert('\n'); qDebug() << "I2C STOP"; } void i2cDecoder::updateConsole(){ std::lock_guard lock(mutex); if (!consoleStateInvalid) return; console->setPlainText(QString::fromLocal8Bit(serialBuffer->begin(), serialBuffer->size())); if(sda->m_serialAutoScroll){ QTextCursor c = console->textCursor(); c.movePosition(QTextCursor::End); console->setTextCursor(c); } consoleStateInvalid = false; }