Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bb45a1a269d5
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 016ca0174761
Choose a head ref
  • 2 commits
  • 7 files changed
  • 2 contributors

Commits on Dec 28, 2019

  1. Verified

    This commit was signed with the committer’s verified signature.
    mbbx6spp Susan Potter
    Copy the full SHA
    907b3b9 View commit details

Commits on Jan 10, 2020

  1. Merge pull request #86 from Toroid-io/CAN_decoder

    Add an incomplete CAN decoder
    azonenberg authored Jan 10, 2020
    Copy the full SHA
    016ca01 View commit details
309 changes: 309 additions & 0 deletions scopeprotocols/CANDecoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
/**
@file
@author Andrés MANELLI
@brief Implementation of CANDecoder
*/

#include "../scopehal/scopehal.h"
#include "../scopehal/ChannelRenderer.h"
#include "../scopehal/TextRenderer.h"
#include "CANRenderer.h"
#include "CANDecoder.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

CANDecoder::CANDecoder(string color)
: ProtocolDecoder(OscilloscopeChannel::CHANNEL_TYPE_COMPLEX, color, CAT_SERIAL)
{
//Set up channels
m_signalNames.push_back("Diff");
m_channels.push_back(NULL);

m_tq = "Time Quantum [ns]";
m_parameters[m_tq] = ProtocolDecoderParameter(ProtocolDecoderParameter::TYPE_INT);
m_parameters[m_tq].SetIntVal(156);

m_bs1 = "Bit Segment 1 [tq]";
m_parameters[m_bs1] = ProtocolDecoderParameter(ProtocolDecoderParameter::TYPE_INT);
m_parameters[m_bs1].SetIntVal(7);

m_bs2 = "Bit Segment 2 [tq]";
m_parameters[m_bs2] = ProtocolDecoderParameter(ProtocolDecoderParameter::TYPE_INT);
m_parameters[m_bs2].SetIntVal(5);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory methods

bool CANDecoder::NeedsConfig()
{
return true;
}

ChannelRenderer* CANDecoder::CreateRenderer()
{
return new CANRenderer(this);
}

bool CANDecoder::ValidateChannel(size_t i, OscilloscopeChannel* channel)
{
if( (i == 0) && (channel->GetType() == OscilloscopeChannel::CHANNEL_TYPE_DIGITAL) && (channel->GetWidth() == 1) )
return true;
return false;
}

string CANDecoder::GetProtocolName()
{
return "CAN";
}

void CANDecoder::SetDefaultName()
{
char hwname[256];
snprintf(hwname, sizeof(hwname), "CAN(%s)", m_channels[0]->m_displayname.c_str());
m_hwname = hwname;
m_displayname = m_hwname;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Actual decoder logic

void CANDecoder::Refresh()
{
//Get the input data
if( (m_channels[0] == NULL) )
{
SetData(NULL);
return;
}

DigitalCapture* diff = dynamic_cast<DigitalCapture*>(m_channels[0]->GetData());
if( (diff == NULL) )
{
SetData(NULL);
return;
}

//Create the capture
CANCapture* cap = new CANCapture;
cap->m_timescale = diff->m_timescale;
cap->m_startTimestamp = diff->m_startTimestamp;
cap->m_startPicoseconds = diff->m_startPicoseconds;

//Loop over the data and look for transactions
//For now, assume equal sample rate
bool last_diff = true;
bool cur_diff = true;
size_t symbol_start = 0;
size_t bit_start = 0;
CANSymbol::stype current_symbol = CANSymbol::TYPE_IDLE;
uint32_t current_data = 0;
uint8_t bitcount = 0;
uint8_t dlc = 0;
uint8_t stuff = 0;

// Sync_seg + bs1 + bs2
// FIXME
m_nbt = m_parameters[m_tq].GetIntVal() * ( 1 + m_parameters[m_bs1].GetIntVal() + m_parameters[m_bs2].GetIntVal() );

for(size_t i = 0; i < diff->m_samples.size(); i++)
{
if (symbol_start != 0 && current_symbol == CANSymbol::TYPE_SOF &&
((diff->m_samples[i].m_offset - diff->m_samples[bit_start].m_offset + 1) * diff->m_timescale)
<
((2 * m_parameters[m_bs1].GetIntVal() + 1) * m_parameters[m_tq].GetIntVal() * 500))
{
// We wait for the next bit
continue;
} else if (symbol_start != 0 && current_symbol != CANSymbol::TYPE_SOF &&
((diff->m_samples[i].m_offset - diff->m_samples[bit_start].m_offset + 1) * diff->m_timescale) < (m_nbt * 1e3))
{
// We wait for the next bit
continue;
}

cur_diff = diff->m_samples[i].m_sample;
bit_start = i;

if (current_symbol != CANSymbol::TYPE_IDLE)
{
if (stuff == 5)
{
// Ignore bit
stuff = 1;
last_diff = cur_diff;
continue;
} else if (cur_diff == last_diff || stuff == 0) {
stuff++;
} else {
stuff = 1;
}
}

// First bit
if (current_symbol == CANSymbol::TYPE_IDLE && cur_diff && !last_diff)
{
symbol_start = i;
current_symbol = CANSymbol::TYPE_SOF;
stuff = 1;
}
else if (current_symbol == CANSymbol::TYPE_SOF)
{
cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_SOF, NULL, 0)
)
);

current_symbol = CANSymbol::TYPE_SID;
symbol_start = i;
}
else if (current_symbol == CANSymbol::TYPE_SID)
{
current_data <<= 1;
current_data |= (cur_diff)?0:1;
bitcount++;

if (bitcount == 11) // SID
{
cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_SID, (uint8_t*)&current_data, 2)
)
);

bitcount = 0;
current_data = 0;
symbol_start = i;
current_symbol = CANSymbol::TYPE_RTR;
}
}
else if (current_symbol == CANSymbol::TYPE_RTR)
{
current_data |= (cur_diff)?0:1;

cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_RTR, (uint8_t *)&current_data, 1)
)
);

current_data = 0;
symbol_start = i;
current_symbol = CANSymbol::TYPE_IDE;
}
else if (current_symbol == CANSymbol::TYPE_IDE)
{
current_data |= (cur_diff)?0:1;

cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_IDE, (uint8_t *)&current_data, 1)
)
);

current_data = 0;
symbol_start = i;
current_symbol = CANSymbol::TYPE_R0;
}
else if (current_symbol == CANSymbol::TYPE_R0)
{
current_data |= (cur_diff)?0:1;

cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_R0, (uint8_t *)&current_data, 1)
)
);

current_data = 0;
symbol_start = i;
current_symbol = CANSymbol::TYPE_DLC;
}
else if (current_symbol == CANSymbol::TYPE_DLC)
{
bitcount++;
current_data <<= 1;
current_data |= (cur_diff)?0:1;

if (bitcount == 4)
{
cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_DLC, (uint8_t*)&current_data, 1)
)
);

dlc = current_data;
bitcount = 0;
current_data = 0;
symbol_start = i;
current_symbol = CANSymbol::TYPE_DATA;
}
}
else if (current_symbol == CANSymbol::TYPE_DATA)
{
bitcount++;
current_data <<= 1;
current_data |= (cur_diff)?0:1;

if (bitcount == 8)
{
cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_DATA, (uint8_t*)&current_data, 1)
)
);

bitcount = 0;
current_data = 0;
symbol_start = i;
--dlc;
if (0 == dlc)
{
current_symbol = CANSymbol::TYPE_CRC;
}
else
{
current_symbol = CANSymbol::TYPE_DATA;
}
}
}
else if (current_symbol == CANSymbol::TYPE_CRC)
{
bitcount++;
current_data <<= 1;
current_data |= (cur_diff)?0:1;

if (bitcount == 15)
{
cap->m_samples.push_back(CANSample(
diff->m_samples[symbol_start].m_offset,
diff->m_samples[i].m_offset - symbol_start,
CANSymbol(CANSymbol::TYPE_CRC, (uint8_t*)&current_data, 2)
)
);

bitcount = 0;
current_data = 0;
symbol_start = 0;
current_symbol = CANSymbol::TYPE_IDLE;
}
}

//Save old state
last_diff = cur_diff;
}

SetData(cap);
}
73 changes: 73 additions & 0 deletions scopeprotocols/CANDecoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
@file
@author Andrés MANELLI
@brief Declaration of CANDecoder
*/

#ifndef CANDecoder_h
#define CANDecoder_h

#include "../scopehal/ProtocolDecoder.h"

class CANSymbol
{
public:
enum stype
{
TYPE_SOF,
TYPE_SID,
TYPE_RTR,
TYPE_IDE,
TYPE_R0,
TYPE_DLC,
TYPE_DATA,
TYPE_CRC,
TYPE_IDLE
};

CANSymbol(stype t, uint8_t *data, size_t size)
: m_stype(t)
{
for (uint8_t i = 0; i < size; i++)
{
m_data.push_back(data[i]);
}
}

stype m_stype;
std::vector<uint8_t> m_data;

bool operator== (const CANSymbol& s) const
{
return (m_stype == s.m_stype) && (m_data == s.m_data);
}
};

typedef OscilloscopeSample<CANSymbol> CANSample;
typedef CaptureChannel<CANSymbol> CANCapture;

class CANDecoder : public ProtocolDecoder
{
public:
CANDecoder(std::string color);

virtual void Refresh();
virtual ChannelRenderer* CreateRenderer();
virtual bool NeedsConfig();

static std::string GetProtocolName();
virtual void SetDefaultName();

virtual bool ValidateChannel(size_t i, OscilloscopeChannel* channel);

PROTOCOL_DECODER_INITPROC(CANDecoder)

protected:
std::string m_tq;
std::string m_bs1, m_bs2;

// Nominal Bit Time, in ns
unsigned int m_nbt;
};

#endif
Loading