/* * Usage: .PROTOcol. * * Implemented s: * * - List * - Chart * - STATistic * - EXPORT * * Options can be given in any order: * * NominalFrequency * DataFrequency * * Specify the baud rate; this sets up a sample point at 70 % of a * period; use these commands if you do not know or care about the exact * timing parameters of the CAN bus. * * NominalTiming * DataTiming * * Specify the exact timing parameters as defined in the CAN * specification. For , specify the effective time of a time quantum * derived from the base clock and the baud rate prescaler. Prefer to use * this family of options, at least for CAN-FD buses. * * Filter * * Add a filter to decode fixed-format frames. For every data frame with * matching type (i. e. base or extended) and ID, extract the specified * data. The number of filters is limited only by the maximum length of a * PRACTICE command. The name is only used to identify the filter in the * List and EXPORT commands. * * DRAWRange * * Specify the range for the DRAW subcommand. If not given, this option * is automatically chosen to encompass the full range of all defined * filters. Note that the range of the DRAW command is limited to either * signed or unsigned 32-bit integers. * * Level * * Specify the default display level for the List command (can always be * changed with the local More/Less buttons) or the level for the EXPORT * command. * * Argument definitions: * * : * * Frequency, e. g. 1.0MHz * * : * * Time, e. g. 0.1us * * , , , , , , , * : * * Integer * * : * * string * * : * * Base | Extended * * : * * Byte | Word | Long | Quad | TByte | PByte | HByte | SByte * * : * * LE | BE * * : * * Decimal | DecimalU | Hex * * : * * PCS | BITS | FIELDS | FRAMES | FILTERS * * The nominal timing always has to be defined, either by the NominalFrequency * or the NominalTiming option. For most commands, this is the only required * option. For the DRAW command, you also have to specify at least one filter. */ #include "proto.h" #ifndef PROTO_NO_STD_INCLUDES # include # include # include # include # include #endif enum { CANFD_CRC_POLY_15 = 0x4599, CANFD_CRC_POLY_17 = 0x1685B, CANFD_CRC_POLY_21 = 0x102899 }; struct canfdChartEntry { uint32_t id; char name[9]; }; enum { CANFD_ID_MASK = (1 << 29) - 1, CANFD_ID_EXTENDED = 1 << 29, CANFD_ID_INVALID = 1 << 30 }; struct canfdChartList { int size; struct canfdChartEntry entries[1024]; struct canfdChartList *next; }; enum canfdFormat { CANFD_FORMAT_DECIMAL, CANFD_FORMAT_DECIMAL_U, CANFD_FORMAT_HEXADECIMAL }; struct canfdFilter { int index; uint32_t id; /* ID to filter for */ int offset; /* Index of the first byte */ int size; /* Number of bytes */ bool be; /* Whether to use the wrong endianness */ enum canfdFormat format; /* For List window, also determines signedness */ struct canfdFilter *next; char name[1]; /* Name to be displayed in the stage 5 list window (extends past end of struct) */ }; struct canfdTiming { protoTime tq; int propSeg; int phaseSeg1; int phaseSeg2; int sjw; }; enum canfdLevel { CANFD_LEVEL_RAW = 0, CANFD_LEVEL_PCS = 1, CANFD_LEVEL_BITS = 2, CANFD_LEVEL_FIELDS = 3, CANFD_LEVEL_FRAMES = 4, CANFD_LEVEL_FILTERS = 5 }; static char const *const canfdLevelStr[] = { "RAW", "PCS", "BITS", "FIELDS", "FRAMES", "FILTERS" }; struct canfdLocalData { struct canfdTiming nom; struct canfdTiming dat; protoTime timeIntegration; struct canfdChartList *statList; struct canfdFilter *filter; int filterCount; int64_t drawMin; int64_t drawMax; }; enum canfdTraceEntryPhase { CANFD_TRACE_ENTRY_SYNC, CANFD_TRACE_ENTRY_PROP, CANFD_TRACE_ENTRY_PHASE_1, CANFD_TRACE_ENTRY_PHASE_2, CANFD_TRACE_ENTRY_INTERFRAME }; static char const *const canfdTraceEntryPhaseStr[] = { "Sync_Seg", "Prop_Seg", "Phase_Seg1", "Phase_Seg2", "Interframe" }; enum canfdTraceEntryBitType { CANFD_TRACE_ENTRY_BIT_TYPE_INTERMISSION, CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_DYNAMIC, CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_FIXED, CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_ERROR, CANFD_TRACE_ENTRY_BIT_TYPE_SOF, CANFD_TRACE_ENTRY_BIT_TYPE_ID_BASE, CANFD_TRACE_ENTRY_BIT_TYPE_ID_EXTENDED, CANFD_TRACE_ENTRY_BIT_TYPE_SRR, CANFD_TRACE_ENTRY_BIT_TYPE_RRS, CANFD_TRACE_ENTRY_BIT_TYPE_RTR, CANFD_TRACE_ENTRY_BIT_TYPE_IDE, CANFD_TRACE_ENTRY_BIT_TYPE_FDF, CANFD_TRACE_ENTRY_BIT_TYPE_RES, CANFD_TRACE_ENTRY_BIT_TYPE_R0, CANFD_TRACE_ENTRY_BIT_TYPE_BRS, CANFD_TRACE_ENTRY_BIT_TYPE_ESI, CANFD_TRACE_ENTRY_BIT_TYPE_DLC, CANFD_TRACE_ENTRY_BIT_TYPE_DATA, CANFD_TRACE_ENTRY_BIT_TYPE_STC, CANFD_TRACE_ENTRY_BIT_TYPE_CRC, CANFD_TRACE_ENTRY_BIT_TYPE_CRC_DEL, CANFD_TRACE_ENTRY_BIT_TYPE_ACK, CANFD_TRACE_ENTRY_BIT_TYPE_ACK_DEL, CANFD_TRACE_ENTRY_BIT_TYPE_EOF }; enum canfdPcsBitrate { CANFD_PCS_BITRATE_REINTEGRATE, CANFD_PCS_BITRATE_INTERFRAME, CANFD_PCS_BITRATE_NOMINAL, CANFD_PCS_BITRATE_DATA }; /* Trace entry for the lower stages of processing; all the processing really * happens in stage 1; states 2 and 3 just filter for display purposes. */ struct canfdTraceEntryRaw { protoTime time; /* phase info; this is always valid */ enum canfdTraceEntryPhase phase; enum canfdPcsBitrate phaseBitrate; int phaseLength; /* ID for Chart and STATistic commands */ uint32_t chartId; /* bit info; this is only valid if phase == CANFD_TRACE_ENTRY_PHASE_2 */ enum canfdTraceEntryBitType bitType; int bitIndex; bool bitValue; /* field info; this only valid if phase == CANFD_TRACE_ENTRY_PHASE_2 && bitIndex == 0 */ bool fieldComplete; /* false if this field might have missing bits due to stuff errors */ uint32_t fieldAux; /* extra info, only for display purposes */ uint32_t fieldValue; }; enum canfdFrameState { CANFD_FRAME_STATE_INTERFRAME, CANFD_FRAME_STATE_ID_BASE, CANFD_FRAME_STATE_ID_EXTENDED, CANFD_FRAME_STATE_R0, CANFD_FRAME_STATE_RTR, CANFD_FRAME_STATE_IDE, CANFD_FRAME_STATE_FDF, CANFD_FRAME_STATE_DLC, CANFD_FRAME_STATE_RES, CANFD_FRAME_STATE_BRS, CANFD_FRAME_STATE_ESI, CANFD_FRAME_STATE_DATA, CANFD_FRAME_STATE_STC, CANFD_FRAME_STATE_CRC, CANFD_FRAME_STATE_CRC_DEL, CANFD_FRAME_STATE_ACK, CANFD_FRAME_STATE_ACK_DEL, CANFD_FRAME_STATE_EOF }; enum canfdStuffMode { CANFD_STUFF_MODE_NONE, CANFD_STUFF_MODE_DYNAMIC, CANFD_STUFF_MODE_FIXED }; struct canfdTraceStateRaw { /* params from CANFD_Process */ protoContext context; struct canfdTraceEntryRaw *out; protoSizeT outSize; struct canfdLocalData *local; protoSizeT outPos; protoSizeT inPos; struct canfdTraceEntryRaw *entryOut; struct canfdTraceEntryRaw *entrySof; struct canfdTraceEntryRaw *entryBit; struct canfdTraceEntryRaw *entryRtr; struct canfdTraceEntryRaw *entryField; /* line input state */ protoTime time; bool line; protoTime nextTime; bool nextLine; /* phase state */ enum canfdPcsBitrate pcsBitrate; /* frame state */ enum canfdFrameState frameState; int frameFieldCount; int frameDataLength; int frameDataCount; int frameCrcLength; int frameStuffCount; bool frameStuffValue; enum canfdStuffMode frameStuffMode; bool frameRtr; bool frameIde; bool frameFdf; bool frameBrs; uint32_t frameCrc15; uint32_t frameCrc17; uint32_t frameCrc21; uint32_t frameStc; uint32_t frameCrcEna; uint32_t frameId; }; enum canfdFrameError { CANFD_FRAME_ERROR_NONE, /* Frame was received correctly */ CANFD_FRAME_ERROR_NACK, /* Ack bit was '1' */ CANFD_FRAME_ERROR_PASSIVE, /* Passive error flag detected */ CANFD_FRAME_ERROR_ACTIVE, /* Active error flag detected */ CANFD_FRAME_ERROR_FD_RES, /* res bit in FD frame was '1' */ CANFD_FRAME_ERROR_CRC, /* CRC or STC mismatch */ CANFD_FRAME_ERROR_CRC_DEL, /* CRC delimiter was '0' */ CANFD_FRAME_ERROR_ACK_DEL, /* FD delimiter was '0' */ CANFD_FRAME_ERROR_EOF, /* '0' bit during end-of-frame */ CANFD_FRAME_ERROR_INTERNAL /* the internal sequence of canfdTraceEntryRaw was inconsistent, should never happen */ }; /* Level 4 entry; each entry represents a complete frame. */ struct canfdTraceEntryFrame { protoTime time; enum canfdFrameError error; uint32_t id; bool fdf; bool brs; /* always false if !fdf */ bool esi; /* always false if !fdf */ bool rtr; /* always false if fdf */ int length; uint8_t data[64]; }; struct canfdTraceStateFrame { /* params from CANFD_Process */ protoContext context; struct canfdTraceEntryRaw *in; struct canfdTraceEntryFrame *out; protoSizeT outSize; protoSizeT inSize; struct canfdLocalData *local; protoSizeT outPos; protoSizeT inPos; struct canfdTraceEntryFrame *entryOut; struct canfdTraceEntryRaw *entryIn; }; /* Level 5 entry; each entry represents the result of a user-defined filter. */ struct canfdTraceEntryFilter { protoTime time; struct canfdFilter *filter; int64_t value; }; enum canfdParseVerb { CANFD_PARSE_VERB_NOMINAL_FREQUENCY, CANFD_PARSE_VERB_NOMINAL_TIMING, CANFD_PARSE_VERB_DATA_FREQUENCY, CANFD_PARSE_VERB_DATA_TIMING, CANFD_PARSE_VERB_FILTER, CANFD_PARSE_VERB_DRAW_RANGE, CANFD_PARSE_VERB_LEVEL, CANFD_PARSE_NUM_VERBS }; static char const *const canfdParseVerbStr[CANFD_PARSE_NUM_VERBS] = { "NominalFrequency", "NominalTiming", "DataFrequency", "DataTiming", "Filter", "DRAWRange", "Level" }; static int CANFD_DecodeDlc(int dlc, bool fdf, bool rtr) { if (rtr) { return 0; } else if (dlc <= 8) { return dlc; } else if (!fdf) { return 8; } switch (dlc) { case 9: return 12; case 10: return 16; case 11: return 20; case 12: return 24; case 13: return 32; case 14: return 48; case 15: return 64; } return 0; } static uint32_t CANFD_CrcStep(uint32_t sr, bool data, uint32_t poly, int length) { if (data != ((sr & 1 << (length - 1)) != 0)) { return (sr << 1 & ((1 << length) - 1)) ^ poly; } else { return sr << 1 & ((1 << length) - 1); } } static protoSizeT CANFD_Out(struct canfdTraceStateRaw *state) { if (state->outPos + 1 >= state->outSize) { return PROTO_PROCESS_OUTOFMEMORY; } else { ++state->outPos; ++state->entryOut; state->entryOut->chartId = CANFD_ID_INVALID; return PROTO_OK; } } static protoSizeT CANFD_InterframeOut(struct canfdTraceStateRaw *state) { state->entryOut->time = state->time; state->entryOut->phase = CANFD_TRACE_ENTRY_INTERFRAME; state->entryOut->phaseLength = 0; state->entryOut->phaseBitrate = CANFD_PCS_BITRATE_INTERFRAME; state->entryOut->chartId = CANFD_ID_INVALID; return CANFD_Out(state); } /* Advance the next time to the next record */ static protoSizeT CANFD_AdvanceNext(struct canfdTraceStateRaw *state) { int traceData; protoSizeT traceResult; do { /* This can return the special value 2 for invalid records, e. g. those * containing only timestamps. */ traceResult = PROTO_ReadTrace(state->context, -1, &state->nextTime, &traceData); if (traceResult < 0) { return traceResult; } ++state->inPos; if (state->inPos % 0x10000 == 0) { traceResult = PROTO_Cancel(state->context); if (traceResult < 0) { return traceResult; } } } while (traceData == 2); state->nextLine = traceData != 0; return PROTO_OK; } /* Advance the current time to the next record */ static protoSizeT CANFD_AdvanceNow(struct canfdTraceStateRaw *state) { protoSizeT result; if (state->time == state->nextTime) { result = CANFD_AdvanceNext(state); if (result < 0) { return result; } } state->time = state->nextTime; state->line = state->nextLine; return PROTO_OK; } /* Advance the next time until there is either an edge or the given time is reached */ static protoSizeT CANFD_AdvanceNextUntil(struct canfdTraceStateRaw *state, protoTime time) { protoSizeT result; while (state->nextTime < time && state->nextLine == state->line) { result = CANFD_AdvanceNext(state); if (result < 0) { return result; } } return PROTO_OK; } /* Advance the current time to a given time, ignoring any edges */ static protoSizeT CANFD_AdvanceNowUntil(struct canfdTraceStateRaw *state, protoTime time) { protoSizeT result; for (;;) { if (state->nextTime > time) { state->time = time; return PROTO_OK; } if (state->time == state->nextTime) { result = CANFD_AdvanceNext(state); } else { result = CANFD_AdvanceNow(state); } if (result < 0) { return result; } } } /* Look for a long '1' period; after this function, we are at the start of an SOF bit. */ static protoSizeT CANFD_Integrate(struct canfdTraceStateRaw *state) { protoSizeT result; for (;;) { if (!state->line) { /* the current state is '0', so we first need to find a '1' */ result = CANFD_AdvanceNow(state); if (result < 0) { return result; } continue; } if (state->nextLine) { /* the next state is '1', we need to find a '1' -> '0' transition */ result = CANFD_AdvanceNext(state); if (result < 0) { return result; } continue; } if (state->nextTime - state->time >= state->local->timeIntegration) { /* we found the edge! */ result = CANFD_InterframeOut(state); if (result < 0) { return result; } return CANFD_AdvanceNow(state); } else { /* too short, try again... */ result = CANFD_AdvanceNow(state); if (result < 0) { return result; } } } } static void CANFD_ProcessBit(struct canfdTraceStateRaw *state, bool bit) { state->entryBit->bitIndex = state->frameFieldCount; state->entryBit->bitValue = bit; if (state->frameStuffMode != CANFD_STUFF_MODE_NONE) { if (state->frameStuffCount == 5) { if (bit == state->frameStuffValue) { state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_ERROR; state->entryBit->bitIndex = 0; state->entryBit->fieldValue = 0; state->entryBit->fieldAux = 0; state->frameState = CANFD_FRAME_STATE_INTERFRAME; state->frameStuffMode = CANFD_STUFF_MODE_NONE; state->frameCrcEna = false; state->frameFieldCount = 0; state->frameId = CANFD_ID_INVALID; state->pcsBitrate = CANFD_PCS_BITRATE_REINTEGRATE; return; } state->entryBit->bitType = state->frameStuffMode == CANFD_STUFF_MODE_DYNAMIC ? CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_DYNAMIC : CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_FIXED; state->frameStuffValue = bit; state->frameStuffCount = 1; if (state->frameStuffMode == CANFD_STUFF_MODE_DYNAMIC) { state->frameStc = (state->frameStc + 1) % 8; if (state->frameCrcEna) { state->frameCrc17 = CANFD_CrcStep(state->frameCrc17, bit, CANFD_CRC_POLY_17, 17); state->frameCrc21 = CANFD_CrcStep(state->frameCrc21, bit, CANFD_CRC_POLY_21, 21); } } return; } else if (state->frameStuffMode == CANFD_STUFF_MODE_DYNAMIC && bit != state->frameStuffValue) { state->frameStuffCount = 1; } else { ++state->frameStuffCount; } } state->frameStuffValue = bit; if (state->frameCrcEna) { state->frameCrc15 = CANFD_CrcStep(state->frameCrc15, bit, CANFD_CRC_POLY_15, 15); state->frameCrc17 = CANFD_CrcStep(state->frameCrc17, bit, CANFD_CRC_POLY_17, 17); state->frameCrc21 = CANFD_CrcStep(state->frameCrc21, bit, CANFD_CRC_POLY_21, 21); } if (state->frameFieldCount == 0) { state->entryField = state->entryBit; state->entryField->fieldComplete = false; state->entryField->fieldValue = 0; } else { state->entryField->fieldValue <<= 1; } state->entryField->fieldValue |= bit ? 1 : 0; state->entryField->fieldAux = 0; switch (state->frameState) { case CANFD_FRAME_STATE_INTERFRAME: if (bit) { state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_INTERMISSION; ++state->frameFieldCount; } else { state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_SOF; state->frameState = CANFD_FRAME_STATE_ID_BASE; state->frameFieldCount = 0; state->frameDataCount = 0; state->frameDataLength = 0; state->frameStuffCount = 1; state->frameStuffValue = false; state->frameStuffMode = CANFD_STUFF_MODE_DYNAMIC; state->frameCrc15 = 0; state->frameCrc17 = CANFD_CRC_POLY_17; state->frameCrc21 = CANFD_CRC_POLY_21; state->frameStc = 0; state->frameCrcEna = true; state->frameIde = false; } break; case CANFD_FRAME_STATE_ID_BASE: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_ID_BASE; ++state->frameFieldCount; if (state->frameFieldCount == 11) { state->frameState = CANFD_FRAME_STATE_RTR; state->frameFieldCount = 0; state->frameId = state->entryField->fieldValue; } break; case CANFD_FRAME_STATE_RTR: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_RTR; state->frameRtr = bit; if (!state->frameIde) { state->frameState = CANFD_FRAME_STATE_IDE; } else { /* previous "RTR" bit was actually a SRR */ state->entryRtr->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_SRR; state->frameState = CANFD_FRAME_STATE_FDF; } state->entryRtr = state->entryBit; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_IDE: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_IDE; state->frameIde = bit; if (!bit) { state->frameState = CANFD_FRAME_STATE_FDF; } else { state->frameState = CANFD_FRAME_STATE_ID_EXTENDED; } state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_ID_EXTENDED: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_ID_EXTENDED; ++state->frameFieldCount; if (state->frameFieldCount == 18) { state->frameState = CANFD_FRAME_STATE_RTR; state->frameFieldCount = 0; state->frameId = CANFD_ID_EXTENDED | state->frameId << 18 | state->entryField->fieldValue; } break; case CANFD_FRAME_STATE_R0: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_R0; state->frameState = CANFD_FRAME_STATE_DLC; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_FDF: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_FDF; state->frameFdf = bit; if (!bit) { if (!state->frameIde) { /* Classical base frame */ state->frameState = CANFD_FRAME_STATE_DLC; } else { /* Classical extended frame */ state->frameState = CANFD_FRAME_STATE_R0; } } else { /* FD frame */ state->frameState = CANFD_FRAME_STATE_RES; state->frameRtr = false; /* previous "RTR" bit was actually a RRS */ state->entryRtr->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_RRS; } state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_RES: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_RES; state->frameState = CANFD_FRAME_STATE_BRS; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_BRS: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_BRS; state->frameState = CANFD_FRAME_STATE_ESI; state->frameFieldCount = 0; state->frameBrs = bit; if (bit) { state->pcsBitrate = CANFD_PCS_BITRATE_DATA; } break; case CANFD_FRAME_STATE_ESI: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_ESI; state->frameState = CANFD_FRAME_STATE_DLC; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_DLC: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_DLC; ++state->frameFieldCount; if (state->frameFieldCount == 4) { state->frameDataLength = CANFD_DecodeDlc(state->entryField->fieldValue, state->frameFdf, state->frameRtr); state->entryField->fieldAux = CANFD_DecodeDlc(state->entryField->fieldValue, state->frameFdf, false); state->frameFieldCount = 0; if (!state->frameFdf) { state->frameCrcLength = 15; } else if (state->frameDataLength <= 16) { state->frameCrcLength = 17; } else { state->frameCrcLength = 21; } if (state->frameDataLength != 0) { state->frameState = CANFD_FRAME_STATE_DATA; } else if (!state->frameFdf) { state->frameCrcEna = false; state->frameState = CANFD_FRAME_STATE_CRC; } else { state->frameStuffMode = CANFD_STUFF_MODE_FIXED; state->frameStuffCount = 5; state->frameState = CANFD_FRAME_STATE_STC; } } break; case CANFD_FRAME_STATE_DATA: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_DATA; state->entryField->fieldAux = state->frameDataCount; ++state->frameFieldCount; if (state->frameFieldCount == 8) { ++state->frameDataCount; if (state->frameDataCount >= state->frameDataLength) { if (!state->frameFdf) { state->frameCrcEna = false; state->frameState = CANFD_FRAME_STATE_CRC; } else { state->frameStuffMode = CANFD_STUFF_MODE_FIXED; state->frameStuffCount = 5; state->frameState = CANFD_FRAME_STATE_STC; } } state->frameFieldCount = 0; } break; case CANFD_FRAME_STATE_STC: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_STC; state->entryField->fieldAux = state->frameStc << 1 ^ state->frameStc; ++state->frameFieldCount; if (state->frameFieldCount == 4) { state->frameCrcEna = false; state->frameState = CANFD_FRAME_STATE_CRC; state->frameFieldCount = 0; } break; case CANFD_FRAME_STATE_CRC: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_CRC; if (!state->frameFdf) { state->entryField->fieldAux = (uint32_t)0 << 30 | state->frameCrc15; } else if (state->frameDataLength <= 16) { state->entryField->fieldAux = (uint32_t)1 << 30 | state->frameCrc17; } else { state->entryField->fieldAux = (uint32_t)2 << 30 | state->frameCrc21; } ++state->frameFieldCount; if (state->frameFieldCount == state->frameCrcLength) { state->frameState = CANFD_FRAME_STATE_CRC_DEL; state->frameFieldCount = 0; } break; case CANFD_FRAME_STATE_CRC_DEL: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_CRC_DEL; state->frameState = CANFD_FRAME_STATE_ACK; state->pcsBitrate = CANFD_PCS_BITRATE_NOMINAL; state->frameFieldCount = 0; state->frameStuffMode = CANFD_STUFF_MODE_NONE; break; case CANFD_FRAME_STATE_ACK: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_ACK; state->frameState = CANFD_FRAME_STATE_ACK_DEL; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_ACK_DEL: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_ACK_DEL; state->frameState = CANFD_FRAME_STATE_EOF; state->frameFieldCount = 0; break; case CANFD_FRAME_STATE_EOF: state->entryBit->bitType = CANFD_TRACE_ENTRY_BIT_TYPE_EOF; ++state->frameFieldCount; if (state->frameFieldCount == 7) { state->pcsBitrate = CANFD_PCS_BITRATE_INTERFRAME; state->frameState = CANFD_FRAME_STATE_INTERFRAME; state->frameFieldCount = 0; } break; } if (state->frameFieldCount == 0) { state->entryField->fieldComplete = true; } } static protoSizeT CANFD_ProcessPhase(struct canfdTraceStateRaw *state, enum canfdTraceEntryPhase type, protoTime tq, int length) { protoSizeT result; state->entryOut->time = state->time; state->entryOut->phase = type; state->entryOut->phaseBitrate = state->pcsBitrate; state->entryOut->phaseLength = length; if (type != CANFD_TRACE_ENTRY_PROP || length != 0) { result = CANFD_Out(state); if (result < 0) { return result; } } result = CANFD_AdvanceNowUntil(state, state->time + length * tq); if (result < 0) { return result; } return PROTO_OK; } static protoSizeT CANFD_ProcessPhases(struct canfdTraceStateRaw *state) { struct canfdTraceEntryRaw *entry; protoSizeT result; struct canfdTiming const *timing; int phaseSeg1; int phaseSeg2; int nextEdge; int phaseError; timing = &state->local->nom; phaseSeg1 = timing->phaseSeg1; phaseSeg2 = timing->phaseSeg2; for (;;) { if (state->pcsBitrate == CANFD_PCS_BITRATE_REINTEGRATE) { result = CANFD_Integrate(state); if (result < 0) { return result; } state->pcsBitrate = CANFD_PCS_BITRATE_INTERFRAME; } if (state->pcsBitrate == CANFD_PCS_BITRATE_INTERFRAME) { while (state->line) { result = CANFD_AdvanceNow(state); if (result < 0) { return result; } } phaseSeg1 = timing->phaseSeg1; state->pcsBitrate = CANFD_PCS_BITRATE_NOMINAL; state->entrySof = state->entryOut; } result = CANFD_ProcessPhase(state, CANFD_TRACE_ENTRY_SYNC, timing->tq, 1); if (result < 0) { return result; } result = CANFD_ProcessPhase(state, CANFD_TRACE_ENTRY_PROP, timing->tq, timing->propSeg); if (result < 0) { return result; } result = CANFD_ProcessPhase(state, CANFD_TRACE_ENTRY_PHASE_1, timing->tq, phaseSeg1); if (result < 0) { return result; } state->entryBit = state->entryOut; CANFD_ProcessBit(state, state->line); if (state->pcsBitrate == CANFD_PCS_BITRATE_DATA) { timing = &state->local->dat; } else { timing = &state->local->nom; } phaseSeg1 = timing->phaseSeg1; phaseSeg2 = timing->phaseSeg2; if (state->line) { protoTime bitTime; bitTime = timing->tq * (1 + timing->propSeg + phaseSeg1 + phaseSeg2); /* check for a '1' -> '0' transition for resynchronization */ result = CANFD_AdvanceNextUntil(state, state->time + bitTime); if (result < 0) { return result; } if (state->nextTime - state->time < bitTime) { nextEdge = (int)((state->nextTime - state->time + timing->tq - 1) / timing->tq); phaseError = nextEdge - phaseSeg2 - 1; if (phaseError > timing->sjw) { phaseError = timing->sjw; } else if (phaseError < -timing->sjw) { phaseError = -timing->sjw; } if (phaseError > 0) { phaseSeg1 += phaseError; } else { phaseSeg2 += phaseError; } } } result = CANFD_ProcessPhase(state, CANFD_TRACE_ENTRY_PHASE_2, timing->tq, phaseSeg2); if (result < 0) { return result; } if (state->pcsBitrate == CANFD_PCS_BITRATE_INTERFRAME) { for (entry = state->entrySof; entry != state->entryOut; ++entry) { entry->chartId = state->frameId; } result = CANFD_InterframeOut(state); if (result < 0) { return result; } } } } static protoSizeT CANFD_ProcessMain(struct canfdTraceStateRaw *state) { protoSizeT result; /* read first sample */ result = CANFD_AdvanceNext(state); if (result < 0) { return result; } state->time = state->nextTime; state->line = state->nextLine; result = CANFD_ProcessPhases(state); if (result < 0) { return result; } return PROTO_OK; } static protoSizeT PROTOAPI CANFD_Process1(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { protoSizeT result; struct canfdTraceStateRaw state; if (arrayOutSize <= 1) { return PROTO_PROCESS_OUTOFMEMORY; } state.context = context; state.out = (struct canfdTraceEntryRaw *)arrayOut; state.outSize = arrayOutSize; state.local = (struct canfdLocalData *)localdata; state.outPos = 0; state.inPos = 0; state.entryOut = &state.out[0]; state.entrySof = NULL; state.entryBit = NULL; state.entryRtr = NULL; state.entryField = NULL; state.pcsBitrate = CANFD_PCS_BITRATE_REINTEGRATE; state.frameState = CANFD_FRAME_STATE_INTERFRAME; state.frameFieldCount = 0; state.frameDataCount = 0; state.frameStuffCount = 0; state.frameStuffValue = 0; state.frameStuffMode = CANFD_STUFF_MODE_NONE; state.frameId = CANFD_ID_INVALID; result = CANFD_ProcessMain(&state); if (result >= 0 || result == PROTO_PROCESS_ENDOFTRACE) { return state.outPos; } else { return result; } } static protoSizeT PROTOAPI CANFD_Process2(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { struct canfdTraceEntryRaw *entryIn; struct canfdTraceEntryRaw *entryOut; protoSizeT posIn; protoSizeT posOut; int cancel; entryIn = (struct canfdTraceEntryRaw *)arrayIn; entryOut = (struct canfdTraceEntryRaw *)arrayOut; posIn = 0; posOut = 0; while (posIn < arrayInSize) { if (posIn % 0x10000 == 0) { cancel = PROTO_Cancel(context); if (cancel != 0) { return PROTO_PROCESS_CANCEL; } } if (entryIn[posIn].phase == CANFD_TRACE_ENTRY_PHASE_2) { if (posOut >= arrayOutSize) { return PROTO_PROCESS_OUTOFMEMORY; } entryOut[posOut] = entryIn[posIn]; ++posOut; } ++posIn; } return posOut; } static protoSizeT PROTOAPI CANFD_Process3(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { struct canfdTraceEntryRaw *entryIn; struct canfdTraceEntryRaw *entryOut; protoSizeT posIn; protoSizeT posOut; int cancel; entryIn = (struct canfdTraceEntryRaw *)arrayIn; entryOut = (struct canfdTraceEntryRaw *)arrayOut; posIn = 0; posOut = 0; while (posIn < arrayInSize) { if (posIn % 0x10000 == 0) { cancel = PROTO_Cancel(context); if (cancel != 0) { return PROTO_PROCESS_CANCEL; } } if (entryIn[posIn].bitIndex == 0 && entryIn[posIn].bitType != CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_DYNAMIC && entryIn[posIn].bitType != CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_FIXED) { if (posOut >= arrayOutSize) { return PROTO_PROCESS_OUTOFMEMORY; } entryOut[posOut] = entryIn[posIn]; ++posOut; } ++posIn; } return posOut; } static protoSizeT CANFD_ProcessFrameIn(struct canfdTraceStateFrame *state) { int cancel; if (state->inPos >= state->inSize) { return PROTO_PROCESS_ENDOFTRACE; } else { if (state->inPos % 0x10000 == 0) { cancel = PROTO_Cancel(state->context); if (cancel != 0) { return PROTO_PROCESS_CANCEL; } } state->entryIn = &state->in[state->inPos]; ++state->inPos; return PROTO_OK; } } static protoSizeT CANFD_ProcessFrameOut(struct canfdTraceStateFrame *state) { if (state->outPos + 1 >= state->outSize) { return PROTO_PROCESS_OUTOFMEMORY; } else { ++state->entryOut; ++state->outPos; return PROTO_OK; } } static protoSizeT CANFD_ProcessFrameInExpect(struct canfdTraceStateFrame *state, enum canfdTraceEntryBitType type, bool *errorRet) { protoSizeT result; enum canfdTraceEntryBitType reducedType; result = CANFD_ProcessFrameIn(state); if (result <= 0) { *errorRet = true; return result; } switch (state->entryIn->bitType) { case CANFD_TRACE_ENTRY_BIT_TYPE_SRR: case CANFD_TRACE_ENTRY_BIT_TYPE_RRS: case CANFD_TRACE_ENTRY_BIT_TYPE_RTR: reducedType = CANFD_TRACE_ENTRY_BIT_TYPE_RTR; break; case CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_ERROR: *errorRet = true; if (state->entryIn->bitValue) { state->entryOut->error = CANFD_FRAME_ERROR_PASSIVE; } else { state->entryOut->error = CANFD_FRAME_ERROR_ACTIVE; } return PROTO_OK; default: reducedType = state->entryIn->bitType; break; } if (reducedType != type) { *errorRet = true; state->entryOut->error = CANFD_FRAME_ERROR_INTERNAL; return PROTO_OK; } *errorRet = false; return PROTO_OK; } static protoSizeT CANFD_ProcessFrameSingle(struct canfdTraceStateFrame *state) { protoSizeT result; bool error; bool ide; int i; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_ID_BASE, &error); if (error) { return result; } state->entryOut->id = state->entryIn->fieldValue; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_RTR, &error); if (error) { return result; } state->entryOut->rtr = state->entryIn->fieldValue != 0 ? true : false; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_IDE, &error); if (error) { return result; } ide = state->entryIn->fieldValue != 0 ? true : false; if (!ide) { /* base frame */ result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_FDF, &error); if (error) { return result; } state->entryOut->fdf = state->entryIn->fieldValue != 0 ? true : false; } else { /* extended frame */ result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_ID_EXTENDED, &error); if (error) { return result; } state->entryOut->id = CANFD_ID_EXTENDED | state->entryOut->id << 18 | state->entryIn->fieldValue; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_RTR, &error); if (error) { return result; } state->entryOut->rtr = state->entryIn->fieldValue != 0 ? true : false; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_FDF, &error); if (error) { return result; } state->entryOut->fdf = state->entryIn->fieldValue != 0 ? true : false; if (!state->entryOut->fdf) { /* classical frame */ result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_R0, &error); if (error) { return result; } } } if (state->entryOut->fdf) { /* FD frame, either classical or extended (doesn't matter anymore at this point) */ result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_RES, &error); if (error) { return result; } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_BRS, &error); if (error) { return result; } state->entryOut->brs = state->entryIn->fieldValue != 0 ? true : false; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_ESI, &error); if (error) { return result; } state->entryOut->esi = state->entryIn->fieldValue != 0 ? true : false; state->entryOut->rtr = false; } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_DLC, &error); if (error) { return result; } state->entryOut->length = CANFD_DecodeDlc(state->entryIn->fieldValue, state->entryOut->fdf, false); if (!state->entryOut->rtr) { for (i = 0; i < state->entryOut->length; ++i) { result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_DATA, &error); if (error) { return result; } state->entryOut->data[i] = (uint8_t)state->entryIn->fieldValue; } } if (state->entryOut->fdf) { result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_STC, &error); if (error) { return result; } } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_CRC, &error); if (error) { return result; } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_CRC_DEL, &error); if (error) { return result; } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_ACK, &error); if (error) { return result; } state->entryOut->error = state->entryIn->fieldValue == 0 ? CANFD_FRAME_ERROR_NONE : CANFD_FRAME_ERROR_NACK; result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_ACK_DEL, &error); if (error) { return result; } result = CANFD_ProcessFrameInExpect(state, CANFD_TRACE_ENTRY_BIT_TYPE_EOF, &error); if (error) { return result; } return PROTO_OK; } static protoSizeT CANFD_ProcessFrameMain(struct canfdTraceStateFrame *state) { protoSizeT result; bool internalError; internalError = false; for (;;) { result = CANFD_ProcessFrameIn(state); if (result <= 0) { return result; } if (state->entryIn->bitType == CANFD_TRACE_ENTRY_BIT_TYPE_INTERMISSION) { continue; } if (internalError && state->entryIn->bitType != CANFD_TRACE_ENTRY_BIT_TYPE_SOF) { continue; } memset(state->entryOut, 0x00, sizeof(*state->entryOut)); state->entryOut->time = state->entryIn->time; if (state->entryIn->bitType != CANFD_TRACE_ENTRY_BIT_TYPE_SOF) { state->entryOut->error = CANFD_FRAME_ERROR_INTERNAL; } else { result = CANFD_ProcessFrameSingle(state); if (result <= 0) { return result; } } internalError = state->entryOut->error == CANFD_FRAME_ERROR_INTERNAL; result = CANFD_ProcessFrameOut(state); if (result <= 0) { return result; } } } static protoSizeT PROTOAPI CANFD_Process4(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { protoSizeT result; struct canfdTraceStateFrame state; if (arrayOutSize <= 1) { return PROTO_PROCESS_OUTOFMEMORY; } state.context = context; state.out = (struct canfdTraceEntryFrame *)arrayOut; state.in = (struct canfdTraceEntryRaw *)arrayIn; state.outSize = arrayOutSize; state.inSize = arrayInSize; state.local = (struct canfdLocalData *)localdata; state.outPos = 0; state.inPos = 0; state.entryOut = &state.out[0]; state.entryIn = NULL; result = CANFD_ProcessFrameMain(&state); if (result >= 0 || result == PROTO_PROCESS_ENDOFTRACE) { return state.outPos; } else { return result; } } static int64_t CANFD_ExtractData(uint8_t const *data, int size, bool be, bool isSigned) { uint64_t value; int pos; int i; pos = be ? size : -1; value = 0; for (i = 0; i < size; ++i) { pos += be ? -1 : 1; value |= (uint64_t)data[pos] << (8 * i); } if (size == 8) { if ((data[pos] & 1 << 7) != 0) { return (int64_t)(value - ((uint64_t)1 << 63)) + INT64_MIN; } else { return (int64_t)value; } } if ((data[pos] & 1 << 7) != 0 && isSigned) { return (int64_t)(value - ((uint64_t)1 << (8 * size - 1))) - ((int64_t)1 << (8 * size - 1)); } else { return (int64_t)value; } } static bool CANFD_ApplyFilter(struct canfdTraceEntryFrame *entry, struct canfdFilter *filter, int64_t *result) { if (entry->rtr) { return false; } if (filter->offset + filter->size > entry->length) { return false; } if (entry->id != filter->id) { return false; } *result = CANFD_ExtractData(&entry->data[filter->offset], filter->size, filter->be, filter->format == CANFD_FORMAT_DECIMAL); return true; } static protoSizeT PROTOAPI CANFD_Process5(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr localdata) { struct canfdLocalData *local; struct canfdTraceEntryFrame *entryIn; struct canfdTraceEntryFilter *entryOut; protoSizeT posIn; protoSizeT posOut; struct canfdFilter *filter; bool match; int64_t value; local = (struct canfdLocalData *)localdata; entryIn = (struct canfdTraceEntryFrame *)arrayIn; entryOut = (struct canfdTraceEntryFilter *)arrayOut; posIn = 0; posOut = 0; while (posIn < arrayInSize) { for (filter = local->filter; filter != NULL; filter = filter->next) { match = CANFD_ApplyFilter(&entryIn[posIn], filter, &value); if (match) { if (posOut >= arrayOutSize) { return PROTO_PROCESS_OUTOFMEMORY; } entryOut[posOut].time = entryIn[posIn].time; entryOut[posOut].filter = filter; entryOut[posOut].value = value; ++posOut; } } ++posIn; } return posOut; } static void PROTOAPI CANFD_Display1(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryRaw *entry; entry = (struct canfdTraceEntryRaw *)pdata; PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL1); PROTO_Control(context, PROTO_CONTROL_INDENT); if (entry->phase != CANFD_TRACE_ENTRY_INTERFRAME) { PROTO_Printf( context, "%s (%d %s quanta)", canfdTraceEntryPhaseStr[entry->phase], entry->phaseLength, entry->phaseBitrate == CANFD_PCS_BITRATE_DATA ? "data" : "nominal" ); } else { PROTO_Puts(context, "\005\005\005 Interframe Space "); PROTO_Control(context, PROTO_CONTROL_LINETILLEND); } } static void PROTOAPI CANFD_Display2(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryRaw *entry; entry = (struct canfdTraceEntryRaw *)pdata; switch (entry->bitType) { case CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_DYNAMIC: PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Printf(context, "'%c' Stuff Bit", entry->bitValue ? '1' : '0'); break; case CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_FIXED: PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Printf(context, "'%c' Fixed Stuff Bit", entry->bitValue ? '1' : '0'); break; case CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_ERROR: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "'%c' Stuff Error or %s Error Flag", entry->bitValue ? '1' : '0', entry->bitValue ? "Passive" : "Active"); break; default: PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL2); PROTO_Printf(context, "'%c' Normal Bit", entry->bitValue ? '1' : '0'); break; } } static void CANFD_Display3Prefix(protoContext context, int len, char const *name, struct canfdTraceEntryRaw *entry) { char str[18]; int i; sprintf(str, "%016" PRIX32 " ", entry->fieldValue); for (i = len + 1; i <= 6; ++i) { str[16 - i] = ' '; } PROTO_Control(context, PROTO_ATTRIBUTE_NORM); PROTO_Control(context, PROTO_CONTROL_INDENT); PROTO_Puts(context, &str[16 - 6]); if (!entry->fieldComplete) { PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Printf(context, "%s (incomplete)", name); } else { PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); PROTO_Puts(context, name); } } static void CANFD_Display3ReservedBitNonstandard(protoContext context, char const *name, bool expectedValue, struct canfdTraceEntryRaw *entry) { CANFD_Display3Prefix(context, 1, name, entry); if (!entry->fieldComplete) { return; } if (expectedValue != (entry->fieldValue != 0)) { PROTO_Control(context, PROTO_ATTRIBUTE_BOLD); PROTO_Printf(context, " -> non-standard, transmitter should have sent '%c'", expectedValue ? '1' : '0'); } } static void CANFD_Display3ReservedBitError(protoContext context, char const *name, bool expectedValue, struct canfdTraceEntryRaw *entry) { CANFD_Display3Prefix(context, 1, name, entry); if (!entry->fieldComplete) { return; } if (expectedValue != (entry->fieldValue != 0)) { PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, " -> ERROR, bit must be '%c'", expectedValue ? '1' : '0'); } } static void PROTOAPI CANFD_Display3(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryRaw *entry; entry = (struct canfdTraceEntryRaw *)pdata; switch (entry->bitType) { case CANFD_TRACE_ENTRY_BIT_TYPE_STUFF_ERROR: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Control(context, PROTO_CONTROL_INDENT); PROTO_Printf(context, " Stuff Error or %s Error Flag", entry->bitValue ? "Passive" : "Active"); break; case CANFD_TRACE_ENTRY_BIT_TYPE_SOF: PROTO_Control(context, PROTO_CONTROL_INDENT); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); PROTO_Puts(context, "\005\005\005\005"); PROTO_Control(context, PROTO_ATTRIBUTE_NORM); PROTO_Puts(context, " 0 "); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); PROTO_Puts(context, "\005\005\005 Start of Frame "); PROTO_Control(context, PROTO_CONTROL_LINETILLEND); break; case CANFD_TRACE_ENTRY_BIT_TYPE_ID_BASE: CANFD_Display3Prefix(context, 3, "ID11", entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_ID_EXTENDED: CANFD_Display3Prefix(context, 5, "ID18", entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_SRR: CANFD_Display3ReservedBitNonstandard(context, "SRR", true, entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_RRS: CANFD_Display3ReservedBitNonstandard(context, "RRS", false, entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_RTR: CANFD_Display3Prefix(context, 1, "RTR", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %s Frame", entry->fieldValue != 0 ? "Remote" : "Data"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_IDE: CANFD_Display3Prefix(context, 1, "IDE", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %s Frame", entry->fieldValue != 0 ? "Extended" : "Base"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_FDF: CANFD_Display3Prefix(context, 1, "FDF", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %s Frame", entry->fieldValue != 0 ? "FD" : "Classical"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_RES: CANFD_Display3ReservedBitError(context, "res", false, entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_R0: CANFD_Display3ReservedBitNonstandard(context, "r0", false, entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_BRS: CANFD_Display3Prefix(context, 1, "BRS", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %s Bitrate", entry->fieldValue != 0 ? "Data" : "Nominal"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_ESI: CANFD_Display3Prefix(context, 1, "ESI", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> Error %s", entry->fieldValue != 0 ? "Passive" : "Active"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_DLC: CANFD_Display3Prefix(context, 1, "DLC", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %d data bytes", entry->fieldAux); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_DATA: CANFD_Display3Prefix(context, 2, "Data", entry); if (entry->fieldComplete) { PROTO_Printf(context, " #%d", entry->fieldAux); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_STC: CANFD_Display3Prefix(context, 1, "Stuff Count", entry); if (entry->fieldComplete) { if (entry->fieldAux == entry->fieldValue) { PROTO_Puts(context, " -> OK"); } else { PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, " -> ERROR, expected %X", entry->fieldAux); } } break; case CANFD_TRACE_ENTRY_BIT_TYPE_CRC: { uint32_t crcLength; uint32_t crcRef; char const *crcName; switch (entry->fieldAux >> 30) { default: crcLength = 15; crcName = "CRC15"; break; case 1: crcLength = 17; crcName = "CRC17"; break; case 2: crcLength = 21; crcName = "CRC21"; break; } crcRef = entry->fieldAux & 0xFFFFFF; CANFD_Display3Prefix(context, (crcLength + 3) / 4, crcName, entry); if (entry->fieldComplete) { if (crcRef == entry->fieldValue) { PROTO_Puts(context, " -> OK"); } else { PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, " -> ERROR, expected %0*X", (crcLength + 3) / 4, crcRef); } } } break; case CANFD_TRACE_ENTRY_BIT_TYPE_CRC_DEL: CANFD_Display3Prefix(context, 1, "CRC Delimiter", entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_ACK: CANFD_Display3Prefix(context, 1, "ACK Slot", entry); if (entry->fieldComplete) { PROTO_Printf(context, " -> %s", entry->fieldValue != 0 ? "NACK" : "ACK"); } break; case CANFD_TRACE_ENTRY_BIT_TYPE_ACK_DEL: CANFD_Display3Prefix(context, 1, "ACK Delimiter", entry); break; case CANFD_TRACE_ENTRY_BIT_TYPE_EOF: CANFD_Display3Prefix(context, 2, "End of Frame", entry); break; default: break; } } static void PROTOAPI CANFD_DisplayCore5(protoContext context, struct canfdTraceEntryFilter *entry) { PROTO_Printf(context, "%s: ", entry->filter->name); switch (entry->filter->format) { case CANFD_FORMAT_DECIMAL: case CANFD_FORMAT_DECIMAL_U: PROTO_Printf(context, "%" PRId64, entry->value); break; case CANFD_FORMAT_HEXADECIMAL: PROTO_Printf(context, "%0*" PRIX64, 2 * entry->filter->size, entry->value); break; } } static void PROTOAPI CANFD_Display5(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryFilter *entry; entry = (struct canfdTraceEntryFilter *)pdata; PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL5); PROTO_Control(context, PROTO_CONTROL_INDENT); CANFD_DisplayCore5(context, entry); } static void PROTOAPI CANFD_Export5(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryFilter *entry; entry = (struct canfdTraceEntryFilter *)pdata; CANFD_DisplayCore5(context, entry); PROTO_Control(context, PROTO_CONTROL_LINEFEED); } static int PROTOAPI CANFD_Draw(protoContext context, protoPtr pdata, protoPtr localdata, int *presult) { struct canfdLocalData *local; struct canfdTraceEntryFilter *entry; local = (struct canfdLocalData *)localdata; entry = (struct canfdTraceEntryFilter *)pdata; if (entry->filter->index > 32) { return 0; } if (entry->value < local->drawMin) { presult[entry->filter->index] = (int)local->drawMin; } else if (entry->value > local->drawMax) { presult[entry->filter->index] = (int)local->drawMax; } else { presult[entry->filter->index] = (int)entry->value; } return (int)((uint32_t)1 << entry->filter->index); } static char const *CANFD_GetChartStr(protoContext context, struct canfdLocalData *local, uint32_t id) { struct canfdChartList **list; struct canfdChartList *newList; struct canfdChartEntry *entry; int size; int i; if ((id & CANFD_ID_INVALID) != 0) { return "no frame"; } list = &local->statList; for (;;) { /* If we reach the end of the linked list, create a new entry */ if (*list == NULL) { newList = (struct canfdChartList *)PROTO_Alloc(context, sizeof(struct canfdChartList)); if (newList == NULL) { return "ALLOC_FAILED"; } *list = newList; size = 0; entry = newList->entries; newList->next = NULL; break; } /* Search for a matching id */ size = (*list)->size; entry = (*list)->entries; for (i = 0; i < size; ++i) { if (entry[i].id == id) { return entry[i].name; } } /* If the list is not yet full, extend it */ if ((size_t)size < sizeof((*list)->entries) / sizeof((*list)->entries[0])) { break; } list = &(*list)->next; } /* Add the new entry to the list */ entry[size].id = id; if ((id & CANFD_ID_EXTENDED) == 0) { sprintf(entry[size].name, "%03X", id & CANFD_ID_MASK); } else { sprintf(entry[size].name, "%08X", id & CANFD_ID_MASK); } (*list)->size = size + 1; return entry[size].name; } static char const *PROTOAPI CANFD_Chart(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdLocalData *local; struct canfdTraceEntryRaw *entry; local = (struct canfdLocalData *)localdata; entry = (struct canfdTraceEntryRaw *)pdata; return CANFD_GetChartStr(context, local, entry->chartId); } static void PROTOAPI CANFD_Display4(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryFrame *entry; int i; entry = (struct canfdTraceEntryFrame *)pdata; PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL4); PROTO_Control(context, PROTO_CONTROL_INDENT); switch (entry->error) { case CANFD_FRAME_ERROR_NONE: case CANFD_FRAME_ERROR_NACK: if ((entry->id & CANFD_ID_EXTENDED) == 0) { PROTO_Printf(context, " %03X", entry->id); } else { PROTO_Printf(context, "%08X", entry->id & CANFD_ID_MASK); } PROTO_Printf(context, " : %s(%d)", entry->rtr ? "RTR" : "D", entry->length); for (i = 0; i < entry->length; ++i) { if (i > 0 && i % 16 == 0) { PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, " ..."); PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Puts(context, " ..."); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL4); } PROTO_Printf(context, " %02X", entry->data[i]); } break; case CANFD_FRAME_ERROR_PASSIVE: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "Frame with passive error flag"); break; case CANFD_FRAME_ERROR_ACTIVE: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "Frame with active error flag"); break; case CANFD_FRAME_ERROR_FD_RES: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "res bit error"); break; case CANFD_FRAME_ERROR_CRC: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "CRC error"); break; case CANFD_FRAME_ERROR_CRC_DEL: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "CRC delimiter error"); break; case CANFD_FRAME_ERROR_ACK_DEL: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "ACK delimiter error"); break; case CANFD_FRAME_ERROR_EOF: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "EOF error"); break; case CANFD_FRAME_ERROR_INTERNAL: PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Printf(context, "internal decoder error"); break; } } static void PROTOAPI CANFD_PrintTime(protoContext context, protoTime time) { int64_t timeUs; bool negative; timeUs = time % PROTO_TIME_ONEMICROSECOND; if (timeUs < 0) { negative = true; timeUs = -timeUs; } else { negative = false; } PROTO_Printf(context, "%s%5" PRId64 ".%06" PRId64 "s", negative ? "-" : "", timeUs / 1000000, timeUs % 1000000); } static void PROTOAPI CANFD_Export4(protoContext context, protoPtr pdata, protoPtr localdata) { struct canfdTraceEntryFrame *entry; int i; entry = (struct canfdTraceEntryFrame *)pdata; CANFD_PrintTime(context, entry->time); if (entry->error != CANFD_FRAME_ERROR_NONE) { /* don't try to export errors */ PROTO_Puts(context, " ERROR"); return; } PROTO_Printf( context, " %c%c%c%c%c", (entry->id & CANFD_ID_EXTENDED) != 0 ? 'x' : '-', entry->rtr ? 'r' : '-', entry->fdf ? 'f' : '-', entry->brs ? 'b' : '-', entry->esi ? 'e' : '-' ); if ((entry->id & CANFD_ID_EXTENDED) != 0) { PROTO_Printf(context, " %08X", entry->id & CANFD_ID_MASK); } else { PROTO_Printf(context, " %03X", entry->id); } PROTO_Printf(context, " %2d", entry->length); if (!entry->rtr) { for (i = 0; i < entry->length; ++i) { PROTO_Printf(context, " %02X", entry->data[i]); } } PROTO_Control(context, PROTO_CONTROL_LINEFEED); } static bool CANFD_EqualTiming(struct canfdTiming const *a, struct canfdTiming const *b) { bool ret; ret = true; ret = ret && a->tq == b->tq; ret = ret && a->propSeg == b->propSeg; ret = ret && a->phaseSeg1 == b->phaseSeg1; ret = ret && a->phaseSeg2 == b->phaseSeg2; ret = ret && a->sjw == b->sjw; return ret; } static bool CANFD_EqualFilter(struct canfdFilter const *a, struct canfdFilter const *b) { bool ret; ret = true; ret = ret && a->id == b->id; ret = ret && a->offset == b->offset; ret = ret && a->size == b->size; ret = ret && a->be == b->be; ret = ret && a->format == b->format; ret = ret && strcmp(a->name, b->name) == 0; return ret; } static int PROTOAPI CANFD_Share(protoContext context, protoPtr sharedata, protoPtr localdata) { struct canfdLocalData *share; struct canfdLocalData *local; struct canfdFilter *filterA; struct canfdFilter *filterB; bool ret; share = (struct canfdLocalData *)sharedata; local = (struct canfdLocalData *)localdata; ret = true; ret = ret && sharedata != NULL && localdata != NULL; ret = ret && CANFD_EqualTiming(&share->nom, &local->nom); ret = ret && CANFD_EqualTiming(&share->dat, &local->dat); filterA = share->filter; filterB = local->filter; while (ret && filterA != NULL && filterB != NULL) { ret = ret && CANFD_EqualFilter(filterA, filterB); filterA = filterA->next; filterB = filterB->next; } ret = ret && (filterA == NULL) == (filterB == NULL); return ret ? 1 : 0; } static int CANFD_ParseCheckSelection(protoContext context, int options, bool const *allowedOptions, char const *const *optionNames, bool optional) { char selection[PROTO_MAXSTRGLEN] = ""; int i; int result; for (i = 0; i < options; ++i) { if (allowedOptions[i]) { if (selection[0] != '\0') { strcat(selection, ","); } strcat(selection, optionNames[i]); } } if (selection[0] == '\0') { return -1; } result = -1; PROTO_Parse(context, &result, selection, PROTO_PARSE_SELECTION | (optional ? PROTO_PARSE_OPTIONAL : 0)); if (result < 0) { return result; } for (i = 0; i < options; ++i) { if (allowedOptions[i]) { if (result == 0) { return i; } else { --result; } } } /* should never happen */ return -1; } static int CANFD_ParseVerb(protoContext context, bool const *allowedVerbs, bool optional) { return CANFD_ParseCheckSelection(context, CANFD_PARSE_NUM_VERBS, allowedVerbs, canfdParseVerbStr, optional); } static void CANFD_ParseTiming(protoContext context, struct canfdLocalData *local, struct canfdTiming *timing) { static char const *softkeys[2][5] = { { "", "", "", "", "" }, { "", "", "", "", "" } }; int index; protoTime parseTime[3]; int parseInt[3]; index = timing == &local->nom ? 0 : 1; parseTime[0] = 100 * PROTO_TIME_ONEMICROSECOND / 1000; parseTime[1] = 1 * PROTO_TIME_ONEMICROSECOND / 1000; parseTime[2] = 1000 * PROTO_TIME_ONEMILLISECOND; PROTO_Parse(context, parseTime, softkeys[index][0], PROTO_PARSE_TIME | PROTO_PARSE_CHECKRANGE); timing->tq = parseTime[0]; parseInt[0] = 0; parseInt[1] = 0; parseInt[2] = 1000; PROTO_Parse(context, parseInt, softkeys[index][1], PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); timing->propSeg = parseInt[0]; parseInt[0] = 0; parseInt[1] = 1; parseInt[2] = 1000; PROTO_Parse(context, parseInt, softkeys[index][2], PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); timing->phaseSeg1 = parseInt[0]; parseInt[0] = 0; parseInt[1] = 1; parseInt[2] = 1000; PROTO_Parse(context, parseInt, softkeys[index][3], PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); timing->phaseSeg2 = parseInt[0]; parseInt[0] = 0; parseInt[1] = 1; parseInt[2] = 1000; PROTO_Parse(context, parseInt, softkeys[index][4], PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); timing->sjw = parseInt[0]; } static void CANFD_ParseFrequency(protoContext context, struct canfdLocalData *local, struct canfdTiming *timing) { char const *softkey; unsigned int parseFrequency[3]; softkey = timing == &local->nom ? "nominal frequency" : "data frequency"; parseFrequency[0] = 0; parseFrequency[1] = (unsigned int)1.0e3; parseFrequency[2] = (unsigned int)100.0e6; PROTO_Parse(context, parseFrequency, softkey, PROTO_PARSE_FREQUENCY | PROTO_PARSE_CHECKRANGE); timing->tq = PROTO_TIME_ONESECOND / parseFrequency[0] / 100; timing->propSeg = 0; timing->phaseSeg1 = 69; timing->phaseSeg2 = 30; timing->sjw = 30; } static void CANFD_ParseFilter(protoContext context, struct canfdLocalData *local) { struct canfdFilter **list; struct canfdFilter filter; char name[PROTO_MAXSTRGLEN]; size_t nameLength; int i; int parseInt[3]; static char const *const sizeNames[8] = { "Byte", "Word", "Long", "Quad", "TByte", "PByte", "HByte", "SByte" }; static int const sizes[8] = { 1, 2, 4, 8, 3, 5, 6, 7 }; bool allowedSizes[8]; PROTO_Parse(context, name, "", PROTO_PARSE_STRING); nameLength = strlen(name); PROTO_Parse(context, parseInt, "Base,Extended", PROTO_PARSE_SELECTION); if (parseInt[0] == 0) { parseInt[1] = 0; parseInt[2] = (1 << 11) - 1; PROTO_Parse(context, parseInt, "", PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); filter.id = parseInt[0]; } else { parseInt[1] = 0; parseInt[2] = (1 << 29) - 1; PROTO_Parse(context, parseInt, "", PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); filter.id = CANFD_ID_EXTENDED | parseInt[0]; } parseInt[1] = 0; parseInt[2] = 63; PROTO_Parse(context, parseInt, "", PROTO_PARSE_INTEGER | PROTO_PARSE_CHECKRANGE); filter.offset = parseInt[0]; for (i = 0; i < 8; ++i) { allowedSizes[i] = filter.offset + sizes[i] <= 64; } i = CANFD_ParseCheckSelection(context, 8, allowedSizes, sizeNames, false); filter.size = sizes[i]; PROTO_Parse(context, parseInt, "LE,BE", PROTO_PARSE_SELECTION); filter.be = parseInt[0] == 1; PROTO_Parse(context, parseInt, "Decimal,DecimalU,Hex", PROTO_PARSE_SELECTION); filter.format = (enum canfdFormat)parseInt[0]; filter.index = local->filterCount; filter.next = NULL; list = &local->filter; while (*list != NULL) { list = &(*list)->next; } *list = (struct canfdFilter *)PROTO_Alloc(context, sizeof(struct canfdFilter) + nameLength); if (*list != NULL) { **list = filter; memcpy((*list)->name, name, nameLength + 1); ++local->filterCount; } } static void CANFD_ParseRange(protoContext context, struct canfdLocalData *local) { int64_t parseInt64[3]; parseInt64[1] = -((int64_t)1 << 31); parseInt64[2] = ((int64_t)1 << 32) - 1; PROTO_Parse(context, parseInt64, "", PROTO_PARSE_INTEGER64 | PROTO_PARSE_CHECKRANGE); local->drawMin = parseInt64[0]; parseInt64[1] = local->drawMin; if (local->drawMin < 0) { parseInt64[2] = ((int64_t)1 << 31) - 1; } else { parseInt64[2] = ((int64_t)1 << 32) - 1; } PROTO_Parse(context, parseInt64, "", PROTO_PARSE_INTEGER64 | PROTO_PARSE_CHECKRANGE); local->drawMax = parseInt64[0]; } static enum canfdLevel CANFD_ParseLevel(protoContext context, int command) { bool allowedLevels[sizeof(canfdLevelStr) / sizeof(canfdLevelStr[0])]; allowedLevels[CANFD_LEVEL_RAW] = false; allowedLevels[CANFD_LEVEL_PCS] = command != PROTO_COMMAND_EXPORT; allowedLevels[CANFD_LEVEL_BITS] = command != PROTO_COMMAND_EXPORT; allowedLevels[CANFD_LEVEL_FIELDS] = command != PROTO_COMMAND_EXPORT; allowedLevels[CANFD_LEVEL_FRAMES] = true; allowedLevels[CANFD_LEVEL_FILTERS] = true; return (enum canfdLevel)CANFD_ParseCheckSelection(context, sizeof(canfdLevelStr) / sizeof(canfdLevelStr[0]), allowedLevels, canfdLevelStr, false); } static bool CANFD_AutoRange(struct canfdLocalData *local) { struct canfdFilter *filter; int64_t min; int64_t max; for (filter = local->filter; filter != NULL; filter = filter->next) { if (filter->format == CANFD_FORMAT_DECIMAL_U) { min = 0; if (filter->size == 8) { max = INT64_MAX; } else { max = (uint64_t)1 << (8 * filter->size); } } else { if (filter->size == 8) { min = INT64_MIN; max = INT64_MAX; } else { min = -((int64_t)1 << (8 * filter->size - 1)); max = ((int64_t)1 << (8 * filter->size - 1)) - 1; } } if (min < local->drawMin) { local->drawMin = min; } if (max > local->drawMax) { local->drawMax = max; } } if (local->drawMin < INT32_MIN) { local->drawMin = INT32_MIN; local->drawMax = INT32_MAX; return false; } else if (local->drawMin < 0 && local->drawMax > INT32_MAX) { local->drawMin = INT32_MIN; local->drawMax = INT32_MAX; return false; } else if (local->drawMax > UINT32_MAX) { local->drawMin = 0; local->drawMax = UINT32_MAX; return false; } else { return true; } } int PROTOAPI PROTO_Init(protoContext context, int command) { struct canfdLocalData *local; int verb; bool allowedVerbs[CANFD_PARSE_NUM_VERBS]; int i; bool timingNomValid; bool timingDatValid; bool optional; bool rangeOk; enum canfdLevel level; if (PROTO_RequestVersion(context, 2) != PROTO_OK) { PROTO_Puts(context, "Requires newer trace32 version"); return PROTO_FAIL; } local = (struct canfdLocalData *)PROTO_Alloc(context, sizeof(struct canfdLocalData)); local->statList = NULL; local->filter = NULL; local->filterCount = 0; local->drawMin = 1; local->drawMax = 0; level = CANFD_LEVEL_FRAMES; PROTO_Parse(context, NULL, "", PROTO_PARSE_CHANNEL); for (i = 0; i < CANFD_PARSE_NUM_VERBS; ++i) { allowedVerbs[i] = true; } timingNomValid = false; timingDatValid = false; for (;;) { if (command == PROTO_COMMAND_DRAW && local->filter == NULL) { optional = false; } else if (!timingNomValid) { optional = false; } else { optional = true; } verb = CANFD_ParseVerb(context, allowedVerbs, optional); switch (verb) { case CANFD_PARSE_VERB_NOMINAL_FREQUENCY: CANFD_ParseFrequency(context, local, &local->nom); allowedVerbs[CANFD_PARSE_VERB_NOMINAL_FREQUENCY] = false; allowedVerbs[CANFD_PARSE_VERB_NOMINAL_TIMING] = false; allowedVerbs[CANFD_PARSE_VERB_DATA_TIMING] = false; timingNomValid = true; break; case CANFD_PARSE_VERB_NOMINAL_TIMING: CANFD_ParseTiming(context, local, &local->nom); allowedVerbs[CANFD_PARSE_VERB_NOMINAL_FREQUENCY] = false; allowedVerbs[CANFD_PARSE_VERB_NOMINAL_TIMING] = false; allowedVerbs[CANFD_PARSE_VERB_DATA_FREQUENCY] = false; timingNomValid = true; break; case CANFD_PARSE_VERB_DATA_FREQUENCY: CANFD_ParseFrequency(context, local, &local->dat); allowedVerbs[CANFD_PARSE_VERB_DATA_FREQUENCY] = false; allowedVerbs[CANFD_PARSE_VERB_DATA_TIMING] = false; allowedVerbs[CANFD_PARSE_VERB_NOMINAL_TIMING] = false; timingDatValid = true; break; case CANFD_PARSE_VERB_DATA_TIMING: CANFD_ParseTiming(context, local, &local->dat); allowedVerbs[CANFD_PARSE_VERB_DATA_FREQUENCY] = false; allowedVerbs[CANFD_PARSE_VERB_DATA_TIMING] = false; allowedVerbs[CANFD_PARSE_VERB_NOMINAL_FREQUENCY] = false; timingDatValid = true; break; case CANFD_PARSE_VERB_FILTER: CANFD_ParseFilter(context, local); break; case CANFD_PARSE_VERB_DRAW_RANGE: CANFD_ParseRange(context, local); allowedVerbs[CANFD_PARSE_VERB_DRAW_RANGE] = false; break; case CANFD_PARSE_VERB_LEVEL: level = CANFD_ParseLevel(context, command); allowedVerbs[CANFD_PARSE_VERB_LEVEL] = false; break; default: verb = -1; break; } if (verb < 0) { break; } } if (!timingDatValid) { local->dat = local->nom; } local->timeIntegration = local->nom.tq * 11 * (1 + local->nom.propSeg + local->nom.phaseSeg1 + local->nom.phaseSeg2); if (local->drawMin > local->drawMax) { rangeOk = CANFD_AutoRange(local); if (!rangeOk && command == PROTO_COMMAND_DRAW) { PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); PROTO_Puts(context, "Defined fields exceed capabilities of draw commands. Range must either be within [-2147483648; 2147483647] or within [0; 4294967295]."); } } /* Stage 1: do most of the decoding; because we need to decode the frame to * manange baud rate switching, there is no way to really split this into * multiple parts. */ PROTO_RegisterProcessCallback(context, CANFD_Process1, local, sizeof(struct canfdTraceEntryRaw), 1); PROTO_RegisterDisplayCallback(context, CANFD_Display1, local, 1); /* Stage 2: Filter out one entry for each individual bit. */ PROTO_RegisterProcessCallback(context, CANFD_Process2, local, sizeof(struct canfdTraceEntryRaw), 2); PROTO_RegisterDisplayCallback(context, CANFD_Display2, local, 2); /* Stage 3: Filter out one entry for each individual field. */ PROTO_RegisterProcessCallback(context, CANFD_Process3, local, sizeof(struct canfdTraceEntryRaw), 3); PROTO_RegisterDisplayCallback(context, CANFD_Display3, local, 3); /* Stage 4: Build actual frames. */ PROTO_RegisterProcessCallback(context, CANFD_Process4, local, sizeof(struct canfdTraceEntryFrame), 4); PROTO_RegisterDisplayCallback(context, CANFD_Display4, local, 4); /* Stage 5: Filter out data if any filters are defined. */ if (local->filter != NULL) { PROTO_RegisterProcessCallback(context, CANFD_Process5, local, sizeof(struct canfdTraceEntryFilter), 5); PROTO_RegisterDisplayCallback(context, CANFD_Display5, local, 5); } else { if (level == CANFD_LEVEL_FILTERS) { level = CANFD_LEVEL_FRAMES; } } if (command == PROTO_COMMAND_DRAW) { PROTO_RegisterDrawCallback(context, CANFD_Draw, local, 5, local->filterCount, (int)local->drawMin, (int)local->drawMax); } if (command == PROTO_COMMAND_EXPORT) { if (level != CANFD_LEVEL_FILTERS) { PROTO_RegisterExportCallback(context, CANFD_Export4, local, 4); } else { PROTO_RegisterExportCallback(context, CANFD_Export5, local, 5); } } PROTO_RegisterChartCallback(context, CANFD_Chart, local, 1); PROTO_RegisterShareCallback(context, CANFD_Share, local, 0); PROTO_SetDefaultLevel(context, level); return PROTO_OK; }