Files
giesCANne/connections/canconnection.cpp
T
Andy Huska 1b41decd20 Custom sender is no longer crashing
There are a TON of explorations I did here, many may be unnecessary, but this is a stake in the ground.

The main issue was the strange queue logic in canconmanager::sendFrame which puts the tx data in the rx
queue so it will show up in the displayed data.  It caused SIGABRT and SIGSEG to show up everywhere.
It is NOT fixed yet, but TX works over the wire you just can't see it in the tableview.

I thought at first it was only when overwrite data was active, so I put in a a pile of changes to keep
frames and filtered frames as two seperate copies of data where frames was always complete and filtered
was only what was seen in the mainwindow.  It made it so the graphing window would work with overwrite
data active which is an improvement.  I wouldn't roll these changes back.  Because of these changes I
had to update the frame sorting code adjust the refresh function in canframemode.cpp

I also thought it was related to UI updates, but its not, that's been confirmed.

I put a mutex around the custom sender tick timer so that the 1ms timer wouldn't re-enter its callback.
This didn't fix the crash, but it sure seems to make a lot of sense, and the way I did it no elasped
time is lost for tracking purposes, and in reality theres no way 1ms was consistent anyway.

I put a mutex around the shrinking of frames and filteredframes to make sure we weren't deleting at
the same time as accessing, but honestly we acccess those lists in many places without semaphores so
that probably did nothing.

Fixed a bug in FrameSenderWindow:DoModifiers that was improperly parsing and sometimes crashing when
looking for the ~ operator before a symbol.

Also added some minor work to keep row expansion functioning when changing filters or sorting.  Need
to make some tweaks so it stops trying so hard when overwrite is not active

Theres also code in main.c taht makes debugging output super verbose.

Committing now to start cleanup
2022-11-01 15:01:07 -05:00

374 lines
10 KiB
C++

#include <QSettings>
#include <QThread>
#include "canconnection.h"
CANConnection::CANConnection(QString pPort,
QString pDriver,
CANCon::type pType,
int pSerialSpeed,
int pBusSpeed,
int pNumBuses,
int pQueueLen,
bool pUseThread) :
mNumBuses(pNumBuses),
mQueue(),
mPort(pPort),
mDriver(pDriver),
mType(pType),
mSerialSpeed(pSerialSpeed),
mIsCapSuspended(false),
mStatus(CANCon::NOT_CONNECTED),
mStarted(false),
mThread_p(nullptr)
{
/* register types */
qRegisterMetaType<CANBus>("CANBus");
qRegisterMetaType<CANFrame>("CANFrame");
qRegisterMetaType<CANConStatus>("CANConStatus");
qRegisterMetaType<CANFltObserver>("CANFlt");
/* set queue size */
mQueue.setSize(pQueueLen); /*TODO add check on returned value */
/* allocate buses */
/* TODO: change those tables for a vector */
mBusData.resize(mNumBuses);
for(int i=0 ; i<mNumBuses ; i++) {
mBusData[i].mConfigured = false;
}
if (pBusSpeed > 0) mBusData[0].mBus.setSpeed(pBusSpeed);
/* if needed, create a thread and move ourself into it */
if(pUseThread) {
mThread_p = new QThread();
}
}
CANConnection::~CANConnection()
{
/* stop and delete thread */
if(mThread_p) {
mThread_p->quit();
mThread_p->wait();
delete mThread_p;
mThread_p = nullptr;
}
mBusData.clear();
}
void CANConnection::start()
{
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
/* move ourself to the thread */
moveToThread(mThread_p); /*TODO handle errors */
/* connect started() */
connect(mThread_p, SIGNAL(started()), this, SLOT(start()));
/* start the thread */
mThread_p->start(QThread::HighPriority);
return;
}
/* set started flag */
mStarted = true;
QSettings settings;
if (settings.value("Main/TimeClock", false).toBool())
{
useSystemTime = true;
}
else useSystemTime = false;
/* in multithread case, this will be called before entering thread event loop */
return piStarted();
}
void CANConnection::suspend(bool pSuspend)
{
/* execute in mThread_p context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "suspend",
Qt::BlockingQueuedConnection,
Q_ARG(bool, pSuspend));
return;
}
return piSuspend(pSuspend);
}
void CANConnection::stop()
{
/* 1) execute in mThread_p context */
if( mThread_p && mStarted && (mThread_p != QThread::currentThread()) )
{
/* if thread is finished, it means we call this function for the second time so we can leave */
if( !mThread_p->isFinished() )
{
/* we need to call piStop() */
QMetaObject::invokeMethod(this, "stop",
Qt::BlockingQueuedConnection);
/* 3) stop thread */
mThread_p->quit();
if(!mThread_p->wait()) {
qDebug() << "can't stop thread";
}
}
return;
}
/* 2) call piStop in mThread context */
return piStop();
}
bool CANConnection::getBusSettings(int pBusIdx, CANBus& pBus)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
bool ret;
QMetaObject::invokeMethod(this, "getBusSettings",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(int , pBusIdx),
Q_ARG(CANBus& , pBus));
return ret;
}
return piGetBusSettings(pBusIdx, pBus);
}
void CANConnection::setBusSettings(int pBusIdx, CANBus pBus)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
QMetaObject::invokeMethod(this, "setBusSettings",
Qt::BlockingQueuedConnection,
Q_ARG(int, pBusIdx),
Q_ARG(CANBus, pBus));
return;
}
return piSetBusSettings(pBusIdx, pBus);
}
bool CANConnection::sendFrame(const CANFrame& pFrame)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
bool ret;
QMetaObject::invokeMethod(this, "sendFrame",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(const CANFrame&, pFrame));
return ret;
}
return piSendFrame(pFrame);
}
bool CANConnection::sendFrames(const QList<CANFrame>& pFrames)
{
/* make sure we execute in mThread context */
if( mThread_p && (mThread_p != QThread::currentThread()) )
{
bool ret;
QMetaObject::invokeMethod(this, "sendFrames",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(const QList<CANFrame>&, pFrames));
return ret;
}
return piSendFrames(pFrames);
}
int CANConnection::getNumBuses() const{
return mNumBuses;
}
bool CANConnection::isConfigured(int pBusId) {
if( pBusId < 0 || pBusId >= getNumBuses())
return false;
return mBusData[pBusId].mConfigured;
}
void CANConnection::setConfigured(int pBusId, bool pConfigured) {
if( pBusId < 0 || pBusId >= getNumBuses())
return;
mBusData[pBusId].mConfigured = pConfigured;
}
bool CANConnection::getBusConfig(int pBusId, CANBus& pBus) {
if( pBusId < 0 || pBusId >= getNumBuses() || !isConfigured(pBusId))
return false;
qDebug() << "getBusConfig id: " << pBusId;
pBus = mBusData[pBusId].mBus;
return true;
}
void CANConnection::setBusConfig(int pBusId, CANBus& pBus) {
if( pBusId < 0 || pBusId >= getNumBuses())
return;
mBusData[pBusId].mConfigured = true;
mBusData[pBusId].mBus = pBus;
}
QString CANConnection::getPort() {
return mPort;
}
QString CANConnection::getDriver()
{
return mDriver;
}
LFQueue<CANFrame>& CANConnection::getQueue() {
return mQueue;
}
CANCon::type CANConnection::getType() {
return mType;
}
CANCon::status CANConnection::getStatus() {
return (CANCon::status) mStatus.loadRelaxed();
}
void CANConnection::setStatus(CANCon::status pStatus) {
mStatus.storeRelaxed(pStatus);
}
bool CANConnection::isCapSuspended() {
return mIsCapSuspended;
}
void CANConnection::setCapSuspended(bool pIsSuspended) {
mIsCapSuspended = pIsSuspended;
}
void CANConnection::debugInput(QByteArray bytes) {
Q_UNUSED(bytes)
}
bool CANConnection::addTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver)
{
/*
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
bool ret;
QMetaObject::invokeMethod(this, "addTargettedFrame",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(int, pBusId),
Q_ARG(uint32_t , ID),
Q_ARG(uint32_t , mask),
Q_ARG(QObject *, receiver));
return ret;
}
*/
/* sanity checks */
if(pBusId < -1 || pBusId >= getNumBuses())
return false;
qDebug() << "Connection is registering a new targetted frame filter, local bus " << pBusId;
CANFltObserver target;
target.id = ID;
target.mask = mask;
target.observer = receiver;
mBusData[pBusId].mTargettedFrames.append(target);
return true;
}
bool CANConnection::removeTargettedFrame(int pBusId, uint32_t ID, uint32_t mask, QObject *receiver)
{
/*
if( mThread_p && (mThread_p != QThread::currentThread()) ) {
bool ret;
QMetaObject::invokeMethod(this, "removeTargettedFrame",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, ret),
Q_ARG(int, pBusId),
Q_ARG(uint32_t , ID),
Q_ARG(uint32_t , mask),
Q_ARG(QObject *, receiver));
return ret;
}
*/
/* sanity checks */
if(pBusId < -1 || pBusId >= getNumBuses())
return false;
CANFltObserver target;
target.id = ID;
target.mask = mask;
target.observer = receiver;
mBusData[pBusId].mTargettedFrames.removeAll(target);
return true;
}
bool CANConnection::removeAllTargettedFrames(QObject *receiver)
{
for (int i = 0; i < getNumBuses(); i++) {
foreach (const CANFltObserver filt, mBusData[i].mTargettedFrames)
{
if (filt.observer == receiver) mBusData[i].mTargettedFrames.removeOne(filt);
}
}
return true;
}
void CANConnection::checkTargettedFrame(CANFrame &frame)
{
unsigned int maskedID;
//qDebug() << "Got frame with ID " << frame.ID << " on bus " << frame.bus;
if (mBusData.count() == 0) return;
int bus = frame.bus;
if (bus > (mBusData.length() - 1)) bus = mBusData.length() - 1;
if (mBusData[bus].mTargettedFrames.length() == 0) return;
foreach (const CANFltObserver filt, mBusData[frame.bus].mTargettedFrames)
{
//qDebug() << "Checking filter with id " << filt.id << " mask " << filt.mask;
maskedID = frame.frameId() & filt.mask;
if (maskedID == filt.id) {
qDebug() << "In connection object I got a targetted frame. Forwarding it.";
QMetaObject::invokeMethod(filt.observer, "gotTargettedFrame",Qt::QueuedConnection, Q_ARG(CANFrame, frame));
}
}
}
bool CANConnection::piSendFrames(const QList<CANFrame>& pFrames)
{
foreach(const CANFrame& frame, pFrames)
{
if(!piSendFrame(frame))
return false;
}
return true;
}