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-apps
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 04173e764f29
Choose a base ref
...
head repository: ngscopeclient/scopehal-apps
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 5ff7cfd22d8d
Choose a head ref
  • 2 commits
  • 1 file changed
  • 2 contributors

Commits on Mar 24, 2021

  1. Improve the usbcsv example

    This program was originally created by azonenberg to assist in
    decoding USB snippets in a headless state. The main intent of this
    program is to export only packets sent from the client device
    to the host computer. It is a bit messy, but I tried to make
    it clear how the logic works.
    
    The output format is as follows:
    [starting line in csv] [ending line in csv] [DATA 1/0] [hex bits] | [SETUP request code]
    
    This is supposed to make it easier to extract those client packets
    from the CSV. I briefly considered using CPython to transform it
    into a format that can easily be used in feature extraction libraries,
    but that is more work than is necessary.
    
    This is not a perfect example, as I only really capture the data
    packets and the NAK packets. There are others in the USB spec,
    so feel free to implement them.
    
    Another thing to note is that there is a `step` variable in the
    ProcessWaveform function that represents the number of femtoseconds
    between lines in the csv. This was done because my logic analyser
    does not sample at that high of a rate, and I wanted to translate
    from femtoseconds that the decoder used back into a format that
    fit my original CSV. So be warned that you will need to change this!
    
    Big thank you to azonenberg for helping out with the original example.
    Codysseus committed Mar 24, 2021
    Copy the full SHA
    090559f View commit details

Commits on Apr 12, 2021

  1. Merge pull request #310 from Codysseus/master

    Improve the usbcsv example
    azonenberg authored Apr 12, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    5ff7cfd View commit details
Showing with 196 additions and 126 deletions.
  1. +196 −126 src/examples/usbcsv/main.cpp
322 changes: 196 additions & 126 deletions src/examples/usbcsv/main.cpp
Original file line number Diff line number Diff line change
@@ -41,6 +41,15 @@ using namespace std;

bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDecoder* pdecode);
USB2PacketDecoder* CreateFilterGraph(Oscilloscope* scope);
string SymbolToString(USB2PacketSymbol sym);
int64_t Round(int64_t number, int64_t step);

enum USBState {
SETUP,
IN,
WAIT,
};


int main(int argc, char* argv[])
{
@@ -101,8 +110,11 @@ USB2PacketDecoder* CreateFilterGraph(Oscilloscope* scope)
{
//Decode the PMA layer (differential voltages to J/K/SE0/SE1 line states)
auto pma = Filter::CreateFilter(USB2PMADecoder::GetProtocolName());
pma->SetInput(0, StreamDescriptor(scope->GetChannel(0)));
pma->SetInput(1, StreamDescriptor(scope->GetChannel(1)));
pma->GetParameter("Speed").SetIntVal(USB2PMADecoder::SPEED_LOW);

//As you can see the channels are switched. This is an historical mistake.
pma->SetInput(0, StreamDescriptor(scope->GetChannel(1)));
pma->SetInput(1, StreamDescriptor(scope->GetChannel(0)));

//Decode the PCS layer (line states to data bytes and sync/end events)
auto pcs = Filter::CreateFilter(USB2PCSDecoder::GetProtocolName());
@@ -115,11 +127,26 @@ USB2PacketDecoder* CreateFilterGraph(Oscilloscope* scope)
return dynamic_cast<USB2PacketDecoder*>(pack);
}

//I created this because my LA only samples at a certain rate
//and femtoseconds is too much precision.
int64_t Round(int64_t number, int64_t step)
{
int64_t leftover = number % step;
int64_t base = number - leftover;

if (leftover > step / 2)
{
base += step;
}
return base;
}


bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDecoder* pdecode)
{
//Import the waveform
LogNotice("Loading waveform \"%s\"\n", fname.c_str());
LogIndenter li;
//LogNotice("Loading waveform \"%s\"\n", fname.c_str());
//LogIndenter li;

if(!scope->LoadCSV(fname))
{
@@ -139,157 +166,200 @@ bool ProcessWaveform(MockOscilloscope* scope, const string& fname, USB2PacketDec

Unit fs(Unit::UNIT_FS);

//This number is the number of femtoseconds between each sample
//in USB captures I have taken.
int64_t step = 8e7;

//Print the protocol analyzer data
LogNotice("Printing packets\n");
{
LogIndenter li2;
auto packets = pdecode->GetPackets();
size_t len = packets.size();
for(size_t i=0; i<len; i++)
size_t len = waveform->m_samples.size();
USBState state = USBState::SETUP;
std::vector<size_t> elts;
std::vector<size_t> setup;
bool collect = false;

for(size_t i=0; i<len;)
{
auto pack = packets[i];

LogNotice("[%11s] len=%s type=%6s dev=%1s endp=%1s len=%3s info=%s\n",
fs.PrettyPrint(pack->m_offset).c_str(),
fs.PrettyPrint(pack->m_len).c_str(),
pack->m_headers["Type"].c_str(),
pack->m_headers["Device"].c_str(),
pack->m_headers["Endpoint"].c_str(),
pack->m_headers["Length"].c_str(),
pack->m_headers["Details"].c_str()
);
// scope->m_channels[0]->m_streamData[0]->m_offsets.size()

for (; i<len; i++)
{
string sym = SymbolToString(waveform->m_samples[i]);
if (sym == "SETUP")
{
state = USBState::SETUP;
setup.clear();
}
else if (state == USBState::SETUP && sym == "Data")
{
setup.push_back(i);
}
else if (sym == "IN")
{
state = USBState::IN;
}
else if (state == USBState::IN && (sym[0] == 'D' || sym == "NAK")) // All the packets are: DATA0, DATA1, Data
{
elts.push_back(i);
collect = true;
}
else if (collect)
{
elts.push_back(i);
state = USBState::WAIT;
collect = false;
break;
}

}

if (elts.size() == 0)
{
LogError("No packets found.\n");
return false;
}

auto first = elts[0];
auto last = elts[elts.size()-1];

int64_t left = Round(waveform->m_offsets[first] * waveform->m_timescale, step)/step;
int64_t right = Round(waveform->m_offsets[last] * waveform->m_timescale, step)/step;
string pid = SymbolToString(waveform->m_samples[first]);

LogNotice("%lu %lu %s ", left, right, pid.c_str());

for (auto loc : elts)
{
auto sym = waveform->m_samples[loc];
LogNotice("%02x ", sym.m_data);
}

LogNotice("| ");
for (auto loc : setup)
{
auto sym = waveform->m_samples[loc];
LogNotice("%02x ", sym.m_data);
}

LogNotice("\n");

elts.clear();
}
}

//Print the symbol level view of the data
LogNotice("Printing symbols\n");
{
LogIndenter li2;
return true;
}

size_t len = waveform->m_samples.size();
for(size_t i=0; i<len; i++)
string SymbolToString(USB2PacketSymbol sym)
{
string type = "";
switch(sym.m_type)
{
int64_t timestamp = waveform->m_offsets[i] * waveform->m_timescale;
int64_t duration = waveform->m_durations[i] * waveform->m_timescale;
auto sym = waveform->m_samples[i];
case USB2PacketSymbol::TYPE_PID:
switch(sym.m_data & 0x0f)
{
case USB2PacketSymbol::PID_RESERVED:
type += "(reserved)";
break;

string type;
switch(sym.m_type)
{
case USB2PacketSymbol::TYPE_PID:
type = "PID ";
switch(sym.m_data & 0x0f)
{
case USB2PacketSymbol::PID_RESERVED:
type += "(reserved)";
break;

case USB2PacketSymbol::PID_OUT:
type += "OUT";
break;

case USB2PacketSymbol::PID_ACK:
type += "ACK";
break;

case USB2PacketSymbol::PID_DATA0:
type += "DATA0";
break;

case USB2PacketSymbol::PID_PING:
type += "PING";
break;

case USB2PacketSymbol::PID_SOF:
type += "SOF";
break;

case USB2PacketSymbol::PID_NYET:
type += "NYET";
break;

case USB2PacketSymbol::PID_DATA2:
type += "DATA2";
break;

case USB2PacketSymbol::PID_SPLIT:
type += "SPLIT";
break;

case USB2PacketSymbol::PID_IN:
type += "IN";
break;

case USB2PacketSymbol::PID_NAK:
type += "NAK";
break;

case USB2PacketSymbol::PID_DATA1:
type += "DATA1";
break;

case USB2PacketSymbol::PID_PRE_ERR:
type += "PRE_ERR";
break;

case USB2PacketSymbol::PID_SETUP:
type += "SETUP";
break;

case USB2PacketSymbol::PID_STALL:
type += "STALL";
break;

case USB2PacketSymbol::PID_MDATA:
type += "MDATA";
break;
}
case USB2PacketSymbol::PID_OUT:
type += "OUT";
break;

case USB2PacketSymbol::TYPE_ADDR:
type = "Addr";
case USB2PacketSymbol::PID_ACK:
type += "ACK";
break;

case USB2PacketSymbol::TYPE_ENDP:
type = "ENDP";
case USB2PacketSymbol::PID_DATA0:
type += "DATA0";
break;

case USB2PacketSymbol::TYPE_CRC5_GOOD:
type = "CRC5 (good)";
case USB2PacketSymbol::PID_PING:
type += "PING";
break;

case USB2PacketSymbol::TYPE_CRC5_BAD:
type = "CRC5 (bad)";
case USB2PacketSymbol::PID_SOF:
type += "SOF";
break;

case USB2PacketSymbol::TYPE_CRC16_GOOD:
type = "CRC16 (good)";
case USB2PacketSymbol::PID_NYET:
type += "NYET";
break;

case USB2PacketSymbol::TYPE_CRC16_BAD:
type = "CRC16 (bad)";
case USB2PacketSymbol::PID_DATA2:
type += "DATA2";
break;

case USB2PacketSymbol::TYPE_NFRAME:
type = "NFRAME";
case USB2PacketSymbol::PID_SPLIT:
type += "SPLIT";
break;

case USB2PacketSymbol::TYPE_DATA:
type = "Data";
case USB2PacketSymbol::PID_IN:
type += "IN";
break;

case USB2PacketSymbol::TYPE_ERROR:
type = "ERROR";
case USB2PacketSymbol::PID_NAK:
type += "NAK";
break;
}

LogNotice("[%11s] len=%11s %-15s %02x\n",
fs.PrettyPrint(timestamp).c_str(),
fs.PrettyPrint(duration).c_str(),
type.c_str(),
sym.m_data);
case USB2PacketSymbol::PID_DATA1:
type += "DATA1";
break;

case USB2PacketSymbol::PID_PRE_ERR:
type += "PRE_ERR";
break;

case USB2PacketSymbol::PID_SETUP:
type += "SETUP";
break;

case USB2PacketSymbol::PID_STALL:
type += "STALL";
break;

case USB2PacketSymbol::PID_MDATA:
type += "MDATA";
break;
}
break;

case USB2PacketSymbol::TYPE_ADDR:
type = "Addr";
break;

case USB2PacketSymbol::TYPE_ENDP:
type = "ENDP";
break;

case USB2PacketSymbol::TYPE_CRC5_GOOD:
type = "CRC5(good)";
break;

case USB2PacketSymbol::TYPE_CRC5_BAD:
type = "CRC5(bad)";
break;

case USB2PacketSymbol::TYPE_CRC16_GOOD:
type = "CRC16(good)";
break;

case USB2PacketSymbol::TYPE_CRC16_BAD:
type = "CRC16(bad)";
break;

case USB2PacketSymbol::TYPE_NFRAME:
type = "NFRAME";
break;

case USB2PacketSymbol::TYPE_DATA:
type = "Data";
break;

case USB2PacketSymbol::TYPE_ERROR:
type = "ERROR";
break;
}
}

return true;
return type;
}