Added flow control and other functionality to UDS / ISO_TP code.
This commit is contained in:
@@ -18,6 +18,8 @@ ISOTP_HANDLER::ISOTP_HANDLER()
|
|||||||
{
|
{
|
||||||
useExtendedAddressing = false;
|
useExtendedAddressing = false;
|
||||||
isReceiving = false;
|
isReceiving = false;
|
||||||
|
|
||||||
|
connect(&frameTimer, SIGNAL(timeout()), this, SLOT(frameTimerTick()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISOTP_HANDLER::setExtendedAddressing(bool mode)
|
void ISOTP_HANDLER::setExtendedAddressing(bool mode)
|
||||||
@@ -61,7 +63,7 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector<unsigned char> data)
|
|||||||
for (int i = 0; i < frame.data[0]; i++) frame.data[i + 1] = data[i];
|
for (int i = 0; i < frame.data[0]; i++) frame.data[i + 1] = data[i];
|
||||||
CANConManager::getInstance()->sendFrame(frame);
|
CANConManager::getInstance()->sendFrame(frame);
|
||||||
}
|
}
|
||||||
else //need to send a multi-part ISO_TP message - no flow control possible right now. TODO - Add flow control
|
else //need to send a multi-part ISO_TP message - Respects timing and frame number based flow control
|
||||||
{
|
{
|
||||||
frame.bus = bus;
|
frame.bus = bus;
|
||||||
frame.ID = ID;
|
frame.ID = ID;
|
||||||
@@ -72,6 +74,11 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector<unsigned char> data)
|
|||||||
frame.data[1] = data.length() & 0xFF;
|
frame.data[1] = data.length() & 0xFF;
|
||||||
for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++];
|
for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++];
|
||||||
CANConManager::getInstance()->sendFrame(frame);
|
CANConManager::getInstance()->sendFrame(frame);
|
||||||
|
//Queue up the rest of the frames
|
||||||
|
waitingForFlow = true;
|
||||||
|
frameTimer.setInterval(200); //wait a while for the flow frame to come in
|
||||||
|
frameTimer.setTimerType(Qt::PreciseTimer);
|
||||||
|
frameTimer.start();
|
||||||
while (currByte < data.length())
|
while (currByte < data.length())
|
||||||
{
|
{
|
||||||
for (int b = 0; b < 8; b++) frame.data[b] = 0xAA;
|
for (int b = 0; b < 8; b++) frame.data[b] = 0xAA;
|
||||||
@@ -81,7 +88,8 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector<unsigned char> data)
|
|||||||
if (bytesToGo > 7) bytesToGo = 7;
|
if (bytesToGo > 7) bytesToGo = 7;
|
||||||
for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++];
|
for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++];
|
||||||
frame.len = 8;
|
frame.len = 8;
|
||||||
CANConManager::getInstance()->sendFrame(frame);
|
sendingFrames.append(frame);
|
||||||
|
//CANConManager::getInstance()->sendFrame(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +108,7 @@ void ISOTP_HANDLER::updatedFrames(int numFrames)
|
|||||||
{
|
{
|
||||||
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
{
|
{
|
||||||
//processFrame(modelFrames->at(i));
|
//processFrame(modelFrames->at(i)); //accepting these frames in rapidFrames instead
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +122,9 @@ void ISOTP_HANDLER::rapidFrames(const CANConnection* conn, const QVector<CANFram
|
|||||||
|
|
||||||
foreach(const CANFrame& thisFrame, pFrames)
|
foreach(const CANFrame& thisFrame, pFrames)
|
||||||
{
|
{
|
||||||
processFrame(thisFrame);
|
//only process frames that we've marked are ISOTP frames
|
||||||
|
//unless processAll is true
|
||||||
|
if (isoIDs[thisFrame.ID] || processAll) processFrame(thisFrame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +230,30 @@ void ISOTP_HANDLER::processFrame(const CANFrame &frame)
|
|||||||
emit newISOMessage(*pMsg);
|
emit newISOMessage(*pMsg);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: //flow control messages -ignored for now
|
case 3: //flow control messages
|
||||||
|
switch (frameLen) //actually flow control type in this case
|
||||||
|
{
|
||||||
|
case 0: //continue to send frames but maybe change inter-frame delay
|
||||||
|
waitingForFlow = false;
|
||||||
|
//data[1] contains number of frames to send before waiting for next flow control
|
||||||
|
framesUntilFlow = frame.data[1];
|
||||||
|
if (framesUntilFlow == 0) framesUntilFlow = -1; //-1 means don't count frames and just keep going
|
||||||
|
//data[2] contains the interframe delay to use (0xF1 through 0xF9 are special through)
|
||||||
|
if (frame.data[2] < 0xF1) frameTimer.start(frame.data[2]); //set proper delay between frames
|
||||||
|
else frameTimer.start(1); //can't do sub-millisecond sending with this code so just use 1ms timing
|
||||||
|
break;
|
||||||
|
case 1: //wait - do not send any more frames until other side says so
|
||||||
|
waitingForFlow = true;
|
||||||
|
frameTimer.stop(); //quit sending frames for now
|
||||||
|
break;
|
||||||
|
case 2: //overflow or abort. Assume this means abort and quit sending
|
||||||
|
frameTimer.stop();
|
||||||
|
sendingFrames.clear();
|
||||||
|
waitingForFlow = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
waitingForFlow = false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,13 +264,7 @@ void ISOTP_HANDLER::checkNeedFlush(uint64_t ID)
|
|||||||
{
|
{
|
||||||
if (messageBuffer[i].ID == ID)
|
if (messageBuffer[i].ID == ID)
|
||||||
{
|
{
|
||||||
//warning... this code will work for direct signals as emit turns into a function call
|
//used to pass by reference but now newISOMessage should pass by value which makes it easier to use cross thread
|
||||||
//and thus the other side will have time to do its processing before control returns
|
|
||||||
//and we delete the message on our side. But, if this code were used cross thread the
|
|
||||||
//emit would be a queued message instead and control would immediately return
|
|
||||||
//here and then the message would be deleted before being delivered.
|
|
||||||
//To fix that the message would have to be passed by value instead which I'd like to avoid.
|
|
||||||
//Thus, don't use this across threads unless you like to debug strange issues.
|
|
||||||
qDebug() << "Flushing a partial frame";
|
qDebug() << "Flushing a partial frame";
|
||||||
emit newISOMessage(messageBuffer[i]);
|
emit newISOMessage(messageBuffer[i]);
|
||||||
messageBuffer.removeAt(i);
|
messageBuffer.removeAt(i);
|
||||||
@@ -245,3 +272,52 @@ void ISOTP_HANDLER::checkNeedFlush(uint64_t ID)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::frameTimerTick()
|
||||||
|
{
|
||||||
|
CANFrame frame;
|
||||||
|
if (!waitingForFlow)
|
||||||
|
{
|
||||||
|
if (!sendingFrames.isEmpty())
|
||||||
|
{
|
||||||
|
frame = sendingFrames.takeFirst();
|
||||||
|
CANConManager::getInstance()->sendFrame(frame);
|
||||||
|
if (framesUntilFlow > -1) framesUntilFlow--;
|
||||||
|
if (framesUntilFlow == 0) //stop sending and wait for another flow control message
|
||||||
|
{
|
||||||
|
frameTimer.stop(); //we absolutely will not send anything until other side says to.
|
||||||
|
waitingForFlow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //no more frames to send
|
||||||
|
{
|
||||||
|
frameTimer.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //while waiting for a flow frame we didn't get one during timeout period. Try to send anyway with default timeout
|
||||||
|
{
|
||||||
|
waitingForFlow = false;
|
||||||
|
frameTimer.setInterval(20); //pretty slow sending which should be OK as a default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::setProcessAll(bool state)
|
||||||
|
{
|
||||||
|
processAll = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::addID(uint32_t id)
|
||||||
|
{
|
||||||
|
isoIDs[id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::removeID(uint32_t id)
|
||||||
|
{
|
||||||
|
isoIDs.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ISOTP_HANDLER::clearAllIDs()
|
||||||
|
{
|
||||||
|
isoIDs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <Qt>
|
#include <Qt>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
#include "can_structs.h"
|
#include "can_structs.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "canframemodel.h"
|
#include "canframemodel.h"
|
||||||
@@ -19,19 +20,30 @@ public:
|
|||||||
static ISOTP_HANDLER* getInstance();
|
static ISOTP_HANDLER* getInstance();
|
||||||
void setReception(bool mode); //set whether to accept and forward frames or not
|
void setReception(bool mode); //set whether to accept and forward frames or not
|
||||||
void sendISOTPFrame(int bus, int ID, QVector<unsigned char> data);
|
void sendISOTPFrame(int bus, int ID, QVector<unsigned char> data);
|
||||||
|
void setProcessAll(bool state);
|
||||||
|
void addID(uint32_t id);
|
||||||
|
void removeID(uint32_t id);
|
||||||
|
void clearAllIDs();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updatedFrames(int);
|
void updatedFrames(int);
|
||||||
void rapidFrames(const CANConnection* conn, const QVector<CANFrame>& pFrames);
|
void rapidFrames(const CANConnection* conn, const QVector<CANFrame>& pFrames);
|
||||||
|
void frameTimerTick();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newISOMessage(ISOTP_MESSAGE &msg);
|
void newISOMessage(ISOTP_MESSAGE msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<ISOTP_MESSAGE> messageBuffer;
|
QList<ISOTP_MESSAGE> messageBuffer;
|
||||||
|
QList<CANFrame> sendingFrames;
|
||||||
|
QMap<uint32_t, bool> isoIDs;
|
||||||
const QVector<CANFrame> *modelFrames;
|
const QVector<CANFrame> *modelFrames;
|
||||||
bool useExtendedAddressing;
|
bool useExtendedAddressing;
|
||||||
bool isReceiving;
|
bool isReceiving;
|
||||||
|
bool waitingForFlow;
|
||||||
|
int framesUntilFlow;
|
||||||
|
bool processAll;
|
||||||
|
QTimer frameTimer;
|
||||||
|
|
||||||
void processFrame(const CANFrame &frame);
|
void processFrame(const CANFrame &frame);
|
||||||
void checkNeedFlush(uint64_t ID);
|
void checkNeedFlush(uint64_t ID);
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ UDS_HANDLER::UDS_HANDLER()
|
|||||||
useExtendedAddressing = false;
|
useExtendedAddressing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg)
|
void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg)
|
||||||
{
|
{
|
||||||
qDebug() << "UDS handler got ISOTP frame";
|
qDebug() << "UDS handler got ISOTP frame";
|
||||||
UDS_MESSAGE udsMsg;
|
UDS_MESSAGE udsMsg;
|
||||||
@@ -195,13 +195,13 @@ void UDS_HANDLER::setReception(bool mode)
|
|||||||
|
|
||||||
if (isReceiving)
|
if (isReceiving)
|
||||||
{
|
{
|
||||||
connect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&)));
|
connect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE)));
|
||||||
ISOTP_HANDLER::getInstance()->setReception(true); //must enable ISOTP reception too.
|
ISOTP_HANDLER::getInstance()->setReception(true); //must enable ISOTP reception too.
|
||||||
qDebug() << "Enabling reception of ISO-TP frames in UDS handler";
|
qDebug() << "Enabling reception of ISO-TP frames in UDS handler";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
disconnect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE&)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE&)));
|
disconnect(ISOTP_HANDLER::getInstance(), SIGNAL(newISOMessage(ISOTP_MESSAGE)), this, SLOT(gotISOTPFrame(ISOTP_MESSAGE)));
|
||||||
//can't disable ISOTP reception because something else might be using it.
|
//can't disable ISOTP reception because something else might be using it.
|
||||||
qDebug() << "Disabling reception of ISOTP frames in UDS handler";
|
qDebug() << "Disabling reception of ISOTP frames in UDS handler";
|
||||||
}
|
}
|
||||||
@@ -264,3 +264,25 @@ QString UDS_HANDLER::getNegativeResponseLong(int respCode)
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Little shim functions that drop straight through to the ISO_TP handler
|
||||||
|
void UDS_HANDLER::setProcessAllIDs(bool state)
|
||||||
|
{
|
||||||
|
ISOTP_HANDLER::getInstance()->setProcessAll(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDS_HANDLER::addID(uint32_t id)
|
||||||
|
{
|
||||||
|
ISOTP_HANDLER::getInstance()->addID(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDS_HANDLER::removeID(uint32_t id)
|
||||||
|
{
|
||||||
|
ISOTP_HANDLER::getInstance()->removeID(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDS_HANDLER::clearAllIDs()
|
||||||
|
{
|
||||||
|
ISOTP_HANDLER::getInstance()->clearAllIDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -89,16 +89,20 @@ public:
|
|||||||
static UDS_HANDLER* getInstance();
|
static UDS_HANDLER* getInstance();
|
||||||
void setReception(bool mode); //set whether to accept and forward frames or not
|
void setReception(bool mode); //set whether to accept and forward frames or not
|
||||||
void sendUDSFrame(const UDS_MESSAGE &msg);
|
void sendUDSFrame(const UDS_MESSAGE &msg);
|
||||||
|
void setProcessAllIDs(bool state);
|
||||||
|
void addID(uint32_t id);
|
||||||
|
void removeID(uint32_t id);
|
||||||
|
void clearAllIDs();
|
||||||
QString getServiceShortDesc(int service);
|
QString getServiceShortDesc(int service);
|
||||||
QString getServiceLongDesc(int service);
|
QString getServiceLongDesc(int service);
|
||||||
QString getNegativeResponseShort(int respCode);
|
QString getNegativeResponseShort(int respCode);
|
||||||
QString getNegativeResponseLong(int respCode);
|
QString getNegativeResponseLong(int respCode);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void gotISOTPFrame(ISOTP_MESSAGE &msg);
|
void gotISOTPFrame(ISOTP_MESSAGE msg);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newUDSMessage(UDS_MESSAGE &msg);
|
void newUDSMessage(UDS_MESSAGE msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<ISOTP_MESSAGE> messageBuffer;
|
QList<ISOTP_MESSAGE> messageBuffer;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ FramePlaybackWindow::FramePlaybackWindow(const QVector<CANFrame> *frames, QWidge
|
|||||||
modelFrames = frames;
|
modelFrames = frames;
|
||||||
|
|
||||||
playbackTimer = new QTimer();
|
playbackTimer = new QTimer();
|
||||||
|
playbackTimer->setTimerType(Qt::PreciseTimer);
|
||||||
|
|
||||||
currentPosition = 0;
|
currentPosition = 0;
|
||||||
playbackActive = false;
|
playbackActive = false;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ FrameSenderWindow::FrameSenderWindow(const QVector<CANFrame> *frames, QWidget *p
|
|||||||
modelFrames = frames;
|
modelFrames = frames;
|
||||||
|
|
||||||
intervalTimer = new QTimer();
|
intervalTimer = new QTimer();
|
||||||
|
intervalTimer->setTimerType(Qt::PreciseTimer);
|
||||||
intervalTimer->setInterval(1);
|
intervalTimer->setInterval(1);
|
||||||
|
|
||||||
QStringList headers;
|
QStringList headers;
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ ISOTP_InterpreterWindow::ISOTP_InterpreterWindow(const QVector<CANFrame> *frames
|
|||||||
|
|
||||||
decoder = ISOTP_HANDLER::getInstance();
|
decoder = ISOTP_HANDLER::getInstance();
|
||||||
|
|
||||||
|
decoder->setReception(true);
|
||||||
|
decoder->setProcessAll(true);
|
||||||
|
|
||||||
connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ISOTP_InterpreterWindow::updatedFrames);
|
connect(MainWindow::getReference(), &MainWindow::framesUpdated, this, &ISOTP_InterpreterWindow::updatedFrames);
|
||||||
connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames);
|
connect(MainWindow::getReference(), &MainWindow::framesUpdated, decoder, &ISOTP_HANDLER::updatedFrames);
|
||||||
connect(decoder, &ISOTP_HANDLER::newISOMessage, this, &ISOTP_InterpreterWindow::newISOMessage);
|
connect(decoder, &ISOTP_HANDLER::newISOMessage, this, &ISOTP_InterpreterWindow::newISOMessage);
|
||||||
@@ -123,7 +126,7 @@ void ISOTP_InterpreterWindow::showDetailView()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE &msg)
|
void ISOTP_InterpreterWindow::newISOMessage(ISOTP_MESSAGE msg)
|
||||||
{
|
{
|
||||||
int rowNum;
|
int rowNum;
|
||||||
QString tempString;
|
QString tempString;
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public:
|
|||||||
void showEvent(QShowEvent*);
|
void showEvent(QShowEvent*);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void newISOMessage(ISOTP_MESSAGE &msg);
|
void newISOMessage(ISOTP_MESSAGE msg);
|
||||||
void showDetailView();
|
void showDetailView();
|
||||||
void updatedFrames(int);
|
void updatedFrames(int);
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ UDSScanWindow::UDSScanWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
|||||||
waitTimer->setInterval(100);
|
waitTimer->setInterval(100);
|
||||||
|
|
||||||
UDS_HANDLER::getInstance()->setReception(true);
|
UDS_HANDLER::getInstance()->setReception(true);
|
||||||
|
UDS_HANDLER::getInstance()->setProcessAllIDs(true);
|
||||||
|
|
||||||
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
connect(UDS_HANDLER::getInstance(), &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply);
|
connect(UDS_HANDLER::getInstance(), &UDS_HANDLER::newUDSMessage, this, &UDSScanWindow::gotUDSReply);
|
||||||
@@ -317,7 +318,7 @@ void UDSScanWindow::updatedFrames(int numFrames)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDSScanWindow::gotUDSReply(UDS_MESSAGE &msg)
|
void UDSScanWindow::gotUDSReply(UDS_MESSAGE msg)
|
||||||
{
|
{
|
||||||
QString result;
|
QString result;
|
||||||
QString serviceShortName;
|
QString serviceShortName;
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updatedFrames(int numFrames);
|
void updatedFrames(int numFrames);
|
||||||
void gotUDSReply(UDS_MESSAGE &msg);
|
void gotUDSReply(UDS_MESSAGE msg);
|
||||||
void scanUDS();
|
void scanUDS();
|
||||||
void saveResults();
|
void saveResults();
|
||||||
void timeOut();
|
void timeOut();
|
||||||
|
|||||||
Reference in New Issue
Block a user