#include "proto.h" /**************************************************************************/ typedef struct { int searchdata; int glitchfilter; } I2Sparameters; typedef struct { protoTime time; int sck; int sd; int ws; } I2STraceEntryRaw; typedef struct { protoTime time; int data; int sdata; int bits; int lr; } I2STraceEntry; /************************************************************************** I2S Protocol Level 1 - parse i2s anti glitch filter **************************************************************************/ /* The Stage one processing filters out glitches which are < 500ns. Basically a signal transition is only valid if the signal stays constant for 500ns after the transition; otherwise the transition is ignored */ static protoSizeT PROTOAPI PROTO_Process(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { I2Sparameters *parameters; int i, j, h; I2STraceEntryRaw *stageOneArray; /* Pointer to array which will contain the output records */ protoTime traceTime; /* timestamp of raw trace data record */ int traceChannel[3]; /* Bit values of SCL and SDA */ int sckOld, lastSckEntry, sckEdge; protoTime lastSckTime, delta, tolerance; stageOneArray = (I2STraceEntryRaw *) arrayOut; /* type cast to the used output record type */ parameters = (I2Sparameters *) localdata; PROTO_ReadTrace(context, -1, &traceTime, traceChannel); tolerance = PROTO_TIME_DIVINT(PROTO_TIME_MULTINT(PROTO_TIME_ONEMICROSECOND, parameters->glitchfilter), 1000); sckOld = traceChannel[0]; lastSckTime = traceTime; stageOneArray[0].time = traceTime; stageOneArray[0].sck = sckOld; stageOneArray[0].sd = traceChannel[1]; stageOneArray[0].ws = traceChannel[2]; lastSckEntry = 0; sckEdge = 0; h = 1; for (i = 1; i < arrayInSize; i++) { if (h >= arrayOutSize) return PROTO_PROCESS_OUTOFMEMORY; if ((i & 0xfff) == 0) if (PROTO_Cancel(context)) return PROTO_PROCESS_CANCEL; PROTO_ReadTrace(context, -1, &traceTime, traceChannel); stageOneArray[h].time = traceTime; stageOneArray[h].sck = traceChannel[0]; stageOneArray[h].sd = traceChannel[1]; stageOneArray[h].ws = traceChannel[2]; if (traceChannel[0] != sckOld && !sckEdge) { /* * this case only happens at the first edge, or after a glitch was suppressed. */ lastSckTime = traceTime; lastSckEntry = h; sckEdge = 1; } if (traceChannel[0] == sckOld && sckEdge) { /* * This means we scanned over something like _____-____ or -----_----, Now we have to check if the signal was stable long enough */ delta = PROTO_TIME_SUB(traceTime, lastSckTime); if (PROTO_TIME_ISSMALLER(delta, tolerance)) { /* If the signal wasn't stable long enough we supress the glitch */ sckEdge = 0; for (j = lastSckEntry; j < h; j++) stageOneArray[j].sck = sckOld; } else { /* Signal was stable enough, so now we are at the next edge. */ sckOld = stageOneArray[lastSckEntry].sck; lastSckTime = traceTime; lastSckEntry = h; } } /* * The following will suppress entries on which nothing happened. This reduces memory usage. */ if (stageOneArray[h].sck != stageOneArray[h - 1].sck) h++; } return h; } /***********/ static void PROTOAPI PROTO_Display(protoContext context, protoPtr pdata, protoPtr localdata) { I2STraceEntryRaw *entry; entry=(I2STraceEntryRaw *)pdata; /* Cast to correct type */ PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, "SCK : "); PROTO_Control(context, PROTO_ATTRIBUTE_NORM); PROTO_Printf(context, "%d ", entry->sck); PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, "SD : "); PROTO_Control(context, PROTO_ATTRIBUTE_NORM); PROTO_Printf(context, "%d ", entry->sd); PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, "WS : "); PROTO_Control(context, PROTO_ATTRIBUTE_NORM); PROTO_Printf(context, "%d", entry->ws); } /************************************************************************** I2S Protocol Level 2 - parse i2s data **************************************************************************/ static protoSizeT PROTOAPI PROTO_Process2(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { I2STraceEntry *I2Stracebuffer; I2STraceEntryRaw *stageOneArray; int data, bits; int indexin, indexout; int sckref, wsref, state; protoTime time; I2Stracebuffer = (I2STraceEntry *) arrayOut; stageOneArray = (I2STraceEntryRaw *) arrayIn; /* Data from Stage One */ if (arrayInSize<2) return 0; indexout = 0; data = 0; bits = 0; state = 0; time = stageOneArray[0].time; sckref = stageOneArray[0].sck; wsref = stageOneArray[0].ws; arrayOutSize-=2; for (indexin = 1; indexin < arrayInSize; indexin++) { if (indexout > arrayOutSize) return PROTO_PROCESS_OUTOFMEMORY; if ((indexin & 0xfff) == 0) if (PROTO_Cancel(context)) return PROTO_PROCESS_CANCEL; if (sckref == 0) { if (stageOneArray[indexin].sck != 0) { data <<= 1; data |= (stageOneArray[indexin].sd & 1); bits++; } if (stageOneArray[indexin].ws != wsref) { if (state) { I2Stracebuffer[indexout].time = time; I2Stracebuffer[indexout].data = data; I2Stracebuffer[indexout].sdata = (data << (32 - bits)) >> (32 - bits); I2Stracebuffer[indexout].bits = bits; I2Stracebuffer[indexout].lr = wsref; indexout++; } data = 0; bits = 0; wsref = stageOneArray[indexin].ws; state = 1; } } else { if (stageOneArray[indexin].sck == 0) { if (state == 1) { time = stageOneArray[indexin].time; state = 2; } } } sckref = stageOneArray[indexin].sck; } return indexout; } /***********/ static void PROTOAPI PROTO_Display2(protoContext context, protoPtr pdata, protoPtr localdata) { I2STraceEntry *data = (I2STraceEntry *) pdata; if (data->lr) { PROTO_Control(context, PROTO_ATTRIBUTE_COLOR0 + 2); PROTO_Puts(context, " R "); } else { PROTO_Control(context, PROTO_ATTRIBUTE_COLOR0 + 1); PROTO_Puts(context, " L "); } if (data->bits > 32) { PROTO_Printf(context, "ERROR %d bits", data->bits); } else { PROTO_Printf(context, "%08x %2d:%11d", data->data, data->bits, data->sdata); } } /***********/ static void PROTOAPI PROTO_Export(protoContext context, protoPtr pdata, protoPtr localdata) { I2STraceEntry *data = (I2STraceEntry *) pdata; PROTO_Printf(context, "%s 0x%08x", ((data->lr) ? "R" : "L"), data->data); } /***********/ static int PROTOAPI PROTO_Find(protoContext context, protoPtr pdata, protoPtr localdata) { I2Sparameters *parameters; I2STraceEntry *data; parameters = (I2Sparameters *) localdata; data = (I2STraceEntry *) pdata; return (data->data == parameters->searchdata); } static int PROTO_Draw(protoContext context, protoPtr pdata, protoPtr localdata, int * presult) { I2STraceEntry *data = (I2STraceEntry *) pdata; if (data->bits > 32) { return 0; } if (data->lr) { presult[1] = data->sdata; return 1 << 1; } else { presult[0] = data->sdata; return 1 << 0; } } static int PROTOAPI PROTO_Share(protoContext context, protoPtr sharedata, protoPtr localdata) { I2Sparameters *localParameters; I2Sparameters *shareParameters; localParameters = (I2Sparameters *)localdata; shareParameters = (I2Sparameters *)sharedata; if (localParameters->glitchfilter != shareParameters->glitchfilter) { return 0; } return 1; } /************************************************************************** I2S Protocol Parser **************************************************************************/ int PROTOAPI PROTO_Init(protoContext context, int command) { I2Sparameters *parameters; int searchdata; int glitchfilter; if (PROTO_RequestVersion(context, 2) != PROTO_OK) { PROTO_Puts(context, "Requires newer trace32 version"); return PROTO_FAIL; } parameters = (I2Sparameters *) PROTO_Alloc(context, sizeof(I2Sparameters)); PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); if (command == PROTO_COMMAND_FIND) { PROTO_Parse(context, (protoPtr) & searchdata, "", PROTO_PARSE_INTEGER); parameters->searchdata = searchdata; } glitchfilter = 500; /* default 500ns */ PROTO_Parse(context, (protoPtr) & glitchfilter, "", PROTO_PARSE_INTEGER | PROTO_PARSE_OPTIONAL); parameters->glitchfilter = glitchfilter; PROTO_RegisterProcessCallback(context, PROTO_Process, (protoPtr) parameters, sizeof(I2STraceEntryRaw), 1); PROTO_RegisterDisplayCallback(context, PROTO_Display, (protoPtr) NULL, 1); PROTO_RegisterProcessCallback(context, PROTO_Process2, (protoPtr) NULL, sizeof(I2STraceEntry), 2); PROTO_RegisterDisplayCallback(context, PROTO_Display2, (protoPtr) NULL, 2); PROTO_RegisterExportCallback(context, PROTO_Export, (protoPtr) NULL, 2); PROTO_RegisterFindCallback(context, PROTO_Find, (protoPtr) parameters, 2); PROTO_RegisterDrawCallback(context, PROTO_Draw, (protoPtr) parameters, 2, 2, -0x80000000, 0x7fffffff); PROTO_RegisterShareCallback(context, PROTO_Share, (protoPtr) NULL, 0); PROTO_SetDefaultLevel(context, 2); return PROTO_OK; }