/** * \file * main source file of procol analaysis for LIN bus \mainpage This file describes the source code of the LIN protocol analyser. It does only sketch the basic structure to get an idea of the program flow. Parallel studying of the source code is strongly advised. \section mainProgramFlow Main Program flow The main program flow is given by the PROTOanalyzer API. Entry point is PROTO_Init() which does the main initialisation. After that PowerView calls Process1_process(), Process2_process() and Process3_process(). Parsing of the Lin Description File (LDF) is done in Process1_process() instead of PROTO_Init() to avoid repeated parsing after each single input. (PROTO_Init() is called each time something was entered at the command line of PowerView.) The corresponding display functions work like expected. \see \ref pageProccessingFunctions "The Three Processing Level" \see \ref pageLDFParser "LDF Parser" \see \ref pageOtherDescriptions "Other Descriptions" \section building Building PROTOanalyzer There are two different ways of building. One just builds 'protoLIN.dll' which is needed by PowerView. The other way builds 'test.exe' which can be used to test the parser and/or generic code (e.g. BufferVector) separately. As mentioned in \ref sectionProtoInterface there has to be included different implementations of struct ProtoInterface. To simplify these two builds a batch-file 'build.bat' exists: \li build.bat builds 'protolin.dll' \li build.bat test builds 'test.exe' \li build.bat clean cleans both projects \page pageProccessingFunctions The Three Processing Levels \section process1 Process 1 This processing level outputs detected data bytes as well as break and sync fields. There are no further processing (e.g. no frame assignment) done at this stage. \subsection description1 Description To fulfil the specification a break field has to be detected at all times, regardless what is expected. As the baudrate is set dynamically (by interpreting the sync field) and the length of break field depends on the baudrate, bit toggles have to be read ahead and checked for a possible break/sync field combination. After successful detection of a break/sync combination, the new baudrate (respectively bitTime) is calculated (Process1_calcBitTime()) and set. The maximal duration of a spike (i.e. every connected voltage level longer than this duration is considered to be NO spike) is set to 1/32 of bitTime. 1/16 bitTime would be too long, because a change from 1 kBit/s to 20 kBit/s (worst case) could then be missed. The read ahead functionality is covered with struct RawdataTimeBuffer_t which is some kind of ring buffer. By and by every bit toggle (which was not detected as a spike) is inserted in this ring buffer. (In fact each toggle is first inserted and after recognition as a spike just dropped/ignored.) The possibility of a break/sync field is checked periodically (Process1_checkApproxBreakPossibility() and Process1_compareFallingEdgeDelays()) and each time these checks fail (=> no break/sync field) the bits are interpreted by Process1_interpreteBits() which also handles the different states of byte detection and "clears" the ring buffer. The final break/sync field check is done by Process1_isBreakSyncField() and in the case of success (=> break/sync field) the above mentioned calculations of bitTime etc. are done. These timing values are needed by Process1_interpreteBits() to sample the bits, of course. \section process2 Process 2 This processing level collect the data bytes associated with a LIN frame and store them in one output entry. Therefore it has to know about frame length (number of data bytes) which is defined for each frame inside the LDF. The correctness of all received data bytes (associated with one frame) is ensured by validating the checksum byte. To find the correct frame definition the PID field (first data byte after sync field) containing the frame ID has to be interpreted. Disadvantageous the association of ID and frame definition can be changed by so called "configuration services" which are packed in special frames called "diagnostic frames". These configuration services use a "node address" (NAD) to address different slave nodes and these addresses can be dynamically changed by other configuration services, too. For this reason it is necessary to interpret the data bytes in case of a diagnostic frame and to change the corresponding data in the PROTOanalyzer representation of the LDF (Process2_diagnosticFrame_interprete()). \subsection description1 Description Processing starts after the first break/sync field. The following data byte represents the PID field and is checked against parity error. Then the existence of a valid LIN frame definition is checked. If no frame definition was found the following data bytes till the next break/sync field are stored as "unused bus traffic". If more than 8 data bytes were found these are stored in dynamically allocated memory. The maximal length of a frame is typically 8 data bytes, although more data bytes are generally possible. If less than the defined number of data bytes are found or if the checksum byte is missing, the frame is marked as "incomplete". If more data bytes are found, the remaining data bytes will be again stored as "unused bus traffic". To finalise the current frame Process2_completeActFrame() is called. This function also do some checks for so called "event triggered frames". \section process3 Process 3 This processing level bundles so called "Packet Data Units" (PDU). These PDUs can consist of several LIN frames. If a part of a PDU is detected, its sequence number and several other things are checked. If no PDU is detected, in case of an ordinary LIN frame, nothing special will be done. This level also inserts entries which mark the end of a frame respectively the end of a PDU to allow the chart display. Interpretation and proper display of signals (which are defined in LDF) is done by Process3_displaySignals() which is called by Process3_display(). \page pageLDFParser LDF Parser A Lin Description File (LDF) is parsed and the data is stored in struct LDFstruct. This structure is used in PROTOanalyzer to get needed data. \section parserProgramFlow Program Flow The parser is split into a tokenizer (LDFParser_tokenFindNext()) and grammar (LDFParser_grammarCheck()) part. The entry point is LDFParser_parse(). This function calls LDFParser_tokenFindNext() (as long as this is successful) which get the next token. After that the grammatically meaning is interpreted with LDFParser_grammarCheck(). \subsection tokenizer Tokenizer LDFParser_tokenFindNext() cover the whole interaction with the file. It works heavily with struct BufferVector which is some kind of ring buffer. This buffer is filled if needed and the function returns false if some file error (including EOF) occurs. After each successful call of LDFParser_tokenFindNext() the next token is ready to use. A tokenizer token has a attribute which describe its kind. Possible attributes are 'identifier', 'string', 'number', hexnumber', 'float' and 'comment' which can be combined. \subsection grammar Grammar LDFParser_grammarCheck() does the grammatically work. It checks for syntax error as well as for semantic errors. This function use also tokens, but these are different to the tokenizer tokens and converted at the beginning of the function. To minimise the number of needed states there are used three variables to define the "context" during parsing. Furthermore there are two different main branches in this function. Generally branch B will be taken if several complete different keywords are allowed whereas branch A will be taken if some context is already defined and only "parameters" are following. To define the rough context the (stack) variable struct Grammar::grammarContext is used. (It is implemented as struct StackInt). The context is GRAMMARCONTEXT_GLOBAL at the beginning and struct Grammar::expectedGrammarToken is cleared which means the second branch (branch B) is taken. In the case of GRAMMARCONTEXT_GLOBAL only a few keywords are allowed. One of this allowed keywords is for example "LIN_protocol_version", which is by the way of type GRAMMARTOKEN_IDENT. If this is matched, struct Grammar::grammarContext will not change, but struct Grammar::nextGrammarContext will get the value GRAMMARCONTEXT_GLOBAL_LIN_PROTOCOL_VERSION and struct Grammar::expectedGrammarToken will get the value GRAMMARTOKEN_EQUALSIGN. These two variables will be always set together. (If struct Grammar::expectedGrammarToken is cleared struct Grammar::nextGrammarContext won't be evaluated). Now, after struct Grammar::expectedGrammarToken was set (grammarp->expectedGrammarToken != GRAMMARTOKEN_NOTOKEN), a complete other branch (branch A) in LDFParser_grammarCheck() will be followed. This branch sequentially checks different struct Grammar::actGrammarToken (which represents the possible combination of the current token) against struct Grammar::expectedGrammarToken (which represents the syntactically expected token and its allowed combinations). struct Grammar::nextGrammarContext now decides what is done in detail. As a sidenote: if for example several GRAMMARTOKEN_COMMA appear in one struct Grammar::nextGrammarContext context, these have to be differed. For this struct Grammar::expectedGrammarSpecialValue is used which is a simple "counter". To summarise, after parsing "LIN_protocol_version" of the input line "LIN_protocol_version = "2.1";", struct Grammar::grammarContext will not be changed but struct Grammar::nextGrammarContext is set to a new value which again won't be changed till ";" is parsed. The normal behaviour after parsing ";" is to leave struct Grammar::grammarContext unchanged and to clear struct Grammar::expectedGrammarToken. This causes branch B to be taken again. If for example "Nodes" is found (instead of "LIN_protocol_version"), (branch B is taken and struct Grammar::expectedGrammarToken will bet set to the value GRAMMARTOKEN_OPENBRACE and struct Grammar::nextGrammarContext will be set to GRAMMARCONTEXT_GLOBAL_NODES. The next time branch A will be taken (because of struct Grammar::expectedGrammarToken) and if a "{" will be parsed then the value of struct Grammar::nextGrammarContext will be pushed at the stack struct Grammar::grammarContext and struct Grammar::expectedGrammarToken will be cleared. After all the state is similar to the beginning. The only change is that grammarContext holds now two values, first GRAMMARCONTEXT_GLOBAL and GRAMMARCONTEXT_GLOBAL_NODES. This causes another branch in branch B to be taken which accepts to keywords: "Master" and "Slaves". struct Grammar::nextGrammarContext will be set respectively and struct Grammar::expectedGrammarToken will be set to GRAMMARTOKEN_COLON in both cases. Parsing a "{" or "}" does generally always the same regardless which context is set. A left brace pushs the current struct Grammar::nextGrammarContext to the stack, a right brace pops and stores it in struct Grammar::nextGrammarContext again. In case of some (syntax) error LDFParser_grammarCheck() returns false. In this case struct Grammar::grammarState represent the error or respectively which should be done. GRAMMAR_ERROR_CONTEXT has been set if some syntax error occurred. The error message is relatively detailed. GRAMMAR_SKIP_BLOCK_ERROR causes the same but does not print the context information message. GRAMMAR_SKIP_BLOCK_SILENT is used to skip whole blocks which are not needed to be parsed. Therefore no message is displayed. If GRAMMAR_ERROR_VERSIONSTRING has been set, some special message have to be print out. This is some kind of semantic error. \page pageOtherDescriptions Other Descriptions \section sectionLDF struct LDFstruct The data of the Lin Description File which is parsed (see \ref pageLDFParser) is stored in an internal structure struct LDFstruct. Beside initialise and destroy functions there are several data management functions. There exists for example functions to find the definitions of nodes, frames or signals by their identifiers/names. In general these functions set a size_t pos argument which after that can be used to get a pointer to the defining structure. Some other auxiliary functions does recurrent jobs. In the case of LDF_frameFind_ByIdTimeref() for example the function searches for the definition of the frame which has as the specific ID assigned at some specific point in time. \section sectionBufferVector BufferVector struct BufferVector is mainly used to implement the file read buffer. But it is also used in struct LDFstruct to store a growing number of for example signal definitions, frame definition or whatever without worrying about memory allocation. struct BufferVector was actually designed to be some simple kind of ring buffer. A ring buffer which is filled completely and then consumed nearly till it is empty. This should be the case while read in some input file. A token (= some keyword) should not be very long. \subsection bufferVectorDescription Description While initialisation, memory is allocated to hold some amount of elements of any type (size of one element have to be defined). There are functions to append elements and to consume (from the beginning) elements. The user have not to care about memory management. The appended elements are stored in an array. If the end of the array is reached, that does not mean the buffer is full (some elements at the beginning could have been consumed), and some element needed to be appended, the buffer will be "reordered" (bufferVector_reorder()). This simply means all remaining elements are copied to the beginning of the array. This will be slow if many elements are valid while reordering occurs, but - as mentioned above - it is assumed that keywords are not very long and therefore only a few valid elements has to be copied. (By the way: a very long comment can causes such an ineffective reorder.) If the buffer is full and some element have to be appended, bufferVector_enlarge() will be called automatically which allocates more memory (default is twice the current size). bufferVector_fillExtern() is used to fill the buffer by an external function like fread(). This was implemented to avoid repeatedly copying of data. \section sectionStackInt StackInt The behaviour of struct StackInt is very similar, except for only unsigned int values are stored. There are functions to push and pop elements. \section sectionProtoInterface ProtoInterface To test the LDF parser separately without PowerView, memory allocation and message printing has to be encapsulated. This is because PowerView needs memory allocated with PROTO_Alloc() and messages printed with PROTO_Printf() or PROTO_Puts(). To allow compilation for both, two different struct ProtoInterface are implemented. To compile 'test.exe' the header 'ProtoInterface_test.h' is included, to compile 'protoLIN.dll' the header 'ProtoInterface.h' is included. This is warranted by the macro PROTOINTERFACE_HEADER_FILENAME inside the makefile. */ #include "protolin.h" #include "proto.h" #include "ldf.h" #include "buffer.h" #include "generic.h" #include "protointerface.h" #include "ldf_parser.h" #include #define PROTO_ASK4CANCEL_MAX_STEPS 0x0000FFu /**< How often a user abort is checked. */ #define LDFPARSER_BUFFER_SIZE 1000000 /*=================================================================== ======= DEKLARATIONS ================================================ ====================================================================*/ /*=================================================================== ======= OTHER PROTO ================================================= ====================================================================*/ /** \defgroup otherProto Other PROTO Types */ /** \{ */ /** Vars for protocol analysis. */ struct LIN_Proto { ProtoInterface protoInterface; /**< Interface to print message in host software. */ LDFstruct *ldfp; /**< Pointer to allocated memory which holds parsed LinDescriptionFile. Allocation happens in PROTO_Init(). */ char ldfFilename[FILENAME_MAX]; /** \todo What does PROTO_parse function if buffer is too small! */ char compositeConfigurationName[300]; /**< Name of optional composite configuration */ protoTime StartValueMaxSpikeTime; /**< Start value for struct Process1_LocalData_t::maxSpikeTime */ int maxFallingEdgeDiffDivisor; /**< Value which is used to calculate the maximal allowed time difference between two falling edges of a \ref breaksync in framedata::Process1_compareFallingEdgeDelays(). */ unsigned char hideNoEncodingSignalsf; /**< Hide dislay of signals with no encoding defined. */ }; union LIN_Pdu { struct LIN_Pdu_sf { unsigned char nad; unsigned char pci; unsigned char sid; unsigned char d1; unsigned char d2; unsigned char d3; unsigned char d4; unsigned char d5; } sf; struct LIN_Pdu_ff { unsigned char nad; unsigned char pci; unsigned char len; unsigned char sid; unsigned char d1; unsigned char d2; unsigned char d3; unsigned char d4; } ff; struct LIN_Pdu_cf { unsigned char nad; unsigned char pci; unsigned char d1; unsigned char d2; unsigned char d3; unsigned char d4; unsigned char d5; unsigned char d6; } cf; }; /** \} */ /*=================================================================== ======= LEVEL1 ====================================================== ====================================================================*/ /** \defgroup framedata Level1 - Framedata */ /** \{ */ #define RAWDATA_BITLOW (0) /**< level of low returned by PROTO_ReadTrace() */ #define RAWDATA_BITHIGH (1) /**< level of high returned by PROTO_ReadTrace() */ enum LIN_FramedataFSM {BREAKSYNC_SEARCH, ACCEPT_DATA}; /**< FSM used to differ between breaksync search and accepting data. Normal mode will be accepting data, because breaksync has to be always detected. */ enum LIN_FramedataFieldFSM {BREAKFIELD, SYNCFIELD, DATABYTE}; /**< FSM used to differ between fields in LIN frame. Describes kind of field in level1 structure (struct LIN_Framedata_t). */ enum LIN_BitFSM {STARTBIT, BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, STOPBIT}; /**< FSM used to differ between kinds of raw bits. */ /** Flags describing state of received framedata. Used to save information (e.g. errors) of one single framedata = databyte in struct LIN_Framedata_t. */ typedef union LIN_FramedataInformation_t { unsigned int flags; /**< To access all flags. */ struct { unsigned int stopbitErrorf:1; /**< Expected stopbit was not framedata::RAWDATA_BITHIGH. */ unsigned int bitvaluesErrorf:1; /**< Value of bit was not well-defined. */ } flag; /**< To access one flag. */ } LIN_FramedataInformation; /** Level1 output data. */ typedef struct LIN_Framedata { protoTime time; /**< Timestamp of information (must remain at this place!). */ protoTime endTime; /**< Timestamp representating end of framedata. */ enum LIN_FramedataFieldFSM framedataField; /**< Type of the field. */ LIN_FramedataInformation framedataInfo; /**< Flags for information. */ unsigned char framedata; /**< Real databyte. */ } LIN_Framedata; /** One entry for struct RawdataTimeBuffer_t::buffer. */ typedef struct LIN_RawdataTime_t { protoTime fallingEdge; protoTime risingEdge; protoTime deltaLowLevel; } LIN_RawdataTime; /** Stores state of struct RawdataTimeBuffer_t::buffer. */ enum RawdataTimeBufferPos { POSSIBLE_BREAK=0, /**< Possible break (any low level) has been found. */ FALLING1, /**< 1st falling/rising edge (start of syncfield). */ FALLING2, /**< 2nd falling/rising edge. */ FALLING3, /**< 3rd falling/rising edge. */ FALLING4, /**< 4th falling/rising edge. */ FALLING5, /**< 5th falling/rising edge (end of syncfield). */ ENSURE_NOSPIKE /**< It has to bee ensured that the last rising edge was no spike. */ }; #define RAWDATA_TIME_BUFFER_SIZE ((int) ENSURE_NOSPIKE + 1) /**< Maximal size of ringbuffer struct RawdataTimeBuffer_t::buffer. This size is needed to detect a correct \ref breaksync. */ /** Ringbuffer of last raw values and managing vars. */ struct RawdataTimeBuffer_t { LIN_RawdataTime buffer[RAWDATA_TIME_BUFFER_SIZE]; /**< buffer which hold the last raw values a little bit prepared. */ enum RawdataTimeBufferPos possibleBreakPos; /**< the next possible berakfield position. */ enum RawdataTimeBufferPos size; /**< size of the buffer. */ }; /** Variables combined for Process1 subroutines. */ typedef struct Process1_LocalData_t { enum LIN_FramedataFSM framedataFSM; enum LIN_FramedataFieldFSM framedataFieldFSM; enum LIN_BitFSM bitFSM; protoTime bitTime; /**< Last calculated bit time. */ protoTime latestBitSampleTime; /**< Latest time when bit changes are significant. Used in Process1_interpreteBits().*/ protoTime earliestBitSampleTime; /**< Earliest time when bit changes are significant. Used in framedata::Process1_interpreteBits().*/ protoTime startBitTime; /**< Timestamp of last startbit. Used in Process1_interpreteBits(). */ protoTime refTime; /**< Used in Process1_interpreteBits(). */ protoTime refTime_old; /**< Used in Process1_interpreteBits(). */ unsigned char framedataByte; /**< Value of frame data byte calculated so far. Used in Process1_interpreteBits(). */ LIN_FramedataInformation framedataInfo; /**< Flags of frame data byte set so far. Used in Process1_interpreteBits(). */ protoTime maxSpikeTime; /**< Spikes shorter than this value will be ignored. */ protoTime compareSyncReference; /**< Used in Process1_compareFallingEdgeDelays(). */ protoTime maxSyncDiff; /**< Used in Process1_compareFallingEdgeDelays(). */ struct LIN_Proto *protoParamsp; /**< Copy of pointer to struct LIN_Proto which is passed to each process and display function. */ LIN_Framedata *framedataArray; /**< Level1 output data array. */ int framedataIndex; /**< Position of next write to framedataArray. It has to be ensured that enough memory was allocated before write. After write, framedataIndex represents the number of inserted entries. */ struct RawdataTimeBuffer_t rawdataTimeBuffer; } Process1_LocalData; /** \} */ /*=================================================================== ======= LEVEL2 ====================================================== ====================================================================*/ /** \defgroup frame Level2 - Frame */ /** \{ */ /** String representattion of different frame types. \sa enum LDFstruct::FrameDef_frameType. */ static const char frameTypeStrings[][3] = { "NA", /**< Frame type unknown/not defined. */ "UF", /**< Unconditional frame. */ "SF", /**< Sporadic frame. */ "ET", /**< Event triggered frame. */ "DF", /**< Diagnostic frame. */ }; enum ProtoFrame_InfoFlags { PROTOFRAME_ALL = 0xFF, /**< All bits. */ PROTOFRAME_ERROR_ALL = 0x7F<<0, /**< All bits of error status. */ PROTOFRAME_BIT_ERROR = 1<<00, PROTOFRAME_PID_ERROR = 1<<01, PROTOFRAME_NOT_COMPLETE = 1<<02, PROTOFRAME_NOT_ASSOCIATED = 1<<03, PROTOFRAME_CHECKSUM_ERROR = 1<<04, PROTOFRAME_EVENTFRAME_ERROR_ALL = 3<<05, PROTOFRAME_EVENTFRAME_NO_FRAME_ADDED = 1<<05, PROTOFRAME_EVENTFRAME_PID_ERROR = 2<<05, PROTOFRAME_EVENTFRAME_ID_NOT_ADDED = 3<<05, PROTOFRAME_UNUSED_TRAFFIC = 1<<07, }; enum ProtoFrame_PDUType { PROTOPDU_NORMALFRAME=0, PROTOPDU_DIAG_REQ_OK, PROTOPDU_DIAG_REQ_NOT_DEFINED, PROTOPDU_DIAG_RESP_POS, PROTOPDU_DIAG_RESP_NEG, PROTOPDU_DIAG_RESP_UNKNOWN_RESULT, PROTOPDU_DIAG_RESP_WITHOUT_REQ, PROTOPDU_DIAG_RESP_NOT_DEFINED, PROTOPDU_SF, PROTOPDU_FF, PROTOPDU_CF, PROTOPDU_UNKNOWNPCI, }; /** Level2 output data. */ struct Proto_Frame { protoTime time; protoTime endTime; TimeRef timeRef; unsigned char infoFlags; /**< Different flags represent frame status (see enum frame::ProtoFrame_InfoFlags). */ unsigned char pduType; char *diagServiceStringp; unsigned char id; unsigned short nrDatabytes; union /** Holds databytes. */ { unsigned char databytes[DATABYTES_MAX_NUMBER_NORMAL]; /**< Array of data bytes. Used if less or equal than frame::DATABYTES_MAX_NUMBER_NORMAL databytes. */ unsigned char *databytesp; /**< Pointer to databytes. Used if more than frame::DATABYTES_MAX_NUMBER_NORMAL databytes. */ } data; unsigned char checksum; }; enum Process2_FrameFSM { FRAME_BREAK, FRAME_SYNC, FRAME_ID, FRAME_DATABYTE, FRAME_DATABYTE_UNUSED }; struct Process2_LocalData { enum Process2_FrameFSM acceptFramedataFSM; int outPos; int outSize; struct LIN_Framedata *actFramedatap; struct Proto_Frame *actFramep; struct LIN_FrameDef *actLinFrameDefp; TimeRef actTimeRef; unsigned char accumulatedChecksum; unsigned char checksumProcessedf; protoTime startTime; protoTime endTime; struct LIN_Pdu_sf *lastDiagReqp; BufferVector databytesBuffer; }; /** \} */ /*=================================================================== ======= LEVEL3 ====================================================== ====================================================================*/ /** \defgroup frameAssociate Level3 - Frame associated */ /** \{ */ #define DATAFRAMES_BUFFER_INIT_SIZE 1 #define DATAFRAMES_BUFFER_FIRST_ENLARGE_SIZE 10 #define ENCODEDSIGNALSTRING_BUFFER_SIZE 100 struct IncludedFrame { struct Proto_Frame *framep; }; enum ProtoFrameAssoc_InfoFlags { PROTOFRAMEASSOC_ALL = 0x1F, /**< All bits. */ PROTOFRAMEASSOC_ERROR_ALL = 0x07<<0, /**< All bits of error status. */ PROTOFRAMEASSOC_ERROR_FRAME = 0x01<<0, PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE = 0x01<<1, PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE_NR = 0x01<<2, PROTOFRAMEASSOC_FRAME_END_MARKER = 0x01<<3, PROTOFRAMEASSOC_UNUSED_TRAFFIC = 0x01<<4, }; /** Level3 output data. */ struct Proto_FrameAssoc { protoTime time; unsigned char infoFlags; unsigned short pduCounterOnError; struct LIN_FrameDef *linFrameDefp; struct LIN_SlaveNodeAttributesDef *pduSlaveNodeDefp; BufferVector includedFrames; /**< struct IncludedFrame */ }; enum ProtoFrameAssocFSM { FRAMEASSOC_FRAMECOMPLETE, FRAMEASSOC_PDU_FOLLOWS }; struct Process3_LocalData { struct Proto_Frame *actFramep; struct Proto_FrameAssoc *actFrameAssocp; struct LIN_FrameDef *actFrameDefp; enum ProtoFrameAssocFSM frameAssocFSM; unsigned short pduCounter; unsigned short pduRemainingLength; int outPos; int outSize; }; #define SERVICENAME_NUMBER 17 #define SERVICENAME_MAX_LEN 35 struct SidServices { const unsigned char sid; const char servicename[SERVICENAME_MAX_LEN]; }; static struct SidServices sidServices[SERVICENAME_NUMBER] = { {0xb0, "Assign NAD req."}, {0xb1, "Assign Frame ID req."}, {0xb2, "Read by Identifier req."}, {0xb3, "Conditional Change NAD req."}, {0xb4, "Data Dump req."}, {0xb5, "Assign NAD via SNPD req."}, {0xb6, "Save Config req."}, {0xb7, "Assign Frame ID by Range req."}, {0xb0 + 0x40, "Assign NAD resp."}, {0xb1 + 0x40, "Assign Frame ID resp."}, {0xb2 + 0x40, "Read by Identifier resp."}, {0xb3 + 0x40, "Conditional Change NAD resp."}, {0xb4 + 0x40, "Data Dump resp."}, {0xb5 + 0x40, "Assign NAD via SNPD resp."}, {0xb6 + 0x40, "Save Config resp."}, {0xb7 + 0x40, "Assign Frame ID by Range resp."}, {0x7f, "Read by Identifier resp."}, /*negative response*/ }; /** \} */ /*=================================================================== ======= FUNCTIONS =================================================== ====================================================================*/ /** \addtogroup otherProto */ /** \{ */ static int parityEven8(unsigned char x) { x = x ^ (x >> 4); x = x ^ (x >> 2); x = x ^ (x >> 1); return x & 0x1; } static unsigned char linPidCalc(unsigned char id) { int parity_P1, parity_P0; parity_P1 = parityEven8( (unsigned char) (id & P1_DETERMINING_BITS) ) ^ 0x1; parity_P0 = parityEven8( (unsigned char) (id & P0_DETERMINING_BITS) ); return parity_P1<<7 | parity_P0<<6 | id & LIN_PID_ID_MASK; } /** Initialize struct struct LIN_Proto. */ static int Proto_protoParams_init(struct LIN_Proto *protoParamsp, protoContext context) { int okf = TRUE; if (FALSE == protoInterface_init(&protoParamsp->protoInterface, context)) okf = FALSE; protoParamsp->ldfp = NULL; protoParamsp->ldfFilename[0] = '\0'; protoParamsp->compositeConfigurationName[0] = '\0'; protoParamsp->StartValueMaxSpikeTime = 0; protoParamsp->maxFallingEdgeDiffDivisor = 0; protoParamsp->hideNoEncodingSignalsf = FALSE; return okf; } static void Proto_protoParams_setContext(struct LIN_Proto *protoParamsp, protoContext context) { protoParamsp->protoInterface.context = context; } int PROTOAPI PROTO_Init(protoContext context, int command) { struct LIN_Proto *protoParamsp = NULL; LDFstruct *ldfp = NULL; int okf = TRUE; okf = (okf && (protoParamsp = (struct LIN_Proto*) PROTO_Alloc(context, sizeof(struct LIN_Proto)))); okf = (okf && Proto_protoParams_init(protoParamsp, context)); if (okf) { PROTO_Parse(context, (protoPtr) 0, "", PROTO_PARSE_CHANNEL); PROTO_Parse(context, (protoPtr) protoParamsp->ldfFilename, "", PROTO_PARSE_STRING); protoParamsp->hideNoEncodingSignalsf = FALSE; PROTO_Parse(context, (protoPtr) &protoParamsp->hideNoEncodingSignalsf, "SHOWnoenc,HIDEnoenc", PROTO_PARSE_SELECTION | PROTO_PARSE_OPTIONAL); protoParamsp->compositeConfigurationName[0] = '\0'; PROTO_Parse(context, (protoPtr) protoParamsp->compositeConfigurationName, "", PROTO_PARSE_STRING | PROTO_PARSE_OPTIONAL); protoParamsp->maxFallingEdgeDiffDivisor = 200; PROTO_Parse(context, (protoPtr) &protoParamsp->maxFallingEdgeDiffDivisor, "", PROTO_PARSE_INTEGER | PROTO_PARSE_OPTIONAL); protoParamsp->StartValueMaxSpikeTime = PROTO_TIME_ONEMICROSECOND; PROTO_Parse(context, (protoPtr) &protoParamsp->StartValueMaxSpikeTime, "", PROTO_PARSE_TIME | PROTO_PARSE_OPTIONAL); PROTO_RegisterProcessCallback(context, Process1_process, (protoPtr) protoParamsp, sizeof(LIN_Framedata), 1); PROTO_RegisterDisplayCallback(context, Process1_display, (protoPtr) protoParamsp, 1); /*in case of no LDF only show raw databytes*/ if (protoParamsp->ldfFilename[0] != '\0') { PROTO_RegisterProcessCallback(context, Process2_process, (protoPtr) protoParamsp, sizeof(struct Proto_Frame), 2); PROTO_RegisterDisplayCallback(context, Process2_display, (protoPtr) protoParamsp, 2); PROTO_RegisterProcessCallback(context, Process3_process, (protoPtr) protoParamsp, sizeof(struct Proto_FrameAssoc), 3); PROTO_RegisterDisplayCallback(context, Process3_display, (protoPtr) protoParamsp, 3); PROTO_RegisterChartCallback(context, Process3_chart, (protoPtr) protoParamsp, 3); PROTO_SetDefaultLevel(context, 3); } /*parsing of ldf file now in Process1_process() to avoid multiply parsing*/ return PROTO_OK; } return PROTO_PROCESS_OUTOFMEMORY; /** \todo return value okay?? */ } /** \} */ /** \addtogroup framedata */ /** \{ */ /** Returns incremented pos of ringbuffer struct RawdataTimeBuffer_t. */ static int Process1_incBufferIndex(int index, int value) { index += value; while (RAWDATA_TIME_BUFFER_SIZE <= index) index -= RAWDATA_TIME_BUFFER_SIZE; return index; } /** Returns decremented pos of ringbuffer struct RawdataTimeBuffer_t. */ static int Process1_decBufferIndex(int index, int value) { index -= value; while (0 > index) index += RAWDATA_TIME_BUFFER_SIZE; return index; } /** Move on readpos of ringbuffer struct RawdataTimeBuffer_t. */ static void Process1_skipPossibleBreakFields(struct RawdataTimeBuffer_t *rawdataTimeBufferp, enum RawdataTimeBufferPos nr2skip) { rawdataTimeBufferp->possibleBreakPos = Process1_incBufferIndex(rawdataTimeBufferp->possibleBreakPos, nr2skip); rawdataTimeBufferp->size -= nr2skip; } /** Do checking of possible \ref breaksync field. Check if \p breakTime /8 is longer than \p actSyncTime. If not, this \b can't be a \ref breaksync. * \returns false if it \b can't be a \ref breaksync field. */ static int Process1_checkApproxBreakPossibility(protoTime breakTime, protoTime actSyncTime) { protoTime breakTime8 = (protoTime) (PROTO_TIME_TOINT(breakTime) >> 3); return ( PROTO_TIME_ISSMALLER(actSyncTime, breakTime8) ); } /** Do checking of possible \ref breaksync field. Check if difference between two falling edges (syncfield) do not differ more than 1/(struct LIN_Proto::maxFallingEdgeDiffDivisor). * \returns false if it \b can't be a \ref breaksync field. */ static int Process1_compareFallingEdgeDelays(Process1_LocalData *localDatap, protoTime lastFallingEdge, protoTime actFallingEdge) { protoTime deltaTime = PROTO_TIME_SUB(actFallingEdge, lastFallingEdge); int boolSetRefDelay = (FALLING2 == localDatap->rawdataTimeBuffer.size); if (boolSetRefDelay) { localDatap->compareSyncReference = deltaTime; /*does not work correctly!*/ //localDatap->maxSyncDiff = (protoTime) (PROTO_TIME_TOINT(deltaTime) >> 8); /*0.5% of localDatap->compareSyncReference, 0.5% = 1/200 approx. 1/256 = x>>8*/ localDatap->maxSyncDiff = (protoTime) (PROTO_TIME_TOINT(deltaTime) / localDatap->protoParamsp->maxFallingEdgeDiffDivisor); return TRUE; } deltaTime = PROTO_TIME_ABS( PROTO_TIME_SUB(localDatap->compareSyncReference, deltaTime) ); return ( PROTO_TIME_ISSMALLER(deltaTime, localDatap->maxSyncDiff) ); } /** Does the last check of possible \ref breaksync field. * If time of syncfield * 11 <= time of breakfield * 8 this function returns true. * \returns true if it \b is a \ref breaksync field. * * * \anchor breaksync * ¯¯¯\\___________/¯¯\\_/¯\\_/¯\\_/¯\\_/¯\\_/¯¯\\_xxxx \n\n * A \ref breaksync field is defined as follows:\n * -# Low level for at least 11 bit times (break field). * -# Following syncfield with toggling bits (value 0x55). * * Detecting \ref breaksync can be done as follows: * - time difference between two falling edges (syncfield) must not differ more than 0.5% (configurable by struct LIN_Proto::maxFallingEdgeDiffDivisor) * - time of syncfield * 11 <= time of breakfield * 8 */ static int Process1_isBreakSyncField(struct RawdataTimeBuffer_t *rawdataTimeBufferp, int breakBufferIndex, int endSyncFieldIndex) { int startSyncFieldIndex = Process1_incBufferIndex(breakBufferIndex, 1); protoTime syncFieldTime; protoTime breakTime; /* BreakTime/SyncFieldTime >= 11/8 => BreakTime*8 >= SynFieldTime*11 worstcase: BreakTime: 13Bits / 1kBit/s = 13ms Syncfield: 13ms/8 (because of 'Process1_checkApproxBreakPossibility()') * 8 = 13ms => worstcase = 13ms * 11 = 143ms 2^64 / PROTO_TIME_ONEMICROSECOND = 335.5ms * 2^32 => OK (even a 32bit type would be ok!) */ syncFieldTime = PROTO_TIME_SUB(rawdataTimeBufferp->buffer[endSyncFieldIndex].fallingEdge, rawdataTimeBufferp->buffer[startSyncFieldIndex].fallingEdge); syncFieldTime = PROTO_TIME_MULTINT(syncFieldTime, 11); breakTime = PROTO_TIME_MULTINT(rawdataTimeBufferp->buffer[breakBufferIndex].deltaLowLevel, 8); return ( PROTO_TIME_ISSMALLER(syncFieldTime, breakTime) ); } /** Returns calculated bit time using the syncfield. */ static protoTime Process1_calcBitTime(struct RawdataTimeBuffer_t *rawdataTimeBufferp) { protoTime falling1; protoTime falling5; int tmpIndex; tmpIndex = Process1_incBufferIndex(rawdataTimeBufferp->possibleBreakPos, 1); falling1 = rawdataTimeBufferp->buffer[tmpIndex].fallingEdge; tmpIndex = Process1_incBufferIndex(tmpIndex, 4); falling5 = rawdataTimeBufferp->buffer[tmpIndex].fallingEdge; return (PROTO_TIME_SUB(falling5, falling1) >> 3); } /** Sets one entry of level1 data (struct LIN_Framedata_t). */ static void Process1_setFrameData(LIN_Framedata *framedatap, protoTime timestamp, protoTime endTime, enum LIN_FramedataFieldFSM framedataField, unsigned char byte, LIN_FramedataInformation framedataInfo) { framedatap->time = timestamp; framedatap->endTime = endTime; framedatap->framedataField = framedataField; framedatap->framedata = byte; framedatap->framedataInfo = framedataInfo; } /** Interpretes the raw data (stored in struct RawdataTimeBuffer_t::buffer) and add them to level1 data (struct LIN_Framedata_t). * \returns PROTO_PROCESS_OUTOFMEMORY if struct Process1_LocalData_t::framedataArray is too small. */ static int Process1_interpreteBits(Process1_LocalData *localDatap, int maxSize) { protoTime stopbitTime = 0; protoTime toggleTime; int actIndex = localDatap->rawdataTimeBuffer.possibleBreakPos; if (ACCEPT_DATA == localDatap->framedataFSM) { while (localDatap->rawdataTimeBuffer.size > 0) { if (STARTBIT == localDatap->bitFSM) { localDatap->startBitTime = localDatap->refTime = localDatap->rawdataTimeBuffer.buffer[actIndex].fallingEdge; localDatap->framedataByte = (unsigned char) 0; localDatap->framedataInfo.flags = FALSE; } /*RAWDATA_BITLOW values*/ toggleTime = localDatap->rawdataTimeBuffer.buffer[actIndex].risingEdge; localDatap->refTime_old = localDatap->refTime; localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); while ( PROTO_TIME_ISSMALLER(localDatap->refTime, toggleTime) ) { if (STOPBIT == localDatap->bitFSM) { localDatap->framedataInfo.flag.stopbitErrorf = TRUE; stopbitTime = localDatap->refTime; break; } localDatap->bitFSM++; localDatap->refTime_old = localDatap->refTime; localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); } localDatap->refTime = localDatap->refTime_old; /*now localDatap->refTime is at the last sure postion*/ if (FALSE == localDatap->framedataInfo.flag.stopbitErrorf) { /*toggle is after latestBitSampleTime => bit value will be accepted*/ if ( PROTO_TIME_ISSMALLER( PROTO_TIME_ADD(localDatap->refTime, localDatap->latestBitSampleTime) , toggleTime)) { localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); if (STOPBIT == localDatap->bitFSM) { localDatap->framedataInfo.flag.stopbitErrorf = TRUE; stopbitTime = localDatap->refTime; } localDatap->bitFSM++; } /*toggle is between earliestBitSampleTime and latestBitSampleTime => BITVALUE_ERROR */ else if ( PROTO_TIME_ISSMALLER( PROTO_TIME_ADD(localDatap->refTime, localDatap->earliestBitSampleTime) , toggleTime) ) { localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); if (STOPBIT == localDatap->bitFSM) { localDatap->framedataInfo.flag.stopbitErrorf = TRUE; stopbitTime = localDatap->refTime; } localDatap->framedataInfo.flag.bitvaluesErrorf = TRUE; localDatap->bitFSM++; } /*toggle is before earliestBitSampleTime => it is save to interprete it in the next step (as toggled bit value)*/ else ; } if (localDatap->framedataInfo.flag.stopbitErrorf) { if (maxSize <= localDatap->framedataIndex) return PROTO_PROCESS_OUTOFMEMORY; Process1_setFrameData(&localDatap->framedataArray[localDatap->framedataIndex], localDatap->startBitTime, stopbitTime, localDatap->framedataFieldFSM, localDatap->framedataByte, localDatap->framedataInfo); localDatap->bitFSM = STARTBIT; localDatap->framedataIndex++; } /*RAWDATA_BITHIGH values*/ else { int tmpIndex = Process1_incBufferIndex(actIndex, 1); toggleTime = localDatap->rawdataTimeBuffer.buffer[tmpIndex].fallingEdge; localDatap->refTime_old = localDatap->refTime; localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); while ( PROTO_TIME_ISSMALLER(localDatap->refTime, toggleTime) ) { if (STOPBIT == localDatap->bitFSM) { localDatap->bitFSM = STARTBIT; stopbitTime = localDatap->refTime; break; } else { localDatap->framedataByte |= 1 << ((int) localDatap->bitFSM - 1); localDatap->bitFSM++; localDatap->refTime_old = localDatap->refTime; localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); } } localDatap->refTime = localDatap->refTime_old; /*now localDatap->refTime is at the last sure postion*/ if (STARTBIT != localDatap->bitFSM) { /*toggle is after latestBitSampleTime => bit value will be accepted*/ if ( PROTO_TIME_ISSMALLER( PROTO_TIME_ADD(localDatap->refTime, localDatap->latestBitSampleTime) , toggleTime)) { localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); if (STOPBIT == localDatap->bitFSM) { localDatap->bitFSM = STARTBIT; stopbitTime = localDatap->refTime; } else { localDatap->framedataByte |= 1 << ((int) localDatap->bitFSM - 1); localDatap->bitFSM++; } } /*toggle is between earliestBitSampleTime and latestBitSampleTime => BITVALUE_ERROR */ else if ( PROTO_TIME_ISSMALLER( PROTO_TIME_ADD(localDatap->refTime, localDatap->earliestBitSampleTime) , toggleTime) ) { localDatap->refTime = PROTO_TIME_ADD(localDatap->refTime, localDatap->bitTime); if (STOPBIT == localDatap->bitFSM) { localDatap->framedataInfo.flag.stopbitErrorf = TRUE; localDatap->bitFSM = STARTBIT; stopbitTime = localDatap->refTime; } else localDatap->bitFSM++; localDatap->framedataInfo.flag.bitvaluesErrorf = TRUE; } /*toggle is before earliestBitSampleTime => it is save to interprete it in the next step (as toggled bit value)*/ else ; } /*byte is interpreted completely*/ if (STARTBIT == localDatap->bitFSM) { if (maxSize <= localDatap->framedataIndex) return PROTO_PROCESS_OUTOFMEMORY; Process1_setFrameData(&localDatap->framedataArray[localDatap->framedataIndex], localDatap->startBitTime, stopbitTime, localDatap->framedataFieldFSM, localDatap->framedataByte, localDatap->framedataInfo); localDatap->framedataIndex++; } } localDatap->rawdataTimeBuffer.size--; actIndex = Process1_incBufferIndex(actIndex, 1); } localDatap->rawdataTimeBuffer.possibleBreakPos = actIndex; } else Process1_skipPossibleBreakFields(&localDatap->rawdataTimeBuffer, localDatap->rawdataTimeBuffer.size); return FALSE; } protoSizeT PROTOAPI Process1_process(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr paramsp) { Process1_LocalData localData, *localDatap = &localData; int rawIndex = 0; unsigned int cancelCounter = 0; int rawData, oldRawData; protoTime rawTimestamp; protoTime deltaLowTime; protoTime deltaHighTime; int actRawdataTimeBufferIndex = 0; int oldRawdataTimeBufferIndex = 0; int possibleBreakPos; struct LDFParser ldfParser; char *compositeConfigurationNamep = NULL; int okf = TRUE; /*init localData*/ localDatap->protoParamsp = (struct LIN_Proto*) paramsp; localDatap->maxSpikeTime = localDatap->protoParamsp->StartValueMaxSpikeTime; localDatap->compareSyncReference = 0; localDatap->maxSyncDiff = 0; localDatap->framedataArray = (LIN_Framedata*) arrayOut; localDatap->framedataFSM = BREAKSYNC_SEARCH; localDatap->framedataIndex = 0; localDatap->rawdataTimeBuffer.possibleBreakPos = localDatap->rawdataTimeBuffer.size = 0; /* --end-- init localData*/ Proto_protoParams_setContext(localDatap->protoParamsp, context); /*allocating LDFstruct*/ if (localDatap->protoParamsp->compositeConfigurationName[0] != '\0') compositeConfigurationNamep = localDatap->protoParamsp->compositeConfigurationName; okf = (okf && (localDatap->protoParamsp->ldfp = (LDFstruct*) PROTO_Alloc(context, sizeof(LDFstruct))) ); okf = (okf && LDF_init(localDatap->protoParamsp->ldfp, &localDatap->protoParamsp->protoInterface, compositeConfigurationNamep)); /*parse ldf file. Done in Process1 (instead of in PROTO_Init()) to avoid multiply parsing.*/ if (localDatap->protoParamsp->ldfFilename[0] != '\0') { okf = (okf && LDFParser_init(&ldfParser, &localDatap->protoParamsp->protoInterface, localDatap->protoParamsp->ldfFilename, LDFPARSER_BUFFER_SIZE)); protoInterface_printf(&localDatap->protoParamsp->protoInterface, "LDFParser: start parsing... [version %s]\n", LDFPARSER_VERSION_STRING); okf = (okf && LDFParser_parse(&ldfParser, localDatap->protoParamsp->ldfp)); LDFParser_message_printState(&ldfParser); LDFParser_destroy(&ldfParser); if (okf == FALSE) return PROTO_PROCESS_CANCEL; } /*wait for HIGH on LIN line*/ do { PROTO_ReadTrace(context, rawIndex, &rawTimestamp, &rawData); rawIndex++; } while (RAWDATA_BITLOW == rawData); oldRawData = rawData; for (; rawIndex < arrayInSize; rawIndex++, cancelCounter++) { if (cancelCounter == PROTO_ASK4CANCEL_MAX_STEPS) { if (PROTO_Cancel(context) != FALSE) return PROTO_PROCESS_CANCEL; cancelCounter = 0; } PROTO_ReadTrace(context, rawIndex, &rawTimestamp, &rawData); /*ignores timestamps with the same raw value*/ if (rawData != oldRawData) { possibleBreakPos = (int) localDatap->rawdataTimeBuffer.possibleBreakPos; actRawdataTimeBufferIndex = Process1_incBufferIndex(possibleBreakPos, (int) localDatap->rawdataTimeBuffer.size); if (RAWDATA_BITLOW == rawData) { localDatap->rawdataTimeBuffer.buffer[actRawdataTimeBufferIndex].fallingEdge = rawTimestamp; if (FALLING1 <= localDatap->rawdataTimeBuffer.size) { deltaHighTime = PROTO_TIME_SUB(rawTimestamp, localDatap->rawdataTimeBuffer.buffer[oldRawdataTimeBufferIndex].risingEdge); /*high level is no spike*/ if ( PROTO_TIME_ISSMALLER(localDatap->maxSpikeTime, deltaHighTime) ) { if (ENSURE_NOSPIKE != localDatap->rawdataTimeBuffer.size) { if (FALLING2 <= localDatap->rawdataTimeBuffer.size) { /*some breakfield possibilities can be approximately discarded (i.e. time between following rising and falling edges (of theoretically syncfield) is longer than 1/8 of possible break field)*/ /*the first time when a high level before this falling edge could be meassured (in Process1_checkApproxBreakPossibility()) is during FALLING2. (high level before FALLING1 would be between possible breakfield and syncfield.)*/ /*the last time when a high level before this falling edge could be meassured (in Process1_checkApproxBreakPossibility()) is during FALLING5. (high level during FALLING5 would be between syncfield and PID field.)*/ if (FALLING5 >= localDatap->rawdataTimeBuffer.size && ! Process1_checkApproxBreakPossibility(localDatap->rawdataTimeBuffer.buffer[possibleBreakPos].deltaLowLevel, deltaHighTime) ) { if (PROTO_PROCESS_OUTOFMEMORY == Process1_interpreteBits(localDatap, arrayOutSize)) return PROTO_PROCESS_OUTOFMEMORY; } else { /*now exact time delays of following falling edges and their differences could be taken into account*/ /*the first time when this could be meassured is at the falling edge of FALLIGN2*/ if ( ! Process1_compareFallingEdgeDelays(localDatap, localDatap->rawdataTimeBuffer.buffer[oldRawdataTimeBufferIndex].fallingEdge, rawTimestamp) ) { if (PROTO_PROCESS_OUTOFMEMORY == Process1_interpreteBits(localDatap, arrayOutSize)) return PROTO_PROCESS_OUTOFMEMORY; } } } } /*ENSURE_NOSPIKE => no spike => therefore breaksync have to be accepted*/ else { /*now, after it has been ensured that last rising edge was no spike, last test have to be done to prove that it is a breakSyncField*/ if( ! Process1_isBreakSyncField(&localDatap->rawdataTimeBuffer, possibleBreakPos, oldRawdataTimeBufferIndex) ) { if (PROTO_PROCESS_OUTOFMEMORY == Process1_interpreteBits(localDatap, arrayOutSize)) return PROTO_PROCESS_OUTOFMEMORY; } else { int tmpIndex = Process1_incBufferIndex(possibleBreakPos, 1); LIN_FramedataInformation framedataInfo; if (arrayOutSize <= localDatap->framedataIndex + 1) /*framedataIndex is pos where next write should happen, but it has to be ensured before write that space is already allocated. (e.g. if framedataIndex == 0 then this is the first entry and it has to be ensured that arrayOutSize is at least 1.*/ return PROTO_PROCESS_OUTOFMEMORY; localDatap->framedataIndex += 2; localDatap->bitTime = Process1_calcBitTime(&localDatap->rawdataTimeBuffer); localDatap->latestBitSampleTime = (protoTime) (PROTO_TIME_TOINT(localDatap->bitTime) * 5 >> 3); /* 10/16 of bitTime*/ localDatap->earliestBitSampleTime = (protoTime) (PROTO_TIME_TOINT(localDatap->bitTime) * 4 >> 3); /* 8/16 of bitTime*/ /*localDatap->maxSpikeTime = (protoTime) (PROTO_TIME_TOINT(localDatap->bitTime) >> 3);*/ /* 2/16 of bitTime*/ localDatap->maxSpikeTime = (protoTime) (PROTO_TIME_TOINT(localDatap->bitTime) >> 5); /* 1/32 of bitTime*/ framedataInfo.flags = FALSE; /*set break- and syncfield in arrayOut*/ Process1_setFrameData(&localDatap->framedataArray[localDatap->framedataIndex - 2], localDatap->rawdataTimeBuffer.buffer[possibleBreakPos].fallingEdge, localDatap->rawdataTimeBuffer.buffer[possibleBreakPos].risingEdge, BREAKFIELD, (unsigned char) 0, framedataInfo); Process1_setFrameData(&localDatap->framedataArray[localDatap->framedataIndex - 1], localDatap->rawdataTimeBuffer.buffer[tmpIndex].fallingEdge, localDatap->rawdataTimeBuffer.buffer[tmpIndex].risingEdge, SYNCFIELD, (unsigned char) 0, framedataInfo); localDatap->rawdataTimeBuffer.possibleBreakPos = actRawdataTimeBufferIndex; localDatap->rawdataTimeBuffer. size = 0; localDatap->framedataFSM = ACCEPT_DATA; localDatap->bitFSM = STARTBIT; localDatap->framedataFieldFSM = DATABYTE; } } } /*spike detected*/ else { localDatap->rawdataTimeBuffer.size--; oldRawdataTimeBufferIndex = Process1_decBufferIndex(oldRawdataTimeBufferIndex, 1); } } } /*RAWDATA_BITHIGH == rawData*/ else { deltaLowTime = PROTO_TIME_SUB(rawTimestamp, localDatap->rawdataTimeBuffer.buffer[actRawdataTimeBufferIndex].fallingEdge); /*was low level a spike?; because of not incrementing localDatap->rawdataTimeBuffer.size in the case of a spike (see below), a spike will be ignored*/ if ( PROTO_TIME_ISSMALLER(localDatap->maxSpikeTime, deltaLowTime) ) { localDatap->rawdataTimeBuffer.buffer[actRawdataTimeBufferIndex].risingEdge = rawTimestamp; localDatap->rawdataTimeBuffer.buffer[actRawdataTimeBufferIndex].deltaLowLevel = deltaLowTime; /*some breakfield possibilities can be approximately discarded (i.e. time between following falling and rising edges (of theoretically syncfield) is longer than 1/8 of possible break field)*/ /*this is also the first time where bits can be interpreted (need size >= FALLING1 to be able to compute RAWDATA_BITHIGH values)*/ if (FALLING1 <= localDatap->rawdataTimeBuffer.size) { if ( ! Process1_checkApproxBreakPossibility(localDatap->rawdataTimeBuffer.buffer[possibleBreakPos].deltaLowLevel, deltaLowTime) ) { if (PROTO_PROCESS_OUTOFMEMORY == Process1_interpreteBits(localDatap, arrayOutSize)) return PROTO_PROCESS_OUTOFMEMORY; } } localDatap->rawdataTimeBuffer.size++; oldRawdataTimeBufferIndex = actRawdataTimeBufferIndex; } /*in case of a spike*/ else; /*localDatap->rawdataTimeBuffer.size and oldRawdataTimeBufferIndex won't be changed*/ } oldRawData = rawData; } } /*interprete remaining bits*/ if (RAWDATA_BITHIGH == rawData) /*if record was truncated in low level => no full byte could have been transmitted (because stopbit is missing)*/ { actRawdataTimeBufferIndex = Process1_incBufferIndex(localDatap->rawdataTimeBuffer.possibleBreakPos, (int) localDatap->rawdataTimeBuffer.size); localDatap->rawdataTimeBuffer.buffer[actRawdataTimeBufferIndex].fallingEdge = rawTimestamp; } Process1_interpreteBits(localDatap, arrayOutSize); return localDatap->framedataIndex; } void PROTOAPI Process1_display(protoContext context, protoPtr pdata, protoPtr params) { const LIN_Framedata *framedatap = (const LIN_Framedata*) pdata; PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL1); switch (framedatap->framedataField) { case (BREAKFIELD) : PROTO_Printf(context, "breakfield"); break; case (SYNCFIELD) : PROTO_Printf(context, "syncfield"); break; case (DATABYTE) : PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Printf(context, "databyte: "); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL1); PROTO_Printf(context, "0x%.2x", framedatap->framedata); if (FALSE != framedatap->framedataInfo.flags) { PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); if (framedatap->framedataInfo.flag.stopbitErrorf) PROTO_Printf(context, " ERROR: stopbit!"); if (framedatap->framedataInfo.flag.bitvaluesErrorf) PROTO_Printf(context, " ERROR: undef bit value!"); } break; } } /** \} */ /** \addtogroup frame */ /** \{ */ static int Process2_nodeFind_byDiag_AssignNAD(LDFstruct *ldfp, struct LIN_Pdu_sf *diagFrameReqDatabytesp, size_t *posp) { size_t pos = 1; struct LIN_SlaveNodeAttributesDef *slaveNodeAttributesDefp = NULL; unsigned short supplierID = 0, functionID = 0; while (slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(ldfp, pos)) { if (slaveNodeAttributesDefp->slaveNodeValid == SLAVENODEDEF_NODEVALID) { if (slaveNodeAttributesDefp->initNAD == diagFrameReqDatabytesp->nad || diagFrameReqDatabytesp->nad == NAD_BROADCAST) { memcpy(&supplierID, &diagFrameReqDatabytesp->d1, sizeof(unsigned short)); if (slaveNodeAttributesDefp->supplierID == LSB16(supplierID) || LSB16(supplierID) == SUPPLIER_WILDCARD) { memcpy(&functionID, &diagFrameReqDatabytesp->d3, sizeof(unsigned short)); if (slaveNodeAttributesDefp->functionID == LSB16(functionID) || LSB16(functionID) == FUNCTION_WILDCARD) { *posp = pos; return TRUE; } } } } pos++; } return FALSE; } static int Process2_frameFind_byDiag_AssignFrameID(LDFstruct *ldfp, struct LIN_Pdu_sf *diagFrameReqDatabytesp, TimeRef timeRef, size_t *posp) { size_t posNodes = 0, posConfiguredFrames = 0; struct LIN_SlaveNodeAttributesDef *slaveNodeAttributesDefp = NULL; unsigned short supplierID = 0, messageID = 0; struct ConfiguredFrame *configuredFramep = NULL; while (LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &posNodes)) { slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(ldfp, posNodes); /*skip if slaveNode is version 2.1 or above*/ if (slaveNodeAttributesDefp->linProtocolVersionMajor < 2 || slaveNodeAttributesDefp->linProtocolVersionMajor == 2 && slaveNodeAttributesDefp->linProtocolVersionMinor == 0) { memcpy(&supplierID, &diagFrameReqDatabytesp->d1, sizeof(unsigned short)); if (slaveNodeAttributesDefp->supplierID == LSB16(supplierID) || LSB16(supplierID) == SUPPLIER_WILDCARD) { memcpy(&messageID, &diagFrameReqDatabytesp->d3, sizeof(unsigned short)); posConfiguredFrames = 0; while (configuredFramep = (struct ConfiguredFrame*) bufferVector_getElementRef(&slaveNodeAttributesDefp->configuredFrames, posConfiguredFrames)) { if (configuredFramep->messageID == LSB16(messageID) || LSB16(messageID) == MESSAGE_WILDCARD) { *posp = configuredFramep->frameIdentPos; return TRUE; } posConfiguredFrames++; } } } posNodes++; } return FALSE; } static int Process2_nodeFind_byDiag_conditionalChangeNAD_hlp_computeDatabyte(unsigned char databyte, struct LIN_Pdu_sf *diagFrameReqDatabytesp) { /*databyte XOR with invert, then AND with mask, then compare with 0*/ if ( (((databyte ^ diagFrameReqDatabytesp->d4) & diagFrameReqDatabytesp->d3) & 0xFF) == 0 ) return TRUE; return FALSE; } static int Process2_nodeFind_byDiag_conditionalChangeNAD(LDFstruct *ldfp, struct LIN_Pdu_sf *diagFrameReqDatabytesp, TimeRef timeRef, size_t *posp) { size_t posNodes = 0; struct LIN_SlaveNodeAttributesDef *slaveNodeAttributesDefp = NULL; int selectedDatabyte = 0; if (diagFrameReqDatabytesp->d2 > 5) return FALSE; /*diagFrameReqDatabytesp->d1==0 means LIN Product Identification*/ if (diagFrameReqDatabytesp->d1 == 0) { while (LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &posNodes)) { slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(ldfp, posNodes); switch (diagFrameReqDatabytesp->d2) { case 1 : selectedDatabyte = slaveNodeAttributesDefp->supplierID & 0xFF; break; case 2 : selectedDatabyte = slaveNodeAttributesDefp->supplierID >> 8; break; case 3 : selectedDatabyte = slaveNodeAttributesDefp->functionID & 0xFF; break; case 4 : selectedDatabyte = slaveNodeAttributesDefp->functionID >> 8; break; case 5: selectedDatabyte = slaveNodeAttributesDefp->variantID; break; } if (Process2_nodeFind_byDiag_conditionalChangeNAD_hlp_computeDatabyte((unsigned char) selectedDatabyte, diagFrameReqDatabytesp)) { *posp = posNodes; return TRUE; } posNodes++; } } /*nodes with version 2.0 support diagFrameReqDatabytesp->d1 from 16 to 31*/ else if (diagFrameReqDatabytesp->d1 >= 16 && diagFrameReqDatabytesp->d1 <= 31) { while (LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &posNodes)) { slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(ldfp, posNodes); /*if slave node version <= 2.0*/ if (slaveNodeAttributesDefp->linProtocolVersionMajor < 2 || slaveNodeAttributesDefp->linProtocolVersionMajor == 2 && slaveNodeAttributesDefp->linProtocolVersionMinor == 0) { struct ConfiguredFrame *configuredFramep = NULL; int databyteFoundf = TRUE; configuredFramep = (struct ConfiguredFrame*) bufferVector_getElementRef(&slaveNodeAttributesDefp->configuredFrames, diagFrameReqDatabytesp->d1 - 16); if (configuredFramep) { switch (diagFrameReqDatabytesp->d2) { case 1 : selectedDatabyte = configuredFramep->messageID & 0xFF; break; case 2 : selectedDatabyte = configuredFramep->messageID >> 8; break; case 3 : { struct LIN_FrameDef *frameDefp = LDF_frameDef_getRef(ldfp, configuredFramep->frameIdentPos); struct LIN_FrameID *frameIDp = NULL; size_t pos = 0; databyteFoundf = FALSE; if (frameDefp->frameValidf) { while (frameIDp = bufferVector_getElementRef(&frameDefp->frameIDs, pos)) { if (LDF_timeRefCheck(timeRef, frameIDp->startTimeRef, frameIDp->endTimeRef)) { selectedDatabyte = linPidCalc(frameIDp->id); databyteFoundf = TRUE; break; } } } } break; case 4 : selectedDatabyte = 0xFF; break; case 5: selectedDatabyte = 0xFF; break; } if (databyteFoundf && Process2_nodeFind_byDiag_conditionalChangeNAD_hlp_computeDatabyte((unsigned char) selectedDatabyte, diagFrameReqDatabytesp)) { *posp = posNodes; return TRUE; } } } posNodes++; } } /*diag service computes unknown data (known data only with diagFrameReqDatabytesp->d1 equal 0 or in the range of message IDs) => if more than one node will be found (matching NAD) we don't know which was responding => unknown behaviour. The serial number of the node (diagFrameReqDatabytesp->d1==1) is also unknown. */ else { size_t tmpPos = 0; if (LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &posNodes)) { tmpPos = posNodes + 1; /*if more than one slave node with the same configured NAD are found (in case of unknown data), we don't know which slave node responded*/ if (FALSE == LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &tmpPos)) { *posp = posNodes; return TRUE; } } } return FALSE; } static int Process2_nodeFind_byDiag_assignFrameIdRange(LDFstruct *ldfp, struct LIN_Pdu_sf *diagFrameReqDatabytesp, TimeRef timeRef, size_t *posp) { size_t posNodes = 0, tmpPos = 0; if (LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &posNodes)) { tmpPos = posNodes + 1; /*if more than one slave node with the same configured NAD are found (in case of unknown data), we don't know which slave node responded*/ if (FALSE == LDF_nodeFind_ByConfiguredNADTimeref(ldfp, diagFrameReqDatabytesp->nad, timeRef, &tmpPos)) { *posp = posNodes; return TRUE; } } return FALSE; } /** Interprets the current diagnostic frame especially if they are configuration services. */ static int Process2_diagnosticFrame_interprete(struct LIN_Proto *protoParamsp, struct Process2_LocalData *localDatap) { struct LIN_Pdu_sf *diagFrameDatabytesp = NULL; if (localDatap->actFramep->nrDatabytes > DATABYTES_MAX_NUMBER_NORMAL) diagFrameDatabytesp = (struct LIN_Pdu_sf*) (localDatap->actFramep->data.databytesp); else diagFrameDatabytesp = (struct LIN_Pdu_sf*) (localDatap->actFramep->data.databytes); /*SID and NAD in range of configuration services*/ if ((diagFrameDatabytesp->sid >= 0xB0 && diagFrameDatabytesp->sid <= 0xB7 || diagFrameDatabytesp->sid >= 0xB0 + 0x40 && diagFrameDatabytesp->sid <= 0xB7 + 0x40) && (diagFrameDatabytesp->nad <= 0x7F && diagFrameDatabytesp->nad != 0x00 && diagFrameDatabytesp->nad != 0x7E)) { /*if request*/ if (diagFrameDatabytesp->sid < 0xB0 + 0x40) { localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_NOT_DEFINED; localDatap->lastDiagReqp = NULL; switch (diagFrameDatabytesp->sid) { /*assign NAD*/ case 0xB0 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*assign frame identifier (only v2.0)*/ case 0xB1 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*read by identifier*/ case 0xB2 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*Conditional change NAD*/ case 0xB3 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*Data Dump*/ case 0xB4 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*Assign NAD via SNPD ??*/ case 0xB5 : break; /*Save Configuration*/ case 0xB6 : if (diagFrameDatabytesp->pci == 1) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; /*Assign frame ID range*/ case 0xB7 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_REQ_OK; break; } if (localDatap->actFramep->pduType == PROTOPDU_DIAG_REQ_OK) localDatap->lastDiagReqp = diagFrameDatabytesp; } /*if response*/ else { if (localDatap->lastDiagReqp == NULL) localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_WITHOUT_REQ; else { struct LIN_SlaveNodeAttributesDef *slaveNodeAttributesDefp = NULL; struct LIN_FrameDef *linFrameDefp = NULL; size_t pos = 0; unsigned int serviceInfoStrLen = 0; char *cp = NULL; localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_NOT_DEFINED; switch (diagFrameDatabytesp->sid) { /*assign NAD*/ case 0xB0 + 0x40 : if (diagFrameDatabytesp->pci == 1) { localDatap->actTimeRef++; if (Process2_nodeFind_byDiag_AssignNAD(protoParamsp->ldfp, localDatap->lastDiagReqp, &pos)) { slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; if (FALSE == LDF_configuredNAD_append(protoParamsp->ldfp, slaveNodeAttributesDefp, localDatap->lastDiagReqp->d5, localDatap->actTimeRef)) return FALSE; serviceInfoStrLen = strlen(slaveNodeAttributesDefp->nodeIdent) + 2 + 4 + 4 + 6 + 1; cp = protoInterface_alloc(&protoParamsp->protoInterface, serviceInfoStrLen); if (cp == NULL) return FALSE; if (-1 == wrapper_snprintf(cp, serviceInfoStrLen, "'%s' <- 0x%02hhX (NAD)", slaveNodeAttributesDefp->nodeIdent, localDatap->lastDiagReqp->d5)) cp[serviceInfoStrLen - 1] = '\0'; localDatap->actFramep->diagServiceStringp = cp; } else localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_UNKNOWN_RESULT; } break; /*assign frame identifier (v2.0)*/ case 0xB1 + 0x40 : if (diagFrameDatabytesp->pci == 1 ) { localDatap->actTimeRef++; if (Process2_frameFind_byDiag_AssignFrameID(protoParamsp->ldfp, localDatap->lastDiagReqp, localDatap->actTimeRef - 1, &pos)) { linFrameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, pos); localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; if (FALSE == LDF_frameID_append(protoParamsp->ldfp, linFrameDefp, (unsigned char) (localDatap->lastDiagReqp->d5 & LIN_PID_ID_MASK), localDatap->actTimeRef)) return FALSE; serviceInfoStrLen = strlen(linFrameDefp->frameIdent) + 2 + 4 + 4 + 5 + 1; cp = protoInterface_alloc(&protoParamsp->protoInterface, serviceInfoStrLen); if (cp == NULL) return FALSE; if (-1 == wrapper_snprintf(cp, serviceInfoStrLen, "'%s' <- 0x%02hhX (ID)", linFrameDefp->frameIdent, (unsigned char) (localDatap->lastDiagReqp->d5 & LIN_PID_ID_MASK))) cp[serviceInfoStrLen - 1] = '\0'; localDatap->actFramep->diagServiceStringp = cp; } else localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_UNKNOWN_RESULT; } break; /*read by identifier*/ case 0xB2 + 0x40 : localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; break; /*Conditional change NAD*/ case 0xB3 + 0x40 : localDatap->actTimeRef++; if (Process2_nodeFind_byDiag_conditionalChangeNAD(protoParamsp->ldfp, localDatap->lastDiagReqp, localDatap->actTimeRef - 1, &pos)) { slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; if (FALSE == LDF_configuredNAD_append(protoParamsp->ldfp, slaveNodeAttributesDefp, localDatap->lastDiagReqp->d5, localDatap->actTimeRef)) return FALSE; serviceInfoStrLen = strlen(slaveNodeAttributesDefp->nodeIdent) + 2 + 4 + 4 + 6 + 1; cp = protoInterface_alloc(&protoParamsp->protoInterface, serviceInfoStrLen); if (cp == NULL) return FALSE; if (-1 == wrapper_snprintf(cp, serviceInfoStrLen, "'%s' <- 0x%02hhX (NAD)", slaveNodeAttributesDefp->nodeIdent, localDatap->lastDiagReqp->d5)) cp[serviceInfoStrLen - 1] = '\0'; localDatap->actFramep->diagServiceStringp = cp; } else localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_UNKNOWN_RESULT; break; /*Data Dump*/ case 0xB4 + 0x40 : if (diagFrameDatabytesp->pci == 6) localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; break; /*Assign NAD via SNPD ??*/ case 0xB5 + 0x40 : localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_UNKNOWN_RESULT; break; /*Save Configuration*/ case 0xB6 + 0x40 : if (diagFrameDatabytesp->pci == 1) localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; break; /*Assign frame ID range*/ case 0xB7 + 0x40 : localDatap->actTimeRef++; if (diagFrameDatabytesp->pci == 1) { if (Process2_nodeFind_byDiag_assignFrameIdRange(protoParamsp->ldfp, localDatap->lastDiagReqp, localDatap->actTimeRef - 1, &pos)) { struct ConfiguredFrame *configuredFramep = NULL; struct LIN_FrameDef *frameDefp = NULL; size_t posConfiguredFrames = localDatap->lastDiagReqp->d1; int n, ret = 0, stringOffset = 0; slaveNodeAttributesDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_POS; for (n=0; n<4; n++) { configuredFramep = (struct ConfiguredFrame*) bufferVector_getElementRef(&slaveNodeAttributesDefp->configuredFrames, posConfiguredFrames + n); if (configuredFramep == NULL) break; frameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, configuredFramep->frameIdentPos); if ((&localDatap->lastDiagReqp->d2)[n] != 0xFF) { LDF_frameID_append(protoParamsp->ldfp, frameDefp, (unsigned char) ((&localDatap->lastDiagReqp->d2)[n] & LIN_PID_ID_MASK), localDatap->actTimeRef); serviceInfoStrLen += strlen(frameDefp->frameIdent) + 13; } } /*only if any ID was changed*/ if (serviceInfoStrLen > 0) { serviceInfoStrLen += -1 + 6; cp = protoInterface_alloc(&protoParamsp->protoInterface, serviceInfoStrLen); if (cp == NULL) return FALSE; localDatap->actFramep->diagServiceStringp = cp; for (n=0; n<4; n++) { configuredFramep = (struct ConfiguredFrame*) bufferVector_getElementRef(&slaveNodeAttributesDefp->configuredFrames, posConfiguredFrames + n); if (configuredFramep == NULL) break; frameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, configuredFramep->frameIdentPos); /*diable ID*/ if ((&localDatap->lastDiagReqp->d2)[n] == 0x00) ret = wrapper_snprintf(cp + stringOffset, serviceInfoStrLen - stringOffset, "'%s' disabled, ", frameDefp->frameIdent); /*assign ID*/ else if ((&localDatap->lastDiagReqp->d2)[n] != 0xFF) ret = wrapper_snprintf(cp + stringOffset, serviceInfoStrLen - stringOffset, "'%s' <- 0x%02hhX, ", frameDefp->frameIdent, (unsigned char) ((&localDatap->lastDiagReqp->d2)[n] & LIN_PID_ID_MASK)); if ((&localDatap->lastDiagReqp->d2)[n] != 0xFF) { if (ret <= 0) break; else stringOffset += ret; } } for (n=0; cp[serviceInfoStrLen - 6 - n] != ','; n++); cp[serviceInfoStrLen - 6 - n] = ' '; /*overwrites the last comma and appends " (IDs)" including ending '\0'*/ memcpy(cp + serviceInfoStrLen - 6, "(IDs)", 6); } } else localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_UNKNOWN_RESULT; } break; /*negative response of 'read by identifier'*/ case 0x7F : if (diagFrameDatabytesp->pci == 3 && diagFrameDatabytesp->d1 == 0xB2) localDatap->actFramep->pduType = PROTOPDU_DIAG_RESP_NEG; break; } } } } /*other PDU frame*/ else { if ((diagFrameDatabytesp->pci & 0xF0) == 0x00) localDatap->actFramep->pduType = PROTOPDU_SF; else if ((diagFrameDatabytesp->pci & 0xF0) == 0x20) localDatap->actFramep->pduType = PROTOPDU_CF; else if ((diagFrameDatabytesp->pci & 0xF0) == 0x10) localDatap->actFramep->pduType = PROTOPDU_FF; else localDatap->actFramep->pduType = PROTOPDU_UNKNOWNPCI; } return TRUE; } static int Process2_ProtoFrame_init(struct LIN_Proto *protoParamsp, struct Proto_Frame *framep) { framep->time = 0; framep->endTime = 0; framep->timeRef = 0; framep->infoFlags = FALSE; framep->pduType = PROTOPDU_NORMALFRAME; framep->diagServiceStringp = NULL; framep->id = 0; framep->nrDatabytes = 0; framep->data.databytesp = NULL; framep->checksum = 0; return TRUE; } static int Process2_localData_init(struct LIN_Proto *protoParamsp, struct Process2_LocalData *localDatap) { localDatap->acceptFramedataFSM = FRAME_BREAK; localDatap->outPos = 0; localDatap->outSize = 0; localDatap->actFramedatap = NULL; localDatap->actFramep = NULL; localDatap->actLinFrameDefp = NULL; localDatap->actTimeRef = 0; localDatap->accumulatedChecksum = 0; localDatap->checksumProcessedf = FALSE; localDatap->startTime = 0; localDatap->endTime = 0; localDatap->lastDiagReqp = NULL; if (FALSE == bufferVector_init(&localDatap->databytesBuffer, sizeof(char), 8*8, &protoParamsp->protoInterface)) return FALSE; return TRUE; } static unsigned char* Process2_getDatabytesRef(struct Proto_Frame *framep) { if (framep->nrDatabytes > DATABYTES_MAX_NUMBER_NORMAL) return framep->data.databytesp; else return framep->data.databytes; } static int Process2_insertNewFrame(struct LIN_Proto *protoParamsp, struct Process2_LocalData *localDatap) { /*"add" one output entry*/ localDatap->outPos++; localDatap->actFramep++; localDatap->actLinFrameDefp = NULL; localDatap->checksumProcessedf = FALSE; /*output array too small*/ if (localDatap->outPos > localDatap->outSize) return PROTO_PROCESS_OUTOFMEMORY; if (FALSE == Process2_ProtoFrame_init(protoParamsp, localDatap->actFramep)) return PROTO_PROCESS_CANCEL; localDatap->actFramep->timeRef = localDatap->actTimeRef; return PROTO_OK; } /** Completes the current frame. */ static int Process2_completeActFrame(struct LIN_Proto *protoParamsp, struct Process2_LocalData *localDatap) { char *cp = NULL; struct Proto_Frame *actFramep = localDatap->actFramep; size_t actReadBytes = actFramep->nrDatabytes; /*if some output entry exist and has to be completed*/ if (localDatap->outPos != 0) { actFramep->time = localDatap->startTime; actFramep->endTime = localDatap->endTime; if (actReadBytes > DATABYTES_MAX_NUMBER_NORMAL) { cp = protoInterface_alloc(&protoParamsp->protoInterface, actReadBytes); if (cp == NULL) return FALSE; memcpy(cp, actFramep->data.databytes, DATABYTES_MAX_NUMBER_NORMAL); bufferVector_getElementsCopy(&localDatap->databytesBuffer, cp + DATABYTES_MAX_NUMBER_NORMAL, 0, actReadBytes - DATABYTES_MAX_NUMBER_NORMAL); actFramep->data.databytesp = cp; } /*only in this cases localDatap->actLinFrameDefp was set*/ if ((localDatap->actFramep->infoFlags & (PROTOFRAME_NOT_ASSOCIATED | PROTOFRAME_PID_ERROR | PROTOFRAME_UNUSED_TRAFFIC)) == FALSE) { if (actReadBytes < localDatap->actLinFrameDefp->frameSize || localDatap->checksumProcessedf == FALSE) localDatap->actFramep->infoFlags |= PROTOFRAME_NOT_COMPLETE; else if (localDatap->actLinFrameDefp->frameType == FRAMETYPE_DIAGNOSTIC) { /*static unsigned DEBUGcounter = 0; union LIN_Pdu *db = (union LIN_Pdu*) Process2_getDatabytesRef(actFramep); switch (DEBUGcounter++) { case 0: db->sf.nad = 0x01; db->sf.pci = 0x06; db->sf.sid = 0xb7; db->sf.d1 = 0x01; db->sf.d2 = 0x1f; db->sf.d3 = 0xff; db->sf.d4 = 0x0b; db->sf.d5 = 0x00; break; case 1: db->sf.nad = 0x01; db->sf.pci = 0x01; db->sf.sid = 0xf7; db->sf.d1 = 0xff; db->sf.d2 = 0xff; db->sf.d3 = 0xff; db->sf.d4 = 0xff; db->sf.d5 = 0xff; break; }*/ if (FALSE == Process2_diagnosticFrame_interprete(protoParamsp, localDatap)) return FALSE; } /*checks for event triggered frames*/ else if (localDatap->actLinFrameDefp->frameType == FRAMETYPE_EVENTTRIGGERED) { unsigned char *databytesp = NULL; size_t pos; databytesp = Process2_getDatabytesRef(localDatap->actFramep); /*checks if some frame is added to event triggered frame*/ if (bufferVector_getActSize(&localDatap->actLinFrameDefp->includedData) == 0) localDatap->actFramep->infoFlags |= PROTOFRAME_EVENTFRAME_NO_FRAME_ADDED; else { /*check PID of event triggered frame (first databyte)*/ if (databytesp[0] != linPidCalc(databytesp[0])) localDatap->actFramep->infoFlags |= PROTOFRAME_EVENTFRAME_PID_ERROR; else if (FALSE == LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, (unsigned char) (databytesp[0] & LIN_PID_ID_MASK), localDatap->actFramep->timeRef, &pos)) localDatap->actFramep->infoFlags |= PROTOFRAME_EVENTFRAME_ID_NOT_ADDED; /*search within included frames (of event triggered frame) for this frame*/ else { unsigned int n = 0; union LIN_IncludedData *includedDatap = NULL; while (includedDatap = (union LIN_IncludedData*) bufferVector_getElementRef(&localDatap->actLinFrameDefp->includedData, n)) { if (includedDatap->includedFrame.frameIdentPos == pos) break; n++; } if (n == bufferVector_getActSize(&localDatap->actLinFrameDefp->includedData)) localDatap->actFramep->infoFlags |= PROTOFRAME_EVENTFRAME_ID_NOT_ADDED; } } } } bufferVector_clear(&localDatap->databytesBuffer); } return TRUE; } protoSizeT PROTOAPI Process2_process(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr paramsp) { struct LIN_Proto *protoParamsp = (struct LIN_Proto*) paramsp; struct Process2_LocalData localData, *localDatap = &localData; int inPos = 0; unsigned int cancelCounter = 0; size_t framePos = 0; int ret; Proto_protoParams_setContext(protoParamsp, context); if (FALSE == Process2_localData_init(protoParamsp, localDatap)) return PROTO_PROCESS_CANCEL; localDatap->actFramedatap = (struct LIN_Framedata*) arrayIn; localDatap->actFramep = (struct Proto_Frame*) arrayOut - 1; localDatap->outSize = arrayOutSize; while (localDatap->actFramedatap->framedataField != BREAKFIELD) { localDatap->actFramedatap++; inPos++; } for (; inPos < arrayInSize; inPos++, localDatap->actFramedatap++) { if (cancelCounter == PROTO_ASK4CANCEL_MAX_STEPS) { if (PROTO_Cancel(context) != FALSE) return PROTO_PROCESS_CANCEL; cancelCounter = 0; } switch(localDatap->actFramedatap->framedataField) { case DATABYTE : /*databyte of frame OR unexpected databyte (= unused/unknown bus traffic)*/ if (localDatap->acceptFramedataFSM == FRAME_DATABYTE || localDatap->acceptFramedataFSM == FRAME_DATABYTE_UNUSED || localDatap->acceptFramedataFSM == FRAME_BREAK) { /*first databyte of unexpected databytes => Proto_Frame hast to be inserted*/ if (localDatap->acceptFramedataFSM == FRAME_BREAK) { localDatap->acceptFramedataFSM = FRAME_DATABYTE_UNUSED; if (FALSE == Process2_completeActFrame(protoParamsp, localDatap)) return PROTO_PROCESS_CANCEL; ret = Process2_insertNewFrame(protoParamsp, localDatap); if (ret != PROTO_OK) return ret; localDatap->startTime = localDatap->actFramedatap->time; localDatap->actFramep->infoFlags |= PROTOFRAME_UNUSED_TRAFFIC; } localDatap->endTime = localDatap->actFramedatap->endTime; /*some bit errors detected in Process1*/ if (localDatap->actFramedatap->framedataInfo.flags != FALSE) localDatap->actFramep->infoFlags |= PROTOFRAME_BIT_ERROR; /*databyte, i.e. not the checksum byte*/ if (localDatap->acceptFramedataFSM == FRAME_DATABYTE_UNUSED || localDatap->actFramep->nrDatabytes + 1 <= localDatap->actLinFrameDefp->frameSize) { localDatap->actFramep->nrDatabytes++; /*accumulate checksum*/ localDatap->accumulatedChecksum += localDatap->actFramedatap->framedata; if (localDatap->accumulatedChecksum < localDatap->actFramedatap->framedata) localDatap->accumulatedChecksum++; /*normal case, nrDataBytes smaller or equal as DATABYTES_MAX_NUMBER_NORMAL*/ if (localDatap->actFramep->nrDatabytes <= DATABYTES_MAX_NUMBER_NORMAL) localDatap->actFramep->data.databytes[localDatap->actFramep->nrDatabytes - 1] = localDatap->actFramedatap->framedata; /*more than DATABYTES_MAX_NUMBER_NORMAL + 1 checksum byte => next databytes has to be buffered*/ else { char *cp = NULL; cp = bufferVector_appendEmptyElements(&localDatap->databytesBuffer, 1); if (cp == NULL) return PROTO_PROCESS_CANCEL; *cp = localDatap->actFramedatap->framedata; } } /*checksum byte*/ else { localDatap->checksumProcessedf = TRUE; localDatap->actFramep->checksum = localDatap->actFramedatap->framedata; localDatap->accumulatedChecksum = ~localDatap->accumulatedChecksum; if (localDatap->accumulatedChecksum != localDatap->actFramedatap->framedata) localDatap->actFramep->infoFlags |= PROTOFRAME_CHECKSUM_ERROR; localDatap->acceptFramedataFSM = FRAME_BREAK; } } else if (localDatap->acceptFramedataFSM == FRAME_ID) { localDatap->acceptFramedataFSM = FRAME_DATABYTE; localDatap->endTime = localDatap->actFramedatap->endTime; ret = Process2_insertNewFrame(protoParamsp, localDatap); if (ret != PROTO_OK) return ret; if (localDatap->actFramedatap->framedataInfo.flags) localDatap->actFramep->infoFlags |= PROTOFRAME_BIT_ERROR; /*Parity of ID ok*/ if (linPidCalc(localDatap->actFramedatap->framedata) == localDatap->actFramedatap->framedata) { localDatap->actFramep->id = localDatap->actFramedatap->framedata & LIN_PID_ID_MASK; /*ID associated with frame*/ if (LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, localDatap->actFramep->id, localDatap->actTimeRef, &framePos)) { localDatap->actLinFrameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, framePos); if (localDatap->actLinFrameDefp->checksumType == CHECKSUMTYPE_CLASSIC) localDatap->accumulatedChecksum = 0; else localDatap->accumulatedChecksum = localDatap->actFramedatap->framedata; } else { localDatap->actFramep->infoFlags |= PROTOFRAME_NOT_ASSOCIATED; localDatap->acceptFramedataFSM = FRAME_BREAK; } } /*Parity error of ID*/ else { localDatap->actFramep->id = localDatap->actFramedatap->framedata; /*stores PID instead of ID*/ localDatap->actFramep->infoFlags |= PROTOFRAME_PID_ERROR; localDatap->acceptFramedataFSM = FRAME_BREAK; } } break; case BREAKFIELD : if (FALSE == Process2_completeActFrame(protoParamsp, localDatap)) return PROTO_PROCESS_CANCEL; localDatap->acceptFramedataFSM = FRAME_SYNC; localDatap->startTime = localDatap->actFramedatap->time; localDatap->endTime = localDatap->actFramedatap->endTime; break; case SYNCFIELD : if (localDatap->acceptFramedataFSM == FRAME_SYNC) { localDatap->acceptFramedataFSM = FRAME_ID; localDatap->endTime = localDatap->actFramedatap->endTime; } else localDatap->acceptFramedataFSM = FRAME_BREAK; break; } } if (localDatap->acceptFramedataFSM != FRAME_SYNC) { if (FALSE == Process2_completeActFrame(protoParamsp, localDatap)) return PROTO_PROCESS_CANCEL; } return localDatap->outPos; } void PROTOAPI Process2_display(protoContext context, protoPtr pdata, protoPtr paramsp) { struct Proto_Frame *framep = (struct Proto_Frame*) pdata; struct LIN_Proto *protoParamsp = paramsp; struct LIN_FrameDef *frameDefp = NULL; size_t pos; char *databytesp = NULL; int n; /*Proto_protoParams_setContext(protoParamsp, context);*/ /*print ID*/ if ((framep->infoFlags & PROTOFRAME_UNUSED_TRAFFIC) == FALSE) { PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL2); if (framep->infoFlags & PROTOFRAME_PID_ERROR) PROTO_Printf(context, "PID: 0x%02hhX ", (unsigned char) framep->id); else PROTO_Printf(context, "ID: 0x%02hhX ", (unsigned char) framep->id); if (LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, framep->id, framep->timeRef, &pos)) { frameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, pos); PROTO_Printf(context, "(%s)", frameTypeStrings[frameDefp->frameType]); } else PROTO_Printf(context, "(%s)", frameTypeStrings[FRAMETYPE_NOTDEFINED]); } /*print unused bus traffic*/ else { PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Printf(context, "%hu data bytes", framep->nrDatabytes); } /*print databytes*/ databytesp = Process2_getDatabytesRef(framep); for (n=0; nnrDatabytes; n++) PROTO_Printf(context, ", 0x%02hhX", (unsigned char) databytesp[n]); if (framep->infoFlags & PROTOFRAME_ERROR_ALL) { PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context," "); PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); if (framep->infoFlags & PROTOFRAME_BIT_ERROR) PROTO_Puts(context, "Physical bit error! "); if (framep->infoFlags & PROTOFRAME_PID_ERROR) PROTO_Puts(context, "PID error! "); if (framep->infoFlags & PROTOFRAME_NOT_COMPLETE) PROTO_Printf(context, "Frame incomplete, %hu data byte(s) + checksum are missing! ", frameDefp->frameSize - framep->nrDatabytes); if (framep->infoFlags & PROTOFRAME_NOT_ASSOCIATED) PROTO_Puts(context, "ID not defined! "); if (framep->infoFlags & PROTOFRAME_CHECKSUM_ERROR) PROTO_Puts(context, "Checksum eror! "); if ((framep->infoFlags & PROTOFRAME_EVENTFRAME_ERROR_ALL) == PROTOFRAME_EVENTFRAME_NO_FRAME_ADDED) PROTO_Puts(context, "Event triggered frame has no triggered frame defined! "); if ((framep->infoFlags & PROTOFRAME_EVENTFRAME_ERROR_ALL) == PROTOFRAME_EVENTFRAME_PID_ERROR) PROTO_Printf(context, "Event triggered frame PID (0x%02hhX) error! ", (unsigned char) databytesp[0]); if ((framep->infoFlags & PROTOFRAME_EVENTFRAME_ERROR_ALL) == PROTOFRAME_EVENTFRAME_ID_NOT_ADDED) PROTO_Printf(context, "Frame ID (0x%02hhX) not added to event triggered frame! ", (unsigned char) (databytesp[0] & LIN_PID_ID_MASK)); } } /** \} */ /** \addtogroup frameAssociate */ /** \{ */ static int Process3_ProtoFrameAssoc_init(struct LIN_Proto *protoParamsp, struct Proto_FrameAssoc *frameAssocp) { frameAssocp->time = 0; frameAssocp->infoFlags = FALSE; frameAssocp->pduCounterOnError = 0; frameAssocp->linFrameDefp = NULL; frameAssocp->pduSlaveNodeDefp = NULL; if (FALSE == bufferVector_init(&frameAssocp->includedFrames, sizeof(struct IncludedFrame), DATAFRAMES_BUFFER_INIT_SIZE, &protoParamsp->protoInterface)) return FALSE; return TRUE; } static int Process3_localData_init(struct LIN_Proto *protoParamsp, struct Process3_LocalData *localDatap) { localDatap->actFramep = NULL; localDatap->actFrameAssocp = NULL; localDatap->actFrameDefp = NULL; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; localDatap->pduCounter = 0; localDatap->pduRemainingLength = 0; localDatap->outPos = 0; localDatap->outSize = 0; return TRUE; } static int Process3_insertNewFrameAssoc(struct LIN_Proto *protoParamsp, struct Process3_LocalData *localDatap) { localDatap->outPos++; localDatap->actFrameAssocp++; if (localDatap->outPos > localDatap->outSize) return PROTO_PROCESS_OUTOFMEMORY; if (FALSE == Process3_ProtoFrameAssoc_init(protoParamsp, localDatap->actFrameAssocp)) return PROTO_PROCESS_CANCEL; return PROTO_OK; } static int Process3_completeActFrameAssoc(struct LIN_Proto *protoParamsp, struct Process3_LocalData *localDatap, protoTime endTime) { int ret; ret = Process3_insertNewFrameAssoc(protoParamsp, localDatap); if (ret == PROTO_OK) { localDatap->actFrameAssocp->infoFlags = PROTOFRAMEASSOC_FRAME_END_MARKER; localDatap->actFrameAssocp->time = endTime; ret = Process3_insertNewFrameAssoc(protoParamsp, localDatap); } return ret; } protoSizeT PROTOAPI Process3_process(protoContext context, protoPtr arrayOut, protoSizeT arrayOutSize, protoPtr arrayIn, protoSizeT arrayInSize, protoPtr paramsp) { struct LIN_Proto *protoParamsp = (struct LIN_Proto*) paramsp; struct Process3_LocalData localData, *localDatap = &localData; int inPos = 0; size_t pos; unsigned int cancelCounter = 0; struct IncludedFrame *includedFramep = NULL; int ret; Proto_protoParams_setContext(protoParamsp, context); if (FALSE == Process3_localData_init(protoParamsp, localDatap)) return PROTO_PROCESS_CANCEL; localDatap->actFramep = (struct Proto_Frame*) arrayIn; localDatap->actFrameAssocp = (struct Proto_FrameAssoc*) arrayOut - 1; localDatap->outSize = arrayOutSize; /*insert dummy entry end of frame to force the IDLE line to be the first in chart display*/ Process3_insertNewFrameAssoc(protoParamsp, localDatap); localDatap->actFrameAssocp->infoFlags = PROTOFRAMEASSOC_FRAME_END_MARKER; Process3_insertNewFrameAssoc(protoParamsp, localDatap); for (inPos=0; inPosactFramep++) { if (cancelCounter == PROTO_ASK4CANCEL_MAX_STEPS) { if (PROTO_Cancel(context) != FALSE) return PROTO_PROCESS_CANCEL; cancelCounter = 0; } /*error in previous processing level, unused/unknown bus traffic, unknown PCI*/ if (localDatap->actFramep->infoFlags & (PROTOFRAME_ERROR_ALL | PROTOFRAME_UNUSED_TRAFFIC) || localDatap->actFramep->pduType == PROTOPDU_UNKNOWNPCI) { /*expected PDU with CF but that did not happen because of an error => mark error and process this localDatap->actFramep*/ if (localDatap->frameAssocFSM == FRAMEASSOC_PDU_FOLLOWS) { localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; ret = Process3_completeActFrameAssoc(protoParamsp, localDatap, (localDatap->actFramep-1)->endTime); if (ret != PROTO_OK) return ret; } localDatap->actFrameAssocp->time = localDatap->actFramep->time; localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_FRAME; if (localDatap->actFramep->infoFlags & PROTOFRAME_UNUSED_TRAFFIC) localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_UNUSED_TRAFFIC; else if ((localDatap->actFramep->infoFlags & (PROTOFRAME_PID_ERROR | PROTOFRAME_NOT_ASSOCIATED)) == FALSE) { LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, localDatap->actFramep->id, localDatap->actFramep->timeRef, &pos); localDatap->actFrameAssocp->linFrameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, pos); } includedFramep = bufferVector_appendEmptyElements(&localDatap->actFrameAssocp->includedFrames, 1); if (includedFramep == NULL) return PROTO_PROCESS_CANCEL; includedFramep->framep = localDatap->actFramep; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else { LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, localDatap->actFramep->id, localDatap->actFramep->timeRef, &pos); localDatap->actFrameDefp = LDF_frameDef_getRef(protoParamsp->ldfp, pos); /*expected PDU with CF but that did not happen => mark error and process this localDatap->actFramep normally*/ if (localDatap->frameAssocFSM == FRAMEASSOC_PDU_FOLLOWS && localDatap->actFramep->pduType != PROTOPDU_CF) { localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; ret = Process3_completeActFrameAssoc(protoParamsp, localDatap, (localDatap->actFramep-1)->endTime); if (ret != PROTO_OK) return ret; } includedFramep = bufferVector_appendEmptyElements(&localDatap->actFrameAssocp->includedFrames, 1); if (includedFramep == NULL) return PROTO_PROCESS_CANCEL; includedFramep->framep = localDatap->actFramep; if (localDatap->actFramep->pduType == PROTOPDU_NORMALFRAME) { localDatap->actFrameAssocp->time = localDatap->actFramep->time; localDatap->actFrameAssocp->linFrameDefp = localDatap->actFrameDefp; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } /*any PDU which is a SF*/ else if ((localDatap->actFramep->pduType >= PROTOPDU_DIAG_REQ_OK && localDatap->actFramep->pduType <= PROTOPDU_DIAG_RESP_NOT_DEFINED) || localDatap->actFramep->pduType == PROTOPDU_SF) { struct LIN_SlaveNodeAttributesDef *slaveNodeDefp = NULL; struct LIN_Pdu_sf *sfp = NULL; localDatap->actFrameAssocp->time = localDatap->actFramep->time; localDatap->actFrameAssocp->linFrameDefp = localDatap->actFrameDefp; sfp = (struct LIN_Pdu_sf*) Process2_getDatabytesRef(localDatap->actFramep); /*service 'Assign NAD' uses initNAD instead of configuredNAD*/ if (sfp->sid != 0xb0 && sfp->sid != 0xf0) { pos = 0; if (LDF_nodeFind_ByConfiguredNADTimeref(protoParamsp->ldfp, sfp->nad, localDatap->actFramep->timeRef, &pos)) localDatap->actFrameAssocp->pduSlaveNodeDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); } else { if (LDF_nodeFind_ByInitNAD(protoParamsp->ldfp, sfp->nad, &pos)) localDatap->actFrameAssocp->pduSlaveNodeDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); } localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else if (localDatap->actFramep->pduType == PROTOPDU_FF) { struct LIN_Pdu_ff *ffp = NULL; /*if enlarge fails bufferVector_appendEmptyElements has already done the job and has only enlarged as much as needed.*/ bufferVector_enlarge(&localDatap->actFrameAssocp->includedFrames, DATAFRAMES_BUFFER_FIRST_ENLARGE_SIZE); localDatap->actFrameAssocp->time = localDatap->actFramep->time; localDatap->actFrameAssocp->linFrameDefp = localDatap->actFrameDefp; ffp = (struct LIN_Pdu_ff*) Process2_getDatabytesRef(localDatap->actFramep); pos = 0; if (LDF_nodeFind_ByConfiguredNADTimeref(protoParamsp->ldfp, ffp->nad, localDatap->actFramep->timeRef, &pos)) localDatap->actFrameAssocp->pduSlaveNodeDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); localDatap->pduCounter = 1; localDatap->pduRemainingLength = (ffp->pci & 0xF)<<8 | ffp->len; if (localDatap->pduRemainingLength <= 5) { localDatap->pduRemainingLength = 0; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else { localDatap->pduRemainingLength -= 5; localDatap->frameAssocFSM = FRAMEASSOC_PDU_FOLLOWS; } } else if (localDatap->actFramep->pduType == PROTOPDU_CF) { struct LIN_Pdu_cf *cfp = NULL; cfp = (struct LIN_Pdu_cf*) Process2_getDatabytesRef(localDatap->actFramep); if (localDatap->frameAssocFSM != FRAMEASSOC_PDU_FOLLOWS) { localDatap->actFrameAssocp->time = localDatap->actFramep->time; localDatap->actFrameAssocp->linFrameDefp = localDatap->actFrameDefp; localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE; pos = 0; if (LDF_nodeFind_ByConfiguredNADTimeref(protoParamsp->ldfp, cfp->nad, localDatap->actFramep->timeRef, &pos)) localDatap->actFrameAssocp->pduSlaveNodeDefp = LDF_slaveNodeAttributesDef_getRef(protoParamsp->ldfp, pos); localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else { localDatap->pduCounter++; if ((localDatap->pduCounter & 0xF) != (cfp->pci & 0xF)) { localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE_NR; localDatap->actFrameAssocp->pduCounterOnError = localDatap->pduCounter; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else if (localDatap->pduRemainingLength <= 6) { localDatap->pduRemainingLength = 0; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; } else localDatap->pduRemainingLength -= 6; } } } if (localDatap->frameAssocFSM == FRAMEASSOC_FRAMECOMPLETE) { ret = Process3_completeActFrameAssoc(protoParamsp, localDatap, localDatap->actFramep->endTime); if (ret != PROTO_OK) return ret; } } if (localDatap->frameAssocFSM != FRAMEASSOC_FRAMECOMPLETE) { localDatap->actFrameAssocp->infoFlags |= PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE; localDatap->frameAssocFSM = FRAMEASSOC_FRAMECOMPLETE; ret = Process3_completeActFrameAssoc(protoParamsp, localDatap, localDatap->actFramep->endTime); if (ret != PROTO_OK) return ret; } return localDatap->outPos - 1; } static const char* Process3_sidServiceName(unsigned char sid) { int n; for (n=0; nprotoInterface.context; int flags = framep->infoFlags; PROTO_Control(context, PROTO_ATTRIBUTE_ERROR); if (flags & PROTOFRAMEASSOC_ERROR_FRAME) PROTO_Puts(context, " Error!"); if (flags & PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE) PROTO_Puts(context, " PDU sequence error!"); if (flags & PROTOFRAMEASSOC_ERROR_PDU_SEQUENCE_NR) PROTO_Printf(context, " PDU sequence error at frame %hu of PDU!", framep->pduCounterOnError); } /** Encodes and display signals of frame defined by \a *frameDefp. */ static void Process3_displaySignals(struct LIN_Proto *protoParamsp, struct LIN_FrameDef *frameDefp, unsigned char *databytesp) { union LIN_IncludedData *includedDatap = NULL; struct LIN_SignalDef *signalDefp = NULL; struct LIN_SignalEncodingType *encodingTypep = NULL; struct SignalEncodingData *encodingDatap = NULL; unsigned char *srcDatabytesp = NULL; protoContext context = protoParamsp->protoInterface.context; union { unsigned short rawValue; unsigned char databytes[ENCODEDSIGNALSTRING_BUFFER_SIZE]; } signalData; size_t pos = 0; int srcBitRightOffset = 0; /*number of bits right of byte boundary of source byte which form destination byte*/ int srcBitLeftOffset = 0; /*number of bits left of byte boundary of source byte which form destination byte*/ int dstNeededBytes = 0; /*number of needed bytes of destination*/ int unusedBits = 0; /*number of MSBits which have to be masked*/ PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); while (includedDatap = (union LIN_IncludedData*) bufferVector_getElementRef(&frameDefp->includedData, pos)) { signalDefp = LDF_signalDef_getRef(protoParamsp->ldfp, includedDatap->includedSignal.signalIdentPos); if (signalDefp->signalValid & SIGNALDEFINTION_SIGNALVALID) { if (signalDefp->signalValid & SIGNALDEFINTION_ENCODINGVALID) { PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context, "%s: ", signalDefp->signalIdent); if (includedDatap->includedSignal.signalOffset + signalDefp->sizeBits <= frameDefp->frameSize * 8) { srcDatabytesp = databytesp; srcBitRightOffset = (includedDatap->includedSignal.signalOffset + signalDefp->sizeBits) & 0x07; dstNeededBytes = (signalDefp->sizeBits + 7) >> 3; srcDatabytesp += ((includedDatap->includedSignal.signalOffset + signalDefp->sizeBits) >> 3) - dstNeededBytes; signalData.rawValue = 0; if (srcBitRightOffset == 0) memcpy(signalData.databytes, srcDatabytesp, dstNeededBytes); else { int n; srcBitLeftOffset = 8 - srcBitRightOffset; for(n=0; n> srcBitLeftOffset; } unusedBits = 8 - (signalDefp->sizeBits & 0x07); if (unusedBits != 8) { signalData.databytes[0] <<= unusedBits; signalData.databytes[0] >>= unusedBits; } if (dstNeededBytes <= sizeof(unsigned short)) encodingDatap = LDF_signalEncodingData_getRef_byRawValue(protoParamsp->ldfp, signalDefp->signalEncodingTypePos, LSB(signalData.rawValue, dstNeededBytes * 8)); else encodingDatap = LDF_signalEncodingData_getRef_withoutRawValue(protoParamsp->ldfp, signalDefp->signalEncodingTypePos); if (encodingDatap) { /*this cases can happen only if less than 16bit rawvalues => rawValue can be used*/ if (encodingDatap->encodingType == SIGNALENCODING_LOGICVALUE) { if (encodingDatap->encodingData.logic.textInfo[0] != '\0') PROTO_Printf(context, "%s ", encodingDatap->encodingData.logic.textInfo); else PROTO_Printf(context, "%hu ", LSB(signalData.rawValue, dstNeededBytes * 8)); } else if (encodingDatap->encodingType == SIGNALENCODING_PHYSICALRANGE) PROTO_Printf(context, "%lf %s ", LSB(signalData.rawValue, dstNeededBytes * 8) * encodingDatap->encodingData.range.scale + encodingDatap->encodingData.range.offset, encodingDatap->encodingData.range.textInfo); /*this cases can happen with every bit length (smaller thann 64bit?)*/ else if (encodingDatap->encodingType == SIGNALENCODING_BCDVALUE) { int n; for (n=0; n> 4) + '0'; if (digit1 > '9') digit1 = '?'; if (digit10 > '9') digit10 = '?'; PROTO_Printf(context, "%c%c", digit10, digit1); } PROTO_Puts(context, " (BCD) "); } else if (encodingDatap->encodingType == SIGNALENCODING_ASCIIVALUE) { int n = 0, len = 0; PROTO_Control(context, PROTO_ATTRIBUTE_ASCII); signalData.databytes[dstNeededBytes] = '\0'; do { PROTO_Puts(context, signalData.databytes + n); len = strlen(signalData.databytes + n); n += len; if (n < dstNeededBytes) { PROTO_Control(context, PROTO_CONTROL_PRINTNIL); n++; } } while (n < dstNeededBytes); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); } } else PROTO_Printf(context, "No encoding found which can handle a %hhu-bit value! ", signalDefp->sizeBits); } else PROTO_Printf(context, "Signal broken! ", signalDefp->sizeBits); } else { if (protoParamsp->hideNoEncodingSignalsf == FALSE) { PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Printf(context, "%s: No encoding defined!", signalDefp->signalIdent); } } } pos++; } } void PROTOAPI Process3_display(protoContext context, protoPtr pdata, protoPtr paramsp) { struct Proto_FrameAssoc *frameAssocp = (struct Proto_FrameAssoc*) pdata; struct LIN_Proto *protoParamsp = paramsp; struct Proto_Frame *framep = NULL; unsigned char *databytesp = NULL; Proto_protoParams_setContext(protoParamsp, context); if (frameAssocp->infoFlags == PROTOFRAMEASSOC_FRAME_END_MARKER) { /*PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, " --end--");*/ } else if (frameAssocp->infoFlags & PROTOFRAMEASSOC_UNUSED_TRAFFIC) { PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); PROTO_Puts(context, "unused bus traffic"); Process3_displayErrors(protoParamsp, frameAssocp); } else if (frameAssocp->infoFlags & PROTOFRAMEASSOC_ERROR_FRAME ) { framep = ((struct IncludedFrame*) bufferVector_getElementRef(&frameAssocp->includedFrames, 0))->framep; PROTO_Control(context, PROTO_ATTRIBUTE_BOLD); if (frameAssocp->linFrameDefp) PROTO_Printf(context, "%s", frameAssocp->linFrameDefp->frameIdent); else if ((framep->infoFlags & PROTOFRAME_PID_ERROR) == FALSE) PROTO_Printf(context, "ID: 0x%02hhX", (unsigned char) framep->id); else PROTO_Printf(context, "PID: 0x%02hhX", (unsigned char) framep->id); Process3_displayErrors(protoParamsp, frameAssocp); } else { framep = ((struct IncludedFrame*) bufferVector_getElementRef(&frameAssocp->includedFrames, 0))->framep; PROTO_Control(context, PROTO_ATTRIBUTE_BOLD); switch (frameAssocp->linFrameDefp->frameType) { case FRAMTEYPE_UNCONDITIONAL : case FRAMETYPE_SPORADIC : PROTO_Puts(context, frameAssocp->linFrameDefp->frameIdent); if (frameAssocp->infoFlags & PROTOFRAMEASSOC_ERROR_ALL) Process3_displayErrors(protoParamsp, frameAssocp); databytesp = Process2_getDatabytesRef(/*includedFramep->*/framep); Process3_displaySignals(protoParamsp, frameAssocp->linFrameDefp, databytesp); break; case FRAMETYPE_EVENTTRIGGERED : { unsigned char *databytesp = NULL; struct LIN_FrameDef *eventframeDefp = NULL; size_t pos; if (frameAssocp->infoFlags & PROTOFRAMEASSOC_ERROR_ALL) Process3_displayErrors(protoParamsp, frameAssocp); databytesp = Process2_getDatabytesRef(framep); LDF_frameFind_ByIdTimeref(protoParamsp->ldfp, (unsigned char) (databytesp[0] & LIN_PID_ID_MASK), framep->timeRef, &pos); eventframeDefp = LDF_frameDef_getRef(protoParamsp->ldfp, pos); PROTO_Printf(context, "%s: %s", frameAssocp->linFrameDefp->frameIdent, eventframeDefp->frameIdent); Process3_displaySignals(protoParamsp, eventframeDefp, databytesp); } break; case FRAMETYPE_DIAGNOSTIC : { unsigned char *databytesp = Process2_getDatabytesRef(framep); const char *cp = NULL; unsigned char *nadp = NULL, *pcip = NULL, *sidp = NULL, *lenp = NULL; nadp = &((struct LIN_Pdu_sf*) databytesp)->nad; pcip = &((struct LIN_Pdu_sf*) databytesp)->pci; sidp = &((struct LIN_Pdu_sf*) databytesp)->sid; if (framep->pduType == PROTOPDU_FF) { sidp = &((struct LIN_Pdu_ff*) databytesp)->sid; lenp = &((struct LIN_Pdu_ff*) databytesp)->len; } PROTO_Puts(context, "DiagFrame <-> "); if (*nadp == NAD_GOTO_SLEEP) { PROTO_Puts(context, "GOTO SLEEP"); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); } else { if (frameAssocp->pduSlaveNodeDefp) PROTO_Printf(context, "%s", frameAssocp->pduSlaveNodeDefp->nodeIdent); else if (*nadp == NAD_BROADCAST) PROTO_Puts(context, "broadcast"); else PROTO_Printf(context, "0x%02hhX (unknown NAD)", *nadp); PROTO_Puts(context,", SID: "); if (cp = Process3_sidServiceName(*sidp)) PROTO_Printf(context, "%s ", cp); else PROTO_Printf(context, "0x%02hhX", *sidp); //PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); PROTO_Control(context, PROTO_ATTRIBUTE_LIGHT); switch (framep->pduType) { /*case PROTOPDU_DIAG_REQ_OK: PROTO_Puts(context, ", ok"); break;*/ case PROTOPDU_DIAG_REQ_NOT_DEFINED: PROTO_Puts(context, ", not defined"); break; /*case PROTOPDU_DIAG_RESP_POS: PROTO_Puts(context, ", positive"); break;*/ case PROTOPDU_DIAG_RESP_NEG: PROTO_Puts(context, ", negative response"); break; case PROTOPDU_DIAG_RESP_UNKNOWN_RESULT: PROTO_Puts(context, ", unknown side effect"); break; case PROTOPDU_DIAG_RESP_WITHOUT_REQ: PROTO_Puts(context, ", unexpected response (no request detected)"); break; case PROTOPDU_DIAG_RESP_NOT_DEFINED: PROTO_Puts(context, ", not defined"); break; case PROTOPDU_SF: PROTO_Printf(context, " (SF, %hhu bytes) ", *pcip & 0x0F); break; case PROTOPDU_FF: PROTO_Printf(context, " (FF, %hu bytes) ", (*pcip & 0x0F)<<8 | *lenp); break; case PROTOPDU_CF: PROTO_Printf(context, " (CF, no. %02hhu) ", *pcip & 0x0F); break; case PROTOPDU_UNKNOWNPCI: PROTO_Puts(context, " PCI code unknown! "); break; } if (frameAssocp->infoFlags & PROTOFRAMEASSOC_ERROR_ALL) Process3_displayErrors(protoParamsp, frameAssocp); if (framep->diagServiceStringp) { PROTO_Control(context, PROTO_CONTROL_LINEFEED); PROTO_Control(context, PROTO_ATTRIBUTE_LEVEL3); PROTO_Puts(context, framep->diagServiceStringp); } } } break; } } } const char* PROTOAPI Process3_chart(protoContext context, protoPtr pdata, protoPtr paramsp) { struct Proto_FrameAssoc *frameAssocp = (struct Proto_FrameAssoc*) pdata; struct LIN_Proto *protoParamsp = (struct LIN_Proto*) paramsp; static const char idleString[] = "IDLE"; static const char errorString[] = "ERROR"; static const char unusedStrng[] = "UNUSED"; if (frameAssocp->infoFlags == PROTOFRAMEASSOC_FRAME_END_MARKER) return idleString; else if (frameAssocp->infoFlags & PROTOFRAMEASSOC_ERROR_ALL) return errorString; else if (frameAssocp->infoFlags & PROTOFRAMEASSOC_UNUSED_TRAFFIC) return unusedStrng; else return (const char*) frameAssocp->linFrameDefp->frameIdent; } /** \} */