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: 09a810a2664c
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2af47b1c6a04
Choose a head ref
  • 1 commit
  • 5 files changed
  • 1 contributor

Commits on Sep 2, 2020

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2af47b1 View commit details
Showing with 314 additions and 0 deletions.
  1. +1 −0 scopeprotocols/CMakeLists.txt
  2. +253 −0 scopeprotocols/QSPIDecoder.cpp
  3. +58 −0 scopeprotocols/QSPIDecoder.h
  4. +1 −0 scopeprotocols/scopeprotocols.cpp
  5. +1 −0 scopeprotocols/scopeprotocols.h
1 change: 1 addition & 0 deletions scopeprotocols/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -53,6 +53,7 @@ set(SCOPEPROTOCOLS_SOURCES
ParallelBus.cpp
PeriodMeasurement.cpp
PkPkMeasurement.cpp
QSPIDecoder.cpp
RiseMeasurement.cpp
SPIDecoder.cpp
SubtractFilter.cpp
253 changes: 253 additions & 0 deletions scopeprotocols/QSPIDecoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Implementation of QSPIDecoder
*/

#include "../scopehal/scopehal.h"
#include "QSPIDecoder.h"
#include <algorithm>

using namespace std;

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

QSPIDecoder::QSPIDecoder(string color)
: SPIDecoder(color)
{
//Remove the x1 SPI inputs
m_inputs.clear();
m_signalNames.clear();

CreateInput("clk");
CreateInput("cs#");
CreateInput("dq3");
CreateInput("dq2");
CreateInput("dq1");
CreateInput("dq0");
}

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

string QSPIDecoder::GetProtocolName()
{
return "Quad SPI";
}

bool QSPIDecoder::ValidateChannel(size_t i, StreamDescriptor stream)
{
if(stream.m_channel == NULL)
return false;

if(
(i < 6) &&
(stream.m_channel->GetType() == OscilloscopeChannel::CHANNEL_TYPE_DIGITAL) &&
(stream.m_channel->GetWidth() == 1)
)
{
return true;
}

return false;
}

void QSPIDecoder::SetDefaultName()
{
char hwname[256];
snprintf(hwname, sizeof(hwname), "QSPI(%s, %s, %s, %s)",
GetInputDisplayName(2).c_str(),
GetInputDisplayName(3).c_str(),
GetInputDisplayName(4).c_str(),
GetInputDisplayName(5).c_str()
);
m_hwname = hwname;
m_displayname = m_hwname;
}

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

void QSPIDecoder::Refresh()
{
//Make sure we've got valid inputs
if(!VerifyAllInputsOK())
{
SetData(NULL, 0);
return;
}

//Get the input data
auto clk = GetDigitalInputWaveform(0);
auto csn = GetDigitalInputWaveform(1);
auto data3 = GetDigitalInputWaveform(2);
auto data2 = GetDigitalInputWaveform(3);
auto data1 = GetDigitalInputWaveform(4);
auto data0 = GetDigitalInputWaveform(5);

//Create the capture
auto cap = new SPIWaveform;
cap->m_timescale = clk->m_timescale;
cap->m_startTimestamp = clk->m_startTimestamp;
cap->m_startPicoseconds = clk->m_startPicoseconds;

//TODO: different cpha/cpol modes

//TODO: packets based on CS# pulses

//Loop over the data and look for transactions
//For now, assume equal sample rate

enum
{
STATE_DESELECTED,
STATE_SELECTED_CLKLO,
STATE_SELECTED_CLKHI
} state = STATE_DESELECTED;

bool high_nibble = true;
int64_t bytestart = 0;
uint8_t current_byte = 0;
bool first_byte = false;

size_t len = clk->m_samples.size();
len = min(len, csn->m_samples.size());
len = min(len, data0->m_samples.size());
len = min(len, data1->m_samples.size());
len = min(len, data2->m_samples.size());
len = min(len, data3->m_samples.size());
size_t last_bytelen = 0;
for(size_t i=0; i<len; i++)
{
bool cur_cs = csn->m_samples[i];
bool cur_clk = clk->m_samples[i];
uint8_t cur_data =
(data3->m_samples[i] ? 0x8 : 0) |
(data2->m_samples[i] ? 0x4 : 0) |
(data1->m_samples[i] ? 0x2 : 0) |
(data0->m_samples[i] ? 0x1 : 0);

switch(state)
{
//wait for falling edge of CS#
case STATE_DESELECTED:
if(!cur_cs)
{
state = STATE_SELECTED_CLKLO;
current_byte = 0;
high_nibble = true;
bytestart = clk->m_offsets[i];
first_byte = true;
}
break;

//wait for rising edge of clk
case STATE_SELECTED_CLKLO:
if(cur_clk)
{
state = STATE_SELECTED_CLKHI;

//High nibble
if(high_nibble)
{
//Add a "chip selected" event
if(first_byte)
{
cap->m_offsets.push_back(bytestart);
cap->m_durations.push_back(clk->m_offsets[i] - bytestart);
cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_SELECT, 0));
}

//Generate the byte, then start the next one
else
{
cap->m_offsets.push_back(bytestart);
last_bytelen = clk->m_offsets[i] - bytestart;
cap->m_durations.push_back(last_bytelen);
cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DATA, current_byte));
}

current_byte = (cur_data << 4);
bytestart = clk->m_offsets[i];
first_byte = false;
}

//Low nibble? Save it
else
current_byte |= cur_data;

high_nibble = !high_nibble;
}

//end of packet
//TODO: error if a byte is truncated
else if(cur_cs)
{
//Push the last in-progress byte
cap->m_offsets.push_back(bytestart);
cap->m_durations.push_back(last_bytelen);
cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DATA, current_byte));

bytestart += last_bytelen;
cap->m_offsets.push_back(bytestart);
cap->m_durations.push_back(clk->m_offsets[i] - bytestart);
cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DESELECT, 0));

bytestart = clk->m_offsets[i];
state = STATE_DESELECTED;
}
break;

//wait for falling edge of clk
case STATE_SELECTED_CLKHI:
if(!cur_clk)
state = STATE_SELECTED_CLKLO;

//end of packet
//TODO: error if a byte is truncated
else if(cur_cs)
{
cap->m_offsets.push_back(bytestart);
cap->m_durations.push_back(clk->m_offsets[i] - bytestart);
cap->m_samples.push_back(SPISymbol(SPISymbol::TYPE_DESELECT, 0));

bytestart = clk->m_offsets[i];
state = STATE_DESELECTED;
}

break;
}
}

SetData(cap, 0);
}
58 changes: 58 additions & 0 deletions scopeprotocols/QSPIDecoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/***********************************************************************************************************************
* *
* ANTIKERNEL v0.1 *
* *
* Copyright (c) 2012-2020 Andrew D. Zonenberg *
* All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the *
* following conditions are met: *
* *
* * Redistributions of source code must retain the above copyright notice, this list of conditions, and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other materials provided with the distribution. *
* *
* * Neither the name of the author nor the names of any contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGE. *
* *
***********************************************************************************************************************/

/**
@file
@author Andrew D. Zonenberg
@brief Declaration of QSPIDecoder
*/

#ifndef QSPIDecoder_h
#define QSPIDecoder_h

#include "SPIDecoder.h"

class QSPIDecoder : public SPIDecoder
{
public:
QSPIDecoder(std::string color);

virtual void Refresh();

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

virtual bool ValidateChannel(size_t i, StreamDescriptor stream);

PROTOCOL_DECODER_INITPROC(QSPIDecoder)

protected:
};

#endif
1 change: 1 addition & 0 deletions scopeprotocols/scopeprotocols.cpp
Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@ void ScopeProtocolStaticInit()
AddDecoderClass(ParallelBus);
AddDecoderClass(PeriodMeasurement);
AddDecoderClass(PkPkMeasurement);
AddDecoderClass(QSPIDecoder);
AddDecoderClass(RiseMeasurement);
AddDecoderClass(SPIDecoder);
AddDecoderClass(SubtractFilter);
1 change: 1 addition & 0 deletions scopeprotocols/scopeprotocols.h
Original file line number Diff line number Diff line change
@@ -89,6 +89,7 @@
#include "ParallelBus.h"
#include "PeriodMeasurement.h"
#include "PkPkMeasurement.h"
#include "QSPIDecoder.h"
#include "RiseMeasurement.h"
#include "SPIDecoder.h"
#include "SubtractFilter.h"