attempt to adapt GVRET to the new interface

This commit is contained in:
canpadawan
2016-06-15 18:24:01 +02:00
parent cdff06ebe3
commit 6e623015dd
2 changed files with 715 additions and 8 deletions
+607 -2
View File
@@ -1,6 +1,611 @@
#include "cvretserial.h"
#include <QObject>
#include <QDebug>
#include <QCanBusFrame>
#include <QSerialPortInfo>
#include <QSettings>
CVRetSerial::CVRetSerial()
#include "gvretserial.h"
GVRetSerial::GVRetSerial(QString portName) :
CANConnection(portName, CANCon::GVRET_SERIAL, 2),
mThread(NULL)
{
getQueue().setSize(2000); /*TODO add check on returned value */
/* move ourself to the thread */
moveToThread(&mThread);
qDebug() << "GVRetSerial()";
serial = NULL;
rx_state = IDLE;
rx_step = 0;
gotValidated = true;
isAutoRestart = false;
txTimestampBasis = QDateTime::currentMSecsSinceEpoch();
readSettings();
}
GVRetSerial::~GVRetSerial()
{
stop();
qDebug() << "~GVRetSerial()";
}
void GVRetSerial::start()
{
qDebug() << "enter thread";
/* start thread */
mThread.start(QThread::HighPriority);
/* connect device in thread context */
connect(&mThread, SIGNAL(started()), this, SLOT(connectDevice()));
/* start timer */
connect(&mTimer, SIGNAL(timeout()), this, SLOT(handleTick()));
mTimer.setInterval(250); //tick four times per second
mTimer.setSingleShot(false); //keep ticking
mTimer.start();
}
void GVRetSerial::suspend(bool pSuspend) {
/* make sure we execute in mThread context */
if(QThread::currentThread() != &mThread) {
QMetaObject::invokeMethod(this, "suspend",
Qt::BlockingQueuedConnection,
Q_ARG(bool, pSuspend));
return;
}
/* update capSuspended */
setCapSuspended(pSuspend);
/* flush queue if we are suspended */
if(isCapSuspended())
getQueue().flush();
}
void GVRetSerial::stop() {
mTimer.stop();
mThread.quit();
if(!mThread.wait()) {
qDebug() << "can't stop thread";
}
disconnectDevice();
}
bool GVRetSerial::getBusSettings(int pBusIdx, CANBus& pBus) {
/* make sure we execute in mThread context */
if(QThread::currentThread() != &mThread) {
bool ret;
QMetaObject::invokeMethod(this, "getBusSettings",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(int , pBusIdx),
Q_ARG(CANBus& , pBus));
return ret;
}
return getBusConfig(pBusIdx, pBus);
}
void GVRetSerial::sendFrame(const CANFrame *) {}
void GVRetSerial::sendFrameBatch(const QList<CANFrame> *){}
void GVRetSerial::readSettings()
{
QSettings settings;
if (settings.value("Main/ValidateComm", true).toBool())
{
doValidation = true;
}
else doValidation = false;
}
void GVRetSerial::connectDevice()
{
QSettings settings;
/* disconnect device */
if(serial)
disconnectDevice();
/* open new device */
serial = new QSerialPort(QSerialPortInfo(getPort()));
if(!serial) {
qDebug() << "can't open serial port " << getPort();
return;
}
/* configure */
serial->setDataBits(serial->Data8);
serial->setFlowControl(serial->HardwareControl); //this is important though
if (!serial->open(QIODevice::ReadWrite))
{
qDebug() << serial->errorString();
}
serial->setDataTerminalReady(true); //you do need to set these or the fan gets dirty
serial->setRequestToSend(true);
QByteArray output;
output.append((char)0xE7); //this puts the device into binary comm mode
output.append((char)0xE7);
output.append((char)0xF1); //signal we want to issue a command
output.append((char)0x06); //request canbus stats from the board
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x07); //request device information
output.append((char)0xF1);
output.append((char)0x08); //setting singlewire mode
if (settings.value("Main/SingleWireMode", false).toBool())
{
output.append((char)0x10); //signal that we do want single wire mode
}
else
{
output.append((char)0xFF); //signal we don't want single wire mode
}
output.append((char)0xF1); //yet another command
output.append((char)0x09); //comm validation command
output.append((char)0xF1); //and another command
output.append((char)0x01); //Time Sync - Not implemented until 333 but we can try
continuousTimeSync = true;
serial->write(output);
if(doValidation) {
QTimer::singleShot(1000, this, SLOT(connectionTimeout()));
}
else {
setStatus(CANCon::CONNECTED);
emit status(getStatus());
}
/* connect reading event */
connect(serial, SIGNAL(readyRead()), this, SLOT(readSerialData()));
}
void GVRetSerial::disconnectDevice() {
if (serial != NULL)
{
if (serial->isOpen())
{
serial->clear();
serial->close();
}
serial->disconnect(); //disconnect all signals
delete serial;
serial = NULL;
}
}
void GVRetSerial::connectionTimeout()
{
//one second after trying to connect are we actually connected?
if (CANCon::NOT_CONNECTED==getStatus()) //no?
{
//then emit the the failure signal and see if anyone cares
qDebug() << "Failed to connect to GVRET at that com port";
disconnectDevice();
}
}
void GVRetSerial::readSerialData()
{
QByteArray data = serial->readAll();
unsigned char c;
//qDebug() << (tr("Got data from serial. Len = %0").arg(data.length()));
for (int i = 0; i < data.length(); i++)
{
c = data.at(i);
procRXChar(c);
}
}
void GVRetSerial::procRXChar(unsigned char c)
{
switch (rx_state)
{
case IDLE:
if (c == 0xF1) rx_state = GET_COMMAND;
break;
case GET_COMMAND:
switch (c)
{
case 0: //receiving a can frame
rx_state = BUILD_CAN_FRAME;
rx_step = 0;
break;
case 1: //time sync
rx_state = TIME_SYNC;
rx_step = 0;
break;
case 2: //process a return reply for digital input states.
rx_state = GET_DIG_INPUTS;
rx_step = 0;
break;
case 3: //process a return reply for analog inputs
rx_state = GET_ANALOG_INPUTS;
break;
case 4: //we set digital outputs we don't accept replies so nothing here.
rx_state = IDLE;
break;
case 5: //we set canbus specs we don't accept replies.
rx_state = IDLE;
break;
case 6: //get canbus parameters from GVRET
rx_state = GET_CANBUS_PARAMS;
rx_step = 0;
break;
case 7: //get device info
rx_state = GET_DEVICE_INFO;
rx_step = 0;
break;
case 9:
gotValidated = true;
//qDebug() << "Got validated";
rx_state = IDLE;
break;
}
break;
case BUILD_CAN_FRAME:
switch (rx_step)
{
case 0:
buildFrame.timestamp = c;
break;
case 1:
buildFrame.timestamp |= (uint)(c << 8);
break;
case 2:
buildFrame.timestamp |= (uint)c << 16;
break;
case 3:
buildFrame.timestamp |= (uint)c << 24;
break;
case 4:
buildFrame.ID = c;
break;
case 5:
buildFrame.ID |= c << 8;
break;
case 6:
buildFrame.ID |= c << 16;
break;
case 7:
buildFrame.ID |= c << 24;
if ((buildFrame.ID & 1 << 31) == 1 << 31)
{
buildFrame.ID &= 0x7FFFFFFF;
buildFrame.extended = true;
}
else buildFrame.extended = false;
break;
case 8:
buildFrame.len = c & 0xF;
if (buildFrame.len > 8) buildFrame.len = 8;
buildFrame.bus = (c & 0xF0) >> 4;
break;
default:
if (rx_step < buildFrame.len + 9)
{
buildFrame.data[rx_step - 9] = c;
}
else
{
rx_state = IDLE;
rx_step = 0;
buildFrame.isReceived = true;
if (!isCapSuspended())
{
/* get frame from queue */
CANFrame* frame_p = getQueue().get();
if(frame_p) {
/* copy frame */
*frame_p = buildFrame;
/* enqueue frame */
getQueue().queue();
}
else
qDebug() << "can't get a frame, ERROR";
//take the time the frame came in and try to resync the time base.
if (continuousTimeSync) txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - (buildFrame.timestamp / 1000);
}
}
break;
}
rx_step++;
break;
case TIME_SYNC: //gives a pretty good base guess for the proper timestamp. Can be refined when traffic starts to flow (if wanted)
switch (rx_step)
{
case 0:
buildTimeBasis = c;
break;
case 1:
buildTimeBasis += ((uint32_t)c << 8);
break;
case 2:
buildTimeBasis += ((uint32_t)c << 16);
break;
case 3:
buildTimeBasis += ((uint32_t)c << 24);
qDebug() << "GVRET firmware reports timestamp of " << buildTimeBasis;
txTimestampBasis = QDateTime::currentMSecsSinceEpoch() - ((uint64_t)buildTimeBasis / (uint64_t)1000ull);
continuousTimeSync = false;
rx_state = IDLE;
break;
}
rx_step++;
break;
case GET_ANALOG_INPUTS: //get 9 bytes - 2 per analog input plus checksum
switch (rx_step)
{
case 0:
break;
}
rx_step++;
break;
case GET_DIG_INPUTS: //get two bytes. One for digital in status and one for checksum.
switch (rx_step)
{
case 0:
break;
case 1:
rx_state = IDLE;
break;
}
rx_step++;
break;
case GET_CANBUS_PARAMS:
switch (rx_step)
{
case 0:
can0Enabled = (c & 0xF);
can0ListenOnly = (c >> 4);
break;
case 1:
can0Baud = c;
break;
case 2:
can0Baud |= c << 8;
break;
case 3:
can0Baud |= c << 16;
break;
case 4:
can0Baud |= c << 24;
break;
case 5:
can1Enabled = (c & 0xF);
can1ListenOnly = (c >> 4);
deviceSingleWireMode = (c >> 6);
break;
case 6:
can1Baud = c;
break;
case 7:
can1Baud |= c << 8;
break;
case 8:
can1Baud |= c << 16;
break;
case 9:
can1Baud |= c << 24;
rx_state = IDLE;
qDebug() << "Baud 0 = " << can0Baud;
qDebug() << "Baud 1 = " << can1Baud;
can0Baud |= 0x80000000;
if (can0Enabled) can0Baud |= 0x40000000;
if (can0ListenOnly) can0Baud |= 0x20000000;
can1Baud |= 0x80000000;
if (can1Enabled) can1Baud |= 0x40000000;
if (can1ListenOnly) can1Baud |= 0x20000000;
if (deviceSingleWireMode > 0) can1Baud |= 0x10000000;
setStatus(CANCon::CONNECTED);
emit status(getStatus());
int can0Status = 0x78; //updating everything we can update
int can1Status = 0x78;
if (can0Enabled) can0Status +=1;
if (can0ListenOnly) can0Status += 4;
if (can1Enabled) can1Status += 1;
if (deviceSingleWireMode > 0) can1Status += 2;
if (can1ListenOnly) can1Status += 4;
//emit busStatus(busBase, can0Baud & 0xFFFFF, can0Status);
//emit busStatus(busBase + 1, can1Baud & 0xFFFFF, can1Status);
break;
}
rx_step++;
break;
case GET_DEVICE_INFO:
switch (rx_step)
{
case 0:
deviceBuildNum = c;
break;
case 1:
deviceBuildNum |= c << 8;
break;
case 2:
break; //don't care about eeprom version
case 3:
break; //don't care about file type
case 4:
break; //don't care about whether it auto logs or not
case 5:
deviceSingleWireMode = c;
rx_state = IDLE;
qDebug() << "build num: " << deviceBuildNum;
qDebug() << "single wire can: " << deviceSingleWireMode;
emit deviceInfo(deviceBuildNum, deviceSingleWireMode);
break;
}
rx_step++;
break;
case SET_DIG_OUTPUTS:
rx_state = IDLE;
break;
case SETUP_CANBUS:
rx_state = IDLE;
break;
case SET_SINGLEWIRE_MODE:
rx_state = IDLE;
break;
}
}
void GVRetSerial::handleTick()
{
//qDebug() << "Tick!";
if( CANCon::CONNECTED == getStatus() )
{
if (!gotValidated && doValidation)
{
if (serial == NULL) return;
if (serial->isOpen()) //if it's still false we have a problem...
{
qDebug() << "Comm validation failed. ";
setStatus(CANCon::NOT_CONNECTED);
emit status(getStatus());
disconnectDevice(); //start by stopping everything.
//Then wait 500ms and restart the connection automatically
QTimer::singleShot(500, this, SLOT(connectDevice()));
return;
}
}
}
if (doValidation && serial && serial->isOpen()) sendCommValidation();
}
void GVRetSerial::sendCommValidation()
{
QByteArray output;
gotValidated = false;
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x09); //request a reply to get validation
//send it twice for good measure.
output.append((char)0xF1); //another command to the GVRET
output.append((char)0x09); //request a reply to get validation
serial->write(output);
}
void GVRetSerial::setBusSettings(int pBusIdx, CANBus bus)
{
/* make sure we execute in mThread context */
if(QThread::currentThread() != &mThread) {
QMetaObject::invokeMethod(this, "setBusSettings",
Qt::BlockingQueuedConnection,
Q_ARG(int, pBusIdx),
Q_ARG(CANBus, bus));
return;
}
/* sanity checks */
if( (pBusIdx < 0) || pBusIdx >= getNumBuses())
return;
/* copy bus config */
setBusConfig(pBusIdx, bus);
qDebug() << "About to update bus " << pBusIdx << " on GVRET";
if (pBusIdx == 0)
{
can0Baud = bus.getSpeed();
can0Baud |= 0x80000000;
if (bus.isActive())
{
can0Baud |= 0x40000000;
can0Enabled = true;
}
else can0Enabled = false;
if (bus.isListenOnly())
{
can0Baud |= 0x20000000;
can0ListenOnly = true;
}
else can0ListenOnly = false;
}
else if (pBusIdx == 1)
{
can1Baud = bus.getSpeed();
can1Baud |= 0x80000000;
if (bus.isActive())
{
can1Baud |= 0x40000000;
can1Enabled = true;
}
else can1Enabled = false;
if (bus.isListenOnly())
{
can1Baud |= 0x20000000;
can1ListenOnly = true;
}
else can1ListenOnly = false;
if (bus.isSingleWire())
{
can1Baud |= 0x10000000;
deviceSingleWireMode = 1;
}
else deviceSingleWireMode = 0;
}
/* update baud rates */
QByteArray buffer;
qDebug() << "Got signal to update bauds. 1: " << can0Baud <<" 2: " << can1Baud;
buffer[0] = (char)0xF1; //start of a command over serial
buffer[1] = 5; //setup canbus
buffer[2] = (unsigned char)(can0Baud & 0xFF); //four bytes of ID LSB first
buffer[3] = (unsigned char)(can0Baud >> 8);
buffer[4] = (unsigned char)(can0Baud >> 16);
buffer[5] = (unsigned char)(can0Baud >> 24);
buffer[6] = (unsigned char)(can1Baud & 0xFF); //four bytes of ID LSB first
buffer[7] = (unsigned char)(can1Baud >> 8);
buffer[8] = (unsigned char)(can1Baud >> 16);
buffer[9] = (unsigned char)(can1Baud >> 24);
buffer[10] = 0;
if (serial == NULL) return;
if (!serial->isOpen()) return;
serial->write(buffer);
}
+108 -6
View File
@@ -1,11 +1,113 @@
#ifndef CVRETSERIAL_H
#define CVRETSERIAL_H
#ifndef GVRETSERIAL_H
#define GVRETSERIAL_H
#include <QSerialPort>
#include <QCanBusDevice>
#include <QThread>
#include <QTimer>
/*************/
#include <QMutex>
#include <QDateTime>
/*************/
class CVRetSerial
#include "canframemodel.h"
#include "canconnection.h"
namespace SERIALSTATE {
enum STATE //keep this enum synchronized with the Arduino firmware project
{
public:
CVRetSerial();
IDLE,
GET_COMMAND,
BUILD_CAN_FRAME,
TIME_SYNC,
GET_DIG_INPUTS,
GET_ANALOG_INPUTS,
SET_DIG_OUTPUTS,
SETUP_CANBUS,
GET_CANBUS_PARAMS,
GET_DEVICE_INFO,
SET_SINGLEWIRE_MODE
};
#endif // CVRETSERIAL_H
}
using namespace SERIALSTATE;
class GVRetSerial : public CANConnection
{
Q_OBJECT
public:
GVRetSerial(QString portName);
virtual ~GVRetSerial();
virtual void start();
virtual void stop();
signals:
void error(const QString &);
void status(CANCon::status);
void deviceInfo(int, int); //First param = driver version (or version of whatever you want), second param a status byte
//bus number, bus speed, status (bit 0 = enabled, 1 = single wire, 2 = listen only)
//3 = Use value stored for enabled, 4 = use value passed for single wire, 5 = use value passed for listen only
//6 = use value passed for speed. This allows bus status to be updated but set that some things aren't really
//being passed. Just set for things that really are being updated.
void busStatus(int, int, int);
public slots:
virtual void sendFrame(const CANFrame *);
virtual void sendFrameBatch(const QList<CANFrame> *);
virtual void setBusSettings(int, CANBus);
virtual bool getBusSettings(int pBusIdx, CANBus& pBus);
virtual void suspend(bool);
protected:
void disconnectDevice();
private slots:
void connectDevice();
void connectionTimeout();
void readSerialData();
void handleTick();
private:
void readSettings();
void procRXChar(unsigned char);
void sendCommValidation();
protected:
QTimer mTimer;
QThread mThread;
bool doValidation;
bool gotValidated;
bool isAutoRestart;
bool continuousTimeSync;
QSerialPort *serial;
QMutex sendBulkMutex;
int framesRapid;
STATE rx_state;
int rx_step;
CANFrame buildFrame;
int can0Baud, can1Baud;
bool can0Enabled, can1Enabled;
bool can0ListenOnly, can1ListenOnly;
int deviceBuildNum;
int deviceSingleWireMode;
uint64_t txTimestampBasis;
uint32_t buildTimeBasis;
};
#endif // GVRETSERIAL_H