├── .clang-format ├── .dockerignore ├── .github └── workflows │ └── test.yml ├── .gitignore ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── README.md ├── codecov.yml ├── config ├── Xcp.lnt ├── xcp.json └── xcp.schema.json ├── debug ├── CMakeLists.txt └── main.c ├── extern └── CMakeLists.txt ├── generated └── CMakeLists.txt ├── interface ├── Xcp.h ├── XcpOnCan_Cbk.h ├── Xcp_Errors.h └── Xcp_Types.h ├── requirements.txt ├── script ├── header_cfg.h.jinja2 ├── header_rt.h.jinja2 ├── source_cfg.c.jinja2 └── source_rt.c.jinja2 ├── source └── Xcp.c ├── test.sh └── test ├── __init__.py ├── asam_error_matrix_test.py ├── asam_protocol_layer_test.py ├── autosar_sws_test.py ├── build_checksum_test.py ├── conftest.py ├── connect_test.py ├── disconnect_test.py ├── get_comm_mode_info_test.py ├── get_id_test.py ├── get_status_test.py ├── parameter.py ├── seed_key_test.py ├── set_mta_test.py ├── set_request_test.py ├── short_upload_test.py ├── stub ├── CanIf.h ├── CanIf_Types.h ├── Det.h ├── Xcp_Checksum.h ├── Xcp_MemMap.h ├── Xcp_MemoryAccess.h ├── Xcp_SeedKey.h ├── Xcp_UserCmd.h └── common │ ├── ComStack_Types.h │ ├── Compiler.h │ ├── Platform_Types.h │ └── Std_Types.h ├── synch_test.py ├── transport_layer_cmd_test.py ├── upload_test.py └── user_cmd_test.py /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # https://zed0.co.uk/clang-format-configurator/ 3 | AlignConsecutiveMacros: None 4 | AlignConsecutiveAssignments: None 5 | AlignConsecutiveDeclarations: None 6 | AlignEscapedNewlines: Right 7 | AlignOperands: false 8 | AlignTrailingComments: false 9 | AllowAllArgumentsOnNextLine: false 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | AllowShortBlocksOnASingleLine: Never 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: None 14 | AllowShortIfStatementsOnASingleLine: Never 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakBeforeMultilineStrings: false 18 | BinPackArguments: false 19 | BinPackParameters: false 20 | BraceWrapping: 21 | AfterCaseLabel: true 22 | AfterClass: true 23 | AfterControlStatement: true 24 | AfterEnum: true 25 | AfterFunction: true 26 | AfterNamespace: true 27 | AfterObjCDeclaration: true 28 | AfterStruct: true 29 | AfterUnion: true 30 | BeforeCatch: true 31 | BeforeElse: true 32 | IndentBraces: false 33 | BreakBeforeBinaryOperators: None 34 | BreakBeforeBraces: Custom 35 | BreakBeforeTernaryOperators: false 36 | BreakStringLiterals: true 37 | ColumnLimit: 150 38 | CommentPragmas: ^lint 39 | ContinuationIndentWidth: 4 40 | DisableFormat: false 41 | ExperimentalAutoDetectBinPacking: false 42 | IncludeBlocks: Regroup 43 | IndentCaseLabels: true 44 | IndentPPDirectives: None 45 | IndentWidth: 4 46 | IndentWrappedFunctionNames: false 47 | KeepEmptyLinesAtTheStartOfBlocks: false 48 | MaxEmptyLinesToKeep: 1 49 | PenaltyReturnTypeOnItsOwnLine: 100 50 | PointerAlignment: Right 51 | ReflowComments: true 52 | SortIncludes: CaseSensitive 53 | SpaceAfterCStyleCast: false 54 | SpaceAfterLogicalNot: false 55 | SpaceBeforeAssignmentOperators: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 1 60 | SpacesInCStyleCastParentheses: false 61 | SpacesInContainerLiterals: false 62 | SpacesInParentheses: false 63 | SpacesInSquareBrackets: false 64 | UseTab: Never 65 | 66 | ... 67 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | **/*.pyc 3 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: [ push ] 4 | 5 | env: 6 | REGISTRY: ghcr.io 7 | IMAGE_NAME: ${{github.repository}} 8 | 9 | jobs: 10 | build-and-push-image: 11 | name: Build and push image 12 | runs-on: ubuntu-20.04 13 | steps: 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | - name: Log in to the Container registry 17 | uses: docker/login-action@v2 18 | with: 19 | registry: ${{env.REGISTRY}} 20 | username: ${{secrets.PKG_REGISTRY_USERNAME}} 21 | password: ${{secrets.PKG_REGISTRY_RW_TOKEN}} 22 | - name: Extract metadata (tags, labels) for Docker 23 | id: meta 24 | uses: docker/metadata-action@v4 25 | with: 26 | images: ${{env.REGISTRY}}/${{env.IMAGE_NAME}} 27 | - name: Build and push Docker image 28 | uses: docker/build-push-action@v4 29 | with: 30 | context: . 31 | push: true 32 | tags: ${{steps.meta.outputs.tags}} 33 | labels: ${{steps.meta.outputs.labels}} 34 | run-tests: 35 | name: Run tests 36 | needs: build-and-push-image 37 | runs-on: ubuntu-20.04 38 | container: 39 | image: ghcr.io/sauci/xcp:develop 40 | credentials: 41 | username: ${{secrets.PKG_REGISTRY_USERNAME}} 42 | password: ${{secrets.PKG_REGISTRY_RW_TOKEN}} 43 | volumes: 44 | - ${{github.workspace}}:/usr/project 45 | steps: 46 | - name: Checkout repository 47 | uses: actions/checkout@v3 48 | - name: Run pytest tests 49 | run: ./test.sh 50 | - name: Upload code coverage to Codecov 51 | if: success() || failure() 52 | uses: codecov/codecov-action@v1 53 | with: 54 | files: ./build/Xcp.c.gcov 55 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .pytest_cache 3 | *__pycache__* 4 | *build* 5 | doc/* 6 | extern/* 7 | !extern/CMakeLists.txt 8 | generated/*.c 9 | generated/*.h 10 | generated/script/__pycache__/* 11 | report/* 12 | test/ffi/cffi_config.py 13 | test/ffi/*.o 14 | test/ffi/*.so 15 | test/ffi/*.gcno 16 | test/ffi/*.gcda 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8.0) 2 | 3 | project(Xcp VERSION 0.1.0 LANGUAGES C) 4 | 5 | set(AUTOSAR_STD_HEADER_PATH ${CMAKE_CURRENT_SOURCE_DIR}/test/stub/common CACHE FILEPATH 6 | "path to directory containing Std_Types.h and ComStack_Types.h.") 7 | set(XCP_CONFIG_FILEPATH ${CMAKE_CURRENT_SOURCE_DIR}/config/xcp.json CACHE FILEPATH 8 | "path to configuration file used to generate post-build configuration.") 9 | option(XCP_ENABLE_TEST "enables/disables tests." OFF) 10 | option(ENABLE_DET "enables/disables development error detection." ON) 11 | option(ENABLE_DOC_GEN "enables/disables documentation generation." OFF) 12 | option(ENABLE_PC_LINT "enables/disables static code analysis." OFF) 13 | set(MISRA_C_VERSION 2012 CACHE STRING "MISRA standard.") 14 | option(XCP_SUPPRESS_TX_SUPPORT "enables/disables transmission functionality of the XCP module." ON) 15 | 16 | find_package(PythonInterp 3.6 REQUIRED) 17 | 18 | if (${ENABLE_DOC_GEN}) 19 | find_package(Doxygen REQUIRED dot) 20 | 21 | set(DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/doc) 22 | 23 | doxygen_add_docs(${PROJECT_NAME}.doc source interface COMMENT "generating Xcp documentation") 24 | endif () 25 | 26 | add_subdirectory(extern) 27 | add_subdirectory(generated) 28 | # add_subdirectory(debug) 29 | 30 | add_library(Xcp STATIC source/Xcp.c) 31 | 32 | target_compile_definitions(Xcp 33 | PRIVATE XCP_DEV_ERROR_DETECT=$,STD_ON,STD_OFF> 34 | PRIVATE XCP_SW_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} 35 | PRIVATE XCP_SW_VERSION_MINOR=${PROJECT_VERSION_MINOR} 36 | PRIVATE XCP_SW_VERSION_PATCH=${PROJECT_VERSION_PATCH} 37 | PUBLIC XCP_AR_RELEASE_MAJOR_VERSION=4 # SWS_BSW_00059 38 | PUBLIC XCP_AR_RELEASE_MINOR_VERSION=3 39 | PUBLIC XCP_AR_RELEASE_PATCH_VERSION=1 40 | PUBLIC XCP_API=STD_ON 41 | PUBLIC XCP_GET_VERSION_INFO_API=STD_ON # ECUC_Xcp_00283 42 | PUBLIC XCP_CHANGE_PARAMETER_API=STD_ON # ECUC_Xcp_00299 43 | PUBLIC XCP_READ_PARAMETER_API=STD_ON # ECUC_Xcp_00300 44 | PUBLIC XCP_SUPPRESS_TX_SUPPORT=$,STD_ON,STD_OFF>) 45 | 46 | target_include_directories(Xcp 47 | PUBLIC interface 48 | PUBLIC ${AUTOSAR_STD_HEADER_PATH} 49 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/generated 50 | PUBLIC $<$:${CMAKE_CURRENT_SOURCE_DIR}/test/stub>) 51 | 52 | target_link_libraries(Xcp 53 | PUBLIC Xcp_Rt) 54 | 55 | if (${XCP_ENABLE_TEST}) 56 | enable_testing() 57 | 58 | add_test(NAME Xcp_UnitTest 59 | COMMAND ${PYTHON_EXECUTABLE} -W ignore::DeprecationWarning 60 | -m pytest ${CMAKE_CURRENT_SOURCE_DIR}/test -v -x 61 | --build_directory ${CMAKE_BINARY_DIR} 62 | --script_directory ${PROJECT_SOURCE_DIR}/script 63 | --header ${PROJECT_SOURCE_DIR}/interface/Xcp.h 64 | --source ${PROJECT_SOURCE_DIR}/source/Xcp.c 65 | --compile_definitions $,$> 66 | --include_directories $,$> 67 | --junitxml=./report/${PROJECT_NAME}.xml 68 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) 69 | endif () 70 | 71 | if (${ENABLE_PC_LINT}) 72 | add_pc_lint_target(NAME Xcp 73 | DEPENDENCIES ${CMAKE_CURRENT_SOURCE_DIR}/generated/Xcp_PBcfg.h 74 | OUTPUT_LOG ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.lnt.log 75 | EXCLUDE_DIRECTORIES 76 | ${AUTOSAR_STD_HEADER_PATH} 77 | OPTION_FILES 78 | ${CMAKE_CURRENT_SOURCE_DIR}/extern/lint/MISRA${MISRA_C_VERSION}.lnt 79 | ${CMAKE_CURRENT_SOURCE_DIR}/config/Xcp.lnt) 80 | endif () 81 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.10 2 | 3 | LABEL maintainer="Guillaume Sottas" 4 | 5 | # setup environment variables. 6 | ENV PROJECT_DIR=/usr/project 7 | 8 | # install required binaries. 9 | RUN apk update && apk add \ 10 | bash \ 11 | build-base \ 12 | cmake \ 13 | curl \ 14 | doxygen \ 15 | findutils \ 16 | gdb \ 17 | git \ 18 | graphviz \ 19 | libffi-dev \ 20 | python3-dev 21 | 22 | # install python requirements. 23 | COPY ./requirements.txt requirements.txt 24 | RUN pip3 install --upgrade pip && pip3 install -r requirements.txt 25 | 26 | # setup a shared volume. 27 | WORKDIR $PROJECT_DIR 28 | VOLUME ["$PROJECT_DIR"] 29 | RUN cd $PROJECT_DIR 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2022, Guillaume Sottas 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | | branch | build status | coverage | 2 | |:-----------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------| 3 | | [master](https://github.com/Sauci/Xcp/tree/master) | [![test](https://github.com/Sauci/Xcp/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/Sauci/Xcp/actions/workflows/test.yml) | [![codecov](https://codecov.io/gh/Sauci/Xcp/branch/master/graph/badge.svg)](https://codecov.io/gh/Sauci/Xcp/branch/master) | 4 | | [develop](https://github.com/Sauci/Xcp/tree/develop) | [![test](https://github.com/Sauci/Xcp/actions/workflows/test.yml/badge.svg?branch=develop)](https://github.com/Sauci/Xcp/actions/workflows/test.yml) | [![codecov](https://codecov.io/gh/Sauci/Xcp/branch/develop/graph/badge.svg)](https://codecov.io/gh/Sauci/Xcp/branch/develop) | 5 | 6 | # Configure/Compile -time definitions 7 | The following definitions might be set by the user, depending on the needs. 8 | 9 | | definition | values | default | description | 10 | |:------------------------------|:---------------------------------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 11 | | ```AUTOSAR_STD_HEADER_PATH``` | ```-``` | ```Xcp/test/stub/common``` | specifies the directory containing **AUTOSAR** standard headers ComStack_Types.h and Std_Types.h (used when integrating this module in an other project) | 12 | | ```XCP_CONFIG_FILEPATH``` | ```-``` | ```Xcp/config/xcp.json``` | specifies which json configuration file should be used to generate the auto-generated code | 13 | | ```XCP_ENABLE_TEST``` | ```ON```/```OFF``` | ```OFF``` | enables/disables tests. | 14 | | ```ENABLE_DET``` | ```ON```/```OFF``` | ```ON``` | enables/disables development error detections (see AUTOSAR [DET](https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_DefaultErrorTracer.pdf) module) | 15 | | ```ENABLE_DOC_GEN``` | ```ON```/```OFF``` | ```OFF``` | enables/disables generation of [Doxygen](http://www.doxygen.nl/) documentation | 16 | | ```ENABLE_PC_LINT``` | ```ON```/```OFF``` | ```OFF``` | enables/disables generation of targets related to static code analysis (should be disabled if [PC-Lint](https://www.gimpel.com) software is not available) | 17 | | ```MISRA_C_VERSION``` | ```1998```/```2004```/```2012``` | ```2012``` | specifies which version of **MISRA** should be used when performing static code analysis (only used if ```ENABLE_PC_LINT``` is set) | 18 | | ```XCP_SUPPRESS_TX_SUPPORT``` | ```ON / OFF``` | ```ON``` | enables/disables transmission functionality of the XCP module | 19 | 20 | To use this feature, simply add ```-D=``` when configuring the build with CMake. 21 | 22 | # Module configuration 23 | A large part of this module consists of auto-generated code. It takes a *JSON* file as input (the path of this file is 24 | specified through the `XCP_CONFIG_FILEPATH` CMake variable, defaulting to [this](config/xcp.json) file), and generates 25 | the *Xcp_Cfg.c* and *Xcp_Cfg.h* files. The content of this configuration file is specified with the *JSON* schema 26 | available [here](config/xcp.schema.json). Most of the recent IDEs are providing auto-completion of the configuration 27 | file based on its schema, thus it is highly recommended using it. 28 | 29 | # Implementation details 30 | This section gives a few implementation details, where the specification is not very clear or a little bit fuzzy. This 31 | will allow the user to properly configure the communication parameters on the master side. 32 | 33 | ## Seed lifetime 34 | Whenever the seed is requested by the master trough the `GET_SEED` command, a new seed is requested by the XCP stack 35 | through the `Xcp_GetSeed` function. The idea behind it is that if the slave would not do this, the master could 36 | calculate a key for a single seed and use it forever, which would lead to a less secured resource protection. 37 | 38 | Whenever the master issues a `UNLOCK` command, the slave will discard the seed as well, either upon successful and 39 | unsuccessful command result. This implies a new `GET_SEED` request for each `UNLOCK` command. 40 | 41 | The `Xcp_GetSeed` function implementation is left to the stack user. The target on which the stack is integrated could 42 | provide some random value generator, thus this is target-specific. The function's prototype is defined 43 | [here](./test/stub/Xcp_SeedKey.h). 44 | 45 | ## Key lifetime 46 | Whenever an `UNLOCK` command is issued by the master, the key is calculated by the slave using the last seed value 47 | requested by the master. No matter if the keys are matching or not, the key validity is discarded after the execution of 48 | the command following the `UNLOCK` sequence. 49 | 50 | If the master issues a `UNLOCK` command without calling `GET_SEED` first, the stack will respond with and error packet 51 | identifier, and the code `ERR_SEQUENCE`. 52 | 53 | The implementation of the function responsible for key calculation, `Xcp_CalcKey` is left to the user. This is required, 54 | as the function must be shared between the master and the slave. 55 | 56 | # Limitations 57 | - The `GET_SLAVE_ID` command (CTO = `TRANSPORT_LAYER_CMD`, sub-command = `0xFF`) returns the PDU ID of the 58 | **CMD**/**STIM** communication channel, not the CAN identifier directly. This is implemented this way to prevent 59 | dependencies on the PDU mapping table in this module. 60 | - The `GET_ID` command only supports the request identification type 0 (*ASCII text*). 61 | --- 62 | # TODO 63 | - Protect variables used in both synchronous and asynchronous APIs. 64 | - Use pre-processor to enable/disable optional APIs. 65 | - Implement sub-command `SET_DAQ_LIST_CAN_IDENTIFIER` for CTO `TRANSPORT_LAYER_CMD`. -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "*/_cffi_*" 3 | -------------------------------------------------------------------------------- /config/Xcp.lnt: -------------------------------------------------------------------------------- 1 | /* http://www.gimpel.com/html/lintops.htm */ 2 | 3 | -wlib(1) 4 | -elib(1) 5 | -elibsym(1) 6 | -elibmacro(1) 7 | 8 | +fff /* output full file path. */ 9 | -width(0) /* keep output on a single line. */ 10 | -restore_at_end /* enable/disable lint message in file scope. */ 11 | -passes(2) /* perform 2 passes. */ 12 | -summary() /* output summary report before exit. */ 13 | +libclass(angle) /* treat #include as library headers. */ 14 | 15 | /*------------------------------------------------------------------------------------------------*/ 16 | /* rules related to AUTOSAR standard. */ 17 | /*------------------------------------------------------------------------------------------------*/ 18 | 19 | /** 20 | * allow the prefix of preprocessor definitions to be the same, as defined in 21 | * https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_MemoryMapping.pdf 22 | * 23 | * violated MISRA rules: 24 | * - 5.1, required 25 | * - 5.2, required 26 | * - 5.4, required 27 | * - 5.5, required 28 | */ 29 | -idlen(63, p) 30 | 31 | /** 32 | * allow multiple inclusions of the same header file without include guards, as defined in 33 | * https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_MemoryMapping.pdf 34 | * 35 | * violated MISRA rules: 36 | * - 4.10, required 37 | */ 38 | -efile(451, Xcp_MemMap.h) 39 | 40 | /** 41 | * allow repeated include file, as defined in 42 | * https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_MemoryMapping.pdf 43 | */ 44 | -efile(537, Xcp_MemMap.h) 45 | 46 | /** 47 | * if no specific memory sections are defined (for example when running on x86 arch) the file 48 | * Xcp_MemMap.h does not alter the code 49 | */ 50 | -efile(766, Xcp_MemMap.h) 51 | 52 | 53 | /** 54 | * allow declarations before #include directive, as defined in 55 | * https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_MemoryMapping.pdf 56 | * 57 | * violated MISRA rules: 58 | * - 20.1, advisory 59 | * 60 | * TODO: this violation might be removed by moving 'private' type definitions into a separated 61 | * header 62 | */ 63 | -e9019 64 | 65 | /** 66 | * allow usage of '#undef' directive, as defined in 67 | * https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_MemoryMapping.pdf 68 | * 69 | * violated MISRA rules: 70 | * - 20.5, advisory 71 | */ 72 | -e9021 73 | 74 | /* violated rules. */ 75 | -e934 /* taking address of near auto variable. */ 76 | -------------------------------------------------------------------------------- /config/xcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "communication": { 5 | "channel_rx_pdu_ref": "XCP_PDU_ID_CTO_RX", 6 | "channel_tx_pdu_ref": "XCP_PDU_ID_CTO_TX" 7 | }, 8 | "daqs": [ 9 | { 10 | "name": "DAQ1", 11 | "type": "DAQ", 12 | "max_odt": 3, 13 | "max_odt_entries": 9, 14 | "pdu_mapping": "XCP_PDU_ID_TRANSMIT", 15 | "dtos": [ 16 | { 17 | "pid": 0 18 | } 19 | ] 20 | }, 21 | { 22 | "name": "DAQ2", 23 | "type": "DAQ", 24 | "max_odt": 5, 25 | "max_odt_entries": 10, 26 | "pdu_mapping": "XCP_PDU_ID_TRANSMIT", 27 | "dtos": [ 28 | { 29 | "pid": 1 30 | } 31 | ] 32 | } 33 | ], 34 | "events": [ 35 | { 36 | "consistency": "ODT", 37 | "priority": 0, 38 | "time_cycle": 10, 39 | "time_unit": "TIMESTAMP_UNIT_1MS", 40 | "triggered_daq_list_ref": [ 41 | "DAQ1" 42 | ] 43 | } 44 | ], 45 | "apis": { 46 | "xcp_set_request_api_enable": { 47 | "enabled": true, 48 | "protected": false 49 | }, 50 | "xcp_get_id_api_enable": { 51 | "enabled": true, 52 | "protected": false 53 | }, 54 | "xcp_get_seed_api_enable": { 55 | "enabled": true, 56 | "protected": false 57 | }, 58 | "xcp_unlock_api_enable": { 59 | "enabled": true, 60 | "protected": false 61 | }, 62 | "xcp_set_mta_api_enable": { 63 | "enabled": true, 64 | "protected": false 65 | }, 66 | "xcp_upload_api_enable": { 67 | "enabled": true, 68 | "protected": true 69 | }, 70 | "xcp_short_upload_api_enable": { 71 | "enabled": true, 72 | "protected": true 73 | }, 74 | "xcp_build_checksum_api_enable": { 75 | "enabled": true, 76 | "protected": true 77 | }, 78 | "xcp_download_api_enable": { 79 | "enabled": true, 80 | "protected": false 81 | }, 82 | "xcp_download_max_api_enable": { 83 | "enabled": true, 84 | "protected": false 85 | }, 86 | "xcp_short_download_api_enable": { 87 | "enabled": true, 88 | "protected": false 89 | }, 90 | "xcp_set_cal_page_api_enable": { 91 | "enabled": true, 92 | "protected": false 93 | }, 94 | "xcp_get_cal_page_api_enable": { 95 | "enabled": true, 96 | "protected": false 97 | }, 98 | "xcp_clear_daq_list_api_enable": { 99 | "enabled": true, 100 | "protected": false 101 | }, 102 | "xcp_set_daq_ptr_api_enable": { 103 | "enabled": true, 104 | "protected": false 105 | }, 106 | "xcp_write_daq_api_enable": { 107 | "enabled": true, 108 | "protected": false 109 | }, 110 | "xcp_set_daq_list_mode_api_enable": { 111 | "enabled": true, 112 | "protected": false 113 | }, 114 | "xcp_get_daq_list_mode_api_enable": { 115 | "enabled": true, 116 | "protected": false 117 | }, 118 | "xcp_start_stop_daq_list_api_enable": { 119 | "enabled": true, 120 | "protected": false 121 | }, 122 | "xcp_start_stop_synch_api_enable": { 123 | "enabled": true, 124 | "protected": false 125 | }, 126 | "xcp_get_daq_clock_api_enable": { 127 | "enabled": true, 128 | "protected": false 129 | }, 130 | "xcp_read_daq_api_enable": { 131 | "enabled": true, 132 | "protected": false 133 | }, 134 | "xcp_get_daq_processor_info_api_enable": { 135 | "enabled": true, 136 | "protected": false 137 | }, 138 | "xcp_get_daq_resolution_info_api_enable": { 139 | "enabled": true, 140 | "protected": false 141 | }, 142 | "xcp_get_daq_list_info_api_enable": { 143 | "enabled": true, 144 | "protected": false 145 | }, 146 | "xcp_get_daq_event_info_api_enable": { 147 | "enabled": true, 148 | "protected": false 149 | }, 150 | "xcp_free_daq_api_enable": { 151 | "enabled": true, 152 | "protected": false 153 | }, 154 | "xcp_alloc_daq_api_enable": { 155 | "enabled": true, 156 | "protected": false 157 | }, 158 | "xcp_alloc_odt_api_enable": { 159 | "enabled": true, 160 | "protected": false 161 | }, 162 | "xcp_alloc_odt_entry_api_enable": { 163 | "enabled": true, 164 | "protected": false 165 | }, 166 | "xcp_program_clear_api_enable": { 167 | "enabled": true, 168 | "protected": false 169 | }, 170 | "xcp_program_api_enable": { 171 | "enabled": true, 172 | "protected": false 173 | }, 174 | "xcp_program_max_api_enable": { 175 | "enabled": true, 176 | "protected": false 177 | }, 178 | "xcp_get_comm_mode_info_api_enable": { 179 | "enabled": true, 180 | "protected": false 181 | }, 182 | "resource_protection": { 183 | "calibration_paging": false, 184 | "data_acquisition": false, 185 | "data_stimulation": false, 186 | "programming": false 187 | } 188 | }, 189 | "protocol_layer": { 190 | "byte_order": "LITTLE_ENDIAN", 191 | "address_granularity": "BYTE", 192 | "master_block_mode": true, 193 | "slave_block_mode": true, 194 | "interleaved_mode": false, 195 | "max_bs": 255, 196 | "min_st": 255, 197 | "cto_queue_size": 16, 198 | "event_queue_size": 16, 199 | "max_cto": 8, 200 | "max_dto": 8, 201 | "checksum_type": "XCP_CRC_16", 202 | "user_defined_checksum_function": null, 203 | "user_cmd_function": null, 204 | "trailing_value": 0, 205 | "identification": "/path/to/database.a2l" 206 | } 207 | } 208 | ] 209 | } 210 | -------------------------------------------------------------------------------- /config/xcp.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "configurations": { 5 | "type": "array", 6 | "items": { 7 | "type": "object", 8 | "properties": { 9 | "communication": { 10 | "description": "This container represents the configuration of the communication channel of XCP (see ECUC_Xcp_00183)", 11 | "type": "object", 12 | "properties": { 13 | "channel_rx_pdu_ref": { 14 | "description": "Optional reference to the XCP Rx PDU (see ECUC_Xcp_00185)", 15 | "type": "string", 16 | "pattern": "[A-Z_][A-Z0-9_]*" 17 | }, 18 | "channel_tx_pdu_ref": { 19 | "description": "Reference to the XCP Tx PDU (see ECUC_Xcp_00184)", 20 | "type": "string", 21 | "pattern": "[A-Z_][A-Z0-9_]*" 22 | }, 23 | "com_m_channel_ref": { 24 | "description": "Reference to the ComM channel the PDUs belong to (see ECUC_Xcp_00186)", 25 | "type": "string", 26 | "pattern": "[A-Z_][A-Z0-9_]*" 27 | } 28 | }, 29 | "required": [ 30 | "channel_rx_pdu_ref", 31 | "channel_tx_pdu_ref" 32 | ] 33 | }, 34 | "events": { 35 | "description": "This container contains the configuration of event channels on the XCP slave (see ECUC_Xcp_00150)", 36 | "type": "array", 37 | "items": { 38 | "type": "object", 39 | "properties": { 40 | "consistency": { 41 | "description": "Type of consistency used by event channel (see ECUC_Xcp_00171)", 42 | "type": "string", 43 | "enum": [ 44 | "DAQ", 45 | "EVENT", 46 | "ODT" 47 | ], 48 | "default": "ODT" 49 | }, 50 | "priority": { 51 | "description": "Priority of the event channel", 52 | "type": "integer", 53 | "minimum": 0, 54 | "maximum": 255 55 | }, 56 | "time_cycle": { 57 | "description": "The event channel time cycle indicates which sampling period is used to\nprocess this event channel. A value of 0 means 'Not cyclic' (see ECUC_Xcp_00173)", 58 | "type": "integer", 59 | "minimum": 0, 60 | "maximum": 255 61 | }, 62 | "time_unit": { 63 | "description": "This configuration parameter indicates the unit of the event channel time cycle (see ECUC_Xcp_00174)", 64 | "type": "string", 65 | "enum": [ 66 | "TIMESTAMP_UNIT_1S", 67 | "TIMESTAMP_UNIT_1MS", 68 | "TIMESTAMP_UNIT_10MS", 69 | "TIMESTAMP_UNIT_100MS", 70 | "TIMESTAMP_UNIT_1US", 71 | "TIMESTAMP_UNIT_10US", 72 | "TIMESTAMP_UNIT_100US", 73 | "TIMESTAMP_UNIT_1NS", 74 | "TIMESTAMP_UNIT_10NS", 75 | "TIMESTAMP_UNIT_100NS", 76 | "TIMESTAMP_UNIT_1PS", 77 | "TIMESTAMP_UNIT_10PS", 78 | "TIMESTAMP_UNIT_100PS" 79 | ] 80 | }, 81 | "type": { 82 | "description": "This configuration parameter indicates what kind of DAQ list can be allocated to this event channel (see ECUC_Xcp_00172)", 83 | "type": "string", 84 | "enum": [ 85 | "DAQ", 86 | "DAQ_STIM" 87 | ], 88 | "default": "DAQ" 89 | }, 90 | "triggered_daq_list_ref": { 91 | "description": "References all DAQ lists that are trigged by this event channel (see ECUC_Xcp_00151)", 92 | "type": "array", 93 | "items": { 94 | "type": "string" 95 | } 96 | } 97 | }, 98 | "required": [ 99 | "priority", 100 | "time_cycle", 101 | "time_unit", 102 | "triggered_daq_list_ref" 103 | ] 104 | }, 105 | "minItems": 1, 106 | "maxItems": 65534 107 | }, 108 | "daqs": { 109 | "description": "This container contains the configuration of the DAQs.", 110 | "type": "array", 111 | "items": { 112 | "type": "object", 113 | "properties": { 114 | "name": { 115 | "description": "Name of the DAQ used as a reference within /configurations[x]/events[x]/triggered_daq_list_ref", 116 | "type": "string", 117 | "pattern": "[A-Z_][A-Z0-9_]*" 118 | }, 119 | "type": { 120 | "description": "This indicates whether this DAQ list represents a DAQ or a STIM (see ECUC_Xcp_00052)", 121 | "type": "string", 122 | "enum": [ 123 | "DAQ", 124 | "DAQ_STIM", 125 | "STIM" 126 | ] 127 | }, 128 | "max_odt": { 129 | "description": "MAX_ODT indicates the maximum amount of ODTs in this DAQ list (STATIC configuration) (see ECUC_Xcp_00053)", 130 | "type": "integer", 131 | "minimum": 0, 132 | "maximum": 252 133 | }, 134 | "max_odt_entries": { 135 | "description": "This parameter indicates the maximum amount of entries in an ODT of this DAQ list (STATIC configuration) (see ECUC_Xcp_00058)", 136 | "type": "integer", 137 | "minimum": 0, 138 | "maximum": 255 139 | }, 140 | "pdu_mapping": { 141 | "description": "This reference specifies the mapping of the DTO to the PDUs from the lower-layer interfaces (CanIf, FrIf, SoAd and Cdd). A reference to a XcpRxPdu is only feasible if the the DaqListType is DAQ_STIM. A reference to a XcpTxPdu is only feasible if the DaqListType is DAQ (see ECUC_Xcp_00067)", 142 | "type": "string", 143 | "pattern": "[A-Z_][A-Z0-9_]*" 144 | }, 145 | "dtos": { 146 | "description": "This container collects data transfer object specific parameters for the DAQ list (see ECUC_Xcp_00065)", 147 | "type": "array", 148 | "items": { 149 | "type": "object", 150 | "properties": { 151 | "pid": { 152 | "description": "Packet identifier (PID) of the DTO that identifies the ODT the content of the DTO (see ECUC_Xcp_00066)", 153 | "type": "integer", 154 | "minimum": 0, 155 | "maximum": 251 156 | } 157 | }, 158 | "required": [ 159 | "pid" 160 | ] 161 | }, 162 | "minItems": 1 163 | } 164 | }, 165 | "required": [ 166 | "name", 167 | "type", 168 | "max_odt", 169 | "max_odt_entries", 170 | "pdu_mapping", 171 | "dtos" 172 | ] 173 | }, 174 | "minItems": 1 175 | }, 176 | "apis": { 177 | "description": "This container allows the user to enable/disable optional APIs from the driver. This is not part of the specification", 178 | "type": "object", 179 | "properties": { 180 | "xcp_set_request_api_enable": { 181 | "$ref": "#/definitions/api_activation_information" 182 | }, 183 | "xcp_get_id_api_enable": { 184 | "$ref": "#/definitions/api_activation_information" 185 | }, 186 | "xcp_get_seed_api_enable": { 187 | "$ref": "#/definitions/api_activation_information" 188 | }, 189 | "xcp_unlock_api_enable": { 190 | "$ref": "#/definitions/api_activation_information" 191 | }, 192 | "xcp_set_mta_api_enable": { 193 | "$ref": "#/definitions/api_activation_information" 194 | }, 195 | "xcp_upload_api_enable": { 196 | "$ref": "#/definitions/api_activation_information" 197 | }, 198 | "xcp_short_upload_api_enable": { 199 | "$ref": "#/definitions/api_activation_information" 200 | }, 201 | "xcp_build_checksum_api_enable": { 202 | "$ref": "#/definitions/api_activation_information" 203 | }, 204 | "xcp_download_api_enable": { 205 | "$ref": "#/definitions/api_activation_information" 206 | }, 207 | "xcp_download_max_api_enable": { 208 | "$ref": "#/definitions/api_activation_information" 209 | }, 210 | "xcp_short_download_api_enable": { 211 | "$ref": "#/definitions/api_activation_information" 212 | }, 213 | "xcp_set_cal_page_api_enable": { 214 | "$ref": "#/definitions/api_activation_information" 215 | }, 216 | "xcp_get_cal_page_api_enable": { 217 | "$ref": "#/definitions/api_activation_information" 218 | }, 219 | "xcp_clear_daq_list_api_enable": { 220 | "$ref": "#/definitions/api_activation_information" 221 | }, 222 | "xcp_set_daq_ptr_api_enable": { 223 | "$ref": "#/definitions/api_activation_information" 224 | }, 225 | "xcp_write_daq_api_enable": { 226 | "$ref": "#/definitions/api_activation_information" 227 | }, 228 | "xcp_set_daq_list_mode_api_enable": { 229 | "$ref": "#/definitions/api_activation_information" 230 | }, 231 | "xcp_get_daq_list_mode_api_enable": { 232 | "$ref": "#/definitions/api_activation_information" 233 | }, 234 | "xcp_start_stop_daq_list_api_enable": { 235 | "$ref": "#/definitions/api_activation_information" 236 | }, 237 | "xcp_start_stop_synch_api_enable": { 238 | "$ref": "#/definitions/api_activation_information" 239 | }, 240 | "xcp_get_daq_clock_api_enable": { 241 | "$ref": "#/definitions/api_activation_information" 242 | }, 243 | "xcp_read_daq_api_enable": { 244 | "$ref": "#/definitions/api_activation_information" 245 | }, 246 | "xcp_get_daq_processor_info_api_enable": { 247 | "$ref": "#/definitions/api_activation_information" 248 | }, 249 | "xcp_get_daq_resolution_info_api_enable": { 250 | "$ref": "#/definitions/api_activation_information" 251 | }, 252 | "xcp_get_daq_list_info_api_enable": { 253 | "$ref": "#/definitions/api_activation_information" 254 | }, 255 | "xcp_get_daq_event_info_api_enable": { 256 | "$ref": "#/definitions/api_activation_information" 257 | }, 258 | "xcp_free_daq_api_enable": { 259 | "$ref": "#/definitions/api_activation_information" 260 | }, 261 | "xcp_alloc_daq_api_enable": { 262 | "$ref": "#/definitions/api_activation_information" 263 | }, 264 | "xcp_alloc_odt_api_enable": { 265 | "$ref": "#/definitions/api_activation_information" 266 | }, 267 | "xcp_alloc_odt_entry_api_enable": { 268 | "$ref": "#/definitions/api_activation_information" 269 | }, 270 | "xcp_program_clear_api_enable": { 271 | "$ref": "#/definitions/api_activation_information" 272 | }, 273 | "xcp_program_api_enable": { 274 | "$ref": "#/definitions/api_activation_information" 275 | }, 276 | "xcp_program_max_api_enable": { 277 | "$ref": "#/definitions/api_activation_information" 278 | }, 279 | "xcp_get_comm_mode_info_api_enable": { 280 | "$ref": "#/definitions/api_activation_information" 281 | }, 282 | "resource_protection": { 283 | "type": "object", 284 | "properties": { 285 | "calibration_paging": { 286 | "type": "boolean", 287 | "default": false 288 | }, 289 | "data_acquisition": { 290 | "type": "boolean", 291 | "default": false 292 | }, 293 | "data_stimulation": { 294 | "type": "boolean", 295 | "default": false 296 | }, 297 | "programming": { 298 | "type": "boolean", 299 | "default": false 300 | } 301 | }, 302 | "required": [ 303 | "calibration_paging", 304 | "data_acquisition", 305 | "data_stimulation", 306 | "programming" 307 | ] 308 | } 309 | }, 310 | "required": [ 311 | "xcp_set_request_api_enable", 312 | "xcp_get_id_api_enable", 313 | "xcp_get_seed_api_enable", 314 | "xcp_unlock_api_enable", 315 | "xcp_set_mta_api_enable", 316 | "xcp_upload_api_enable", 317 | "xcp_short_upload_api_enable", 318 | "xcp_build_checksum_api_enable", 319 | "xcp_download_api_enable", 320 | "xcp_download_max_api_enable", 321 | "xcp_short_download_api_enable", 322 | "xcp_set_cal_page_api_enable", 323 | "xcp_get_cal_page_api_enable", 324 | "xcp_clear_daq_list_api_enable", 325 | "xcp_set_daq_ptr_api_enable", 326 | "xcp_write_daq_api_enable", 327 | "xcp_set_daq_list_mode_api_enable", 328 | "xcp_get_daq_list_mode_api_enable", 329 | "xcp_start_stop_daq_list_api_enable", 330 | "xcp_start_stop_synch_api_enable", 331 | "xcp_get_daq_clock_api_enable", 332 | "xcp_read_daq_api_enable", 333 | "xcp_get_daq_processor_info_api_enable", 334 | "xcp_get_daq_resolution_info_api_enable", 335 | "xcp_get_daq_list_info_api_enable", 336 | "xcp_get_daq_event_info_api_enable", 337 | "xcp_free_daq_api_enable", 338 | "xcp_alloc_daq_api_enable", 339 | "xcp_alloc_odt_api_enable", 340 | "xcp_alloc_odt_entry_api_enable", 341 | "xcp_program_clear_api_enable", 342 | "xcp_program_api_enable", 343 | "xcp_program_max_api_enable", 344 | "xcp_get_comm_mode_info_api_enable", 345 | "resource_protection" 346 | ] 347 | }, 348 | "protocol_layer": { 349 | "description": "This container allows the user to specify protocol layer specific parameters. This is not part of the specification", 350 | "type": "object", 351 | "properties": { 352 | "byte_order": { 353 | "type": "string", 354 | "enum": [ 355 | "LITTLE_ENDIAN", 356 | "BIG_ENDIAN" 357 | ], 358 | "default": "LITTLE_ENDIAN" 359 | }, 360 | "address_granularity": { 361 | "type": "string", 362 | "enum": [ 363 | "BYTE", 364 | "WORD", 365 | "DWORD" 366 | ], 367 | "default": "DWORD" 368 | }, 369 | "master_block_mode": { 370 | "description": "MASTER_BLOCK_MODE flag indicates whether the master block mode is available.", 371 | "type": "boolean", 372 | "default": true 373 | }, 374 | "slave_block_mode": { 375 | "type": "boolean", 376 | "default": true 377 | }, 378 | "interleaved_mode": { 379 | "description": "INTERLEAVED_MODE flag indicates whether the interleaved mode is available. If interleaved mode is available, QUEUE_SIZE indicates the maximum number of consecutive command packets the master can send to the receipt queue of the slave.", 380 | "type": "boolean", 381 | "default": false 382 | }, 383 | "max_bs": { 384 | "description": "MAX_BS indicates the maximum allowed block size as the number of consecutive command packets (DOWNLOAD_NEXT or PROGRAM_NEXT) in a block sequence.", 385 | "type": "integer", 386 | "default": 255, 387 | "minimum": 0, 388 | "maximum": 255 389 | }, 390 | "min_st": { 391 | "description": "MIN_ST indicates the required minimum separation time between the packets of a block transfer from the master device to the slave device in units of 100 microseconds.", 392 | "type": "integer", 393 | "default": 255, 394 | "minimum": 0, 395 | "maximum": 255 396 | }, 397 | "cto_queue_size": { 398 | "description": "CTO_QUEUE_SIZE indicates the maximum number of consecutive command packets the master can send to the receipt queue of the slave.", 399 | "type": "integer", 400 | "default": 16, 401 | "minimum": 0, 402 | "maximum": 255 403 | }, 404 | "event_queue_size": { 405 | "description": "EVENT_QUEUE_SIZE indicates the maximum number of events stacked before dropping them, in case the slave is not able to transmit them to the master.", 406 | "type": "integer", 407 | "default": 16, 408 | "minimum": 0, 409 | "maximum": 255 410 | }, 411 | "max_cto": { 412 | "description": "MAX_CTO shows the maximum length of a CTO packet in bytes (see ECUC_Xcp_00004)\nNote: the AUTOSAR specification defines the upper limit to 255.", 413 | "type": "integer", 414 | "minimum": 8, 415 | "maximum": 256, 416 | "default": 8 417 | }, 418 | "max_dto": { 419 | "type": "integer", 420 | "minimum": 8, 421 | "maximum": 65535, 422 | "default": 8 423 | }, 424 | "checksum_type": { 425 | "type": "string", 426 | "enum": [ 427 | "XCP_ADD_11", 428 | "XCP_ADD_12", 429 | "XCP_ADD_14", 430 | "XCP_ADD_22", 431 | "XCP_ADD_24", 432 | "XCP_ADD_44", 433 | "XCP_CRC_16", 434 | "XCP_CRC_16_CITT", 435 | "XCP_CRC_32", 436 | "XCP_USER_DEFINED" 437 | ], 438 | "default": "XCP_CRC_32" 439 | }, 440 | "user_defined_checksum_function": { 441 | "OneOf": [ 442 | { 443 | "type": "null" 444 | }, 445 | { 446 | "type": "string", 447 | "enum": [ 448 | "Xcp_UserDefinedChecksumFunction" 449 | ] 450 | } 451 | ], 452 | "default": null 453 | }, 454 | "user_cmd_function": { 455 | "OneOf": [ 456 | { 457 | "type": "null" 458 | }, 459 | { 460 | "type": "string", 461 | "enum": [ 462 | "Xcp_UserCmdFunction" 463 | ] 464 | } 465 | ], 466 | "default": null 467 | }, 468 | "trailing_value": { 469 | "type": "integer", 470 | "minimum": 0, 471 | "maximum": 255, 472 | "default": 0 473 | }, 474 | "identification": { 475 | "type": "string", 476 | "default": "/path/to/database.a2l" 477 | } 478 | }, 479 | "required": [ 480 | "byte_order", 481 | "address_granularity", 482 | "master_block_mode", 483 | "slave_block_mode", 484 | "interleaved_mode", 485 | "max_bs", 486 | "min_st", 487 | "cto_queue_size", 488 | "event_queue_size", 489 | "max_cto", 490 | "max_dto", 491 | "checksum_type", 492 | "user_defined_checksum_function", 493 | "user_cmd_function", 494 | "trailing_value", 495 | "identification" 496 | ] 497 | } 498 | }, 499 | "required": [ 500 | "communication", 501 | "events", 502 | "daqs", 503 | "apis", 504 | "protocol_layer" 505 | ], 506 | "additionalProperties": false 507 | }, 508 | "minItems": 1 509 | } 510 | }, 511 | "required": [ 512 | "configurations" 513 | ], 514 | "definitions": { 515 | "api_activation_information": { 516 | "type": "object", 517 | "properties": { 518 | "enabled": { 519 | "type": "boolean", 520 | "default": true 521 | }, 522 | "protected": { 523 | "type": "boolean", 524 | "default": false 525 | } 526 | }, 527 | "required": [ 528 | "enabled", 529 | "protected" 530 | ] 531 | } 532 | } 533 | } 534 | -------------------------------------------------------------------------------- /debug/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(main main.c) 2 | 3 | target_link_libraries(main 4 | PUBLIC Xcp 5 | PUBLIC Xcp_Cfg) 6 | 7 | target_include_directories(main 8 | PUBLIC ${CMAKE_SOURCE_DIR}/generated) -------------------------------------------------------------------------------- /debug/main.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Guillaume Sottas on 2019-07-16. 3 | // 4 | 5 | #include 6 | #include "Xcp.h" 7 | #include "Xcp_Cfg.h" 8 | #include "XcpOnCan_Cbk.h" 9 | #include "Xcp_SeedKey.h" 10 | 11 | Std_ReturnType Xcp_GetSeed(uint8 *pSeedBuffer, 12 | const uint16 maxSeedLength, 13 | uint16 *pSeedLength) 14 | { 15 | (void)maxSeedLength; 16 | 17 | pSeedBuffer[0x00u] = 0x01u; 18 | pSeedBuffer[0x01u] = 0x02u; 19 | pSeedBuffer[0x02u] = 0x03u; 20 | pSeedBuffer[0x03u] = 0x04u; 21 | pSeedBuffer[0x04u] = 0x05u; 22 | pSeedBuffer[0x05u] = 0x06u; 23 | pSeedBuffer[0x06u] = 0x07u; 24 | pSeedBuffer[0x07u] = 0x08u; 25 | pSeedBuffer[0x08u] = 0x09u; 26 | pSeedBuffer[0x09u] = 0x0Au; 27 | pSeedBuffer[0x0Au] = 0x0Bu; 28 | 29 | *pSeedLength = 0x0Bu; 30 | 31 | return E_OK; 32 | } 33 | 34 | Std_ReturnType Xcp_CalcKey(const uint8 *pSeedBuffer, 35 | const uint16 seedLength, 36 | uint8* pKeyBuffer, 37 | const uint16 maxKeyLength, 38 | uint16 *pKeyLength) 39 | { 40 | (void)pSeedBuffer; 41 | (void)seedLength; 42 | (void)pKeyBuffer; 43 | (void)maxKeyLength; 44 | (void)pKeyLength; 45 | 46 | return E_OK; 47 | } 48 | 49 | Std_ReturnType CanIf_Transmit(PduIdType txPduId, const PduInfoType *pPduInfo) 50 | { 51 | return E_OK; 52 | } 53 | 54 | Std_ReturnType Det_ReportError(uint16 moduleId, 55 | uint8 instanceId, 56 | uint8 apiId, 57 | uint8 errorId) 58 | { 59 | (void)moduleId; 60 | (void)instanceId; 61 | (void)apiId; 62 | (void)errorId; 63 | 64 | return E_OK; 65 | } 66 | 67 | Std_ReturnType Det_ReportRuntimeError(uint16 moduleId, 68 | uint8 instanceId, 69 | uint8 apiId, 70 | uint8 errorId) 71 | { 72 | (void)moduleId; 73 | (void)instanceId; 74 | (void)apiId; 75 | (void)errorId; 76 | 77 | return E_OK; 78 | } 79 | 80 | Std_ReturnType Det_ReportTransientFault(uint16 moduleId, 81 | uint8 instanceId, 82 | uint8 apiId, 83 | uint8 faultId) 84 | { 85 | (void)moduleId; 86 | (void)instanceId; 87 | (void)apiId; 88 | (void)faultId; 89 | 90 | return E_OK; 91 | } 92 | 93 | void PduR_CanTpRxIndication(PduIdType rxPduId, Std_ReturnType result) 94 | { 95 | (void)rxPduId; 96 | (void)result; 97 | } 98 | 99 | void PduR_CanTpTxConfirmation(PduIdType txPduId, Std_ReturnType result) 100 | { 101 | (void)txPduId; 102 | (void)result; 103 | } 104 | 105 | BufReq_ReturnType PduR_CanTpCopyRxData(PduIdType rxPduId, 106 | const PduInfoType *pPduInfo, 107 | PduLengthType *pBuffer) 108 | { 109 | (void)rxPduId; 110 | (void)pPduInfo; 111 | (void)pBuffer; 112 | 113 | return E_OK; 114 | } 115 | 116 | BufReq_ReturnType PduR_CanTpCopyTxData(PduIdType txPduId, 117 | const PduInfoType *pPduInfo, 118 | const RetryInfoType *pRetryInfo, 119 | PduLengthType *pAvailableData) 120 | { 121 | (void)txPduId; 122 | (void)pPduInfo; 123 | (void)pRetryInfo; 124 | (void)pAvailableData; 125 | 126 | return E_OK; 127 | } 128 | 129 | BufReq_ReturnType PduR_CanTpStartOfReception(PduIdType pduId, 130 | const PduInfoType *pPduInfo, 131 | PduLengthType tpSduLength, 132 | PduLengthType *pBufferSize) 133 | { 134 | (void)pduId; 135 | (void)pPduInfo; 136 | (void)tpSduLength; 137 | (void)pBufferSize; 138 | 139 | *pBufferSize = 8; 140 | 141 | return E_OK; 142 | } 143 | 144 | int main(int argc, char *argv[]) 145 | { 146 | int i; 147 | uint8 rx_data[0x08u]; 148 | uint8 tx_data[0x08u]; 149 | 150 | PduInfoType rx_pdu; 151 | PduInfoType tx_pdu; 152 | 153 | rx_pdu.SduDataPtr = &rx_data[0x00u]; 154 | rx_pdu.MetaDataPtr = NULL_PTR; 155 | rx_pdu.SduLength = sizeof(rx_data); 156 | 157 | tx_pdu.SduDataPtr = &tx_data[0x00u]; 158 | tx_pdu.MetaDataPtr = NULL_PTR; 159 | tx_pdu.SduLength = sizeof(tx_data); 160 | 161 | Xcp_Init(&Xcp[0x00u]); 162 | 163 | rx_data[0x00u] = 0xFFu; 164 | rx_data[0x01u] = 0x00u; 165 | rx_data[0x02u] = 0x00u; 166 | rx_data[0x03u] = 0x00u; 167 | rx_data[0x04u] = 0x00u; 168 | rx_data[0x05u] = 0x00u; 169 | rx_data[0x06u] = 0x00u; 170 | rx_data[0x07u] = 0x00u; 171 | Xcp_CanIfRxIndication(0x01u, &rx_pdu); 172 | Xcp_MainFunction(); 173 | Xcp_CanIfTxConfirmation(0x01u, E_OK); 174 | 175 | rx_data[0x00u] = 0xF8u; 176 | rx_data[0x01u] = 0x00u; 177 | rx_data[0x02u] = 0x01u; 178 | rx_data[0x03u] = 0x02u; 179 | rx_data[0x04u] = 0x03u; 180 | rx_data[0x05u] = 0x04u; 181 | rx_data[0x06u] = 0x05u; 182 | rx_data[0x07u] = 0x06u; 183 | Xcp_CanIfRxIndication(0x01u, &rx_pdu); 184 | Xcp_MainFunction(); 185 | Xcp_CanIfTxConfirmation(0x01u, E_OK); 186 | 187 | rx_data[0x00u] = 0xF7u; 188 | rx_data[0x01u] = 0x02u; 189 | rx_data[0x02u] = 0x07u; 190 | rx_data[0x03u] = 0x08u; 191 | rx_data[0x04u] = 0x00u; 192 | rx_data[0x05u] = 0x00u; 193 | rx_data[0x06u] = 0x00u; 194 | rx_data[0x07u] = 0x00u; 195 | Xcp_CanIfRxIndication(0x01u, &rx_pdu); 196 | Xcp_MainFunction(); 197 | Xcp_CanIfTxConfirmation(0x01u, E_OK); 198 | 199 | return 0; 200 | } 201 | -------------------------------------------------------------------------------- /extern/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(MISRA_CONFIG_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lint) 2 | 3 | execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${MISRA_CONFIG_DIRECTORY}) 4 | 5 | file(DOWNLOAD 6 | https://gist.githubusercontent.com/Sauci/39b03e60642a910e358d4dd0871a0b05/raw/b4830fba6d48517950866c14e811000b0ae08020/add_pc_lint_target.cmake 7 | ${CMAKE_CURRENT_SOURCE_DIR}/add_pc_lint_target.cmake) 8 | 9 | file(DOWNLOAD https://gimpel.com/html/pub90/au-misra1.lnt ${MISRA_CONFIG_DIRECTORY}/MISRA1998.lnt) 10 | file(DOWNLOAD https://gimpel.com/html/pub90/au-misra2.lnt ${MISRA_CONFIG_DIRECTORY}/MISRA2004.lnt) 11 | file(DOWNLOAD https://gimpel.com/html/pub90/au-misra3.lnt ${MISRA_CONFIG_DIRECTORY}/MISRA2012.lnt) 12 | 13 | if (${ENABLE_PC_LINT}) 14 | include(add_pc_lint_target.cmake) 15 | endif () 16 | -------------------------------------------------------------------------------- /generated/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_command(OUTPUT 2 | ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Cfg.c 3 | ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Cfg.h 4 | DEPENDS ${XCP_CONFIG_FILEPATH} 5 | ${PROJECT_SOURCE_DIR}/script/header_cfg.h.jinja2 6 | ${PROJECT_SOURCE_DIR}/script/source_cfg.c.jinja2 7 | COMMAND bsw_code_gen 8 | -source_cfg=${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Cfg.c 9 | -header_cfg=${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Cfg.h 10 | -template_directory ${PROJECT_SOURCE_DIR}/script 11 | ${XCP_CONFIG_FILEPATH} 12 | COMMENT "generating configuration source files") 13 | 14 | add_library(Xcp_Cfg STATIC ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Cfg.c) 15 | 16 | target_include_directories(Xcp_Cfg 17 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} 18 | PRIVATE ${PROJECT_SOURCE_DIR}/interface 19 | PRIVATE ${AUTOSAR_STD_HEADER_PATH} 20 | PUBLIC $<$:${PROJECT_SOURCE_DIR}/test/stub>) 21 | 22 | add_custom_command(OUTPUT 23 | ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Rt.c 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Rt.h 25 | DEPENDS ${XCP_CONFIG_FILEPATH} 26 | ${PROJECT_SOURCE_DIR}/script/header_rt.h.jinja2 27 | ${PROJECT_SOURCE_DIR}/script/source_rt.c.jinja2 28 | COMMAND bsw_code_gen 29 | -source_rt=${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Rt.c 30 | -header_rt=${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Rt.h 31 | -template_directory ${PROJECT_SOURCE_DIR}/script 32 | ${XCP_CONFIG_FILEPATH} 33 | COMMENT "generating runtime configuration source files") 34 | 35 | add_library(Xcp_Rt STATIC ${CMAKE_CURRENT_SOURCE_DIR}/Xcp_Rt.c) 36 | 37 | target_include_directories(Xcp_Rt 38 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} 39 | PRIVATE ${PROJECT_SOURCE_DIR}/interface 40 | PRIVATE ${AUTOSAR_STD_HEADER_PATH} 41 | PUBLIC $<$:${PROJECT_SOURCE_DIR}/test/stub>) 42 | 43 | if (${ENABLE_PC_LINT}) 44 | add_pc_lint_target(NAME Xcp_Cfg 45 | DEPENDS Xcp_Cfg.c Xcp_Cfg.h 46 | OUTPUT_LOG ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}_Cfg.lnt.log 47 | EXCLUDE_DIRECTORIES 48 | ${PROJECT_SOURCE_DIR}/interface 49 | ${AUTOSAR_STD_HEADER_PATH} 50 | OPTION_FILES 51 | ${PROJECT_SOURCE_DIR}/extern/lint/MISRA${MISRA_C_VERSION}.lnt 52 | ${PROJECT_SOURCE_DIR}/config/Xcp.lnt) 53 | 54 | add_pc_lint_target(NAME Xcp_Rt 55 | DEPENDS Xcp_Rt.c Xcp_Rt.h 56 | OUTPUT_LOG ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}_Rt.lnt.log 57 | EXCLUDE_DIRECTORIES 58 | ${PROJECT_SOURCE_DIR}/interface 59 | ${AUTOSAR_STD_HEADER_PATH} 60 | OPTION_FILES 61 | ${PROJECT_SOURCE_DIR}/extern/lint/MISRA${MISRA_C_VERSION}.lnt 62 | ${PROJECT_SOURCE_DIR}/config/Xcp.lnt) 63 | endif () 64 | -------------------------------------------------------------------------------- /interface/Xcp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp.h 3 | * @author Guillaume Sottas 4 | * @date 15/01/2018 5 | * 6 | * @defgroup XCP CAN transport layer 7 | * 8 | * @defgroup XCP_H_GDEF identification informations 9 | * @ingroup XCP_H 10 | * @defgroup XCP_H_E errors classification 11 | * @ingroup XCP_H 12 | * @defgroup XCP_H_E_D development errors 13 | * @ingroup XCP_H_E 14 | * @defgroup XCP_H_E_R runtime errors 15 | * @ingroup XCP_H_E 16 | * @defgroup XCP_H_E_T transient faults 17 | * @ingroup XCP_H_E 18 | * @defgroup XCP_H_GTDEF global data type definitions 19 | * @ingroup XCP_H 20 | * @defgroup XCP_H_EFDECL external function declarations 21 | * @ingroup XCP_H 22 | * @defgroup XCP_H_GCDECL global constant declarations 23 | * @ingroup XCP_H 24 | * @defgroup XCP_H_GVDECL global variable declarations 25 | * @ingroup XCP_H 26 | * @defgroup XCP_H_GFDECL global function declarations 27 | * @ingroup XCP_H 28 | * @defgroup XCP_H_GSFDECL global scheduled function declarations 29 | * @ingroup XCP_H 30 | */ 31 | 32 | #ifndef XCP_H 33 | #define XCP_H 34 | 35 | #ifdef __cplusplus 36 | 37 | extern "C" { 38 | 39 | #endif /* #ifdef __cplusplus */ 40 | 41 | /*------------------------------------------------------------------------------------------------*/ 42 | /* included files (#include). */ 43 | /*------------------------------------------------------------------------------------------------*/ 44 | 45 | /** 46 | * @addtogroup XCP_H 47 | * @{ 48 | */ 49 | 50 | #include "Xcp_Types.h" 51 | 52 | #include "Xcp_Errors.h" 53 | 54 | #include "Xcp_SeedKey.h" 55 | 56 | #include "Xcp_Checksum.h" 57 | 58 | #include "Xcp_UserCmd.h" 59 | 60 | #include "Xcp_MemoryAccess.h" 61 | 62 | #if defined(CFFI_ENABLE) 63 | 64 | /** 65 | * @brief if CFFI_ENABLE is defined, expose the Xcp callback function to CFFI module as well as 66 | * the external functions. 67 | */ 68 | #include "XcpOnCan_Cbk.h" 69 | 70 | #ifndef CANIF_H 71 | 72 | #include "CanIf.h" 73 | 74 | #endif /* #ifndef CANIF_H */ 75 | 76 | #if (XCP_DEV_ERROR_DETECT == STD_ON) 77 | 78 | #include "Det.h" 79 | 80 | #endif /* #if (XCP_DEV_ERROR_DETECT == STD_ON) */ 81 | 82 | #endif /* #if defined(CFFI_ENABLE) */ 83 | 84 | /** @} */ 85 | 86 | /*------------------------------------------------------------------------------------------------*/ 87 | /* global definitions (#define). */ 88 | /*------------------------------------------------------------------------------------------------*/ 89 | 90 | /** 91 | * @addtogroup XCP_H_GDEF 92 | * @{ 93 | */ 94 | 95 | /** 96 | * @brief unique identifier of the XCP driver. 97 | * @note this value corresponds to document ID of corresponding Autosar software specification. 98 | */ 99 | #define XCP_MODULE_ID (0xFFu) 100 | 101 | #ifndef XCP_SW_MAJOR_VERSION 102 | 103 | /** 104 | * @brief XCP driver major version number. 105 | */ 106 | #define XCP_SW_MAJOR_VERSION (0x00u) 107 | 108 | #endif /* #ifndef XCP_SW_MAJOR_VERSION */ 109 | 110 | #ifndef XCP_SW_MINOR_VERSION 111 | 112 | /** 113 | * @brief XCP driver minor version number. 114 | */ 115 | #define XCP_SW_MINOR_VERSION (0x01u) 116 | 117 | #endif /* #ifndef XCP_SW_MINOR_VERSION */ 118 | 119 | #ifndef XCP_SW_PATCH_VERSION 120 | 121 | /** 122 | * @brief XCP driver patch version number. 123 | */ 124 | #define XCP_SW_PATCH_VERSION (0x00u) 125 | 126 | #endif /* #ifndef XCP_SW_PATCH_VERSION */ 127 | 128 | /** 129 | * @brief @ref Xcp_Init API ID. 130 | */ 131 | #define XCP_INIT_API_ID (0x00u) 132 | 133 | /** 134 | * @brief @ref Xcp_GetVersionInfo API ID. 135 | */ 136 | #define XCP_GET_VERSION_INFO_API_ID (0x01u) 137 | 138 | /** 139 | * @brief @ref Xcp_SetTransmissionMode API ID. 140 | */ 141 | #define XCP_SET_TRANSMISSION_MODE_API_ID (0x05u) 142 | 143 | /** 144 | * @brief @ref Xcp_MainFunction API ID. 145 | */ 146 | #define XCP_MAIN_FUNCTION_API_ID (0x04u) 147 | 148 | /** 149 | * @brief @ref Xcp_CanIfTxConfirmation API ID. 150 | */ 151 | #define XCP_CAN_IF_TX_CONFIRMATION_API_ID (0x40u) 152 | 153 | /** 154 | * @brief @ref Xcp_CanIfTriggerTransmit API ID. 155 | */ 156 | #define XCP_CAN_IF_TRIGGER_TRANSMIT_API_ID (0x41u) 157 | 158 | /** 159 | * @brief @ref Xcp_CanIfRxIndication API ID. 160 | */ 161 | #define XCP_CAN_IF_RX_INDICATION_API_ID (0x42u) 162 | 163 | /** @} */ 164 | 165 | /** 166 | * @addtogroup XCP_H_E_D 167 | * @{ 168 | */ 169 | 170 | /** 171 | * @brief Module not initialized. 172 | */ 173 | #define XCP_E_UNINIT (0x02u) 174 | 175 | /** 176 | * @brief Initialization of XCP failed. 177 | */ 178 | #define XCP_E_INIT_FAILED (0x04u) 179 | 180 | /** 181 | * @brief Null pointer has been passed as an argument. 182 | */ 183 | #define XCP_E_PARAM_POINTER (0x12u) 184 | 185 | /** 186 | * @brief API call with wrong PDU ID. 187 | */ 188 | #define XCP_E_INVALID_PDUID (0x03u) 189 | 190 | /** 191 | * @brief The stack tried to stack an event while the queue was full. 192 | * @note This error is not part of the specification. 193 | */ 194 | #define XCP_E_EVENT_QUEUE_FULL (0x04u) 195 | 196 | /** @} */ 197 | 198 | /** 199 | * @addtogroup XCP_H_E_R 200 | * @{ 201 | */ 202 | 203 | /** @} */ 204 | 205 | /** 206 | * @addtogroup XCP_H_E_T 207 | * @{ 208 | */ 209 | 210 | /** @} */ 211 | 212 | /*------------------------------------------------------------------------------------------------*/ 213 | /* global data type definitions (typedef, struct). */ 214 | /*------------------------------------------------------------------------------------------------*/ 215 | 216 | /** 217 | * @addtogroup XCP_H_GTDEF 218 | * @{ 219 | */ 220 | 221 | typedef enum { 222 | XCP_UNINITIALIZED = 0x00u, 223 | XCP_INITIALIZED, 224 | } Xcp_StateType; 225 | 226 | /** @} */ 227 | 228 | /*------------------------------------------------------------------------------------------------*/ 229 | /* external function declarations (extern). */ 230 | /*------------------------------------------------------------------------------------------------*/ 231 | 232 | /** 233 | * @addtogroup XCP_H_EFDECL 234 | * @{ 235 | */ 236 | 237 | /** @} */ 238 | 239 | /*------------------------------------------------------------------------------------------------*/ 240 | /* global constant declarations (extern const). */ 241 | /*------------------------------------------------------------------------------------------------*/ 242 | 243 | /** 244 | * @addtogroup XCP_H_GCDECL 245 | * @{ 246 | */ 247 | 248 | /** @} */ 249 | 250 | /*------------------------------------------------------------------------------------------------*/ 251 | /* global variable declarations (extern). */ 252 | /*------------------------------------------------------------------------------------------------*/ 253 | 254 | /** 255 | * @addtogroup XCP_H_GVDECL 256 | * @{ 257 | */ 258 | 259 | #ifdef CFFI_ENABLE 260 | 261 | extern Xcp_StateType Xcp_State; 262 | 263 | extern const Xcp_Type *Xcp_Ptr; 264 | 265 | #endif /* #ifndef CFFI_ENABLE */ 266 | 267 | /** @} */ 268 | 269 | /*------------------------------------------------------------------------------------------------*/ 270 | /* global function declarations. */ 271 | /*------------------------------------------------------------------------------------------------*/ 272 | 273 | /** 274 | * @addtogroup XCP_H_GFDECL 275 | * @{ 276 | */ 277 | 278 | #define Xcp_START_SEC_CODE_SLOW 279 | #include "Xcp_MemMap.h" 280 | 281 | /** 282 | * @brief this service initializes interfaces and variables of the AUTOSAR XCP layer. 283 | * @param [in] pConfig pointer to a selected configuration structure 284 | */ 285 | void Xcp_Init(const Xcp_Type *pConfig); 286 | 287 | #define Xcp_STOP_SEC_CODE_SLOW 288 | #include "Xcp_MemMap.h" 289 | 290 | #if (XCP_GET_VERSION_INFO_API == STD_ON) 291 | 292 | #define Xcp_START_SEC_CODE_SLOW 293 | #include "Xcp_MemMap.h" 294 | 295 | /** 296 | * @brief returns the version information of this module. 297 | * @param [out] pVersionInfo pointer to where to store the version information of this module 298 | */ 299 | void Xcp_GetVersionInfo(Std_VersionInfoType *pVersionInfo); 300 | 301 | #define Xcp_STOP_SEC_CODE_SLOW 302 | #include "Xcp_MemMap.h" 303 | 304 | #endif /* #if (XCP_GET_VERSION_INFO_API == STD_ON) */ 305 | 306 | #if (XCP_SUPPRESS_TX_SUPPORT == STD_ON) 307 | 308 | #define Xcp_START_SEC_CODE_FAST 309 | #include "Xcp_MemMap.h" 310 | 311 | /** 312 | * @brief this API is used to turn on and off of the TX capabilities of used communication bus 313 | * channel in XCP module. 314 | * @param [in] channel the Network channel for the used bus communication 315 | * @param [in] mode enabled or disabled Transmission mode Parameters 316 | */ 317 | void Xcp_SetTransmissionMode(NetworkHandleType channel, Xcp_TransmissionModeType mode); 318 | 319 | #define Xcp_STOP_SEC_CODE_FAST 320 | #include "Xcp_MemMap.h" 321 | 322 | #endif /* #if (XCP_SUPPRESS_TX_SUPPORT == STD_ON) */ 323 | 324 | /** @} */ 325 | 326 | /*------------------------------------------------------------------------------------------------*/ 327 | /* global scheduled function declarations. */ 328 | /*------------------------------------------------------------------------------------------------*/ 329 | 330 | /** 331 | * @addtogroup XCP_H_GSFDECL 332 | * @{ 333 | */ 334 | 335 | #define Xcp_START_SEC_CODE_FAST 336 | #include "Xcp_MemMap.h" 337 | 338 | /** 339 | * @brief the main function for scheduling the CAN TP. 340 | */ 341 | void Xcp_MainFunction(void); 342 | 343 | #define Xcp_STOP_SEC_CODE_FAST 344 | #include "Xcp_MemMap.h" 345 | 346 | /** @} */ 347 | 348 | #ifdef __cplusplus 349 | }; 350 | 351 | #endif /* #ifdef __cplusplus */ 352 | 353 | #endif /* #ifndef XCP_H */ 354 | -------------------------------------------------------------------------------- /interface/XcpOnCan_Cbk.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file XcpOnCan_Cbk.h 3 | * @author Guillaume Sottas 4 | * @date 15/01/2018 5 | * 6 | * @defgroup XCP_CBK notifications 7 | * @ingroup XCP 8 | * 9 | * @brief notifications provided by CAN transport layer. 10 | * 11 | * @defgroup XCP_CBK_GCFDECL global callback function declarations 12 | * @ingroup XCP_CBK 13 | */ 14 | 15 | #ifndef XCPONCAN_CBK_H 16 | #define XCPONCAN_CBK_H 17 | 18 | #ifdef __cplusplus 19 | 20 | extern "C" { 21 | 22 | #endif /* #ifdef __cplusplus */ 23 | 24 | /*------------------------------------------------------------------------------------------------*/ 25 | /* included files (#include). */ 26 | /*------------------------------------------------------------------------------------------------*/ 27 | 28 | /** 29 | * @addtogroup XCP_CBK 30 | * @{ 31 | */ 32 | 33 | /** @} */ 34 | 35 | /*------------------------------------------------------------------------------------------------*/ 36 | /* global callback function declarations. */ 37 | /*------------------------------------------------------------------------------------------------*/ 38 | 39 | /** 40 | * @addtogroup XCP_CBK_GCFDECL 41 | * @{ 42 | */ 43 | 44 | #define Xcp_START_SEC_CODE_FAST 45 | #include "Xcp_MemMap.h" 46 | 47 | /** 48 | * @brief indication of a received PDU from a lower layer communication interface module. 49 | * @param [in] rxPduId ID of the received PDU. 50 | * @param [in] pPduInfo contains the length (SduLength) of the received PDU, a pointer to a buffer 51 | * (SduDataPtr) containing the PDU, and the MetaData related to this PDU 52 | */ 53 | void Xcp_CanIfRxIndication(PduIdType rxPduId, const PduInfoType *pPduInfo); 54 | 55 | #define Xcp_STOP_SEC_CODE_FAST 56 | #include "Xcp_MemMap.h" 57 | 58 | #define Xcp_START_SEC_CODE_FAST 59 | #include "Xcp_MemMap.h" 60 | 61 | /** 62 | * @brief the lower layer communication interface module confirms the transmission of a PDU, or the 63 | * failure to transmit a PDU. 64 | * @param [in] txPduId ID of the PDU that has been transmitted 65 | * @param [in] result E_OK: the PDU was transmitted, E_NOT_OK: transmission of the PDU failed 66 | */ 67 | void Xcp_CanIfTxConfirmation(PduIdType txPduId, Std_ReturnType result); 68 | 69 | #define Xcp_STOP_SEC_CODE_FAST 70 | #include "Xcp_MemMap.h" 71 | 72 | #define Xcp_START_SEC_CODE_FAST 73 | #include "Xcp_MemMap.h" 74 | 75 | /** 76 | * @brief within this API, the upper layer module (called module) shall check whether the available 77 | * data fits into the buffer size reported by PduInfoPtr->SduLength. If it fits, it shall copy its 78 | * data into the buffer provided by PduInfoPtr->SduDataPtr and update the length of the actual 79 | * copied data in PduInfoPtr->SduLength. If not, it returns E_NOT_OK without changing PduInfoPtr. 80 | * @param [in] txPduId ID of the SDU that is requested to be transmitted 81 | * @param [in/out] pPduInfo contains a pointer to a buffer (SduDataPtr) to where the SDU data shall 82 | * be copied, and the available buffer size in SduLength. On return, the service will indicate the 83 | * length of the copied SDU data in SduLength 84 | * @retval E_OK: SDU has been copied and SduLength indicates the number of copied bytes 85 | * @retval E_NOT_OK: No SDU data has been copied. PduInfoPtr must not be used since it may contain a 86 | * NULL pointer or point to invalid data. 87 | */ 88 | Std_ReturnType Xcp_CanIfTriggerTransmit(PduIdType txPduId, PduInfoType* pPduInfo); 89 | 90 | 91 | #define Xcp_STOP_SEC_CODE_FAST 92 | #include "Xcp_MemMap.h" 93 | 94 | /** @} */ 95 | 96 | #ifdef __cplusplus 97 | } 98 | 99 | #endif /* #ifdef __cplusplus */ 100 | 101 | #endif /* #ifndef XCPONCAN_CBK_H */ 102 | -------------------------------------------------------------------------------- /interface/Xcp_Errors.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_errors.h 3 | * @author Guillaume Sottas 4 | * @date 20/01/2022 5 | */ 6 | 7 | #ifndef XCP_ERRORS_H 8 | #define XCP_ERRORS_H 9 | 10 | /*------------------------------------------------------------------------------------------------*/ 11 | /* global definitions (#define). */ 12 | /*------------------------------------------------------------------------------------------------*/ 13 | 14 | /** 15 | * @brief Command processor synchronization (see ASAM protocol layer specification 1.7.3.1) 16 | */ 17 | #define XCP_E_ASAM_CMD_SYNCH (0x00u) 18 | 19 | /** 20 | * @brief Command was not executed (see ASAM protocol layer specification 1.7.3.1) 21 | */ 22 | #define XCP_E_ASAM_CMD_BUSY (0x10u) 23 | 24 | /** 25 | * @brief Command rejected because PGM is running (see ASAM protocol layer specification 1.7.3.1) 26 | */ 27 | #define XCP_E_ASAM_PGM_ACTIVE (0x12u) 28 | 29 | /** 30 | * @brief Unknown command or not implemented optional command (see ASAM protocol layer specification 31 | * 1.7.3.1) 32 | */ 33 | #define XCP_E_ASAM_CMD_UNKNOWN (0x20u) 34 | 35 | /** 36 | * @brief Command syntax invalid (see ASAM protocol layer specification 1.7.3.1) 37 | */ 38 | #define XCP_E_ASAM_CMD_SYNTAX (0x21u) 39 | 40 | /** 41 | * @brief Command syntax valid but command parameter(s) out of range (see ASAM protocol layer 42 | * specification 1.7.3.1) 43 | */ 44 | #define XCP_E_ASAM_OUT_OF_RANGE (0x22u) 45 | 46 | /** 47 | * @brief Access denied, Seed & Key is required (see ASAM protocol layer specification 1.7.3.1) 48 | */ 49 | #define XCP_E_ASAM_ACCESS_LOCKED (0x25u) 50 | 51 | /** 52 | * @brief Sequence error (see ASAM protocol layer specification 1.7.3.1) 53 | */ 54 | #define XCP_E_ASAM_SEQUENCE (0x29u) 55 | 56 | #endif /* #ifndef XCP_ERRORS_H */ 57 | -------------------------------------------------------------------------------- /interface/Xcp_Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_Types.h 3 | * @author Guillaume Sottas 4 | * @date 10/12/2021 5 | */ 6 | 7 | #ifndef XCP_TYPES_H 8 | #define XCP_TYPES_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | /*------------------------------------------------------------------------------------------------*/ 17 | /* included files (#include). */ 18 | /*------------------------------------------------------------------------------------------------*/ 19 | 20 | /** 21 | * @addtogroup XCP_TYPES_H 22 | * @{ 23 | */ 24 | 25 | #ifndef COMSTACK_TYPES_H 26 | 27 | #include "ComStack_Types.h" 28 | 29 | #endif /* #ifndef COMSTACK_TYPES_H */ 30 | 31 | /** @} */ 32 | 33 | /*------------------------------------------------------------------------------------------------*/ 34 | /* global definitions (#define). */ 35 | /*------------------------------------------------------------------------------------------------*/ 36 | 37 | #ifndef XCP_EVENT_USER_DATA_SIZE 38 | 39 | #define XCP_EVENT_USER_DATA_SIZE (0x10u) 40 | 41 | #endif /* #ifndef XCP_EVENT_USER_DATA_SIZE */ 42 | 43 | /** @} */ 44 | 45 | /*------------------------------------------------------------------------------------------------*/ 46 | /* global data type definitions (typedef, struct). */ 47 | /*------------------------------------------------------------------------------------------------*/ 48 | 49 | /** 50 | * @addtogroup XCP_H_GTDEF 51 | * @{ 52 | */ 53 | 54 | typedef enum 55 | { 56 | /** 57 | * @brief Transmission Disabled 58 | */ 59 | XCP_TX_OFF = 0x00u, 60 | 61 | /** 62 | * @brief Transmission Enabled 63 | */ 64 | XCP_TX_ON = 0x01u 65 | 66 | } Xcp_TransmissionModeType; 67 | 68 | typedef enum 69 | { 70 | /** 71 | * @brief only DAQ supported (default value) 72 | */ 73 | DAQ = 0x00u, 74 | 75 | /** 76 | * @brief both DAQ and STIM supported (simultaneously) 77 | */ 78 | DAQ_STIM, 79 | 80 | /** 81 | * @brief only STIM supported 82 | */ 83 | STIM 84 | } Xcp_EventChannelTypeType; 85 | 86 | typedef enum 87 | { 88 | /** 89 | * @brief if XCP_DAQ_DYNAMIC is selected, the DAQ_CONFIG_TYPE bit is set to 1 90 | */ 91 | DAQ_DYNAMIC, 92 | 93 | /** 94 | * @brief if XCP_DAQ_STATIC is selected, the DAQ_CONFIG_TYPE bit is set to 0 95 | */ 96 | DAQ_STATIC 97 | } Xcp_DaqConfigTypeType; 98 | 99 | typedef enum 100 | { 101 | /** 102 | * @brief absolute ODT number 103 | */ 104 | ABSOLUTE, 105 | 106 | /** 107 | * @brief relative ODT number, absolute DAQ list number (BYTE) 108 | */ 109 | RELATIVE_BYTE, 110 | 111 | /** 112 | * @brief relative ODT number, absolute DAQ list number (WORD) 113 | */ 114 | RELATIVE_WORD, 115 | 116 | /** 117 | * @brief relative ODT number, absolute DAQ list number (WORD, aligned) 118 | */ 119 | RELATIVE_WORD_ALIGNED 120 | } Xcp_IdentificationFieldTypeType; 121 | 122 | typedef enum 123 | { 124 | /** 125 | * @brief timestamp field is not available 126 | */ 127 | NO_TIME_STAMP, 128 | 129 | /** 130 | * @brief timestamp field has the size of one byte 131 | */ 132 | ONE_BYTE, 133 | 134 | /** 135 | * @brief timestamp field has the size of two byte 136 | */ 137 | TWO_BYTE, 138 | 139 | /** 140 | * @brief timestamp field has the size of four byte 141 | */ 142 | FOUR_BYTE 143 | } Xcp_TimestampTypeType; 144 | 145 | typedef enum 146 | { 147 | /** 148 | * @brief unit is 100 millisecond 149 | */ 150 | TIMESTAMP_UNIT_100MS = 0x08u, 151 | 152 | /** 153 | * @brief unit is 100 nanosecond 154 | */ 155 | TIMESTAMP_UNIT_100NS = 0x02u, 156 | 157 | /** 158 | * @brief unit is 100 picosecond 159 | TIMESTAMP_UNIT_100PS,*/ 160 | 161 | /** 162 | * @brief unit is 100 microsecond 163 | */ 164 | TIMESTAMP_UNIT_100US = 0x05u, 165 | 166 | /** 167 | * @brief unit is 10 millisecond 168 | */ 169 | TIMESTAMP_UNIT_10MS = 0x07u, 170 | 171 | /** 172 | * @brief unit is 10 nanosecond 173 | */ 174 | TIMESTAMP_UNIT_10NS = 0x01u, 175 | 176 | /** 177 | * @brief unit is 10 picosecond 178 | TIMESTAMP_UNIT_10PS,*/ 179 | 180 | /** 181 | * @brief unit is 10 microsecond 182 | */ 183 | TIMESTAMP_UNIT_10US = 0x04u, 184 | 185 | /** 186 | * @brief unit is 1 millisecond 187 | */ 188 | TIMESTAMP_UNIT_1MS = 0x06u, 189 | 190 | /** 191 | * @brief unit is 1 nanosecond 192 | */ 193 | TIMESTAMP_UNIT_1NS = 0x00u, 194 | 195 | /** 196 | * @brief unit is 1 picosecond 197 | TIMESTAMP_UNIT_1PS,*/ 198 | 199 | /** 200 | * @brief unit is 1 second 201 | */ 202 | TIMESTAMP_UNIT_1S = 0x09u, 203 | 204 | /** 205 | * @brief unit is 1 microsecond 206 | */ 207 | TIMESTAMP_UNIT_1US = 0x03u 208 | } Xcp_TimestampUnitType; 209 | 210 | typedef enum 211 | { 212 | /** 213 | * @brief consistency on ODT level (default value) 214 | */ 215 | ODT = 0x00u, 216 | 217 | /** 218 | * @brief consistency on DAQ list level 219 | */ 220 | //DAQ, 221 | 222 | /** 223 | * @brief consistency on event channel level 224 | */ 225 | EVENT 226 | } Xcp_EventChannelConsistencyType; 227 | 228 | /** 229 | * @brief BYTE_ORDER indicates the byte order used for transferring multi-byte parameters in an XCP 230 | * Packet. BYTE_ORDER = 0 means Intel format, BYTE_ORDER = 1 means Motorola format. Motorola format 231 | * means MSB on lower address/position. 232 | * 233 | * @note This enumeration is not specified in the AUTOSAR specification, but in the ASAM XCP part 234 | * 2 - Protocol Layer Specification 1.0/1.6.1.1.1 235 | */ 236 | typedef enum 237 | { 238 | LITTLE_ENDIAN = 0x00u, 239 | BIG_ENDIAN = 0x01u 240 | } Xcp_ByteOrderType; 241 | 242 | /** 243 | * @brief The address granularity indicates the size of an element contained at a single address. It 244 | * is needed if the master has to do address calculation. 245 | * 246 | * @note This enumeration is not specified in the AUTOSAR specification, but in the ASAM XCP part 247 | * 2 - Protocol Layer Specification 1.0/1.6.1.1.1 248 | */ 249 | typedef enum 250 | { 251 | BYTE = 0x00u, 252 | WORD = 0x01u, 253 | DWORD = 0x02u 254 | } Xcp_AddressGranularityType; 255 | 256 | typedef enum 257 | { 258 | XCP_ADD_11, 259 | XCP_ADD_12, 260 | XCP_ADD_14, 261 | XCP_ADD_22, 262 | XCP_ADD_24, 263 | XCP_ADD_44, 264 | XCP_CRC_16, 265 | XCP_CRC_16_CITT, 266 | XCP_CRC_32, 267 | XCP_USER_DEFINED 268 | } Xcp_ChecksumType; 269 | 270 | typedef struct 271 | { 272 | const uint16 id; 273 | const void *pdu; 274 | } Xcp_RxPduType; 275 | 276 | typedef struct 277 | { 278 | const uint16 id; 279 | const void *pdu; 280 | } Xcp_TxPduType; 281 | 282 | typedef struct 283 | { 284 | const Xcp_RxPduType *channel_rx_pdu_ref; 285 | const Xcp_TxPduType *channel_tx_pdu_ref; 286 | const void *com_m_channel_ref; 287 | } Xcp_CommunicationChannelType; 288 | 289 | typedef struct 290 | { 291 | const uint8 id; 292 | const union 293 | { 294 | Xcp_RxPduType rxPdu; 295 | Xcp_TxPduType txPdu; 296 | } dto2PduMapping; 297 | } Xcp_DtoType; 298 | 299 | /** 300 | * @brief this container collects all configuration parameters that comprise an ODT entry. 301 | */ 302 | typedef struct 303 | { 304 | /** 305 | * @brief memory address that the ODT entry is referencing to 306 | */ 307 | uint32 *address; 308 | 309 | /** 310 | * @brief represent the bit offset in case of the element represents status bit 311 | */ 312 | uint8 bitOffset; 313 | 314 | /** 315 | * @brief length of the referenced memory area that is referenced by the ODT entry 316 | */ 317 | uint8 length; 318 | 319 | /** 320 | * @brief index number of the ODT entry 321 | */ 322 | const uint8 number; 323 | } Xcp_OdtEntryType; 324 | 325 | /** 326 | * @brief this container contains ODT-specific parameter for the DAQ list. 327 | */ 328 | typedef struct 329 | { 330 | /** 331 | * @brief this parameter indicates the upper limit for the size of the element described by an 332 | * ODT entry. depending on the DaqListType this ODT belongs to it describes the limit for a DAQ 333 | * (MAX_ODT_ENTRY_SIZE_DAQ) or a STIM (MAX_ODT_ENTRY_SIZE_STIM) 334 | */ 335 | const uint8 odtEntryMaxSize; 336 | 337 | /** 338 | * @brief index number of this ODT within the DAQ list 339 | */ 340 | const uint8 odtNumber; 341 | 342 | /** 343 | * @brief this reference maps the ODT to the according DTO in which it will be transmitted 344 | */ 345 | const Xcp_DtoType *odt2DtoMapping; 346 | 347 | /** 348 | * @brief This container collects all configuration parameters that comprise an ODT entry 349 | */ 350 | Xcp_OdtEntryType *odtEntry; 351 | } Xcp_OdtType; 352 | 353 | typedef struct 354 | { 355 | const uint16 number; 356 | const Xcp_EventChannelTypeType type; 357 | const uint8 maxOdt; 358 | const uint8 maxOdtEntries; 359 | const Xcp_DtoType *dto; 360 | const uint32 dtoCount; /* TODO: check if this value can be retrieved from somewhere else... */ 361 | Xcp_OdtType *odt; 362 | } Xcp_DaqListType; 363 | 364 | /** 365 | * @brief This container contains the configuration of event channels on the XCP slave. 366 | */ 367 | typedef struct 368 | { 369 | /** 370 | * @brief Type of consistency used by event channel. 371 | */ 372 | Xcp_EventChannelConsistencyType consistency; 373 | 374 | /** 375 | * @brief Maximum amount of DAQ lists that are handled by this event channel. 376 | */ 377 | uint8 maxDaqList; 378 | 379 | /** 380 | * @brief Index number of the event channel. 381 | */ 382 | uint16 number; 383 | 384 | /** 385 | * @brief Priority of the event channel. 386 | */ 387 | uint8 priority; 388 | 389 | /** 390 | * @brief The event channel time cycle indicates which sampling period is used to process this 391 | * event channel. A value of 0 means 'Not cyclic'. 392 | */ 393 | uint8 timeCycle; 394 | 395 | /** 396 | * @brief This configuration parameter indicates the unit of the event channel time cycle. 397 | */ 398 | Xcp_TimestampUnitType timeUnit; 399 | 400 | /** 401 | * This configuration parameter indicates what kind of DAQ list can be allocated to this event 402 | * channel. 403 | */ 404 | Xcp_EventChannelTypeType type; 405 | 406 | /** 407 | * @brief References all DAQ lists that are trigged by this event channel. 408 | */ 409 | const Xcp_DaqListType *triggeredDaqListRef; 410 | const uint32 triggeredDaqListRefCount; 411 | } Xcp_EventChannelType; 412 | 413 | typedef struct 414 | { 415 | const Xcp_DaqConfigTypeType daqConfigType; 416 | const uint16 daqCount; 417 | const boolean devErrorDetect; 418 | const boolean flashProgrammingEnabled; 419 | const Xcp_IdentificationFieldTypeType identificationFieldType; 420 | const ieee_float mainFunctionPeriod; 421 | const uint16 maxCto; 422 | const uint16 maxDto; 423 | const uint16 maxEventChannel; 424 | const uint8 minDaq; 425 | const uint8 odtCount; 426 | const uint8 odtEntriesCount; 427 | const uint8 odtEntrySizeDaq; 428 | const uint8 odtEntrySizeStim; 429 | const boolean xcpOnCanEnabled; 430 | const boolean xcpOnCddEnabled; 431 | const boolean xcpOnEthernetEnable; 432 | const boolean xcpOnFlexRayEnabled; 433 | const boolean prescalerSupported; 434 | const boolean suppressTxSupport; 435 | const uint16 timestampTicks; 436 | const Xcp_TimestampTypeType timestampType; 437 | const Xcp_TimestampUnitType timestampUnit; 438 | const boolean versionInfoApi; 439 | /* TODO: pass a callback function here... */ 440 | const void *counter; 441 | const void *nvRamBlockId; 442 | const uint8 ctoInfo[0x100u]; /* not part of the specification... */ 443 | const Xcp_ByteOrderType byteOrder; /* not part of the specification... */ 444 | const Xcp_AddressGranularityType addressGranularity; /* not part of the specification... */ 445 | const boolean masterBlockModeSupported; /* not part of the specification... */ 446 | const boolean slaveBlockModeSupported; /* not part of the specification... */ 447 | const boolean interleavedModeSupported; /* not part of the specification... */ 448 | const uint8 maxBS; /* not part of the specification... */ 449 | const uint8 minST; /* not part of the specification... */ 450 | const uint8 ctoQueueSize; /* not part of the specification... */ 451 | const uint8 eventQueueSize; /* not part of the specification... */ 452 | const uint8 protectedResource; /* not part of the specification... */ 453 | const Xcp_ChecksumType checksumType; /* not part of the specification... */ 454 | void *(*const userDefinedChecksumFunction)(void *lowerAddress, const void *upperAddress, uint32 *pResult); /* not part of the specification... */ 455 | uint8 (*const userCmdFunction)(const PduInfoType *pCtoPduInfo, PduInfoType *pResErrPduInfo); /* not part of the specification... */ 456 | const uint8 trailingValue; /* not part of the specification... */ 457 | const char *identification; /* not part of the specification... */ 458 | } Xcp_GeneralType; 459 | 460 | /** 461 | * @brief this is the type of the data structure containing the initialization data for XCP. 462 | */ 463 | typedef struct 464 | { 465 | const Xcp_CommunicationChannelType *communicationChannel; 466 | Xcp_DaqListType *daqList; 467 | const uint16 daqListCount; /* not part of the specification... */ 468 | const Xcp_EventChannelType *eventChannel; 469 | const void *pdu; 470 | } Xcp_ConfigType; 471 | 472 | typedef struct { 473 | uint8 packetID; 474 | uint8 eventCode; 475 | uint8 userData[XCP_EVENT_USER_DATA_SIZE]; 476 | uint32 userDataSize; 477 | } Xcp_EventType; 478 | 479 | typedef struct { 480 | Xcp_EventType *queue; 481 | uint32 read; 482 | uint32 write; 483 | } Xcp_EventQueueType; 484 | 485 | typedef struct { 486 | Xcp_EventQueueType *eventQueue; 487 | } Xcp_RtType; 488 | 489 | typedef struct 490 | { 491 | const Xcp_ConfigType *config; 492 | const Xcp_GeneralType *general; 493 | const uint8 xcpRtRef; /* not part of the specification... */ 494 | } Xcp_Type; 495 | 496 | /** @} */ 497 | 498 | #ifdef __cplusplus 499 | }; 500 | 501 | #endif /* ifdef __cplusplus */ 502 | 503 | #endif /* define XCP_TYPES_H */ 504 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cffi==1.15.0 2 | crcmod~=1.7 3 | jinja2==2.11.3 4 | jsonschema==3.0.1 5 | pcpp==1.22 6 | pycparser==2.21.0 7 | pytest 8 | pytest_cases 9 | pytest-xdist 10 | bsw_code_gen~=0.1.8 11 | MarkupSafe==2.0.1 # required to fix https://github.com/aws/aws-sam-cli/issues/3661 12 | -------------------------------------------------------------------------------- /script/header_cfg.h.jinja2: -------------------------------------------------------------------------------- 1 | #ifndef XCP_CFG_H 2 | #define XCP_CFG_H 3 | 4 | #ifndef XCP_TYPES_H 5 | #include "Xcp_Types.h" 6 | #endif /* #ifndef XCP_TYPES_H */ 7 | 8 | #ifndef XCP_CHECKSUM_H 9 | #include "Xcp_Checksum.h" 10 | #endif /* #ifndef XCP_CHECKSUM_H */ 11 | 12 | #ifndef XCP_USER_CMD_H 13 | #include "Xcp_UserCmd.h" 14 | #endif /* #ifndef XCP_USER_CMD_H */ 15 | 16 | #define Xcp_START_SEC_CONST_UNSPECIFIED 17 | #include "Xcp_MemMap.h" 18 | 19 | extern const Xcp_Type Xcp[{{'0x%02Xu' % configurations|length}}]; 20 | 21 | #define Xcp_STOP_SEC_CONST_UNSPECIFIED 22 | #include "Xcp_MemMap.h" 23 | 24 | #endif /* #ifndef XCP_CFG_H */ 25 | -------------------------------------------------------------------------------- /script/header_rt.h.jinja2: -------------------------------------------------------------------------------- 1 | #ifndef XCP_RT_H 2 | #define XCP_RT_H 3 | 4 | #ifndef XCP_TYPES_H 5 | 6 | #include "Xcp_Types.h" 7 | 8 | #endif /* #ifndef XCP_TYPES_H */ 9 | 10 | #define Xcp_START_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 11 | #include "Xcp_MemMap.h" 12 | 13 | extern Xcp_RtType Xcp_Rt[{{'0x%02Xu' % configurations|length}}]; 14 | 15 | #define Xcp_STOP_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 16 | #include "Xcp_MemMap.h" 17 | 18 | #endif /* #ifndef XCP_RT_H */ -------------------------------------------------------------------------------- /script/source_rt.c.jinja2: -------------------------------------------------------------------------------- 1 | 2 | #ifndef XCP_RT_H 3 | 4 | #include "Xcp_Rt.h" 5 | 6 | #endif /* #ifndef XCP_RT_H */ 7 | {% for configuration in configurations %} 8 | #define Xcp_START_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 9 | #include "Xcp_MemMap.h" 10 | 11 | static Xcp_EventType Xcp_Event00[{{'0x%02Xu' % configuration.protocol_layer.event_queue_size}}]; 12 | 13 | #define Xcp_STOP_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 14 | #include "Xcp_MemMap.h" 15 | 16 | #define Xcp_START_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 17 | #include "Xcp_MemMap.h" 18 | 19 | static Xcp_EventQueueType Xcp_EventQueue00 = { 20 | &Xcp_Event00[0x00u], 21 | 0x00000000u, 22 | 0x00000000u 23 | }; 24 | 25 | #define Xcp_STOP_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 26 | #include "Xcp_MemMap.h" 27 | {%- endfor %} 28 | 29 | #define Xcp_START_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 30 | #include "Xcp_MemMap.h" 31 | 32 | Xcp_RtType Xcp_Rt[{{'0x%02Xu' % configurations|length}}] = { 33 | {%- for configuration in configurations %} 34 | { 35 | &Xcp_EventQueue{{'%02X' % loop.index0}} 36 | }, 37 | {%- endfor %} 38 | }; 39 | 40 | #define Xcp_STOP_SEC_VAR_FAST_POWER_ON_INIT_UNSPECIFIED 41 | #include "Xcp_MemMap.h" 42 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | result=0 4 | mkdir -p build 5 | cd build 6 | cmake .. -DXCP_ENABLE_TEST=ON 7 | make all 8 | LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/project/build" ctest -V 9 | result=$? 10 | gcov _cffi_xcp.c 11 | exit $result 12 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | from .conftest import XcpTest 2 | from .parameter import * 3 | -------------------------------------------------------------------------------- /test/asam_protocol_layer_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from unittest.mock import ANY 5 | 6 | from .parameter import * 7 | from .conftest import XcpTest 8 | 9 | 10 | @pytest.mark.parametrize('max_cto, address_granularity', ((1, 'WORD'), 11 | (3, 'WORD'), 12 | (1, 'DWORD'), 13 | (3, 'DWORD'))) 14 | def test_xcp_init_raises_e_init_failed_if_max_cto_parameter_does_not_fit_with_address_granularity(max_cto, 15 | address_granularity): 16 | handle = XcpTest(DefaultConfig(max_cto=max_cto, address_granularity=address_granularity)) 17 | handle.det_report_error.assert_called_once_with(ANY, 18 | ANY, 19 | handle.define('XCP_INIT_API_ID'), 20 | handle.define('XCP_E_INIT_FAILED')) 21 | 22 | 23 | @pytest.mark.parametrize('max_dto, address_granularity', ((1, 'WORD'), 24 | (3, 'WORD'), 25 | (1, 'DWORD'), 26 | (3, 'DWORD'))) 27 | def test_xcp_init_raises_e_init_failed_if_max_dto_parameter_does_not_fit_with_address_granularity(max_dto, 28 | address_granularity): 29 | handle = XcpTest(DefaultConfig(max_dto=max_dto, address_granularity=address_granularity)) 30 | handle.det_report_error.assert_called_once_with(ANY, 31 | ANY, 32 | handle.define('XCP_INIT_API_ID'), 33 | handle.define('XCP_E_INIT_FAILED')) 34 | 35 | 36 | def test_command_get_status_sets_the_packet_id_byte_to_pid_response_on_positive_response(): 37 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 38 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 39 | handle.lib.Xcp_MainFunction() 40 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 41 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFD,))) 42 | handle.lib.Xcp_MainFunction() 43 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[0] == 0xFF 44 | -------------------------------------------------------------------------------- /test/autosar_sws_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from unittest.mock import ANY 5 | 6 | import pytest 7 | 8 | from .parameter import * 9 | from .conftest import XcpTest 10 | 11 | 12 | def test_sws_00802(): 13 | """ 14 | The function Xcp_Init shall internally store the configuration address to enable subsequent API calls to access the 15 | configuration. 16 | """ 17 | 18 | handle = XcpTest(DefaultConfig()) 19 | assert handle.config.lib.Xcp == handle.lib.Xcp_Ptr 20 | 21 | 22 | class TestSWS00825: 23 | """ 24 | If development error detection for the Xcp module is enabled, then the function Xcp_GetVersionInfo shall check 25 | whether the parameter VersioninfoPtr is a NULL pointer (NULL_PTR). If VersioninfoPtr is a NULL pointer, then the 26 | function Xcp_GetVersionInfo shall raise the development error XCP_E_PARAM_POINTER and return. 27 | """ 28 | 29 | def test_null_parameter(self): 30 | handle = XcpTest(DefaultConfig()) 31 | handle.lib.Xcp_GetVersionInfo(handle.ffi.NULL) 32 | handle.det_report_error.assert_called_once_with(ANY, 33 | ANY, 34 | handle.define('XCP_GET_VERSION_INFO_API_ID'), 35 | handle.define('XCP_E_PARAM_POINTER')) 36 | 37 | def test_non_null_parameter(self): 38 | handle = XcpTest(DefaultConfig()) 39 | version_info = handle.ffi.new('Std_VersionInfoType *') 40 | handle.lib.Xcp_GetVersionInfo(version_info) 41 | handle.det_report_error.assert_not_called() 42 | 43 | 44 | def test_sws_00840(): 45 | """ 46 | If development error detection for the XCP module is enabled: if the function Xcp_TxConfirmation is called 47 | before the XCP was initialized successfully, the function Xcp_TxConfirmation shall raise the development error 48 | XCP_E_UNINIT and return. 49 | """ 50 | 51 | handle = XcpTest(DefaultConfig(), initialize=False) 52 | handle.lib.Xcp_CanIfTxConfirmation(0, handle.define('E_OK')) 53 | handle.det_report_error.assert_called_once_with(ANY, 54 | ANY, 55 | handle.define('XCP_CAN_IF_TX_CONFIRMATION_API_ID'), 56 | handle.define('XCP_E_UNINIT')) 57 | 58 | 59 | def test_sws_00842(): 60 | """ 61 | If development error detection for the XCP module is enabled: if the function Xcp_TriggerTransmit is called 62 | before the XCP was initialized successfully, the function Xcp_TriggerTransmit shall raise the development error 63 | XCP_E_UNINIT and return E_NOT_OK. 64 | """ 65 | 66 | handle = XcpTest(DefaultConfig(), initialize=False) 67 | assert handle.lib.Xcp_CanIfTriggerTransmit(0, handle.ffi.NULL) == handle.define('E_NOT_OK') 68 | handle.det_report_error.assert_called_once_with(ANY, 69 | ANY, 70 | handle.define('XCP_CAN_IF_TRIGGER_TRANSMIT_API_ID'), 71 | handle.define('XCP_E_UNINIT')) 72 | 73 | 74 | @pytest.mark.parametrize('enumeration, value', (('XCP_TX_OFF', 0), ('XCP_TX_ON', 1))) 75 | def test_sws_00846(enumeration, value): 76 | handle = XcpTest(DefaultConfig()) 77 | assert getattr(handle.lib, enumeration) == value 78 | 79 | 80 | class TestSWS00847: 81 | """ 82 | The callback function Xcp_RxIndication shall inform the DET, if development error detection is enabled 83 | (XCP_DEV_ERROR_DETECT is set to TRUE) and if function call has failed because of the following reasons: 84 | - Xcp was not initialized (XCP_E_UNINIT) 85 | - PduInfoPtr equals NULL_PTR (XCP_E_PARAM_POINTER) 86 | - Invalid PDUID (XCP_E_INVALID_PDUID) 87 | """ 88 | 89 | def test_not_initialized_error(self): 90 | handle = XcpTest(DefaultConfig(), initialize=False) 91 | handle.lib.Xcp_CanIfRxIndication(0, handle.get_pdu_info((dummy_byte,))) 92 | handle.det_report_error.assert_called_once_with(ANY, 93 | ANY, 94 | handle.define('XCP_CAN_IF_RX_INDICATION_API_ID'), 95 | handle.define('XCP_E_UNINIT')) 96 | 97 | def test_null_pdu_info_pointer_error(self): 98 | handle = XcpTest(DefaultConfig()) 99 | handle.lib.Xcp_CanIfRxIndication(0, handle.ffi.NULL) 100 | handle.det_report_error.assert_called_once_with(ANY, 101 | ANY, 102 | handle.define('XCP_CAN_IF_RX_INDICATION_API_ID'), 103 | handle.define('XCP_E_PARAM_POINTER')) 104 | 105 | @pytest.mark.parametrize('pdu_id', [0x0002] + list(range(0x0004, 0x000F))) 106 | @pytest.mark.parametrize('daq_type', ('STIM', 'DAQ_STIM')) 107 | def test_invalid_pdu_id_error(self, pdu_id, daq_type): 108 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 109 | channel_tx_pdu_ref=0x0002, 110 | default_daq_dto_pdu_mapping=0x0003, 111 | daqs=(dict(name='DAQ1', 112 | type=daq_type, 113 | max_odt=1, 114 | max_odt_entries=1, 115 | pdu_mapping='XCP_PDU_ID_TRANSMIT', 116 | dtos=[dict(pid=0)]),))) 117 | handle.lib.Xcp_CanIfRxIndication(pdu_id, handle.get_pdu_info((dummy_byte,))) 118 | handle.det_report_error.assert_called_once_with(ANY, 119 | ANY, 120 | handle.define('XCP_CAN_IF_RX_INDICATION_API_ID'), 121 | handle.define('XCP_E_INVALID_PDUID')) 122 | 123 | 124 | @pytest.mark.parametrize('definition, value', (('XCP_E_UNINIT', 0x02), 125 | ('XCP_E_INIT_FAILED', 0x04), 126 | ('XCP_E_PARAM_POINTER', 0x12), 127 | ('XCP_E_INVALID_PDUID', 0x03))) 128 | def test_sws_00857(definition, value): 129 | handle = XcpTest(DefaultConfig()) 130 | assert handle.define(definition) == value 131 | -------------------------------------------------------------------------------- /test/build_checksum_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # see http://www.sunshine2k.de/coding/javascript/crc/crc_js.html 5 | 6 | import crcmod 7 | import crcmod.predefined 8 | 9 | from .parameter import * 10 | from .conftest import XcpTest 11 | 12 | from unittest.mock import ANY 13 | 14 | 15 | def checksum_add_u8_into_u8(data: [int], _byte_order) -> int: 16 | result = 0 17 | for b in data: 18 | result = ((result & 0xFF) + b) & 0xFF 19 | return result 20 | 21 | 22 | def checksum_add_u8_into_u16(data: [int], _byte_order) -> int: 23 | result = 0 24 | for b in data: 25 | result = ((result & 0xFFFF) + b) & 0xFFFF 26 | return result 27 | 28 | 29 | def checksum_add_u8_into_u32(data: [int], _byte_order) -> int: 30 | result = 0 31 | for b in data: 32 | result = ((result & 0xFFFFFFFF) + b) & 0xFFFFFFFF 33 | return result 34 | 35 | 36 | def checksum_add_u16_into_u16(data: [int], _byte_order) -> int: 37 | result = 0 38 | for b in data: 39 | result = ((result & 0xFFFF) + b) & 0xFFFF 40 | return result 41 | 42 | 43 | def checksum_add_u16_into_u32(data: [int], _byte_order) -> int: 44 | result = 0 45 | for b in data: 46 | result = ((result & 0xFFFFFFFF) + b) & 0xFFFFFFFF 47 | return result 48 | 49 | 50 | def checksum_add_u32_into_u32(data: [int], _byte_order) -> int: 51 | result = 0 52 | for b in data: 53 | result = ((result & 0xFFFFFFFF) + b) & 0xFFFFFFFF 54 | return result 55 | 56 | 57 | def checksum_crc16(data: [int], _byte_order) -> int: 58 | f = crcmod.predefined.mkPredefinedCrcFun('crc-16') 59 | return f(bytearray(data)) 60 | 61 | 62 | def checksum_crc16_citt(data: [int], _byte_order) -> int: 63 | f = crcmod.predefined.mkPredefinedCrcFun('crc-ccitt-false') 64 | return f(bytearray(data)) 65 | 66 | 67 | def checksum_crc32(data: [int], _byte_order) -> int: 68 | f = crcmod.predefined.mkPredefinedCrcFun('crc-32') 69 | return f(bytearray(data)) 70 | 71 | 72 | @pytest.mark.parametrize('ag, checksum_type, checksum_type_int, function', [ 73 | pytest.param('BYTE', 'XCP_ADD_11', 0x01, checksum_add_u8_into_u8, id='XCP_ADD_11'), 74 | pytest.param('BYTE', 'XCP_ADD_12', 0x02, checksum_add_u8_into_u16, id='XCP_ADD_12'), 75 | pytest.param('BYTE', 'XCP_ADD_14', 0x03, checksum_add_u8_into_u32, id='XCP_ADD_14'), 76 | pytest.param('WORD', 'XCP_ADD_22', 0x04, checksum_add_u16_into_u16, id='XCP_ADD_22'), 77 | pytest.param('WORD', 'XCP_ADD_24', 0x05, checksum_add_u16_into_u32, id='XCP_ADD_24'), 78 | pytest.param('DWORD', 'XCP_ADD_44', 0x06, checksum_add_u32_into_u32, id='XCP_ADD_44'), 79 | pytest.param('BYTE', 'XCP_CRC_16', 0x07, checksum_crc16, id='XCP_CRC_16'), 80 | pytest.param('BYTE', 'XCP_CRC_16_CITT', 0x08, checksum_crc16_citt, id='XCP_CRC_16_CITT'), 81 | pytest.param('BYTE', 'XCP_CRC_32', 0x09, checksum_crc32, id='XCP_CRC_32') 82 | ]) 83 | @pytest.mark.parametrize('block_size', [pytest.param(v, id='block_size = {:04}d'.format(v)) for v in [1, 2, 3, 1000]]) 84 | @pytest.mark.parametrize('mta', mtas) 85 | @pytest.mark.parametrize('byte_order', byte_orders) 86 | def test_build_checksum_returns_expected_checksum_on_a_single_block(ag, 87 | checksum_type, 88 | checksum_type_int, 89 | function, 90 | block_size, 91 | mta, 92 | byte_order): 93 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 94 | address_granularity=ag, 95 | byte_order=byte_order, 96 | checksum_type=checksum_type)) 97 | 98 | element_size = element_size_from_address_granularity(ag) 99 | expected_block = generate_random_block_content(block_size, element_size, mta) 100 | expected_block_generator = (v for v in expected_block) 101 | 102 | def read_slave_memory(p_address, _extension, p_buffer): 103 | expected_address, expected_value = next(expected_block_generator) 104 | assert int(handle.ffi.cast('uint32_t', p_address)) == expected_address 105 | raw = expected_value.to_bytes(element_size, dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[byte_order], 106 | signed=False) 107 | for i, b in enumerate(raw): 108 | p_buffer[i] = int(b) 109 | return None 110 | 111 | handle.xcp_read_slave_memory_u8.side_effect = read_slave_memory 112 | handle.xcp_read_slave_memory_u16.side_effect = read_slave_memory 113 | handle.xcp_read_slave_memory_u32.side_effect = read_slave_memory 114 | 115 | # CONNECT 116 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 117 | handle.lib.Xcp_MainFunction() 118 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 119 | 120 | # SET_MTA 121 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF6, 122 | 0x00, 123 | 0x00, 124 | 0x00, 125 | *address_to_array(mta, 4, byte_order)))) 126 | handle.lib.Xcp_MainFunction() 127 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 128 | 129 | # BUILD_CHECKSUM 130 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF3, 131 | 0x00, 132 | 0x00, 133 | 0x00, 134 | *u32_to_array(block_size, byte_order)))) 135 | handle.lib.Xcp_MainFunction() 136 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 137 | 138 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 139 | 140 | # check packet ID. 141 | assert raw_data[0] == 0xFF 142 | 143 | # check checksum type. 144 | assert raw_data[1] == checksum_type_int 145 | 146 | # check reserved bytes. 147 | assert raw_data[2] == 0x00 148 | assert raw_data[3] == 0x00 149 | 150 | # check checksum value. 151 | actual_checksum = u32_from_array(bytearray(raw_data[4:8]), byte_order) 152 | expected_checksum = function([v[1] for v in expected_block], byte_order) 153 | assert actual_checksum == expected_checksum 154 | 155 | 156 | @pytest.mark.parametrize('ag', [pytest.param('BYTE', id='XCP_USER_DEFINED')]) 157 | @pytest.mark.parametrize('block_size', [pytest.param(v, id='block_size = {:04}d'.format(v)) for v in [1, 2, 3, 1000]]) 158 | @pytest.mark.parametrize('mta', mtas) 159 | @pytest.mark.parametrize('byte_order', byte_orders) 160 | def test_build_checksum_user_defined_returns_expected_checksum_on_a_single_block(ag, 161 | block_size, 162 | mta, 163 | byte_order): 164 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 165 | address_granularity=ag, 166 | byte_order=byte_order, 167 | checksum_type='XCP_USER_DEFINED', 168 | user_defined_checksum_function='Xcp_UserDefinedChecksumFunction')) 169 | 170 | element_size = element_size_from_address_granularity(ag) 171 | 172 | def xcp_user_defined_checksum_function(_p_lower_address, p_upper_address, p_checksum): 173 | p_checksum[0] = int.from_bytes(bytearray((1, 2, 3, 4)), 174 | dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[byte_order], 175 | signed=False) 176 | return p_upper_address 177 | 178 | handle.xcp_user_defined_checksum_function.side_effect = xcp_user_defined_checksum_function 179 | 180 | # CONNECT 181 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 182 | handle.lib.Xcp_MainFunction() 183 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 184 | 185 | # SET_MTA 186 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF6, 187 | 0x00, 188 | 0x00, 189 | 0x00, 190 | *address_to_array(mta, 4, byte_order)))) 191 | handle.lib.Xcp_MainFunction() 192 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 193 | 194 | # BUILD_CHECKSUM 195 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF3, 196 | 0x00, 197 | 0x00, 198 | 0x00, 199 | *u32_to_array(block_size, byte_order)))) 200 | handle.lib.Xcp_MainFunction() 201 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 202 | 203 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 204 | 205 | # check packet ID. 206 | assert raw_data[0] == 0xFF 207 | 208 | # check checksum type. 209 | assert raw_data[1] == 0xFF 210 | 211 | # check reserved bytes. 212 | assert raw_data[2] == 0x00 213 | assert raw_data[3] == 0x00 214 | 215 | # check checksum. 216 | expected_checksum = u32_from_array(bytearray((1, 2, 3, 4)), byte_order) 217 | assert u32_from_array(bytearray(raw_data[4:8]), byte_order) == expected_checksum 218 | 219 | # check checksum value. 220 | handle.xcp_user_defined_checksum_function.assert_called_once_with(handle.ffi.cast('void *', mta), 221 | handle.ffi.cast('void *', mta + element_size * block_size), 222 | ANY) 223 | 224 | 225 | def test_build_checksum_calls_the_det_with_err_param_pointer_if_checksum_function_is_null(): 226 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 227 | checksum_type='XCP_USER_DEFINED', 228 | user_defined_checksum_function=None)) 229 | 230 | # CONNECT 231 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 232 | handle.lib.Xcp_MainFunction() 233 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 234 | 235 | # BUILD_CHECKSUM 236 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01))) 237 | 238 | handle.det_report_error.assert_called_once_with(ANY, 239 | ANY, 240 | handle.define('XCP_CAN_IF_RX_INDICATION_API_ID'), 241 | handle.define('XCP_E_PARAM_POINTER')) 242 | 243 | 244 | def test_build_checksum_returns_err_out_of_range_if_checksum_function_is_null(): 245 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 246 | checksum_type='XCP_USER_DEFINED', 247 | user_defined_checksum_function=None)) 248 | 249 | # CONNECT 250 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 251 | handle.lib.Xcp_MainFunction() 252 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 253 | 254 | # BUILD_CHECKSUM 255 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01))) 256 | handle.lib.Xcp_MainFunction() 257 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 258 | 259 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFE, 0x22) 260 | 261 | 262 | def test_build_checksum_returns_err_out_of_range_if_checksum_type_is_out_of_range(): 263 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, checksum_type=0xFF, user_defined_checksum_function=None)) 264 | 265 | # CONNECT 266 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 267 | handle.lib.Xcp_MainFunction() 268 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 269 | 270 | # BUILD_CHECKSUM 271 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01))) 272 | handle.lib.Xcp_MainFunction() 273 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 274 | 275 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFE, 0x22) 276 | -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import random 4 | 5 | import pytest 6 | from bsw_code_gen import BSWCodeGen 7 | from cffi import FFI 8 | from importlib import import_module 9 | from io import StringIO 10 | from re import sub 11 | from unittest.mock import MagicMock 12 | from glob import glob 13 | 14 | from pycparser.c_ast import FuncDecl, NodeVisitor 15 | from pycparser.c_generator import CGenerator as Generator 16 | from pycparser.c_parser import CParser 17 | from pcpp.preprocessor import Preprocessor as Pp 18 | 19 | 20 | def pytest_addoption(parser): 21 | parser.addoption('--build_directory', action='store') 22 | parser.addoption('--script_directory', action='store') 23 | parser.addoption('--header', action='store') 24 | parser.addoption('--source', action='store') 25 | parser.addoption('--compile_definitions', action='store') 26 | parser.addoption('--include_directories', action='store') 27 | 28 | 29 | def pytest_configure(config): 30 | print(config) 31 | os.environ['build_directory'] = config.getoption('build_directory') 32 | os.environ['script_directory'] = config.getoption('script_directory') 33 | os.environ['header'] = config.getoption('header') 34 | os.environ['source'] = config.getoption('source') 35 | os.environ['compile_definitions'] = config.getoption('compile_definitions') 36 | os.environ['include_directories'] = config.getoption('include_directories') 37 | 38 | 39 | @pytest.fixture 40 | def seed(request) -> [int]: 41 | return [random.getrandbits(8, ) for _ in range(request.param)] 42 | 43 | 44 | @pytest.fixture 45 | def seed_array(request) -> [[int]]: 46 | seed_size, number_of_seeds = request.param 47 | return [[random.getrandbits(8, ) for _ in range(seed_size)] for _ in range(number_of_seeds)] 48 | 49 | 50 | def convert(name): 51 | s1 = sub('(.)([A-Z][a-z][_]+)', r'\1_\2', name) 52 | return sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() 53 | 54 | 55 | class FunctionDecl(NodeVisitor): 56 | def __init__(self, source_string): 57 | self.static = set() 58 | self.extern = set() 59 | self.locals = set() 60 | self.visit(CParser().parse(source_string)) 61 | 62 | def visit_Decl(self, node): 63 | if isinstance(node.type, FuncDecl): 64 | if 'static' in node.storage: 65 | self.static.add(node) 66 | elif 'extern' in node.storage: 67 | self.extern.add(node) 68 | else: 69 | self.locals.add(node) 70 | 71 | 72 | class CFFIHeader(Generator): 73 | def __init__(self, interface, local, extern): 74 | super(CFFIHeader, self).__init__() 75 | self.locals = set(e.name for e in local) 76 | self.extern = set(e.name for e in extern) 77 | self.mocked = set() 78 | self.string = self.visit(CParser().parse(interface)) 79 | 80 | def __str__(self): 81 | return self.string 82 | 83 | def visit_Decl(self, n, no_type=False): 84 | if isinstance(n.type, FuncDecl): 85 | if n.name in self.extern: 86 | self.mocked.add(n.name) 87 | n.storage.remove('extern') 88 | n.storage.append('extern "Python+C"') 89 | return Generator.visit_Decl(self, n) 90 | 91 | 92 | class Preprocessor(Pp): 93 | def __init__(self): 94 | super(Preprocessor, self).__init__() 95 | self.defines = dict() 96 | 97 | def on_directive_handle(self, directive, tokens, if_pass_thru, preceding_tokens): 98 | if directive.value == 'define': 99 | name = [t.value for t in tokens if t.type == 'CPP_ID'] 100 | value = [t.value for t in tokens if t.type in 'CPP_INTEGER'] 101 | if len(name) and len(value): 102 | name = name[0] 103 | value = value[0].rstrip('UuLl') 104 | try: 105 | value = int(value, 10) 106 | except ValueError: 107 | try: 108 | value = int(value, 16) 109 | except ValueError as e: 110 | raise e 111 | self.defines[name] = value 112 | return super(Preprocessor, self).on_directive_handle(directive, tokens, if_pass_thru, preceding_tokens) 113 | 114 | 115 | class MockGen(FFI): 116 | _pp = dict() 117 | _ffi_header = dict() 118 | 119 | def __init__(self, 120 | name, 121 | source, 122 | header, 123 | include_dirs=tuple(), 124 | define_macros=tuple(), 125 | compile_flags=tuple(), 126 | link_flags=tuple(), 127 | link_libraries=tuple(), 128 | build_dir=''): 129 | super(MockGen, self).__init__() 130 | self._name = name 131 | if self.name in sys.modules: 132 | self.ffi_module = sys.modules[self.name] 133 | else: 134 | pre_processor = Preprocessor() 135 | for include_directory in include_dirs: 136 | pre_processor.add_path(include_directory) 137 | for compile_definition in (' '.join(d.split('=')) for d in define_macros): 138 | pre_processor.define(compile_definition) 139 | pre_processor.parse(header) 140 | handle = StringIO() 141 | pre_processor.write(handle) 142 | self._pp[self.name] = pre_processor 143 | header = handle.getvalue() 144 | func_decl = FunctionDecl(header) 145 | self._ffi_header[self.name] = CFFIHeader(header, func_decl.locals, func_decl.extern) 146 | self.cdef(str(CFFIHeader(header, func_decl.locals, func_decl.extern))) 147 | self.set_source(self.name, source, 148 | include_dirs=include_dirs, 149 | define_macros=list(tuple(d.split('=')) for d in define_macros), 150 | extra_compile_args=list(compile_flags), 151 | libraries=list(link_libraries), 152 | library_dirs=(build_dir,), 153 | extra_link_args=list(link_flags)) 154 | lib_path = self.compile(tmpdir=build_dir) 155 | sys.path.append(os.path.dirname(lib_path)) 156 | self.ffi_module = import_module(self.name) 157 | 158 | @property 159 | def name(self): 160 | return self._name 161 | 162 | @property 163 | def pp(self): 164 | return self._pp[self.name] 165 | 166 | @property 167 | def ffi_header(self): 168 | return self._ffi_header[self.name] 169 | 170 | @property 171 | def mocked(self): 172 | return self.ffi_header.mocked 173 | 174 | @property 175 | def ffi(self): 176 | return self.ffi_module.ffi 177 | 178 | @property 179 | def lib(self): 180 | return self.ffi_module.lib 181 | 182 | 183 | class XcpTest(object): 184 | def __init__(self, 185 | config, 186 | initialize=True, 187 | rx_buffer_size=0x0FFF): 188 | self.available_rx_buffer = rx_buffer_size 189 | self.can_if_tx_data = list() 190 | self.can_tp_rx_data = list() 191 | code_gen = BSWCodeGen(config, self.script_directory) 192 | with open(os.path.join(self.build_directory, 'Xcp_Cfg.h'), 'w') as fp: 193 | fp.write(code_gen.header_cfg) 194 | with open(os.path.join(self.build_directory, 'Xcp_Cfg.c'), 'w') as fp: 195 | fp.write(code_gen.source_cfg) 196 | with open(os.path.join(self.build_directory, 'Xcp_Rt.h'), 'w') as fp: 197 | fp.write(code_gen.header_rt) 198 | with open(os.path.join(self.build_directory, 'Xcp_Rt.c'), 'w') as fp: 199 | fp.write(code_gen.source_rt) 200 | with open(self.header, 'r') as fp: 201 | header = fp.read() 202 | os.environ['DYLD_LIBRARY_PATH'] = '{}'.format(self.build_directory) 203 | os.environ['LD_LIBRARY_PATH'] = '{}'.format(self.build_directory) 204 | self.rt = MockGen('libcffi_xcp_rt_{}'.format(config.get_id), 205 | code_gen.source_rt, 206 | code_gen.header_rt, 207 | define_macros=tuple(self.compile_definitions) + 208 | ('XCP_EVENT_QUEUE_SIZE=0x{:04X}'.format(config.event_queue_size),), 209 | include_dirs=tuple(self.include_directories + [self.build_directory]), 210 | build_dir=self.build_directory) 211 | self.config = MockGen('_cffi_xcp_cfg_{}'.format(config.get_id), 212 | code_gen.source_cfg, 213 | code_gen.header_cfg, 214 | define_macros=tuple(self.compile_definitions) + 215 | ('XCP_PDU_ID_CTO_RX=0x{:04X}'.format(config.channel_rx_pdu),) + 216 | ('XCP_PDU_ID_CTO_TX=0x{:04X}'.format(config.channel_tx_pdu),) + 217 | ('XCP_PDU_ID_TRANSMIT=0x{:04X}'.format( 218 | config.default_daq_dto_pdu_mapping),), 219 | include_dirs=tuple(self.include_directories + [self.build_directory]), 220 | build_dir=self.build_directory) 221 | f = glob(os.path.join(self.build_directory, 'libcffi_xcp_rt_{}*.so'.format(config.get_id)))[0] 222 | self.code = MockGen('_cffi_xcp', 223 | '#include "{}"'.format(self.source), 224 | header, 225 | define_macros=tuple(self.compile_definitions) + 226 | ('XCP_EVENT_QUEUE_SIZE=0x{:04X}'.format(config.event_queue_size),), 227 | include_dirs=tuple(self.include_directories + [self.build_directory]), 228 | compile_flags=('-g', '-O0', '-fprofile-arcs', '-ftest-coverage'), 229 | link_flags=('-g', '-O0', '-fprofile-arcs', '-ftest-coverage',), 230 | link_libraries=(os.path.basename(f).lstrip('lib').rstrip('.so'),), 231 | build_dir=self.build_directory) 232 | self.can_if_transmit = MagicMock() 233 | self.det_report_error = MagicMock() 234 | self.det_report_runtime_error = MagicMock() 235 | self.det_report_transient_fault = MagicMock() 236 | self.xcp_get_seed = MagicMock() 237 | self.xcp_calc_key = MagicMock() 238 | self.xcp_read_slave_memory_u8 = MagicMock() 239 | self.xcp_read_slave_memory_u16 = MagicMock() 240 | self.xcp_read_slave_memory_u32 = MagicMock() 241 | self.xcp_write_slave_memory_u8 = MagicMock() 242 | self.xcp_write_slave_memory_u16 = MagicMock() 243 | self.xcp_write_slave_memory_u32 = MagicMock() 244 | self.xcp_store_calibration_data_to_non_volatile_memory = MagicMock() 245 | self.xcp_user_cmd_function = MagicMock() 246 | self.config.ffi.def_extern('Xcp_UserCmdFunction')(self.xcp_user_cmd_function) 247 | self.xcp_user_cmd_function.return_value = self.define('E_OK') 248 | self.xcp_user_defined_checksum_function = MagicMock() 249 | self.config.ffi.def_extern('Xcp_UserDefinedChecksumFunction')(self.xcp_user_defined_checksum_function) 250 | self.xcp_user_defined_checksum_function.return_value = 0 251 | for func in self.code.mocked: 252 | self.ffi.def_extern(func)(getattr(self, convert(func))) 253 | self.can_if_transmit.return_value = self.define('E_OK') 254 | self.det_report_error.return_value = self.define('E_OK') 255 | self.det_report_runtime_error.return_value = self.define('E_OK') 256 | self.det_report_transient_fault.return_value = self.define('E_OK') 257 | self.xcp_get_seed.return_value = self.define('E_OK') 258 | self.xcp_calc_key.return_value = self.define('E_OK') 259 | self.xcp_read_slave_memory_u8.return_value = None 260 | self.xcp_read_slave_memory_u16.return_value = None 261 | self.xcp_read_slave_memory_u32.return_value = None 262 | self.xcp_write_slave_memory_u8.return_value = None 263 | self.xcp_write_slave_memory_u16.return_value = None 264 | self.xcp_write_slave_memory_u32.return_value = None 265 | self.xcp_store_calibration_data_to_non_volatile_memory.return_value = self.define('E_OK') 266 | 267 | self.code.lib.Xcp_State = self.code.lib.XCP_UNINITIALIZED 268 | if initialize: 269 | self.code.lib.Xcp_Init(self.code.ffi.cast('const Xcp_Type *', self.config.lib.Xcp)) 270 | 271 | def get_pdu_info(self, payload, null_payload=False, overridden_size=None, meta_data=None): 272 | if isinstance(payload, str): 273 | payload = [ord(c) for c in payload] 274 | sdu_data = self.code.ffi.new('uint8 []', list(payload)) 275 | if overridden_size is not None: 276 | sdu_length = overridden_size 277 | else: 278 | sdu_length = len(payload) 279 | if null_payload: 280 | sdu_data = self.code.ffi.NULL 281 | pdu_info = self.code.ffi.new('PduInfoType *') 282 | pdu_info.SduDataPtr = sdu_data 283 | pdu_info.SduLength = sdu_length 284 | if meta_data is not None: 285 | sdu_meta_data = self.code.ffi.new('uint8 []', list(meta_data)) 286 | pdu_info.MetaDataPtr = sdu_meta_data 287 | else: 288 | pdu_info.MetaDataPtr = self.code.ffi.NULL 289 | return pdu_info 290 | 291 | def define(self, name): 292 | return self.code.pp.defines[name] 293 | 294 | @property 295 | def lib(self): 296 | return self.code.lib 297 | 298 | @property 299 | def ffi(self): 300 | return self.code.ffi 301 | 302 | @property 303 | def build_directory(self): 304 | return os.getenv('build_directory') 305 | 306 | @property 307 | def script_directory(self): 308 | return os.getenv('script_directory') 309 | 310 | @property 311 | def header(self): 312 | return os.getenv('header') 313 | 314 | @property 315 | def source(self): 316 | return os.getenv('source') 317 | 318 | @property 319 | def compile_definitions(self): 320 | return os.getenv('compile_definitions').split(';') + ['CFFI_ENABLE=STD_ON'] 321 | 322 | @property 323 | def include_directories(self): 324 | return os.getenv('include_directories').split(';') 325 | -------------------------------------------------------------------------------- /test/connect_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import pytest 4 | 5 | from .parameter import * 6 | from .conftest import XcpTest 7 | 8 | 9 | def test_command_connect_sets_the_packet_id_byte_to_pid_response_on_positive_response(): 10 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 11 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 12 | handle.lib.Xcp_MainFunction() 13 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[0] == 0xFF 14 | 15 | 16 | @pytest.mark.parametrize('resource_cal_pag_bit, api_enable', ((0, (False, False, False, False, False)), 17 | (0, (True, False, False, False, False)), 18 | (0, (True, True, False, False, False)), 19 | (0, (True, True, True, False, False)), 20 | (0, (True, True, True, True, False)), 21 | (1, (True, True, True, True, True)))) 22 | def test_connect_sets_the_resource_cal_pag_bit_according_to_enabled_apis(resource_cal_pag_bit, api_enable): 23 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 24 | xcp_download_api_enable=api_enable[0], 25 | xcp_download_max_api_enable=api_enable[1], 26 | xcp_short_download_api_enable=api_enable[2], 27 | xcp_set_cal_page_api_enable=api_enable[3], 28 | xcp_get_cal_page_api_enable=api_enable[4])) 29 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 30 | handle.lib.Xcp_MainFunction() 31 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[1] & 0x01 == resource_cal_pag_bit 32 | 33 | 34 | @pytest.mark.parametrize('resource_daq_bit, api_enable', ( 35 | (0, ( 36 | False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, 37 | False, 38 | False)), 39 | (0, ( 40 | True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, 41 | False, 42 | False)), 43 | (0, ( 44 | True, True, False, False, False, False, False, False, False, False, False, False, False, False, False, 45 | False, 46 | False)), 47 | (0, ( 48 | True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, 49 | False, 50 | False)), 51 | (0, (True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, False, 52 | False)), 53 | (0, (True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False, 54 | False)), 55 | (0, (True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, 56 | False)), 57 | (0, (True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, False, 58 | False)), 59 | (0, ( 60 | True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, False, 61 | False)), 62 | (0, ( 63 | True, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False, 64 | False)), 65 | (0, 66 | (True, True, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False)), 67 | (0, 68 | (True, True, True, True, True, True, True, True, True, True, True, False, False, False, False, False, False)), 69 | ( 70 | 0, (True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, False, 71 | False)), 72 | (0, (True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, False)), 73 | (0, (True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False)), 74 | (0, (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False)), 75 | (0, (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, False)), 76 | (1, (True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True)))) 77 | def test_connect_sets_the_resource_daq_bit_according_to_enabled_apis(resource_daq_bit, api_enable): 78 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 79 | xcp_clear_daq_list_api_enable=api_enable[0], 80 | xcp_set_daq_ptr_api_enable=api_enable[1], 81 | xcp_write_daq_api_enable=api_enable[2], 82 | xcp_set_daq_list_mode_api_enable=api_enable[3], 83 | xcp_get_daq_list_mode_api_enable=api_enable[4], 84 | xcp_start_stop_daq_list_api_enable=api_enable[5], 85 | xcp_start_stop_synch_api_enable=api_enable[6], 86 | xcp_get_daq_clock_api_enable=api_enable[7], 87 | xcp_read_daq_api_enable=api_enable[8], 88 | xcp_get_daq_processor_info_api_enable=api_enable[9], 89 | xcp_get_daq_resolution_info_api_enable=api_enable[10], 90 | xcp_get_daq_list_info_api_enable=api_enable[11], 91 | xcp_get_daq_event_info_api_enable=api_enable[12], 92 | xcp_free_daq_api_enable=api_enable[13], 93 | xcp_alloc_daq_api_enable=api_enable[14], 94 | xcp_alloc_odt_api_enable=api_enable[15], 95 | xcp_alloc_odt_entry_api_enable=api_enable[16])) 96 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 97 | handle.lib.Xcp_MainFunction() 98 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[1] & (0x01 << 0x02)) >> 0x02) == resource_daq_bit 99 | 100 | 101 | @pytest.mark.parametrize('resource_stim_bit, daq_type', ((0, "DAQ"), (1, "STIM"), (1, "DAQ_STIM"))) 102 | def test_connect_sets_the_resource_stim_bit_according_to_enabled_apis(resource_stim_bit, daq_type): 103 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, daqs=(dict(name='DAQ1', 104 | type=daq_type, 105 | max_odt=1, 106 | max_odt_entries=1, 107 | pdu_mapping='XCP_PDU_ID_TRANSMIT', 108 | dtos=[dict(pid=0)]),))) 109 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 110 | handle.lib.Xcp_MainFunction() 111 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[1] & (0x01 << 0x03)) >> 0x03) == resource_stim_bit 112 | 113 | 114 | @pytest.mark.parametrize('resource_pgm_bit, api_enable', ((0, (False, False, False)), 115 | (0, (True, False, False)), 116 | (0, (True, True, False)), 117 | (1, (True, True, True)))) 118 | def test_connect_sets_the_resource_cal_pag_bit_according_to_enabled_apis(resource_pgm_bit, api_enable): 119 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 120 | xcp_program_clear_api_enable=api_enable[0], 121 | xcp_program_api_enable=api_enable[1], 122 | xcp_program_max_api_enable=api_enable[2])) 123 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 124 | handle.lib.Xcp_MainFunction() 125 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[1] & (0x01 << 0x04)) >> 0x04) == resource_pgm_bit 126 | 127 | 128 | @pytest.mark.parametrize('byte_order_bit, byte_order', ((0, "LITTLE_ENDIAN"), (1, "BIG_ENDIAN"))) 129 | def test_connect_sets_the_byte_order_bit_according_to_the_configured_value(byte_order_bit, byte_order): 130 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, byte_order=byte_order)) 131 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 132 | handle.lib.Xcp_MainFunction() 133 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[2] & 0x01 == byte_order_bit 134 | 135 | 136 | @pytest.mark.parametrize('address_granularity_bits, address_granularity', ((0, 'BYTE'), (1, 'WORD'), (2, 'DWORD'))) 137 | def test_connect_sets_the_address_granularity_bits_according_to_the_configured_value(address_granularity_bits, 138 | address_granularity): 139 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, address_granularity=address_granularity)) 140 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 141 | handle.lib.Xcp_MainFunction() 142 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[2] & 0x06) >> 0x01) == address_granularity_bits 143 | 144 | 145 | @pytest.mark.parametrize('slave_block_mode_bit, slave_block_mode', ((0, False), (1, True))) 146 | def test_connect_sets_the_slave_block_mode_bit_according_to_the_configured_value(slave_block_mode_bit, 147 | slave_block_mode): 148 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, slave_block_mode=slave_block_mode)) 149 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 150 | handle.lib.Xcp_MainFunction() 151 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[2] & (0x01 << 0x06)) >> 0x06) == slave_block_mode_bit 152 | 153 | 154 | @pytest.mark.parametrize('optional_bit, api_enable', ((0, False), (1, True))) 155 | def test_connect_sets_the_optional_bit_according_to_enabled_apis(optional_bit, api_enable): 156 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, xcp_get_comm_mode_info_api_enable=api_enable)) 157 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 158 | handle.lib.Xcp_MainFunction() 159 | assert ((handle.can_if_transmit.call_args[0][1].SduDataPtr[2] & (0x01 << 0x07)) >> 0x07) == optional_bit 160 | 161 | 162 | @pytest.mark.parametrize('max_cto_byte, max_cto', ((8, 8), (16, 16), (32, 32))) 163 | def test_connect_sets_the_max_cto_byte_according_to_the_configured_value(max_cto_byte, max_cto): 164 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto)) 165 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 166 | handle.lib.Xcp_MainFunction() 167 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[3] == max_cto_byte 168 | 169 | 170 | @pytest.mark.parametrize('max_dto_bytes, max_dto, byte_order', (((8, 0), 8, 'LITTLE_ENDIAN'), 171 | ((16, 0), 16, 'LITTLE_ENDIAN'), 172 | ((32, 0), 32, 'LITTLE_ENDIAN'), 173 | ((0, 8), 8, 'BIG_ENDIAN'), 174 | ((0, 16), 16, 'BIG_ENDIAN'), 175 | ((0, 32), 32, 'BIG_ENDIAN'))) 176 | def test_connect_sets_the_max_dto_byte_according_to_the_configured_value(max_dto_bytes, max_dto, byte_order): 177 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_dto=max_dto, byte_order=byte_order)) 178 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 179 | handle.lib.Xcp_MainFunction() 180 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[4:6]) == max_dto_bytes 181 | 182 | 183 | def test_connect_sets_the_protocol_layer_version_number_byte_according_to_the_implementation(): 184 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 185 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 186 | handle.lib.Xcp_MainFunction() 187 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[6] == 0x01 188 | 189 | 190 | def test_connect_sets_the_transport_layer_version_number_byte_according_to_the_implementation(): 191 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 192 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 193 | handle.lib.Xcp_MainFunction() 194 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[7] == 0x01 195 | 196 | 197 | @pytest.mark.parametrize('trailing_value', trailing_values) 198 | @pytest.mark.parametrize('max_cto', max_ctos) 199 | def test_connect_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 200 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 201 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 202 | handle.lib.Xcp_MainFunction() 203 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x08)) 204 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[8:max_cto]) == remaining_zeros 205 | -------------------------------------------------------------------------------- /test/disconnect_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | from .parameter import * 6 | from .conftest import XcpTest 7 | 8 | 9 | def test_command_disconnect_sets_the_packet_id_byte_to_pid_response_on_positive_response(): 10 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 11 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 12 | handle.lib.Xcp_MainFunction() 13 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 14 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFE,))) 15 | handle.lib.Xcp_MainFunction() 16 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[0] == 0xFF 17 | 18 | 19 | @pytest.mark.parametrize('trailing_value', trailing_values) 20 | @pytest.mark.parametrize('max_cto', max_ctos) 21 | def test_disconnect_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 22 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 23 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 24 | handle.lib.Xcp_MainFunction() 25 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 26 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFE,))) 27 | handle.lib.Xcp_MainFunction() 28 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x01)) 29 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[1:max_cto]) == remaining_zeros 30 | -------------------------------------------------------------------------------- /test/get_comm_mode_info_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | @pytest.mark.parametrize('cto_queue_size', cto_queue_sizes) 9 | @pytest.mark.parametrize('max_bs', max_bss) 10 | @pytest.mark.parametrize('min_st', min_sts) 11 | @pytest.mark.parametrize('comm_mode_optional, master_block_mode, interleaved_mode', [ 12 | (0x00, False, False), 13 | (0x01, True, False), 14 | (0x02, False, True), 15 | (0x03, True, True)]) 16 | def test_get_comm_mode_info_returns_expected_values(cto_queue_size, 17 | max_bs, 18 | min_st, 19 | comm_mode_optional, 20 | master_block_mode, 21 | interleaved_mode): 22 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 23 | master_block_mode=master_block_mode, 24 | interleaved_mode=interleaved_mode, 25 | max_bs=max_bs, 26 | min_st=min_st, 27 | cto_queue_size=cto_queue_size)) 28 | 29 | # CONNECT 30 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 31 | handle.lib.Xcp_MainFunction() 32 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 33 | 34 | handle.lib.Xcp_MainFunction() 35 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 36 | 37 | # GET_COMM_MODE_INFO 38 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFB,))) 39 | handle.lib.Xcp_MainFunction() 40 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 41 | 42 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 43 | 44 | # check packet ID. 45 | assert raw_data[0] == 0xFF 46 | 47 | # check reserved byte. 48 | assert raw_data[1] == 0x00 49 | 50 | # check COMM_MODE_OPTIONAL. 51 | assert raw_data[2] == comm_mode_optional 52 | 53 | # check reserved byte. 54 | assert raw_data[3] == 0x00 55 | 56 | # check MAX_BS. 57 | assert raw_data[4] == max_bs 58 | 59 | # check MIN_ST. 60 | assert raw_data[5] == min_st 61 | 62 | # check CTO_QUEUE_SIZE. 63 | assert raw_data[6] == cto_queue_size 64 | 65 | # check XCP driver version number. 66 | assert raw_data[7] == ((handle.define('XCP_SW_MAJOR_VERSION') & 0x0F) << 4) | \ 67 | (handle.define('XCP_SW_MINOR_VERSION') & 0x0F) 68 | 69 | 70 | @pytest.mark.parametrize('trailing_value', trailing_values) 71 | @pytest.mark.parametrize('max_cto', max_ctos) 72 | def test_get_comm_mode_info_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 73 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 74 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 75 | handle.lib.Xcp_MainFunction() 76 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 77 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFB,))) 78 | handle.lib.Xcp_MainFunction() 79 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x08)) 80 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[8:max_cto]) == remaining_zeros 81 | -------------------------------------------------------------------------------- /test/get_id_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import math 4 | 5 | from .parameter import * 6 | from .conftest import XcpTest 7 | 8 | 9 | @pytest.mark.parametrize('byte_order', byte_orders) 10 | @pytest.mark.parametrize('mode, actual_identification, expected_identification', [ 11 | (0x00, '/path/to/database.a2l', '/path/to/database.a2l')]) 12 | def test_get_id_returns_identification_through_mta_when_mode_is_0(byte_order, 13 | mode, 14 | actual_identification, 15 | expected_identification): 16 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 17 | address_granularity='BYTE', 18 | byte_order=byte_order, 19 | identification=actual_identification)) 20 | 21 | memory_identification = [] 22 | 23 | def read_slave_memory(p_address, _extension, _p_buffer): 24 | memory_identification.append(handle.ffi.cast('uint8_t*', p_address)[0]) 25 | 26 | handle.xcp_read_slave_memory_u8.side_effect = read_slave_memory 27 | 28 | # CONNECT 29 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 30 | handle.lib.Xcp_MainFunction() 31 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 32 | 33 | # GET_ID 34 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFA, mode))) 35 | handle.lib.Xcp_MainFunction() 36 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 37 | 38 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 39 | 40 | # check packet ID. 41 | assert raw_data[0] == 0xFF 42 | 43 | # check Mode. 44 | assert raw_data[1] == mode 45 | 46 | # check reserved bytes. 47 | assert raw_data[2] == 0x00 48 | assert raw_data[3] == 0x00 49 | 50 | # check Length. 51 | assert u32_from_array(bytearray(raw_data[4:8]), byte_order) == len(expected_identification) 52 | 53 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF5, len(expected_identification)))) 54 | for _ in range(int(math.ceil(len(expected_identification) / 7))): 55 | handle.lib.Xcp_MainFunction() 56 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 57 | 58 | # check Identification. 59 | assert ''.join(chr(c) for c in memory_identification) == expected_identification 60 | 61 | 62 | @pytest.mark.parametrize('trailing_value', trailing_values) 63 | @pytest.mark.parametrize('max_cto', max_ctos) 64 | def test_get_id_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 65 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 66 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 67 | handle.lib.Xcp_MainFunction() 68 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 69 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFA, 0x00))) 70 | handle.lib.Xcp_MainFunction() 71 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x08)) 72 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0x08:max_cto]) == remaining_zeros 73 | -------------------------------------------------------------------------------- /test/get_status_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | @pytest.mark.parametrize('current_session_status_byte, set_request_mode_byte', ((0b00000000, 0b00000000), 9 | (0b00000001, 0b00000001), 10 | (0b00000100, 0b00000100), 11 | (0b00001000, 0b00001000), 12 | (0b00001001, 0b00001001), 13 | (0b00001100, 0b00001100), 14 | (0b00001101, 0b00001101))) 15 | def test_get_status_returns_the_current_session_status_for_bytes_0_2_3(current_session_status_byte, 16 | set_request_mode_byte): 17 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 18 | 19 | def store_calibration_data_to_non_volatile_memory(p_success): 20 | p_success[0] = handle.define('E_NOT_OK') 21 | return handle.define('E_NOT_OK') 22 | 23 | handle.xcp_store_calibration_data_to_non_volatile_memory.side_effect = store_calibration_data_to_non_volatile_memory 24 | 25 | # CONNECT 26 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 27 | handle.lib.Xcp_MainFunction() 28 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 29 | 30 | # SET_REQUEST 31 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF9, set_request_mode_byte, 0x00, 0x00))) 32 | handle.lib.Xcp_MainFunction() 33 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 34 | 35 | # GET_STATUS 36 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFD,))) 37 | handle.lib.Xcp_MainFunction() 38 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[1] == current_session_status_byte 39 | 40 | 41 | @pytest.mark.skip(reason='not implemented yet, implement me...') 42 | def test_get_status_returns_the_current_session_status_for_bytes_6_7(): 43 | pass 44 | 45 | 46 | @pytest.mark.parametrize('trailing_value', trailing_values) 47 | @pytest.mark.parametrize('max_cto', max_ctos) 48 | def test_get_status_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 49 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 50 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 51 | handle.lib.Xcp_MainFunction() 52 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 53 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFD,))) 54 | handle.lib.Xcp_MainFunction() 55 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x06)) 56 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[6:max_cto]) == remaining_zeros 57 | -------------------------------------------------------------------------------- /test/parameter.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import json 3 | import pytest 4 | import random 5 | import struct 6 | 7 | from math import floor 8 | 9 | dummy_byte = 0xFF 10 | 11 | address_extensions = [pytest.param(v, id='address extension = {:02}d'.format(v)) for v in range(8)] 12 | address_granularities = [pytest.param('BYTE', id='AG = BYTE'), 13 | pytest.param('WORD', id='AG = WORD'), 14 | pytest.param('DWORD', id='AG = DWORD')] 15 | byte_orders = [pytest.param('BIG_ENDIAN', id='byte_order = BIG_ENDIAN'), 16 | pytest.param('LITTLE_ENDIAN', id='byte_order = LITTLE_ENDIAN')] 17 | max_ctos = [pytest.param(v, id='MAX_CTO = {:04X}h'.format(v)) for v in (8, 128, 256)] 18 | mtas = [pytest.param(v, id='MTA = {:08X}h'.format(v)) for v in (0xDEADBEEF,)] 19 | resources = [pytest.param(1, id='RESOURCE = CAL/PAG'), 20 | pytest.param(4, id='RESOURCE = DAQ'), 21 | pytest.param(8, id='RESOURCE = STIM'), 22 | pytest.param(16, id='RESOURCE = PGM')] 23 | seeds = [pytest.param(v, id='seed length = {:03}d'.format(v)) for v in range(0x01, 0x100)] 24 | trailing_values = [pytest.param(v, id='trailing value = {:02X}h'.format(v)) for v in (0, 255)] 25 | cto_queue_sizes = [pytest.param(v, id='CTO_QUEUE_SIZE = {:02}d'.format(v)) for v in (0, 1, 255)] 26 | max_bss = [pytest.param(v, id='MAX_BS = {:02}d'.format(v)) for v in (0, 1, 255)] 27 | min_sts = [pytest.param(v, id='MIN_ST = {:02}d'.format(v)) for v in (0, 1, 255)] 28 | 29 | 30 | def element_size_from_address_granularity(address_granularity): 31 | return dict(BYTE=1, WORD=2, DWORD=4)[address_granularity] 32 | 33 | 34 | def generate_random_block_content(n, element_size, base_address) -> [(int, int)]: 35 | return list((base_address + (i * element_size), random.getrandbits(8 * element_size, )) for i in range(n)) 36 | 37 | 38 | def get_block_slices_for_max_cto(block, element_size, max_cto=8): 39 | n = floor((max_cto - 1) / element_size) 40 | return [block[i * n:(i + 1) * n] for i in range(len(block)) if len(block[i * n:(i + 1) * n]) != 0] 41 | 42 | 43 | def address_to_array(address: int, byte_size: int, endianness: str) -> [int]: 44 | return [int(b) for b in address.to_bytes(byte_size, 45 | dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[endianness], 46 | signed=False)] 47 | 48 | 49 | def u16_to_array(value: int, endianness: str) -> [int]: 50 | return [int(b) for b in value.to_bytes(2, dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[endianness], signed=False)] 51 | 52 | 53 | def u32_to_array(value: int, endianness: str) -> [int]: 54 | return [int(b) for b in value.to_bytes(4, dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[endianness], signed=False)] 55 | 56 | 57 | def u32_from_array(data: bytearray, endianness: str): 58 | return int.from_bytes(data, dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[endianness], signed=False) 59 | 60 | 61 | def payload_to_array(payload, number_of_data_elements, element_size, byte_order): 62 | return struct.unpack('{}{}'.format('>' if byte_order == 'BIG_ENDIAN' else '<', 63 | {1: 'B', 2: 'H', 4: 'I'}[element_size] * 64 | number_of_data_elements), payload) 65 | 66 | 67 | class DAQ(object): 68 | def __init__(self, name, type, max_odt, max_odt_entries, dtos): 69 | self._name = name 70 | self._type = type 71 | self._max_odt = max_odt 72 | self._max_odt_entries = max_odt_entries 73 | self._dtos = dtos 74 | 75 | 76 | class DefaultConfig(dict): 77 | def __init__(self, 78 | channel_rx_pdu_ref=0x0001, 79 | channel_tx_pdu_ref=0x0002, 80 | default_daq_dto_pdu_mapping=0x0003, 81 | daqs=({ 82 | "name": "DAQ1", 83 | "type": "DAQ", 84 | "max_odt": 1, 85 | "max_odt_entries": 1, 86 | "pdu_mapping": "XCP_PDU_ID_TRANSMIT", 87 | "dtos": [ 88 | { 89 | "pid": 0 90 | } 91 | ] 92 | },), 93 | xcp_set_request_api_enable=True, 94 | xcp_get_id_api_enable=True, 95 | xcp_get_seed_api_enable=True, 96 | xcp_unlock_api_enable=True, 97 | xcp_set_mta_api_enable=True, 98 | xcp_upload_api_enable=True, 99 | xcp_short_upload_api_enable=True, 100 | xcp_build_checksum_api_enable=True, 101 | xcp_download_api_enable=True, 102 | xcp_download_max_api_enable=True, 103 | xcp_short_download_api_enable=True, 104 | xcp_set_cal_page_api_enable=True, 105 | xcp_get_cal_page_api_enable=True, 106 | xcp_clear_daq_list_api_enable=True, 107 | xcp_set_daq_ptr_api_enable=True, 108 | xcp_write_daq_api_enable=True, 109 | xcp_set_daq_list_mode_api_enable=True, 110 | xcp_get_daq_list_mode_api_enable=True, 111 | xcp_start_stop_daq_list_api_enable=True, 112 | xcp_start_stop_synch_api_enable=True, 113 | xcp_get_daq_clock_api_enable=True, 114 | xcp_read_daq_api_enable=True, 115 | xcp_get_daq_processor_info_api_enable=True, 116 | xcp_get_daq_resolution_info_api_enable=True, 117 | xcp_get_daq_list_info_api_enable=True, 118 | xcp_get_daq_event_info_api_enable=True, 119 | xcp_free_daq_api_enable=True, 120 | xcp_alloc_daq_api_enable=True, 121 | xcp_alloc_odt_api_enable=True, 122 | xcp_alloc_odt_entry_api_enable=True, 123 | xcp_program_clear_api_enable=True, 124 | xcp_program_api_enable=True, 125 | xcp_program_max_api_enable=True, 126 | xcp_get_comm_mode_info_api_enable=True, 127 | resource_protection_calibration_paging=False, 128 | resource_protection_data_acquisition=False, 129 | resource_protection_data_stimulation=False, 130 | resource_protection_programming=False, 131 | byte_order='LITTLE_ENDIAN', 132 | address_granularity='BYTE', 133 | master_block_mode=True, 134 | slave_block_mode=True, 135 | interleaved_mode=False, 136 | max_bs=255, 137 | min_st=255, 138 | cto_queue_size=16, 139 | event_queue_size=16, 140 | max_cto=8, 141 | max_dto=8, 142 | checksum_type='XCP_CRC_32', 143 | user_defined_checksum_function='Xcp_UserDefinedChecksumFunction', 144 | user_cmd_function='Xcp_UserCmdFunction', 145 | trailing_value=0, 146 | identification='/path/to/database.a2l'): 147 | self._channel_rx_pdu = channel_rx_pdu_ref 148 | self._channel_tx_pdu = channel_tx_pdu_ref 149 | self._default_daq_dto_pdu_mapping = default_daq_dto_pdu_mapping 150 | self._event_queue_size = event_queue_size 151 | super(DefaultConfig, self).__init__(configurations=[ 152 | { 153 | "communication": { 154 | "channel_rx_pdu_ref": "XCP_PDU_ID_CTO_RX", 155 | "channel_tx_pdu_ref": "XCP_PDU_ID_CTO_TX" 156 | }, 157 | "daqs": list(daqs), 158 | "events": [ 159 | { 160 | "consistency": "ODT", 161 | "priority": 0, 162 | "time_cycle": 10, 163 | "time_unit": "TIMESTAMP_UNIT_1MS", 164 | "triggered_daq_list_ref": [ 165 | "DAQ1" 166 | ] 167 | } 168 | ], 169 | "apis": { 170 | "xcp_set_request_api_enable": {"enabled": xcp_set_request_api_enable, "protected": False}, 171 | "xcp_get_id_api_enable": {"enabled": xcp_get_id_api_enable, "protected": False}, 172 | "xcp_get_seed_api_enable": {"enabled": xcp_get_seed_api_enable, "protected": False}, 173 | "xcp_unlock_api_enable": {"enabled": xcp_unlock_api_enable, "protected": False}, 174 | "xcp_set_mta_api_enable": {"enabled": xcp_set_mta_api_enable, "protected": False}, 175 | "xcp_upload_api_enable": {"enabled": xcp_upload_api_enable, "protected": False}, 176 | "xcp_short_upload_api_enable": {"enabled": xcp_short_upload_api_enable, "protected": False}, 177 | "xcp_build_checksum_api_enable": {"enabled": xcp_build_checksum_api_enable, "protected": False}, 178 | "xcp_download_api_enable": {"enabled": xcp_download_api_enable, "protected": False}, 179 | "xcp_download_max_api_enable": {"enabled": xcp_download_max_api_enable, "protected": False}, 180 | "xcp_short_download_api_enable": {"enabled": xcp_short_download_api_enable, "protected": False}, 181 | "xcp_set_cal_page_api_enable": {"enabled": xcp_set_cal_page_api_enable, "protected": False}, 182 | "xcp_get_cal_page_api_enable": {"enabled": xcp_get_cal_page_api_enable, "protected": False}, 183 | "xcp_clear_daq_list_api_enable": {"enabled": xcp_clear_daq_list_api_enable, "protected": False}, 184 | "xcp_set_daq_ptr_api_enable": {"enabled": xcp_set_daq_ptr_api_enable, "protected": False}, 185 | "xcp_write_daq_api_enable": {"enabled": xcp_write_daq_api_enable, "protected": False}, 186 | "xcp_set_daq_list_mode_api_enable": {"enabled": xcp_set_daq_list_mode_api_enable, 187 | "protected": False}, 188 | "xcp_get_daq_list_mode_api_enable": {"enabled": xcp_get_daq_list_mode_api_enable, 189 | "protected": False}, 190 | "xcp_start_stop_daq_list_api_enable": {"enabled": xcp_start_stop_daq_list_api_enable, 191 | "protected": False}, 192 | "xcp_start_stop_synch_api_enable": {"enabled": xcp_start_stop_synch_api_enable, "protected": False}, 193 | "xcp_get_daq_clock_api_enable": {"enabled": xcp_get_daq_clock_api_enable, "protected": False}, 194 | "xcp_read_daq_api_enable": {"enabled": xcp_read_daq_api_enable, "protected": False}, 195 | "xcp_get_daq_processor_info_api_enable": {"enabled": xcp_get_daq_processor_info_api_enable, 196 | "protected": False}, 197 | "xcp_get_daq_resolution_info_api_enable": {"enabled": xcp_get_daq_resolution_info_api_enable, 198 | "protected": False}, 199 | "xcp_get_daq_list_info_api_enable": {"enabled": xcp_get_daq_list_info_api_enable, 200 | "protected": False}, 201 | "xcp_get_daq_event_info_api_enable": {"enabled": xcp_get_daq_event_info_api_enable, 202 | "protected": False}, 203 | "xcp_free_daq_api_enable": {"enabled": xcp_free_daq_api_enable, "protected": False}, 204 | "xcp_alloc_daq_api_enable": {"enabled": xcp_alloc_daq_api_enable, "protected": False}, 205 | "xcp_alloc_odt_api_enable": {"enabled": xcp_alloc_odt_api_enable, "protected": False}, 206 | "xcp_alloc_odt_entry_api_enable": {"enabled": xcp_alloc_odt_entry_api_enable, "protected": False}, 207 | "xcp_program_clear_api_enable": {"enabled": xcp_program_clear_api_enable, "protected": False}, 208 | "xcp_program_api_enable": {"enabled": xcp_program_api_enable, "protected": False}, 209 | "xcp_program_max_api_enable": {"enabled": xcp_program_max_api_enable, "protected": False}, 210 | "xcp_get_comm_mode_info_api_enable": {"enabled": xcp_get_comm_mode_info_api_enable, 211 | "protected": False}, 212 | "resource_protection": { 213 | "calibration_paging": resource_protection_calibration_paging, 214 | "data_acquisition": resource_protection_data_acquisition, 215 | "data_stimulation": resource_protection_data_stimulation, 216 | "programming": resource_protection_programming 217 | } 218 | }, 219 | "protocol_layer": { 220 | "byte_order": byte_order, 221 | "address_granularity": address_granularity, 222 | "master_block_mode": master_block_mode, 223 | "slave_block_mode": slave_block_mode, 224 | "interleaved_mode": interleaved_mode, 225 | "max_bs": max_bs, 226 | "min_st": min_st, 227 | "cto_queue_size": cto_queue_size, 228 | "event_queue_size": event_queue_size, 229 | "max_cto": max_cto, 230 | "max_dto": max_dto, 231 | "checksum_type": checksum_type, 232 | "user_defined_checksum_function": user_defined_checksum_function, 233 | "user_cmd_function": user_cmd_function, 234 | "trailing_value": trailing_value, 235 | 'identification': identification 236 | } 237 | } 238 | ]) 239 | 240 | @property 241 | def get_id(self): 242 | tmp = self.copy() 243 | tmp.update(dict(_channel_rx_pdu=self.channel_rx_pdu, 244 | _channel_tx_pdu=self.channel_tx_pdu, 245 | _default_daq_dto_pdu_mapping=self.default_daq_dto_pdu_mapping)) 246 | return hashlib.sha224(json.dumps(tmp, sort_keys=True, indent=0).encode('utf-8')).hexdigest()[0:8] 247 | 248 | @property 249 | def channel_rx_pdu(self): 250 | return self._channel_rx_pdu 251 | 252 | @property 253 | def channel_tx_pdu(self): 254 | return self._channel_tx_pdu 255 | 256 | @property 257 | def default_daq_dto_pdu_mapping(self): 258 | return self._default_daq_dto_pdu_mapping 259 | 260 | @property 261 | def event_queue_size(self): 262 | return self._event_queue_size 263 | 264 | 265 | if __name__ == '__main__': 266 | a = DefaultConfig() 267 | print(a.get_id) 268 | -------------------------------------------------------------------------------- /test/seed_key_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | def get_seed_key_slices(seed, max_cto=8): 9 | n = max_cto - 2 10 | return [seed[i * n:(i + 1) * n] for i in range(len(seed)) if len(seed[i * n:(i + 1) * n]) != 0] 11 | 12 | 13 | def get_seed_side_effect_copy_ok(handle, seed): 14 | def wrapper(p_seed_buffer, _max_seed_length, p_seed_length): 15 | for i, b in enumerate(seed): 16 | p_seed_buffer[i] = b 17 | p_seed_length[0] = len(seed) 18 | return handle.define('E_OK') 19 | return wrapper 20 | 21 | 22 | def calc_key_side_effect_copy_ok(handle, key): 23 | def wrapper(_p_seed_buffer, _seed_length, p_key_buffer, _max_key_length, p_key_length): 24 | for i, b in enumerate(key): 25 | p_key_buffer[i] = b 26 | p_key_length[0] = len(key) 27 | return handle.define('E_OK') 28 | return wrapper 29 | 30 | 31 | @pytest.mark.parametrize('resource', resources) 32 | @pytest.mark.parametrize('max_cto', max_ctos) 33 | @pytest.mark.parametrize('seed', seeds, indirect=True) 34 | def test_get_seed_returns_the_expected_responses(resource, max_cto, seed): 35 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto)) 36 | 37 | handle.xcp_get_seed.side_effect = get_seed_side_effect_copy_ok(handle, seed) 38 | 39 | # CONNECT 40 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 41 | handle.lib.Xcp_MainFunction() 42 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 43 | 44 | # GET_SEED 45 | actual_seed = list() 46 | remaining_seed_length = len(seed) 47 | for mode, seed_slice in zip([0] + [1] * (len(get_seed_key_slices(seed, max_cto)) - 1), 48 | get_seed_key_slices(seed, max_cto)): 49 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, mode, resource))) 50 | handle.lib.Xcp_MainFunction() 51 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, remaining_seed_length) 52 | actual_seed += list(handle.can_if_transmit.call_args[0][1].SduDataPtr[2:2 + min(remaining_seed_length, max_cto - 2)]) 53 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 54 | 55 | remaining_seed_length -= len(seed_slice) 56 | 57 | assert actual_seed == seed 58 | 59 | 60 | @pytest.mark.parametrize('seed_array', ((s, 2) for s in range(0x07, 0x0D)), indirect=True) 61 | def test_get_seed_does_not_return_an_error_pid_if_the_first_part_of_the_seed_is_requested_twice(seed_array): 62 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 63 | 64 | def get_seed_1_side_effect(p_seed_buffer, _max_seed_length, p_seed_length): 65 | for i, b in enumerate(seed_array[0]): 66 | p_seed_buffer[i] = b 67 | p_seed_length[0] = len(seed_array[0]) 68 | return handle.define('E_OK') 69 | 70 | def get_seed_2_side_effect(p_seed_buffer, _max_seed_length, p_seed_length): 71 | for i, b in enumerate(seed_array[1]): 72 | p_seed_buffer[i] = b 73 | p_seed_length[0] = len(seed_array[1]) 74 | return handle.define('E_OK') 75 | 76 | handle.xcp_get_seed.side_effect = get_seed_1_side_effect 77 | 78 | # CONNECT 79 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 80 | handle.lib.Xcp_MainFunction() 81 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 82 | 83 | # GET_SEED #1 84 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, 0x00, 0x01))) 85 | handle.lib.Xcp_MainFunction() 86 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, len(seed_array[0])) 87 | assert seed_array[0][0:6] == list(handle.can_if_transmit.call_args[0][1].SduDataPtr[2:8]) 88 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 89 | 90 | handle.xcp_get_seed.side_effect = get_seed_2_side_effect 91 | 92 | # GET_SEED #1 93 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, 0x00, 0x01))) 94 | handle.lib.Xcp_MainFunction() 95 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, len(seed_array[1])) 96 | second_seed = list(handle.can_if_transmit.call_args[0][1].SduDataPtr[2:8]) 97 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 98 | 99 | # GET_SEED #2 100 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, 0x01, 0x01))) 101 | handle.lib.Xcp_MainFunction() 102 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, len(seed_array[1]) - 0x06) 103 | second_seed += list(handle.can_if_transmit.call_args[0][1].SduDataPtr[2:2 + len(seed_array[1]) - 0x06]) 104 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 105 | 106 | assert second_seed == seed_array[1] 107 | 108 | 109 | @pytest.mark.parametrize('resource', resources) 110 | @pytest.mark.parametrize('max_cto', max_ctos) 111 | @pytest.mark.parametrize('seed', seeds, indirect=True) 112 | def test_unlock_unlocks_the_requested_resource_if_the_key_is_valid(resource, max_cto, seed): 113 | key = seed 114 | 115 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto)) 116 | 117 | handle.xcp_get_seed.side_effect = get_seed_side_effect_copy_ok(handle, seed) 118 | handle.xcp_calc_key.side_effect = calc_key_side_effect_copy_ok(handle, key) 119 | 120 | seed_slices = get_seed_key_slices(seed, max_cto=max_cto) 121 | key_slices = get_seed_key_slices(key, max_cto=max_cto) 122 | 123 | # CONNECT 124 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 125 | handle.lib.Xcp_MainFunction() 126 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 127 | 128 | # GET_SEED 129 | for mode, _ in zip([0] + [1] * (len(seed_slices) - 1), seed_slices): 130 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, mode, resource))) 131 | handle.lib.Xcp_MainFunction() 132 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 133 | 134 | # UNLOCK 135 | remaining_key_length = len(key) 136 | for key_slice in key_slices: 137 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF7, remaining_key_length, *key_slice))) 138 | handle.lib.Xcp_MainFunction() 139 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 140 | 141 | remaining_key_length -= len(key_slice) 142 | 143 | if remaining_key_length != 0: 144 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, 0x00) 145 | 146 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFF, resource) 147 | 148 | 149 | @pytest.mark.parametrize('resource', resources) 150 | @pytest.mark.parametrize('seed', [pytest.param(1, id='seed length = {:03}d'.format(1))], indirect=True) 151 | def test_unlock_disconnects_the_master_if_key_is_invalid(resource, seed): 152 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 153 | 154 | def calc_key_side_effect(_p_seed_buffer, _seed_length, p_key_buffer, _max_key_length, p_key_length): 155 | for i, b in enumerate(seed): 156 | p_key_buffer[i] = (~b) & 0xFF 157 | p_key_length[0] = len(seed) 158 | return handle.define('E_OK') 159 | 160 | handle.xcp_get_seed.side_effect = get_seed_side_effect_copy_ok(handle, seed) 161 | handle.xcp_calc_key.side_effect = calc_key_side_effect 162 | 163 | # CONNECT 164 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 165 | handle.lib.Xcp_MainFunction() 166 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 167 | 168 | # GET_SEED 169 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF8, 0x00, resource))) 170 | handle.lib.Xcp_MainFunction() 171 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 172 | 173 | # UNLOCK 174 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF7, len(seed), *seed))) 175 | handle.lib.Xcp_MainFunction() 176 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 177 | 178 | # GET_STATUS 179 | # If we are disconnected, no commands except the CONNECT command is processed. Here, we send a GET_STATUS command to 180 | # check if the CanIf underlying function is called or not (we expect that it is not called, as we should be 181 | # disconnected). 182 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFD,))) 183 | handle.lib.Xcp_MainFunction() 184 | 185 | assert handle.can_if_transmit.call_count == 3 186 | -------------------------------------------------------------------------------- /test/set_mta_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | @pytest.mark.parametrize('trailing_value', trailing_values) 9 | @pytest.mark.parametrize('max_cto', max_ctos) 10 | def test_set_mta_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 11 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 12 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 13 | handle.lib.Xcp_MainFunction() 14 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 15 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00))) 16 | handle.lib.Xcp_MainFunction() 17 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x08)) 18 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0x08:max_cto]) == remaining_zeros 19 | -------------------------------------------------------------------------------- /test/set_request_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | from unittest.mock import ANY 7 | 8 | 9 | def test_set_request_activates_the_callback_function_call_until_finished(): 10 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 11 | 12 | return_values = (r for r in [handle.define('E_NOT_OK'), handle.define('E_NOT_OK'), handle.define('E_OK')]) 13 | 14 | def store_calibration_data_to_non_volatile_memory(p_success): 15 | p_success[0] = handle.define('E_OK') 16 | return next(return_values) 17 | 18 | handle.xcp_store_calibration_data_to_non_volatile_memory.side_effect = store_calibration_data_to_non_volatile_memory 19 | 20 | # CONNECT 21 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 22 | handle.lib.Xcp_MainFunction() 23 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 24 | 25 | # SET_REQUEST 26 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF9, 0x01, 0x00, 0x00))) 27 | handle.lib.Xcp_MainFunction() 28 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 29 | 30 | handle.lib.Xcp_MainFunction() 31 | handle.lib.Xcp_MainFunction() 32 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 33 | 34 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFD, 0x03) 35 | 36 | 37 | @pytest.mark.parametrize('event_queue_size', [2, 4, 8, 16, 32]) 38 | def test_set_request_calls_det_with_err_event_queue_full_if_no_event_is_sent(event_queue_size): 39 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, event_queue_size=event_queue_size)) 40 | 41 | def store_calibration_data_to_non_volatile_memory(p_success): 42 | p_success[0] = handle.define('E_OK') 43 | return handle.define('E_OK') 44 | 45 | handle.xcp_store_calibration_data_to_non_volatile_memory.side_effect = store_calibration_data_to_non_volatile_memory 46 | 47 | # CONNECT 48 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 49 | handle.lib.Xcp_MainFunction() 50 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 51 | 52 | for _ in range(event_queue_size): 53 | # SET_REQUEST 54 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF9, 0x01, 0x00, 0x00))) 55 | handle.lib.Xcp_MainFunction() 56 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 57 | 58 | handle.det_report_error.assert_called_once_with(ANY, 59 | ANY, 60 | handle.define('XCP_MAIN_FUNCTION_API_ID'), 61 | handle.define('XCP_E_EVENT_QUEUE_FULL')) 62 | 63 | 64 | @pytest.mark.parametrize('trailing_value', trailing_values) 65 | @pytest.mark.parametrize('max_cto', max_ctos) 66 | def test_set_request_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 67 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 68 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 69 | handle.lib.Xcp_MainFunction() 70 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 71 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF9, 0x01, 0x00, 0x00))) 72 | handle.lib.Xcp_MainFunction() 73 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x08)) 74 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0x08:max_cto]) == remaining_zeros 75 | -------------------------------------------------------------------------------- /test/short_upload_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import pytest_cases 5 | 6 | from .parameter import * 7 | from .conftest import XcpTest 8 | 9 | 10 | @pytest_cases.fixture() 11 | @pytest.mark.parametrize('ag', address_granularities) 12 | @pytest.mark.parametrize('max_cto', max_ctos) 13 | def short_upload_payload_properties(ag, max_cto): 14 | element_size = element_size_from_address_granularity(ag) 15 | num_of_data_elements = floor((max_cto - 1) / element_size) 16 | alignment = max_cto - 1 - num_of_data_elements * element_size 17 | return ag, max_cto, alignment, num_of_data_elements 18 | 19 | 20 | @pytest_cases.parametrize('ag, max_cto, alignment, number_of_data_elements', 21 | [pytest_cases.fixture_ref(short_upload_payload_properties)]) 22 | @pytest.mark.parametrize('address_extension', address_extensions) 23 | @pytest.mark.parametrize('mta', mtas) 24 | @pytest.mark.parametrize('byte_order', byte_orders) 25 | def test_short_upload_uploads_elements_according_to_provided_mta_with_address_granularity_byte(ag, 26 | max_cto, 27 | alignment, 28 | number_of_data_elements, 29 | address_extension, 30 | mta, 31 | byte_order): 32 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 33 | address_granularity=ag, 34 | byte_order=byte_order, 35 | max_cto=max_cto)) 36 | 37 | element_size = element_size_from_address_granularity(ag) 38 | expected_block = generate_random_block_content(number_of_data_elements, element_size, mta) 39 | expected_block_generator = (v for v in expected_block) 40 | actual_block = list() 41 | block_slices = get_block_slices_for_max_cto(expected_block, element_size, max_cto=max_cto) 42 | 43 | def read_slave_memory(p_address, _extension, p_buffer): 44 | expected_address, expected_value = next(expected_block_generator) 45 | expected_value_buffer = expected_value.to_bytes(element_size, 46 | dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[byte_order], 47 | signed=False) 48 | for i, b in enumerate(expected_value_buffer): 49 | p_buffer[i] = int(b) 50 | actual_block.append((int(handle.ffi.cast('uint32_t', p_address)), expected_value)) 51 | 52 | handle.xcp_read_slave_memory_u8.side_effect = read_slave_memory 53 | handle.xcp_read_slave_memory_u16.side_effect = read_slave_memory 54 | handle.xcp_read_slave_memory_u32.side_effect = read_slave_memory 55 | 56 | # CONNECT 57 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 58 | handle.lib.Xcp_MainFunction() 59 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 60 | 61 | handle.lib.Xcp_MainFunction() 62 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 63 | 64 | # SHORT_UPLOAD 65 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF4, 66 | number_of_data_elements, 67 | 0x00, 68 | address_extension, 69 | *address_to_array(mta, 4, byte_order)))) 70 | handle.lib.Xcp_MainFunction() 71 | 72 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[0] == 0xFF 73 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[1:1 + alignment]) == tuple([0] * alignment) 74 | raw_values = bytearray(handle.can_if_transmit.call_args[0][1].SduDataPtr[element_size:max_cto]) 75 | actual_values = tuple(payload_to_array(raw_values, number_of_data_elements, element_size, byte_order)) 76 | assert actual_values == tuple(v[1] for v in block_slices[0]) 77 | 78 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 79 | 80 | # Call Xcp_MainFunction one more time to make sure no more data are sent. 81 | handle.lib.Xcp_MainFunction() 82 | 83 | assert handle.can_if_transmit.call_count == 2 84 | assert actual_block == expected_block 85 | -------------------------------------------------------------------------------- /test/stub/CanIf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CanIf.h 3 | * @author Guillaume Sottas 4 | * @date 07/12/2017 5 | */ 6 | 7 | #ifndef CANIF_H 8 | #define CANIF_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | #include "CanIf_Types.h" 17 | 18 | extern Std_ReturnType CanIf_Transmit(PduIdType txPduId, const PduInfoType *pPduInfo); 19 | 20 | #ifdef __cplusplus 21 | } 22 | 23 | #endif /* ifdef __cplusplus */ 24 | 25 | #endif /* define CANIF_H */ 26 | -------------------------------------------------------------------------------- /test/stub/CanIf_Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CanIf_Types.h 3 | * @author Guillaume Sottas 4 | * @date 07/12/2017 5 | */ 6 | 7 | #ifndef CANIF_TYPES_H 8 | #define CANIF_TYPES_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | #include "ComStack_Types.h" 17 | #include "Std_Types.h" 18 | 19 | #ifdef __cplusplus 20 | } 21 | 22 | #endif /* ifdef __cplusplus */ 23 | 24 | #endif /* define CANIF_TYPES_H */ 25 | -------------------------------------------------------------------------------- /test/stub/Det.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Det.h 3 | * @author Guillaume Sottas 4 | * @date 10/12/2021 5 | */ 6 | 7 | #ifndef DET_H 8 | #define DET_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* #ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | extern Std_ReturnType 21 | Det_ReportError(uint16 moduleId, uint8 instanceId, uint8 apiId, uint8 errorId); 22 | 23 | extern Std_ReturnType 24 | Det_ReportRuntimeError(uint16 moduleId, uint8 instanceId, uint8 apiId, uint8 errorId); 25 | 26 | extern Std_ReturnType 27 | Det_ReportTransientFault(uint16 moduleId, uint8 instanceId, uint8 apiId, uint8 faultId); 28 | 29 | #ifdef __cplusplus 30 | } 31 | 32 | #endif /* #ifdef __cplusplus */ 33 | 34 | #endif /* #ifndef DET_H */ 35 | -------------------------------------------------------------------------------- /test/stub/Xcp_Checksum.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_Checksum.h 3 | * @author Guillaume Sottas 4 | * @date 18/07/2022 5 | */ 6 | 7 | #ifndef XCP_CHECKSUM_H 8 | #define XCP_CHECKSUM_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* #ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | /** 21 | * @brief Calculates the checksum on the provided address range. 22 | * @param [in] pLowerAddress Pointer to lower address of the data range on which the checksum is calculated 23 | * @param [in] pUpperAddress Pointer to upper address of the data range on which the checksum is calculated 24 | * @param [out] pResult Pointer to the buffer where the calculated checksum will be stored 25 | * @returns The post-incremented MTA value. 26 | */ 27 | extern void *Xcp_UserDefinedChecksumFunction(void *pLowerAddress, const void *pUpperAddress, uint32 *pResult); 28 | 29 | #ifdef __cplusplus 30 | } 31 | 32 | #endif /* #ifdef __cplusplus */ 33 | 34 | #endif /* #ifndef XCP_CHECKSUM_H */ 35 | -------------------------------------------------------------------------------- /test/stub/Xcp_MemoryAccess.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_SeedKey.h 3 | * @author Guillaume Sottas 4 | * @date 27/01/2022 5 | */ 6 | 7 | #ifndef XCP_MEMORY_ACCESS_H 8 | #define XCP_MEMORY_ACCESS_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* #ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | /** 21 | * @brief Reads a single byte form slave memory. 22 | * @param [in] pAddress Pointer to address location from where data must be read 23 | * @param [in] extension Address extension from where data must be read 24 | * @param [out] pBuffer Pointer to the buffer where the memory content will be stored 25 | */ 26 | extern void Xcp_ReadSlaveMemoryU8(void *pAddress, uint8 extension, uint8 *pBuffer); 27 | 28 | /** 29 | * @brief Reads two bytes form slave memory. 30 | * @param [in] pAddress Pointer to address location from where data must be read 31 | * @param [in] extension Address extension from where data must be read 32 | * @param [out] pBuffer Pointer to the buffer where the memory content will be stored 33 | */ 34 | extern void Xcp_ReadSlaveMemoryU16(void *address, uint8 extension, uint8 *pBuffer); 35 | 36 | /** 37 | * @brief Reads four bytes form slave memory. 38 | * @param [in] pAddress Pointer to address location from where data must be read 39 | * @param [in] extension Address extension from where data must be read 40 | * @param [out] pBuffer Pointer to the buffer where the memory content will be stored 41 | */ 42 | extern void Xcp_ReadSlaveMemoryU32(void *address, uint8 extension, uint8 *pBuffer); 43 | 44 | /** 45 | * @brief Writes a single byte into slave memory. 46 | * @param [in] pAddress Pointer to address location where data must be written 47 | * @param [in] pBuffer Pointer to the data buffer 48 | */ 49 | extern void Xcp_WriteSlaveMemoryU8(void *pAddress, uint8 *pBuffer); 50 | 51 | /** 52 | * @brief Writes two bytes into slave memory. 53 | * @param [in] pAddress Pointer to address location where data must be written 54 | * @param [in] pBuffer Pointer to the data buffer 55 | */ 56 | extern void Xcp_WriteSlaveMemoryU16(void *address, uint8 *pBuffer); 57 | 58 | /** 59 | * @brief Writes four bytes into slave memory. 60 | * @param [in] pAddress Pointer to address location where data must be written 61 | * @param [in] pBuffer Pointer to the data buffer 62 | */ 63 | extern void Xcp_WriteSlaveMemoryU32(void *address, uint8 *pBuffer); 64 | 65 | /** 66 | * @brief Stores calibration data in slave's non-volatile memory. 67 | * @param [out] pStatusCode Pointer to status indicating the store sequence result value 68 | * @retval E_OK: The store sequence is finished (no matter if it was successfully terminated or not) 69 | * @retval E_NOT_OK: The store sequence is not finished 70 | */ 71 | extern Std_ReturnType Xcp_StoreCalibrationDataToNonVolatileMemory(uint8 *pStatusCode); 72 | 73 | #ifdef __cplusplus 74 | } 75 | 76 | #endif /* #ifdef __cplusplus */ 77 | 78 | #endif /* #ifndef XCP_MEMORY_ACCESS_H */ 79 | -------------------------------------------------------------------------------- /test/stub/Xcp_SeedKey.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_SeedKey.h 3 | * @author Guillaume Sottas 4 | * @date 27/01/2022 5 | */ 6 | 7 | #ifndef XCP_SEED_KEY_H 8 | #define XCP_SEED_KEY_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* #ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | /** 21 | * @brief Generates a random seed. 22 | * @param [out] pSeedBuffer Pointer to the buffer where the generated seed will be stored 23 | * @param [in] maxSeedLength Maximum length of the seed the caller can handle. This value depends of 24 | * the size of the buffer in the XCP stack 25 | * @param [out] pSeedLength Pointer to the seed length of the generated seed. This value should 26 | * never be greater than the maxSeedLength parameter 27 | * @retval E_OK : The seed has been successfully generated 28 | * @retval E_NOT_OK : The seed has not been successfully generated, or the seed length is greater 29 | * than the specified maximum seed length 30 | */ 31 | extern Std_ReturnType Xcp_GetSeed(uint8 *pSeedBuffer, 32 | const uint16 maxSeedLength, 33 | uint16 *pSeedLength); 34 | 35 | /** 36 | * @brief Calculates the key for the provided seed. 37 | * @param [in] pSeedBuffer Pointer to the buffer containing the input seed 38 | * @param [in] seedLength Length of the provided input seed 39 | * @param [out] pKeyBuffer Pointer to the buffer where the calculated key will be stored 40 | * @param [in] maxKeyLength Maximum length of the key the caller can handle. This value depends of 41 | * the size of the buffer in the XCP stack 42 | * @param [out] pKeyLength Pointer to the key length of the calculated key. This value should never 43 | * be greater than the maxKeyLength parameter 44 | * @retval E_OK: The key has been successfully calculated 45 | * @retval E_NOT_OK: The key has not been successfully generated, or the key length is greater 46 | * than the specified maximum key length 47 | * 48 | * @link https://support.vector.com/kb?id=kb_article_view&sysparm_article=KB0011313&sys_kb_id=35e40ea41b2614148e9a535c2e4bcb28&spa=1 49 | */ 50 | extern Std_ReturnType Xcp_CalcKey(const uint8 *pSeedBuffer, 51 | const uint16 seedLength, 52 | uint8* pKeyBuffer, 53 | const uint16 maxKeyLength, 54 | uint16 *pKeyLength); 55 | 56 | #ifdef __cplusplus 57 | } 58 | 59 | #endif /* #ifdef __cplusplus */ 60 | 61 | #endif /* #ifndef XCP_SEED_KEY_H */ 62 | -------------------------------------------------------------------------------- /test/stub/Xcp_UserCmd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Xcp_UserCmd.h 3 | * @author Guillaume Sottas 4 | * @date 21/07/2022 5 | */ 6 | 7 | #ifndef XCP_USER_CMD_H 8 | #define XCP_USER_CMD_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* #ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | #ifndef COMSTACK_TYPES_H 21 | #include "ComStack_Types.h" 22 | #endif /* #ifndef COMSTACK_TYPES_H */ 23 | 24 | /** 25 | * @brief Calculates the checksum on the provided address range. 26 | * @param [in] pCtoPduInfo Lower address of the data range on which the checksum is calculated 27 | * @param [out] pResErrPduInfo Upper address of the data range on which the checksum is calculated 28 | * @retval E_OK : Command executed successfully 29 | * @retval XCP_E_* : Command failed. If the DET module is enabled, this error will be reported to the DET 30 | */ 31 | extern uint8 Xcp_UserCmdFunction(const PduInfoType *pCtoPduInfo, PduInfoType *pResErrPduInfo); 32 | 33 | #ifdef __cplusplus 34 | } 35 | 36 | #endif /* #ifdef __cplusplus */ 37 | 38 | #endif /* #ifndef XCP_USER_CMD_H */ 39 | -------------------------------------------------------------------------------- /test/stub/common/ComStack_Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ComStack_Types.h 3 | * @author Guillaume Sottas 4 | * @date 06/12/2017 5 | */ 6 | 7 | #ifndef COMSTACK_TYPES_H 8 | #define COMSTACK_TYPES_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | #ifndef STD_TYPES_H 17 | #include "Std_Types.h" 18 | #endif /* #ifndef STD_TYPES_H */ 19 | 20 | typedef uint16 PduIdType; 21 | 22 | typedef uint32 PduLengthType; 23 | 24 | typedef uint8 NetworkHandleType; 25 | 26 | typedef uint8 IcomConfigIdType; 27 | 28 | typedef enum 29 | { 30 | ICOM_SWITCH_E_OK = 0x00u, 31 | ICOM_SWITCH_E_FAILED = 0x01u 32 | } IcomSwitch_ErrorType; 33 | 34 | typedef enum 35 | { 36 | TP_STMIN = 0x00u, 37 | TP_BS = 0x01u, 38 | TP_BC = 0x02u 39 | } TPParameterType; 40 | 41 | typedef enum 42 | { 43 | BUFREQ_OK = 0x00u, 44 | BUFREQ_E_NOT_OK = 0x01u, 45 | BUFREQ_E_BUSY = 0x02u, 46 | BUFREQ_E_OVFL = 0x03u 47 | } BufReq_ReturnType; 48 | 49 | typedef enum 50 | { 51 | TP_DATACONF = 0x00u, 52 | TP_DATARETRY = 0x01u, 53 | TP_CONFPENDING = 0x02u 54 | } TpDataStateType; 55 | 56 | typedef struct 57 | { 58 | uint8 *SduDataPtr; 59 | uint8 *MetaDataPtr; 60 | PduLengthType SduLength; 61 | } PduInfoType; 62 | 63 | typedef struct 64 | { 65 | TpDataStateType TpDataState; 66 | PduLengthType TxTpDataCnt; 67 | } RetryInfoType; 68 | 69 | #ifdef __cplusplus 70 | } 71 | 72 | #endif /* ifdef __cplusplus */ 73 | 74 | #endif /* #ifndef COMSTACK_TYPES_H */ 75 | -------------------------------------------------------------------------------- /test/stub/common/Compiler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Compiler.h 3 | * @author Guillaume Sottas 4 | * @date 30/07/2019 5 | */ 6 | 7 | #ifndef COMPILER_H 8 | #define COMPILER_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | /* SWS_COMPILER_00057 17 | #define INLINE inline */ 18 | 19 | /* SWS_COMPILER_00060 */ 20 | #define LOCAL_INLINE static inline 21 | 22 | #ifdef __cplusplus 23 | } 24 | 25 | #endif /* ifdef __cplusplus */ 26 | 27 | #endif /* #ifndef COMPILER_H */ 28 | -------------------------------------------------------------------------------- /test/stub/common/Platform_Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Platform_Types.h 3 | * @author Guillaume Sottas 4 | * @date 14/10/2016 5 | */ 6 | 7 | #ifndef PLATFORM_TYPES_H 8 | #define PLATFORM_TYPES_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | typedef unsigned char uint8; 17 | 18 | typedef signed char sint8; 19 | 20 | typedef unsigned short uint16; 21 | 22 | typedef signed short sint16; 23 | 24 | typedef unsigned int uint32; 25 | 26 | typedef signed int sint32; 27 | 28 | typedef uint32 uint8_least; 29 | 30 | typedef sint32 sint8_least; 31 | 32 | typedef uint32 uint16_least; 33 | 34 | typedef sint32 sint16_least; 35 | 36 | typedef uint32 uint32_least; 37 | 38 | typedef sint32 sint32_least; 39 | 40 | typedef uint8_least boolean; 41 | 42 | typedef float ieee_float; 43 | 44 | #ifdef __cplusplus 45 | } 46 | 47 | #endif /* ifdef __cplusplus */ 48 | 49 | #endif /* #ifndef PLATFORM_TYPES_H */ 50 | -------------------------------------------------------------------------------- /test/stub/common/Std_Types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Std_Types.h 3 | * @author Guillaume Sottas 4 | * @date 14/10/2016 5 | */ 6 | 7 | #ifndef STD_TYPES_H 8 | #define STD_TYPES_H 9 | 10 | #ifdef __cplusplus 11 | 12 | extern "C" { 13 | 14 | #endif /* ifdef __cplusplus */ 15 | 16 | #include "Compiler.h" 17 | #include "Platform_Types.h" 18 | 19 | #ifndef STD_ON 20 | 21 | #define STD_ON (0x01u) 22 | 23 | #endif /* #ifndef STD_ON */ 24 | 25 | #ifndef STD_OFF 26 | 27 | #define STD_OFF (0x00u) 28 | 29 | #endif /* #ifndef STD_OFF */ 30 | 31 | #ifndef E_OK 32 | 33 | #define E_OK (0x00u) 34 | 35 | #endif /* #ifndef E_OK */ 36 | 37 | #ifndef E_NOT_OK 38 | 39 | #define E_NOT_OK (0x01u) 40 | 41 | #endif /* #ifndef E_NOT_OK */ 42 | 43 | #ifndef TRUE 44 | 45 | #define TRUE (0x01u) 46 | 47 | #endif /* #ifndef TRUE */ 48 | 49 | #ifndef FALSE 50 | 51 | #define FALSE (0x00u) 52 | 53 | #endif /* #ifndef FALSE */ 54 | 55 | #ifndef STD_LOW 56 | 57 | #define STD_LOW (0x00u) 58 | 59 | #endif /* #ifndef STD_LOW */ 60 | 61 | #ifndef STD_HIGH 62 | 63 | #define STD_HIGH (0x01u) 64 | 65 | #endif /* #ifndef STD_HIGH */ 66 | 67 | #ifndef NULL_PTR 68 | 69 | #define NULL_PTR ((void *)0x00u) 70 | 71 | #endif /* #ifndef NULL_PTR */ 72 | 73 | typedef uint32 Std_ReturnType; 74 | 75 | typedef struct 76 | { 77 | uint16 vendorID; 78 | uint16 moduleID; 79 | uint8 sw_major_version; 80 | uint8 sw_minor_version; 81 | uint8 sw_patch_version; 82 | } Std_VersionInfoType; 83 | 84 | #ifdef __cplusplus 85 | } 86 | 87 | #endif /* ifdef __cplusplus */ 88 | 89 | #endif /* #ifndef STD_TYPES_H */ 90 | -------------------------------------------------------------------------------- /test/synch_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | @pytest.mark.parametrize('trailing_value', trailing_values) 9 | @pytest.mark.parametrize('max_cto', max_ctos) 10 | def test_synch_sets_all_remaining_bytes_to_trailing_value(trailing_value, max_cto): 11 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, max_cto=max_cto, trailing_value=trailing_value)) 12 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 13 | handle.lib.Xcp_MainFunction() 14 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 15 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFC,))) 16 | handle.lib.Xcp_MainFunction() 17 | remaining_zeros = tuple(trailing_value for _ in range(max_cto - 0x02)) 18 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[2:max_cto]) == remaining_zeros 19 | -------------------------------------------------------------------------------- /test/transport_layer_cmd_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from .parameter import * 5 | from .conftest import XcpTest 6 | 7 | 8 | @pytest.mark.parametrize('rx_pdu_ref, tx_pdu_ref', [(0x0001, 0x0002), (0xFFFE, 0xFFFF)]) 9 | @pytest.mark.parametrize('mode, xcp_tag', [pytest.param(0, [0x58, 0x43, 0x50], id='mode=echo'), 10 | pytest.param(1, [0xA7, 0xBC, 0xAF], id='mode=inversed echo')]) 11 | @pytest.mark.parametrize('byte_order', byte_orders) 12 | def test_transport_layer_cmd_sub_command_get_slave_can_identifier_returns_expected_data(rx_pdu_ref, tx_pdu_ref, 13 | mode, 14 | xcp_tag, 15 | byte_order): 16 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=rx_pdu_ref, 17 | channel_tx_pdu_ref=tx_pdu_ref, 18 | byte_order=byte_order)) 19 | 20 | # CONNECT 21 | handle.lib.Xcp_CanIfRxIndication(rx_pdu_ref, handle.get_pdu_info((0xFF, 0x00))) 22 | handle.lib.Xcp_MainFunction() 23 | handle.lib.Xcp_CanIfTxConfirmation(rx_pdu_ref, handle.define('E_OK')) 24 | 25 | # TRANSPORT_LAYER_CMD 26 | handle.lib.Xcp_CanIfRxIndication(rx_pdu_ref, handle.get_pdu_info((0xF2, 0xFF, 0x58, 0x43, 0x50, mode))) 27 | handle.lib.Xcp_MainFunction() 28 | 29 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 30 | 31 | # check packet ID. 32 | assert raw_data[0] == 0xFF 33 | 34 | # check XCP tag. 35 | assert list(raw_data[1:4]) == xcp_tag 36 | 37 | # check CAN identifier for CMD/STIM. 38 | assert u32_from_array(bytearray(raw_data[4:8]), byte_order) == rx_pdu_ref 39 | 40 | 41 | @pytest.mark.parametrize('daq_list_number, daq_pdu_ref', [(0x0000, 0x0001), (0x0000, 0x0003)]) 42 | @pytest.mark.parametrize('byte_order', byte_orders[0:1]) 43 | def test_transport_layer_cmd_sub_command_get_daq_list_can_identifier_returns_expected_data(daq_list_number, 44 | daq_pdu_ref, 45 | byte_order): 46 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 47 | byte_order=byte_order, 48 | daqs=(dict(name='DAQ1', 49 | type='DAQ', 50 | max_odt=1, 51 | max_odt_entries=1, 52 | pdu_mapping=daq_pdu_ref, 53 | dtos=[dict(pid=0)]),))) 54 | # CONNECT 55 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 56 | handle.lib.Xcp_MainFunction() 57 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 58 | 59 | # TRANSPORT_LAYER_CMD 60 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info( 61 | (0xF2, 0xFE) + tuple(u16_to_array(daq_list_number, byte_order)))) 62 | handle.lib.Xcp_MainFunction() 63 | 64 | raw_data = tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:8]) 65 | 66 | # check packet ID. 67 | assert raw_data[0] == 0xFF 68 | 69 | # check CAN ID fixed. 70 | assert raw_data[1] == 0x01 71 | 72 | # check reserved bytes. 73 | assert raw_data[2] == 0x00 74 | assert raw_data[3] == 0x00 75 | 76 | # check DAQ CAN identifier of DTO dedicated to list number. 77 | print(u32_from_array(bytearray(raw_data[4:8]), byte_order)) 78 | print(daq_pdu_ref) 79 | assert u32_from_array(bytearray(raw_data[4:8]), byte_order) == daq_pdu_ref 80 | 81 | 82 | def test_transport_layer_cmd_sub_cmd_set_daq_list_can_identifier_returns_err_cmd_unknown(): 83 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001)) 84 | # CONNECT 85 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 86 | handle.lib.Xcp_MainFunction() 87 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 88 | 89 | # TRANSPORT_LAYER_CMD 90 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF2, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00))) 91 | handle.lib.Xcp_MainFunction() 92 | 93 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFE, 0x20) 94 | -------------------------------------------------------------------------------- /test/upload_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import pytest 5 | import pytest_cases 6 | 7 | from .parameter import * 8 | from .conftest import XcpTest 9 | 10 | 11 | @pytest_cases.fixture() 12 | @pytest.mark.parametrize('ag', address_granularities) 13 | @pytest.mark.parametrize('max_cto', max_ctos) 14 | def upload_payload_properties(ag, max_cto): 15 | element_size = element_size_from_address_granularity(ag) 16 | num_of_data_elements = floor((max_cto - 1) / element_size) 17 | alignment = max_cto - 1 - num_of_data_elements * element_size 18 | return ag, max_cto, alignment 19 | 20 | 21 | @pytest_cases.parametrize('ag, max_cto, alignment', [pytest_cases.fixture_ref(upload_payload_properties)]) 22 | @pytest.mark.parametrize('number_of_data_elements', range(1, 256)) 23 | @pytest.mark.parametrize('mta', mtas) 24 | @pytest.mark.parametrize('byte_order', byte_orders) 25 | def test_upload_uploads_elements_according_to_provided_mta_with_address_granularity_byte(ag, 26 | max_cto, 27 | alignment, 28 | number_of_data_elements, 29 | mta, 30 | byte_order): 31 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 32 | address_granularity=ag, 33 | byte_order=byte_order, 34 | slave_block_mode=True, 35 | max_cto=max_cto)) 36 | 37 | element_size = element_size_from_address_granularity(ag) 38 | expected_block = generate_random_block_content(number_of_data_elements, element_size, mta) 39 | expected_block_generator = (v for v in expected_block) 40 | actual_block = list() 41 | block_slices = get_block_slices_for_max_cto(expected_block, element_size, max_cto=max_cto) 42 | 43 | def read_slave_memory(p_address, _extension, p_buffer): 44 | expected_address, expected_value = next(expected_block_generator) 45 | expected_value_buffer = expected_value.to_bytes(element_size, 46 | dict(BIG_ENDIAN='big', LITTLE_ENDIAN='little')[byte_order], 47 | signed=False) 48 | for i, b in enumerate(expected_value_buffer): 49 | p_buffer[i] = int(b) 50 | actual_block.append((int(handle.ffi.cast('uint32_t', p_address)), expected_value)) 51 | 52 | handle.xcp_read_slave_memory_u8.side_effect = read_slave_memory 53 | handle.xcp_read_slave_memory_u16.side_effect = read_slave_memory 54 | handle.xcp_read_slave_memory_u32.side_effect = read_slave_memory 55 | 56 | # CONNECT 57 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 58 | handle.lib.Xcp_MainFunction() 59 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 60 | 61 | # SET_MTA 62 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF6, 63 | 0x00, 64 | 0x00, 65 | 0x00, 66 | *address_to_array(mta, 4, byte_order)))) 67 | handle.lib.Xcp_MainFunction() 68 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 69 | 70 | # UPLOAD 71 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF5, number_of_data_elements))) 72 | for i, s in enumerate(block_slices): 73 | handle.lib.Xcp_MainFunction() 74 | 75 | # check packet ID. 76 | assert handle.can_if_transmit.call_args[0][1].SduDataPtr[0] == 0xFF 77 | 78 | # check alignment byte(s) if any. 79 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[1:1 + alignment]) == tuple([0] * alignment) 80 | 81 | # check uploaded values. 82 | raw_payload = bytearray(handle.can_if_transmit.call_args[0][1].SduDataPtr[element_size:max_cto]) 83 | expected = [v[1] for v in s] 84 | actual = payload_to_array(raw_payload[:len(s) * element_size], len(s), element_size, byte_order) 85 | assert tuple(actual) == tuple(expected) 86 | 87 | # check trailing zeros (if any). 88 | expected = [0] * (max_cto - (len(s) * element_size) - alignment - 1) 89 | actual = handle.can_if_transmit.call_args[0][1].SduDataPtr[max_cto - len(expected):max_cto] 90 | assert tuple(actual) == tuple(expected) 91 | 92 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 93 | 94 | # Call Xcp_MainFunction one more time to make sure no more data are sent. 95 | handle.lib.Xcp_MainFunction() 96 | 97 | assert handle.can_if_transmit.call_count == len(block_slices) + 2 98 | assert actual_block == expected_block 99 | 100 | 101 | @pytest.mark.parametrize('ag,max_cto,data_elements', [ 102 | ('BYTE', 0x08, 0x08), 103 | ('WORD', 0x08, 0x04), 104 | ('DWORD', 0x08, 0x02)]) 105 | def test_upload_returns_err_out_of_range_if_slave_block_mode_is_disabled_and_payload_exceeds_range(ag, 106 | max_cto, 107 | data_elements): 108 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 109 | address_granularity=ag, 110 | slave_block_mode=False, 111 | max_cto=max_cto)) 112 | 113 | # CONNECT 114 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 115 | handle.lib.Xcp_MainFunction() 116 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 117 | 118 | # UPLOAD 119 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF5, data_elements))) 120 | handle.lib.Xcp_MainFunction() 121 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 122 | 123 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFE, 0x22) 124 | 125 | 126 | def test_upload_returns_err_out_of_range_if_slave_block_mode_is_enabled_and_payload_exceeds_range(): 127 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, 128 | slave_block_mode=True)) 129 | 130 | # CONNECT 131 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 132 | handle.lib.Xcp_MainFunction() 133 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 134 | 135 | # UPLOAD 136 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF5, 0x00))) 137 | handle.lib.Xcp_MainFunction() 138 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 139 | 140 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:2]) == (0xFE, 0x22) -------------------------------------------------------------------------------- /test/user_cmd_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # see http://www.sunshine2k.de/coding/javascript/crc/crc_js.html 5 | 6 | import ctypes 7 | 8 | import crcmod 9 | import zlib 10 | import crcmod.predefined 11 | import pytest 12 | 13 | from .parameter import * 14 | from .conftest import XcpTest 15 | 16 | from unittest.mock import ANY 17 | 18 | 19 | @pytest.mark.parametrize('sdu_length, sdu_data', [(0x03, (0xF1, 0x01, 0x02)), 20 | (0x04, (0xF1, 0x01, 0x02, 0x03)), 21 | (0x05, (0xF1, 0x01, 0x02, 0x03, 0x04)), 22 | (0x06, (0xF1, 0x01, 0x02, 0x03, 0x04, 0x05)), 23 | (0x07, (0xF1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06)), 24 | (0x08, (0xF1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07))]) 25 | def test_user_cmd_function_is_called_with_received_pdu_info(sdu_length, sdu_data): 26 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, user_cmd_function='Xcp_UserCmdFunction')) 27 | 28 | # CONNECT 29 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 30 | handle.lib.Xcp_MainFunction() 31 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 32 | 33 | # USER_CMD 34 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info(sdu_data)) 35 | handle.lib.Xcp_MainFunction() 36 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 37 | 38 | assert handle.xcp_user_cmd_function.call_args[0][0].SduLength == sdu_length 39 | assert tuple(handle.xcp_user_cmd_function.call_args[0][0].SduDataPtr[0:sdu_length]) == sdu_data 40 | 41 | 42 | @pytest.mark.parametrize('sdu_length, sdu_data', [(0x01, (0x01,)), 43 | (0x02, (0x01, 0x02)), 44 | (0x03, (0x01, 0x02, 0x03)), 45 | (0x04, (0x01, 0x02, 0x03, 0x04)), 46 | (0x05, (0x01, 0x02, 0x03, 0x04, 0x05)), 47 | (0x06, (0x01, 0x02, 0x03, 0x04, 0x05, 0x06)), 48 | (0x07, (0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07)), 49 | (0x08, (0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08)) 50 | ]) 51 | def test_user_cmd_function_returns_the_user_defined_buffer(sdu_length, sdu_data): 52 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, user_cmd_function='Xcp_UserCmdFunction')) 53 | 54 | def xcp_user_cmd_function(_p_cmd_pdu_info, p_res_err_pdu_info): 55 | p_res_err_pdu_info[0].SduLength = sdu_length 56 | for i in range(len(sdu_data)): 57 | p_res_err_pdu_info[0].SduDataPtr[i] = sdu_data[i] 58 | return handle.define('E_OK') 59 | 60 | handle.xcp_user_cmd_function.side_effect = xcp_user_cmd_function 61 | 62 | # CONNECT 63 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 64 | handle.lib.Xcp_MainFunction() 65 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 66 | 67 | # USER_CMD 68 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00))) 69 | handle.lib.Xcp_MainFunction() 70 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 71 | 72 | assert handle.can_if_transmit.call_args[0][1].SduLength == sdu_length 73 | assert tuple(handle.can_if_transmit.call_args[0][1].SduDataPtr[0:sdu_length]) == sdu_data 74 | 75 | 76 | def test_user_cmd_function_calls_det_with_err_invalid_pointer_if_no_user_cmd_function_is_defined(): 77 | handle = XcpTest(DefaultConfig(channel_rx_pdu_ref=0x0001, user_cmd_function=None)) 78 | 79 | def xcp_user_cmd_function(_p_cmd_pdu_info, _p_res_err_pdu_info): 80 | return 0 81 | 82 | handle.xcp_user_cmd_function.side_effect = xcp_user_cmd_function 83 | 84 | # CONNECT 85 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xFF, 0x00))) 86 | handle.lib.Xcp_MainFunction() 87 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 88 | 89 | # USER_CMD 90 | handle.lib.Xcp_CanIfRxIndication(0x0001, handle.get_pdu_info((0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00))) 91 | handle.lib.Xcp_MainFunction() 92 | handle.lib.Xcp_CanIfTxConfirmation(0x0001, handle.define('E_OK')) 93 | 94 | handle.det_report_error.assert_called_once_with(ANY, 95 | ANY, 96 | handle.define('XCP_CAN_IF_RX_INDICATION_API_ID'), 97 | handle.define('XCP_E_PARAM_POINTER')) 98 | --------------------------------------------------------------------------------