Last active
May 7, 2016 01:42
-
-
Save GeorgeHahn/d588b2890c9d488310faba83fe55dea7 to your computer and use it in GitHub Desktop.
Enhanced SPI decoder for OLSFront
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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