Page MenuHomec4science

hriboard.cpp
No OneTemporary

File Metadata

Created
Mon, May 6, 07:28

hriboard.cpp

#include "hriboard.h"
#include <QDebug>
#include <QSerialPortInfo>
#include <stdexcept>
const int SYNCVAR_LIST_ITEM_SIZE = SYNCVAR_NAME_SIZE + 3;
/**
* @brief Constructor.
*/
HriBoard::HriBoard()
{
}
/**
* @brief Establish the link with the board.
* Establish the link with the board, then stops the streaming and requests the
* variables list.
* @param comPortName serial port name, in the format "COM1" on Windows, or
* "/dev/ttyO1" on UNIX.
* @throws A runtime_error is thrown if the serial port could not be opened.
*/
void HriBoard::openLink(QString comPortName)
{
streamID = 0;
// Setup the serial port.
serial.setPortName(comPortName);
serial.setBaudRate(UART_BAUDRATE);
serial.setDataBits(QSerialPort::Data8);
serial.setFlowControl(QSerialPort::NoFlowControl);
serial.setParity(QSerialPort::NoParity);
connect(&serial, SIGNAL(readyRead()), this, SLOT(onReceivedData()));
qDebug() << "Opening the serial COM port...";
if(serial.open(QIODevice::ReadWrite))
qDebug() << "COM port opened successfully.";
else
throw std::runtime_error("Can't open the COM port.");
// Stop the streaming, in case it was enabled.
QByteArray ba;
ba.append((char)0);
sendPacket(PC_MESSAGE_SET_STREAMED_VAR, ba);
// Request the variables list.
sendPacket(PC_MESSAGE_GET_VARS_LIST);
}
/**
* @brief Sets the SyncVars to stream.
* @param varsToStream list of the SyncVars to stream.
*/
void HriBoard::setStreamedVars(QList<SyncVarPointerBase*> varsToStream)
{
// Copy the list of variables to stream, and compute the size of a streaming
// packet.
streamedVars.clear();
streamPacketSize = sizeof(quint8) + sizeof(quint32); // Stream ID + timestamp.
for(SyncVarPointerBase* svpb : varsToStream)
{
streamedVars.append(&syncVars[svpb->getVar()->getIndex()]);
streamPacketSize += svpb->getVar()->getSize();
}
//
streamID++;
QByteArray ba;
ba.append((quint8)varsToStream.size());
ba.append(streamID);
for(SyncVarPointerBase* svpb : varsToStream)
{
int varIndex = svpb->getVar()->getIndex();
ba.append((quint8)varIndex);
}
sendPacket(PC_MESSAGE_SET_STREAMED_VAR, ba);
}
/**
* @brief Associates a SyncVarPointer to an actual SyncVar, from its name.
* @param svp the SyncVarPointer to the SyncVar.
* @param name the name of the SyncVar to associate to the pointer.
* @return true if a variable with the given name was found, false otherwise.
*/
bool HriBoard::associate(SyncVarPointerBase &svp, QString name)
{
for(SyncVar &sv : syncVars)
{
if(sv.getName() == name && sv.getType() == svp.getType())
{
svp.associate(this, &sv);
return true;
}
}
svp.associate(this, nullptr);
return false;
}
/**
* @brief Updates a SyncVar on the board with the value of the local SyncVar.
* @param var the SyncVar to synchronize.
*/
void HriBoard::writeRemoteVar(SyncVar *var)
{
QByteArray ba;
ba.append(var->getIndex());
ba.append(var->getData());
sendPacket(PC_MESSAGE_SET_VAR, ba);
}
/**
* @brief Updates a local SyncVar with the value of the SyncVar on the board.
* @param var the SyncVar to synchronize.
*/
void HriBoard::readRemoteVar(SyncVar *var)
{
QByteArray ba;
ba.append(var->getIndex());
sendPacket(PC_MESSAGE_GET_VAR, ba);
}
/**
* @brief Makes a list of all the candidate serial ports.
* @return a list of all the serial port that use the right USB-to-UART chip.
*/
QStringList HriBoard::getComPorts()
{
QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
for(int i=ports.size()-1; i >= 0; i--)
{
// Remove from the list all the serial COM ports that are not the CP210x
// USB-to-serial chip.
if(!ports[i].description().contains("CP210x"))
ports.removeAt(i);
}
// Make a list of the COM ports names.
QStringList portsNames;
for(QSerialPortInfo comInfo : ports)
portsNames << comInfo.portName();
return portsNames;
}
/**
* @brief Interprets the received bytes, and reacts accordingly.
*/
void HriBoard::onReceivedData()
{
QByteArray rxData = serial.readAll();
//qDebug() << "RX:" << rxData;
for(int i=0; i<rxData.size(); i++)
{
quint8 rxByte = rxData[i];
if(rxByte & (1<<7)) // The start byte has the most significant bit high.
{
rxCurrentMessageType = (rxByte & ~(1<<7)); // Remove the start bit.
rxBytesCount = 0;
}
else // The data bytes have the most significant byte low.
rxBytesCount++;
if(rxBytesCount % 2 == 1) // First half of the data byte has been received.
firstHalfByte = rxByte; // Store it until the second half arrives.
else // Second half of the data byte has been received.
{
int dataBytesReady = rxBytesCount/2;
if(dataBytesReady > 0)
rxDataBytesBuffer[dataBytesReady-1] = (firstHalfByte<<4) + (rxByte & 0xf);
switch(rxCurrentMessageType)
{
case STM_MESSAGE_START_INFO:
if(dataBytesReady == 0)
{
// Request variables list.
sendPacket(PC_MESSAGE_GET_VARS_LIST);
}
break;
case STM_MESSAGE_VAR:
if(dataBytesReady >= 1)
{
quint8 varIndex = rxDataBytesBuffer[0];
if(dataBytesReady == 1 + syncVars[varIndex].getSize())
{
QByteArray ba((char*)&rxDataBytesBuffer[1],
syncVars[varIndex].getSize());
syncVars[varIndex].setData(ba);
}
}
break;
case STM_MESSAGE_VARS_LIST:
if(dataBytesReady >= 1)
{
quint8 nVars = rxDataBytesBuffer[0];
if(dataBytesReady == 1 + nVars * SYNCVAR_LIST_ITEM_SIZE)
{
syncVars.clear();
quint8* p = &rxDataBytesBuffer[1];
for(int i=0; i<nVars; i++)
{
QString varName((char*)p);
p += SYNCVAR_NAME_SIZE;
VarType varType = (VarType)*p;
p++;
VarAccess varAccess = (VarAccess)*p;
p++;
//int varSize = (int)*p; // Size is ignored.
p++;
SyncVar sv(i, varName, varType, varAccess);
syncVars.append(sv);
}
emit syncVarsListReceived(syncVars);
}
}
break;
case STM_MESSAGE_STREAMING_PACKET:
if(dataBytesReady == streamPacketSize)
{
if(rxDataBytesBuffer[0] == (quint8)streamID)
{
// Decode the timestamp.
quint32 timestamp;
memcpy(&timestamp, &rxDataBytesBuffer[1],
sizeof(timestamp));
// Decode the variables values.
quint8 const* p = &rxDataBytesBuffer[5];
for(int i=0; i<streamedVars.size(); i++)
{
QByteArray value((char*)p,
streamedVars[i]->getSize());
streamedVars[i]->setData(value);
p += streamedVars[i]->getSize();
}
emit syncVarsUpdated();
}
}
break;
case STM_MESSAGE_DEBUG_TEXT:
if(dataBytesReady > 0 &&
rxDataBytesBuffer[dataBytesReady-1] == '\0')
{
qDebug() << QString((const char*)rxDataBytesBuffer);
rxCurrentMessageType = 0;
}
break;
default: // Ignore.
break;
}
}
}
}
/**
* @brief Sends a communication packet to the board.
* @param messageType the type of the message.
* @param dataBytes the data that will be part of the packet, which is
* type-specific. If omitted, there will be no data in the message, so it will
* contain only the type.
*/
void HriBoard::sendPacket(comm_PcMessage messageType, QByteArray dataBytes)
{
QByteArray txBuffer;
txBuffer.append((1<<7) + (uint8_t)messageType);
for(int i=0; i<dataBytes.size(); i++)
{
txBuffer.append(((quint8)dataBytes[i]) >> 4); // MSB.
txBuffer.append(((quint8)dataBytes[i]) & 0xf); // LSB.
}
serial.write(txBuffer);
serial.waitForBytesWritten(-1);
}

Event Timeline