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;
|
||||
isReceiving = false;
|
||||
|
||||
connect(&frameTimer, SIGNAL(timeout()), this, SLOT(frameTimerTick()));
|
||||
}
|
||||
|
||||
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];
|
||||
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.ID = ID;
|
||||
@@ -72,6 +74,11 @@ void ISOTP_HANDLER::sendISOTPFrame(int bus, int ID, QVector<unsigned char> data)
|
||||
frame.data[1] = data.length() & 0xFF;
|
||||
for (int i = 0; i < 6; i++) frame.data[2 + i] = data[currByte++];
|
||||
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())
|
||||
{
|
||||
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;
|
||||
for (int i = 0; i < bytesToGo; i++) frame.data[1 + i] = data[currByte++];
|
||||
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++)
|
||||
{
|
||||
//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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -231,13 +264,7 @@ void ISOTP_HANDLER::checkNeedFlush(uint64_t ID)
|
||||
{
|
||||
if (messageBuffer[i].ID == ID)
|
||||
{
|
||||
//warning... this code will work for direct signals as emit turns into a function call
|
||||
//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.
|
||||
//used to pass by reference but now newISOMessage should pass by value which makes it easier to use cross thread
|
||||
qDebug() << "Flushing a partial frame";
|
||||
emit newISOMessage(messageBuffer[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 <QObject>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include "can_structs.h"
|
||||
#include "mainwindow.h"
|
||||
#include "canframemodel.h"
|
||||
@@ -19,19 +20,30 @@ public:
|
||||
static ISOTP_HANDLER* getInstance();
|
||||
void setReception(bool mode); //set whether to accept and forward frames or not
|
||||
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:
|
||||
void updatedFrames(int);
|
||||
void rapidFrames(const CANConnection* conn, const QVector<CANFrame>& pFrames);
|
||||
void frameTimerTick();
|
||||
|
||||
signals:
|
||||
void newISOMessage(ISOTP_MESSAGE &msg);
|
||||
void newISOMessage(ISOTP_MESSAGE msg);
|
||||
|
||||
private:
|
||||
QList<ISOTP_MESSAGE> messageBuffer;
|
||||
QList<CANFrame> sendingFrames;
|
||||
QMap<uint32_t, bool> isoIDs;
|
||||
const QVector<CANFrame> *modelFrames;
|
||||
bool useExtendedAddressing;
|
||||
bool isReceiving;
|
||||
bool waitingForFlow;
|
||||
int framesUntilFlow;
|
||||
bool processAll;
|
||||
QTimer frameTimer;
|
||||
|
||||
void processFrame(const CANFrame &frame);
|
||||
void checkNeedFlush(uint64_t ID);
|
||||
|
||||
@@ -150,7 +150,7 @@ UDS_HANDLER::UDS_HANDLER()
|
||||
useExtendedAddressing = false;
|
||||
}
|
||||
|
||||
void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE &msg)
|
||||
void UDS_HANDLER::gotISOTPFrame(ISOTP_MESSAGE msg)
|
||||
{
|
||||
qDebug() << "UDS handler got ISOTP frame";
|
||||
UDS_MESSAGE udsMsg;
|
||||
@@ -195,13 +195,13 @@ void UDS_HANDLER::setReception(bool mode)
|
||||
|
||||
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.
|
||||
qDebug() << "Enabling reception of ISO-TP frames in UDS handler";
|
||||
}
|
||||
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.
|
||||
qDebug() << "Disabling reception of ISOTP frames in UDS handler";
|
||||
}
|
||||
@@ -264,3 +264,25 @@ QString UDS_HANDLER::getNegativeResponseLong(int respCode)
|
||||
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();
|
||||
void setReception(bool mode); //set whether to accept and forward frames or not
|
||||
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 getServiceLongDesc(int service);
|
||||
QString getNegativeResponseShort(int respCode);
|
||||
QString getNegativeResponseLong(int respCode);
|
||||
|
||||
public slots:
|
||||
void gotISOTPFrame(ISOTP_MESSAGE &msg);
|
||||
void gotISOTPFrame(ISOTP_MESSAGE msg);
|
||||
|
||||
signals:
|
||||
void newUDSMessage(UDS_MESSAGE &msg);
|
||||
void newUDSMessage(UDS_MESSAGE msg);
|
||||
|
||||
private:
|
||||
QList<ISOTP_MESSAGE> messageBuffer;
|
||||
|
||||
Reference in New Issue
Block a user