Skip to content

Instantly share code, notes, and snippets.

@GeorgeHahn
Last active May 7, 2016 01:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GeorgeHahn/d588b2890c9d488310faba83fe55dea7 to your computer and use it in GitHub Desktop.
Save GeorgeHahn/d588b2890c9d488310faba83fe55dea7 to your computer and use it in GitHub Desktop.
Enhanced SPI decoder for OLSFront
include('util/obj_struct.js');
//////////////////////////////////////////////////////////////////////////////////////////////////
// Parser Info
//////////////////////////////////////////////////////////////////////////////////////////////////
function info()
{
parser.name = 'SPI';
parser.descr = 'SPI Parser';
parser.ver_maj = 0;
parser.ver_min = 5;
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Set configuration
// -----------------
// This function defines what needs to be asked of the user
//////////////////////////////////////////////////////////////////////////////////////////////////
function config()
{
return {
'channels': ['/CS', 'SCK', 'MOSI', 'MISO'],
'options':
{
'Mode':
{
'type': 'map',
'values':
{
'Mode 0': 0,
'Mode 1': 1,
'Mode 2': 2,
'Mode 3': 3,
},
'default': 0
},
'Bits':
{
'type': 'list',
'values': [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
'default': 8
},
'Order':
{
'type': 'map',
'values': {'LSB' : 0, 'MSB': 1},
'default': 1
},
'Format':
{
'type': 'map',
'values': {'Hex' : 'hex', 'Dec': 'dec', 'Bin': 'bin'},
'default': 'hex'
},
'Show ASCII':
{
'type': 'check',
'default': 0
},
'Invert CS':
{
'type': 'check',
'default': 0
},
},
};
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// Check Configuration
// -------------------
// This function will validate the user input, in the config dialog
//////////////////////////////////////////////////////////////////////////////////////////////////
function checkConfig(config)
{
if (config.channels['/CS'] < 0)
{
alert('Invalid Chip Select channel');
return false;
}
if (config.channels.SCK < 0)
{
alert('Invalid SCK channel');
return false;
}
if (config.channels.MOSI < 0 && config.channels.MISO < 0)
{
alert('We need at least one valid data channel, MOSI and/or MISO');
return false;
}
return true;
}
// No format
function noFmt(b)
{
return b;
}
// TODO: Handle non-8 bit values (how?)
function hex2ascii(hexx) {
return String.fromCharCode(hexx);
}
function run(config)
{
var cs = config.channels['/CS'];
var sck = config.channels.SCK;
var mosi = config.channels.MOSI;
var miso = config.channels.MISO;
var bits = parseInt(config.options.Bits);
var nrBytes = Math.ceil(bits / 8);
var msb = parseInt(config.options.Order);
var mode = parseInt(config.options.Mode);
var csOn = parseInt(config.options['Invert CS']);
var csOff = csOn ? 0 : 1;
var ascii = parseInt(config.options['Show ASCII']);
var fmtOpt = config.options.Format;
var fmt = noFmt;
switch (fmtOpt)
{
case 'hex':
fmt = function(b, pre) {return ( pre ? '0x' : '') + hex(b, nrBytes); };
break;
case 'bin':
fmt = function(b) { return bin(b, bits); };
break;
}
if(ascii) {
var oldfmt = fmt;
fmt = function(b, pre)
{
return oldfmt(b, pre) + ' - ' + '\'' + hex2ascii(b) + '\'';
}
}
// not really used right now
var cpol = (mode & 2) >> 1; // polarity
var cpha = mode & 1; // 0 = leading / 1 = trailing edge
var samp_edge = 1; // sample on rising edge
var set_edge = 0; // setup on falling edge
if (mode == 1 || mode == 2)
{
samp_edge = 0; // falling
set_edge = 1; // rising
}
// Go to the first sample that has CS on low
var sample = Samples.first(cs, csOn);
var last = sample.next(cs, csOff); // The last sample we care about is when the CS goes back up
// When the polarity of the clock is the same with sampling edge, it means we have to wait for a change
// in the clock, after CS gets low, otherwise, we would end up sampling the line right after CS goes low.
// Which is why we'll use sample.next() in one case and sample.first() in another.
// Reference: http://eenoob.com/home/post?id=4
var sampleFirst = cpol != samp_edge;
while (sample.id < last.id)
{
// For the duration of the CS, let's sample some data
var bitIndex = 0;
var outData = 0;
var inData = 0;
sample = sampleFirst ? sample.first(sck, samp_edge) : sample.next(sck, samp_edge); // get the first sampling edge of the sck
startSample = sample;
while (sample.id < last.id)
{
if (msb == 1)
{
if (mosi >= 0)
outData |= sample.level(mosi) << ((bits - 1) - bitIndex);
if (miso >= 0)
inData |= sample.level(miso) << ((bits - 1) - bitIndex);
}
else
{
if (mosi >= 0)
outData |= sample.level(mosi) << bitIndex;
if (miso >= 0)
inData |= sample.level(miso) << bitIndex;
}
++bitIndex;
if (bitIndex == bits)
{
// We have data!
var clockEnd = sample.next(sck, set_edge);
// If it goes beyond CS, make it so it doesn't
if (clockEnd.id > last.id)
clockEnd = last;
if (mosi >= 0)
addData(mosi, startSample.id, clockEnd.id, fmt(outData), fmt(outData, true));
if (miso >= 0)
addData(miso, startSample.id, clockEnd.id, fmt(inData), fmt(inData, true));
bitIndex = 0;
outData = 0;
inData = 0;
sample = sample.next(sck, samp_edge);
startSample = sample;
}
else
sample = sample.next(sck, samp_edge);
}
// It means we were left with some unprocessed bits after the chip select got released,
// this is a protocol error
if (bitIndex > 0)
{
var csEnd = startSample.next(cs, csOff);
if (mosi >= 0)
addData(mosi, startSample.id, csEnd.id, fmt(outData), fmt(outData, true), true);
if (miso >= 0)
addData(miso, startSample.id, csEnd.id, fmt(inData), fmt(inData, true), true);
}
// Go to the next low CS
sample = last.next(cs, csOn);
last = sample.next(cs, csOff);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment