From b778690187926049f0fb462ef956642a7f95fc2a Mon Sep 17 00:00:00 2001 From: Geoff Phillips Date: Mon, 6 Mar 2023 08:50:19 +0100 Subject: [PATCH] Release v1.0.4 --- .flake8 | 8 + .git-blame-ignore-revs | 2 - .github/template/fwe-build/action.yml | 17 +- .github/workflows/ci.yml | 15 +- .gitignore | 2 + .pre-commit-config.yaml | 33 +- CHANGELOG.md | 38 +- CMakeLists.txt | 2 +- README.md | 2 +- cmake/compiler_gcc.cmake | 1 + configuration/static-config.json | 3 +- docs/AWS-IoTFleetWiseOffboarding.md | 24 +- .../edge-agent-dev-guide-renesas-rcar-s4.md | 18 +- docs/dev-guide/edge-agent-dev-guide.md | 28 +- docs/iwave-g26-tutorial/iwave-g26-tutorial.md | 8 +- docs/rpi-tutorial/raspberry-pi-tutorial.md | 8 +- .../staticConfiguration.json | 4 - src/datamanagement/custom/CMakeLists.txt | 7 +- src/datamanagement/custom/README.md | 5 +- .../custom/example/iwavegps/README.md | 6 +- .../example/iwavegps/include/IWaveGpsSource.h | 7 +- .../example/iwavegps/src/IWaveGpsSource.cpp | 42 +- .../iwavegps/test/IWaveGpsSourceTest.cpp | 18 +- .../example/iwavegps/test/valgrind.supp | 9 + .../custom/generic/include/CustomDataSource.h | 2 - .../custom/generic/src/CustomDataSource.cpp | 28 +- .../datacollection/CMakeLists.txt | 8 - .../datacollection/include/CollectionScheme.h | 109 --- .../include/CollectionSchemeIngestion.h | 12 +- .../include/CollectionSchemeIngestionList.h | 6 - .../include/CollectionSchemeJSONParser.h | 57 -- .../include/DataCollectionJSONWriter.h | 93 --- .../include/DataCollectionSender.h | 12 +- .../datacollection/src/CollectionScheme.cpp | 221 ----- .../src/CollectionSchemeIngestion.cpp | 148 ++-- .../src/CollectionSchemeIngestionList.cpp | 25 +- .../src/CollectionSchemeJSONParser.cpp | 151 ---- .../src/DataCollectionJSONWriter.cpp | 164 ---- .../src/DataCollectionProtoWriter.cpp | 45 +- .../src/DataCollectionSender.cpp | 69 +- .../test/CollectionSchemeJSONParserTest.cpp | 59 -- .../test/DataCollectionJSONWriterTest.cpp | 171 ---- .../test/DataCollectionProtoWriterTest.cpp | 5 +- .../test/DataCollectionSenderTest.cpp | 14 +- .../datacollection/test/valgrind.supp | 9 + .../datadecoding/CMakeLists.txt | 1 - .../datadecoding/include/CANDecoder.h | 2 - .../include/DecoderManifestIngestion.h | 18 +- .../datadecoding/include/IDecoderDictionary.h | 27 - .../datadecoding/include/IDecoderManifest.h | 32 +- .../datadecoding/include/OBDDataDecoder.h | 24 +- .../datadecoding/src/CANDecoder.cpp | 87 +- .../src/DecoderManifestIngestion.cpp | 33 +- .../datadecoding/src/OBDDataDecoder.cpp | 188 +++-- .../datadecoding/test/CANDecoderTest.cpp | 99 +++ .../datadecoding/test/OBDDataDecoderTest.cpp | 661 ++++++++++++--- .../datadecoding/test/valgrind.supp | 9 + .../datainspection/include/CANDataConsumer.h | 2 - .../include/CollectionInspectionEngine.h | 320 ++++++- .../CollectionInspectionWorkerThread.h | 4 +- .../include/DataOverDDSModule.h | 2 - .../include/GeohashFunctionNode.h | 6 - .../datainspection/include/OBDOverCANECU.h | 2 - .../datainspection/include/OBDOverCANModule.h | 2 - .../include/VehicleDataSourceBinder.h | 2 - .../src/CollectionInspectionEngine.cpp | 778 +++++++++++++----- .../src/CollectionInspectionWorkerThread.cpp | 119 ++- .../src/dds/DataOverDDSModule.cpp | 44 +- .../datainspection/src/diag/OBDOverCANECU.cpp | 105 ++- .../src/diag/OBDOverCANModule.cpp | 100 +-- .../src/location/GeohashFunctionNode.cpp | 21 +- .../src/vehicledatasource/CANDataConsumer.cpp | 92 ++- .../VehicleDataSourceBinder.cpp | 84 +- .../test/CollectionInspectionEngineTest.cpp | 418 ++++++---- .../CollectionInspectionWorkerThreadTest.cpp | 119 +-- .../test/DataOverDDSModuleTest.cpp | 33 +- .../test/OBDOverCANModuleTest.cpp | 200 +++-- .../test/VehicleDataSourceBinderTest.cpp | 265 +++--- .../datainspection/test/valgrind.supp | 9 + .../include/CollectionSchemeManager.h | 19 +- .../datamanager/include/Schema.h | 38 +- .../datamanager/src/CheckinAndPersistency.cpp | 33 +- .../src/CollectionSchemeManager.cpp | 125 ++- .../src/DecoderDictionaryExtractor.cpp | 13 +- .../src/InspectionMatrixExtractor.cpp | 5 +- src/datamanagement/datamanager/src/Schema.cpp | 21 +- .../test/CollectionSchemeManagerTest.cpp | 15 +- .../datamanager/test/SchemaTest.cpp | 13 +- .../include/CollectionSchemeManagerMock.h | 1 - .../datamanager/test/valgrind.supp | 9 + .../types/include/CANDataTypes.h | 43 +- .../include/CollectionInspectionAPITypes.h | 209 ++++- src/datamanagement/types/include/Geohash.h | 2 + .../types/include/OBDDataTypes.h | 33 +- .../types/include/SignalTypes.h | 26 + src/datamanagement/types/test/valgrind.supp | 8 + src/executionmanagement/CMakeLists.txt | 2 - .../include/IoTFleetWiseEngine.h | 22 - .../src/IoTFleetWiseEngine.cpp | 263 +++--- src/executionmanagement/src/main.cpp | 4 +- .../test/IoTFleetWiseEngineTest.cpp | 14 +- src/executionmanagement/test/valgrind.supp | 1 - .../api/include/ISender.h | 2 +- .../aws/bootstrap/src/AwsBootstrap.cpp | 9 +- .../aws/bootstrap/src/AwsSDKMemoryManager.cpp | 1 + .../aws/iotcpp/include/AwsIotChannel.h | 12 +- .../iotcpp/include/AwsIotConnectivityModule.h | 5 +- .../aws/iotcpp/include/PayloadManager.h | 10 +- .../aws/iotcpp/include/RemoteProfiler.h | 9 +- .../aws/iotcpp/include/RetryThread.h | 3 - .../aws/iotcpp/src/AwsIotChannel.cpp | 53 +- .../iotcpp/src/AwsIotConnectivityModule.cpp | 60 +- .../aws/iotcpp/src/PayloadManager.cpp | 55 +- .../aws/iotcpp/src/RemoteProfiler.cpp | 35 +- .../aws/iotcpp/src/RetryThread.cpp | 16 +- .../test/src/AwsIotConnectivityModuleTest.cpp | 21 +- .../iotcpp/test/src/RemoteProfilerTest.cpp | 8 +- .../aws/iotcpp/test/valgrind.supp | 9 + .../logmanagement/include/ConsoleLogger.h | 20 +- .../linux/logmanagement/include/ILogger.h | 8 +- .../logmanagement/include/LoggingModule.h | 136 ++- .../linux/logmanagement/include/TraceModule.h | 14 +- .../linux/logmanagement/src/ConsoleLogger.cpp | 29 +- .../linux/logmanagement/src/LoggingModule.cpp | 39 +- .../linux/logmanagement/src/TraceModule.cpp | 56 +- .../include/CacheAndPersist.h | 2 - .../src/CacheAndPersist.cpp | 27 +- .../resourcemanagement/include/CPUUsageInfo.h | 2 + .../include/MemoryUsageInfo.h | 1 + src/platform/linux/test/valgrind.supp | 8 + .../threadingmanagement/include/Signal.h | 2 + .../linux/threadingmanagement/src/Thread.cpp | 4 - .../linux/timemanagement/src/ClockHandler.cpp | 4 +- src/testingsupport/CMakeLists.txt | 15 +- src/testingsupport/include/Testing.h | 144 ++++ src/testingsupport/include/WaitUntil.h | 121 +++ src/testingsupport/test/WaitUntilTest.cpp | 79 ++ src/testingsupport/test/valgrind.supp | 8 + .../include/businterfaces/CANDataSource.h | 4 +- .../businterfaces/ISOTPOverCANReceiver.h | 4 +- .../businterfaces/ISOTPOverCANSender.h | 6 +- .../ISOTPOverCANSenderReceiver.h | 2 - .../datatypes/VehicleDataSourceTypes.h | 2 +- .../include/dds/CameraDataPublisher.h | 2 - .../include/dds/CameraDataSubscriber.h | 2 - src/vehiclenetwork/src/CANDataSource.cpp | 61 +- .../src/CameraDataPublisher.cpp | 17 +- .../src/CameraDataSubscriber.cpp | 21 +- .../src/ISOTPOverCANReceiver.cpp | 22 +- src/vehiclenetwork/src/ISOTPOverCANSender.cpp | 23 +- .../src/ISOTPOverCANSenderReceiver.cpp | 47 +- src/vehiclenetwork/test/CANDataSourceTest.cpp | 74 +- .../test/CameraDataPublisherTest.cpp | 10 +- .../test/CameraDataSubscriberTest.cpp | 12 +- src/vehiclenetwork/test/valgrind.supp | 9 + tools/arm64.list | 14 +- tools/armhf.list | 14 +- tools/build-dist.sh | 10 +- tools/build-fwe-cross-arm64.sh | 2 + tools/build-fwe-cross-armhf.sh | 2 + tools/build-fwe-native.sh | 3 + tools/cansim/canigen.py | 222 ++--- tools/cansim/cansim.py | 4 +- tools/cansim/run-cansim.sh | 2 +- tools/cfn-templates/fwdemo.yml | 36 +- tools/cfn-templates/fwdev.yml | 36 +- tools/cloud/README.md | 10 +- tools/cloud/clean-up.sh | 5 + tools/cloud/dbc-to-json.py | 10 +- tools/cloud/dbc-to-nodes.py | 7 +- tools/cloud/demo.sh | 14 +- tools/cloud/install-deps.sh | 9 +- tools/cloud/timestream-to-html.py | 8 +- tools/cloud/timestream-to-mdf.py | 8 +- tools/code_check/compile_db_remove_test.py | 4 +- tools/configure-fwe.sh | 14 + tools/container/Dockerfile | 2 +- tools/deploy/fwe@.service | 2 +- tools/deploy/run-fwe.sh | 14 + tools/install-cansim.sh | 10 +- tools/install-deps-cross-arm64.sh | 158 ++-- tools/install-deps-cross-armhf.sh | 156 ++-- tools/install-deps-native.sh | 201 ++--- tools/install-deps-versions.sh | 14 + tools/install-fwe.sh | 1 + tools/install-socketcan.sh | 9 +- tools/provision.sh | 41 + tools/yocto/README.md | 2 +- .../build_s32g274ardb2ubuntu/conf/local.conf | 2 +- 189 files changed, 5129 insertions(+), 3804 deletions(-) create mode 100644 .flake8 delete mode 100644 .git-blame-ignore-revs delete mode 100644 src/datamanagement/datacollection/include/CollectionScheme.h delete mode 100644 src/datamanagement/datacollection/include/CollectionSchemeJSONParser.h delete mode 100644 src/datamanagement/datacollection/include/DataCollectionJSONWriter.h delete mode 100644 src/datamanagement/datacollection/src/CollectionScheme.cpp delete mode 100644 src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp delete mode 100644 src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp delete mode 100644 src/datamanagement/datacollection/test/CollectionSchemeJSONParserTest.cpp delete mode 100644 src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp create mode 100644 src/datamanagement/types/test/valgrind.supp create mode 100644 src/platform/linux/test/valgrind.supp create mode 100644 src/testingsupport/include/WaitUntil.h create mode 100644 src/testingsupport/test/WaitUntilTest.cpp create mode 100644 src/testingsupport/test/valgrind.supp create mode 100755 tools/deploy/run-fwe.sh create mode 100755 tools/install-deps-versions.sh diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..c82f4272 --- /dev/null +++ b/.flake8 @@ -0,0 +1,8 @@ +[flake8] +max-line-length = 100 +ignore = + E203, # not pep8, black adds whitespace before ':' + W503, # not pep8, black adds line break before binary operator + PT004, + PT005, +pytest-fixture-no-parentheses = true diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 0a903627..00000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,2 +0,0 @@ -# Format most files with black and prettier -5048591323cd5aac93af69d0d2b4e359be33b9a3 diff --git a/.github/template/fwe-build/action.yml b/.github/template/fwe-build/action.yml index 83f6fec7..ea071eb3 100644 --- a/.github/template/fwe-build/action.yml +++ b/.github/template/fwe-build/action.yml @@ -8,6 +8,8 @@ inputs: required: true upload-arch: required: true + cache-paths: + required: true runs: using: "composite" @@ -16,14 +18,23 @@ runs: id: cache-deps uses: actions/cache@v3 with: - path: deps-${{ inputs.build-arch }} - key: deps-${{ inputs.build-arch }} + path: cache + key: deps-${{ inputs.build-arch }}-${{ hashFiles('tools/install-deps-*.sh') }} - name: install-deps shell: bash run: | + if [ -d cache ]; then + sudo cp -r cache/* /usr/local + fi sudo ./tools/install-deps-${{ inputs.build-arch }}.sh - sudo chown -R $(id -u):$(id -g) deps-${{ inputs.build-arch }} + if [ ! -d cache ]; then + mkdir cache + IFS=":" + for P in ${{ inputs.cache-paths }}; do + cp -r ${P} cache + done + fi - name: build shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a963e0b0..cdb5b689 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ env: jobs: linting: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 @@ -29,34 +29,37 @@ jobs: - run: pip install pre-commit - run: unbuffer pre-commit run --all-files build-amd64: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: "./.github/template/fwe-build" with: build-arch: "native" upload-arch: "amd64" + cache-paths: /usr/local/x86_64-linux-gnu build-arm64: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: "./.github/template/fwe-build" with: build-arch: "cross-arm64" upload-arch: "arm64" + cache-paths: /usr/local/aarch64-linux-gnu:/usr/local/x86_64-linux-gnu build-armhf: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 - uses: "./.github/template/fwe-build" with: build-arch: "cross-armhf" upload-arch: "armhf" + cache-paths: /usr/local/arm-linux-gnueabihf:/usr/local/x86_64-linux-gnu build-docker: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 needs: - build-amd64 - build-arm64 @@ -73,7 +76,7 @@ jobs: find linux -name aws-iot-fleetwise-edge -exec chmod +x {} \; - uses: docker/setup-qemu-action@v2 - uses: docker/setup-buildx-action@v2 - - uses: aws-actions/configure-aws-credentials@v1 + - uses: aws-actions/configure-aws-credentials@v1-node16 if: github.ref_type == 'tag' with: role-to-assume: ${{ secrets.PUBLIC_ECR_PUSH_ROLE }} diff --git a/.gitignore b/.gitignore index f8b90daf..0aad0498 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ __pycache__/ build*/ compile_commands.json +install*/ +log/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55e1ef0d..0c36e239 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,9 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks default_language_version: - node: "16.19.0" # More recent versions are built against GLIBC_2.28. We can upgrade once we move to Ubuntu 20.04 + # More recent versions are built against GLIBC_2.28+. We want to keep it compatible with + # Amazon Linux 2 (GLIBC_2.26) + node: "16.19.0" repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 @@ -28,6 +30,23 @@ repos: rev: v10.0.1 hooks: - id: clang-format + - repo: https://github.com/PyCQA/autoflake + rev: v2.0.0 + hooks: + - id: autoflake + name: autoflake + args: + [ + "--in-place", + "--remove-unused-variables", + "--remove-all-unused-imports", + "--expand-star-imports", + ] + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.1 + hooks: + - id: pyupgrade + args: [--py37-plus] - repo: https://github.com/pycqa/isort rev: 5.12.0 hooks: @@ -42,6 +61,18 @@ repos: hooks: - id: blacken-docs additional_dependencies: [black==22.12.0] + - repo: https://github.com/PyCQA/flake8 + rev: 5.0.4 # Some plugins still require <6 + hooks: + - id: flake8 + additional_dependencies: + - flake8-implicit-str-concat==0.3.0 + - pep8-naming==0.13.3 + - flake8-bugbear==22.12.6 + - flake8-broken-line==0.6.0 + - flake8-comprehensions==3.10.1 + - flake8-builtins==2.1.0 + - flake8-pytest-style==1.6.0 - repo: https://github.com/pre-commit/mirrors-prettier rev: v2.7.1 hooks: diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c22daf..0ba36fe6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,32 @@ # Change Log -## future release (TBD) +## v1.0.4 (2023-03-02) Bugfixes: - Fix OBD timers not being reset. If the decoder manifest is empty or DTCs are not collected the OBD PID or DTC timers were not reset, causing a 100% CPU and log spam with the following message `[WARN ] [OBDOverCANModule::doWork]: [Request time overdue by -X ms]`. +- Support OBD2 PIDs ECU response in different order than requested. Also accept ECU response if not + all requested PIDs are answered. +- Unsubscribe and disconnect from MQTT on shutdown: previously a message arriving during shutdown + could cause a segmentation fault. -## v1.0.3 (Jan 9, 2023) +Improvements: + +- Update to Ubuntu 20.04 for the development environment. +- Add flake8 checking of Python scripts. +- Improve GitHub CI caching. +- Improve MISRA C++ 2008, and AUTOSAR C++ compliance. +- Improve logging: macros used to automatically add file, line number and function. +- Improve unit test stability, by replacing sleep statements with 'wait until' loops. +- Removed redundant JSON output code from `DataCollection*` files. + +Work in Progress: + +- Support for signal datatypes other than `double`, including `uint64_t` and `int64_t`. + +## v1.0.3 (2023-01-09) Features: @@ -36,7 +54,7 @@ Improvements: - Improve quick start guide and demo script. - Clarify the meaning of the `startBit`. -## v1.0.2 (Nov 28, 2022) +## v1.0.2 (2022-11-28) Bugfixes: @@ -58,7 +76,7 @@ Improvements: script. - Improve CERT-CPP compliance. -## v1.0.1 (Nov 3, 2022) +## v1.0.1 (2022-11-03) License Update: @@ -93,7 +111,7 @@ Improvements: - Added an extra attribute, so that users can search vehicle in the FleetWise console - Added two extra steps for quick demo: suspending campaigns and resuming campaigns -## v1.0.0 (Sept 27, 2022) +## v1.0.0 (2022-09-27) Bugfixes: @@ -113,7 +131,7 @@ Improvements: - Update FleetWise CLI Model to GA release version. - Update Customer Demo to remove service-linked role creation for FleetWise Account Registration. -## v0.1.4 (Aug 29, 2022) +## v0.1.4 (2022-08-29) Bugfixes: @@ -130,7 +148,7 @@ Improvements: - OBDDataDecoder will only decode the payload with the PIDs that previously requested. - Improve OBD logging to log CAN ISOTP raw bytes for better debugging -## v0.1.3 (Aug 3, 2022) +## v0.1.3 (2022-08-03) Customer Demo: @@ -162,7 +180,7 @@ Improvements: - Refactored Vehicle Network module to improve extensibility for other network types - Improvement to cansim to better handle ISO-TP error. -## v0.1.2 (February 24, 2022) +## v0.1.2 (2022-02-24) Features: @@ -185,7 +203,7 @@ Bugfixes/Improvements: - CloudFormation template `fwdemo.yml` updated to pull source from GitHub instead of S3. - Developer guide converted to Markdown. -## v0.1.1 (January 25, 2022) +## v0.1.1 (2022-01-25) Features: @@ -213,7 +231,7 @@ Bugfixes/Improvements: becoming unavailable after system upgrade of EC2 instance. - Edge agent now compiled and run on the same EC2 instance, rather than using CodePipeline. -## v0.1.0 (November 29, 2021) +## v0.1.0 (2021-11-29) Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 54723f88..a7384b0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10.2) -project(iotfleetwise VERSION 1.0.3) +project(iotfleetwise VERSION 1.0.4) # AWS IoT FleetWise Edge uses C++14 for compatibility reasons with # Automotive middlewares ( Adaptive AUTOSAR, ROS2) diff --git a/README.md b/README.md index 32baeae3..ae516a86 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ the following details: - **AvailabilityZone**: us-east-1 - **Architecture**: x86_64 - **CpuOptions**: {'CoreCount': 18, 'ThreadsPerCore': 2} -- **AMI name**: ubuntu-bionic-18.04-amd64-server-20210224 +- **AMI name**: ubuntu-focal-20.04-amd64-server-20230112 ## AWS IoT FleetWise Client-Server Communication diff --git a/cmake/compiler_gcc.cmake b/cmake/compiler_gcc.cmake index 8758ba6d..dd2c998c 100644 --- a/cmake/compiler_gcc.cmake +++ b/cmake/compiler_gcc.cmake @@ -7,6 +7,7 @@ link_libraries( if(FWE_STATIC_LINK) set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + set(Boost_USE_STATIC_LIBS ON) link_libraries("-static-libstdc++" "-static-libgcc") endif() diff --git a/configuration/static-config.json b/configuration/static-config.json index 9d9ee464..4bd94d4b 100644 --- a/configuration/static-config.json +++ b/configuration/static-config.json @@ -42,8 +42,7 @@ "internalParameters": { "readyToPublishDataBufferSize": 10000, "systemWideLogLevel": "Trace", - "dataReductionProbabilityDisabled": false, - "useJsonBasedCollection": false + "dataReductionProbabilityDisabled": false }, "publishToCloudParameters": { "maxPublishMessageCount": 1000, diff --git a/docs/AWS-IoTFleetWiseOffboarding.md b/docs/AWS-IoTFleetWiseOffboarding.md index 64c0bd21..c6eb1212 100644 --- a/docs/AWS-IoTFleetWiseOffboarding.md +++ b/docs/AWS-IoTFleetWiseOffboarding.md @@ -5,24 +5,24 @@ following commands: 1. Stop AWS IoT FleetWise -``` -sudo systemctl stop fwe@0 -``` + ```bash + sudo systemctl stop fwe@0 + ``` 2. Disable AWS IoT FleetWise -``` -sudo systemctl disable fwe@0 -``` + ```bash + sudo systemctl disable fwe@0 + ``` 3. Delete all persistent data files -``` -sudo rm -f /var/aws-iot-fleetwise/* -``` + ```bash + sudo rm -f /var/aws-iot-fleetwise/* + ``` 4. Delete AWS IoT FleetWise configuration files -``` -sudo rm -f /etc/aws-iot-fleetwise/* -``` + ```bash + sudo rm -f /etc/aws-iot-fleetwise/* + ``` diff --git a/docs/dev-guide/edge-agent-dev-guide-renesas-rcar-s4.md b/docs/dev-guide/edge-agent-dev-guide-renesas-rcar-s4.md index 42f99e29..6fd3c41f 100644 --- a/docs/dev-guide/edge-agent-dev-guide-renesas-rcar-s4.md +++ b/docs/dev-guide/edge-agent-dev-guide-renesas-rcar-s4.md @@ -24,9 +24,6 @@ This section describes how to deploy AWS IoT FleetWise Edge Agent onto an Renesa ```bash cd ~/aws-iot-fleetwise-edge - CODENAME=$(grep UBUNTU_CODENAME /etc/os-release | cut -d'=' -f2 ) - # update the ubuntu version to your host - sed -i "s/bionic/${CODENAME}/g" ./tools/arm64.list sudo -H ./tools/install-deps-cross-arm64.sh \ && rm -rf build \ && ./tools/build-fwe-cross-arm64.sh @@ -78,9 +75,9 @@ on the Ubuntu variant of the Renesas Linux BSP version 5.10.41. 1. Use screen command on your develop machine terminal to veiw serial output.(Modify the device path `/dev/xxxxx` to the correct path) -``` -screen /dev/xxxxx 1843200 -``` + ```bash + screen /dev/xxxxx 1843200 + ``` 1. Power on S4 Spider board. You can see the count down during U-Boot. Hit enter key to stop U-Boot. 1. Enter following settings to flash the micro SD-card data to board @@ -157,12 +154,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ && sudo mkdir -p /etc/aws-iot-fleetwise \ && sudo cp config/* /etc/aws-iot-fleetwise - cp ./tools/install-socketcan.sh ./tools/setup-vcan.sh - sed -i '17,68d' ./tools/setup-vcan.sh - ./tools/setup-vcan.sh - sudo ./tools/install-fwe.sh - sed -i 's/python3.7/python3/g' ./tools/cansim/run-cansim.sh - sed -i 's/python3.7/python3/g' ./tools/install-cansim.sh + sudo ./tools/install-socketcan.sh sed -i -e 's/^After/# After/' -e 's/^Wants/#Wants/' ./tools/cansim/cansim@.service sudo -H ./tools/install-cansim.sh ``` @@ -181,8 +173,6 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ ```bash cd ~/aws-iot-fleetwise-edge/tools/cloud - sed -i 's/python3.7/python3/g' ./install-deps.sh sudo -H ./install-deps.sh - sed -i 's/python3.7/python3/g' ./demo.sh ./demo.sh --vehicle-name fwdemo-rcars4 --campaign-file campaign-obd-heartbeat.json ``` diff --git a/docs/dev-guide/edge-agent-dev-guide.md b/docs/dev-guide/edge-agent-dev-guide.md index 4691103c..8a9e2396 100644 --- a/docs/dev-guide/edge-agent-dev-guide.md +++ b/docs/dev-guide/edge-agent-dev-guide.md @@ -221,7 +221,7 @@ machine. ### Launch your development machine -An Ubuntu 18.04 development machine with 200GB free disk space will be required. A local Intel +An Ubuntu 20.04 development machine with 200GB free disk space will be required. A local Intel x86_64 (amd64) machine can be used, however it is recommended to use the following instructions to launch an AWS EC2 Graviton (arm64) instance. Pricing for EC2 can be found, [here](https://aws.amazon.com/ec2/pricing/on-demand/). @@ -267,11 +267,10 @@ launch an AWS EC2 Graviton (arm64) instance. Pricing for EC2 can be found, `build-essential dkms can-utils git linux-modules-extra-aws`. Additionally it installs the following: `can-isotp`. It also installs a systemd service called `setup-socketcan` that brings up the virtual SocketCAN interface `vcan0` at startup. - 1. Install the following Ubuntu packages: `python3.7 python3-setuptools curl`. It then installs - Python PIP for Python 3.7 and the following PIP packages: - `wrapt cantools prompt_toolkit python-can can-isotp matplotlib`. It also installs a systemd - service called `cansim` that periodically transmits data on the virtual SocketCAN bus `vcan0` - to simulate vehicle data. + 1. Install the following Ubuntu packages: `python3 python3-pip`. It then installs the following + PIP packages: `wrapt cantools prompt_toolkit python-can can-isotp matplotlib`. It also + installs a systemd service called `cansim` that periodically transmits data on the virtual + SocketCAN bus `vcan0` to simulate vehicle data. ```bash sudo -H ./tools/install-deps-native.sh \ @@ -335,9 +334,8 @@ collect data from it. 1. Run the following _on the development machine_ to install the dependencies of the AWS IoT FleetWise Cloud demo script: - 1. Following command installs the following Ubuntu packages: `python3.7 python3-setuptools curl`. - It then installs Python PIP for Python 3.7 and the following PIP packages: - `wrapt plotly pandas cantools` + 1. Following command installs the following Ubuntu packages: `python3 python3-pip`. It then + installs the following PIP packages: `wrapt plotly pandas cantools` ```bash cd ~/aws-iot-fleetwise-edge/tools/cloud \ @@ -1579,12 +1577,14 @@ Customers can set the System level logging severity externally via the software described below in the configuration section. Each log entry includes the following attributes: ``` -[Thread: ID] [Time] [Level] [function]: [Message] +[Thread: ID] [Time] [Level] [Filename:LineNumber] [Function()]: [Message] ``` - Thread — the thread ID triggering the log entry. - Time — the timestamp in milliseconds since Epoch. - Level — the severity of the log entry. +- Filename - the file name that invoked the log entry. +- LineNumber - the line in the file that invoked the log entry. - Function — the function name that invoked the log entry. - Message — the actual log message. @@ -1692,11 +1692,9 @@ The kernel module for ISO-TP (can-isotp) would need to be installed in addition The device software code base includes modules that are still in development an are disabled by default. These modules are not intended for use in a production environment. This includes the Data Distribution Service Support (DDS) that is used to communicate with any sensor node connected over a -DDS bus, a Remote Profiler module that helps sending traces from the device to AWS Cloud Watch, and -a JSON data serialization module that’s intended for dumping the collected data in a JSON format -locally (mainly for local debugging needs). The device software has been checked for any memory -leaks and runtime errors such as type overflows using Valgrind. No issues have been detected during -the load tests. +DDS bus and a Remote Profiler module that helps sending traces from the device to AWS Cloud Watch. +The device software has been checked for any memory leaks and runtime errors such as type overflows +using Valgrind. No issues have been detected during the load tests. ## Getting Help diff --git a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md index dbed6f6e..3f064617 100644 --- a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md +++ b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md @@ -283,7 +283,7 @@ Setting up the 4G LTE modem inside the G26 TCU is dependent on your SIM card ser ## Step 2: Launch your development machine -These steps require an Ubuntu 18.04 development machine with 10 GB free disk space. If necessary, +These steps require an Ubuntu 20.04 development machine with 10 GB free disk space. If necessary, you can use a local Intel x86_64 (amd64) machine. We recommended using the following instructions to launch an AWS EC2 Graviton (arm64) instance. For more information about Amazon EC2 pricing, see [Amazon EC2 On-Demand Pricing](https://aws.amazon.com/ec2/pricing/on-demand/). @@ -412,7 +412,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ AWS IoT Core: ``` - [INFO ] [AwsIotConnectivityModule::connect] [Connection completed successfully] + [INFO ] [AwsIotConnectivityModule.cpp:161] [connect()] [Connection completed successfully] ``` ## Step 6: Connect the TCU to the vehicle @@ -435,8 +435,8 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ 1. On the development machine, install the AWS IoT FleetWise cloud demo script dependencies by running the following commands. The script installs the following Ubuntu packages: - `python3.7 python3-setuptools curl`, and then installs Python PIP for Python 3.7 and the - following PIP packages: `wrapt plotly pandas cantools`. + `python3 python3-pip`, and then installs the following PIP packages: + `wrapt plotly pandas cantools`. ```bash cd ~/aws-iot-fleetwise-edge/tools/cloud \ diff --git a/docs/rpi-tutorial/raspberry-pi-tutorial.md b/docs/rpi-tutorial/raspberry-pi-tutorial.md index 5679c170..983174ff 100644 --- a/docs/rpi-tutorial/raspberry-pi-tutorial.md +++ b/docs/rpi-tutorial/raspberry-pi-tutorial.md @@ -76,7 +76,7 @@ Amazon. ## Step 2: Launch your development machine -These steps require an Ubuntu 18.04 development machine with 10 GB free disk space. If necessary, +These steps require an Ubuntu 20.04 development machine with 10 GB free disk space. If necessary, you can use a local Intel x86_64 (amd64) machine. We recommended using the following instructions to launch an AWS EC2 Graviton (arm64) instance. For more information about Amazon EC2 pricing, see [Amazon EC2 On-Demand Pricing](https://aws.amazon.com/ec2/pricing/on-demand/). @@ -219,7 +219,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ ``` - Look for this message to verify: ``` - [INFO ] [AwsIotConnectivityModule::connect] [Connection completed successfully] + [INFO ] [AwsIotConnectivityModule.cpp:161] [connect()] [Connection completed successfully] ``` - Use the [troubleshooting information and solutions](https://docs.aws.amazon.com/iot-fleetwise/latest/developerguide/troubleshooting.html) @@ -230,8 +230,8 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ 1. On the development machine, install the AWS IoT FleetWise cloud demo script dependencies by running the following commands. The script installs the following Ubuntu packages: - `python3.7 python3-setuptools curl`, and then installs Python PIP for Python 3.7 and the - following PIP packages: `wrapt plotly pandas cantools`. + `python3 python3-pip`, and then installs the following PIP packages: + `wrapt plotly pandas cantools`. ```bash cd ~/aws-iot-fleetwise-edge/tools/cloud \ diff --git a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json index 6fb017a8..2bb48715 100644 --- a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json +++ b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json @@ -205,10 +205,6 @@ "metricsCyclicPrintIntervalMs": { "type": "string", "description": "Sets the interval in milliseconds how often the application metrics should be printed to stdout. Default 0 means never" - }, - "useJsonBasedCollection": { - "type": "boolean", - "description": "Enables debug JSON output of the collected data" } }, "required": [ diff --git a/src/datamanagement/custom/CMakeLists.txt b/src/datamanagement/custom/CMakeLists.txt index 86284395..840dcb89 100644 --- a/src/datamanagement/custom/CMakeLists.txt +++ b/src/datamanagement/custom/CMakeLists.txt @@ -36,11 +36,8 @@ install(TARGETS ${libraryTargetName} DESTINATION lib) install( FILES - include/ICollectionSchemeManager.h - include/CollectionSchemeManagementListener.h - include/CollectionSchemeManager.h - include/Schema.h - include/SchemaListener.h + generic/include/CustomDataSource.h + example/iwavegps/include/IWaveGpsSource.h DESTINATION include ) diff --git a/src/datamanagement/custom/README.md b/src/datamanagement/custom/README.md index 17ef1677..a8786ca0 100644 --- a/src/datamanagement/custom/README.md +++ b/src/datamanagement/custom/README.md @@ -87,8 +87,7 @@ if(mIWaveGpsSource->init( if ( !mCollectionSchemeManagerPtr->subscribeListener( static_cast( mIWaveGpsSource.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - " Failed to register the IWaveGps to the CollectionScheme Manager" ); + FWE_LOG_ERROR(" Failed to register the IWaveGps to the CollectionScheme Manager"); return false; } mIWaveGpsSource->start(); @@ -134,5 +133,5 @@ configured using `setFilter(canChannel,canRawFrameId);`. If that is the case you following line in the log ``` -[Thread : 563] [2022-10-27 02:39:02 PM] [TRACE] [CustomDataSource::matchDictionaryToFilter]: [Dictionary with relevant information for CustomDataSource so waking up] +[TRACE] [CustomDataSource.cpp:159] [matchDictionaryToFilter()]: [Dictionary with relevant information for CustomDataSource so waking up] ``` diff --git a/src/datamanagement/custom/example/iwavegps/README.md b/src/datamanagement/custom/example/iwavegps/README.md index e3cef90c..3d20f841 100644 --- a/src/datamanagement/custom/example/iwavegps/README.md +++ b/src/datamanagement/custom/example/iwavegps/README.md @@ -37,18 +37,18 @@ compile using `make` as usual. Like CAN if data is sent to cloud you should see this: ``` -[Thread : 565] [2022-10-27 02:39:12 PM] [INFO] [IoTFleetWiseEngine::doWork]: [FWE data ready to send with eventID 1644139266 from arn:aws:iotfleetwise:us-east-1:748151249882:campaign/IWaveGpsCampaign Signals:70 [2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196, ...] first signal timestamp: 1666881551998 raw CAN frames:0 DTCs:0 Geohash:] +[INFO ] [IoTFleetWiseEngine.cpp:914] [doWork()]: [FWE data ready to send with eventID 1644139266 from arn:aws:iotfleetwise:us-east-1:748151249882:campaign/IWaveGpsCampaign Signals:70 [2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196, ...] first signal timestamp: 1666881551998 raw CAN frames:0 DTCs:0 Geohash:] ``` If the GPS NMEA output it working but gps fix is available you should move to an area with a open sight to the sky. As long as no GPS fix is available you will see every 10 seconds: ``` -[Thread : 618] [2022-10-27 03:11:00 PM] [TRACE] [IWaveGpsSource::pollData]: [In the last 10000 millisecond found 10 lines with $GPGGA and extracted 0 valid coordinates from it] +[TRACE] [IWaveGpsSource.cpp:112] [pollData()]: [In the last 10000 millisecond found 10 lines with $GPGGA and extracted 0 valid coordinates from it] ``` As soon as data is available you should see this: ``` -[Thread : 618] [2022-10-27 03:12:54 PM] [TRACE] [IWaveGpsSource::pollData]: [In the last 10000 millisecond found 11 lines with $GPGGA and extracted 11 valid coordinates from it] +[TRACE] [IWaveGpsSource.cpp:112] [pollData()]: [In the last 10000 millisecond found 11 lines with $GPGGA and extracted 11 valid coordinates from it] ``` diff --git a/src/datamanagement/custom/example/iwavegps/include/IWaveGpsSource.h b/src/datamanagement/custom/example/iwavegps/include/IWaveGpsSource.h index 917042f3..4029349e 100644 --- a/src/datamanagement/custom/example/iwavegps/include/IWaveGpsSource.h +++ b/src/datamanagement/custom/example/iwavegps/include/IWaveGpsSource.h @@ -66,9 +66,9 @@ class IWaveGpsSource : public CustomDataSource, public AbstractVehicleDataSource private: static bool validLatitude( double latitude ); static bool validLongitude( double longitude ); - bool extractIntegerFromConfig( const std::vector &sourceConfigs, - const std::string key, - uint32_t &extractedValue ); + static bool extractIntegerFromConfig( const std::vector &sourceConfigs, + const std::string key, + uint32_t &extractedValue ); /** * The NMEA protocol provides the position in $GPGGA in the following format @@ -87,7 +87,6 @@ class IWaveGpsSource : public CustomDataSource, public AbstractVehicleDataSource uint16_t mLongitudeStartBit = 0; int mFileHandle = -1; - LoggingModule mLogger; SignalBufferPtr mSignalBufferPtr; std::shared_ptr mClock = ClockHandler::getClock(); Timer mCyclicLoggingTimer; diff --git a/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp b/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp index 3a16f540..68ff612d 100644 --- a/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp +++ b/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp @@ -3,8 +3,8 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes #include "IWaveGpsSource.h" +#include "LoggingModule.h" #include -#include #include #include #include @@ -15,11 +15,12 @@ namespace IoTFleetWise { namespace DataManagement { -constexpr const char *IWaveGpsSource::PATH_TO_NMEA; -constexpr const char *IWaveGpsSource::CAN_CHANNEL_NUMBER; -constexpr const char *IWaveGpsSource::CAN_RAW_FRAME_ID; -constexpr const char *IWaveGpsSource::LATITUDE_START_BIT; -constexpr const char *IWaveGpsSource::LONGITUDE_START_BIT; +// NOLINT below due to C++17 warning of redundant declarations that are required to maintain C++14 compatibility +constexpr const char *IWaveGpsSource::PATH_TO_NMEA; // NOLINT +constexpr const char *IWaveGpsSource::CAN_CHANNEL_NUMBER; // NOLINT +constexpr const char *IWaveGpsSource::CAN_RAW_FRAME_ID; // NOLINT +constexpr const char *IWaveGpsSource::LATITUDE_START_BIT; // NOLINT +constexpr const char *IWaveGpsSource::LONGITUDE_START_BIT; // NOLINT IWaveGpsSource::IWaveGpsSource( SignalBufferPtr signalBufferPtr ) { mSignalBufferPtr = signalBufferPtr; @@ -56,14 +57,13 @@ IWaveGpsSource::getThreadName() void IWaveGpsSource::pollData() { - char buffer[MAX_BYTES_READ_PER_POLL]; + char buffer[MAX_BYTES_READ_PER_POLL]{}; // Read from NMEA formatted file auto bytes = read( mFileHandle, buffer, MAX_BYTES_READ_PER_POLL - 1 ); - buffer[MAX_BYTES_READ_PER_POLL - 1] = 0; if ( bytes < 0 ) { - mLogger.error( "IWaveGpsSource::pollData", "Error reading from file" ); + FWE_LOG_ERROR( "Error reading from file" ); return; } @@ -108,10 +108,9 @@ IWaveGpsSource::pollData() } if ( mCyclicLoggingTimer.getElapsedMs().count() > CYCLIC_LOG_PERIOD_MS ) { - mLogger.trace( "IWaveGpsSource::pollData", - "In the last " + std::to_string( CYCLIC_LOG_PERIOD_MS ) + " millisecond found " + - std::to_string( mGpggaLineCounter ) + " lines with $GPGGA and extracted " + - std::to_string( mValidCoordinateCounter ) + " valid coordinates from it" ); + FWE_LOG_TRACE( "In the last " + std::to_string( CYCLIC_LOG_PERIOD_MS ) + " millisecond found " + + std::to_string( mGpggaLineCounter ) + " lines with $GPGGA and extracted " + + std::to_string( mValidCoordinateCounter ) + " valid coordinates from it" ); mCyclicLoggingTimer.reset(); mGpggaLineCounter = 0; mValidCoordinateCounter = 0; @@ -121,12 +120,12 @@ IWaveGpsSource::pollData() bool IWaveGpsSource::validLatitude( double latitude ) { - return latitude >= -90.0 && latitude <= 90.0; + return ( latitude >= -90.0 ) && ( latitude <= 90.0 ); } bool IWaveGpsSource::validLongitude( double longitude ) { - return longitude >= -180.0 && longitude <= 180.0; + return ( longitude >= -180.0 ) && ( longitude <= 180.0 ); } double @@ -208,15 +207,15 @@ IWaveGpsSource::init( const std::vector &sourceConfigs uint32_t latitudeStartBit = 0; uint32_t longitudeStartBit = 0; - if ( sourceConfigs.size() > 1 || sourceConfigs.empty() ) + if ( ( sourceConfigs.size() > 1 ) || sourceConfigs.empty() ) { - mLogger.error( "IWaveGpsSource::init", "Only one source config is supported" ); + FWE_LOG_ERROR( "Only one source config is supported" ); return false; } auto settingsIterator = sourceConfigs[0].transportProperties.find( std::string( PATH_TO_NMEA ) ); if ( settingsIterator == sourceConfigs[0].transportProperties.end() ) { - mLogger.error( "IWaveGpsSource::init", "Could not find nmeaFilePath in the config" ); + FWE_LOG_ERROR( "Could not find nmeaFilePath in the config" ); return false; } else @@ -246,7 +245,7 @@ IWaveGpsSource::extractIntegerFromConfig( const std::vector #include #include @@ -12,6 +13,7 @@ #include using namespace Aws::IoTFleetWise::DataManagement; +using namespace Aws::IoTFleetWise::TestingSupport; class IWaveGpsSourceTest : public ::testing::Test { @@ -72,17 +74,15 @@ TEST_F( IWaveGpsSourceTest, testDecoding ) gpsSource.start(); gpsSource.onChangeOfActiveDictionary( mDictionary, VehicleDataSourceProtocol::RAW_SOCKET ); - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - CollectedSignal firstSignal; CollectedSignal secondSignal; - ASSERT_TRUE( signalBufferPtr->pop( firstSignal ) ); + WAIT_ASSERT_TRUE( signalBufferPtr->pop( firstSignal ) ); ASSERT_TRUE( signalBufferPtr->pop( secondSignal ) ); ASSERT_EQ( firstSignal.signalID, 0x1234 ); ASSERT_EQ( secondSignal.signalID, 0x5678 ); // raw value from NMEA 5234.56789 01234.56789 converted to DD - ASSERT_NEAR( firstSignal.value, 52.5761, 0.0001 ); - ASSERT_NEAR( secondSignal.value, 12.5761, 0.0001 ); + ASSERT_NEAR( firstSignal.value.value.doubleVal, 52.5761, 0.0001 ); + ASSERT_NEAR( secondSignal.value.value.doubleVal, 12.5761, 0.0001 ); } // Test longitude west @@ -106,15 +106,13 @@ TEST_F( IWaveGpsSourceTest, testWestNegativeLongitude ) gpsSource.start(); gpsSource.onChangeOfActiveDictionary( mDictionary, VehicleDataSourceProtocol::RAW_SOCKET ); - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - CollectedSignal firstSignal; CollectedSignal secondSignal; - ASSERT_TRUE( signalBufferPtr->pop( firstSignal ) ); + WAIT_ASSERT_TRUE( signalBufferPtr->pop( firstSignal ) ); ASSERT_TRUE( signalBufferPtr->pop( secondSignal ) ); ASSERT_EQ( firstSignal.signalID, 0x1234 ); ASSERT_EQ( secondSignal.signalID, 0x5678 ); // raw value from NMEA 5234.56789 01234.56789 converted to DD - ASSERT_NEAR( firstSignal.value, 52.5761, 0.0001 ); - ASSERT_NEAR( secondSignal.value, -12.5761, 0.0001 ); // negative number + ASSERT_NEAR( firstSignal.value.value.doubleVal, 52.5761, 0.0001 ); + ASSERT_NEAR( secondSignal.value.value.doubleVal, -12.5761, 0.0001 ); // negative number } diff --git a/src/datamanagement/custom/example/iwavegps/test/valgrind.supp b/src/datamanagement/custom/example/iwavegps/test/valgrind.supp index 81f54a0c..72475585 100644 --- a/src/datamanagement/custom/example/iwavegps/test/valgrind.supp +++ b/src/datamanagement/custom/example/iwavegps/test/valgrind.supp @@ -5,3 +5,12 @@ fun:_ZN5boost8lockfree5queue* ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/datamanagement/custom/generic/include/CustomDataSource.h b/src/datamanagement/custom/generic/include/CustomDataSource.h index c5843ea1..1e7bdea7 100644 --- a/src/datamanagement/custom/generic/include/CustomDataSource.h +++ b/src/datamanagement/custom/generic/include/CustomDataSource.h @@ -3,7 +3,6 @@ #pragma once #include "IActiveDecoderDictionaryListener.h" -#include "LoggingModule.h" #include "Thread.h" namespace Aws @@ -88,7 +87,6 @@ class CustomDataSource : public IActiveDecoderDictionaryListener bool shouldSleep() const; - LoggingModule mLogger; Thread mThread; std::atomic mShouldStop{ false }; std::atomic mShouldSleep{ false }; diff --git a/src/datamanagement/custom/generic/src/CustomDataSource.cpp b/src/datamanagement/custom/generic/src/CustomDataSource.cpp index 6aaa61d1..5c3af903 100644 --- a/src/datamanagement/custom/generic/src/CustomDataSource.cpp +++ b/src/datamanagement/custom/generic/src/CustomDataSource.cpp @@ -4,6 +4,7 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes #include "CustomDataSource.h" +#include "LoggingModule.h" #include "Timer.h" namespace Aws @@ -33,12 +34,16 @@ CustomDataSource::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CustomDataSource::start", "Thread failed to start" ); + FWE_LOG_TRACE( "Thread failed to start" ); } else { - mLogger.trace( "CustomDataSource::start", "Thread started" ); - mThread.setThreadName( getThreadName() ); + FWE_LOG_TRACE( "Thread started" ); + const auto name = getThreadName(); + if ( name != nullptr ) + { + mThread.setThreadName( name ); + } } return mThread.isActive() && mThread.isValid(); @@ -65,7 +70,7 @@ CustomDataSource::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CustomDataSource::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); return !mThread.isActive(); } @@ -92,8 +97,7 @@ CustomDataSource::doWork( void *data ) { // We either just started or there was a decoder dictionary update that we can't use. // We should sleep - customDataSource->mLogger.trace( "CustomDataSource::doWork", - "No valid decoding information available so sleep" ); + FWE_LOG_TRACE( "No valid decoding information available so sleep" ); // Wait here for the decoder dictionary to come. customDataSource->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); // At this point, we should be able to see events coming as the channel is also @@ -105,8 +109,8 @@ CustomDataSource::doWork( void *data ) customDataSource->mUsedMessageFormat = customDataSource->mExtractedMessageFormat; customDataSource->mNewMessageFormatExtracted = false; } - if ( !customDataSource->shouldSleep() && !customDataSource->mUsedMessageFormat.mSignals.empty() && - pollTimer.getElapsedMs().count() >= static_cast( customDataSource->mPollIntervalMs ) ) + if ( ( !customDataSource->shouldSleep() ) && ( !customDataSource->mUsedMessageFormat.mSignals.empty() ) && + ( pollTimer.getElapsedMs().count() >= static_cast( customDataSource->mPollIntervalMs ) ) ) { customDataSource->pollData(); pollTimer.reset(); @@ -138,7 +142,7 @@ CustomDataSource::matchDictionaryToFilter( const CANDecoderDictionary &dictionar { if ( mCanChannel == INVALID_CAN_SOURCE_NUMERIC_ID ) { - mLogger.trace( "CustomDataSource::matchDictionaryToFilter", "No Valid CAN so requesting sleep" ); + FWE_LOG_TRACE( "No Valid CAN so requesting sleep" ); mShouldSleep = true; // Nothing found return; } @@ -156,8 +160,7 @@ CustomDataSource::matchDictionaryToFilter( const CANDecoderDictionary &dictionar mNewMessageFormatExtracted = true; mShouldSleep = false; } - mLogger.trace( "CustomDataSource::matchDictionaryToFilter", - "Dictionary with relevant information for CustomDataSource so waking up" ); + FWE_LOG_TRACE( "Dictionary with relevant information for CustomDataSource so waking up" ); mWait.notify(); return; } @@ -165,8 +168,7 @@ CustomDataSource::matchDictionaryToFilter( const CANDecoderDictionary &dictionar break; } } - mLogger.trace( "CustomDataSource::matchDictionaryToFilter", - "Dictionary has no relevant information for CustomDataSource" ); + FWE_LOG_TRACE( "Dictionary has no relevant information for CustomDataSource" ); mShouldSleep = true; // Nothing found } diff --git a/src/datamanagement/datacollection/CMakeLists.txt b/src/datamanagement/datacollection/CMakeLists.txt index 249f5c91..16ab368c 100644 --- a/src/datamanagement/datacollection/CMakeLists.txt +++ b/src/datamanagement/datacollection/CMakeLists.txt @@ -5,11 +5,8 @@ set(libraryTargetName iotfleetwise.datacollection) set(libraryAliasName IoTFleetWise::DataCollection) set(SRCS - src/CollectionScheme.cpp src/CollectionSchemeIngestion.cpp src/CollectionSchemeIngestionList.cpp - src/CollectionSchemeJSONParser.cpp - src/DataCollectionJSONWriter.cpp src/DataCollectionProtoWriter.cpp src/DataCollectionSender.cpp ) @@ -46,11 +43,8 @@ install(TARGETS ${libraryTargetName} DESTINATION lib) install( FILES include/CANInterfaceIDTranslator.h - include/CollectionScheme.h include/CollectionSchemeIngestion.h include/CollectionSchemeIngestionList.h - include/CollectionSchemeJSONParser.h - include/DataCollectionJSONWriter.h include/DataCollectionProtoWriter.h include/DataCollectionSender.h include/ICollectionScheme.h @@ -75,8 +69,6 @@ if(${BUILD_TESTING}) set( testSources - test/CollectionSchemeJSONParserTest.cpp - test/DataCollectionJSONWriterTest.cpp test/DataCollectionProtoWriterTest.cpp test/DataCollectionSenderTest.cpp ) diff --git a/src/datamanagement/datacollection/include/CollectionScheme.h b/src/datamanagement/datacollection/include/CollectionScheme.h deleted file mode 100644 index 732e2445..00000000 --- a/src/datamanagement/datacollection/include/CollectionScheme.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -// Includes -#include "CANDataTypes.h" -#include "MessageTypes.h" -#include -#include -#include -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ -/** - * @brief A set of structs used to represent the AWS IoT FleetWise Collection Scheme. - */ -enum class TriggerType -{ - TIMEPOINT, - SIGNALVALUE -}; - -enum class PredicateCondition -{ - EVERY, - EQUAL, - LESS, - BIGGER -}; - -struct ValuePredicate -{ - PredicateCondition mCondition{ PredicateCondition::EVERY }; - double mValue{ 0.0 }; -}; - -struct EventTrigger -{ - TriggerType mTriggerType{ TriggerType::TIMEPOINT }; - uint32_t mSignalID{ 0x0 }; - uint32_t mParentMessageID{ 0x0 }; - ValuePredicate mValuePredicate; - bool - isValid() const - { - return ( ( mTriggerType == TriggerType::SIGNALVALUE ) && ( mSignalID > 0 ) && - ( mValuePredicate.mCondition != PredicateCondition::EVERY ) ) || - ( ( mTriggerType == TriggerType::TIMEPOINT ) && - ( mValuePredicate.mCondition == PredicateCondition::EVERY ) && ( mValuePredicate.mValue > 0.0 ) ); - } - bool - operator<( const EventTrigger &a ) const - { - return mSignalID < a.mSignalID; - } -}; - -using EventTriggers = std::vector; -using CollectedCANMessages = std::map; -using WatchedCANMessages = std::map; - -class CollectionScheme -{ - -public: - bool isValid(); - void setVersion( const std::string &version ); - void setCollectionSchemeID( const std::string &collectionSchemeID ); - void setEventType( const std::string &eventType ); - void setTimeTrigger( const EventTrigger &timeTrigger ); - void setEventTriggers( const EventTriggers &eventTriggers ); - void setEventID( const uint64_t &eventID ); - const std::string &getVersion() const; - const std::string &getCollectionSchemeID() const; - const std::string &getEventType() const; - const uint64_t &getEventID() const; - const EventTriggers &getEventTriggers() const; - const EventTrigger &getTimeTrigger() const; - - void insertMessageToCollected( const uint32_t &messageID, const CANMessageFormat &messageFormat ); - void insertSignalTriggerToMessage( const uint32_t &messageID, const EventTrigger &trigger ); - void clear(); - const WatchedCANMessages &getWatchedCANMessages() const; - const CollectedCANMessages &getCollectedCANMessages() const; - bool shouldWatchCANMessage( const uint32_t &messageID ) const; - const CANMessageFormat &getCANMessageFormat( const uint32_t &messageID ) const; - bool shouldCollectCANMessage( const uint32_t &messageID ) const; - bool shouldTriggerUpload( const CANFrameInfo &frameInfo, EventTrigger &eventTrigger ); - -private: - static constexpr uint64_t INVALID_EVENT_ID = 0; - std::string mVersion; - std::string mCollectionSchemeID; - std::string mEventType; - uint64_t mEventID{ INVALID_EVENT_ID }; - EventTriggers mEventTriggers; - CollectedCANMessages mMessageIDsToBeCollected; - WatchedCANMessages mMessageIDsToBeWatched; - EventTrigger mTimeTrigger; -}; -using CollectionSchemePtr = std::shared_ptr; - -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/include/CollectionSchemeIngestion.h b/src/datamanagement/datacollection/include/CollectionSchemeIngestion.h index 923335f9..08142b5d 100644 --- a/src/datamanagement/datacollection/include/CollectionSchemeIngestion.h +++ b/src/datamanagement/datacollection/include/CollectionSchemeIngestion.h @@ -5,7 +5,6 @@ #include "CollectionInspectionAPITypes.h" #include "ICollectionScheme.h" -#include "LoggingModule.h" #include namespace Aws @@ -113,7 +112,7 @@ class CollectionSchemeIngestion : public ICollectionScheme * @brief Function used to Flatten the Abstract Syntax Tree (AST) */ ExpressionNode *serializeNode( const CollectionSchemesMsg::ConditionNode &node, - uint32_t &nextIndex, + std::size_t &nextIndex, const int depth ); /** @@ -129,18 +128,13 @@ class CollectionSchemeIngestion : public ICollectionScheme /** * @brief Private Local Function used by the serializeNode Function to return the used Function Type */ - WindowFunction convertFunctionType( + static WindowFunction convertFunctionType( CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType function ); /** * @brief Private Local Function used by the serializeNode Function to return the used Operator Type */ - ExpressionNodeType convertOperatorType( CollectionSchemesMsg::ConditionNode_NodeOperator_Operator op ); - - /** - * @brief Logging module used to output to logs - */ - LoggingModule mLogger; + static ExpressionNodeType convertOperatorType( CollectionSchemesMsg::ConditionNode_NodeOperator_Operator op ); }; } // namespace DataManagement } // namespace IoTFleetWise diff --git a/src/datamanagement/datacollection/include/CollectionSchemeIngestionList.h b/src/datamanagement/datacollection/include/CollectionSchemeIngestionList.h index 9a7218d3..6beb93a6 100644 --- a/src/datamanagement/datacollection/include/CollectionSchemeIngestionList.h +++ b/src/datamanagement/datacollection/include/CollectionSchemeIngestionList.h @@ -5,7 +5,6 @@ #include "CollectionSchemeIngestion.h" #include "ICollectionSchemeList.h" -#include "LoggingModule.h" #include "collection_schemes.pb.h" #include @@ -73,11 +72,6 @@ class CollectionSchemeIngestionList : public ICollectionSchemeList * @brief Used internally to hold the collectionSchemes message from the protobuffer */ CollectionSchemesMsg::CollectionSchemes mCollectionSchemeListMsg; - - /** - * @brief Logging module used to output to logs - */ - LoggingModule mLogger; }; } // namespace DataManagement diff --git a/src/datamanagement/datacollection/include/CollectionSchemeJSONParser.h b/src/datamanagement/datacollection/include/CollectionSchemeJSONParser.h deleted file mode 100644 index 905e876b..00000000 --- a/src/datamanagement/datacollection/include/CollectionSchemeJSONParser.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -// Includes -#include "CollectionScheme.h" -#include "LoggingModule.h" -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ -using namespace Aws::IoTFleetWise::Platform::Linux; -/** - * @brief A Parser for a Json representation of the Collection Scheme. - */ -class CollectionSchemeJSONParser -{ -public: - /** - * @brief Constructor. - * @param path to the Json file. - */ - CollectionSchemeJSONParser( const std::string &path ); - - /** - * @brief Parses the Json file following the scheme defined. - * @return true if success. - */ - bool parse(); - /** - * @brief reloads the Json file if it has changed. Locks any new access to - * underlying deserialized object till the parsing ends. - * @return true if success. - */ - bool reLoad(); - /** - * @brief getter for the Collection Scheme Object. - * @return Shared pointer to the object. Waits to return on a Mutex if - * the object is being constructed. - */ - CollectionSchemePtr getCollectionScheme(); - -private: - std::mutex mMutex; - CollectionSchemePtr mCollectionScheme; - LoggingModule mLogger; - std::string mPath; -}; -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/include/DataCollectionJSONWriter.h b/src/datamanagement/datacollection/include/DataCollectionJSONWriter.h deleted file mode 100644 index 9cbbe590..00000000 --- a/src/datamanagement/datacollection/include/DataCollectionJSONWriter.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -// Includes -#include "CANDataTypes.h" -#include "ClockHandler.h" -#include "CollectionInspectionAPITypes.h" -#include "GeohashInfo.h" -#include "LoggingModule.h" -#include "OBDDataTypes.h" -#include -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ -using namespace Aws::IoTFleetWise::DataInspection; - -/** - * @brief A Json based writer of the collected data. - */ -class DataCollectionJSONWriter -{ -public: - /** - * @brief Construct a new Data Collection JSON Writer object - * - * @param persistencyPath Path to file system where files will be written for durable storage. - */ - DataCollectionJSONWriter( std::string persistencyPath ); - void setupEvent( const TriggeredCollectionSchemeDataPtr triggeredCollectionSchemeData, uint32_t collectionEventID ); - - void append( const CollectedSignal &msg ); - void append( const CollectedCanRawFrame &msg ); - void append( const GeohashInfo &geohashInfo ); - - /** - * @brief Write the contents of the event to a file. - * - * @return std::pair with - * the first element containing the file path and name of the created file. The file extension will be - * json for uncompressed files and snappy for compressed files. - * the second element indicating whether the file was compressed or not. - */ - std::pair flushToFile(); - - unsigned getJSONMessageCount() const; - -private: - /** - * @brief Write the event data to a file - * - * @param fileBaseName Base file name to use. - * Do not provide a file extension. - * The extension will be added based on whether the file contents are compressed or not. - * For uncompressed file, the extension will be ".json". For compressed files, it will be ".snappy" - * - * @return std::pair with - * the first element containing the file name of the created file. The file extension will be - * json for uncompressed files and snappy for compressed files. - * the second element indicating whether the file was compressed or not. - */ - std::pair flushToFile( const std::string &fileBaseName ); - - Json::Value mEvent; - Json::Value mMessages{ Json::arrayValue }; - Json::UInt64 mTriggerTime{ 0 }; - std::string mPersistencyPath; - - /** - * @brief Whether the contents of the JSON file will be compressed or not. - * This is based on the metadata available in the CollectionSchemeData and is modified as part of - * setupEvent method. - * - */ - bool mShouldCompress{ false }; - - /** - * @brief Logger used to log output. - */ - LoggingModule mLogger; - - std::shared_ptr mClock = ClockHandler::getClock(); -}; -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/include/DataCollectionSender.h b/src/datamanagement/datacollection/include/DataCollectionSender.h index ef11b7f8..b02c8493 100644 --- a/src/datamanagement/datacollection/include/DataCollectionSender.h +++ b/src/datamanagement/datacollection/include/DataCollectionSender.h @@ -5,10 +5,8 @@ // Includes #include "CollectionInspectionAPITypes.h" -#include "DataCollectionJSONWriter.h" #include "DataCollectionProtoWriter.h" #include "ISender.h" -#include "LoggingModule.h" #include #include #include @@ -35,7 +33,6 @@ enum class SendDestination /** * @brief Serializes collected data and sends it to the cloud. - * Optionally supports debug JSON output of collected data. * The maxMessageCount option limits the number of messages * (or signals) appended to the protobuf message before the * protobuf is serialized and sent to the cloud. @@ -47,16 +44,12 @@ class DataCollectionSender * @brief Constructor. Setup the DataCollectionSender. * * @param sender ISender interface to the cloud - * @param jsonOutputEnabled True to enable debug JSON output of the collected data * @param maxMessageCount Maximum number of messages before the data is serialized and sent to the cloud * @param canIDTranslator Needed to translate the internal used can channel id to the can interface id used by - * @param persistencyPath Path to file system where files will be written for durable storage. */ DataCollectionSender( std::shared_ptr sender, - bool jsonOutputEnabled, unsigned maxMessageCount, - CANInterfaceIDTranslator &canIDTranslator, - std::string persistencyPath ); + CANInterfaceIDTranslator &canIDTranslator ); /** * @brief Serializes the collected data and transmits it to the cloud @@ -82,15 +75,12 @@ class DataCollectionSender ConnectivityError transmit( const std::string &payload ); private: - LoggingModule mLogger; uint32_t mCollectionEventID; // A unique ID that FWE generates each time a collectionScheme condition is triggered. std::shared_ptr mSender; - bool mJsonOutputEnabled{ false }; SendDestination mSendDestination{ SendDestination::MQTT }; unsigned mTransmitThreshold; // max number of messages that can be sent to cloud at one time std::string mPersistencyPath; DataCollectionProtoWriter mProtoWriter; - DataCollectionJSONWriter mJsonWriter; std::string mProtoOutput; CollectionSchemeParams mCollectionSchemeParams; diff --git a/src/datamanagement/datacollection/src/CollectionScheme.cpp b/src/datamanagement/datacollection/src/CollectionScheme.cpp deleted file mode 100644 index ed7364eb..00000000 --- a/src/datamanagement/datacollection/src/CollectionScheme.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -// Includes -#include "CollectionScheme.h" -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ - -bool -CollectionScheme::isValid() -{ - return ( ( !mMessageIDsToBeWatched.empty() ) && ( !mEventTriggers.empty() ) ) || - ( ( !mMessageIDsToBeCollected.empty() ) && ( mTimeTrigger.isValid() ) ); -} - -void -CollectionScheme::clear() -{ - mVersion = ""; - mCollectionSchemeID = ""; - mEventType = ""; - mEventID = 0; - - mMessageIDsToBeCollected.clear(); - mMessageIDsToBeWatched.clear(); -} - -void -CollectionScheme::insertMessageToCollected( const uint32_t &messageID, const CANMessageFormat &messageFormat ) -{ - mMessageIDsToBeCollected.emplace( messageID, messageFormat ); -} -void -CollectionScheme::insertSignalTriggerToMessage( const uint32_t &messageID, const EventTrigger &trigger ) -{ - if ( !trigger.isValid() ) - { - return; - } - auto it = mMessageIDsToBeWatched.find( messageID ); - if ( it != mMessageIDsToBeWatched.end() ) - { - // Append the trigger to the message if it exists. - it->second.emplace_back( trigger ); - // Sort the triggers to allow fast lookup during evaluation. - std::sort( it->second.begin(), it->second.end() ); - } - else - { - // First item in the trigger - EventTriggers triggers; - triggers.emplace_back( trigger ); - - mMessageIDsToBeWatched.emplace( messageID, triggers ); - } -} - -void -CollectionScheme::setVersion( const std::string &version ) -{ - mVersion = version; -} - -void -CollectionScheme::setCollectionSchemeID( const std::string &collectionSchemeID ) -{ - mCollectionSchemeID = collectionSchemeID; -} -void -CollectionScheme::setEventType( const std::string &eventType ) -{ - mEventType = eventType; -} -void -CollectionScheme::setEventID( const uint64_t &eventID ) -{ - mEventID = eventID; -} - -void -CollectionScheme::setTimeTrigger( const EventTrigger &timeTrigger ) -{ - if ( !timeTrigger.isValid() ) - { - return; - } - - mTimeTrigger = timeTrigger; -} - -void -CollectionScheme::setEventTriggers( const EventTriggers &eventTriggers ) -{ - mEventTriggers.assign( eventTriggers.begin(), eventTriggers.end() ); -} - -const std::string & -CollectionScheme::getVersion() const -{ - return mVersion; -} - -const std::string & -CollectionScheme::getCollectionSchemeID() const -{ - return mCollectionSchemeID; -} - -const std::string & -CollectionScheme::getEventType() const -{ - return mEventType; -} - -const uint64_t & -CollectionScheme::getEventID() const -{ - return mEventID; -} - -const EventTriggers & -CollectionScheme::getEventTriggers() const -{ - return mEventTriggers; -} -const EventTrigger & -CollectionScheme::getTimeTrigger() const -{ - return mTimeTrigger; -} - -const WatchedCANMessages & -CollectionScheme::getWatchedCANMessages() const -{ - return mMessageIDsToBeWatched; -} -const CollectedCANMessages & -CollectionScheme::getCollectedCANMessages() const -{ - return mMessageIDsToBeCollected; -} - -bool -CollectionScheme::shouldWatchCANMessage( const uint32_t &messageID ) const -{ - auto it = mMessageIDsToBeWatched.find( messageID ); - return it != mMessageIDsToBeWatched.end() ? true : false; -} - -const CANMessageFormat & -CollectionScheme::getCANMessageFormat( const uint32_t &messageID ) const -{ - static CANMessageFormat format; - auto it = mMessageIDsToBeCollected.find( messageID ); - if ( it != mMessageIDsToBeCollected.end() ) - { - return it->second; - } - return format; -} - -bool -CollectionScheme::shouldCollectCANMessage( const uint32_t &messageID ) const -{ - auto it = mMessageIDsToBeCollected.find( messageID ); - return it != mMessageIDsToBeCollected.end() ? true : false; -} - -bool -CollectionScheme::shouldTriggerUpload( const CANFrameInfo &frameInfo, EventTrigger &eventTrigger ) -{ - bool predicateMet = false; - auto it = mMessageIDsToBeWatched.find( frameInfo.mFrameID ); - if ( it != mMessageIDsToBeWatched.end() ) - { - // Lookup the triggers for this message - // the triggers are already sorted by signalID during parsing. - size_t i = 0; - while ( ( i < frameInfo.mSignals.size() ) ) - { - for ( size_t j = 0; j < it->second.size(); ++j ) - { - if ( ( it->second[j].mTriggerType == TriggerType::SIGNALVALUE ) && - ( it->second[j].mSignalID == frameInfo.mSignals[i].mSignalID ) ) - { - if ( it->second[j].mValuePredicate.mCondition == PredicateCondition::LESS ) - { - predicateMet = frameInfo.mSignals[i].mPhysicalValue < it->second[j].mValuePredicate.mValue; - } - else if ( it->second[j].mValuePredicate.mCondition == PredicateCondition::BIGGER ) - { - predicateMet = frameInfo.mSignals[i].mPhysicalValue > it->second[j].mValuePredicate.mValue; - } - else if ( it->second[j].mValuePredicate.mCondition == PredicateCondition::EQUAL ) - { - predicateMet = frameInfo.mSignals[i].mPhysicalValue == it->second[j].mValuePredicate.mValue; - } - } - if ( predicateMet ) - { - // Hint at the trigger - eventTrigger = it->second[j]; - return predicateMet; - } - } - i++; - } - } - return predicateMet; -} - -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp b/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp index 6fd710bf..245468ee 100644 --- a/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp +++ b/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp @@ -3,6 +3,7 @@ // Includes #include "CollectionSchemeIngestion.h" +#include "LoggingModule.h" namespace Aws { @@ -40,7 +41,7 @@ CollectionSchemeIngestion::build() if ( mProtoCollectionSchemeMessagePtr->campaign_arn().empty() || mProtoCollectionSchemeMessagePtr->decoder_manifest_arn().empty() ) { - mLogger.error( "CollectionSchemeIngestion::build", "CollectionScheme does not have ID or DM ID" ); + FWE_LOG_ERROR( "CollectionScheme does not have ID or DM ID" ); return false; } @@ -48,12 +49,11 @@ CollectionSchemeIngestion::build() if ( mProtoCollectionSchemeMessagePtr->expiry_time_ms_epoch() < mProtoCollectionSchemeMessagePtr->start_time_ms_epoch() ) { - mLogger.error( "CollectionSchemeIngestion::build", "CollectionScheme end time comes before start time" ); + FWE_LOG_ERROR( "CollectionScheme end time comes before start time" ); return false; } - mLogger.trace( "CollectionSchemeIngestion::build", - "Building CollectionScheme with ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); + FWE_LOG_TRACE( "Building CollectionScheme with ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); // Build Collected Signals for ( int signalIndex = 0; signalIndex < mProtoCollectionSchemeMessagePtr->signal_information_size(); @@ -71,8 +71,7 @@ CollectionSchemeIngestion::build() signalInfo.fixedWindowPeriod = signalInformation.fixed_window_period_ms(); signalInfo.isConditionOnlySignal = signalInformation.condition_only_signal(); - mLogger.trace( "CollectionSchemeIngestion::build", - "Adding signalID: " + std::to_string( signalInfo.signalID ) + " to list of signals to collect" ); + FWE_LOG_TRACE( "Adding signalID: " + std::to_string( signalInfo.signalID ) + " to list of signals to collect" ); mCollectedSignals.emplace_back( signalInfo ); } @@ -91,9 +90,8 @@ CollectionSchemeIngestion::build() rawCAN.sampleBufferSize = rawCanFrame.sample_buffer_size(); rawCAN.minimumSampleIntervalMs = rawCanFrame.minimum_sample_period_ms(); - mLogger.trace( "CollectionSchemeIngestion::build", - "Adding rawCAN frame to collect ID: " + std::to_string( rawCAN.frameID ) + - " node ID: " + rawCAN.interfaceID ); + FWE_LOG_TRACE( "Adding rawCAN frame to collect ID: " + std::to_string( rawCAN.frameID ) + + " node ID: " + rawCAN.interfaceID ); mCollectedRawCAN.emplace_back( rawCAN ); } @@ -105,30 +103,28 @@ CollectionSchemeIngestion::build() getNumberOfNodes( mProtoCollectionSchemeMessagePtr->condition_based_collection_scheme().condition_tree(), Aws::IoTFleetWise::DataInspection::MAX_EQUATION_DEPTH ); - mLogger.info( "CollectionSchemeIngestion::build", - "CollectionScheme is Condition Based. Building AST with " + std::to_string( numNodes ) + - " nodes" ); + FWE_LOG_INFO( "CollectionScheme is Condition Based. Building AST with " + std::to_string( numNodes ) + + " nodes" ); mExpressionNodes.resize( numNodes ); // As pointers to elements inside the vector are used after this no realloc for mExpressionNodes is allowed - uint32_t currentIndex = 0; // start at index 0 of mExpressionNodes for first node + std::size_t currentIndex = 0; // start at index 0 of mExpressionNodes for first node mExpressionNode = serializeNode( mProtoCollectionSchemeMessagePtr->condition_based_collection_scheme().condition_tree(), currentIndex, Aws::IoTFleetWise::DataInspection::MAX_EQUATION_DEPTH ); - mLogger.info( "CollectionSchemeIngestion::build", "AST complete" ); + FWE_LOG_INFO( "AST complete" ); } // time based node // For time based node the condition is always set to true hence: currentNode.booleanValue=true else if ( mProtoCollectionSchemeMessagePtr->collection_scheme_type_case() == CollectionSchemesMsg::CollectionScheme::kTimeBasedCollectionScheme ) { - mLogger.info( "CollectionSchemeIngestion::build", - "CollectionScheme is Time based with interval of: " + - std::to_string( mProtoCollectionSchemeMessagePtr->time_based_collection_scheme() - .time_based_collection_scheme_period_ms() ) + - " ms" ); + FWE_LOG_INFO( "CollectionScheme is Time based with interval of: " + + std::to_string( mProtoCollectionSchemeMessagePtr->time_based_collection_scheme() + .time_based_collection_scheme_period_ms() ) + + " ms" ); mExpressionNodes.emplace_back(); ExpressionNode ¤tNode = mExpressionNodes.back(); @@ -138,7 +134,7 @@ CollectionSchemeIngestion::build() } else { - mLogger.error( "CollectionSchemeIngestion::build", "COLLECTION_SCHEME_TYPE_NOT_SET" ); + FWE_LOG_ERROR( "COLLECTION_SCHEME_TYPE_NOT_SET" ); } // Build Image capture collection info @@ -161,20 +157,18 @@ CollectionSchemeIngestion::build() imageCaptureData.beforeDurationMs = imageData.time_based_image_data().before_duration_ms(); // Image format imageCaptureData.imageFormat = static_cast( imageData.image_type() ); - mLogger.info( "CollectionSchemeIngestion::build", - "Adding Image capture settings for DeviceID: " + - std::to_string( imageCaptureData.deviceID ) ); + FWE_LOG_INFO( "Adding Image capture settings for DeviceID: " + + std::to_string( imageCaptureData.deviceID ) ); mImagesCaptureData.emplace_back( imageCaptureData ); } else { - mLogger.warn( "CollectionSchemeIngestion::build", "Unsupported Image capture settings provided, skipping" ); + FWE_LOG_WARN( "Unsupported Image capture settings provided, skipping" ); } } - mLogger.info( "CollectionSchemeIngestion::build", - "Successfully built CollectionScheme ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); + FWE_LOG_INFO( "Successfully built CollectionScheme ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); // Set ready flag to true mReady = true; @@ -199,28 +193,25 @@ CollectionSchemeIngestion::convertFunctionType( switch ( function ) { case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_LAST_WINDOW_MIN: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", "Converting node to: LAST_FIXED_WINDOW_MIN" ); + FWE_LOG_INFO( "Converting node to: LAST_FIXED_WINDOW_MIN" ); return WindowFunction::LAST_FIXED_WINDOW_MIN; case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_LAST_WINDOW_MAX: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", "Converting node to: LAST_FIXED_WINDOW_MAX" ); + FWE_LOG_INFO( "Converting node to: LAST_FIXED_WINDOW_MAX" ); return WindowFunction::LAST_FIXED_WINDOW_MAX; case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_LAST_WINDOW_AVG: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", "Converting node to: LAST_FIXED_WINDOW_AVG" ); + FWE_LOG_INFO( "Converting node to: LAST_FIXED_WINDOW_AVG" ); return WindowFunction::LAST_FIXED_WINDOW_AVG; case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_PREV_LAST_WINDOW_MIN: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", - "Converting node to: PREV_LAST_FIXED_WINDOW_MIN" ); + FWE_LOG_INFO( "Converting node to: PREV_LAST_FIXED_WINDOW_MIN" ); return WindowFunction::PREV_LAST_FIXED_WINDOW_MIN; case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_PREV_LAST_WINDOW_MAX: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", - "Converting node to: PREV_LAST_FIXED_WINDOW_MAX" ); + FWE_LOG_INFO( "Converting node to: PREV_LAST_FIXED_WINDOW_MAX" ); return WindowFunction::PREV_LAST_FIXED_WINDOW_MAX; case CollectionSchemesMsg::ConditionNode_NodeFunction_WindowFunction_WindowType_PREV_LAST_WINDOW_AVG: - mLogger.info( "CollectionSchemeIngestion::convertFunctionType", - "Converting node to: PREV_LAST_FIXED_WINDOW_AVG" ); + FWE_LOG_INFO( "Converting node to: PREV_LAST_FIXED_WINDOW_AVG" ); return WindowFunction::PREV_LAST_FIXED_WINDOW_AVG; default: - mLogger.error( "CollectionSchemeIngestion::convertFunctionType", "Function node type not supported." ); + FWE_LOG_ERROR( "Function node type not supported." ); return WindowFunction::NONE; } } @@ -231,52 +222,43 @@ CollectionSchemeIngestion::convertOperatorType( CollectionSchemesMsg::ConditionN switch ( op ) { case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_SMALLER: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", "Converting operator to: OPERATOR_SMALLER" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_SMALLER" ); return ExpressionNodeType::OPERATOR_SMALLER; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_BIGGER: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", "Converting operator to: OPERATOR_BIGGER" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_BIGGER" ); return ExpressionNodeType::OPERATOR_BIGGER; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_SMALLER_EQUAL: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_SMALLER_EQUAL" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_SMALLER_EQUAL" ); return ExpressionNodeType::OPERATOR_SMALLER_EQUAL; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_BIGGER_EQUAL: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_BIGGER_EQUAL" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_BIGGER_EQUAL" ); return ExpressionNodeType::OPERATOR_BIGGER_EQUAL; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_EQUAL: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", "Converting operator to: OPERATOR_EQUAL" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_EQUAL" ); return ExpressionNodeType::OPERATOR_EQUAL; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_COMPARE_NOT_EQUAL: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator NodeOperator_Operator_COMPARE_NOT_EQUAL to OPERATOR_NOT_EQUAL" ); + FWE_LOG_INFO( "Converting operator NodeOperator_Operator_COMPARE_NOT_EQUAL to OPERATOR_NOT_EQUAL" ); return ExpressionNodeType::OPERATOR_NOT_EQUAL; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_LOGICAL_AND: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_LOGICAL_AND" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_LOGICAL_AND" ); return ExpressionNodeType::OPERATOR_LOGICAL_AND; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_LOGICAL_OR: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", "Converting operator to: OPERATOR_LOGICAL_OR" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_LOGICAL_OR" ); return ExpressionNodeType::OPERATOR_LOGICAL_OR; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_LOGICAL_NOT: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_LOGICAL_NOT" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_LOGICAL_NOT" ); return ExpressionNodeType::OPERATOR_LOGICAL_NOT; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_ARITHMETIC_PLUS: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_ARITHMETIC_PLUS" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_ARITHMETIC_PLUS" ); return ExpressionNodeType::OPERATOR_ARITHMETIC_PLUS; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_ARITHMETIC_MINUS: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_ARITHMETIC_MINUS" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_ARITHMETIC_MINUS" ); return ExpressionNodeType::OPERATOR_ARITHMETIC_MINUS; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_ARITHMETIC_MULTIPLY: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_ARITHMETIC_MULTIPLY" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_ARITHMETIC_MULTIPLY" ); return ExpressionNodeType::OPERATOR_ARITHMETIC_MULTIPLY; case CollectionSchemesMsg::ConditionNode_NodeOperator_Operator_ARITHMETIC_DIVIDE: - mLogger.info( "CollectionSchemeIngestion::convertOperatorType", - "Converting operator to: OPERATOR_ARITHMETIC_DIVIDE" ); + FWE_LOG_INFO( "Converting operator to: OPERATOR_ARITHMETIC_DIVIDE" ); return ExpressionNodeType::OPERATOR_ARITHMETIC_DIVIDE; default: return ExpressionNodeType::BOOLEAN; @@ -308,7 +290,7 @@ CollectionSchemeIngestion::getNumberOfNodes( const CollectionSchemesMsg::Conditi ExpressionNode * CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionNode &node, - uint32_t &nextIndex, + std::size_t &nextIndex, int remainingDepth ) { if ( remainingDepth <= 0 ) @@ -316,32 +298,37 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN return nullptr; } mExpressionNodes.emplace_back(); - ExpressionNode *currentNode = &( mExpressionNodes[nextIndex] ); + ExpressionNode *currentNode = nullptr; + if ( mExpressionNodes.empty() || ( mExpressionNodes.size() <= nextIndex ) ) + { + return nullptr; + } + else + { + currentNode = &( mExpressionNodes[nextIndex] ); + } nextIndex++; if ( node.node_case() == CollectionSchemesMsg::ConditionNode::kNodeSignalId ) { currentNode->signalID = node.node_signal_id(); currentNode->nodeType = ExpressionNodeType::SIGNAL; - mLogger.trace( "CollectionSchemeIngestion::serializeNode", - "Creating SIGNAL node with ID: " + std::to_string( currentNode->signalID ) ); + FWE_LOG_TRACE( "Creating SIGNAL node with ID: " + std::to_string( currentNode->signalID ) ); return currentNode; } else if ( node.node_case() == CollectionSchemesMsg::ConditionNode::kNodeDoubleValue ) { currentNode->floatingValue = node.node_double_value(); currentNode->nodeType = ExpressionNodeType::FLOAT; - mLogger.trace( "CollectionSchemeIngestion::serializeNode", - "Creating FLOAT node with value: " + std::to_string( currentNode->floatingValue ) ); + FWE_LOG_TRACE( "Creating FLOAT node with value: " + std::to_string( currentNode->floatingValue ) ); return currentNode; } else if ( node.node_case() == CollectionSchemesMsg::ConditionNode::kNodeBooleanValue ) { currentNode->booleanValue = node.node_boolean_value(); currentNode->nodeType = ExpressionNodeType::BOOLEAN; - mLogger.trace( "CollectionSchemeIngestion::serializeNode", - "Creating BOOLEAN node with value: " + - std::to_string( static_cast( currentNode->booleanValue ) ) ); + FWE_LOG_TRACE( "Creating BOOLEAN node with value: " + + std::to_string( static_cast( currentNode->booleanValue ) ) ); return currentNode; } else if ( node.node_case() == CollectionSchemesMsg::ConditionNode::kNodeFunction ) @@ -353,8 +340,7 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN currentNode->function.windowFunction = convertFunctionType( node.node_function().window_function().window_type() ); currentNode->nodeType = ExpressionNodeType::WINDOWFUNCTION; - mLogger.trace( "CollectionSchemeIngestion::serializeNode", - "Creating Window FUNCTION node for Signal ID:" + std::to_string( currentNode->signalID ) ); + FWE_LOG_TRACE( "Creating Window FUNCTION node for Signal ID:" + std::to_string( currentNode->signalID ) ); return currentNode; } else if ( node.node_function().functionType_case() == @@ -369,20 +355,20 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN static_cast( node.node_function().geohash_function().geohash_precision() ); currentNode->function.geohashFunction.gpsUnitType = static_cast( node.node_function().geohash_function().gps_unit() ); - mLogger.trace( - "CollectionSchemeIngestion::serializeNode", + FWE_LOG_TRACE( + "Creating Geohash FUNCTION node: Lat SignalID: " + - std::to_string( currentNode->function.geohashFunction.latitudeSignalID ) + - "; Lon SignalID: " + std::to_string( currentNode->function.geohashFunction.longitudeSignalID ) + - "; precision: " + std::to_string( currentNode->function.geohashFunction.precision ) + - "; GPS Unit Type: " + - std::to_string( static_cast( currentNode->function.geohashFunction.gpsUnitType ) ) ); + std::to_string( currentNode->function.geohashFunction.latitudeSignalID ) + + "; Lon SignalID: " + std::to_string( currentNode->function.geohashFunction.longitudeSignalID ) + + "; precision: " + std::to_string( currentNode->function.geohashFunction.precision ) + + "; GPS Unit Type: " + + std::to_string( static_cast( currentNode->function.geohashFunction.gpsUnitType ) ) ); return currentNode; } else { // unsupported function type - mLogger.warn( "CollectionSchemeIngestion::serializeNode", "Unsupported Function Node Type" ); + FWE_LOG_WARN( "Unsupported Function Node Type" ); } } else if ( node.node_case() == CollectionSchemesMsg::ConditionNode::kNodeOperator ) @@ -390,12 +376,12 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN // If no left node this node_operator is invalid if ( node.node_operator().has_left_child() ) { - mLogger.trace( "CollectionSchemeIngestion::serializeNode", "Processing left child" ); + FWE_LOG_TRACE( "Processing left child" ); currentNode->nodeType = convertOperatorType( node.node_operator().operator_() ); // If no valid function found return always false if ( currentNode->nodeType == ExpressionNodeType::BOOLEAN ) { - mLogger.info( "CollectionSchemeIngestion::serializeNode", "Setting BOOLEAN node to false" ); + FWE_LOG_INFO( "Setting BOOLEAN node to false" ); currentNode->booleanValue = false; return currentNode; } @@ -405,14 +391,14 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN if ( ( currentNode->nodeType != ExpressionNodeType::OPERATOR_LOGICAL_NOT ) && node.node_operator().has_right_child() ) { - mLogger.trace( "CollectionSchemeIngestion::serializeNode", "Processing right child" ); + FWE_LOG_TRACE( "Processing right child" ); ExpressionNode *right = serializeNode( node.node_operator().right_child(), nextIndex, remainingDepth - 1 ); currentNode->right = right; } else { - mLogger.trace( "CollectionSchemeIngestion::serializeNode", "Setting right child to nullptr" ); + FWE_LOG_TRACE( "Setting right child to nullptr" ); currentNode->right = nullptr; } return currentNode; diff --git a/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp b/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp index a900b3c4..a9108eca 100644 --- a/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp +++ b/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionSchemeIngestionList.h" +#include "LoggingModule.h" #include namespace Aws @@ -38,14 +39,14 @@ CollectionSchemeIngestionList::copyData( const std::uint8_t *inputBuffer, const if ( ( inputBuffer == nullptr ) || ( size == 0 ) ) { // Error, input buffer empty or invalid - mLogger.error( "CollectionSchemeIngestionList::copyData", "Input buffer empty" ); + FWE_LOG_ERROR( "Input buffer empty" ); return false; } // We have to guard against document sizes that are too large if ( size > COLLECTION_SCHEME_LIST_BYTE_SIZE_LIMIT ) { - mLogger.error( "CollectionSchemeIngestionList::copyData", "Collection Schema document is too big, ignoring" ); + FWE_LOG_ERROR( "Collection Schema document is too big, ignoring" ); return false; } @@ -55,11 +56,11 @@ CollectionSchemeIngestionList::copyData( const std::uint8_t *inputBuffer, const // Check to make sure the vector size is the same as our input size if ( mProtoBinaryData.size() != size ) { - mLogger.error( "CollectionSchemeIngestionList::copyData", "Copied data size doesn't match" ); + FWE_LOG_ERROR( "Copied data size doesn't match" ); return false; } - mLogger.trace( "CollectionSchemeIngestionList::copyData", "Collection Scheme Data copied successfully" ); + FWE_LOG_TRACE( "Collection Scheme Data copied successfully" ); return true; } @@ -80,12 +81,12 @@ CollectionSchemeIngestionList::build() // version of the headers we compiled with. GOOGLE_PROTOBUF_VERIFY_VERSION; - mLogger.trace( "CollectionSchemeIngestionList::build", "Building CollectionScheme list" ); + FWE_LOG_TRACE( "Building CollectionScheme list" ); // Ensure that we have data to parse if ( mProtoBinaryData.empty() || ( mProtoBinaryData.data() == nullptr ) ) { - mLogger.error( "CollectionSchemeIngestionList::build", "Input buffer empty" ); + FWE_LOG_ERROR( "Input buffer empty" ); // Error, input buffer empty or invalid return false; } @@ -95,7 +96,7 @@ CollectionSchemeIngestionList::build() static_cast( mProtoBinaryData.size() ) ) ) { // Error parsing proto binary - mLogger.error( "CollectionSchemeIngestionList::build", "Error parsing collectionSchemes.proto binary" ); + FWE_LOG_ERROR( "Error parsing collectionSchemes.proto binary" ); return false; } @@ -115,9 +116,8 @@ CollectionSchemeIngestionList::build() // Check to see if it successfully builds if ( pICPPtr->build() ) { - mLogger.trace( "CollectionSchemeIngestionList::build", - "Adding CollectionScheme index: " + std::to_string( i ) + " of " + - std::to_string( mCollectionSchemeListMsg.collection_schemes_size() ) ); + FWE_LOG_TRACE( "Adding CollectionScheme index: " + std::to_string( i ) + " of " + + std::to_string( mCollectionSchemeListMsg.collection_schemes_size() ) ); // Add this newly created shared pointer to the vector of ICollectionScheme shared pointers. // It is implicitly upcasted to its base pointer @@ -125,12 +125,11 @@ CollectionSchemeIngestionList::build() } else { - mLogger.error( "CollectionSchemeIngestionList::build", - "CollectionScheme index: " + std::to_string( i ) + " failed to build, dropping it" ); + FWE_LOG_ERROR( "CollectionScheme index: " + std::to_string( i ) + " failed to build, dropping it. " ); } } - mLogger.trace( "CollectionSchemeIngestionList::build", "Building CollectionScheme List complete" ); + FWE_LOG_TRACE( "Building CollectionScheme List complete" ); // Set the ready flag to true, as the collection collectionSchemes are ready to read mReady = true; diff --git a/src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp b/src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp deleted file mode 100644 index 2ffb2776..00000000 --- a/src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -// Includes -#include "CollectionSchemeJSONParser.h" -#include "datatypes/VehicleDataSourceTypes.h" -#include -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ - -CollectionSchemeJSONParser::CollectionSchemeJSONParser( const std::string &path ) -{ - mPath = path; - mCollectionScheme.reset( new CollectionScheme() ); -} - -bool -CollectionSchemeJSONParser::parse() -{ - std::ifstream collectionSchemeFile( mPath, std::ifstream::in ); - if ( collectionSchemeFile.is_open() ) - { - Json::Value root; - Json::CharReaderBuilder builder; - JSONCPP_STRING errs; - bool success = parseFromStream( builder, collectionSchemeFile, &root, &errs ); - if ( !success ) - { - mLogger.error( "CollectionSchemeJSONParser::parse", "Failed to parse the collectionScheme file: " + mPath ); - return false; - } - mCollectionScheme->setVersion( root["version"].asString() ); - mCollectionScheme->setCollectionSchemeID( root["collectionSchemeID"].asString() ); - mCollectionScheme->setEventType( root["eventType"].asString() ); - mCollectionScheme->setEventID( root["eventID"].asUInt64() ); - const auto eventTriggers = root["eventTriggers"]; - const auto eventMessages = root["eventMessages"]; - EventTriggers triggers; - // Triggers - for ( unsigned int i = 0; i < eventTriggers.size(); ++i ) - { - EventTrigger trigger; - // Trigger - const std::string triggerType = eventTriggers[i]["triggerType"].asString(); - if ( triggerType == "timepoint" ) - { - trigger.mTriggerType = TriggerType::TIMEPOINT; - } - else if ( triggerType == "signalvalue" ) - { - trigger.mTriggerType = TriggerType::SIGNALVALUE; - } - // Predicate - // Condition - const std::string condition = eventTriggers[i]["valuePredicate"]["condition"].asString(); - if ( condition == "every" ) - { - trigger.mValuePredicate.mCondition = PredicateCondition::EVERY; - } - else if ( condition == "equal" ) - { - trigger.mValuePredicate.mCondition = PredicateCondition::EQUAL; - } - else if ( condition == "less" ) - { - trigger.mValuePredicate.mCondition = PredicateCondition::LESS; - } - else if ( condition == "bigger" ) - { - trigger.mValuePredicate.mCondition = PredicateCondition::BIGGER; - } - // Value - trigger.mValuePredicate.mValue = eventTriggers[i]["valuePredicate"]["value"].asDouble(); - // SignalID - if ( trigger.mTriggerType == TriggerType::SIGNALVALUE ) - { - trigger.mSignalID = eventTriggers[i]["valuePredicate"]["signalID"].asUInt(); - trigger.mParentMessageID = eventTriggers[i]["valuePredicate"]["messageID"].asUInt(); - mCollectionScheme->insertSignalTriggerToMessage( trigger.mParentMessageID, trigger ); - } - if ( trigger.mTriggerType == TriggerType::TIMEPOINT ) - { - mCollectionScheme->setTimeTrigger( trigger ); - } - else - { - triggers.emplace_back( trigger ); - } - } - mCollectionScheme->setEventTriggers( triggers ); - // Messages - for ( unsigned int i = 0; i < eventMessages.size(); ++i ) - { - CANMessageFormat message; - message.mMessageID = eventMessages[i]["messageID"].asUInt(); - message.mSizeInBytes = static_cast( eventMessages[i]["sizeInBytes"].asUInt() ); - message.mIsMultiplexed = eventMessages[i]["isMultiplexed"].asBool(); - const auto signals = eventMessages[i]["signals"]; - for ( unsigned int j = 0; j < signals.size(); ++j ) - { - CANSignalFormat signal; - signal.mSignalID = signals[j]["signalID"].asUInt(); - signal.mIsBigEndian = signals[j]["isBigEndian"].asBool(); - signal.mIsSigned = signals[j]["isSigned"].asBool(); - signal.mFirstBitPosition = static_cast( signals[j]["firstBitPosition"].asUInt() ); - signal.mSizeInBits = static_cast( signals[j]["sizeInBits"].asUInt() ); - signal.mOffset = signals[j]["offset"].asDouble(); - signal.mFactor = signals[j]["factor"].asDouble(); - signal.mIsMultiplexorSignal = signals[j]["isMultiplexer"].asBool(); - signal.mMultiplexorValue = static_cast( signals[j]["multiplexerValue"].asUInt() ); - message.mSignals.emplace_back( signal ); - } - mCollectionScheme->insertMessageToCollected( message.mMessageID, message ); - } - - collectionSchemeFile.close(); - return true; - } - else - { - mLogger.error( "CollectionSchemeJSONParser::parse", "Failed to open the collectionScheme file: " + mPath ); - return false; - } -} - -bool -CollectionSchemeJSONParser::reLoad() -{ - std::lock_guard lock( mMutex ); - mCollectionScheme->clear(); - bool success = parse(); - return success; -} - -CollectionSchemePtr -CollectionSchemeJSONParser::getCollectionScheme() -{ - std::lock_guard lock( mMutex ); - return mCollectionScheme; -} - -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp b/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp deleted file mode 100644 index 7d448e8d..00000000 --- a/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -// Includes -#include "DataCollectionJSONWriter.h" -#include - -#include -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ - -namespace -{ -constexpr char JSON_FILE_EXT[] = ".json"; -constexpr char SNAPPY_FILE_EXT[] = ".snappy"; - -constexpr char EVENT_KEY[] = "Event"; -constexpr char COLLECTION_SCHEME_ARN_KEY[] = "collectionSchemeARN"; -constexpr char DECODER_ARN_KEY[] = "decoderARN"; -constexpr char COLLECTION_EVENT_ID_KEY[] = "collectionEventID"; -constexpr char COLLECTION_EVENT_TIME_KEY[] = "collectionEventTimeMSEpoch"; - -constexpr char PATH_SEP = '/'; - -} // namespace - -DataCollectionJSONWriter::DataCollectionJSONWriter( std::string persistencyPath ) - : mPersistencyPath( std::move( persistencyPath ) ) -{ -} - -void -DataCollectionJSONWriter::append( const CollectedCanRawFrame &msg ) -{ - Json::Value message; - message["CANFrame"]["messageID"] = (Json::UInt)msg.frameID; - message["CANFrame"]["nodeID"] = (Json::UInt)msg.channelId; - message["CANFrame"]["relativeTimeMS"] = ( Json::Int64 )( ( msg.receiveTime ) - mTriggerTime ); - - Json::Value signals( Json::arrayValue ); - Json::Value signal; - for ( size_t i = 0; i < msg.size; ++i ) - { - signal["CANFrame"]["byteValue"] = msg.data[i]; - signals.append( signal ); - } - message["CANFrame"]["byteValues"] = signals; - mMessages.append( message ); -} - -void -DataCollectionJSONWriter::append( const CollectedSignal &msg ) -{ - Json::Value message; - message["CapturedSignal"]["signalID"] = (Json::UInt)msg.signalID; - message["CapturedSignal"]["relativeTimeMS"] = ( Json::Int64 )( ( msg.receiveTime ) - mTriggerTime ); - message["CapturedSignal"]["doubleValue"] = msg.value; - mMessages.append( message ); -} - -void -DataCollectionJSONWriter::append( const GeohashInfo &geohashInfo ) -{ - Json::Value message; - message["Geohash"] = geohashInfo.mGeohashString; - message["PrevReportedGeohash"] = geohashInfo.mPrevReportedGeohashString; - mMessages.append( message ); -} - -std::pair -DataCollectionJSONWriter::flushToFile() -{ - std::string eventId = "NoEventID"; - if ( mEvent.isMember( EVENT_KEY ) && mEvent[EVENT_KEY].isMember( COLLECTION_EVENT_ID_KEY ) ) - { - eventId = std::to_string( mEvent[EVENT_KEY][COLLECTION_EVENT_ID_KEY].asUInt() ); - } - - static constexpr char SEP = '-'; - std::ostringstream oss; - oss << "IoTFleetWise" << SEP << "Data" << SEP << eventId << SEP - << std::to_string( mClock->systemTimeSinceEpochMs() ); - return flushToFile( oss.str() ); -} - -std::pair -DataCollectionJSONWriter::flushToFile( const std::string &fileBaseName ) -{ - constexpr char FUNC_NAME[] = "DataCollectionJSONWriter::flushToFile"; - - mLogger.trace( FUNC_NAME, "Base file name: " + fileBaseName ); - mEvent["Messages"] = mMessages; - Json::StreamWriterBuilder builder; - builder["commentStyle"] = "None"; - builder["indentation"] = " "; // or whatever you like - std::unique_ptr writer( builder.newStreamWriter() ); - std::ostringstream ss; - writer->write( mEvent, &ss ); - - auto data = ss.str(); - std::string outData; - bool didCompress = false; - if ( mShouldCompress ) - { - mLogger.trace( FUNC_NAME, "File contents will be compressed" ); - if ( snappy::Compress( data.data(), data.size(), &outData ) == 0u ) - { - mLogger.warn( FUNC_NAME, "Compression resulted in 0 bytes. Writing uncompressed file content" ); - outData = std::move( data ); - } - else - { - didCompress = true; - } - } - else - { - mLogger.trace( FUNC_NAME, "File contents will be uncompressed" ); - outData = std::move( data ); - } - - auto fileCloser = []( std::ofstream *fs ) { fs->close(); }; - std::ofstream ofs; - std::unique_ptr fileHandle( &ofs, fileCloser ); - - const std::string fileExt = didCompress ? SNAPPY_FILE_EXT : JSON_FILE_EXT; - const auto fileNameWithExt = mPersistencyPath + PATH_SEP + fileBaseName + fileExt; - ofs.open( fileNameWithExt, std::ios::out | std::ios::binary ); - ofs.write( outData.c_str(), static_cast( outData.size() ) ); - mLogger.trace( FUNC_NAME, "File write completed. File: " + fileNameWithExt ); - - return std::make_pair( boost::filesystem::path( fileNameWithExt ), didCompress ); -} - -void -DataCollectionJSONWriter::setupEvent( const TriggeredCollectionSchemeDataPtr triggeredCollectionSchemeData, - uint32_t collectionEventID ) -{ - mEvent.clear(); - mMessages.clear(); - mEvent[EVENT_KEY][COLLECTION_SCHEME_ARN_KEY] = triggeredCollectionSchemeData->metaData.collectionSchemeID; - mEvent[EVENT_KEY][DECODER_ARN_KEY] = triggeredCollectionSchemeData->metaData.decoderID; - mEvent[EVENT_KEY][COLLECTION_EVENT_ID_KEY] = (Json::UInt)collectionEventID; - mEvent[EVENT_KEY][COLLECTION_EVENT_TIME_KEY] = ( Json::UInt64 )( triggeredCollectionSchemeData->triggerTime ); - mTriggerTime = triggeredCollectionSchemeData->triggerTime; - mShouldCompress = triggeredCollectionSchemeData->metaData.compress; -} - -unsigned -DataCollectionJSONWriter::getJSONMessageCount() const -{ - return mMessages.size(); -} - -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/datamanagement/datacollection/src/DataCollectionProtoWriter.cpp b/src/datamanagement/datacollection/src/DataCollectionProtoWriter.cpp index e34ebdc0..69822712 100644 --- a/src/datamanagement/datacollection/src/DataCollectionProtoWriter.cpp +++ b/src/datamanagement/datacollection/src/DataCollectionProtoWriter.cpp @@ -43,7 +43,50 @@ DataCollectionProtoWriter::append( const CollectedSignal &msg ) capturedSignals->set_relative_time_ms( static_cast( msg.receiveTime ) - static_cast( mTriggerTime ) ); capturedSignals->set_signal_id( msg.signalID ); - capturedSignals->set_double_value( msg.value ); + auto signalValue = msg.getValue(); + // TODO :: Change the datatype of the signal here when the DataPlane supports it + double signalPhysicalValue{ 0 }; + switch ( signalValue.getType() ) + { + + case SignalType::UINT8: + signalPhysicalValue = static_cast( signalValue.value.uint8Val ); + break; + case SignalType::INT8: + signalPhysicalValue = static_cast( signalValue.value.int8Val ); + break; + case SignalType::UINT16: + signalPhysicalValue = static_cast( signalValue.value.uint16Val ); + break; + case SignalType::INT16: + signalPhysicalValue = static_cast( signalValue.value.int16Val ); + break; + case SignalType::UINT32: + signalPhysicalValue = static_cast( signalValue.value.uint32Val ); + break; + case SignalType::INT32: + signalPhysicalValue = static_cast( signalValue.value.int32Val ); + break; + case SignalType::UINT64: + signalPhysicalValue = static_cast( signalValue.value.uint64Val ); + break; + case SignalType::INT64: + signalPhysicalValue = static_cast( signalValue.value.int64Val ); + break; + case SignalType::FLOAT: + signalPhysicalValue = static_cast( signalValue.value.floatVal ); + break; + case SignalType::DOUBLE: + signalPhysicalValue = signalValue.value.doubleVal; + break; + case SignalType::BOOLEAN: + signalPhysicalValue = static_cast( signalValue.value.boolVal ); + break; + default: + signalPhysicalValue = signalValue.value.doubleVal; + break; + } + capturedSignals->set_double_value( signalPhysicalValue ); } void diff --git a/src/datamanagement/datacollection/src/DataCollectionSender.cpp b/src/datamanagement/datacollection/src/DataCollectionSender.cpp index 258d895f..9adde299 100644 --- a/src/datamanagement/datacollection/src/DataCollectionSender.cpp +++ b/src/datamanagement/datacollection/src/DataCollectionSender.cpp @@ -3,6 +3,7 @@ // Includes #include "DataCollectionSender.h" +#include "LoggingModule.h" #include #include #include @@ -15,14 +16,10 @@ namespace DataManagement { DataCollectionSender::DataCollectionSender( std::shared_ptr sender, - bool jsonOutputEnabled, unsigned maxMessageCount, - CANInterfaceIDTranslator &canIDTranslator, - std::string persistencyPath ) + CANInterfaceIDTranslator &canIDTranslator ) : mSender( std::move( sender ) ) - , mJsonOutputEnabled( jsonOutputEnabled ) , mProtoWriter( canIDTranslator ) - , mJsonWriter( std::move( persistencyPath ) ) { mTransmitThreshold = ( maxMessageCount > 0U ) ? maxMessageCount : UINT_MAX; mCollectionEventID = 0U; @@ -33,7 +30,7 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl { if ( triggeredCollectionSchemeDataPtr == nullptr ) { - mLogger.warn( "DataCollectionSender::send", "Nothing to send as the input is empty" ); + FWE_LOG_WARN( "Nothing to send as the input is empty" ); return; } @@ -42,11 +39,6 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl setCollectionSchemeParameters( triggeredCollectionSchemeDataPtr ); - if ( mJsonOutputEnabled ) - { - mJsonWriter.setupEvent( triggeredCollectionSchemeDataPtr, mCollectionEventID ); - } - if ( mSendDestination == SendDestination::MQTT ) { mProtoWriter.setupVehicleData( triggeredCollectionSchemeDataPtr, mCollectionEventID ); @@ -55,10 +47,6 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl // Iterate through all the signals and add to the protobuf for ( const auto &signal : triggeredCollectionSchemeDataPtr->signals ) { - if ( mJsonOutputEnabled ) - { - mJsonWriter.append( signal ); - } if ( mSendDestination == SendDestination::MQTT ) { mProtoWriter.append( signal ); @@ -74,10 +62,6 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl // Iterate through all the raw CAN frames and add to the protobuf for ( const auto &canFrame : triggeredCollectionSchemeDataPtr->canFrames ) { - if ( mJsonOutputEnabled ) - { - mJsonWriter.append( canFrame ); - } if ( mSendDestination == SendDestination::MQTT ) { mProtoWriter.append( canFrame ); @@ -118,10 +102,6 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl // Add Geohash to the payload if ( triggeredCollectionSchemeDataPtr->mGeohashInfo.hasItems() ) { - if ( mJsonOutputEnabled ) - { - mJsonWriter.append( triggeredCollectionSchemeDataPtr->mGeohashInfo ); - } if ( mSendDestination == SendDestination::MQTT ) { mProtoWriter.append( triggeredCollectionSchemeDataPtr->mGeohashInfo ); @@ -134,17 +114,12 @@ DataCollectionSender::send( const TriggeredCollectionSchemeDataPtr triggeredColl } } - if ( mJsonOutputEnabled && ( mJsonWriter.getJSONMessageCount() > 0U ) ) - { - const auto result = mJsonWriter.flushToFile(); - } if ( mSendDestination == SendDestination::MQTT ) { // Serialize and transmit any remaining messages if ( mProtoWriter.getVehicleDataMsgCount() >= 1U ) { - mLogger.trace( "DataCollectionSender::send", - "The data collection snapshot has been written on disk and is now scheduled for upload to " + FWE_LOG_TRACE( "The data collection snapshot has been written on disk and is now scheduled for upload to " "AWS IoT Core" ); serializeAndTransmit(); } @@ -156,8 +131,7 @@ DataCollectionSender::transmit() { if ( mSendDestination != SendDestination::MQTT ) { - mLogger.trace( "DataCollectionSender::transmit", - "Upload destination is not set to AWS IoT Core. Skipping this request" ); + FWE_LOG_TRACE( "Upload destination is not set to AWS IoT Core. Skipping this request" ); return ConnectivityError::Success; } @@ -165,11 +139,10 @@ DataCollectionSender::transmit() // compress the data before transmitting if specified in the collectionScheme if ( mCollectionSchemeParams.compression ) { - mLogger.trace( "DataCollectionSender::transmit", - "Compress the payload before transmitting since compression flag is true" ); + FWE_LOG_TRACE( "Compress the payload before transmitting since compression flag is true" ); if ( snappy::Compress( mProtoOutput.data(), mProtoOutput.size(), &payloadData ) == 0u ) { - mLogger.trace( "DataCollectionSender::transmit", "Error in compressing the payload" ); + FWE_LOG_TRACE( "Error in compressing the payload" ); return ConnectivityError::WrongInputData; } } @@ -179,18 +152,16 @@ DataCollectionSender::transmit() payloadData = mProtoOutput; } - ConnectivityError ret = mSender->send( + ConnectivityError ret = mSender->sendBuffer( reinterpret_cast( payloadData.data() ), payloadData.size(), mCollectionSchemeParams ); if ( ret != ConnectivityError::Success ) { - mLogger.error( "DataCollectionSender::transmit", - "Failed to send vehicle data proto with error: " + std::to_string( static_cast( ret ) ) ); + FWE_LOG_ERROR( "Failed to send vehicle data proto with error: " + std::to_string( static_cast( ret ) ) ); } else { - mLogger.info( "DataCollectionSender::transmit", - "A Payload of size: " + std::to_string( payloadData.length() ) + - " bytes has been unloaded to AWS IoT Core" ); + FWE_LOG_INFO( "A Payload of size: " + std::to_string( payloadData.length() ) + + " bytes has been unloaded to AWS IoT Core" ); } return ret; } @@ -200,16 +171,14 @@ DataCollectionSender::transmit( const std::string &payload ) { if ( mSendDestination != SendDestination::MQTT ) { - mLogger.trace( "DataCollectionSender::transmit", - "Upload destination is not set to AWS IoT Core. Skipping this request" ); + FWE_LOG_TRACE( "Upload destination is not set to AWS IoT Core. Skipping this request" ); return ConnectivityError::WrongInputData; } - auto res = mSender->send( reinterpret_cast( payload.data() ), payload.size() ); + auto res = mSender->sendBuffer( reinterpret_cast( payload.data() ), payload.size() ); if ( res != ConnectivityError::Success ) { - mLogger.error( "DataCollectionSender::transmit", - "offboardconnectivity error " + std::to_string( static_cast( res ) ) ); + FWE_LOG_ERROR( "offboardconnectivity error " + std::to_string( static_cast( res ) ) ); } return res; } @@ -219,15 +188,14 @@ DataCollectionSender::serializeAndTransmit() { if ( mSendDestination != SendDestination::MQTT ) { - mLogger.trace( "DataCollectionSender::serializeAndTransmit", - "Upload destination is not set to AWS IoT Core. Skipping this request" ); + FWE_LOG_TRACE( "Upload destination is not set to AWS IoT Core. Skipping this request" ); return; } // Note: a class member is used to store the serialized proto output to avoid heap fragmentation if ( !mProtoWriter.serializeVehicleData( &mProtoOutput ) ) { - mLogger.error( "DataCollectionSender::serializeAndTransmit", "serialization failed" ); + FWE_LOG_ERROR( "serialization failed" ); } else { @@ -235,9 +203,8 @@ DataCollectionSender::serializeAndTransmit() auto res = transmit(); if ( res != ConnectivityError::Success ) { - mLogger.error( "DataCollectionSender::serializeAndTransmit", - "offboardconnectivity error while transmitting data" + - std::to_string( static_cast( res ) ) ); + FWE_LOG_ERROR( "offboardconnectivity error while transmitting data" + + std::to_string( static_cast( res ) ) ); } } } diff --git a/src/datamanagement/datacollection/test/CollectionSchemeJSONParserTest.cpp b/src/datamanagement/datacollection/test/CollectionSchemeJSONParserTest.cpp deleted file mode 100644 index e3244c9e..00000000 --- a/src/datamanagement/datacollection/test/CollectionSchemeJSONParserTest.cpp +++ /dev/null @@ -1,59 +0,0 @@ - -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include "CollectionSchemeJSONParser.h" -#include -#include - -using namespace Aws::IoTFleetWise::DataManagement; - -TEST( CollectionSchemeJSONParserTest, CollectionSchemeJSONParserSignalTrigger ) -{ - CollectionSchemeJSONParser parser( "dm-collection-scheme-example.json" ); - ASSERT_TRUE( parser.parse() ); - ASSERT_EQ( parser.getCollectionScheme()->getVersion(), "1.0" ); - ASSERT_EQ( parser.getCollectionScheme()->getCollectionSchemeID(), "arn::testCollectionScheme" ); - ASSERT_EQ( parser.getCollectionScheme()->getEventType(), "heartbeat" ); - ASSERT_EQ( parser.getCollectionScheme()->getCollectedCANMessages().size(), 3 ); - ASSERT_EQ( parser.getCollectionScheme()->getWatchedCANMessages().size(), 2 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers().size(), 2 ); - - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[0].mTriggerType, TriggerType::SIGNALVALUE ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[1].mTriggerType, TriggerType::SIGNALVALUE ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[0].mValuePredicate.mCondition, - PredicateCondition::LESS ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[1].mValuePredicate.mCondition, - PredicateCondition::BIGGER ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[0].mValuePredicate.mValue, 1 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[1].mValuePredicate.mValue, 1 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[0].mSignalID, 10 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[1].mSignalID, 30 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[0].mParentMessageID, 123 ); - ASSERT_EQ( parser.getCollectionScheme()->getEventTriggers()[1].mParentMessageID, 456 ); - CANMessageFormat f123 = parser.getCollectionScheme()->getCANMessageFormat( 123 ); - CANMessageFormat f456 = parser.getCollectionScheme()->getCANMessageFormat( 456 ); - ASSERT_TRUE( f123.isValid() ); - ASSERT_EQ( f123.mSignals.size(), 2 ); - ASSERT_TRUE( f456.isValid() ); - ASSERT_EQ( f456.mSignals.size(), 2 ); - ASSERT_TRUE( f123 != f456 ); -} - -TEST( CollectionSchemeJSONParserTest, CollectionSchemeJSONParserTimeTrigger ) -{ - CollectionSchemeJSONParser parser( "dm-collection-scheme-example.json" ); - ASSERT_TRUE( parser.parse() ); - ASSERT_TRUE( parser.getCollectionScheme()->getTimeTrigger().isValid() ); - ASSERT_EQ( parser.getCollectionScheme()->getTimeTrigger().mValuePredicate.mCondition, PredicateCondition::EVERY ); - ASSERT_EQ( parser.getCollectionScheme()->getTimeTrigger().mValuePredicate.mValue, 10 ); -} - -TEST( CollectionSchemeJSONParserTest, CollectionSchemeJSONParserMultiplexer ) -{ - CollectionSchemeJSONParser parser( "dm-collection-scheme-example.json" ); - ASSERT_TRUE( parser.parse() ); - ASSERT_EQ( parser.getCollectionScheme()->getCollectedCANMessages().size(), 3 ); - auto it = parser.getCollectionScheme()->getCollectedCANMessages().find( 678 ); - ASSERT_TRUE( it->second.isMultiplexed() ); -} diff --git a/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp b/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp deleted file mode 100644 index acc19a0c..00000000 --- a/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "DataCollectionJSONWriter.h" - -using namespace Aws::IoTFleetWise::DataManagement; -using namespace Aws::IoTFleetWise::Platform::Linux; - -using ::testing::HasSubstr; - -namespace -{ - -static constexpr int collectionEventID = 10; -static constexpr uint64_t testTimestamp = 1000; -static constexpr char EVENT_KEY[] = "Event"; -static constexpr char MESSAGES_KEY[] = "Messages"; -static constexpr char SIGNAL_KEY[] = "CapturedSignal"; -static constexpr char SIGNAL_VAL_KEY[] = "doubleValue"; -static constexpr char SIGNAL_TIME_KEY[] = "relativeTimeMS"; -static constexpr char SIGNAL_ID_KEY[] = "signalID"; -static constexpr char COLLECTION_EVENT_ID_KEY[] = "collectionEventID"; - -static constexpr char JSON_FILE_EXT[] = "json"; -static constexpr char SNAPPY_FILE_EXT[] = "snappy"; - -/** - * @brief Helper function to read the binary contents of a file. - * - * @param fs File stream - * @return std::string Contents of the file - */ -std::string -readFile( std::ifstream &fs ) -{ - std::stringstream buffer; - buffer << fs.rdbuf(); - return buffer.str(); -} - -/** - * @brief Assert that the JSON value conforms to the expected signals - * - * @param expectedSignals The expected signals to compare against - * @param root The root of the JSON document to compare - */ -void -assertEventData( const std::vector &expectedSignals, const Json::Value &root ) -{ - const auto &event = root[EVENT_KEY]; - ASSERT_EQ( collectionEventID, event[COLLECTION_EVENT_ID_KEY].asInt() ); - const auto &messages = root[MESSAGES_KEY]; - ASSERT_EQ( messages.size(), expectedSignals.size() ); - for ( size_t i = 0; i < messages.size(); ++i ) - { - const auto &msg = messages[static_cast( i )]; - const auto &sig = msg[SIGNAL_KEY]; - const auto &expectedSig = expectedSignals[i]; - ASSERT_DOUBLE_EQ( expectedSig.value, sig[SIGNAL_VAL_KEY].asDouble() ); - ASSERT_EQ( expectedSig.receiveTime, sig[SIGNAL_TIME_KEY].asInt() ); - ASSERT_DOUBLE_EQ( expectedSig.signalID, sig[SIGNAL_ID_KEY].asInt() ); - } -} - -} // namespace - -class DataCollectionJSONWriterTest : public ::testing::TestWithParam> -{ -protected: - void - TearDown() override - { - // remove the file if it exists - std::ifstream f( mFileName.c_str() ); - if ( f.good() ) - { - std::remove( mFileName.c_str() ); - } - } - - /** - * @brief Helper function for test cases to assert the event data written to JSON. - * - * @param signals Expected signals to be present in the output files - * @param expectedToCompress Whether compression is expected or not. - */ - void - testEventData( const std::vector &signals, bool expectedToCompress ) - { - DataCollectionJSONWriter writer{ mTmpDir.generic_string() }; - writer.setupEvent( schemaDataPtr, collectionEventID ); - for ( const auto &sig : signals ) - { - writer.append( sig ); - } - - const auto res = writer.flushToFile(); - mFileName = res.first.filename().generic_string(); - EXPECT_THAT( mFileName, HasSubstr( std::to_string( collectionEventID ) ) ); - ASSERT_EQ( expectedToCompress, res.second ); - - auto fileCloser = []( std::ifstream *fs ) { fs->close(); }; - std::ifstream fs( res.first.generic_string(), std::ifstream::binary ); - std::unique_ptr fh( &fs, fileCloser ); - ASSERT_TRUE( fs.good() ); - - auto data = readFile( fs ); - std::string inData; - if ( schemaDataPtr->metaData.compress ) - { - EXPECT_THAT( mFileName, HasSubstr( SNAPPY_FILE_EXT ) ); - const bool status = snappy::Uncompress( data.data(), data.size(), &inData ); - ASSERT_TRUE( status ); - } - else - { - EXPECT_THAT( mFileName, HasSubstr( JSON_FILE_EXT ) ); - inData = std::move( data ); - } - - Json::Value root; - Json::Reader reader; - ASSERT_TRUE( reader.parse( inData, root ) ); - ASSERT_FALSE( root.empty() ); - assertEventData( signals, root ); - } - - std::shared_ptr schemaDataPtr = std::make_shared(); - std::string mFileName; - boost::filesystem::path mTmpDir = boost::filesystem::temp_directory_path(); -}; - -/** - * @brief Tests the event writing to JSON for - * 1. Different signals size - * 2. with/without compression - * - */ -TEST_P( DataCollectionJSONWriterTest, TestSingleEventWithSignals ) -{ - const size_t numSignals = std::get<0>( GetParam() ); - schemaDataPtr->metaData.compress = std::get<1>( GetParam() ); - - constexpr uint64_t signalT = 2000; - constexpr double signalVal = 1.0; - std::vector signals; - for ( size_t i = 0; i < numSignals; ++i ) - { - signals.emplace_back( i + 1, signalT + ( i * 1000 ), signalVal ); - } - - testEventData( signals, schemaDataPtr->metaData.compress ); -} - -INSTANTIATE_TEST_CASE_P( DataCollectionJSONWriterTestSuite, - DataCollectionJSONWriterTest, - ::testing::Values( std::make_tuple( 0, false ), - std::make_tuple( 0, true ), - std::make_tuple( 1, false ), - std::make_tuple( 10, false ), - std::make_tuple( 1, false ), - std::make_tuple( 10, true ) ) ); diff --git a/src/datamanagement/datacollection/test/DataCollectionProtoWriterTest.cpp b/src/datamanagement/datacollection/test/DataCollectionProtoWriterTest.cpp index f8eadec6..1491b3a2 100644 --- a/src/datamanagement/datacollection/test/DataCollectionProtoWriterTest.cpp +++ b/src/datamanagement/datacollection/test/DataCollectionProtoWriterTest.cpp @@ -3,9 +3,11 @@ #include "DataCollectionProtoWriter.h" #include "ClockHandler.h" +#include "Testing.h" #include #include +using namespace Aws::IoTFleetWise::TestingSupport; using namespace Aws::IoTFleetWise::DataManagement; using namespace Aws::IoTFleetWise::Platform::Linux; @@ -45,7 +47,8 @@ TEST_F( DataCollectionProtoWriterTest, TestVehicleData ) uint32_t collectionEventID = std::rand(); protoWriter.setupVehicleData( triggeredCollectionSchemeDataPtr, collectionEventID ); - CollectedSignal collectedSignalMsg( 120 /*signalId*/, testTriggerTime + 2000 /*receiveTime*/, 77.88 /*value*/ ); + CollectedSignal collectedSignalMsg( + 120 /*signalId*/, testTriggerTime + 2000 /*receiveTime*/, 77.88 /*value*/, SignalType::DOUBLE ); protoWriter.append( collectedSignalMsg ); EXPECT_EQ( protoWriter.getVehicleDataMsgCount(), 1 ); diff --git a/src/datamanagement/datacollection/test/DataCollectionSenderTest.cpp b/src/datamanagement/datacollection/test/DataCollectionSenderTest.cpp index 3fb41157..8a0619ff 100644 --- a/src/datamanagement/datacollection/test/DataCollectionSenderTest.cpp +++ b/src/datamanagement/datacollection/test/DataCollectionSenderTest.cpp @@ -28,10 +28,10 @@ class MockSender : public ISender } ConnectivityError - send( const std::uint8_t *buf, - size_t size, - struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = - CollectionSchemeParams() ) + sendBuffer( const std::uint8_t *buf, + size_t size, + struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = + CollectionSchemeParams() ) override { static_cast( collectionSchemeParams ); // Currently not implemented, hence unused @@ -138,7 +138,7 @@ TEST_F( DataCollectionSenderTest, TestMaxMessageCountNotHit ) { auto mockSender = std::make_shared(); CANInterfaceIDTranslator canIDTranslator; - DataCollectionSender dataCollectionSender( mockSender, true, 10, canIDTranslator, mTmpDir.generic_string() ); + DataCollectionSender dataCollectionSender( mockSender, 10, canIDTranslator ); mockSender->mCallback = [&]( const std::uint8_t *buf, size_t size ) -> ConnectivityError { // deserialize the proto @@ -153,7 +153,7 @@ TEST_F( DataCollectionSenderTest, TestMaxMessageCountHit ) { auto mockSender = std::make_shared(); CANInterfaceIDTranslator canIDTranslator; - DataCollectionSender dataCollectionSender( mockSender, true, 2, canIDTranslator, mTmpDir.generic_string() ); + DataCollectionSender dataCollectionSender( mockSender, 2, canIDTranslator ); uint32_t maxMessageCount = 2; mockSender->mCallback = [&]( const std::uint8_t *buf, size_t size ) -> ConnectivityError { @@ -168,7 +168,7 @@ TEST_F( DataCollectionSenderTest, TestTransmitPayload ) { auto mockSender = std::make_shared(); CANInterfaceIDTranslator canIDTranslator; - DataCollectionSender dataCollectionSender( mockSender, true, 10, canIDTranslator, mTmpDir.generic_string() ); + DataCollectionSender dataCollectionSender( mockSender, 10, canIDTranslator ); std::string testProto = "abcdefjh!24$iklmnop!24$3@qrstuvwxyz"; diff --git a/src/datamanagement/datacollection/test/valgrind.supp b/src/datamanagement/datacollection/test/valgrind.supp index 17d9a8d5..fb93ef2c 100644 --- a/src/datamanagement/datacollection/test/valgrind.supp +++ b/src/datamanagement/datacollection/test/valgrind.supp @@ -30,3 +30,12 @@ fun:*add_persistence_guid* ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/datamanagement/datadecoding/CMakeLists.txt b/src/datamanagement/datadecoding/CMakeLists.txt index 1e390e2b..32abb62b 100644 --- a/src/datamanagement/datadecoding/CMakeLists.txt +++ b/src/datamanagement/datadecoding/CMakeLists.txt @@ -23,7 +23,6 @@ target_link_libraries( ${libraryTargetName} Boost::filesystem IoTFleetWise::DataCollection - #IoTFleetWise::DataManagementTypes IoTFleetWise::Platform::Linux IoTFleetWise::Vehiclenetwork ) diff --git a/src/datamanagement/datadecoding/include/CANDecoder.h b/src/datamanagement/datadecoding/include/CANDecoder.h index e8063da8..16065b78 100644 --- a/src/datamanagement/datadecoding/include/CANDecoder.h +++ b/src/datamanagement/datadecoding/include/CANDecoder.h @@ -7,7 +7,6 @@ #include "CANDataTypes.h" #include "ClockHandler.h" #include "IDecoderManifest.h" -#include "LoggingModule.h" #include "Timer.h" #include #include @@ -53,7 +52,6 @@ class CANDecoder static int64_t extractSignalFromFrame( const uint8_t *frameData, const CANSignalFormat &signalDescription ); private: - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); }; diff --git a/src/datamanagement/datadecoding/include/DecoderManifestIngestion.h b/src/datamanagement/datadecoding/include/DecoderManifestIngestion.h index 25fbf0bb..ee059020 100644 --- a/src/datamanagement/datadecoding/include/DecoderManifestIngestion.h +++ b/src/datamanagement/datadecoding/include/DecoderManifestIngestion.h @@ -68,6 +68,18 @@ class DecoderManifestIngestion : public IDecoderManifest return mProtoBinaryData; } + inline SignalType + getSignalType( const SignalID signalID ) const override + { + if ( mSignalIDToTypeMap.find( signalID ) == mSignalIDToTypeMap.end() ) + { + FWE_LOG_WARN( "Signal Type not found for requested SignalID:" + std::to_string( signalID ) + + ", using type as double" ); + return SignalType::DOUBLE; + } + return mSignalIDToTypeMap.at( signalID ); + } + private: /** * @brief The DecoderManifest message that will hold the deserialized proto. @@ -109,10 +121,8 @@ class DecoderManifestIngestion : public IDecoderManifest */ std::unordered_map mSignalToPIDDictionary; - /** - * @brief Logging module used to output to logs - */ - LoggingModule mLogger; + using SignalIDToTypeMap = std::unordered_map; + SignalIDToTypeMap mSignalIDToTypeMap; }; } // namespace DataManagement } // namespace IoTFleetWise diff --git a/src/datamanagement/datadecoding/include/IDecoderDictionary.h b/src/datamanagement/datadecoding/include/IDecoderDictionary.h index aca3643a..18a2330a 100644 --- a/src/datamanagement/datadecoding/include/IDecoderDictionary.h +++ b/src/datamanagement/datadecoding/include/IDecoderDictionary.h @@ -59,33 +59,6 @@ struct DecoderDictionary std::unordered_set signalIDsToCollect; }; -/** - * @brief Metadata regarding a signal - * - */ -struct SignalMetaData -{ - SignalMetaData( SignalID pSignalId, SignalDataType pDataType ) - : signalId( pSignalId ) - , dataType( pDataType ) - { - } - SignalID signalId; - SignalDataType dataType; -}; - -inline bool -operator<( const SignalMetaData &lhs, const SignalMetaData &rhs ) -{ - return lhs.signalId < rhs.signalId; -} - -inline bool -operator==( const SignalMetaData &lhs, const SignalMetaData &rhs ) -{ - return ( lhs.signalId == rhs.signalId ) && ( lhs.dataType == rhs.dataType ); -} - /** * @brief CAN decoder dictionary to be used to decode CAN Frame message to signals. This dictionary comes from * CollectionScheme Management diff --git a/src/datamanagement/datadecoding/include/IDecoderManifest.h b/src/datamanagement/datadecoding/include/IDecoderManifest.h index 0f9ddb6c..4e921ee5 100644 --- a/src/datamanagement/datadecoding/include/IDecoderManifest.h +++ b/src/datamanagement/datadecoding/include/IDecoderManifest.h @@ -23,25 +23,6 @@ namespace DataManagement */ constexpr uint8_t BYTE_SIZE = 8; -/** - * @brief SignalDataType defines the data type for each signal. - */ -enum class SignalDataType -{ - UNDEFINED_TYPE, - BOOL_TYPE, - UINT8_TYPE, - UINT16_TYPE, - UINT32_TYPE, - UINT64_TYPE, - INT8_TYPE, - INT16_TYPE, - INT32_TYPE, - INT64_TYPE, - FLOAT_TYPE, - DOUBLE_TYPE -}; - /** * @brief An invalid CAN Message Format, set as a CANMessageFormat object initialized to all zeros */ @@ -135,6 +116,11 @@ struct PIDSignalDecoderFormat */ uint8_t mBitMaskLength{ 0 }; + /** + * @brief The datatype of the signal. The default is double for backward compatibility + */ + SignalType mSignalType{ SignalType::DOUBLE }; + public: /** * @brief Overload of the == operator @@ -242,6 +228,14 @@ class IDecoderManifest */ virtual const std::vector &getData() const = 0; + /** + * @brief This function returns Signal Type from the Decoder + * + * @param signalID + * @return SignalType + */ + virtual SignalType getSignalType( const SignalID signalID ) const = 0; + /** * @brief Virtual destructor to be implemented by the base class */ diff --git a/src/datamanagement/datadecoding/include/OBDDataDecoder.h b/src/datamanagement/datadecoding/include/OBDDataDecoder.h index 631d44de..3fb99344 100644 --- a/src/datamanagement/datadecoding/include/OBDDataDecoder.h +++ b/src/datamanagement/datadecoding/include/OBDDataDecoder.h @@ -6,7 +6,6 @@ // Includes #include "ClockHandler.h" #include "IDecoderDictionary.h" -#include "LoggingModule.h" #include "OBDDataTypes.h" #include "Timer.h" #include @@ -56,7 +55,9 @@ class OBDDataDecoder * @return True if we received a positive response and extracted the PIDs. * needed. */ - bool decodeSupportedPIDs( const SID &sid, const std::vector &inputData, SupportedPIDs &supportedPIDs ); + static bool decodeSupportedPIDs( const SID &sid, + const std::vector &inputData, + SupportedPIDs &supportedPIDs ); /** * @brief Decodes an ECU response to a list of Emission related PIDs. @@ -105,17 +106,32 @@ class OBDDataDecoder private: Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); // shared pointer to decoder dictionary std::shared_ptr mDecoderDictionaryConstPtr; + + /** + * @brief Uses the given formula to transform the raw data and add the results to info + * @param pid The PID this formula is related to + * @param formula The formula that will be used to calculate the final value + * @param inputData Raw response from the ECU + * @param byteCounter The index of inputData where this value starts + * @param info Output vector of PID physical values + */ + void calculateValueFromFormula( PID pid, + const CANSignalFormat &formula, + const std::vector &inputData, + size_t byteCounter, + EmissionInfo &info ); + /** * @brief Validate signal formula * @param pid * @param formula * @return True if formula is valid. */ - bool isFormulaValid( PID pid, CANSignalFormat formula ); + bool isFormulaValid( PID pid, const CANSignalFormat &formula ); + /** * @brief Check if PIDs response length is valid. When the response consists of multiple PIDs, * this function will check whether each PID exists in response and whether each PID's response diff --git a/src/datamanagement/datadecoding/src/CANDecoder.cpp b/src/datamanagement/datadecoding/src/CANDecoder.cpp index 9a346ca8..f7e2fc5f 100644 --- a/src/datamanagement/datadecoding/src/CANDecoder.cpp +++ b/src/datamanagement/datadecoding/src/CANDecoder.cpp @@ -3,6 +3,7 @@ // Includes #include "CANDecoder.h" +#include "LoggingModule.h" #include #include #define MASK64( nbits ) ( ( 0xFFFFFFFFFFFFFFFFULL ) >> ( 64 - ( nbits ) ) ) @@ -30,14 +31,13 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, { // Lookup the multiplexor signal // complexity. Try to fix in the scheme not in the code. - auto it = std::find_if( format.mSignals.begin(), format.mSignals.end(), []( CANSignalFormat signal ) { + auto it = std::find_if( format.mSignals.begin(), format.mSignals.end(), []( CANSignalFormat signal ) -> bool { return signal.isMultiplexor(); } ); if ( it == format.mSignals.end() ) { - mLogger.error( "CANDecoder::decodeCANMessage", - "Message ID " + std::to_string( format.mMessageID ) + - " is multiplexed but no Multiplexor signal has been found" ); + FWE_LOG_ERROR( "Message ID" + std::to_string( format.mMessageID ) + + " is multiplexed but no Multiplexor signal has been found" ); return false; } if ( signalIDsToCollect.find( it->mSignalID ) != signalIDsToCollect.end() ) @@ -45,8 +45,39 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, // Decode the multiplexor Value int64_t rawValue = extractSignalFromFrame( frameData, *it ); multiplexorValue = static_cast( static_cast( rawValue ) * it->mFactor + it->mOffset ); - decodedMessage.mFrameInfo.mSignals.emplace_back( - CANDecodedSignal( it->mSignalID, rawValue, static_cast( multiplexorValue ) ) ); + + const auto CANsignalType = it->mSignalType; + switch ( CANsignalType ) + { + case ( SignalType::UINT64 ): { + if ( typeid( it->mFactor ) == typeid( double ) ) + { + FWE_LOG_WARN( "Scaling Factor is double for signal ID " + std::to_string( it->mSignalID ) + + " and type as uint64" ); + } + auto physicalRawValue = static_cast( multiplexorValue ); + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( it->mSignalID, rawValue, physicalValue, CANsignalType ) ); + break; + } + case ( SignalType::INT64 ): { + + auto physicalRawValue = static_cast( multiplexorValue ); + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( it->mSignalID, rawValue, physicalValue, CANsignalType ) ); + break; + } + default: { + + auto physicalRawValue = static_cast( multiplexorValue ); + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( it->mSignalID, rawValue, physicalValue, CANsignalType ) ); + break; + } + } } } @@ -64,7 +95,7 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, ( ( format.mSignals[i].mSizeInBits < 1 ) || ( format.mSignals[i].mSizeInBits > frameSizeInBits ) ) ) { // Wrongly coded Signal, skip it - mLogger.error( "CANDecoder::decodeCANMessage", "Signal Out of Range" ); + FWE_LOG_ERROR( "Signal Out of Range" ); errorCounter++; continue; } @@ -73,17 +104,47 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, ( format.mSignals[i].mFirstBitPosition + format.mSignals[i].mSizeInBits > frameSizeInBits ) ) { // Wrongly coded Signal, skip it - mLogger.error( "CANDecoder::decodeCANMessage", "Little endian signal Out of Range" ); + FWE_LOG_ERROR( "Little endian signal Out of Range" ); errorCounter++; continue; } // Start decoding the signal, extract the value before scaling from the Frame. int64_t rawValue = extractSignalFromFrame( frameData, format.mSignals[i] ); - double physicalValue = - static_cast( rawValue ) * format.mSignals[i].mFactor + format.mSignals[i].mOffset; - decodedMessage.mFrameInfo.mSignals.emplace_back( - CANDecodedSignal( format.mSignals[i].mSignalID, rawValue, physicalValue ) ); + const auto CANsignalType = format.mSignals[i].mSignalType; + switch ( CANsignalType ) + { + case ( SignalType::UINT64 ): { + if ( typeid( format.mSignals[i].mFactor ) == typeid( double ) ) + { + FWE_LOG_WARN( "Scaling Factor is double for signal ID " + + std::to_string( format.mSignals[i].mSignalID ) + " and type as uint64" ); + } + uint64_t physicalRawValue = + static_cast( rawValue ) * static_cast( format.mSignals[i].mFactor ) + + static_cast( format.mSignals[i].mOffset ); + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( format.mSignals[i].mSignalID, rawValue, physicalValue, CANsignalType ) ); + break; + } + case ( SignalType::INT64 ): { + auto physicalRawValue = + static_cast( rawValue ) * static_cast( format.mSignals[i].mFactor ) + + static_cast( format.mSignals[i].mOffset ); + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( format.mSignals[i].mSignalID, rawValue, physicalValue, CANsignalType ) ); + break; + } + default: { + auto physicalRawValue = + static_cast( rawValue ) * format.mSignals[i].mFactor + format.mSignals[i].mOffset; + auto physicalValue = CANPhysicalValueType( physicalRawValue, CANsignalType ); + decodedMessage.mFrameInfo.mSignals.emplace_back( + CANDecodedSignal( format.mSignals[i].mSignalID, rawValue, physicalValue, CANsignalType ) ); + } + } } } @@ -138,7 +199,7 @@ CANDecoder::extractSignalFromFrame( const uint8_t *frameData, const CANSignalFor // perform sign extension if ( signalDescription.mIsSigned ) { - uint64_t msbSignMask = static_cast( 1ULL << ( signalDescription.mSizeInBits - 1 ) ); + uint64_t msbSignMask = static_cast( 1U ) << ( signalDescription.mSizeInBits - 1 ); result = ( ( result ^ msbSignMask ) - msbSignMask ); } return static_cast( result ); diff --git a/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp b/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp index 2aa5a6e9..8791bfb9 100644 --- a/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp +++ b/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp @@ -3,6 +3,7 @@ #include "DecoderManifestIngestion.h" #include "CollectionInspectionAPITypes.h" +#include "LoggingModule.h" #include namespace Aws @@ -118,16 +119,15 @@ DecoderManifestIngestion::copyData( const std::uint8_t *inputBuffer, const size_ // check for a null input buffer or size set to 0 if ( ( inputBuffer == nullptr ) || ( size == 0 ) ) { - mLogger.error( "DecoderManifestIngestion::copyData", "Input buffer invalid" ); + FWE_LOG_ERROR( "Input buffer invalid" ); return false; } // We have to guard against document sizes that are too large if ( size > DECODER_MANIFEST_BYTE_SIZE_LIMIT ) { - mLogger.error( "DecoderManifestIngestion::copyData", - "Decoder Manifest binary too big. Size: " + std::to_string( size ) + - " limit: " + std::to_string( DECODER_MANIFEST_BYTE_SIZE_LIMIT ) ); + FWE_LOG_ERROR( "Decoder Manifest binary too big. Size: " + std::to_string( size ) + + " limit: " + std::to_string( DECODER_MANIFEST_BYTE_SIZE_LIMIT ) ); return false; } @@ -137,14 +137,14 @@ DecoderManifestIngestion::copyData( const std::uint8_t *inputBuffer, const size_ // Check to make sure the vector size is the same as our input size if ( mProtoBinaryData.size() != size ) { - mLogger.error( "DecoderManifestIngestion::copyData", "Copied data not the same size as input data" ); + FWE_LOG_ERROR( "Copied data not the same size as input data" ); return false; } // Set the ready flag to false, as we have new data that needs to be parsed mReady = false; - mLogger.trace( "DecoderManifestIngestion::copyData", "Copy of DecoderManifest data success" ); + FWE_LOG_TRACE( "Copy of DecoderManifest data success" ); return true; } @@ -161,7 +161,7 @@ DecoderManifestIngestion::build() // Ensure that we have data to parse if ( mProtoBinaryData.empty() ) { - mLogger.error( "DecoderManifestIngestion::build", "Failed to build due to an empty Decoder Manifest" ); + FWE_LOG_ERROR( "Failed to build due to an empty Decoder Manifest" ); // Error, input buffer empty or invalid return false; } @@ -169,7 +169,7 @@ DecoderManifestIngestion::build() // Try to parse the binary data into our mProtoDecoderManifest member variable if ( !mProtoDecoderManifest.ParseFromArray( mProtoBinaryData.data(), static_cast( mProtoBinaryData.size() ) ) ) { - mLogger.error( "DecoderManifestIngestion::build", "Failed to parse DecoderManifest proto" ); + FWE_LOG_ERROR( "Failed to parse DecoderManifest proto" ); // Error parsing proto binary return false; } @@ -178,14 +178,12 @@ DecoderManifestIngestion::build() if ( ( mProtoDecoderManifest.can_signals_size() == 0 ) && ( mProtoDecoderManifest.obd_pid_signals_size() == 0 ) ) { // Error, missing required decoding information in the Decoder mProtoDecoderManifest - mLogger.error( - "DecoderManifestIngestion::build", + FWE_LOG_ERROR( "CAN Nodes or CAN Signal array or OBD PID Signal array is empty. Failed to build Decoder Manifest" ); return false; } - mLogger.info( "DecoderManifestIngestion::build", - "Building Decoder Manifest with ID: " + mProtoDecoderManifest.arn() ); + FWE_LOG_INFO( "Building Decoder Manifest with ID: " + mProtoDecoderManifest.arn() ); // Iterate over CAN Signals and build the mCANSignalFormatDictionary for ( int i = 0; i < mProtoDecoderManifest.can_signals_size(); i++ ) @@ -209,11 +207,13 @@ DecoderManifestIngestion::build() canSignalFormat.mOffset = canSignal.offset(); canSignalFormat.mFactor = canSignal.factor(); + // TODO :: Update the datatype from the DM after the schema update for the datatype support + mSignalIDToTypeMap[canSignal.signal_id()] = SignalType::DOUBLE; // using double as default + canSignalFormat.mIsMultiplexorSignal = false; canSignalFormat.mMultiplexorValue = 0; - mLogger.trace( "DecoderManifestIngestion::build", - "Adding CAN Signal Format for Signal ID: " + std::to_string( canSignalFormat.mSignalID ) ); + FWE_LOG_TRACE( "Adding CAN Signal Format for Signal ID: " + std::to_string( canSignalFormat.mSignalID ) ); // Each CANMessageFormat object contains an array of signal decoding rules for each signal it contains. Cloud // sends us a set of Signal IDs so we need to iterate through them and either create new CANMessageFormat @@ -267,7 +267,6 @@ DecoderManifestIngestion::build() // Get a reference to the OBD PID signal in the protobuf const DecoderManifestMsg::OBDPIDSignal &pidSignal = mProtoDecoderManifest.obd_pid_signals( i ); mSignalToVehicleDataSourceProtocol[pidSignal.signal_id()] = VehicleDataSourceProtocol::OBD; - PIDSignalDecoderFormat obdPIDSignalDecoderFormat = PIDSignalDecoderFormat( pidSignal.pid_response_length(), static_cast( pidSignal.service_mode() ), @@ -279,9 +278,11 @@ DecoderManifestIngestion::build() static_cast( pidSignal.bit_right_shift() ), static_cast( pidSignal.bit_mask_length() ) ); mSignalToPIDDictionary[pidSignal.signal_id()] = obdPIDSignalDecoderFormat; + // TODO :: Update the datatype from the DM after the schema update for the datatype support + mSignalIDToTypeMap[pidSignal.signal_id()] = SignalType::DOUBLE; // using double as default } - mLogger.trace( "DecoderManifestIngestion::build", "Decoder Manifest build succeeded" ); + FWE_LOG_TRACE( "Decoder Manifest build succeeded" ); // Set our ready flag to true mReady = true; return true; diff --git a/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp b/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp index 23a830d8..c09035aa 100644 --- a/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp +++ b/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp @@ -4,7 +4,10 @@ // Includes #include "OBDDataDecoder.h" #include "EnumUtility.h" +#include "LoggingModule.h" +#include "TraceModule.h" #include +#include #include #include constexpr int POSITIVE_ECU_RESPONSE_BASE = 0x40; @@ -35,7 +38,7 @@ OBDDataDecoder::decodeSupportedPIDs( const SID &sid, if ( ( inputData.size() < 6 ) || ( POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] ) || ( ( inputData.size() - 1 ) % 5 != 0 ) ) { - mLogger.warn( "OBDDataDecoder::decodeSupportedPIDs", "Invalid Supported PID Input" ); + FWE_LOG_WARN( "Invalid Supported PID Input" ); return false; } // Make sure we put only the ones we support by our software in the result. @@ -59,8 +62,7 @@ OBDDataDecoder::decodeSupportedPIDs( const SID &sid, basePID = inputData[i]; if ( basePID % SUPPORTED_PID_STEP != 0 ) { - mLogger.warn( "OBDDataDecoder::decodeSupportedPIDs", - "Invalid PID for support range: " + std::to_string( basePID ) ); + FWE_LOG_WARN( "Invalid PID for support range: " + std::to_string( basePID ) ); break; } baseIdx = i; @@ -114,19 +116,19 @@ OBDDataDecoder::decodeEmissionPIDs( const SID &sid, // this is also not a valid input as we expect at least one by response. if ( ( inputData.size() < 3 ) || ( POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] ) ) { - mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid response to PID request" ); + FWE_LOG_WARN( "Invalid response to PID request" ); return false; } if ( mDecoderDictionaryConstPtr == nullptr ) { - mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid Decoder Dictionary" ); + FWE_LOG_WARN( "Invalid Decoder Dictionary" ); return false; } // Validate 1) The PIDs in response match with expected PID; 2) Total length of PID response matches with Decoder // Manifest. If not matched, the program will discard this response and not attempt to decode. if ( isPIDResponseValid( pids, inputData ) == false ) { - mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid PIDs response" ); + FWE_LOG_WARN( "Invalid PIDs response" ); return false; } // Setup the Info @@ -135,7 +137,8 @@ OBDDataDecoder::decodeEmissionPIDs( const SID &sid, size_t byteCounter = 1; while ( byteCounter < inputData.size() ) { - auto pid = inputData[byteCounter++]; + auto pid = inputData[byteCounter]; + byteCounter++; // first check whether the decoder dictionary contains this PID if ( mDecoderDictionaryConstPtr->find( pid ) != mDecoderDictionaryConstPtr->end() ) { @@ -150,39 +153,7 @@ OBDDataDecoder::decodeEmissionPIDs( const SID &sid, // Each signal has its associated formula for ( auto formula : formulas ) { - // Before using formula, check it against rule - if ( isFormulaValid( pid, formula ) ) - { - // In J1979 spec, longest value has 4-byte. - // Allocate 64-bit here in case signal value increased in the future - uint64_t rawData = 0; - size_t byteIdx = byteCounter + ( formula.mFirstBitPosition / BYTE_SIZE ); - // If the signal length is less than 8-bit, we need to perform bit field operation - if ( formula.mSizeInBits < BYTE_SIZE ) - { - // bit manipulation performed here: shift first, then apply mask - // e.g. If signal are bit 4 ~ 7 in Byte A. - // we firstly right shift by 4, then apply bit mask 0b1111 - rawData = inputData[byteIdx]; - rawData >>= formula.mFirstBitPosition % BYTE_SIZE; - rawData &= ( 0xFF >> ( BYTE_SIZE - formula.mSizeInBits ) ); - } - else - { - // This signal contain greater or equal than one byte, concatenate raw bytes - auto numOfBytes = formula.mSizeInBits / BYTE_SIZE; - // This signal contains multiple bytes, concatenate the bytes - while ( numOfBytes != 0 ) - { - --numOfBytes; - rawData = ( rawData << BYTE_SIZE ) | inputData[byteIdx++]; - } - } - // apply scaling and offset to the raw data. - info.mPIDsToValues.emplace( formula.mSignalID, - static_cast( rawData ) * formula.mFactor + - formula.mOffset ); - } + calculateValueFromFormula( pid, formula, inputData, byteCounter, info ); } } // Done with this PID, move on to next PID by increment byteCounter by response length of current PID @@ -190,8 +161,7 @@ OBDDataDecoder::decodeEmissionPIDs( const SID &sid, } else { - mLogger.trace( "OBDDataDecoder::decodeEmissionPIDs", - "PID " + std::to_string( pid ) + " missing in decoder dictionary" ); + FWE_LOG_TRACE( "PID " + std::to_string( pid ) + " missing in decoder dictionary" ); // Cannot decode this byte as it doesn't exist in both decoder dictionary // Cannot proceed with the rest of response because the payload might already be misaligned. // Note because we already checked the response validity with isPIDResponseValid(), the program should @@ -304,19 +274,24 @@ OBDDataDecoder::decodeVIN( const std::vector &inputData, std::string &v bool OBDDataDecoder::isPIDResponseValid( const std::vector &pids, const std::vector &ecuResponse ) { + // All PIDs which are still expected in the remaining message + // once processed they are set to INVALID_PID + std::vector pidsLeft( pids ); + // This index is used to iterate through the ECU PID response length // As the first byte in response is the Service Mode, we will start from the second byte. size_t responseByteIndex = 1; - for ( auto pid : pids ) + while ( responseByteIndex < ecuResponse.size() ) { - // if the response length is shorter than expected or the PID in ECU response mismatches with - // the requested PID, it's an invalid ECU response - if ( ( responseByteIndex >= ecuResponse.size() ) || ( ecuResponse[responseByteIndex] != pid ) ) + auto pid = ecuResponse[responseByteIndex]; + auto foundPid = std::find( pidsLeft.begin(), pidsLeft.end(), pid ); + if ( foundPid == pidsLeft.end() ) { - mLogger.warn( "OBDDataDecoder::isPIDResponseValid", - "Cannot find PID " + std::to_string( pid ) + " in ECU response" ); + FWE_LOG_WARN( "PID " + std::to_string( pid ) + " in ECU response position " + + std::to_string( responseByteIndex ) + " is not expected" ); return false; } + *foundPid = INVALID_PID; // for every time a PID is requested only one response is expected if ( mDecoderDictionaryConstPtr->find( pid ) != mDecoderDictionaryConstPtr->end() ) { // Move Index into the next PID @@ -324,22 +299,127 @@ OBDDataDecoder::isPIDResponseValid( const std::vector &pids, const std::vec } else { - mLogger.warn( "OBDDataDecoder::isPIDResponseValid", - "PID " + std::to_string( pid ) + " not found in decoder dictionary" ); + FWE_LOG_WARN( "PID " + std::to_string( pid ) + " not found in decoder dictionary" ); return false; } } + + for ( auto p : pidsLeft ) + { + if ( p != INVALID_PID ) + { + FWE_LOG_TRACE( "Cannot find PID " + std::to_string( p ) + " which was requested in ECU response" ); + } + } if ( responseByteIndex != ecuResponse.size() ) { - mLogger.warn( "OBDDataDecoder::isPIDResponseValid", - "Expect response length: " + std::to_string( responseByteIndex ) + - " Actual response length: " + std::to_string( ecuResponse.size() ) ); + FWE_LOG_WARN( "Expect response length: " + std::to_string( responseByteIndex ) + + " Actual response length: " + std::to_string( ecuResponse.size() ) ); } return responseByteIndex == ecuResponse.size(); } +void +OBDDataDecoder::calculateValueFromFormula( PID pid, + const CANSignalFormat &formula, + const std::vector &inputData, + size_t byteCounter, + EmissionInfo &info ) +{ + // Before using formula, check it against rule + if ( !isFormulaValid( pid, formula ) ) + { + return; + } + + // In J1979 spec, longest value has 4-byte. + // Allocate 64-bit here in case signal value increased in the future. + // Currently we always consider the raw value is positive. There are cases where a raw + // value itself is a negative integer as 2-complement. In those cases, the raw value will also + // be interpreted as positive because we store it in a 64-bit type without looking at the sign. + // In the future we have to know whether a raw value is signed and then extend the sign (filling + // all left-side bits with 1 instead of 0). + uint64_t rawData = 0; + size_t byteIdx = byteCounter + ( formula.mFirstBitPosition / BYTE_SIZE ); + // If the signal length is less than 8-bit, we need to perform bit field operation + if ( formula.mSizeInBits < BYTE_SIZE ) + { + // bit manipulation performed here: shift first, then apply mask + // e.g. If signal are bit 4 ~ 7 in Byte A. + // we firstly right shift by 4, then apply bit mask 0b1111 + rawData = inputData[byteIdx]; + rawData >>= formula.mFirstBitPosition % BYTE_SIZE; + rawData &= ( 0xFF >> ( BYTE_SIZE - formula.mSizeInBits ) ); + } + else + { + // This signal contain greater or equal than one byte, concatenate raw bytes + auto numOfBytes = formula.mSizeInBits / BYTE_SIZE; + // This signal contains multiple bytes, concatenate the bytes + while ( numOfBytes != 0 ) + { + --numOfBytes; + rawData = ( rawData << BYTE_SIZE ) | inputData[byteIdx]; + byteIdx++; + } + } + + const auto signalType = formula.mSignalType; + switch ( signalType ) + { + case ( SignalType::UINT64 ): { + uint64_t calculatedValue = 0; + if ( ( formula.mFactor > 0.0 ) && ( floor( formula.mFactor ) == formula.mFactor ) && + ( floor( formula.mOffset ) == formula.mOffset ) ) + { + if ( formula.mOffset >= 0.0 ) + { + calculatedValue = static_cast( rawData ) * static_cast( formula.mFactor ) + + static_cast( formula.mOffset ); + } + else + { + calculatedValue = static_cast( rawData ) * static_cast( formula.mFactor ) - + static_cast( std::abs( formula.mOffset ) ); + } + } + else + { + calculatedValue = + static_cast( static_cast( rawData ) * formula.mFactor + formula.mOffset ); + TraceModule::get().incrementVariable( TraceVariable::OBD_POSSIBLE_PRECISION_LOSS_UINT64 ); + } + info.mPIDsToValues.emplace( formula.mSignalID, OBDSignal( calculatedValue, signalType ) ); + break; + } + case ( SignalType::INT64 ): { + int64_t calculatedValue = 0; + if ( ( floor( formula.mFactor ) == formula.mFactor ) && ( floor( formula.mOffset ) == formula.mOffset ) ) + { + calculatedValue = static_cast( rawData ) * static_cast( formula.mFactor ) + + static_cast( formula.mOffset ); + } + else + { + calculatedValue = + static_cast( static_cast( rawData ) * formula.mFactor + formula.mOffset ); + TraceModule::get().incrementVariable( TraceVariable::OBD_POSSIBLE_PRECISION_LOSS_INT64 ); + } + info.mPIDsToValues.emplace( formula.mSignalID, OBDSignal( calculatedValue, signalType ) ); + break; + } + // For any other type, we can safely cast everything to double as only int64 and uint64 can't + // fit in a double. + default: { + double calculatedValue = + static_cast( static_cast( rawData ) ) * formula.mFactor + formula.mOffset; + info.mPIDsToValues.emplace( formula.mSignalID, OBDSignal( calculatedValue, signalType ) ); + } + } +} + bool -OBDDataDecoder::isFormulaValid( PID pid, CANSignalFormat formula ) +OBDDataDecoder::isFormulaValid( PID pid, const CANSignalFormat &formula ) { bool isValid = false; // Here's the rules we apply to check whether PID formula is valid diff --git a/src/datamanagement/datadecoding/test/CANDecoderTest.cpp b/src/datamanagement/datadecoding/test/CANDecoderTest.cpp index f7fb3dc2..f19ef8ed 100644 --- a/src/datamanagement/datadecoding/test/CANDecoderTest.cpp +++ b/src/datamanagement/datadecoding/test/CANDecoderTest.cpp @@ -3,6 +3,7 @@ #include "CANDecoder.h" #include +#include #include using namespace Aws::IoTFleetWise::DataManagement; @@ -98,6 +99,104 @@ TEST( CANDecoderTest, CANDecoderTestSimpleMessage2 ) ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[1].mRawValue, -299667802 ); } +// Precision Test +TEST( CANDecoderTest, CANDecoderPrecisionTest ) +{ + constexpr auto maxUnSignedVal = std::numeric_limits::max(); + constexpr auto maxSignedVal = std::numeric_limits::max(); + + // Test for max val + constexpr uint32_t msgSizeBytes = 16; + std::vector frameData; + for ( size_t i = 0; i < 15; i++ ) + { + frameData.emplace_back( 0xFF ); + } + frameData.emplace_back( 0x7F ); + + CANSignalFormat sigFormat1; + sigFormat1.mSignalID = 1; + sigFormat1.mIsBigEndian = false; + sigFormat1.mIsSigned = false; + sigFormat1.mFirstBitPosition = 0; + sigFormat1.mSizeInBits = 64; + sigFormat1.mOffset = 0.0; + sigFormat1.mFactor = 1.0; + sigFormat1.mSignalType = SignalType::UINT64; + + CANSignalFormat sigFormat2; + sigFormat2.mSignalID = 7; + sigFormat2.mIsBigEndian = false; + sigFormat2.mIsSigned = true; + sigFormat2.mFirstBitPosition = 64; + sigFormat2.mSizeInBits = 64; + sigFormat2.mOffset = 0.0; + sigFormat2.mFactor = 1.0; + sigFormat2.mSignalType = SignalType::INT64; + + CANMessageFormat msgFormat; + msgFormat.mMessageID = 0x32A; + msgFormat.mSizeInBytes = msgSizeBytes; + msgFormat.mSignals.emplace_back( sigFormat1 ); + msgFormat.mSignals.emplace_back( sigFormat2 ); + + CANDecoder decoder; + CANDecodedMessage decodedMsg; + std::unordered_set signalIDsToCollect = { 1, 7 }; + ASSERT_TRUE( + decoder.decodeCANMessage( frameData.data(), msgSizeBytes, msgFormat, signalIDsToCollect, decodedMsg ) ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals.size(), 2 ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[0].mSignalType, SignalType::UINT64 ); + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[1].mSignalType, SignalType::INT64 ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[0].mPhysicalValue.signalValue.uint64Val, maxUnSignedVal ); + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[1].mPhysicalValue.signalValue.int64Val, maxSignedVal ); +} + +TEST( CANDecoderTest, CANDecoderPrecisionSignedTest ) +{ + constexpr auto minSignedVal = std::numeric_limits::min(); + + // Test for max val + constexpr uint32_t msgSizeBytes = 8; + std::vector frameData; + frameData.emplace_back( 0x00 ); + for ( size_t i = 0; i < 6; i++ ) + { + frameData.emplace_back( 0x00 ); + } + frameData.emplace_back( 0x80 ); + + CANSignalFormat sigFormat1; + sigFormat1.mSignalID = 1; + sigFormat1.mIsBigEndian = false; + sigFormat1.mIsSigned = true; + sigFormat1.mFirstBitPosition = 0; + sigFormat1.mSizeInBits = 64; + sigFormat1.mOffset = 0.0; + sigFormat1.mFactor = 1.0; + sigFormat1.mSignalType = SignalType::INT64; + + CANMessageFormat msgFormat; + msgFormat.mMessageID = 0x32A; + msgFormat.mSizeInBytes = msgSizeBytes; + msgFormat.mSignals.emplace_back( sigFormat1 ); + + CANDecoder decoder; + CANDecodedMessage decodedMsg; + std::unordered_set signalIDsToCollect = { 1 }; + ASSERT_TRUE( + decoder.decodeCANMessage( frameData.data(), msgSizeBytes, msgFormat, signalIDsToCollect, decodedMsg ) ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals.size(), 1 ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[0].mSignalType, SignalType::INT64 ); + + ASSERT_EQ( decodedMsg.mFrameInfo.mSignals[0].mPhysicalValue.signalValue.int64Val, minSignedVal ); +} + TEST( CANDecoderTest, CANDecoderTestSimpleMessage3 ) { // Test for BigEndian & LittleEndian Signals diff --git a/src/datamanagement/datadecoding/test/OBDDataDecoderTest.cpp b/src/datamanagement/datadecoding/test/OBDDataDecoderTest.cpp index 95ab10e5..dcb8c907 100644 --- a/src/datamanagement/datadecoding/test/OBDDataDecoderTest.cpp +++ b/src/datamanagement/datadecoding/test/OBDDataDecoderTest.cpp @@ -4,11 +4,13 @@ #include "OBDDataDecoder.h" #include "EnumUtility.h" +#include "Testing.h" #include "datatypes/OBDDataTypesUnitTestOnly.h" #include #include using namespace Aws::IoTFleetWise::DataManagement; +using namespace Aws::IoTFleetWise::TestingSupport; // For testing purpose, Signal ID is defined as PID | (signal_order << PID_SIGNAL_BITS_LEFT_SHIFT) #define PID_SIGNAL_BITS_LEFT_SHIFT 8 @@ -50,11 +52,307 @@ class OBDDataDecoderTest : public ::testing::Test } void - TearDown() override + assertSignalValue( const OBDSignal &obdSignal, double expectedSignalValue, SignalType expectedSignalType ) { + switch ( expectedSignalType ) + { + case SignalType::UINT8: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::INT8: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT16: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::INT16: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT32: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::INT32: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT64: + ASSERT_EQ( obdSignal.signalValue.uint64Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::INT64: + ASSERT_EQ( obdSignal.signalValue.int64Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::FLOAT: + ASSERT_FLOAT_EQ( static_cast( obdSignal.signalValue.doubleVal ), + static_cast( expectedSignalValue ) ); + break; + case SignalType::DOUBLE: + ASSERT_DOUBLE_EQ( obdSignal.signalValue.doubleVal, static_cast( expectedSignalValue ) ); + break; + case SignalType::BOOLEAN: + ASSERT_EQ( static_cast( obdSignal.signalValue.doubleVal ), static_cast( expectedSignalValue ) ); + break; + default: + FAIL() << "Unsupported signal type"; + }; } }; +class OBDDataDecoderTestWithAllSignalTypes : public OBDDataDecoderTest, public testing::WithParamInterface +{ +}; + +INSTANTIATE_TEST_SUITE_P( AllSignals, OBDDataDecoderTestWithAllSignalTypes, allSignalTypes, signalTypeToString ); + +class OBDDataDecoderTestWithSignedSignalTypes : public OBDDataDecoderTest, + public testing::WithParamInterface +{ +}; + +INSTANTIATE_TEST_SUITE_P( SignedSignals, + OBDDataDecoderTestWithSignedSignalTypes, + signedSignalTypes, + signalTypeToString ); + +TEST_P( OBDDataDecoderTestWithAllSignalTypes, FullSingleByte ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 1; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 8; + signalFormat.mFactor = (double)100 / 255; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0x99 }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 60, signalType ); +} + +TEST_P( OBDDataDecoderTestWithAllSignalTypes, FullSingleByteNegativeOffset ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 1; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 8; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = -10; + signalFormat.mSignalType = signalType; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0x99 }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 143, signalType ); +} + +TEST_P( OBDDataDecoderTestWithAllSignalTypes, FullMultipleBytes ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 2; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 16; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0x00, 0x0A }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 10, signalType ); +} + +TEST_P( OBDDataDecoderTestWithAllSignalTypes, PartialByte ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 1; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 2; + signalFormat.mSizeInBits = 2; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0xFB }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 2, signalType ); +} + +TEST_P( OBDDataDecoderTestWithSignedSignalTypes, FullSingleByteWithUnsignedRawValue ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 1; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 8; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + signalFormat.mIsSigned = false; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0xC4 }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + // Even though the signal type is a signed type, the raw OBD value is not signed. + // So the raw value 0xC4 should be interpreted as a positive integer instead of negative (-60). + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 196, signalType ); +} + +TEST_P( OBDDataDecoderTestWithSignedSignalTypes, FullMultipleBytesWithUnsignedRawValue ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 2; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 16; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + signalFormat.mIsSigned = false; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + std::vector txPDUData = { 0x41, pid, 0xC4, 0x0A }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + // Even though the signal type is a signed type, the raw OBD value is not signed. + // So the raw value 0xC40A should be interpreted as a positive integer instead of negative (-15350). + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 50186, signalType ); +} + +TEST_P( OBDDataDecoderTestWithSignedSignalTypes, PartialByteWithUnsignedRawValue ) +{ + SignalType signalType = GetParam(); + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 1; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 2; + signalFormat.mSizeInBits = 5; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = 0; + signalFormat.mSignalType = signalType; + signalFormat.mIsSigned = false; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + // 0x4C shifted 2 bits to the right (without extending the sign) = 0x13 = 19 + std::vector txPDUData = { 0x41, pid, 0x4C }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + assertSignalValue( info.mPIDsToValues.at( signalFormat.mSignalID ), 19, signalType ); +} + +TEST_F( OBDDataDecoderTest, KeepPrecisionForUInt64 ) +{ + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 8; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 64; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = -100000; + signalFormat.mSignalType = SignalType::UINT64; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + // 2305843009213693951, which when represented as a double loses precision + std::vector txPDUData = { 0x41, pid, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + // Ensure that we are not casting to double anywhere + ASSERT_EQ( info.mPIDsToValues.at( signalFormat.mSignalID ).signalValue.uint64Val, 2305843009213593951UL ); +} + +TEST_F( OBDDataDecoderTest, KeepPrecisionForInt64 ) +{ + PID pid = 0xEF; + CANMessageFormat format; + format.mMessageID = pid; + format.mSizeInBytes = 8; + CANSignalFormat signalFormat; + signalFormat.mSignalID = 0x100000EF; + signalFormat.mFirstBitPosition = 0; + signalFormat.mSizeInBits = 64; + signalFormat.mFactor = 1.0; + signalFormat.mOffset = -100000; + signalFormat.mSignalType = SignalType::INT64; + format.mSignals.emplace_back( signalFormat ); + decoderDictPtr->emplace( pid, format ); + + // -6917529027641081857, which when represented as a double loses precision + std::vector txPDUData = { 0x41, pid, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + // Ensure that we are not casting to double anywhere + ASSERT_EQ( info.mPIDsToValues.at( signalFormat.mSignalID ).signalValue.int64Val, -6917529027641181857L ); +} + TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedSupportedPIDs ) { // supported PID: 0x01 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, @@ -83,7 +381,7 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineLoad ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x04 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_LOAD )], 60 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_LOAD ) ).signalValue.doubleVal, 60 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineTemperature ) @@ -94,7 +392,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineTemperature ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x05 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE )], 70 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ) ).signalValue.doubleVal, 70 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedFuelTrim ) @@ -106,10 +405,14 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedFuelTrim ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x06, 0x07, 0x08, 0x09 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::SHORT_TERM_FUEL_TRIM_BANK_1 )], 50 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::SHORT_TERM_FUEL_TRIM_BANK_2 )], 50 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::LONG_TERM_FUEL_TRIM_BANK_1 )], 50 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::LONG_TERM_FUEL_TRIM_BANK_2 )], 50 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::SHORT_TERM_FUEL_TRIM_BANK_1 ) ).signalValue.doubleVal, 50 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::SHORT_TERM_FUEL_TRIM_BANK_2 ) ).signalValue.doubleVal, 50 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::LONG_TERM_FUEL_TRIM_BANK_1 ) ).signalValue.doubleVal, 50 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::LONG_TERM_FUEL_TRIM_BANK_2 ) ).signalValue.doubleVal, 50 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedIntakeManifoldPressure ) @@ -120,7 +423,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedIntakeManifoldPressure ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0B }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE )], 200 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE ) ).signalValue.doubleVal, + 200 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedIntakeAirFLowTemperature ) @@ -131,7 +436,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedIntakeAirFLowTemperature ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0F }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::INTAKE_AIR_FLOW_TEMPERATURE )], 30 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::INTAKE_AIR_FLOW_TEMPERATURE ) ).signalValue.doubleVal, 30 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMAFRate ) @@ -142,7 +448,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMAFRate ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x10 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::MAF_RATE )], ( 256.0 * 0x0A + 0x0A ) / 100 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::MAF_RATE ) ).signalValue.doubleVal, + ( 256.0 * 0x0A + 0x0A ) / 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedThrottlePosition ) @@ -153,7 +460,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedThrottlePosition ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x11 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::THROTTLE_POSITION )], (double)0x80 * 100 / 255 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::THROTTLE_POSITION ) ).signalValue.doubleVal, + (double)0x80 * 100 / 255 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedOxygenSensorX_1 ) @@ -166,8 +474,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedOxygenSensorX_1 ) txPDUData[1] = pid; ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[pid | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], (double)0x10 / 200 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[pid | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( pid | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ).signalValue.doubleVal, + (double)0x10 / 200 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( pid | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ).signalValue.doubleVal, (double)0x20 * 100 / 128 - 100 ); } } @@ -180,7 +489,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedRuntimeSinceEngineStart ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x1F }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::RUNTIME_SINCE_ENGINE_START )], 500 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::RUNTIME_SINCE_ENGINE_START ) ).signalValue.doubleVal, 500 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDistanceTraveledWithMIL ) @@ -191,7 +501,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDistanceTraveledWithMIL ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x21 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::DISTANCE_TRAVELED_WITH_MIL )], 10 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::DISTANCE_TRAVELED_WITH_MIL ) ).signalValue.doubleVal, 10 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedOxygenSensorX_2 ) @@ -204,9 +515,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedOxygenSensorX_2 ) txPDUData[1] = pid; ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { pid }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[pid | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( pid | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ).signalValue.doubleVal, ( 256 * 0x10 + 0x20 ) * 0.0000305 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[pid | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( pid | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ).signalValue.doubleVal, ( 256 * 0x30 + 0x40 ) * 0.000122 ); } } @@ -219,7 +530,7 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedFuelTankLevel ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x2F }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::FUEL_TANK_LEVEL )], 100 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::FUEL_TANK_LEVEL ) ).signalValue.doubleVal, 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDistanceTraveledSinceClearedDTC ) @@ -230,7 +541,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDistanceTraveledSinceClearedDTC ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x31 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::DISTANCE_TRAVELED_SINCE_CLEARED_DTC )], 10 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::DISTANCE_TRAVELED_SINCE_CLEARED_DTC ) ).signalValue.doubleVal, + 10 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedControlModuleVoltage ) @@ -241,7 +554,7 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedControlModuleVoltage ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x42 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::CONTROL_MODULE_VOLTAGE )], + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::CONTROL_MODULE_VOLTAGE ) ).signalValue.doubleVal, ( 256.0 * 100 + 100 ) / 1000 ); } @@ -253,8 +566,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedRelativeThrottlePosition ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x45 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::RELATIVE_THROTTLE_POSITION )], - (double)0x80 * 100 / 255 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::RELATIVE_THROTTLE_POSITION ) ).signalValue.doubleVal, + (double)0x80 * 100 / 255 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedAmbientAireTemperature ) @@ -265,7 +579,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedAmbientAireTemperature ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x46 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::AMBIENT_AIR_TEMPERATURE )], 30 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::AMBIENT_AIR_TEMPERATURE ) ).signalValue.doubleVal, + 30 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedRelativePedalPosition ) @@ -276,7 +591,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedRelativePedalPosition ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x5A }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::RELATIVE_ACCELERATOR_PEDAL_POSITION )], 100 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::RELATIVE_ACCELERATOR_PEDAL_POSITION ) ).signalValue.doubleVal, + 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBatteryRemainingLife ) @@ -287,7 +604,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBatteryRemainingLife ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x5B }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::HYBRID_BATTERY_PACK_REMAINING_LIFE )], 100 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::HYBRID_BATTERY_PACK_REMAINING_LIFE ) ).signalValue.doubleVal, + 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineOilTemperature ) @@ -298,7 +617,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineOilTemperature ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x5C }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_OIL_TEMPERATURE )], 30 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_OIL_TEMPERATURE ) ).signalValue.doubleVal, + 30 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDriverDemandTorque ) @@ -309,7 +629,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedDriverDemandTorque ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x61 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::DRIVER_DEMAND_PERCENT_TORQUE )], 100 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::DRIVER_DEMAND_PERCENT_TORQUE ) ).signalValue.doubleVal, 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedActualEngineTorque ) @@ -320,7 +641,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedActualEngineTorque ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x62 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ACTUAL_PERCENT_TORQUE )], 100 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ACTUAL_PERCENT_TORQUE ) ).signalValue.doubleVal, + 100 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedReferenceEngineTorque ) @@ -331,7 +653,9 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedReferenceEngineTorque ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x63 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_REFERENCE_PERCENT_TORQUE )], 25700 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_REFERENCE_PERCENT_TORQUE ) ).signalValue.doubleVal, + 25700 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBoostPressureControl ) @@ -342,28 +666,36 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBoostPressureControl ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x70 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x3F ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x03 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x03 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x00 ); } @@ -374,30 +706,46 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedVariableGeometryTurboControl ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x71 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x3F ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x10 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x20 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x30 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x40 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x03 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x03 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x00 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x3F ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x10 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x20 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x30 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x03 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x03 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x00 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBoostPressureControlAndVariableGeometryTurboControl ) @@ -426,53 +774,77 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedBoostPressureControlAndVariable ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x70, 0x71 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x3F ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 803.125 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x03 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x03 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x00 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x3F ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x10 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x20 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x30 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + (double)100 / 255 * 0x40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x03 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x03 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::BOOST_PRESSURE_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues + .at( toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x00 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x3F ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x10 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x20 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x30 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT )], - (double)100 / 255 * 0x40 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 5 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x03 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 6 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x03 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VARIABLE_GEOMETRY_TURBO_CONTROL ) | - ( 7 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x00 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineRunTime ) @@ -484,13 +856,21 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineRunTime ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x7F }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], 0x08 ); + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x08 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], 16909060 ); + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 16909060 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], 16909060 ); + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 16909060 ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], 16909060 ); + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_RUN_TIME ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 16909060 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderExhaustGasTemperatureSensor ) @@ -500,21 +880,31 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderExhaustGasTemperatureSensor ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x98 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | - ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0xFF ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | - ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x1020 * 0.1 - 40 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | - ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x3040 * 0.1 - 40 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | - ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x5060 * 0.1 - 40 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | - ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT )], - 0x7080 * 0.1 - 40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0xFF ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x1020 * 0.1 - 40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x3040 * 0.1 - 40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | ( 3 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x5060 * 0.1 - 40 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues + .at( toUType( EmissionPIDs::EXHAUST_GAS_TEMPERATURE_SENSORA ) | ( 4 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, + 0x7080 * 0.1 - 40 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedTransmissionActualGear ) @@ -525,13 +915,16 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedTransmissionActualGear ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0xA4 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0xFF ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 1 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x0F ); ASSERT_DOUBLE_EQ( - info.mPIDsToValues[toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT )], + info.mPIDsToValues.at( toUType( EmissionPIDs::TRANSMISSION_ACTUAL_GEAR ) | ( 2 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0xAA55 * 0.001 ); } @@ -542,7 +935,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedOdometer ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0xA6 }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ODOMETER ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT )], + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ODOMETER ) | ( 0 << PID_SIGNAL_BITS_LEFT_SHIFT ) ) + .signalValue.doubleVal, 0x0110AA55 * 0.1 ); } @@ -554,7 +948,7 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedFuelPressure ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0A }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::FUEL_PRESSURE )], 450 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::FUEL_PRESSURE ) ).signalValue.doubleVal, 450 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineSpeed ) @@ -565,7 +959,8 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedEngineSpeed ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0C }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_SPEED )], ( 256.0 * 0x0A + 0x6B ) / 4 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_SPEED ) ).signalValue.doubleVal, + ( 256.0 * 0x0A + 0x6B ) / 4 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedVehicleSpeed ) @@ -576,7 +971,7 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedVehicleSpeed ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0D }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VEHICLE_SPEED )], 35 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::VEHICLE_SPEED ) ).signalValue.doubleVal, 35 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMultiplePIDs ) @@ -586,11 +981,29 @@ TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMultiplePIDs ) ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x04, 0x05, 0x0A, 0x0C, 0x0D }, txPDUData, info ) ); ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_LOAD )], 60 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE )], 70 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::FUEL_PRESSURE )], 450 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::ENGINE_SPEED )], ( 256.0 * 0x0A + 0x6B ) / 4 ); - ASSERT_DOUBLE_EQ( info.mPIDsToValues[toUType( EmissionPIDs::VEHICLE_SPEED )], 35 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_LOAD ) ).signalValue.doubleVal, 60 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ) ).signalValue.doubleVal, 70 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::FUEL_PRESSURE ) ).signalValue.doubleVal, 450 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_SPEED ) ).signalValue.doubleVal, + ( 256.0 * 0x0A + 0x6B ) / 4 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::VEHICLE_SPEED ) ).signalValue.doubleVal, 35 ); +} + +TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMultiplePIDsWhereResponseOrderDifferentThanRequestOrder ) +{ + std::vector txPDUData = { 0x41, 0x04, 0x99, 0x05, 0x6E, 0x0A, 0x96, 0x0C, 0x0A, 0x6B, 0x0D, 0x23 }; + EmissionInfo info; + + ASSERT_TRUE( decoder.decodeEmissionPIDs( SID::CURRENT_STATS, { 0x0D, 0x04, 0x0A, 0x0C, 0x05 }, txPDUData, info ) ); + ASSERT_EQ( info.mSID, SID::CURRENT_STATS ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_LOAD ) ).signalValue.doubleVal, 60 ); + ASSERT_DOUBLE_EQ( + info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ) ).signalValue.doubleVal, 70 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::FUEL_PRESSURE ) ).signalValue.doubleVal, 450 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::ENGINE_SPEED ) ).signalValue.doubleVal, + ( 256.0 * 0x0A + 0x6B ) / 4 ); + ASSERT_DOUBLE_EQ( info.mPIDsToValues.at( toUType( EmissionPIDs::VEHICLE_SPEED ) ).signalValue.doubleVal, 35 ); } TEST_F( OBDDataDecoderTest, OBDDataDecoderDecodedMultiplePIDsWrongPDU ) diff --git a/src/datamanagement/datadecoding/test/valgrind.supp b/src/datamanagement/datadecoding/test/valgrind.supp index 17d9a8d5..fb93ef2c 100644 --- a/src/datamanagement/datadecoding/test/valgrind.supp +++ b/src/datamanagement/datadecoding/test/valgrind.supp @@ -30,3 +30,12 @@ fun:*add_persistence_guid* ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/datamanagement/datainspection/include/CANDataConsumer.h b/src/datamanagement/datainspection/include/CANDataConsumer.h index 10204326..4a75fccb 100644 --- a/src/datamanagement/datainspection/include/CANDataConsumer.h +++ b/src/datamanagement/datainspection/include/CANDataConsumer.h @@ -9,7 +9,6 @@ #include "ClockHandler.h" #include "IDecoderDictionary.h" #include "IVehicleDataConsumer.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -98,7 +97,6 @@ class CANDataConsumer : public IVehicleDataConsumer std::atomic mShouldStop{ false }; std::atomic mShouldSleep{ false }; mutable std::mutex mThreadMutex; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); std::mutex mDecoderDictMutex; std::unique_ptr mCANDecoder; diff --git a/src/datamanagement/datainspection/include/CollectionInspectionEngine.h b/src/datamanagement/datainspection/include/CollectionInspectionEngine.h index 74f1c5d6..13573990 100644 --- a/src/datamanagement/datainspection/include/CollectionInspectionEngine.h +++ b/src/datamanagement/datainspection/include/CollectionInspectionEngine.h @@ -13,6 +13,7 @@ #include // As _Find_first() is not part of C++ standard and compiler specific other structure could be considered #include +#include namespace Aws { @@ -84,9 +85,13 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * * @param id id of the obd based or can based signal * @param receiveTime timestamp at which time was the signal seen on the physical bus - * @param value the signal value as double + * @param value the signal value */ - void addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, InspectionValue value ); + template + void addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, T value ); + + template + void addSignalToBuffer( const InspectionMatrixSignalCollectionInfo &signalIn ); /** * @brief Add new raw CAN Frame history buffer. If frame is not needed call will be just ignored @@ -159,9 +164,10 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre private: std::bitset mAlreadyConsumed{ 0 }; }; + template struct SignalSample : SampleConsumed { - InspectionValue mValue{ 0.0 }; + T mValue; InspectionTimestamp mTimestamp{ 0 }; }; @@ -183,6 +189,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * need to look at historic values. The window is time based and not sample based. * Currently the last 2 windows are maintained inside this class. * */ + template class FixedTimeWindowFunctionData { public: @@ -195,24 +202,24 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre InspectionTimestamp mLastTimeCalculated{ 0 }; /** ::min() }; - InspectionValue mLastMax{ std::numeric_limits::max() }; - InspectionValue mLastAvg{ 0 }; + T mLastMin{ std::numeric_limits::min() }; + T mLastMax{ std::numeric_limits::max() }; + T mLastAvg{ 0 }; bool mLastAvailable{ false }; /** ::min() }; - InspectionValue mPreviousLastMax{ std::numeric_limits::max() }; - InspectionValue mPreviousLastAvg{ 0 }; + T mPreviousLastMin{ std::numeric_limits::min() }; + T mPreviousLastMax{ std::numeric_limits::max() }; + T mPreviousLastAvg{ 0 }; bool mPreviousLastAvailable{ false }; // This values are changed online with every new signal sample and will be used to calculate // the next window as soon as the window time is over - InspectionValue mCollectingMin{ std::numeric_limits::min() }; - InspectionValue mCollectingMax{ std::numeric_limits::max() }; - InspectionValue mCollectingSum{ 0 }; + T mCollectingMin{ std::numeric_limits::min() }; + T mCollectingMax{ std::numeric_limits::max() }; + double mCollectingSum{ 0 }; uint32_t mCollectedSignals{ 0 }; /** @@ -225,9 +232,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre */ bool updateWindow( InspectionTimestamp timestamp, InspectionTimestamp &nextWindowFunctionTimesOut ); inline void - addValue( InspectionValue value, - InspectionTimestamp timestamp, - InspectionTimestamp &nextWindowFunctionTimesOut ) + addValue( T value, InspectionTimestamp timestamp, InspectionTimestamp &nextWindowFunctionTimesOut ) { updateWindow( timestamp, nextWindowFunctionTimesOut ); updateInternalVariables( value ); @@ -235,18 +240,18 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre private: inline void - updateInternalVariables( InspectionValue value ) + updateInternalVariables( T value ) { mCollectingMin = std::min( mCollectingMin, value ); mCollectingMax = std::max( mCollectingMax, value ); - mCollectingSum += value; + mCollectingSum += static_cast( value ); mCollectedSignals++; } inline void initNewWindow( InspectionTimestamp timestamp, InspectionTimestamp &nextWindowFunctionTimesOut ) { - mCollectingMin = std::numeric_limits::max(); - mCollectingMax = std::numeric_limits::min(); + mCollectingMin = std::numeric_limits::max(); + mCollectingMax = std::numeric_limits::min(); mCollectingSum = 0; mCollectedSignals = 0; mLastTimeCalculated += @@ -261,6 +266,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * The signal can be used as part of a condition or only to be published in the case * a condition is true */ + template struct SignalHistoryBuffer { SignalHistoryBuffer() = default; @@ -272,26 +278,26 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre } uint32_t mMinimumSampleIntervalMs{ 0 }; - std::vector + std::vector> mBuffer; // ringbuffer, Consider to move to raw pointer allocated with new[] if vector allocates too much uint32_t mSize{ 0 }; // minimum size needed by all conditions, buffer must be at least this big uint32_t mCurrentPosition{ 0 }; /**< position in ringbuffer needs to come after size as it depends on it */ uint32_t mCounter{ 0 }; /**< over all recorded samples*/ TimePoint mLastSample{ 0, 0 }; - std::vector + std::vector> mWindowFunctionData; /**< every signal buffer can have multiple windows over different time periods*/ std::bitset mConditionsThatEvaluateOnThisSignal; /**< if bit 0 is set it means element with index 0 of vector conditions needs to reevaluate if this signal changes*/ - inline FixedTimeWindowFunctionData * + inline FixedTimeWindowFunctionData * addFixedWindow( uint32_t windowSizeMs ) { if ( windowSizeMs == 0 ) { return nullptr; } - FixedTimeWindowFunctionData *findWindow = getFixedWindow( windowSizeMs ); + FixedTimeWindowFunctionData *findWindow = getFixedWindow( windowSizeMs ); if ( findWindow != nullptr ) { return findWindow; @@ -300,7 +306,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre return &( mWindowFunctionData.back() ); } - inline FixedTimeWindowFunctionData * + inline FixedTimeWindowFunctionData * getFixedWindow( uint32_t windowSizeMs ) { if ( windowSizeMs == 0 ) @@ -347,6 +353,32 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre TimePoint mLastSample{ 0, 0 }; }; + // VSS supported datatypes + using signalHistoryBufferPtrVar = boost::variant *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *, + SignalHistoryBuffer *>; + + // VSS supported datatypes + using FixedTimeWindowFunctionPtrVar = boost::variant *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *, + FixedTimeWindowFunctionData *>; + /** * @brief Stores information specific to one condition like the last time if was true */ @@ -358,13 +390,60 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre } InspectionTimestamp mLastDataTimestampPublished{ 0 }; TimePoint mLastTrigger{ 0, 0 }; - std::unordered_map + // TODO** :: Update the type here + std::unordered_map mEvaluationSignals; // for fast lookup signals used for evaluation - std::unordered_map + std::unordered_map mEvaluationFunctions; // for fast lookup functions used for evaluation const ConditionWithCollectedData &mCondition; // Unique Identifier of the Event matched by this condition. EventID mEventID{ 0 }; + + template + SignalHistoryBuffer * + getEvaluationSignalsBufferPtr( InspectionSignalID signalIDIn ) + { + auto evaluationSignalPtr = mEvaluationSignals.find( signalIDIn ); + if ( evaluationSignalPtr == mEvaluationSignals.end() ) + { + return nullptr; + } + try + { + auto vecPtr = boost::get *>( &( evaluationSignalPtr->second ) ); + if ( vecPtr != nullptr ) + { + return *vecPtr; + } + } + catch ( ... ) + { + } + return nullptr; + } + + template + FixedTimeWindowFunctionData * + getFixedTimeWindowFunctionDataPtr( InspectionSignalID signalIDIn ) + { + auto evaluationfunctionPtr = mEvaluationFunctions.find( signalIDIn ); + if ( evaluationfunctionPtr == mEvaluationFunctions.end() ) + { + return nullptr; + } + try + { + auto vecPtr = boost::get *>( &( evaluationfunctionPtr->second ) ); + if ( vecPtr != nullptr ) + { + return *vecPtr; + } + } + catch ( ... ) + { + } + return nullptr; + } }; enum class ExpressionErrorCode @@ -377,7 +456,6 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre NOT_IMPLEMENTED_FUNCTION }; - SignalHistoryBuffer &addSignalToBuffer( const InspectionMatrixSignalCollectionInfo &signal ); bool preAllocateBuffers(); bool isSignalPartOfEval( const struct ExpressionNode *expression, InspectionSignalID signalID, @@ -391,17 +469,26 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre ExpressionErrorCode getLatestSignalValue( InspectionSignalID id, ActiveCondition &condition, InspectionValue &result ); - static ExpressionErrorCode getSampleWindowFunction( WindowFunction function, - InspectionSignalID signalID, - ActiveCondition &condition, - InspectionValue &result ); + ExpressionErrorCode getSampleWindowFunction( WindowFunction function, + InspectionSignalID signalID, + ActiveCondition &condition, + InspectionValue &result ); + + template + ExpressionErrorCode getSampleWindowFunctionType( WindowFunction function, + InspectionSignalID signalID, + ActiveCondition &condition, + InspectionValue &result ); + ExpressionErrorCode getGeohashFunctionNode( const struct ExpressionNode *expression, ActiveCondition &condition, bool &resultValueBool ); + template void collectLastSignals( InspectionSignalID id, uint32_t minimumSamplingInterval, uint32_t maxNumberOfSignalsToCollect, uint32_t conditionId, + SignalType signalTypeIn, InspectionTimestamp &newestSignalTimestamp, std::vector &output ); void collectLastCanFrames( CANRawFrameID canID, @@ -412,6 +499,11 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre InspectionTimestamp &newestSignalTimestamp, std::vector &output ); + template + void updateConditionBuffer( const InspectionMatrixSignalCollectionInfo &inspectionMatrixCollectionInfoIn, + ActiveCondition &acIn, + const long unsigned int conditionIndexIn ); + void updateAllFixedWindowFunctions( InspectionTimestamp timestamp ); /** @@ -444,11 +536,74 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre return ++counter; } - using SignalHistoryBufferCollection = std::unordered_map>; + // VSS supported datatypes + using signalHistoryBufferVar = boost::variant>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>, + std::vector>>; + using SignalHistoryBufferCollection = std::unordered_map; SignalHistoryBufferCollection mSignalBuffers; /**< signal history buffer. First vector has the signalID as index. In the nested vector * the different subsampling of this signal are stored. */ + using SignalToBufferTypeMap = std::unordered_map; + SignalToBufferTypeMap mSignalToBufferTypeMap; + + template + std::vector> * + getSignalHistoryBufferPtr( InspectionSignalID signalIDIn ) + { + std::vector> *resVec = nullptr; + if ( mSignalBuffers.find( signalIDIn ) == mSignalBuffers.end() ) + { + // create a new map entry + auto mapEntryVec = std::vector>{}; + try + { + signalHistoryBufferVar mapEntry = mapEntryVec; + mSignalBuffers.insert( { signalIDIn, mapEntry } ); + } + catch ( ... ) + { + FWE_LOG_ERROR( "Cannot Insert the signalHistoryBuffer vector for Signal " + + std::to_string( signalIDIn ) ); + return nullptr; + } + } + + try + { + auto signalBufferVectorPtr = mSignalBuffers.find( signalIDIn ); + if ( signalBufferVectorPtr != mSignalBuffers.end() ) + { + resVec = boost::get>>( &( signalBufferVectorPtr->second ) ); + } + } + catch ( ... ) + { + FWE_LOG_ERROR( "Cannot retrive the signalHistoryBuffer vector for Signal " + std::to_string( signalIDIn ) ); + } + return resVec; + } + + template + bool allocateBufferVector( SignalID signalIDIn, uint32_t &usedBytes ); + + template + void updateBufferFixedWindowFunction( SignalID signalIDIn, InspectionTimestamp timestamp ); + + template + ExpressionErrorCode getLatestBufferSignalValue( InspectionSignalID id, + ActiveCondition &condition, + InspectionValue &result ); + using CanFrameHistoryBufferCollection = std::vector; CanFrameHistoryBufferCollection mCanFrameBuffers; /**< signal history buffer for raw can frames. */ DTCInfo mActiveDTCs; @@ -485,11 +640,110 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre uint32_t mNextConditionToCollectedIndex{ 0 }; InspectionTimestamp mNextWindowFunctionTimesOut{ 0 }; - Aws::IoTFleetWise::Platform::Linux::LoggingModule mLogger; DataReduction mDataReduction; bool mSendDataOnlyOncePerCondition{ false }; }; +template +void +CollectionInspectionEngine::addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, T value ) +{ + if ( mSignalBuffers.find( id ) == mSignalBuffers.end() || mSignalBuffers[id].empty() ) + { + // Signal not collected by any active condition + return; + } + // Iterate through all sampling intervals of the signal + std::vector> *signalHistoryBufferPtr = nullptr; + signalHistoryBufferPtr = getSignalHistoryBufferPtr( id ); + if ( signalHistoryBufferPtr == nullptr ) + { + // Invalid access to the map Buffer datatype + return; + } + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &buf : bufferVec ) + { + if ( ( ( buf.mSize > 0 ) && ( buf.mSize <= buf.mBuffer.size() ) ) && + ( ( buf.mMinimumSampleIntervalMs == 0 ) || + ( ( buf.mLastSample.systemTimeMs == 0 ) && ( buf.mLastSample.monotonicTimeMs == 0 ) ) || + ( receiveTime.monotonicTimeMs >= buf.mLastSample.monotonicTimeMs + buf.mMinimumSampleIntervalMs ) ) ) + { + buf.mCurrentPosition++; + if ( buf.mCurrentPosition >= buf.mSize ) + { + buf.mCurrentPosition = 0; + } + buf.mBuffer[buf.mCurrentPosition].mValue = value; + buf.mBuffer[buf.mCurrentPosition].mTimestamp = receiveTime.systemTimeMs; + buf.mBuffer[buf.mCurrentPosition].setAlreadyConsumed( ALL_CONDITIONS, false ); + buf.mCounter++; + buf.mLastSample = receiveTime; + for ( auto &window : buf.mWindowFunctionData ) + { + window.addValue( value, receiveTime.monotonicTimeMs, mNextWindowFunctionTimesOut ); + } + mConditionsWithInputSignalChanged |= buf.mConditionsThatEvaluateOnThisSignal; + } + } +} + +template +bool +CollectionInspectionEngine::FixedTimeWindowFunctionData::updateWindow( + InspectionTimestamp timestamp, InspectionTimestamp &nextWindowFunctionTimesOut ) +{ + if ( mLastTimeCalculated == 0 ) + { + // First time a signal arrives start the window for this signal + mLastTimeCalculated = timestamp; + initNewWindow( timestamp, nextWindowFunctionTimesOut ); + } + // check the last 2 windows as this class records the last and previous last data + else if ( timestamp >= mLastTimeCalculated + mWindowSizeMs * 2 ) + { + // In the last window not a single sample arrived + mLastAvailable = false; + if ( mCollectedSignals == 0 ) + { + mPreviousLastAvailable = false; + } + else + { + mPreviousLastAvailable = true; + mPreviousLastMin = mCollectingMin; + mPreviousLastMax = mCollectingMax; + mPreviousLastAvg = static_cast( mCollectingSum / mCollectedSignals ); + } + initNewWindow( timestamp, nextWindowFunctionTimesOut ); + } + else if ( timestamp >= mLastTimeCalculated + mWindowSizeMs ) + { + mPreviousLastMin = mLastMin; + mPreviousLastMax = mLastMax; + mPreviousLastAvg = mLastAvg; + mPreviousLastAvailable = mLastAvailable; + if ( mCollectedSignals == 0 ) + { + mLastAvailable = false; + } + else + { + mLastAvailable = true; + mLastMin = mCollectingMin; + mLastMax = mCollectingMax; + mLastAvg = static_cast( mCollectingSum / mCollectedSignals ); + } + initNewWindow( timestamp, nextWindowFunctionTimesOut ); + } + else + { + nextWindowFunctionTimesOut = std::min( nextWindowFunctionTimesOut, mLastTimeCalculated + mWindowSizeMs ); + return false; + } + return true; +} + } // namespace DataInspection } // namespace IoTFleetWise } // namespace Aws diff --git a/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h b/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h index 53d69ded..29c7954a 100644 --- a/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h +++ b/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h @@ -7,7 +7,6 @@ #include "CollectionInspectionEngine.h" #include "IDataReadyToPublishListener.h" #include "Listener.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -111,7 +110,7 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, static void doWork( void *data ); - TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); + static TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); CollectionInspectionEngine fCollectionInspectionEngine; @@ -126,7 +125,6 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, std::mutex fInspectionMatrixMutex; std::mutex fThreadMutex; Platform::Linux::Signal fWait; - LoggingModule fLogger; uint32_t fIdleTimeMs{ DEFAULT_THREAD_IDLE_TIME_MS }; std::shared_ptr fClock = ClockHandler::getClock(); }; diff --git a/src/datamanagement/datainspection/include/DataOverDDSModule.h b/src/datamanagement/datainspection/include/DataOverDDSModule.h index a1262a85..565fa06e 100644 --- a/src/datamanagement/datainspection/include/DataOverDDSModule.h +++ b/src/datamanagement/datainspection/include/DataOverDDSModule.h @@ -6,7 +6,6 @@ // Includes #include "ClockHandler.h" #include "InspectionEventListener.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -112,7 +111,6 @@ class DataOverDDSModule : public InspectionEventListener, public SensorDataListe std::atomic mShouldStop{ false }; std::atomic mNewEventReceived{ false }; mutable std::mutex mThreadMutex; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); Platform::Linux::Signal mWait; Timer mTimer; diff --git a/src/datamanagement/datainspection/include/GeohashFunctionNode.h b/src/datamanagement/datainspection/include/GeohashFunctionNode.h index c2d8d8ba..76bbacf5 100644 --- a/src/datamanagement/datainspection/include/GeohashFunctionNode.h +++ b/src/datamanagement/datainspection/include/GeohashFunctionNode.h @@ -6,7 +6,6 @@ #include "Geohash.h" #include "GeohashInfo.h" #include "ICollectionScheme.h" -#include "LoggingModule.h" #include namespace Aws @@ -81,11 +80,6 @@ class GeohashFunctionNode * @brief If this flag is true, it indicates a Geohash has been generated but not read yet. */ bool mIsGeohashNew{ false }; - - /** - * @brief Logging module used to output to logs - */ - LoggingModule mLogger; }; } // namespace DataInspection } // namespace IoTFleetWise diff --git a/src/datamanagement/datainspection/include/OBDOverCANECU.h b/src/datamanagement/datainspection/include/OBDOverCANECU.h index 10e43ed7..dbfdee09 100644 --- a/src/datamanagement/datainspection/include/OBDOverCANECU.h +++ b/src/datamanagement/datainspection/include/OBDOverCANECU.h @@ -5,7 +5,6 @@ // Includes #include "CollectionInspectionAPITypes.h" -#include "LoggingModule.h" #include "OBDDataDecoder.h" #include "businterfaces/ISOTPOverCANSenderReceiver.h" @@ -142,7 +141,6 @@ class OBDOverCANECU bool requestDTCs( const SID sid ); bool receiveDTCs( const SID sid, DTCInfo &info ); - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); // A map contains the Supported PIDs for each service mode std::unordered_map mSupportedPIDs; diff --git a/src/datamanagement/datainspection/include/OBDOverCANModule.h b/src/datamanagement/datainspection/include/OBDOverCANModule.h index a5d743bd..ce62e958 100644 --- a/src/datamanagement/datainspection/include/OBDOverCANModule.h +++ b/src/datamanagement/datainspection/include/OBDOverCANModule.h @@ -8,7 +8,6 @@ #include "CollectionInspectionAPITypes.h" #include "IActiveConditionProcessor.h" #include "IActiveDecoderDictionaryListener.h" -#include "LoggingModule.h" #include "OBDDataDecoder.h" #include "OBDOverCANECU.h" #include "Signal.h" @@ -173,7 +172,6 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive std::atomic mShouldRequestDTCs{ false }; std::vector> mECUs; mutable std::mutex mThreadMutex; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); // Stop signal Platform::Linux::Signal mWait; diff --git a/src/datamanagement/datainspection/include/VehicleDataSourceBinder.h b/src/datamanagement/datainspection/include/VehicleDataSourceBinder.h index 62c23fe8..5b822e6d 100644 --- a/src/datamanagement/datainspection/include/VehicleDataSourceBinder.h +++ b/src/datamanagement/datainspection/include/VehicleDataSourceBinder.h @@ -7,7 +7,6 @@ #include "ClockHandler.h" #include "IActiveDecoderDictionaryListener.h" #include "IVehicleDataConsumer.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -134,7 +133,6 @@ class VehicleDataSourceBinder : public VehicleDataSourceListener, public IActive IdsToStates mDataSourceStates; Platform::Linux::Signal mWait; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); SourcesToConsumers mDataSourcesToConsumers; IdsToDataSources mIdsToDataSources; diff --git a/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp b/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp index 83eb9342..18f19378 100644 --- a/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp +++ b/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp @@ -20,23 +20,6 @@ CollectionInspectionEngine::CollectionInspectionEngine( bool sendDataOnlyOncePer setActiveDTCsConsumed( ALL_CONDITIONS, false ); } -CollectionInspectionEngine::SignalHistoryBuffer & -CollectionInspectionEngine::addSignalToBuffer( const InspectionMatrixSignalCollectionInfo &signal ) -{ - - for ( auto &buffer : mSignalBuffers[signal.signalID] ) - { - if ( buffer.mMinimumSampleIntervalMs == signal.minimumSampleIntervalMs ) - { - buffer.mSize = std::max( buffer.mSize, signal.sampleBufferSize ); - return buffer; - } - } - // No entry with same sample interval found - mSignalBuffers[signal.signalID].emplace_back( signal.sampleBufferSize, signal.minimumSampleIntervalMs ); - return mSignalBuffers[signal.signalID].back(); -} - bool CollectionInspectionEngine::isSignalPartOfEval( const struct ExpressionNode *expression, InspectionSignalID signalID, @@ -62,6 +45,33 @@ CollectionInspectionEngine::isSignalPartOfEval( const struct ExpressionNode *exp return leftRet || rightRet; } +template +void +CollectionInspectionEngine::addSignalToBuffer( const InspectionMatrixSignalCollectionInfo &signalIn ) +{ + std::vector> *signalHistoryBufferPtr = nullptr; + const auto signalIDIn = signalIn.signalID; + + signalHistoryBufferPtr = getSignalHistoryBufferPtr( signalIDIn ); + + if ( signalHistoryBufferPtr == nullptr ) + { + return; + } + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &buffer : bufferVec ) + { + if ( buffer.mMinimumSampleIntervalMs == signalIn.minimumSampleIntervalMs ) + { + buffer.mSize = std::max( buffer.mSize, signalIn.sampleBufferSize ); + buffer.addFixedWindow( signalIn.fixedWindowPeriod ); + return; + } + } + bufferVec.emplace_back( signalIn.sampleBufferSize, signalIn.minimumSampleIntervalMs ); + bufferVec.back().addFixedWindow( signalIn.fixedWindowPeriod ); +} + void CollectionInspectionEngine::onChangeInspectionMatrix( const std::shared_ptr &activeInspectionMatrix ) @@ -77,38 +87,72 @@ CollectionInspectionEngine::onChangeInspectionMatrix( if ( mConditions.size() >= MAX_NUMBER_OF_ACTIVE_CONDITION ) { TraceModule::get().incrementVariable( TraceVariable::CE_TOO_MANY_CONDITIONS ); - mLogger.warn( "CollectionInspectionEngine::onChangeInspectionMatrix", - "Too many conditions are active. Up to " + - std::to_string( MAX_NUMBER_OF_ACTIVE_CONDITION - 1 ) + - " conditions can be active at a time. Additional conditions will be skipped" ); + FWE_LOG_WARN( "Too many conditions are active. Up to " + + std::to_string( MAX_NUMBER_OF_ACTIVE_CONDITION - 1 ) + + " conditions can be active at a time. Additional conditions will be skipped" ); break; } mConditions.emplace_back( p ); if ( p.signals.size() > MAX_DIFFERENT_SIGNAL_IDS ) { TraceModule::get().incrementVariable( TraceVariable::CE_SIGNAL_ID_OUTBOUND ); - mLogger.error( "CollectionInspectionEngine::onChangeInspectionMatrix", - "There can be only " + std::to_string( MAX_DIFFERENT_SIGNAL_IDS ) + - " different signal IDs" ); + FWE_LOG_ERROR( "There can be only " + std::to_string( MAX_DIFFERENT_SIGNAL_IDS ) + + " different signal IDs" ); return; } for ( auto &s : p.signals ) { if ( s.signalID == INVALID_SIGNAL_ID ) { - mLogger.error( "CollectionInspectionEngine::onChangeInspectionMatrix", - "A SignalID with value" + std::to_string( INVALID_SIGNAL_ID ) + " is not allowed" ); + FWE_LOG_ERROR( "A SignalID with value" + std::to_string( INVALID_SIGNAL_ID ) + " is not allowed" ); return; } if ( s.sampleBufferSize == 0 ) { TraceModule::get().incrementVariable( TraceVariable::CE_SAMPLE_SIZE_ZERO ); - mLogger.error( "CollectionInspectionEngine::onChangeInspectionMatrix", - "A Sample buffer size of 0 is not allowed" ); + FWE_LOG_ERROR( "A Sample buffer size of 0 is not allowed" ); return; } - SignalHistoryBuffer &buf = addSignalToBuffer( s ); - buf.addFixedWindow( s.fixedWindowPeriod ); + auto signalIDIn = s.signalID; + mSignalToBufferTypeMap.insert( { signalIDIn, s.signalType } ); + switch ( s.signalType ) + { + case SignalType::UINT8: + addSignalToBuffer( s ); + break; + case SignalType::INT8: + addSignalToBuffer( s ); + break; + case SignalType::UINT16: + addSignalToBuffer( s ); + break; + case SignalType::INT16: + addSignalToBuffer( s ); + break; + case SignalType::UINT32: + addSignalToBuffer( s ); + break; + case SignalType::INT32: + addSignalToBuffer( s ); + break; + case SignalType::UINT64: + addSignalToBuffer( s ); + break; + case SignalType::INT64: + addSignalToBuffer( s ); + break; + case SignalType::FLOAT: + addSignalToBuffer( s ); + break; + case SignalType::DOUBLE: + addSignalToBuffer( s ); + break; + case SignalType::BOOLEAN: + addSignalToBuffer( s ); + break; + default: + break; + } } for ( auto &c : p.canFrames ) { @@ -136,24 +180,43 @@ CollectionInspectionEngine::onChangeInspectionMatrix( auto &ac = mConditions[conditionIndex]; for ( auto &s : ac.mCondition.signals ) { - SignalHistoryBuffer *buf = nullptr; - for ( auto &buffer : mSignalBuffers[s.signalID] ) - { - if ( buffer.mMinimumSampleIntervalMs == s.minimumSampleIntervalMs ) - { - buf = &buffer; - break; - } - } - if ( ( buf != nullptr ) && isSignalPartOfEval( ac.mCondition.condition, s.signalID, MAX_EQUATION_DEPTH ) ) + switch ( s.signalType ) { - buf->mConditionsThatEvaluateOnThisSignal.set( conditionIndex ); - ac.mEvaluationSignals[s.signalID] = buf; - FixedTimeWindowFunctionData *window = buf->getFixedWindow( s.fixedWindowPeriod ); - if ( window != nullptr ) - { - ac.mEvaluationFunctions[s.signalID] = window; - } + case SignalType::UINT8: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::INT8: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::UINT16: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::INT16: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::UINT32: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::INT32: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::UINT64: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::INT64: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::FLOAT: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::DOUBLE: + updateConditionBuffer( s, ac, conditionIndex ); + break; + case SignalType::BOOLEAN: + updateConditionBuffer( s, ac, conditionIndex ); + break; + default: + break; } } } @@ -163,25 +226,66 @@ CollectionInspectionEngine::onChangeInspectionMatrix( (void)preAllocateBuffers(); } + +template +void +CollectionInspectionEngine::updateConditionBuffer( + const InspectionMatrixSignalCollectionInfo &inspectionMatrixCollectionInfoIn, + ActiveCondition &acIn, + const long unsigned int conditionIndexIn ) +{ + SignalID signalIDIn = inspectionMatrixCollectionInfoIn.signalID; + SignalHistoryBuffer *buf = nullptr; + std::vector> *signalHistoryBufferPtr = nullptr; + + signalHistoryBufferPtr = getSignalHistoryBufferPtr( signalIDIn ); + + if ( signalHistoryBufferPtr != nullptr ) + { + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &buffer : bufferVec ) + { + if ( buffer.mMinimumSampleIntervalMs == inspectionMatrixCollectionInfoIn.minimumSampleIntervalMs ) + { + buf = &buffer; + break; + } + } + } + if ( ( buf != nullptr ) && isSignalPartOfEval( acIn.mCondition.condition, signalIDIn, MAX_EQUATION_DEPTH ) ) + { + buf->mConditionsThatEvaluateOnThisSignal.set( conditionIndexIn ); + // acIn.mEvaluationSignals[signalIDIn] = buf; + acIn.mEvaluationSignals.insert( { signalIDIn, buf } ); + FixedTimeWindowFunctionData *window = + buf->getFixedWindow( inspectionMatrixCollectionInfoIn.fixedWindowPeriod ); + if ( window != nullptr ) + { + // acIn.mEvaluationFunctions[signalIDIn] = window; + acIn.mEvaluationFunctions.insert( { signalIDIn, window } ); + } + } +} + +template bool -CollectionInspectionEngine::preAllocateBuffers() +CollectionInspectionEngine::allocateBufferVector( SignalID signalIDIn, uint32_t &usedBytes ) { - // Allocate size - uint32_t usedBytes = 0; - // Allocate Signal Buffer - for ( auto &bufferVector : mSignalBuffers ) + std::vector> *signalHistoryBufferPtr = nullptr; + signalHistoryBufferPtr = getSignalHistoryBufferPtr( signalIDIn ); + + if ( signalHistoryBufferPtr != nullptr ) { - // Go trough different sample intervals - for ( auto &signal : bufferVector.second ) + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &signal : bufferVec ) { - uint64_t requiredBytes = signal.mSize * static_cast( sizeof( struct SignalSample ) ); + uint64_t requiredBytes = signal.mSize * static_cast( sizeof( struct SignalSample ) ); if ( usedBytes + requiredBytes > MAX_SAMPLE_MEMORY ) { - mLogger.warn( "CollectionInspectionEngine::preAllocateBuffers", - "The requested " + std::to_string( signal.mSize ) + - " number of signal samples leads to a memory requirement that's above the maximum " - "configured of " + - std::to_string( MAX_SAMPLE_MEMORY ) + "Bytes" ); + FWE_LOG_WARN( "The requested " + std::to_string( signal.mSize ) + + " number of signal samples leads to a memory requirement that's above the maximum " + "configured of " + + std::to_string( MAX_SAMPLE_MEMORY ) + "Bytes" ); signal.mSize = 0; return false; } @@ -191,17 +295,109 @@ CollectionInspectionEngine::preAllocateBuffers() signal.mBuffer.resize( signal.mSize ); } } + return true; +} + +bool +CollectionInspectionEngine::preAllocateBuffers() +{ + // Allocate size + uint32_t usedBytes = 0; + + // Allocate Signal Buffer + for ( auto &bufferVector : mSignalBuffers ) + { + auto signalID = bufferVector.first; + if ( mSignalToBufferTypeMap.find( signalID ) != mSignalToBufferTypeMap.end() ) + { + auto signalType = mSignalToBufferTypeMap[signalID]; + switch ( signalType ) + { + case SignalType::UINT8: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::INT8: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::UINT16: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::INT16: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::UINT32: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::INT32: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::UINT64: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::INT64: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::FLOAT: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::DOUBLE: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + case SignalType::BOOLEAN: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + default: + if ( !allocateBufferVector( signalID, usedBytes ) ) + { + return false; + } + break; + } + } + } // Allocate Can buffer for ( auto &buf : mCanFrameBuffers ) { uint64_t requiredBytes = buf.mSize * static_cast( sizeof( struct CanFrameSample ) ); if ( usedBytes + requiredBytes > MAX_SAMPLE_MEMORY ) { - mLogger.warn( "CollectionInspectionEngine::preAllocateBuffers", - "The requested " + std::to_string( buf.mSize ) + - " number of CAN raw samples leads to a memory requirement that's above the maximum " - "configured of" + - std::to_string( MAX_SAMPLE_MEMORY ) + "Bytes" ); + FWE_LOG_WARN( "The requested " + std::to_string( buf.mSize ) + + " number of CAN raw samples leads to a memory requirement that's above the maximum " + "configured of" + + std::to_string( MAX_SAMPLE_MEMORY ) + "Bytes" ); buf.mSize = 0; return false; } @@ -217,6 +413,7 @@ void CollectionInspectionEngine::clear() { mSignalBuffers.clear(); + mSignalToBufferTypeMap.clear(); mCanFrameBuffers.clear(); mConditions.clear(); mNextConditionToCollectedIndex = 0; @@ -226,13 +423,28 @@ CollectionInspectionEngine::clear() mConditionsNotTriggeredWaitingPublished.reset(); } +template void -CollectionInspectionEngine::updateAllFixedWindowFunctions( InspectionTimestamp timestamp ) +CollectionInspectionEngine::updateBufferFixedWindowFunction( SignalID signalIDIn, InspectionTimestamp timestamp ) { - mNextWindowFunctionTimesOut = std::numeric_limits::max(); - for ( auto &signalVector : mSignalBuffers ) + std::vector> *signalHistoryBufferPtr = nullptr; + try { - for ( auto &signal : signalVector.second ) + if ( mSignalBuffers.find( signalIDIn ) != mSignalBuffers.end() ) + { + auto &mapVal = mSignalBuffers.at( signalIDIn ); + signalHistoryBufferPtr = boost::get>>( &mapVal ); + } + } + catch ( ... ) + { + FWE_LOG_ERROR( "Failed to retrieve signalHistoryBuffer vector for signal ID " + std::to_string( signalIDIn ) ); + return; + } + if ( signalHistoryBufferPtr != nullptr ) + { + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &signal : bufferVec ) { for ( auto &functionWindow : signal.mWindowFunctionData ) { @@ -246,6 +458,60 @@ CollectionInspectionEngine::updateAllFixedWindowFunctions( InspectionTimestamp t } } +void +CollectionInspectionEngine::updateAllFixedWindowFunctions( InspectionTimestamp timestamp ) +{ + mNextWindowFunctionTimesOut = std::numeric_limits::max(); + for ( auto &signalVector : mSignalBuffers ) + { + auto signalID = signalVector.first; + if ( mSignalToBufferTypeMap.find( signalID ) != mSignalToBufferTypeMap.end() ) + { + + auto signalType = mSignalToBufferTypeMap[signalID]; + switch ( signalType ) + { + case SignalType::UINT8: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::INT8: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::UINT16: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::INT16: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::UINT32: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::INT32: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::UINT64: + + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::INT64: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::FLOAT: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::DOUBLE: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + case SignalType::BOOLEAN: + updateBufferFixedWindowFunction( signalID, timestamp ); + break; + default: + break; + } + } + } +} + bool CollectionInspectionEngine::evaluateConditions( const TimePoint ¤tTime ) { @@ -253,6 +519,7 @@ CollectionInspectionEngine::evaluateConditions( const TimePoint ¤tTime ) // if any sampling window times out there is a new value available to be processed by a condition if ( currentTime.monotonicTimeMs >= mNextWindowFunctionTimesOut ) { + updateAllFixedWindowFunctions( currentTime.monotonicTimeMs ); } auto conditionsToEvaluate = ( mConditionsWithConditionCurrentlyTrue | mConditionsWithInputSignalChanged ) & @@ -299,11 +566,13 @@ CollectionInspectionEngine::evaluateConditions( const TimePoint ¤tTime ) return oneConditionIsTrue; } +template void CollectionInspectionEngine::collectLastSignals( InspectionSignalID id, uint32_t minimumSamplingInterval, uint32_t maxNumberOfSignalsToCollect, uint32_t conditionId, + SignalType signalTypeIn, InspectionTimestamp &newestSignalTimestamp, std::vector &output ) { @@ -312,8 +581,15 @@ CollectionInspectionEngine::collectLastSignals( InspectionSignalID id, // Signal not collected by any active condition return; } - // Iterate through all sampling intervals of the signal - for ( auto &buf : mSignalBuffers[id] ) + std::vector> *signalHistoryBufferPtr = nullptr; + signalHistoryBufferPtr = getSignalHistoryBufferPtr( id ); + if ( signalHistoryBufferPtr == nullptr ) + { + // Access by Invalid DataType + return; + } + auto &bufferVec = *signalHistoryBufferPtr; + for ( auto &buf : bufferVec ) { if ( ( buf.mMinimumSampleIntervalMs == minimumSamplingInterval ) && ( buf.mSize > 0 ) ) { @@ -332,7 +608,7 @@ CollectionInspectionEngine::collectLastSignals( InspectionSignalID id, auto &sample = buf.mBuffer[static_cast( pos )]; if ( ( !sample.isAlreadyConsumed( conditionId ) ) || ( !mSendDataOnlyOncePerCondition ) ) { - output.emplace_back( id, sample.mTimestamp, sample.mValue ); + output.emplace_back( id, sample.mTimestamp, sample.mValue, signalTypeIn ); sample.setAlreadyConsumed( conditionId, true ); } newestSignalTimestamp = std::max( newestSignalTimestamp, sample.mTimestamp ); @@ -396,12 +672,110 @@ CollectionInspectionEngine::collectData( ActiveCondition &condition, { if ( !s.isConditionOnlySignal ) { - collectLastSignals( s.signalID, - s.minimumSampleIntervalMs, - s.sampleBufferSize, - conditionId, - newestSignalTimestamp, - collectedData->signals ); + switch ( s.signalType ) + { + case SignalType::UINT8: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::INT8: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::UINT16: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::INT16: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::UINT32: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::INT32: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::UINT64: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::INT64: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::FLOAT: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::DOUBLE: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + case SignalType::BOOLEAN: + collectLastSignals( s.signalID, + s.minimumSampleIntervalMs, + s.sampleBufferSize, + conditionId, + s.signalType, + newestSignalTimestamp, + collectedData->signals ); + break; + default: + break; + } } } @@ -520,41 +894,6 @@ CollectionInspectionEngine::evaluateAndTriggerRichSensorCapture( const ActiveCon } } -void -CollectionInspectionEngine::addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, InspectionValue value ) -{ - if ( mSignalBuffers.find( id ) == mSignalBuffers.end() || mSignalBuffers[id].empty() ) - { - // Signal not collected by any active condition - return; - } - // Iterate through all sampling intervals of the signal - for ( auto &buf : mSignalBuffers[id] ) - { - if ( ( buf.mSize > 0 ) && ( buf.mSize <= buf.mBuffer.size() ) && - ( ( buf.mMinimumSampleIntervalMs == 0 ) || - ( ( buf.mLastSample.systemTimeMs == 0 ) && ( buf.mLastSample.monotonicTimeMs == 0 ) ) || - ( receiveTime.monotonicTimeMs >= buf.mLastSample.monotonicTimeMs + buf.mMinimumSampleIntervalMs ) ) ) - { - buf.mCurrentPosition++; - if ( buf.mCurrentPosition >= buf.mSize ) - { - buf.mCurrentPosition = 0; - } - buf.mBuffer[buf.mCurrentPosition].mValue = value; - buf.mBuffer[buf.mCurrentPosition].mTimestamp = receiveTime.systemTimeMs; - buf.mBuffer[buf.mCurrentPosition].setAlreadyConsumed( ALL_CONDITIONS, false ); - buf.mCounter++; - buf.mLastSample = receiveTime; - for ( auto &window : buf.mWindowFunctionData ) - { - window.addValue( value, receiveTime.monotonicTimeMs, mNextWindowFunctionTimesOut ); - } - mConditionsWithInputSignalChanged |= buf.mConditionsThatEvaluateOnThisSignal; - } - } -} - void CollectionInspectionEngine::addNewRawCanFrame( CANRawFrameID canID, CANChannelNumericID channelID, @@ -598,63 +937,117 @@ CollectionInspectionEngine::setActiveDTCs( const DTCInfo &activeDTCs ) mActiveDTCs = activeDTCs; } +template CollectionInspectionEngine::ExpressionErrorCode -CollectionInspectionEngine::getLatestSignalValue( InspectionSignalID id, - ActiveCondition &condition, - InspectionValue &result ) +CollectionInspectionEngine::getLatestBufferSignalValue( InspectionSignalID id, + ActiveCondition &condition, + InspectionValue &result ) { - auto mapLookup = condition.mEvaluationSignals.find( id ); - if ( ( mapLookup == condition.mEvaluationSignals.end() ) || ( mapLookup->second == nullptr ) ) + + auto *s = condition.getEvaluationSignalsBufferPtr( id ); + if ( s == nullptr ) { - mLogger.warn( "CollectionInspectionEngine::getLatestSignalValue", "SIGNAL_NOT_FOUND" ); + FWE_LOG_WARN( "SIGNAL_NOT_FOUND" ); // Signal not collected by any active condition return ExpressionErrorCode::SIGNAL_NOT_FOUND; } - SignalHistoryBuffer *s = mapLookup->second; if ( s->mCounter == 0 ) { // Not a single sample collected yet return ExpressionErrorCode::SIGNAL_NOT_FOUND; } - result = s->mBuffer[s->mCurrentPosition].mValue; + result = static_cast( s->mBuffer[s->mCurrentPosition].mValue ); return ExpressionErrorCode::SUCCESSFUL; } CollectionInspectionEngine::ExpressionErrorCode -CollectionInspectionEngine::getSampleWindowFunction( WindowFunction function, - InspectionSignalID signalID, - ActiveCondition &condition, - InspectionValue &result ) +CollectionInspectionEngine::getLatestSignalValue( InspectionSignalID id, + ActiveCondition &condition, + InspectionValue &result ) +{ + if ( mSignalToBufferTypeMap.find( id ) == mSignalToBufferTypeMap.end() ) + { + FWE_LOG_WARN( "SIGNAL_NOT_FOUND" ); + // Signal not collected by any active condition + return ExpressionErrorCode::SIGNAL_NOT_FOUND; + } + auto signalType = mSignalToBufferTypeMap[id]; + switch ( signalType ) + { + case SignalType::UINT8: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::INT8: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::UINT16: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::INT16: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::UINT32: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::INT32: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::UINT64: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::INT64: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::FLOAT: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::DOUBLE: + return getLatestBufferSignalValue( id, condition, result ); + break; + case SignalType::BOOLEAN: + return getLatestBufferSignalValue( id, condition, result ); + break; + default: + return ExpressionErrorCode::SIGNAL_NOT_FOUND; + break; + } +} + +template +CollectionInspectionEngine::ExpressionErrorCode +CollectionInspectionEngine::getSampleWindowFunctionType( WindowFunction function, + InspectionSignalID signalID, + ActiveCondition &condition, + InspectionValue &result ) { - auto mapLookup = condition.mEvaluationFunctions.find( signalID ); - if ( ( mapLookup == condition.mEvaluationFunctions.end() ) || ( mapLookup->second == nullptr ) ) + auto w = condition.getFixedTimeWindowFunctionDataPtr( signalID ); + if ( w == nullptr ) { // Signal not collected by any active condition return ExpressionErrorCode::SIGNAL_NOT_FOUND; } - auto w = mapLookup->second; switch ( function ) { case WindowFunction::LAST_FIXED_WINDOW_AVG: - result = w->mLastAvg; + result = static_cast( w->mLastAvg ); return w->mLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; case WindowFunction::LAST_FIXED_WINDOW_MIN: - result = w->mLastMin; + result = static_cast( w->mLastMin ); return w->mLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; case WindowFunction::LAST_FIXED_WINDOW_MAX: - result = w->mLastMax; + result = static_cast( w->mLastMax ); return w->mLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; case WindowFunction::PREV_LAST_FIXED_WINDOW_AVG: - result = w->mPreviousLastAvg; + result = static_cast( w->mPreviousLastAvg ); return w->mPreviousLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; case WindowFunction::PREV_LAST_FIXED_WINDOW_MIN: - result = w->mPreviousLastMin; + result = static_cast( w->mPreviousLastMin ); return w->mPreviousLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; case WindowFunction::PREV_LAST_FIXED_WINDOW_MAX: - result = w->mPreviousLastMax; + result = static_cast( w->mPreviousLastMax ); return w->mPreviousLastAvailable ? ExpressionErrorCode::SUCCESSFUL : ExpressionErrorCode::FUNCTION_DATA_NOT_AVAILABLE; default: @@ -662,6 +1055,60 @@ CollectionInspectionEngine::getSampleWindowFunction( WindowFunction function, } } +CollectionInspectionEngine::ExpressionErrorCode +CollectionInspectionEngine::getSampleWindowFunction( WindowFunction function, + InspectionSignalID signalID, + ActiveCondition &condition, + InspectionValue &result ) +{ + if ( mSignalToBufferTypeMap.find( signalID ) == mSignalToBufferTypeMap.end() ) + { + FWE_LOG_WARN( "SIGNAL_NOT_FOUND" ); + // Signal not collected by any active condition + return ExpressionErrorCode::SIGNAL_NOT_FOUND; + } + auto signalType = mSignalToBufferTypeMap[signalID]; + switch ( signalType ) + { + case SignalType::UINT8: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::INT8: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::UINT16: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::INT16: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::UINT32: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::INT32: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::UINT64: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::INT64: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::FLOAT: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::DOUBLE: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + case SignalType::BOOLEAN: + return getSampleWindowFunctionType( function, signalID, condition, result ); + break; + default: + return ExpressionErrorCode::SIGNAL_NOT_FOUND; + break; + } +} + CollectionInspectionEngine::ExpressionErrorCode CollectionInspectionEngine::getGeohashFunctionNode( const struct ExpressionNode *expression, ActiveCondition &condition, @@ -673,16 +1120,14 @@ CollectionInspectionEngine::getGeohashFunctionNode( const struct ExpressionNode auto status = getLatestSignalValue( expression->function.geohashFunction.latitudeSignalID, condition, latitude ); if ( status != ExpressionErrorCode::SUCCESSFUL ) { - mLogger.warn( "CollectionInspectionEngine::getGeohashFunctionNode", - "Unable to evaluate Geohash due to missing latitude signal" ); + FWE_LOG_WARN( "Unable to evaluate Geohash due to missing latitude signal" ); return status; } InspectionValue longitude = 0; status = getLatestSignalValue( expression->function.geohashFunction.longitudeSignalID, condition, longitude ); if ( status != ExpressionErrorCode::SUCCESSFUL ) { - mLogger.warn( "CollectionInspectionEngine::getGeohashFunctionNode", - "Unable to evaluate Geohash due to missing longitude signal" ); + FWE_LOG_WARN( "Unable to evaluate Geohash due to missing longitude signal" ); return status; } resultValueBool = mGeohashFunctionNode.evaluateGeohash( latitude, @@ -701,7 +1146,7 @@ CollectionInspectionEngine::eval( const struct ExpressionNode *expression, { if ( ( remainingStackDepth <= 0 ) || ( expression == nullptr ) ) { - mLogger.warn( "CollectionInspectionEngine::eval", "STACK_DEPTH_REACHED or nullptr" ); + FWE_LOG_WARN( "STACK_DEPTH_REACHED or nullptr" ); return ExpressionErrorCode::STACK_DEPTH_REACHED; } if ( expression->nodeType == ExpressionNodeType::FLOAT ) @@ -800,61 +1245,6 @@ CollectionInspectionEngine::eval( const struct ExpressionNode *expression, } } -bool -CollectionInspectionEngine::FixedTimeWindowFunctionData::updateWindow( InspectionTimestamp timestamp, - InspectionTimestamp &nextWindowFunctionTimesOut ) -{ - if ( mLastTimeCalculated == 0 ) - { - // First time a signal arrives start the window for this signal - mLastTimeCalculated = timestamp; - initNewWindow( timestamp, nextWindowFunctionTimesOut ); - } - // check the last 2 windows as this class records the last and previous last data - else if ( timestamp >= mLastTimeCalculated + mWindowSizeMs * 2 ) - { - // In the last window not a single sample arrived - mLastAvailable = false; - if ( mCollectedSignals == 0 ) - { - mPreviousLastAvailable = false; - } - else - { - mPreviousLastAvailable = true; - mPreviousLastMin = mCollectingMin; - mPreviousLastMax = mCollectingMax; - mPreviousLastAvg = mCollectingSum / mCollectedSignals; - } - initNewWindow( timestamp, nextWindowFunctionTimesOut ); - } - else if ( timestamp >= mLastTimeCalculated + mWindowSizeMs ) - { - mPreviousLastMin = mLastMin; - mPreviousLastMax = mLastMax; - mPreviousLastAvg = mLastAvg; - mPreviousLastAvailable = mLastAvailable; - if ( mCollectedSignals == 0 ) - { - mLastAvailable = false; - } - else - { - mLastAvailable = true; - mLastMin = mCollectingMin; - mLastMax = mCollectingMax; - mLastAvg = mCollectingSum / mCollectedSignals; - } - initNewWindow( timestamp, nextWindowFunctionTimesOut ); - } - else - { - nextWindowFunctionTimesOut = std::min( nextWindowFunctionTimesOut, mLastTimeCalculated + mWindowSizeMs ); - return false; - } - return true; -} - EventID CollectionInspectionEngine::generateEventID( InspectionTimestamp timestamp ) { diff --git a/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp b/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp index 7a06cb93..a148df0e 100644 --- a/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp +++ b/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionInspectionWorkerThread.h" +#include "LoggingModule.h" #include "TraceModule.h" namespace Aws @@ -38,8 +39,7 @@ CollectionInspectionWorkerThread::start() if ( ( fInputCANBuffer == nullptr ) || ( fInputCANBuffer == nullptr ) || ( fInputActiveDTCBuffer == nullptr ) || ( fOutputCollectedData == nullptr ) ) { - fLogger.error( "CollectionInspectionWorkerThread::start", - "Collection Engine cannot be started without correct configurations" ); + FWE_LOG_ERROR( "Collection Engine cannot be started without correct configurations" ); return false; } // Prevent concurrent stop/init @@ -49,11 +49,11 @@ CollectionInspectionWorkerThread::start() fShouldStop.store( false ); if ( !fThread.create( doWork, this ) ) { - fLogger.trace( "CollectionInspectionWorkerThread::start", "Inspection Thread failed to start" ); + FWE_LOG_TRACE( "Inspection Thread failed to start" ); } else { - fLogger.trace( "CollectionInspectionWorkerThread::start", "Inspection Thread started" ); + FWE_LOG_TRACE( "Inspection Thread started" ); fThread.setThreadName( "fwDICollInsEng" ); } @@ -69,10 +69,10 @@ CollectionInspectionWorkerThread::stop() } std::lock_guard lock( fThreadMutex ); fShouldStop.store( true, std::memory_order_relaxed ); - fLogger.trace( "CollectionInspectionWorkerThread::stop", "Request stop" ); + FWE_LOG_TRACE( "Request stop" ); fWait.notify(); fThread.release(); - fLogger.trace( "CollectionInspectionWorkerThread::stop", "Stop finished" ); + FWE_LOG_TRACE( "Stop finished" ); fShouldStop.store( false, std::memory_order_relaxed ); return !fThread.isActive(); } @@ -91,8 +91,7 @@ CollectionInspectionWorkerThread::onChangeInspectionMatrix( std::lock_guard lock( fInspectionMatrixMutex ); fUpdatedInspectionMatrix = activeConditions; fUpdatedInspectionMatrixAvailable = true; - fLogger.trace( "CollectionInspectionWorkerThread::onChangeInspectionMatrix", - "New inspection matrix handed over" ); + FWE_LOG_TRACE( "New inspection matrix handed over" ); // Wake up the thread. fWait.notify(); } @@ -145,10 +144,78 @@ CollectionInspectionWorkerThread::doWork( void *data ) TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); TraceModule::get().incrementVariable( TraceVariable::CE_PROCESSED_SIGNALS ); readyToSleep = false; - consumer->fCollectionInspectionEngine.addNewSignal( - inputSignal.signalID, - consumer->calculateMonotonicTime( currentTime, inputSignal.receiveTime ), - inputSignal.value ); + auto signalValue = inputSignal.getValue(); + switch ( signalValue.getType() ) + { + case SignalType::UINT8: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.uint8Val ); + break; + case SignalType::INT8: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.int8Val ); + break; + case SignalType::UINT16: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.uint16Val ); + break; + case SignalType::INT16: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.int16Val ); + break; + case SignalType::UINT32: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.uint32Val ); + break; + case SignalType::INT32: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.int32Val ); + break; + case SignalType::UINT64: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.uint64Val ); + break; + case SignalType::INT64: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.int64Val ); + break; + case SignalType::FLOAT: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.floatVal ); + break; + case SignalType::DOUBLE: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.doubleVal ); + break; + case SignalType::BOOLEAN: + consumer->fCollectionInspectionEngine.addNewSignal( + inputSignal.signalID, + calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + signalValue.value.boolVal ); + break; + default: + break; + } latestSignalTime = std::max( latestSignalTime, inputSignal.receiveTime ); inputCounterSinceLastEvaluate++; statisticInputMessagesProcessed++; @@ -162,7 +229,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) consumer->fCollectionInspectionEngine.addNewRawCanFrame( inputCANFrame.frameID, inputCANFrame.channelId, - consumer->calculateMonotonicTime( currentTime, inputCANFrame.receiveTime ), + calculateMonotonicTime( currentTime, inputCANFrame.receiveTime ), inputCANFrame.data, inputCANFrame.size ); latestSignalTime = std::max( latestSignalTime, inputCANFrame.receiveTime ); @@ -211,8 +278,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) TraceModule::get().incrementVariable( TraceVariable::CE_TRIGGERS ); if ( !consumer->fOutputCollectedData->push( collectedData ) ) { - consumer->fLogger.warn( "CollectionInspectionWorkerThread::doWork", - "Collected data output buffer is full" ); + FWE_LOG_WARN( "Collected data output buffer is full" ); } else { @@ -231,14 +297,12 @@ CollectionInspectionWorkerThread::doWork( void *data ) if ( consumer->fClock->monotonicTimeSinceEpochMs() > ( lastTraceOutput + LoggingModule::LOG_AGGREGATION_TIME_MS ) ) { - consumer->fLogger.trace( - "CollectionInspectionWorkerThread::doWork", - "Activations: " + std::to_string( activations ) + - ". Waiting for some data to come. Idling for :" + std::to_string( timeToWait ) + - " ms or until notify. Since last idling processed " + - std::to_string( statisticInputMessagesProcessed ) + - " incoming data packages and sent out " + std::to_string( statisticDataSentOut ) + - " packages out" ); + FWE_LOG_TRACE( "Activations: " + std::to_string( activations ) + + ". Waiting for some data to come. Idling for :" + std::to_string( timeToWait ) + + " ms or until notify. Since last idling processed " + + std::to_string( statisticInputMessagesProcessed ) + + " incoming data packages and sent out " + std::to_string( statisticDataSentOut ) + + " packages out" ); activations = 0; statisticInputMessagesProcessed = 0; statisticDataSentOut = 0; @@ -261,11 +325,10 @@ CollectionInspectionWorkerThread::calculateMonotonicTime( const TimePoint &currT TimePoint convertedTime = timePointFromSystemTime( currTime, systemTimeMs ); if ( ( convertedTime.systemTimeMs == 0 ) && ( convertedTime.monotonicTimeMs == 0 ) ) { - fLogger.error( "CollectionInspectionWorkerThread::timePointFromSystemTime", - "The system time " + std::to_string( systemTimeMs ) + - " corresponds to a time in the past before the monotonic" + - " clock started ticking. Current system time: " + std::to_string( currTime.systemTimeMs ) + - ". Current monotonic time: " + std::to_string( currTime.monotonicTimeMs ) ); + FWE_LOG_ERROR( "The system time " + std::to_string( systemTimeMs ) + + " corresponds to a time in the past before the monotonic" + + " clock started ticking. Current system time: " + std::to_string( currTime.systemTimeMs ) + + ". Current monotonic time: " + std::to_string( currTime.monotonicTimeMs ) ); return TimePoint{ systemTimeMs, 0 }; } return convertedTime; diff --git a/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp b/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp index 06ddf29c..4cd131c7 100644 --- a/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp +++ b/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp @@ -3,6 +3,7 @@ // Includes #include "DataOverDDSModule.h" +#include "LoggingModule.h" #include "dds/CameraDataPublisher.h" #include "dds/CameraDataSubscriber.h" #include @@ -48,7 +49,7 @@ DataOverDDSModule::init( const DDSDataSourcesConfig &ddsDataSourcesConfig ) subscriber = std::make_unique(); if ( ( !publisher->init( config ) ) || ( !subscriber->init( config ) ) ) { - mLogger.error( "DataOverDDSModule::init", "Failed to init the Publisher/Subscriber" ); + FWE_LOG_ERROR( "Failed to init the Publisher/Subscriber" ); return false; } else @@ -60,12 +61,12 @@ DataOverDDSModule::init( const DDSDataSourcesConfig &ddsDataSourcesConfig ) mSubscribers.emplace_back( std::move( subscriber ) ); } - mLogger.info( "DataOverDDSModule::init", "Camera Publisher/Subscriber successfully initialised" ); + FWE_LOG_INFO( "Camera Publisher/Subscriber successfully initialised" ); } break; default: - mLogger.warn( "DataOverDDSModule::init", "Not supported SensorType" ); + FWE_LOG_WARN( "Not supported SensorType" ); break; } } @@ -82,11 +83,11 @@ DataOverDDSModule::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "DataOverDDSModule::start", "DataOverDDSModule Thread failed to start" ); + FWE_LOG_TRACE( "DataOverDDSModule Thread failed to start" ); } else { - mLogger.trace( "DataOverDDSModule::start", "DataOverDDSModule Thread started" ); + FWE_LOG_TRACE( "DataOverDDSModule Thread started" ); mThread.setThreadName( "fwDIDDSModule" ); } @@ -141,9 +142,8 @@ DataOverDDSModule::doWork( void *data ) { // Hmm, we have received a notification to request data from a source that's // not configured. We should log an error and skip the event. - DDSModule->mLogger.error( "DataOverDDSModule::doWork", - "Received an event for a Source that's not configured, Source ID: " + - std::to_string( eventItem.sourceID ) ); + FWE_LOG_ERROR( "Received an event for a Source that's not configured, Source ID: " + + std::to_string( eventItem.sourceID ) ); } else { @@ -155,10 +155,10 @@ DataOverDDSModule::doWork( void *data ) // Go ahead and request the data from the underlying source publishIterator->second->publishDataRequest( request ); - DDSModule->mLogger.trace( - "DataOverDDSModule::doWork", + FWE_LOG_TRACE( + "Send a request to the DDS Network upon eventID: " + std::to_string( eventItem.eventID ) + - " to DeviceID " + std::to_string( eventItem.sourceID ) ); + " to DeviceID " + std::to_string( eventItem.sourceID ) ); } } } @@ -180,12 +180,12 @@ DataOverDDSModule::connect() // Register the module as a listener of the Subscriber if ( ( !sub->subscribeListener( this ) ) || ( !sub->connect() ) ) { - mLogger.error( "DataOverDDSModule::connect", "Failed to connect Subscriber" ); + FWE_LOG_ERROR( "Failed to connect Subscriber" ); return false; } else { - mLogger.trace( "DataOverDDSModule::connect", "Subscriber connected" ); + FWE_LOG_TRACE( "Subscriber connected" ); } } @@ -193,12 +193,12 @@ DataOverDDSModule::connect() { if ( !pub.second->connect() ) { - mLogger.error( "DataOverDDSModule::connect", "Failed to connect Publisher" ); + FWE_LOG_ERROR( "Failed to connect Publisher" ); return false; } else { - mLogger.trace( "DataOverDDSModule::connect", "Publisher connected" ); + FWE_LOG_TRACE( "Publisher connected" ); } } } @@ -217,12 +217,12 @@ DataOverDDSModule::disconnect() { if ( ( !sub->unSubscribeListener( this ) ) || ( !sub->disconnect() ) ) { - mLogger.error( "DataOverDDSModule::disconnect", "Failed to disconnect Subscriber" ); + FWE_LOG_ERROR( "Failed to disconnect Subscriber" ); return false; } else { - mLogger.trace( "DataOverDDSModule::disconnect", "Subscriber disconnected" ); + FWE_LOG_TRACE( "Subscriber disconnected" ); } } @@ -230,12 +230,12 @@ DataOverDDSModule::disconnect() { if ( !pub.second->disconnect() ) { - mLogger.error( "DataOverDDSModule::disconnect", "Failed to disconnect Publisher" ); + FWE_LOG_ERROR( "Failed to disconnect Publisher" ); return false; } else { - mLogger.trace( "DataOverDDSModule::disconnect", "Publisher disconnected" ); + FWE_LOG_TRACE( "Publisher disconnected" ); } } } @@ -253,7 +253,7 @@ DataOverDDSModule::isAlive() { if ( !sub->isAlive() ) { - mLogger.error( "DataOverDDSModule::isAlive", "Subscriber not alive" ); + FWE_LOG_ERROR( "Subscriber not alive" ); return false; } } @@ -262,7 +262,7 @@ DataOverDDSModule::isAlive() { if ( !pub.second->isAlive() ) { - mLogger.error( "DataOverDDSModule::isAlive", " Publisher not alive" ); + FWE_LOG_ERROR( "Publisher not alive" ); return false; } } @@ -280,7 +280,7 @@ DataOverDDSModule::onEventOfInterestDetected( const std::vector & // We don't need to guard for thread safety as this notification comes // from the Inspection thread only, but we still guard as the main loop // might be running an ongoing request. - mLogger.trace( "DataOverDDSModule::onEventOfInterestDetected", "Received a new event " ); + FWE_LOG_TRACE( "Received a new event" ); std::lock_guard lock( mEventMetaMutex ); { mEventMetatdata = eventMetadata; diff --git a/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp b/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp index 868b15d1..df183137 100644 --- a/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp +++ b/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp @@ -3,6 +3,7 @@ // Includes #include "OBDOverCANECU.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -14,7 +15,8 @@ namespace IoTFleetWise namespace DataInspection { -constexpr size_t OBDOverCANECU::MAX_PID_RANGE; +// NOLINT below due to C++17 warning of redundant declarations that are required to maintain C++14 compatibility +constexpr size_t OBDOverCANECU::MAX_PID_RANGE; // NOLINT bool OBDOverCANECU::init( const std::string &gatewayCanInterfaceName, @@ -40,11 +42,11 @@ OBDOverCANECU::init( const std::string &gatewayCanInterfaceName, if ( mISOTPSenderReceiver.init( optionsECU ) && mISOTPSenderReceiver.connect() ) { - mLogger.trace( "OBDOverCANECU::init", "Successfully initialized ECU with ecu id: " + mStreamRxID ); + FWE_LOG_TRACE( "Successfully initialized ECU with ecu id: " + mStreamRxID ); } else { - mLogger.error( "OBDOverCANECU::init", "Failed to initialize the ECU with ecu id: " + mStreamRxID ); + FWE_LOG_ERROR( "Failed to initialize the ECU with ecu id: " + mStreamRxID ); return false; } return true; @@ -53,7 +55,7 @@ OBDOverCANECU::init( const std::string &gatewayCanInterfaceName, uint32_t OBDOverCANECU::flush( uint32_t timeout ) { - mLogger.trace( "OBDOverCANECU::flushSocket", "Flushed socket for ECU with ecu id: " + mStreamRxID ); + FWE_LOG_TRACE( "Flushed socket for ECU with ecu id: " + mStreamRxID ); return mISOTPSenderReceiver.flush( timeout ); } @@ -68,9 +70,8 @@ OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) if ( mSupportedPIDs.find( sid ) == mSupportedPIDs.end() ) { SupportedPIDs allSupportedPIDs; - mLogger.trace( "OBDOverCANECU::requestReceiveSupportedPIDs", - "Requesting Supported PIDs from the ECU " + mStreamRxID + " for SID " + - std::to_string( toUType( sid ) ) ); + FWE_LOG_TRACE( "Requesting Supported PIDs from the ECU " + mStreamRxID + " for SID " + + std::to_string( toUType( sid ) ) ); // Request supported PID range. Per ISO 15765, we can only send six PID at one time auto pidList = @@ -85,8 +86,7 @@ OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) TraceModule::get().incrementVariable( TraceVariable::OBD_ENG_PID_REQ_ERROR ); // log warning as all emissions-related OBD ECUs which support at least one of the // services defined in J1979 shall support Service $01 and PID $00 - mLogger.warn( "OBDOverCANECU::requestReceiveSupportedPIDs", - "Failed to receive supported PID range from the ECU " + mStreamRxID ); + FWE_LOG_WARN( "Failed to receive supported PID range from the ECU " + mStreamRxID ); } } // check if we need to send out more PID range request @@ -101,10 +101,8 @@ OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) } } mSupportedPIDs.emplace( sid, allSupportedPIDs ); - mLogger.traceBytesInVector( "OBDOverCANECU::requestReceiveSupportedPIDs", - "ECU " + mStreamRxID + " supports PIDs for SID " + - std::to_string( toUType( sid ) ), - allSupportedPIDs ); + FWE_LOG_TRACE( "ECU " + mStreamRxID + " supports PIDs for SID " + std::to_string( toUType( sid ) ) + ": " + + getStringFromBytes( allSupportedPIDs ) ); } } return numRequests; @@ -135,16 +133,38 @@ OBDOverCANECU::requestReceiveEmissionPIDs( const SID sid ) // Note Signal buffer is a multi producer single consumer queue. Besides current thread, // Vehicle Data Consumer will also push signals onto this buffer TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); - if ( !mSignalBufferPtr->push( CollectedSignal( signals.first, receptionTime, signals.second ) ) ) + struct CollectedSignal collectedSignal; + const auto signalType = signals.second.signalType; + switch ( signalType ) + { + case SignalType::UINT64: + collectedSignal = CollectedSignal{ + signals.first, receptionTime, signals.second.signalValue.uint64Val, signalType }; + FWE_LOG_TRACE( "Received Signal " + std::to_string( signals.first ) + " : " + + std::to_string( signals.second.signalValue.uint64Val ) + + " for ECU: " + mStreamRxID ); + break; + case SignalType::INT64: + collectedSignal = CollectedSignal{ + signals.first, receptionTime, signals.second.signalValue.int64Val, signalType }; + FWE_LOG_TRACE( "Received Signal " + std::to_string( signals.first ) + " : " + + std::to_string( signals.second.signalValue.int64Val ) + " for ECU: " + mStreamRxID ); + break; + default: + collectedSignal = CollectedSignal{ + signals.first, receptionTime, signals.second.signalValue.doubleVal, signalType }; + FWE_LOG_TRACE( "Received Signal " + std::to_string( signals.first ) + " : " + + std::to_string( signals.second.signalValue.doubleVal ) + + " for ECU: " + mStreamRxID ); + break; + } + + if ( !mSignalBufferPtr->push( collectedSignal ) ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); - mLogger.warn( "OBDOverCANECU::requestReceiveEmissionPIDs", - "Signal Buffer full with ECU " + mStreamRxID ); + FWE_LOG_WARN( "Signal Buffer full with ECU " + mStreamRxID ); } - mLogger.trace( "OBDOverCANECU::requestReceiveEmissionPIDs", - "Received Signal " + std::to_string( signals.first ) + ": " + - std::to_string( signals.second ) + " for ECU: " + mStreamRxID ); } } } @@ -159,12 +179,11 @@ OBDOverCANECU::getDTCData( DTCInfo &dtcInfo, size_t &numRequests ) if ( requestReceiveDTCs( SID::STORED_DTC, dtcInfo ) ) { successfulDTCRequest = true; - mLogger.trace( "OBDOverCANECU::getDTCData", - "Total number of DTCs: " + std::to_string( dtcInfo.mDTCCodes.size() ) ); + FWE_LOG_TRACE( "Total number of DTCs: " + std::to_string( dtcInfo.mDTCCodes.size() ) ); } else { - mLogger.warn( "OBDOverCANECU::getDTCData", "Failed to receive DTCs for ECU: " + mStreamRxID ); + FWE_LOG_WARN( "Failed to receive DTCs for ECU: " + mStreamRxID ); } return successfulDTCRequest; } @@ -178,23 +197,22 @@ OBDOverCANECU::requestReceivePIDs( SupportedPIDs::iterator &pidItr, std::vector currPIDs; while ( ( currPIDs.size() < MAX_PID_RANGE ) && ( pidItr != pids.end() ) ) { - currPIDs.push_back( *pidItr++ ); + currPIDs.push_back( *pidItr ); + pidItr++; } if ( requestPIDs( sid, currPIDs ) ) { if ( receivePIDs( sid, currPIDs, info ) ) { - mLogger.trace( "OBDOverCANECU::requestReceivePIDs", - "Received Emission PID data for SID: " + std::to_string( toUType( sid ) ) + - " with ECU: " + mStreamRxID ); + FWE_LOG_TRACE( "Received Emission PID data for SID: " + std::to_string( toUType( sid ) ) + + " with ECU: " + mStreamRxID ); } else { TraceModule::get().incrementVariable( TraceVariable::OBD_ENG_PID_REQ_ERROR ); - mLogger.warn( "OBDOverCANECU::requestReceivePIDs", - "Failed to receive emission PID data for SID: " + std::to_string( toUType( sid ) ) + - " with ECU: " + mStreamRxID ); + FWE_LOG_WARN( "Failed to receive emission PID data for SID: " + std::to_string( toUType( sid ) ) + + " with ECU: " + mStreamRxID ); } } } @@ -213,7 +231,7 @@ OBDOverCANECU::receiveSupportedPIDs( const SID sid, SupportedPIDs &supportedPIDs { return true; } - mLogger.warn( "OBDOverCANECU::receiveSupportedPIDs", "Failed to decode PDU for ECU " + mStreamRxID ); + FWE_LOG_WARN( "Failed to decode PDU for ECU " + mStreamRxID ); return false; } @@ -230,12 +248,14 @@ OBDOverCANECU::requestPIDs( const SID sid, const std::vector &pids ) } // First insert the SID - mTxPDU.emplace_back( static_cast( sid ) ); + mTxPDU.push_back( static_cast( sid ) ); // Then insert the items of the PIDs - mTxPDU.insert( std::end( mTxPDU ), std::begin( pids ), std::end( pids ) ); - mLogger.trace( "OBDOverCANECU::requestPIDs", - "Start to request emission PID data for SID: " + std::to_string( toUType( sid ) ) + - " with ECU: " + mStreamRxID ); + for ( auto pid : pids ) + { + mTxPDU.push_back( pid ); + } + FWE_LOG_TRACE( "Start to request emission PID data for SID: " + std::to_string( toUType( sid ) ) + + " with ECU: " + mStreamRxID ); return mISOTPSenderReceiver.sendPDU( mTxPDU ); } @@ -248,7 +268,7 @@ OBDOverCANECU::receivePIDs( const SID sid, const std::vector &pids, Emissio // decoded according to J1979 8.1.2.2 if ( !mISOTPSenderReceiver.receivePDU( ecuResponse ) ) { - mLogger.warn( "OBDOverCANECU::receivePIDs", "Failed to receive PDU for ECU " + mStreamRxID ); + FWE_LOG_WARN( "Failed to receive PDU for ECU " + mStreamRxID ); return false; } // The info structure will be appended with the new decoded PIDs @@ -258,8 +278,7 @@ OBDOverCANECU::receivePIDs( const SID sid, const std::vector &pids, Emissio } else { - mLogger.warn( "OBDOverCANECU::receivePIDs", - "Failed to receive PID: ECU response is empty for ECU " + mStreamRxID ); + FWE_LOG_WARN( "Failed to receive PID: ECU response is empty for ECU " + mStreamRxID ); return false; } return true; @@ -306,9 +325,8 @@ OBDOverCANECU::requestReceiveDTCs( const SID sid, DTCInfo &info ) } else { - mLogger.warn( "OBDOverCANECU::requestReceiveDTCs", - "Can't request/receive ECU PIDs, with ECU: " + mStreamRxID + - " for SID: " + std::to_string( toUType( sid ) ) ); + FWE_LOG_WARN( "Can't request/receive ECU PIDs, with ECU: " + mStreamRxID + + " for SID: " + std::to_string( toUType( sid ) ) ); } return false; } @@ -352,7 +370,7 @@ OBDOverCANECU::updatePIDRequestList( const SID sid, std::copy_if( pidIntersectionList.begin(), pidIntersectionList.end(), std::back_inserter( pidsToRequest ), - [&]( PID pid ) { + [&]( PID pid ) -> bool { if ( pidAssigned.count( pid ) == 0 ) { pidAssigned.insert( pid ); @@ -363,8 +381,7 @@ OBDOverCANECU::updatePIDRequestList( const SID sid, return false; } } ); - mLogger.traceBytesInVector( - "OBDOverCANECU::updatePIDRequestList", "The PIDs to request from " + mStreamRxID + " are", pidsToRequest ); + FWE_LOG_TRACE( "The PIDs to request from " + mStreamRxID + " are: " + getStringFromBytes( pidsToRequest ) ); mPIDsToRequest[sid] = pidsToRequest; } } diff --git a/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp b/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp index 22e68113..6daf6047 100644 --- a/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp +++ b/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp @@ -4,6 +4,7 @@ // Includes #include "OBDOverCANModule.h" #include "EnumUtility.h" +#include "LoggingModule.h" #include "TraceModule.h" #include "datatypes/ISOTPOverCANOptions.h" #include @@ -25,11 +26,12 @@ namespace DataInspection { using namespace Aws::IoTFleetWise::VehicleNetwork; -constexpr int OBDOverCANModule::SLEEP_TIME_SECS; -constexpr uint32_t OBDOverCANModule::MASKING_GET_BYTE; // Get last byte -constexpr uint32_t OBDOverCANModule::MASKING_SHIFT_BITS; // Shift 8 bits -constexpr uint32_t OBDOverCANModule::MASKING_TEMPLATE_TX_ID; // All 29-bit tx id has the same bytes -constexpr uint32_t OBDOverCANModule::MASKING_REMOVE_BYTE; +// NOLINT below due to C++17 warning of redundant declarations that are required to maintain C++14 compatibility +constexpr int OBDOverCANModule::SLEEP_TIME_SECS; // NOLINT +constexpr uint32_t OBDOverCANModule::MASKING_GET_BYTE; // NOLINT Get last byte +constexpr uint32_t OBDOverCANModule::MASKING_SHIFT_BITS; // NOLINT Shift 8 bits +constexpr uint32_t OBDOverCANModule::MASKING_TEMPLATE_TX_ID; // NOLINT All 29-bit tx id has the same bytes +constexpr uint32_t OBDOverCANModule::MASKING_REMOVE_BYTE; // NOLINT OBDOverCANModule::~OBDOverCANModule() { @@ -51,15 +53,14 @@ OBDOverCANModule::init( SignalBufferPtr signalBufferPtr, // Sanity check if ( ( pidRequestIntervalSeconds == 0 ) && ( dtcRequestIntervalSeconds == 0 ) ) { - mLogger.trace( "OBDOverCANModule::init", - "Both PID and DTC interval seconds are set to 0. OBD module will not be initialized" ); + FWE_LOG_TRACE( "Both PID and DTC interval seconds are set to 0. OBD module will not be initialized" ); // We should not start the module if both intervals are zero return false; } if ( ( signalBufferPtr.get() == nullptr ) || ( activeDTCBufferPtr.get() == nullptr ) ) { - mLogger.error( "OBDOverCANModule::init", "Received Buffer nullptr" ); + FWE_LOG_ERROR( "Received Buffer nullptr" ); return false; } else @@ -92,11 +93,11 @@ OBDOverCANModule::start() mShouldRequestDTCs.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "OBDOverCANModule::start", "Thread failed to start" ); + FWE_LOG_TRACE( "OBD Module Thread failed to start" ); } else { - mLogger.trace( "OBDOverCANModule::start", "Thread started" ); + FWE_LOG_TRACE( "OBD Module Thread started" ); mThread.setThreadName( "fwDIOBDModule" ); } @@ -113,15 +114,15 @@ OBDOverCANModule::stop() std::lock_guard lock( mThreadMutex ); mShouldStop.store( true, std::memory_order_relaxed ); - mLogger.trace( "OBDOverCANModule::stop", "Thread requested to stop" ); + FWE_LOG_TRACE( "OBD Module Thread requested to stop" ); mWait.notify(); mDataAvailableWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "OBDOverCANModule::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); if ( ( mBroadcastSocket >= 0 ) && ( close( mBroadcastSocket ) < 0 ) ) { - mLogger.error( "OBDOverCANModule::stop", "Failed to close broadcastSocket." ); + FWE_LOG_ERROR( "Failed to close broadcastSocket" ); } return !mThread.isActive(); } @@ -146,8 +147,7 @@ OBDOverCANModule::doWork( void *data ) if ( ( !obdModule->mShouldRequestDTCs.load( std::memory_order_relaxed ) ) && ( ( !obdModule->mDecoderDictionaryPtr ) || obdModule->mDecoderDictionaryPtr->empty() ) ) { - obdModule->mLogger.trace( - "OBDOverCANModule::doWork", + FWE_LOG_TRACE( "No valid decoding dictionary available and DTC requests disabled, Module Thread going to sleep " ); obdModule->mDataAvailableWait.wait( Platform::Linux::Signal::WaitWithPredicate ); } @@ -159,8 +159,7 @@ OBDOverCANModule::doWork( void *data ) isExtendedID = true; obdModule->autoDetectECUs( isExtendedID, canIDResponses ); } - obdModule->mLogger.trace( "OBDOverCANModule::doWork", - "Detect size of ECUs:" + std::to_string( canIDResponses.size() ) ); + FWE_LOG_TRACE( "Detect size of ECUs:" + std::to_string( canIDResponses.size() ) ); if ( !canIDResponses.empty() ) { // If broadcast mode is enabled, open the broadcast socket: @@ -178,8 +177,7 @@ OBDOverCANModule::doWork( void *data ) if ( !obdModule->initECUs( isExtendedID, canIDResponses, obdModule->mBroadcastSocket ) ) { // Failure from initECUs is non recoverable, hence we will send signal out to terminate program - obdModule->mLogger.error( "OBDOverCANModule::doWork", - "Fatal Error. OBDOverCANECU failed to init. Check CAN ISO-TP module" ); + FWE_LOG_ERROR( "Fatal Error. OBDOverCANECU failed to init. Check CAN ISO-TP module" ); std::raise( SIGUSR1 ); return; } @@ -188,8 +186,7 @@ OBDOverCANModule::doWork( void *data ) // As we haven't detected ECUs, wait for 1 second and try again else { - obdModule->mLogger.trace( "OBDOverCANModule::doWork", - "Waiting for: " + std::to_string( SLEEP_TIME_SECS ) + " seconds" ); + FWE_LOG_TRACE( "Waiting for :" + std::to_string( SLEEP_TIME_SECS ) + " seconds" ); obdModule->mWait.wait( static_cast( SLEEP_TIME_SECS * 1000 ) ); } } @@ -206,7 +203,7 @@ OBDOverCANModule::doWork( void *data ) // A new decoder manifest arrived. Pass it over to the OBD decoder. std::lock_guard lock( obdModule->mDecoderDictMutex ); obdModule->mOBDDataDecoder->setDecoderDictionary( obdModule->mDecoderDictionaryPtr ); - obdModule->mLogger.trace( "OBDOverCANModule::doWork", "Decoder Manifest set on the OBD Decoder " ); + FWE_LOG_TRACE( "Decoder Manifest set on the OBD Decoder " ); // Reset the atomic state obdModule->mDecoderManifestAvailable.store( false, std::memory_order_relaxed ); } @@ -265,7 +262,7 @@ OBDOverCANModule::doWork( void *data ) // thread to push DTC Info to the queue if ( !obdModule->mActiveDTCBufferPtr->push( dtcInfo ) ) { - obdModule->mLogger.warn( "OBDOverCANModule::doWork", "DTC Buffer full" ); + FWE_LOG_WARN( "DTC Buffer full" ); } } } @@ -277,13 +274,11 @@ OBDOverCANModule::doWork( void *data ) calcSleepTime( obdModule->mDTCRequestIntervalSeconds, obdModule->mDTCTimer, sleepTime ); if ( sleepTime < 0 ) { - obdModule->mLogger.warn( "OBDOverCANModule::doWork", - "Request time overdue by " + std::to_string( -sleepTime ) + " ms" ); + FWE_LOG_WARN( "Request time overdue by " + std::to_string( -sleepTime ) + " ms" ); } else { - obdModule->mLogger.trace( "OBDOverCANModule::doWork", - "Waiting for: " + std::to_string( sleepTime ) + " ms" ); + FWE_LOG_TRACE( "Waiting for: " + std::to_string( sleepTime ) + " ms" ); obdModule->mWait.wait( static_cast( sleepTime ) ); } } @@ -343,7 +338,7 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI int rawSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); if ( rawSocket < 0 ) { - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to create socket" ); + FWE_LOG_ERROR( "Failed to create socket" ); return false; } // Set the IF name @@ -351,7 +346,7 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI if ( ioctl( rawSocket, SIOCGIFINDEX, &interfaceRequest ) != 0 ) { close( rawSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "CAN interface is not accessible" ); + FWE_LOG_ERROR( "CAN interface is not accessible" ); return false; } @@ -362,7 +357,7 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI if ( bind( rawSocket, reinterpret_cast( &interfaceAddress ), sizeof( interfaceAddress ) ) < 0 ) { close( rawSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to bind" ); + FWE_LOG_ERROR( "Failed to bind" ); return false; } // Set frame can_id and flags @@ -377,10 +372,10 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI if ( write( rawSocket, &frame, sizeof( struct can_frame ) ) != sizeof( struct can_frame ) ) { close( rawSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to write" ); + FWE_LOG_ERROR( "Failed to write" ); return false; } - mLogger.trace( "OBDOverCANModule::autoDetectECUs", "Sent broadcast request" ); + FWE_LOG_TRACE( "Sent broadcast request" ); Timer broadcastTimer; broadcastTimer.reset(); @@ -389,9 +384,8 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI { if ( broadcastTimer.getElapsedMs().count() > MAX_WAITING_MS ) { - mLogger.trace( "OBDOverCANModule::autoDetectECUs", - "Time elapsed:" + std::to_string( broadcastTimer.getElapsedMs().count() ) + - ", time to stop ECUs' detection" ); + FWE_LOG_TRACE( "Time elapsed:" + std::to_string( broadcastTimer.getElapsedMs().count() ) + + ", time to stop ECUs' detection" ); break; } struct pollfd pfd = { rawSocket, POLLIN, 0 }; @@ -399,7 +393,7 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI if ( res < 0 ) { close( rawSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Poll error" ); + FWE_LOG_ERROR( "Poll error" ); return false; } if ( res == 0 ) // Time out @@ -410,7 +404,7 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI if ( recv( rawSocket, &frame, sizeof( struct can_frame ), 0 ) < 0 ) { close( rawSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to read response" ); + FWE_LOG_ERROR( "Failed to read response" ); return false; } @@ -427,18 +421,17 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI canIDResponses.push_back( frameCANId ); } } - mLogger.trace( "OBDOverCANModule::autoDetectECUs", - "Detected number of ECUs:" + std::to_string( canIDResponses.size() ) ); + FWE_LOG_TRACE( "Detected number of ECUs:" + std::to_string( canIDResponses.size() ) ); for ( std::size_t i = 0; i < canIDResponses.size(); ++i ) { std::stringstream stream_rx; stream_rx << std::hex << canIDResponses[i]; - mLogger.trace( "OBDOverCANModule::autoDetectECUs", "ECU with rx_id: " + stream_rx.str() ); + FWE_LOG_TRACE( "ECU with rx_id: " + stream_rx.str() ); } // Close the socket if ( close( rawSocket ) < 0 ) { - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to close socket" ); + FWE_LOG_ERROR( "Failed to close socket" ); return false; } return true; @@ -461,16 +454,14 @@ OBDOverCANModule::openISOTPBroadcastSocket( bool isExtendedID ) int broadcastSocket = socket( PF_CAN, SOCK_DGRAM, CAN_ISOTP ); if ( broadcastSocket < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::openISOTPBroadcastSocket", - "Failed to create the ISOTP broadcast socket to IF: " + mGatewayCanInterfaceName ); + FWE_LOG_ERROR( "Failed to create the ISOTP broadcast socket to IF: " + mGatewayCanInterfaceName ); return -1; } // Set the optional Flags if ( setsockopt( broadcastSocket, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &optionalFlags, sizeof( optionalFlags ) ) < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::openISOTPBroadcastSocket", - "Failed to set ISO-TP socket option flags" ); + FWE_LOG_ERROR( "Failed to set ISO-TP socket option flags" ); close( broadcastSocket ); return -1; } @@ -482,13 +473,11 @@ OBDOverCANModule::openISOTPBroadcastSocket( bool isExtendedID ) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) if ( bind( broadcastSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::openISOTPBroadcastSocket", - "Failed to bind the ISOTP Socket to IF: " + mGatewayCanInterfaceName ); + FWE_LOG_ERROR( "Failed to bind the ISOTP Socket to IF: " + mGatewayCanInterfaceName ); close( broadcastSocket ); return -1; } - mLogger.trace( "ISOTPOverCANSenderReceiver::openISOTPBroadcastSocket", - "ISOTP Socket connected to IF: " + mGatewayCanInterfaceName ); + FWE_LOG_TRACE( "ISOTP Socket connected to IF: " + mGatewayCanInterfaceName ); return broadcastSocket; } @@ -526,7 +515,7 @@ OBDOverCANModule::initECUs( bool isExtendedID, std::vector &canIDRespo } mECUs.push_back( ecu ); } - mLogger.trace( "OBDOverCANModule::initialECUs", "Initialize ECUs in size of: " + std::to_string( mECUs.size() ) ); + FWE_LOG_TRACE( "Initialize ECUs in size of: " + std::to_string( mECUs.size() ) ); return true; } @@ -587,7 +576,7 @@ OBDOverCANModule::onChangeInspectionMatrix( const std::shared_ptrmGeohashInfo.mGeohashString.length() >= precision ) && ( currentGeohashString.length() >= precision ) ) @@ -40,9 +41,8 @@ GeohashFunctionNode::evaluateGeohash( double latitude, if ( currentGeohashString.substr( 0, precision ) != this->mGeohashInfo.mGeohashString.substr( 0, precision ) ) { - mLogger.trace( "GeohashFunctionNode::evaluateGeohash", - "Geohash has changed from " + this->mGeohashInfo.mGeohashString + " to " + - currentGeohashString + " at given precision " + std::to_string( precision ) ); + FWE_LOG_TRACE( "Geohash has changed from " + this->mGeohashInfo.mGeohashString + " to " + + currentGeohashString + " at given precision " + std::to_string( precision ) ); this->mIsGeohashNew = true; } } @@ -50,22 +50,20 @@ GeohashFunctionNode::evaluateGeohash( double latitude, { // There's no existing Geohash, set the flag to true. One use case is first time Geohash evaluation. this->mIsGeohashNew = true; - mLogger.trace( "GeohashFunctionNode::evaluateGeohash", "Geohash start at: " + currentGeohashString ); + FWE_LOG_TRACE( "Geohash start at: " + currentGeohashString ); } else { TraceModule::get().incrementVariable( TraceVariable::GE_COMPARE_PRECISION_ERROR ); - mLogger.error( "GeohashFunctionNode::evaluateGeohash", - "Cannot compare two Geohashes as they have less precision than required" ); + FWE_LOG_ERROR( "Cannot compare two Geohashes as they have less precision than required" ); } this->mGeohashInfo.mGeohashString = currentGeohashString; } else { TraceModule::get().incrementVariable( TraceVariable::GE_EVALUATE_ERROR_LAT_LON ); - mLogger.error( "GeohashFunctionNode::evaluateGeohash", - "Unable to calculate Geohash with lat/lon: " + std::to_string( latitude ) + ", " + - std::to_string( longitude ) ); + FWE_LOG_ERROR( "Unable to calculate Geohash with lat/lon: " + std::to_string( latitude ) + ", " + + std::to_string( longitude ) ); } return this->mIsGeohashNew; } @@ -77,8 +75,7 @@ GeohashFunctionNode::consumeGeohash( GeohashInfo &geohashInfo ) this->mIsGeohashNew = false; geohashInfo = this->mGeohashInfo; this->mGeohashInfo.mPrevReportedGeohashString = this->mGeohashInfo.mGeohashString; - mLogger.trace( "GeohashFunctionNode::consumeGeohash ", - "Previous Geohash is updated to " + this->mGeohashInfo.mPrevReportedGeohashString ); + FWE_LOG_TRACE( "Previous Geohash is updated to " + this->mGeohashInfo.mPrevReportedGeohashString ); } bool diff --git a/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp b/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp index c97b4b9a..4ae1d1e6 100644 --- a/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp +++ b/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp @@ -3,6 +3,7 @@ // Includes #include "CANDataConsumer.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -31,13 +32,12 @@ CANDataConsumer::init( VehicleDataSourceID canChannelID, SignalBufferPtr signalB mCANDecoder = std::make_unique(); if ( signalBufferPtr.get() == nullptr ) { - mLogger.trace( "CANDataConsumer::init", "Init Failed due to bufferPtr as nullptr" ); + FWE_LOG_TRACE( "Init Failed due to bufferPtr as nullptr" ); return false; } else { - mLogger.trace( "CANDataConsumer::init", - "Init Network channel consumer with id: " + std::to_string( canChannelID ) ); + FWE_LOG_TRACE( "Init Network channel consumer with id: " + std::to_string( canChannelID ) ); mDataSourceID = canChannelID; mSignalBufferPtr = signalBufferPtr; } @@ -52,8 +52,7 @@ void CANDataConsumer::suspendDataConsumption() { // Go back to sleep - mLogger.trace( "CANDataConsumer::suspendDataConsumption", - "Going to sleep until a the resume signal. Consumer: " + std::to_string( mDataSourceID ) ); + FWE_LOG_TRACE( "Going to sleep until a the resume signal. Consumer : " + std::to_string( mDataSourceID ) ); mShouldSleep.store( true, std::memory_order_relaxed ); } @@ -89,9 +88,8 @@ CANDataConsumer::resumeDataConsumption( ConstDecoderDictionaryConstPtr &dictiona canIds += std::to_string( decode.first ) + ", "; } } - mLogger.trace( "CANDataConsumer::resumeDataConsumption", - "Changing Decoder Dictionary on Consumer: " + std::to_string( mID ) + - " with decoding rules for CAN-IDs: " + canIds ); + FWE_LOG_TRACE( "Changing Decoder Dictionary on Consumer :" + std::to_string( mID ) + + " with decoding rules for CAN-IDs: " + canIds ); // Make sure the thread does not sleep anymore mShouldSleep.store( false ); // Wake up the worker thread. @@ -99,8 +97,7 @@ CANDataConsumer::resumeDataConsumption( ConstDecoderDictionaryConstPtr &dictiona } else { - mLogger.error( "CANDataConsumer::resumeDataConsumption", - "Received invalid decoder dictionary: " + std::to_string( mID ) ); + FWE_LOG_ERROR( "Received invalid decoder dictionary :" + std::to_string( mID ) ); } } } @@ -118,11 +115,11 @@ CANDataConsumer::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CANDataConsumer::start", "Thread failed to start" ); + FWE_LOG_TRACE( "Thread failed to start" ); } else { - mLogger.trace( "CANDataConsumer::start", "Thread started" ); + FWE_LOG_TRACE( "Thread started" ); mThread.setThreadName( "fwDIConsumer" + std::to_string( mID ) ); } @@ -137,7 +134,7 @@ CANDataConsumer::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CANDataConsumer::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); return !mThread.isActive(); } @@ -197,10 +194,10 @@ CANDataConsumer::doWork( void *data ) uint32_t processedFramesCounter = 0; TraceSection traceSection = - ( ( consumer->mDataSourceID + toUType( TraceSection::CAN_DECODER_CYCLE_0 ) < - toUType( TraceSection::CAN_DECODER_CYCLE_MAX ) ) + ( ( consumer->mDataSourceID < static_cast( toUType( TraceSection::CAN_DECODER_CYCLE_19 ) - + toUType( TraceSection::CAN_DECODER_CYCLE_0 ) ) ) ? static_cast( consumer->mDataSourceID + toUType( TraceSection::CAN_DECODER_CYCLE_0 ) ) - : TraceSection::CAN_DECODER_CYCLE_MAX ); + : TraceSection::CAN_DECODER_CYCLE_19 ); do { activations++; @@ -208,8 +205,7 @@ CANDataConsumer::doWork( void *data ) { // We either just started or there was a decoder manifest update that we can't use. // We should sleep - consumer->mLogger.trace( "CANDataConsumer::doWork", - "No valid decoding dictionary available, consumer going to sleep" ); + FWE_LOG_TRACE( "No valid decoding dictionary available, Consumer going to sleep" ); // Wait here for the decoder Manifest to come. consumer->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); // At this point, we should be able to see events coming as the channel is also @@ -231,9 +227,9 @@ CANDataConsumer::doWork( void *data ) { TraceVariable traceQueue = static_cast( consumer->mDataSourceID + toUType( TraceVariable::QUEUE_SOCKET_TO_CONSUMER_0 ) ); - TraceModule::get().setVariable( ( traceQueue < TraceVariable::QUEUE_SOCKET_TO_CONSUMER_MAX ) + TraceModule::get().setVariable( ( traceQueue < TraceVariable::QUEUE_SOCKET_TO_CONSUMER_19 ) ? traceQueue - : TraceVariable::QUEUE_SOCKET_TO_CONSUMER_MAX, + : TraceVariable::QUEUE_SOCKET_TO_CONSUMER_19, consumer->mInputBufferPtr->read_available() + 1 ); CANDecodedMessage decodedMessage; decodedMessage.mChannelProtocol = consumer->mDataSourceProtocol; @@ -323,15 +319,14 @@ CANDataConsumer::doWork( void *data ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_CAN ); - consumer->mLogger.warn( "CANDataConsumer::doWork", "RAW CAN Frame Buffer Full" ); + FWE_LOG_WARN( "RAW CAN Frame Buffer Full" ); } else { // Enable below logging for debugging - // consumer->mLogger.trace( "CANDataConsumer::doWork", - // "Collect RAW CAN Frame ID: " + - // std::to_string( static_cast( - // messageId ) ) ); + // FWE_LOG_TRACE( "CANDataConsumer::doWork", + // "Collect RAW CAN Frame ID: " + + // std::to_string( static_cast( messageId ) ) ); } } // check if we want to decode can frame into signals and collect signals @@ -350,8 +345,30 @@ CANDataConsumer::doWork( void *data ) for ( auto const &signal : decodedMessage.mFrameInfo.mSignals ) { // Create Collected Signal Object - struct CollectedSignal collectedSignal( - signal.mSignalID, decodedMessage.mReceptionTime, signal.mPhysicalValue ); + struct CollectedSignal collectedSignal; + const auto signalType = signal.mSignalType; + switch ( signalType ) + { + case SignalType::UINT64: + collectedSignal = CollectedSignal{ signal.mSignalID, + decodedMessage.mReceptionTime, + signal.mPhysicalValue.signalValue.uint64Val, + signal.mSignalType }; + break; + case SignalType::INT64: + collectedSignal = CollectedSignal{ signal.mSignalID, + decodedMessage.mReceptionTime, + signal.mPhysicalValue.signalValue.int64Val, + signal.mSignalType }; + break; + default: + collectedSignal = CollectedSignal{ signal.mSignalID, + decodedMessage.mReceptionTime, + signal.mPhysicalValue.signalValue.doubleVal, + signal.mSignalType }; + break; + } + // Push collected signal to the Signal Buffer TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); @@ -359,33 +376,30 @@ CANDataConsumer::doWork( void *data ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); - consumer->mLogger.warn( "CANDataConsumer::doWork", "Signal Buffer Full" ); + FWE_LOG_WARN( "Signal Buffer Full" ); } else { // Enable below logging for debugging - // consumer->mLogger.trace( "CANDataConsumer::doWork", - // "Acquire Signal ID: " + - // std::to_string( signal.mSignalID ) - // ); + // FWE_LOG_TRACE( "CANDataConsumer::doWork", + // "Acquire Signal ID: " + std::to_string( signal.mSignalID ) ); } } } else { // The decoding was not fully successful - consumer->mLogger.warn( "CANDataConsumer::doWork", - "CAN Frame " + std::to_string( messageId ) + " decoding failed" ); + FWE_LOG_WARN( "CAN Frame " + std::to_string( messageId ) + " decoding failed" ); } } else { // The CAN Message format is not valid, report as warning - consumer->mLogger.warn( - "CANDataConsumer::doWork", + FWE_LOG_WARN( + "CANMessageFormat Invalid for format message id: " + std::to_string( format.mMessageID ) + - " can message id: " + std::to_string( messageId ) + - " on CAN Channel Id: " + std::to_string( consumer->mDataSourceID ) ); + " can message id: " + std::to_string( messageId ) + + " on CAN Channel Id: " + std::to_string( consumer->mDataSourceID ) ); } } } @@ -406,7 +420,7 @@ CANDataConsumer::doWork( void *data ) } logMessage << ". Waiting for some data to come. Idling for :" + std::to_string( consumer->mIdleTime ) + " ms"; - consumer->mLogger.trace( "CANDataConsumer::doWork", logMessage.str() ); + FWE_LOG_TRACE( logMessage.str() ); activations = 0; logTimer.reset(); } diff --git a/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp b/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp index 44028e85..880338df 100644 --- a/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp +++ b/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp @@ -3,6 +3,7 @@ // Includes #include "VehicleDataSourceBinder.h" +#include "LoggingModule.h" namespace Aws { @@ -29,7 +30,7 @@ VehicleDataSourceBinder::addVehicleDataSource( VehicleDataSourcePtr source ) // Check if the data source is valid if ( ( source.get() == nullptr ) || ( source->getVehicleDataSourceID() == INVALID_DATA_SOURCE_ID ) ) { - mLogger.error( "VehicleDataSourceBinder::attachVehicleDataSource", "Invalid vehicle data source" ); + FWE_LOG_ERROR( "Invalid vehicle data source" ); return false; } // Insert the Source if it's not already inserted @@ -38,14 +39,12 @@ VehicleDataSourceBinder::addVehicleDataSource( VehicleDataSourcePtr source ) auto sourceIterator = mIdsToDataSources.emplace( source->getVehicleDataSourceID(), source ); if ( !sourceIterator.second ) { - mLogger.error( "VehicleDataSourceBinder::attachVehicleDataSource", - "Could not add the vehicle data source to the binder instance" ); + FWE_LOG_ERROR( "Could not add the vehicle data source to the binder instance" ); return false; } else { - mLogger.trace( "VehicleDataSourceBinder::attachVehicleDataSource", - "SourceID: " + std::to_string( source->getVehicleDataSourceID() ) + " added" ); + FWE_LOG_TRACE( "SourceID: " + std::to_string( source->getVehicleDataSourceID() ) + " added" ); } } // Register Self for Connect and Disconnect Callbacks and connect the vehicle data source @@ -55,9 +54,8 @@ VehicleDataSourceBinder::addVehicleDataSource( VehicleDataSourcePtr source ) } else { - mLogger.error( "VehicleDataSourceBinder::attachVehicleDataSource", - "Could not connect the vehicle data source with ID: " + - std::to_string( source->getVehicleDataSourceID() ) ); + FWE_LOG_ERROR( "Could not connect the vehicle data source with ID: " + + std::to_string( source->getVehicleDataSourceID() ) ); return false; } } @@ -68,6 +66,7 @@ VehicleDataSourceBinder::removeVehicleDataSource( const VehicleDataSourceID &id // Check if the data source is valid if ( id == INVALID_DATA_SOURCE_ID ) { + FWE_LOG_ERROR( "Invalid consumer instance or data source" ); return false; } auto backupSource = VehicleDataSourcePtr(); @@ -78,8 +77,7 @@ VehicleDataSourceBinder::removeVehicleDataSource( const VehicleDataSourceID &id // Something went wrong... removing a data source that does not exist if ( sourceIterator == mIdsToDataSources.end() ) { - mLogger.error( "VehicleDataSourceBinder::removeVehicleDataSource", - "Attempting to remove a vehicle data source that was not added" ); + FWE_LOG_ERROR( "Attempting to remove a vehicle data source that was not added" ); return false; } backupSource = sourceIterator->second; @@ -94,9 +92,8 @@ VehicleDataSourceBinder::removeVehicleDataSource( const VehicleDataSourceID &id } else { - mLogger.error( "VehicleDataSourceBinder::removeVehicleDataSource", - "Could not disconnect the vehicle data source with ID: " + - std::to_string( backupSource->getVehicleDataSourceID() ) ); + FWE_LOG_ERROR( "Could not disconnect the vehicle data source with ID: " + + std::to_string( backupSource->getVehicleDataSourceID() ) ); return false; } } @@ -113,15 +110,14 @@ VehicleDataSourceBinder::bindConsumerToVehicleDataSource( VehicleDataConsumerPtr // Check if the channelID and the consumer are valid if ( ( consumer.get() == nullptr ) || ( id == INVALID_DATA_SOURCE_ID ) ) { - mLogger.error( "VehicleDataSourceBinder::bindConsumerToVehicleDataSource", - "Invalid consumer instance or data source" ); + FWE_LOG_ERROR( "Invalid consumer instance or data source" ); return false; } // First lookup the data source and check if it's registered auto dataSourceIterator = mIdsToDataSources.find( id ); if ( dataSourceIterator == mIdsToDataSources.end() ) { - mLogger.error( "VehicleDataSourceBinder::bindConsumerToVehicleDataSource", "Source not found" ); + FWE_LOG_ERROR( "Source not found" ); return false; } // Insert the consumer/ID pair @@ -150,8 +146,7 @@ VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource( const VehicleDataS // Check if the data source ID is valid if ( id == INVALID_DATA_SOURCE_ID ) { - mLogger.error( "VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource", - "Invalid consumer instance or data source" ); + FWE_LOG_ERROR( "Invalid consumer instance or data source" ); return false; } @@ -163,7 +158,7 @@ VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource( const VehicleDataS // Something went wrong... No consumer is registered for this data source if ( consumerIterator == mDataSourcesToConsumers.end() ) { - mLogger.error( "VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource", "Consumer not found" ); + FWE_LOG_ERROR( "Consumer not found" ); return false; } backupConsumer = consumerIterator->second; @@ -192,7 +187,7 @@ VehicleDataSourceBinder::disconnectConsumer( const VehicleDataSourceID &id ) // Something went wrong... No consumer is registered for this data source if ( consumerIterator == mDataSourcesToConsumers.end() ) { - mLogger.error( "VehicleDataSourceBinder::disconnectConsumer", "Consumer not found" ); + FWE_LOG_ERROR( "Consumer not found" ); return false; } backupConsumer = consumerIterator->second; @@ -220,7 +215,7 @@ VehicleDataSourceBinder::reConnectConsumer( const VehicleDataSourceID &id ) // Something went wrong... No consumer is registered for this data source if ( consumerIterator == mDataSourcesToConsumers.end() ) { - mLogger.error( "VehicleDataSourceBinder::reConnectConsumer", "Consumer not found" ); + FWE_LOG_ERROR( "Consumer not found" ); return false; } backupConsumer = consumerIterator->second; @@ -246,11 +241,11 @@ VehicleDataSourceBinder::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "VehicleDataSourceBinder::start", "Binder Thread failed to start" ); + FWE_LOG_TRACE( "Binder Thread failed to start" ); } else { - mLogger.trace( "VehicleDataSourceBinder::start", "Binder Thread started" ); + FWE_LOG_TRACE( "Binder Thread started" ); mThread.setThreadName( "fwDIBinder" ); } @@ -296,8 +291,7 @@ VehicleDataSourceBinder::doWork( void *data ) uint32_t elapsedTimeUs = 0; binder->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); elapsedTimeUs += static_cast( binder->mTimer.getElapsedMs().count() ); - binder->mLogger.trace( "VehicleDataSourceBinder::doWork", - "Time Elapsed waiting for the interrupt: " + std::to_string( elapsedTimeUs ) ); + FWE_LOG_TRACE( "Time Elapsed waiting for the interrupt : " + std::to_string( elapsedTimeUs ) ); // Some Channels have been either connected or disconnected. // Copy the updates and release the lock so that other channels can @@ -319,8 +313,7 @@ VehicleDataSourceBinder::doWork( void *data ) // by the binder. if ( binder->reConnectConsumer( sourceID.first ) ) { - binder->mLogger.trace( "VehicleDataSourceBinder::doWork", - "Reconnected Source ID: " + std::to_string( sourceID.first ) ); + FWE_LOG_TRACE( "Reconnected Source ID: " + std::to_string( sourceID.first ) ); } } else if ( sourceID.second == VehicleDataSourceState::DISCONNECTED ) @@ -328,8 +321,7 @@ VehicleDataSourceBinder::doWork( void *data ) // Data source is disconnected, we need to make sure the consumer is also disconnected if ( binder->disconnectConsumer( sourceID.first ) ) { - binder->mLogger.trace( "VehicleDataSourceBinder::doWork", - "Disconnected Source ID: " + std::to_string( sourceID.first ) ); + FWE_LOG_TRACE( "Disconnected Source ID: " + std::to_string( sourceID.first ) ); } } } @@ -344,6 +336,7 @@ VehicleDataSourceBinder::onVehicleDataSourceConnected( const VehicleDataSourceID // Check if the data source ID is valid, should not happen if ( id == INVALID_DATA_SOURCE_ID ) { + FWE_LOG_ERROR( "Invalid consumer instance or data source" ); return; } // This event happens if the data source has been disconnected before and got @@ -365,6 +358,7 @@ VehicleDataSourceBinder::onVehicleDataSourceDisconnected( const VehicleDataSourc // Check if the data source ID is valid, should not happen if ( id == INVALID_DATA_SOURCE_ID ) { + FWE_LOG_ERROR( "Invalid consumer instance or data source" ); return; } // This event happens if the data source has been disconnected. @@ -401,12 +395,12 @@ VehicleDataSourceBinder::disconnect() { if ( !consumer.second->disconnect() ) { - mLogger.error( "VehicleDataSourceBinder::disconnect", "Failed to disconnect Consumer" ); + FWE_LOG_ERROR( "Failed to disconnect Consumer" ); return false; } else { - mLogger.trace( "VehicleDataSourceBinder::disconnect", "Consumer disconnected" ); + FWE_LOG_TRACE( "Consumer disconnected" ); } } } @@ -422,14 +416,12 @@ VehicleDataSourceBinder::disconnect() // if ( !source.second->unSubscribeListener( this ) || !source.second->disconnect() ) if ( !source.second->disconnect() ) { - mLogger.error( "VehicleDataSourceBinder::disconnect", - "Failed to disconnect Data source ID: " + std::to_string( source.first ) ); + FWE_LOG_ERROR( "Failed to disconnect Data source ID: " + std::to_string( source.first ) ); return false; } else { - mLogger.trace( "VehicleDataSourceBinder::disconnect", - "Data source ID: " + std::to_string( source.first ) + " disconnected" ); + FWE_LOG_TRACE( "Data source ID: " + std::to_string( source.first ) + " disconnected" ); } } } @@ -446,7 +438,7 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst // the channels and consumers must go to sleep. // 2- If we receive a new manifest, we should wake up the data source and the consumer for the given // Vehicle Data Consumer type - mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", "Decoder Manifest received" ); + FWE_LOG_TRACE( "Decoder Manifest received" ); // Start with the consumers, make sure that wake up first so that they pick up // the data for decoding immediately @@ -464,9 +456,8 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst if ( networkProtocol == consumer.second->getVehicleDataSourceProtocol() ) { consumer.second->resumeDataConsumption( dictionary ); - mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Resuming Consumption on Consumer: " + - std::to_string( consumer.second->getConsumerID() ) ); + FWE_LOG_TRACE( "Resuming Consumption on Consumer: " + + std::to_string( consumer.second->getConsumerID() ) ); } } ); @@ -476,9 +467,8 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst if ( networkProtocol == source.second->getVehicleDataSourceProtocol() ) { source.second->resumeDataAcquisition(); - mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Resuming Consumption on Data source: " + - std::to_string( source.second->getVehicleDataSourceID() ) ); + FWE_LOG_TRACE( "Resuming Consumption on Data source: " + + std::to_string( source.second->getVehicleDataSourceID() ) ); } } ); } @@ -491,9 +481,8 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst if ( networkProtocol == consumer.second->getVehicleDataSourceProtocol() ) { consumer.second->suspendDataConsumption(); - mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Interrupting Consumption on Consumer: " + - std::to_string( consumer.second->getConsumerID() ) ); + FWE_LOG_TRACE( "Interrupting Consumption on Consumer :" + + std::to_string( consumer.second->getConsumerID() ) ); } } ); @@ -503,9 +492,8 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst if ( networkProtocol == source.second->getVehicleDataSourceProtocol() ) { source.second->suspendDataAcquisition(); - mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Interrupting Consumption on Data source: " + - std::to_string( source.second->getVehicleDataSourceID() ) ); + FWE_LOG_TRACE( "Interrupting Consumption on Data source: " + + std::to_string( source.second->getVehicleDataSourceID() ) ); } } ); } diff --git a/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp b/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp index 2b1f2628..9136ee07 100644 --- a/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp +++ b/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp @@ -11,6 +11,10 @@ using namespace Aws::IoTFleetWise::DataInspection; using namespace Aws::IoTFleetWise::DataManagement; using namespace Aws::IoTFleetWise::TestingSupport; +using signalTypes = + ::testing::Types; + +template class CollectionInspectionEngineTest : public ::testing::Test { protected: @@ -18,6 +22,38 @@ class CollectionInspectionEngineTest : public ::testing::Test std::shared_ptr consCollectionSchemes; std::vector> expressionNodes; + bool + compareSignalValue( const SignalValueWrapper &signalValueWrapper, T sigVal ) + { + auto sigType = signalValueWrapper.getType(); + switch ( sigType ) + { + case SignalType::UINT8: + return static_cast( sigVal ) == signalValueWrapper.value.uint8Val; + case SignalType::INT8: + return static_cast( sigVal ) == signalValueWrapper.value.int8Val; + case SignalType::UINT16: + return static_cast( sigVal ) == signalValueWrapper.value.uint16Val; + case SignalType::INT16: + return static_cast( sigVal ) == signalValueWrapper.value.int16Val; + case SignalType::UINT32: + return static_cast( sigVal ) == signalValueWrapper.value.uint32Val; + case SignalType::INT32: + return static_cast( sigVal ) == signalValueWrapper.value.int32Val; + case SignalType::UINT64: + return static_cast( sigVal ) == signalValueWrapper.value.uint64Val; + case SignalType::INT64: + return static_cast( sigVal ) == signalValueWrapper.value.int64Val; + case SignalType::FLOAT: + return static_cast( sigVal ) == signalValueWrapper.value.floatVal; + case SignalType::DOUBLE: + return static_cast( sigVal ) == signalValueWrapper.value.doubleVal; + case SignalType::BOOLEAN: + return static_cast( sigVal ) == signalValueWrapper.value.boolVal; + } + return false; + } + void addSignalToCollect( ConditionWithCollectedData &collectionScheme, InspectionMatrixSignalCollectionInfo s ) { @@ -345,7 +381,81 @@ class CollectionInspectionEngineTest : public ::testing::Test } }; -TEST_F( CollectionInspectionEngineTest, EndlessCondition ) +class CollectionInspectionEngineDoubleTest : public CollectionInspectionEngineTest +{ +}; + +TYPED_TEST_SUITE( CollectionInspectionEngineTest, signalTypes ); + +TYPED_TEST( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToCollect ) +{ + CollectionInspectionEngine engine; + InspectionMatrixSignalCollectionInfo s1{}; + s1.signalID = 1; + s1.sampleBufferSize = 50; + s1.minimumSampleIntervalMs = 10; + s1.fixedWindowPeriod = 77777; + s1.isConditionOnlySignal = true; + InspectionMatrixSignalCollectionInfo s2{}; + s2.signalID = 2; + s2.sampleBufferSize = 50; + s2.minimumSampleIntervalMs = 10; + s2.fixedWindowPeriod = 77777; + s2.isConditionOnlySignal = true; + InspectionMatrixSignalCollectionInfo s3{}; + s3.signalID = 3; + s3.sampleBufferSize = 50; + s3.minimumSampleIntervalMs = 0; + s3.fixedWindowPeriod = 77777; + s3.isConditionOnlySignal = false; + s3.signalType = getSignalType(); + + this->addSignalToCollect( this->collectionSchemes->conditions[0], s1 ); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s2 ); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s3 ); + + // The condition is (signalID(1)>-100) && (signalID(2)>-500) + this->collectionSchemes->conditions[0].condition = + this->getTwoSignalsBiggerCondition( s1.signalID, -100.0, s2.signalID, -500.0 ).get(); + engine.onChangeInspectionMatrix( this->consCollectionSchemes ); + + TimePoint timestamp = { 160000000, 100 }; + TypeParam testVal1 = 10; + TypeParam testVal2 = 20; + TypeParam testVal3 = 30; + engine.addNewSignal( s3.signalID, timestamp, testVal1 ); + engine.addNewSignal( s3.signalID, timestamp, testVal2 ); + engine.addNewSignal( s3.signalID, timestamp, testVal3 ); + + // Signals for condition are not available yet so collectionScheme should not trigger + engine.evaluateConditions( timestamp ); + uint32_t waitTimeMs = 0; + ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); + + timestamp += 1000; + engine.addNewSignal( s1.signalID, timestamp, -90.0 ); + engine.addNewSignal( s2.signalID, timestamp, -1000.0 ); + + // Condition only for first signal is fulfilled (-90 > -100) but second not so boolean and is false + engine.evaluateConditions( timestamp ); + ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); + + timestamp += 1000; + + engine.addNewSignal( s2.signalID, timestamp, -480.0 ); + + // Condition is fulfilled so it should trigger + engine.evaluateConditions( timestamp ); + auto collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); + ASSERT_NE( collectedData, nullptr ); + ASSERT_EQ( collectedData->signals.size(), 3 ); + ASSERT_EQ( collectedData->signals[0].signalID, s3.signalID ); + ASSERT_EQ( collectedData->signals[1].signalID, s3.signalID ); + ASSERT_EQ( collectedData->signals[2].signalID, s3.signalID ); + ASSERT_EQ( collectedData->triggerTime, timestamp.systemTimeMs ); +} + +TEST_F( CollectionInspectionEngineDoubleTest, EndlessCondition ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -372,7 +482,7 @@ TEST_F( CollectionInspectionEngineTest, EndlessCondition ) EXPECT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, TooBigForSignalBuffer ) +TEST_F( CollectionInspectionEngineDoubleTest, TooBigForSignalBuffer ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -382,14 +492,15 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBuffer ) 500000000; // this number of samples should exceed the maximum buffer size defined in MAX_SAMPLE_MEMORY s1.minimumSampleIntervalMs = 5; s1.fixedWindowPeriod = 77777; + s1.signalType = SignalType::DOUBLE; addSignalToCollect( collectionSchemes->conditions[0], s1 ); collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); // All signal come at the same timestamp - engine.addNewSignal( s1.signalID, timestamp + 1000, 0.2 ); - engine.addNewSignal( s1.signalID, timestamp + 2000, 0.3 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); // All signal come at the same timestamp + engine.addNewSignal( s1.signalID, timestamp + 1000, 0.2 ); + engine.addNewSignal( s1.signalID, timestamp + 2000, 0.3 ); engine.evaluateConditions( timestamp + 3000 ); @@ -399,7 +510,7 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBuffer ) ASSERT_EQ( collectedData->signals.size(), 0 ); } -TEST_F( CollectionInspectionEngineTest, TooBigForSignalBufferOverflow ) +TEST_F( CollectionInspectionEngineDoubleTest, TooBigForSignalBufferOverflow ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -422,9 +533,9 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBufferOverflow ) TimePoint timestamp = { 160000000, 100 }; // All signal come at the same timestamp - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); - engine.addNewSignal( s1.signalID, timestamp + 1000, 0.2 ); - engine.addNewSignal( s1.signalID, timestamp + 2000, 0.3 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 1000, 0.2 ); + engine.addNewSignal( s1.signalID, timestamp + 2000, 0.3 ); engine.evaluateConditions( timestamp + 3000 ); @@ -434,7 +545,7 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBufferOverflow ) ASSERT_EQ( collectedData->signals.size(), 0 ); } -TEST_F( CollectionInspectionEngineTest, SignalBufferErasedAfterNewConditions ) +TEST_F( CollectionInspectionEngineDoubleTest, SignalBufferErasedAfterNewConditions ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -449,15 +560,15 @@ TEST_F( CollectionInspectionEngineTest, SignalBufferErasedAfterNewConditions ) TimePoint timestamp = { 160000000, 100 }; // All signal come at the same timestamp - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); - engine.addNewSignal( s1.signalID, timestamp + 1, 0.2 ); - engine.addNewSignal( s1.signalID, timestamp + 2, 0.3 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 1, 0.2 ); + engine.addNewSignal( s1.signalID, timestamp + 2, 0.3 ); // This call will flush the signal history buffer even when // exactly the same conditions are handed over. engine.onChangeInspectionMatrix( consCollectionSchemes ); - engine.addNewSignal( s1.signalID, timestamp + 3, 0.4 ); + engine.addNewSignal( s1.signalID, timestamp + 3, 0.4 ); engine.evaluateConditions( timestamp + 3 ); @@ -466,10 +577,10 @@ TEST_F( CollectionInspectionEngineTest, SignalBufferErasedAfterNewConditions ) ASSERT_NE( collectedData, nullptr ); ASSERT_EQ( collectedData->signals.size(), 1 ); - EXPECT_EQ( collectedData->signals[0].value, 0.4 ); + EXPECT_EQ( collectedData->signals[0].value.value.doubleVal, 0.4 ); } -TEST_F( CollectionInspectionEngineTest, CollectBurstWithoutSubsampling ) +TEST_F( CollectionInspectionEngineDoubleTest, CollectBurstWithoutSubsampling ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -484,9 +595,9 @@ TEST_F( CollectionInspectionEngineTest, CollectBurstWithoutSubsampling ) TimePoint timestamp = { 160000000, 100 }; // All signal come at the same timestamp - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); - engine.addNewSignal( s1.signalID, timestamp, 0.2 ); - engine.addNewSignal( s1.signalID, timestamp, 0.3 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.2 ); + engine.addNewSignal( s1.signalID, timestamp, 0.3 ); engine.evaluateConditions( timestamp ); @@ -495,12 +606,12 @@ TEST_F( CollectionInspectionEngineTest, CollectBurstWithoutSubsampling ) ASSERT_NE( collectedData, nullptr ); ASSERT_EQ( collectedData->signals.size(), 3 ); - EXPECT_EQ( collectedData->signals[0].value, 0.3 ); - EXPECT_EQ( collectedData->signals[1].value, 0.2 ); - EXPECT_EQ( collectedData->signals[2].value, 0.1 ); + EXPECT_EQ( collectedData->signals[0].value.value.doubleVal, 0.3 ); + EXPECT_EQ( collectedData->signals[1].value.value.doubleVal, 0.2 ); + EXPECT_EQ( collectedData->signals[2].value.value.doubleVal, 0.1 ); } -TEST_F( CollectionInspectionEngineTest, IllegalSignalID ) +TEST_F( CollectionInspectionEngineDoubleTest, IllegalSignalID ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -514,7 +625,7 @@ TEST_F( CollectionInspectionEngineTest, IllegalSignalID ) engine.onChangeInspectionMatrix( consCollectionSchemes ); } -TEST_F( CollectionInspectionEngineTest, IllegalSampleSize ) +TEST_F( CollectionInspectionEngineDoubleTest, IllegalSampleSize ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -528,7 +639,7 @@ TEST_F( CollectionInspectionEngineTest, IllegalSampleSize ) engine.onChangeInspectionMatrix( consCollectionSchemes ); } -TEST_F( CollectionInspectionEngineTest, ZeroSignalsOnlyDTCCollection ) +TEST_F( CollectionInspectionEngineDoubleTest, ZeroSignalsOnlyDTCCollection ) { CollectionInspectionEngine engine; collectionSchemes->conditions[0].includeActiveDtcs = true; @@ -549,7 +660,7 @@ TEST_F( CollectionInspectionEngineTest, ZeroSignalsOnlyDTCCollection ) EXPECT_EQ( collectedData->mDTCInfo.mDTCCodes[0], "B1217" ); } -TEST_F( CollectionInspectionEngineTest, CollectRawCanFrames ) +TEST_F( CollectionInspectionEngineDoubleTest, CollectRawCanFrames ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -580,7 +691,7 @@ TEST_F( CollectionInspectionEngineTest, CollectRawCanFrames ) EXPECT_TRUE( 0 == std::memcmp( collectedData->canFrames[0].data.data(), buf.data(), sizeof( buf ) ) ); } -TEST_F( CollectionInspectionEngineTest, CollectRawCanFDFrames ) +TEST_F( CollectionInspectionEngineDoubleTest, CollectRawCanFDFrames ) { CollectionInspectionEngine engine; // minimumSampleIntervalMs=0 means no subsampling @@ -612,7 +723,7 @@ TEST_F( CollectionInspectionEngineTest, CollectRawCanFDFrames ) EXPECT_TRUE( 0 == std::memcmp( collectedData->canFrames[0].data.data(), buf.data(), sizeof( buf ) ) ); } -TEST_F( CollectionInspectionEngineTest, MultipleCanSubsampling ) +TEST_F( CollectionInspectionEngineDoubleTest, MultipleCanSubsampling ) { CollectionInspectionEngine engine; InspectionMatrixCanFrameCollectionInfo c1; @@ -663,7 +774,7 @@ TEST_F( CollectionInspectionEngineTest, MultipleCanSubsampling ) ASSERT_EQ( collectedData->canFrames.size(), 8 ); } -TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInConditions ) +TEST_F( CollectionInspectionEngineDoubleTest, MultipleSubsamplingOfSameSignalUsedInConditions ) { CollectionInspectionEngine engine; @@ -718,10 +829,10 @@ TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInCon for ( int i = 0; i < 100; i++ ) { - engine.addNewSignal( s1.signalID, timestamp + i * 10, i * 2 ); - engine.addNewSignal( s3.signalID, timestamp + i * 10, i * 2 + 1 ); - engine.addNewSignal( s5.signalID, timestamp + i * 10, 55555 ); - engine.addNewSignal( s6.signalID, timestamp + i * 10, 77777 ); + engine.addNewSignal( s1.signalID, timestamp + i * 10, i * 2 ); + engine.addNewSignal( s3.signalID, timestamp + i * 10, i * 2 + 1 ); + engine.addNewSignal( s5.signalID, timestamp + i * 10, 55555 ); + engine.addNewSignal( s6.signalID, timestamp + i * 10, 77777 ); } engine.evaluateConditions( timestamp ); @@ -736,7 +847,6 @@ TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInCon collectedDataList.push_back( collectedData ); collectedData = engine.collectNextDataToSend( timestamp + 100 * 10, waitTimeMs ); } - ASSERT_EQ( collectedDataList.size(), 2 ); std::sort( collectedDataList.begin(), collectedDataList.end(), []( CollectionType a, CollectionType b ) { @@ -755,7 +865,7 @@ TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInCon 1 ); } -TEST_F( CollectionInspectionEngineTest, MultipleFixedWindowsOfSameSignalUsedInConditions ) +TEST_F( CollectionInspectionEngineDoubleTest, MultipleFixedWindowsOfSameSignalUsedInConditions ) { CollectionInspectionEngine engine; @@ -796,9 +906,9 @@ TEST_F( CollectionInspectionEngineTest, MultipleFixedWindowsOfSameSignalUsedInCo for ( int i = 0; i < 300; i++ ) { - engine.addNewSignal( s1.signalID, timestamp + i * 10, i * 2 ); - engine.addNewSignal( s5.signalID, timestamp + i * 10, 55555 ); - engine.addNewSignal( s6.signalID, timestamp + i * 10, 77777 ); + engine.addNewSignal( s1.signalID, timestamp + i * 10, i * 2 ); + engine.addNewSignal( s5.signalID, timestamp + i * 10, 55555 ); + engine.addNewSignal( s6.signalID, timestamp + i * 10, 77777 ); } engine.evaluateConditions( timestamp ); @@ -831,7 +941,7 @@ TEST_F( CollectionInspectionEngineTest, MultipleFixedWindowsOfSameSignalUsedInCo 1 ); } -TEST_F( CollectionInspectionEngineTest, Subsampling ) +TEST_F( CollectionInspectionEngineDoubleTest, Subsampling ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -846,12 +956,12 @@ TEST_F( CollectionInspectionEngineTest, Subsampling ) engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); - engine.addNewSignal( s1.signalID, timestamp + 1, 0.2 ); - engine.addNewSignal( s1.signalID, timestamp + 9, 0.3 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 1, 0.2 ); + engine.addNewSignal( s1.signalID, timestamp + 9, 0.3 ); // As subsampling is 10 this value should be sampled again - engine.addNewSignal( s1.signalID, timestamp + 10, 0.4 ); - engine.addNewSignal( s1.signalID, timestamp + 40, 0.5 ); + engine.addNewSignal( s1.signalID, timestamp + 10, 0.4 ); + engine.addNewSignal( s1.signalID, timestamp + 40, 0.5 ); engine.evaluateConditions( timestamp ); @@ -860,13 +970,13 @@ TEST_F( CollectionInspectionEngineTest, Subsampling ) ASSERT_NE( collectedData, nullptr ); ASSERT_EQ( collectedData->signals.size(), 3 ); - EXPECT_EQ( collectedData->signals[0].value, 0.5 ); - EXPECT_EQ( collectedData->signals[1].value, 0.4 ); - EXPECT_EQ( collectedData->signals[2].value, 0.1 ); + EXPECT_EQ( collectedData->signals[0].value.value.doubleVal, 0.5 ); + EXPECT_EQ( collectedData->signals[1].value.value.doubleVal, 0.4 ); + EXPECT_EQ( collectedData->signals[2].value.value.doubleVal, 0.1 ); } // Only valid when sendDataOnlyOncePerCondition is defined true -TEST_F( CollectionInspectionEngineTest, SendoutEverySignalOnlyOnce ) +TEST_F( CollectionInspectionEngineDoubleTest, SendoutEverySignalOnlyOnce ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -884,7 +994,7 @@ TEST_F( CollectionInspectionEngineTest, SendoutEverySignalOnlyOnce ) engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -897,7 +1007,7 @@ TEST_F( CollectionInspectionEngineTest, SendoutEverySignalOnlyOnce ) ASSERT_NE( res2, nullptr ); EXPECT_EQ( res2->signals.size(), 0 ); // Very old element in queue gets pushed - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp + 20000 ); auto res3 = engine.collectNextDataToSend( timestamp + 20000, waitTimeMs ); @@ -905,7 +1015,7 @@ TEST_F( CollectionInspectionEngineTest, SendoutEverySignalOnlyOnce ) EXPECT_EQ( res3->signals.size(), 1 ); } -TEST_F( CollectionInspectionEngineTest, HearbeatInterval ) +TYPED_TEST( CollectionInspectionEngineTest, HearbeatInterval ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -913,35 +1023,36 @@ TEST_F( CollectionInspectionEngineTest, HearbeatInterval ) s1.sampleBufferSize = 50; s1.minimumSampleIntervalMs = 10; s1.fixedWindowPeriod = 77777; - addSignalToCollect( collectionSchemes->conditions[0], s1 ); + s1.signalType = getSignalType(); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; - collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); + this->collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; + this->collectionSchemes->conditions[0].condition = this->getAlwaysTrueCondition().get(); - engine.onChangeInspectionMatrix( consCollectionSchemes ); + engine.onChangeInspectionMatrix( this->consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 11 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; // it should have triggered and data should be available EXPECT_NE( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); - engine.addNewSignal( s1.signalID, timestamp + 500, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 500, 11 ); engine.evaluateConditions( timestamp + 500 ); // No new data because heartbeat did not trigger less than 10 seconds passed EXPECT_EQ( engine.collectNextDataToSend( timestamp + 500, waitTimeMs ), nullptr ); - engine.addNewSignal( s1.signalID, timestamp + 10000, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 10000, 11 ); engine.evaluateConditions( timestamp + 10000 ); // heartbeat MinimumPublishIntervalMs=10seconds is over so again data EXPECT_NE( engine.collectNextDataToSend( timestamp + 10000, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, TwoCollectionSchemesWithDifferentNumberOfSamplesToCollect ) +TEST_F( CollectionInspectionEngineDoubleTest, TwoCollectionSchemesWithDifferentNumberOfSamplesToCollect ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -980,8 +1091,8 @@ TEST_F( CollectionInspectionEngineTest, TwoCollectionSchemesWithDifferentNumberO for ( int i = 0; i < 10000; i++ ) { timestamp++; - engine.addNewSignal( s1.signalID, timestamp, i * i ); - engine.addNewSignal( s2.signalID, timestamp, i + 2 ); + engine.addNewSignal( s1.signalID, timestamp, i * i ); + engine.addNewSignal( s2.signalID, timestamp, i + 2 ); } engine.evaluateConditions( timestamp ); @@ -999,7 +1110,7 @@ TEST_F( CollectionInspectionEngineTest, TwoCollectionSchemesWithDifferentNumberO // twice by different collection schemes, otherwise this would have only 720 samples } -TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToCollect ) +TEST_F( CollectionInspectionEngineDoubleTest, TwoSignalsInConditionAndOneSignalToCollect ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -1030,9 +1141,9 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s3.signalID, timestamp, 1000.0 ); - engine.addNewSignal( s3.signalID, timestamp, 2000.0 ); - engine.addNewSignal( s3.signalID, timestamp, 3000.0 ); + engine.addNewSignal( s3.signalID, timestamp, 1000.0 ); + engine.addNewSignal( s3.signalID, timestamp, 2000.0 ); + engine.addNewSignal( s3.signalID, timestamp, 3000.0 ); // Signals for condition are not available yet so collectionScheme should not trigger engine.evaluateConditions( timestamp ); @@ -1041,8 +1152,8 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle timestamp += 1000; - engine.addNewSignal( s1.signalID, timestamp, -90.0 ); - engine.addNewSignal( s2.signalID, timestamp, -1000.0 ); + engine.addNewSignal( s1.signalID, timestamp, -90.0 ); + engine.addNewSignal( s2.signalID, timestamp, -1000.0 ); // Condition only for first signal is fulfilled (-90 > -100) but second not so boolean and is false engine.evaluateConditions( timestamp ); @@ -1050,7 +1161,7 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle timestamp += 1000; - engine.addNewSignal( s2.signalID, timestamp, -480.0 ); + engine.addNewSignal( s2.signalID, timestamp, -480.0 ); // Condition is fulfilled so it should trigger engine.evaluateConditions( timestamp ); @@ -1064,7 +1175,7 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle } // Default is to send data only out once per collectionScheme -TEST_F( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionScheme ) +TYPED_TEST( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionScheme ) { CollectionInspectionEngine engine( true ); InspectionMatrixSignalCollectionInfo s1{}; @@ -1072,16 +1183,17 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionS s1.sampleBufferSize = 50; s1.minimumSampleIntervalMs = 10; s1.fixedWindowPeriod = 77777; - addSignalToCollect( collectionSchemes->conditions[0], s1 ); + s1.signalType = getSignalType(); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishIntervalMs = 5000; - collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); + this->collectionSchemes->conditions[0].minimumPublishIntervalMs = 5000; + this->collectionSchemes->conditions[0].condition = this->getAlwaysTrueCondition().get(); - engine.onChangeInspectionMatrix( consCollectionSchemes ); + engine.onChangeInspectionMatrix( this->consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 10 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -1094,7 +1206,7 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionS ASSERT_NE( res2, nullptr ); EXPECT_EQ( res2->signals.size(), 0 ); - engine.addNewSignal( s1.signalID, timestamp + 15000, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 15000, 10 ); engine.evaluateConditions( timestamp + 20000 ); auto res3 = engine.collectNextDataToSend( timestamp + 20000, waitTimeMs ); @@ -1102,7 +1214,7 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionS EXPECT_EQ( res3->signals.size(), 1 ); } -TEST_F( CollectionInspectionEngineTest, SendOutEverySignalNotOnlyOncePerCollectionScheme ) +TEST_F( CollectionInspectionEngineDoubleTest, SendOutEverySignalNotOnlyOncePerCollectionScheme ) { CollectionInspectionEngine engine( false ); InspectionMatrixSignalCollectionInfo s1{}; @@ -1119,7 +1231,7 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalNotOnlyOncePerCollecti engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -1132,7 +1244,7 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalNotOnlyOncePerCollecti ASSERT_NE( res2, nullptr ); EXPECT_EQ( res2->signals.size(), 1 ); - engine.addNewSignal( s1.signalID, timestamp + 15000, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp + 15000, 0.1 ); engine.evaluateConditions( timestamp + 20000 ); auto res3 = engine.collectNextDataToSend( timestamp + 20000, waitTimeMs ); @@ -1140,7 +1252,7 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalNotOnlyOncePerCollecti EXPECT_EQ( res3->signals.size(), 2 ); } -TEST_F( CollectionInspectionEngineTest, MoreCollectionSchemesThanSupported ) +TEST_F( CollectionInspectionEngineDoubleTest, MoreCollectionSchemesThanSupported ) { CollectionInspectionEngine engine( false ); InspectionMatrixSignalCollectionInfo s1{}; @@ -1159,7 +1271,7 @@ TEST_F( CollectionInspectionEngineTest, MoreCollectionSchemesThanSupported ) TimePoint timestamp = { 160000000, 100 }; uint32_t waitTimeMs = 0; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); engine.collectNextDataToSend( timestamp, waitTimeMs ); timestamp += 10000; @@ -1183,7 +1295,7 @@ TEST_F( CollectionInspectionEngineTest, MoreCollectionSchemesThanSupported ) * 6. As final step, we supply invalid lat/lon to test Inspection Engine can gracefully handle * invalid signal */ -TEST_F( CollectionInspectionEngineTest, GeohashFunctionNodeTrigger ) +TEST_F( CollectionInspectionEngineDoubleTest, GeohashFunctionNodeTrigger ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo lat{}; @@ -1212,8 +1324,8 @@ TEST_F( CollectionInspectionEngineTest, GeohashFunctionNodeTrigger ) ASSERT_EQ( collectedData, nullptr ); timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.371392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.046208 ); + engine.addNewSignal( lat.signalID, timestamp, 37.371392 ); + engine.addNewSignal( lon.signalID, timestamp, -122.046208 ); ASSERT_TRUE( engine.evaluateConditions( timestamp ) ); collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); @@ -1224,16 +1336,16 @@ TEST_F( CollectionInspectionEngineTest, GeohashFunctionNodeTrigger ) // 37.361392, -122.056208 -> 9q9hw93mu. still within the same geohash tile at precision 5. timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.361392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.056208 ); + engine.addNewSignal( lat.signalID, timestamp, 37.361392 ); + engine.addNewSignal( lon.signalID, timestamp, -122.056208 ); ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); ASSERT_EQ( collectedData, nullptr ); // 37.351392, -122.066208 -> 9q9hqkpbp. Geohash changed at precision 5. timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); + engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); + engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); ASSERT_TRUE( engine.evaluateConditions( timestamp ) ); collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); ASSERT_NE( collectedData, nullptr ); @@ -1243,22 +1355,22 @@ TEST_F( CollectionInspectionEngineTest, GeohashFunctionNodeTrigger ) // We supply an invalid latitude timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 137.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); + engine.addNewSignal( lat.signalID, timestamp, 137.351392 ); + engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); ASSERT_EQ( collectedData, nullptr ); // We supply an invalid longitude timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -222.066208 ); + engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); + engine.addNewSignal( lon.signalID, timestamp, -222.066208 ); ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); ASSERT_EQ( collectedData, nullptr ); } -TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) +TYPED_TEST( CollectionInspectionEngineTest, CollectWithAfterTime ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -1279,22 +1391,24 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) s3.minimumSampleIntervalMs = 0; s3.fixedWindowPeriod = 77777; s3.isConditionOnlySignal = false; - addSignalToCollect( collectionSchemes->conditions[0], s1 ); - addSignalToCollect( collectionSchemes->conditions[0], s2 ); - addSignalToCollect( collectionSchemes->conditions[0], s3 ); + s3.signalType = getSignalType(); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s1 ); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s2 ); + this->addSignalToCollect( this->collectionSchemes->conditions[0], s3 ); // The condition is (signalID(1)>-100) && (signalID(2)>-500) - collectionSchemes->conditions[0].condition = - getTwoSignalsBiggerCondition( s1.signalID, -100.0, s2.signalID, -500.0 ).get(); + this->collectionSchemes->conditions[0].condition = + this->getTwoSignalsBiggerCondition( s1.signalID, -100.0, s2.signalID, -500.0 ).get(); // After the collectionScheme triggered signals should be collected for 2 more seconds - collectionSchemes->conditions[0].afterDuration = 2000; - engine.onChangeInspectionMatrix( consCollectionSchemes ); + this->collectionSchemes->conditions[0].afterDuration = 2000; + engine.onChangeInspectionMatrix( this->consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s3.signalID, timestamp, 1000.0 ); - engine.addNewSignal( s1.signalID, timestamp, -90.0 ); - engine.addNewSignal( s2.signalID, timestamp, -1000.0 ); + TypeParam val1 = 10; + engine.addNewSignal( s3.signalID, timestamp, val1 ); + engine.addNewSignal( s1.signalID, timestamp, -90.0 ); + engine.addNewSignal( s2.signalID, timestamp, -1000.0 ); // Condition not fulfilled so should not trigger engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -1303,9 +1417,10 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) timestamp += 1000; TimePoint timestamp0 = timestamp; - engine.addNewSignal( s3.signalID, timestamp, 2000.0 ); - engine.addNewSignal( s1.signalID, timestamp, -90.0 ); - engine.addNewSignal( s2.signalID, timestamp, -480.0 ); + TypeParam val2 = 20; + engine.addNewSignal( s3.signalID, timestamp, val2 ); + engine.addNewSignal( s1.signalID, timestamp, -90.0 ); + engine.addNewSignal( s2.signalID, timestamp, -480.0 ); // Condition fulfilled so should trigger but afterTime not over yet engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); @@ -1313,9 +1428,10 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) timestamp += 1000; TimePoint timestamp1 = timestamp; - engine.addNewSignal( s3.signalID, timestamp, 3000.0 ); - engine.addNewSignal( s1.signalID, timestamp, -95.0 ); - engine.addNewSignal( s2.signalID, timestamp, -485.0 ); + TypeParam val3 = 30; + engine.addNewSignal( s3.signalID, timestamp, val3 ); + engine.addNewSignal( s1.signalID, timestamp, -95.0 ); + engine.addNewSignal( s2.signalID, timestamp, -485.0 ); // Condition still fulfilled but already triggered. After time still not over engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); @@ -1323,18 +1439,20 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) timestamp += 500; TimePoint timestamp2 = timestamp; - engine.addNewSignal( s3.signalID, timestamp, 4000.0 ); - engine.addNewSignal( s1.signalID, timestamp, -9000.0 ); - engine.addNewSignal( s2.signalID, timestamp, -9000.0 ); + TypeParam val4 = 40; + engine.addNewSignal( s3.signalID, timestamp, val4 ); + engine.addNewSignal( s1.signalID, timestamp, -9000.0 ); + engine.addNewSignal( s2.signalID, timestamp, -9000.0 ); // Condition not fulfilled anymore but still waiting for afterTime engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); timestamp += 500; TimePoint timestamp3 = timestamp; - engine.addNewSignal( s3.signalID, timestamp, 5000.0 ); - engine.addNewSignal( s1.signalID, timestamp, -9100.0 ); - engine.addNewSignal( s2.signalID, timestamp, -9100.0 ); + TypeParam val5 = 50; + engine.addNewSignal( s3.signalID, timestamp, val5 ); + engine.addNewSignal( s1.signalID, timestamp, -9100.0 ); + engine.addNewSignal( s2.signalID, timestamp, -9100.0 ); // Condition not fulfilled. After Time is over so data should be sent out engine.evaluateConditions( timestamp ); auto collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); @@ -1342,16 +1460,16 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) // sampleBufferSize of the only collected signal s3 is 3 ASSERT_EQ( collectedData->signals.size(), 3 ); - ASSERT_EQ( collectedData->signals[0].value, 5000.0 ); + ASSERT_TRUE( this->compareSignalValue( collectedData->signals[0].getValue(), val5 ) ); ASSERT_EQ( collectedData->signals[0].receiveTime, timestamp3.systemTimeMs ); - ASSERT_EQ( collectedData->signals[1].value, 4000.0 ); + ASSERT_TRUE( this->compareSignalValue( collectedData->signals[1].getValue(), val4 ) ); ASSERT_EQ( collectedData->signals[1].receiveTime, timestamp2.systemTimeMs ); - ASSERT_EQ( collectedData->signals[2].value, 3000.0 ); + ASSERT_TRUE( this->compareSignalValue( collectedData->signals[2].getValue(), val3 ) ); ASSERT_EQ( collectedData->signals[2].receiveTime, timestamp1.systemTimeMs ); ASSERT_EQ( collectedData->triggerTime, timestamp0.systemTimeMs ); } -TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) +TEST_F( CollectionInspectionEngineDoubleTest, ProbabilityToSendTest ) { CollectionInspectionEngine engine; @@ -1379,7 +1497,7 @@ TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) for ( uint32_t i = 0; i < NR_OF_HEARTBEAT_INTERVALS; i++ ) { - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); + engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); if ( engine.collectNextDataToSend( timestamp, waitTimeMs ) != nullptr ) { @@ -1399,7 +1517,7 @@ TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) << " were actually sent" << std::endl; } -TEST_F( CollectionInspectionEngineTest, AvgWindowCondition ) +TEST_F( CollectionInspectionEngineDoubleTest, AvgWindowCondition ) { CollectionInspectionEngine engine; // fixedWindowPeriod means that we collect data over 300 seconds @@ -1423,7 +1541,7 @@ TEST_F( CollectionInspectionEngineTest, AvgWindowCondition ) { timestamp++; currentValue += increasePerSample; - engine.addNewSignal( s1.signalID, timestamp, currentValue ); + engine.addNewSignal( s1.signalID, timestamp, currentValue ); engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } @@ -1435,7 +1553,7 @@ TEST_F( CollectionInspectionEngineTest, AvgWindowCondition ) { timestamp++; currentValue += increasePerSample; - engine.addNewSignal( s1.signalID, timestamp, currentValue ); + engine.addNewSignal( s1.signalID, timestamp, currentValue ); engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } @@ -1444,7 +1562,7 @@ TEST_F( CollectionInspectionEngineTest, AvgWindowCondition ) ASSERT_NE( engine.collectNextDataToSend( timestamp + 2, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, PrevLastAvgWindowCondition ) +TEST_F( CollectionInspectionEngineDoubleTest, PrevLastAvgWindowCondition ) { CollectionInspectionEngine engine; // fixedWindowPeriod means that we collect data over 300 seconds @@ -1465,19 +1583,19 @@ TEST_F( CollectionInspectionEngineTest, PrevLastAvgWindowCondition ) for ( uint32_t i = 0; i < s1.fixedWindowPeriod; i++ ) { timestamp++; - engine.addNewSignal( s1.signalID, timestamp, 0.0 ); + engine.addNewSignal( s1.signalID, timestamp, 0.0 ); engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } // No samples arrive for two window2: timestamp += s1.fixedWindowPeriod * 2; // One more arrives, prev last average is still 0 which is > -50 - engine.addNewSignal( s1.signalID, timestamp, -100.0 ); + engine.addNewSignal( s1.signalID, timestamp, -100.0 ); engine.evaluateConditions( timestamp ); ASSERT_NE( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, MultiWindowCondition ) +TEST_F( CollectionInspectionEngineDoubleTest, MultiWindowCondition ) { CollectionInspectionEngine engine; // fixedWindowPeriod means that we collect data over 300 seconds @@ -1496,22 +1614,22 @@ TEST_F( CollectionInspectionEngineTest, MultiWindowCondition ) engine.onChangeInspectionMatrix( consCollectionSchemes ); TimePoint timestamp = { 160000000, 100 }; - engine.addNewSignal( s1.signalID, timestamp, -95.0 ); - engine.addNewSignal( s1.signalID, timestamp + 50, 100.0 ); - engine.addNewSignal( s1.signalID, timestamp + 70, 110.0 ); + engine.addNewSignal( s1.signalID, timestamp, -95.0 ); + engine.addNewSignal( s1.signalID, timestamp + 50, 100.0 ); + engine.addNewSignal( s1.signalID, timestamp + 70, 110.0 ); // Condition still fulfilled but already triggered. After time still not over engine.evaluateConditions( timestamp + 70 ); uint32_t waitTimeMs = 0; ASSERT_EQ( engine.collectNextDataToSend( timestamp + 70, waitTimeMs ), nullptr ); - engine.addNewSignal( s1.signalID, timestamp + 100, -205.0 ); - engine.addNewSignal( s1.signalID, timestamp + 150, -300.0 ); - engine.addNewSignal( s1.signalID, timestamp + 200, +30.0 ); + engine.addNewSignal( s1.signalID, timestamp + 100, -205.0 ); + engine.addNewSignal( s1.signalID, timestamp + 150, -300.0 ); + engine.addNewSignal( s1.signalID, timestamp + 200, +30.0 ); engine.evaluateConditions( timestamp + 200 ); ASSERT_NE( engine.collectNextDataToSend( timestamp + 200, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, TestNotEqualOperator ) +TEST_F( CollectionInspectionEngineDoubleTest, TestNotEqualOperator ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -1533,26 +1651,26 @@ TEST_F( CollectionInspectionEngineTest, TestNotEqualOperator ) TimePoint timestamp = { 160000000, 100 }; // Expression should be false because they are equal - engine.addNewSignal( s1.signalID, timestamp, 100.0 ); - engine.addNewSignal( s2.signalID, timestamp, 100.0 ); + engine.addNewSignal( s1.signalID, timestamp, 100.0 ); + engine.addNewSignal( s2.signalID, timestamp, 100.0 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); // Expression should be true: because they are not equal timestamp++; - engine.addNewSignal( s1.signalID, timestamp, 50 ); + engine.addNewSignal( s1.signalID, timestamp, 50 ); engine.evaluateConditions( timestamp ); ASSERT_NE( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); // Expression should be false because they are equal again timestamp++; - engine.addNewSignal( s2.signalID, timestamp, 50.0 ); + engine.addNewSignal( s2.signalID, timestamp, 50.0 ); engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, TwoSignalsRatioCondition ) +TEST_F( CollectionInspectionEngineDoubleTest, TwoSignalsRatioCondition ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -1575,32 +1693,32 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsRatioCondition ) TimePoint timestamp = { 160000000, 100 }; // Expression should be false: (1.0 <= 0.001) || (1.0 / 100.0) >= 0.5) - engine.addNewSignal( s1.signalID, timestamp, 1.0 ); - engine.addNewSignal( s2.signalID, timestamp, 100.0 ); + engine.addNewSignal( s1.signalID, timestamp, 1.0 ); + engine.addNewSignal( s2.signalID, timestamp, 100.0 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); // Expression should be true: (0.001 <= 0.001) || (0.001 / 100.0) >= 0.5) timestamp++; - engine.addNewSignal( s1.signalID, timestamp, 0.001 ); + engine.addNewSignal( s1.signalID, timestamp, 0.001 ); engine.evaluateConditions( timestamp ); ASSERT_NE( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); // Expression should be false: (1.0 <= 0.001) || (1.0 / 100.0) >= 0.5) timestamp++; - engine.addNewSignal( s1.signalID, timestamp, 1.0 ); + engine.addNewSignal( s1.signalID, timestamp, 1.0 ); engine.evaluateConditions( timestamp ); ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); // Expression should be true: (50.0 <= 0.001) || (50.0 / 100.0) >= 0.5) timestamp++; - engine.addNewSignal( s1.signalID, timestamp, 50.0 ); + engine.addNewSignal( s1.signalID, timestamp, 50.0 ); engine.evaluateConditions( timestamp ); ASSERT_NE( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, UnknownExpressionNode ) +TEST_F( CollectionInspectionEngineDoubleTest, UnknownExpressionNode ) { CollectionInspectionEngine engine; InspectionMatrixSignalCollectionInfo s1{}; @@ -1616,13 +1734,13 @@ TEST_F( CollectionInspectionEngineTest, UnknownExpressionNode ) TimePoint timestamp = { 160000000, 100 }; // Expression should be false: (1.0 <= Unknown) - engine.addNewSignal( s1.signalID, timestamp, 1.0 ); + engine.addNewSignal( s1.signalID, timestamp, 1.0 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); } -TEST_F( CollectionInspectionEngineTest, RequestTooMuchMemorySignals ) +TEST_F( CollectionInspectionEngineDoubleTest, RequestTooMuchMemorySignals ) { CollectionInspectionEngine engine; // for each of the .sampleBufferSize=1000000 multiple bytes have to be allocated @@ -1636,7 +1754,7 @@ TEST_F( CollectionInspectionEngineTest, RequestTooMuchMemorySignals ) engine.onChangeInspectionMatrix( consCollectionSchemes ); } -TEST_F( CollectionInspectionEngineTest, RequestTooMuchMemoryFrames ) +TEST_F( CollectionInspectionEngineDoubleTest, RequestTooMuchMemoryFrames ) { CollectionInspectionEngine engine; InspectionMatrixCanFrameCollectionInfo c1; @@ -1653,7 +1771,7 @@ TEST_F( CollectionInspectionEngineTest, RequestTooMuchMemoryFrames ) * This test is also used for performance analysis. The add new signal takes > 100ns * The performance varies if number of signal, number of conditions is changed. */ -TEST_F( CollectionInspectionEngineTest, RandomDataTest ) +TEST_F( CollectionInspectionEngineDoubleTest, RandomDataTest ) { const int NUMBER_OF_COLLECTION_SCHEMES = 200; const int NUMBER_OF_SIGNALS = 20000; @@ -1750,7 +1868,7 @@ TEST_F( CollectionInspectionEngineTest, RandomDataTest ) counter = 0; tickIncreased = true; } - engine.addNewSignal( signalIDGenerator( gen2 ), timestamp, normalDistribution( gen ) ); + engine.addNewSignal( signalIDGenerator( gen2 ), timestamp, normalDistribution( gen ) ); if ( tickIncreased ) { uint32_t waitTimeMs = 0; @@ -1767,7 +1885,7 @@ TEST_F( CollectionInspectionEngineTest, RandomDataTest ) << " collected data every second" << std::endl; } -TEST_F( CollectionInspectionEngineTest, NoCollectionSchemes ) +TEST_F( CollectionInspectionEngineDoubleTest, NoCollectionSchemes ) { CollectionInspectionEngine engine; TimePoint timestamp = { 160000000, 100 }; diff --git a/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp b/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp index 62da5af0..04313579 100644 --- a/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp +++ b/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionInspectionWorkerThread.h" +#include "WaitUntil.h" #include #include #include @@ -9,6 +10,7 @@ using namespace Aws::IoTFleetWise::DataInspection; using namespace Aws::IoTFleetWise::DataManagement; +using namespace Aws::IoTFleetWise::TestingSupport; class CollectionInspectionWorkerThreadTest : public ::testing::Test { @@ -100,7 +102,22 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectBurstWithoutSubsampling ) s1.sampleBufferSize = 50; s1.minimumSampleIntervalMs = 0; s1.fixedWindowPeriod = 77777; + s1.signalType = SignalType::DOUBLE; s1.isConditionOnlySignal = false; + InspectionMatrixSignalCollectionInfo s2{}; + s2.signalID = 2222; + s2.sampleBufferSize = 50; + s2.minimumSampleIntervalMs = 0; + s2.fixedWindowPeriod = 77777; + s2.signalType = SignalType::INT32; + s2.isConditionOnlySignal = false; + InspectionMatrixSignalCollectionInfo s3{}; + s3.signalID = 3333; + s3.sampleBufferSize = 50; + s3.minimumSampleIntervalMs = 0; + s3.fixedWindowPeriod = 77777; + s3.signalType = SignalType::BOOLEAN; + s3.isConditionOnlySignal = false; InspectionMatrixCanFrameCollectionInfo c1; c1.frameID = 0x380; c1.channelID = 3; @@ -109,9 +126,17 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectBurstWithoutSubsampling ) collectionSchemes->conditions[0].canFrames.push_back( c1 ); collectionSchemes->conditions[0].triggerOnlyOnRisingEdge = true; collectionSchemes->conditions[0].signals.push_back( s1 ); + collectionSchemes->conditions[0].signals.push_back( s2 ); + collectionSchemes->conditions[0].signals.push_back( s3 ); collectionSchemes->conditions[0].condition = getSignalsBiggerCondition( s1.signalID, 1 ).get(); worker.onChangeInspectionMatrix( consCollectionSchemes ); Timestamp timestamp = fClock->systemTimeSinceEpochMs(); + signalBufferPtr->push( CollectedSignal( s3.signalID, timestamp, 0, s3.signalType ) ); + signalBufferPtr->push( CollectedSignal( s3.signalID, timestamp, 1, s3.signalType ) ); + signalBufferPtr->push( CollectedSignal( s3.signalID, timestamp, 0, s3.signalType ) ); + signalBufferPtr->push( CollectedSignal( s2.signalID, timestamp, 10, s2.signalType ) ); + signalBufferPtr->push( CollectedSignal( s2.signalID, timestamp, 15, s2.signalType ) ); + signalBufferPtr->push( CollectedSignal( s2.signalID, timestamp, 20, s2.signalType ) ); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.1 ) ); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.2 ) ); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1.5 ) ); @@ -124,16 +149,22 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectBurstWithoutSubsampling ) worker.onNewDataAvailable(); - std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) ); - std::shared_ptr collectedData; - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + + ASSERT_EQ( collectedData->signals.size(), 9 ); - ASSERT_EQ( collectedData->signals.size(), 3 ); + EXPECT_EQ( collectedData->signals[0].value.value.doubleVal, 1.5 ); + EXPECT_EQ( collectedData->signals[1].value.value.doubleVal, 0.2 ); + EXPECT_EQ( collectedData->signals[2].value.value.doubleVal, 0.1 ); - EXPECT_EQ( collectedData->signals[0].value, 1.5 ); - EXPECT_EQ( collectedData->signals[1].value, 0.2 ); - EXPECT_EQ( collectedData->signals[2].value, 0.1 ); + EXPECT_EQ( collectedData->signals[3].value.value.int32Val, 20 ); + EXPECT_EQ( collectedData->signals[4].value.value.int32Val, 15 ); + EXPECT_EQ( collectedData->signals[5].value.value.int32Val, 10 ); + + EXPECT_EQ( collectedData->signals[6].value.value.boolVal, 0 ); + EXPECT_EQ( collectedData->signals[7].value.value.boolVal, 1 ); + EXPECT_EQ( collectedData->signals[8].value.value.boolVal, 0 ); ASSERT_EQ( collectedData->canFrames.size(), 3 ); @@ -174,10 +205,9 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectionQueueFull ) Timestamp timestamp = fClock->systemTimeSinceEpochMs(); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1 ) ); worker.onNewDataAvailable(); - std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); std::shared_ptr collectedData; - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); @@ -199,33 +229,27 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeDataWithoutNotify ) s1.isConditionOnlySignal = false; collectionSchemes->conditions[0].signals.push_back( s1 ); collectionSchemes->conditions[0].condition = getSignalsBiggerCondition( s1.signalID, 1 ).get(); + collectionSchemes->conditions[0].triggerOnlyOnRisingEdge = true; worker.onChangeInspectionMatrix( consCollectionSchemes ); Timestamp timestamp = fClock->systemTimeSinceEpochMs(); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); - - signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.1 ) ); - signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.2 ) ); - // this fulfills condition >1 so should trigger - signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1.5 ) ); - - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.1 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.2 ) ) ); + // // this fulfills condition >1 so should trigger + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1.5 ) ) ); std::shared_ptr collectedData; - ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); // After one second even without notifying data in the queue should be consumed - std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); - - ASSERT_EQ( collectedData->signals.size(), 3 ); + ASSERT_EQ( collectedData->signals.size(), 3U ); - EXPECT_EQ( collectedData->signals[0].value, 1.5 ); - EXPECT_EQ( collectedData->signals[1].value, 0.2 ); - EXPECT_EQ( collectedData->signals[2].value, 0.1 ); + EXPECT_EQ( collectedData->signals[0].value.value.doubleVal, 1.5 ); + EXPECT_EQ( collectedData->signals[1].value.value.doubleVal, 0.2 ); + EXPECT_EQ( collectedData->signals[2].value.value.doubleVal, 0.1 ); - ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); + DELAY_ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); worker.stop(); } @@ -257,22 +281,21 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH signal.isConditionOnlySignal = false; collectionSchemes->conditions[0].signals.push_back( signal ); collectionSchemes->conditions[0].condition = getSignalsBiggerCondition( signal.signalID, 1 ).get(); + collectionSchemes->conditions[0].triggerOnlyOnRisingEdge = true; // Make sure that DTCs should be collected collectionSchemes->conditions[0].includeActiveDtcs = true; inspectionWorker.onChangeInspectionMatrix( consCollectionSchemes ); Timestamp timestamp = fClock->systemTimeSinceEpochMs(); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); // Push the signals so that the condition is met - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ) ); + std::shared_ptr collectedData; - ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) ); + // Expect the data to be collected and has the DTCs - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_TRUE( collectedData->mDTCInfo.hasItems() ); ASSERT_EQ( collectedData->mDTCInfo.mSID, SID::STORED_DTC ); ASSERT_EQ( collectedData->mDTCInfo.mDTCCodes[0], "P0143" ); @@ -287,16 +310,14 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH // Push the DTCs to the buffer ASSERT_TRUE( activeDTCBufferPtr->push( dtcInfo ) ); timestamp = fClock->systemTimeSinceEpochMs(); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); // Push the signals so that the condition is met - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); - ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) ); + + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ) ); + // Expect the data to be collected and has the DTCs - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_TRUE( collectedData->mDTCInfo.hasItems() ); ASSERT_EQ( collectedData->mDTCInfo.mSID, SID::STORED_DTC ); ASSERT_EQ( collectedData->mDTCInfo.mDTCCodes[0], "B0148" ); @@ -336,17 +357,15 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH inspectionWorker.onChangeInspectionMatrix( consCollectionSchemes ); Timestamp timestamp = fClock->systemTimeSinceEpochMs(); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); // Push the signals so that the condition is met - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ); - signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.1 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 0.2 ) ) ); + ASSERT_TRUE( signalBufferPtr->push( CollectedSignal( signal.signalID, timestamp, 1.5 ) ) ); + std::shared_ptr collectedData; - ASSERT_FALSE( outputCollectedData->pop( collectedData ) ); - std::this_thread::sleep_for( std::chrono::milliseconds( 1000 ) ); + // Expect the data to be collected and has NO DTCs - ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); + WAIT_ASSERT_TRUE( outputCollectedData->pop( collectedData ) ); ASSERT_FALSE( collectedData->mDTCInfo.hasItems() ); inspectionWorker.stop(); diff --git a/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp b/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp index ef2942f8..0c951261 100644 --- a/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp +++ b/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp @@ -5,6 +5,7 @@ #include "DataOverDDSModule.h" #include "CollectionInspectionEngine.h" #include "Testing.h" +#include "WaitUntil.h" #include "dds/CameraDataPublisher.h" #include "dds/CameraDataSubscriber.h" #include "dds/DDSDataTypes.h" @@ -413,8 +414,8 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleInitAndConnectSuccessAndIsAliveSHM ASSERT_TRUE( testModule.init( configList ) ); ASSERT_TRUE( testModule.connect() ); // Give some time till the threads are warmed up - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - ASSERT_TRUE( testModule.isAlive() ); + + WAIT_ASSERT_TRUE( testModule.isAlive() ); ASSERT_TRUE( testModule.disconnect() ); } @@ -449,9 +450,9 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleInitAndConnectSuccessAndIsAliveUDP ASSERT_TRUE( testModule.init( configList ) ); ASSERT_TRUE( testModule.connect() ); // Give some time till the threads are warmed up - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // The module should be now alive - ASSERT_TRUE( testModule.isAlive() ); + WAIT_ASSERT_TRUE( testModule.isAlive() ); ASSERT_TRUE( testModule.disconnect() ); } @@ -487,8 +488,8 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleSendaRequest ) ASSERT_TRUE( testModule.init( configList ) ); ASSERT_TRUE( testModule.connect() ); // Give some time till the threads are warmed up - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - ASSERT_TRUE( testModule.isAlive() ); + + WAIT_ASSERT_TRUE( testModule.isAlive() ); // Create a notification about an event. // An event of ID 123 on sourceID 1, with 1 ms as positive and negative offsets std::vector mockedEvent; @@ -496,9 +497,9 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleSendaRequest ) // Notify the Module about this event testModule.onEventOfInterestDetected( mockedEvent ); // Wait a bit till the thread wakes up and sends the request over DDS to the Subscriber - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // Check that the same event has been propagated to the peer DDS Node - ASSERT_EQ( testSub.dataItem.dataItemId(), 123 ); + WAIT_ASSERT_EQ( testSub.dataItem.dataItemId(), 123U ); ASSERT_EQ( testSub.dataItem.negativeOffsetMs(), 1 ); ASSERT_EQ( testSub.dataItem.positiveOffsetMs(), 1 ); ASSERT_TRUE( testModule.disconnect() ); @@ -536,9 +537,9 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleSendaRequestReceiveResponse ) ASSERT_TRUE( testModule.init( configList ) ); ASSERT_TRUE( testModule.connect() ); // Give some time till the threads are warmed up - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // The module should be now alive - ASSERT_TRUE( testModule.isAlive() ); + WAIT_ASSERT_TRUE( testModule.isAlive() ); // Create a notification about an event. // An event of ID 123 on sourceID 1, with 1 ms as positive and negative offsets std::vector mockedEvent; @@ -546,17 +547,17 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleSendaRequestReceiveResponse ) // Notify the Module about this event testModule.onEventOfInterestDetected( mockedEvent ); // Wait a bit till the thread wakes up and sends the request over DDS to the Subscriber - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // Check that the same event has been propagated to the peer DDS Node - ASSERT_EQ( testSub.dataItem.dataItemId(), 123 ); + WAIT_ASSERT_EQ( testSub.dataItem.dataItemId(), 123U ); ASSERT_EQ( testSub.dataItem.negativeOffsetMs(), 1 ); ASSERT_EQ( testSub.dataItem.positiveOffsetMs(), 1 ); // Send a response from the DDS Node back. testPub.publishTestData( "123" ); // Give it some time till the artifact is received - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - ASSERT_TRUE( testModule.receivedArtifact ); - ASSERT_EQ( testModule.artifact.sourceID, config.sourceID ); + + WAIT_ASSERT_TRUE( testModule.receivedArtifact ); + WAIT_ASSERT_EQ( testModule.artifact.sourceID, config.sourceID ); ASSERT_EQ( testModule.artifact.path, config.temporaryCacheLocation + "123" ); ASSERT_TRUE( testModule.disconnect() ); } @@ -631,7 +632,7 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleReceiveNotificationFromInspectionE // we must have received a notification ASSERT_TRUE( testModule.receivedEvent ); // One event of size one should have been received - ASSERT_EQ( testModule.event.size(), 1 ); + WAIT_ASSERT_EQ( testModule.event.size(), 1U ); ASSERT_EQ( testModule.event[0].sourceID, config.sourceID ); // we need a total of condition.afterDuration + condition.imageCollectionInfo.beforeDurationMs // from the camera module. As we have yet to consolidate the Inspection Engine evaluate and diff --git a/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp b/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp index 45060e7d..6b0f76d0 100644 --- a/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp +++ b/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp @@ -3,6 +3,8 @@ #include "OBDOverCANModule.h" #include "OBDDataTypes.h" +#include "Testing.h" +#include "WaitUntil.h" #include "businterfaces/ISOTPOverCANReceiver.h" #include "datatypes/OBDDataTypesUnitTestOnly.h" #include @@ -15,9 +17,11 @@ #include using namespace Aws::IoTFleetWise::DataInspection; +using namespace Aws::IoTFleetWise::TestingSupport; namespace { +using SignalDoubleValue = double; // ECU ID mocked for unit test enum class ECU_ID_MOCK @@ -80,7 +84,7 @@ initInspectionMatrix( OBDOverCANModule &module ) // Note In actual product, decoder dictionary comes from decoder manifest. For this unit test, // The decoder dictionary is initialized based on a local table mode1PIDs in OBDDataDecoder Module. std::shared_ptr -initDecoderDictionary() +initDecoderDictionary( SignalType signalType = SignalType::DOUBLE ) { auto decoderDictPtr = std::make_shared(); decoderDictPtr->canMessageDecoderMethod.emplace( 0, std::unordered_map() ); @@ -103,6 +107,7 @@ initDecoderDictionary() ( pidInfo.formulas[idx].numOfBytes - 1 ) * BYTE_SIZE + pidInfo.formulas[idx].bitMaskLen ); format.mSignals[idx].mFactor = pidInfo.formulas[idx].scaling; format.mSignals[idx].mOffset = pidInfo.formulas[idx].offset; + format.mSignals[idx].mSignalType = signalType; decoderDictPtr->signalIDsToCollect.insert( pid | ( idx << 8 ) ); } decoderDictPtr->canMessageDecoderMethod[0].emplace( pid, CANMessageDecoderMethod() ); @@ -241,6 +246,51 @@ class OBDOverCANModuleTest : public ::testing::Test std::shared_ptr signalBufferPtr; std::shared_ptr activeDTCBufferPtr; std::vector ecus; + + void + assertSignalValue( const SignalValueWrapper &signalValueWrapper, + double expectedSignalValue, + SignalType expectedSignalType ) + { + switch ( expectedSignalType ) + { + case SignalType::UINT8: + ASSERT_EQ( signalValueWrapper.value.uint8Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::INT8: + ASSERT_EQ( signalValueWrapper.value.int8Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT16: + ASSERT_EQ( signalValueWrapper.value.uint16Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::INT16: + ASSERT_EQ( signalValueWrapper.value.int16Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT32: + ASSERT_EQ( signalValueWrapper.value.uint32Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::INT32: + ASSERT_EQ( signalValueWrapper.value.int32Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::UINT64: + ASSERT_EQ( signalValueWrapper.value.uint64Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::INT64: + ASSERT_EQ( signalValueWrapper.value.int64Val, static_cast( expectedSignalValue ) ); + break; + case SignalType::FLOAT: + ASSERT_FLOAT_EQ( signalValueWrapper.value.floatVal, static_cast( expectedSignalValue ) ); + break; + case SignalType::DOUBLE: + ASSERT_DOUBLE_EQ( signalValueWrapper.value.doubleVal, static_cast( expectedSignalValue ) ); + break; + case SignalType::BOOLEAN: + ASSERT_EQ( signalValueWrapper.value.boolVal, static_cast( expectedSignalValue ) ); + break; + default: + FAIL() << "Unsupported signal type"; + } + } }; TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitFailure ) @@ -253,8 +303,8 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitFailure ) TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitTestSuccess ) { - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds - constexpr uint32_t obdDTCRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second + constexpr uint32_t obdDTCRequestInterval = 1; // 1 seconds ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); @@ -278,7 +328,7 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleAndDecoderManifestLifecycle ) // Then later we activate a decoder manifest and we should see the module sending // requests on the bus std::vector ecmRxPDUData; - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 2; // 2 seconds ISOTPOverCANSenderReceiver engineECU; @@ -300,8 +350,16 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleAndDecoderManifestLifecycle ) ASSERT_TRUE( obdModule.disconnect() ); } -TEST_F( OBDOverCANModuleTest, RequestPIDFromNotExtendedIDECUTest ) +class OBDOverCANModuleTestWithAllSignalTypes : public OBDOverCANModuleTest, + public testing::WithParamInterface { +}; + +INSTANTIATE_TEST_SUITE_P( MultipleSignals, OBDOverCANModuleTestWithAllSignalTypes, allSignalTypes, signalTypeToString ); + +TEST_P( OBDOverCANModuleTestWithAllSignalTypes, RequestPIDFromNotExtendedIDECUTest ) +{ + SignalType signalType = GetParam(); // Setup ECU Mock ecus = std::vector( 2 ); @@ -309,7 +367,7 @@ TEST_F( OBDOverCANModuleTest, RequestPIDFromNotExtendedIDECUTest ) ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; ecus[0].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; ecus[0].mRequestPID1 = { 0x01, 0x04, 0x05 }; - ecus[0].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x05, 0x6E }; + ecus[0].mPIDResponse1 = { 0x41, 0x04, 0x90, 0x05, 0x6E }; ecus[0].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; ecus[0].mThread.create( ecuResponse, &ecus[0] ); @@ -322,30 +380,29 @@ TEST_F( OBDOverCANModuleTest, RequestPIDFromNotExtendedIDECUTest ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds and no DTC request - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // Create decoder dictionary - auto decoderDictPtr = initDecoderDictionary(); + auto decoderDictPtr = initDecoderDictionary( signalType ); // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + 4 ) ); // Expected value for PID signals - std::map expectedPIDSignalValue = { - { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, + std::map expectedPIDSignalValue = { + { toUType( EmissionPIDs::ENGINE_LOAD ), 56.470588235294116 }, { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 70 }, { toUType( EmissionPIDs::VEHICLE_SPEED ), 35 } }; // Verify all PID Signals are correctly decoded CollectedSignal signal; - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + assertSignalValue( signal.value, expectedPIDSignalValue[signal.signalID], signalType ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + assertSignalValue( signal.value, expectedPIDSignalValue[signal.signalID], signalType ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + assertSignalValue( signal.value, expectedPIDSignalValue[signal.signalID], signalType ); } // This test is to validate that OBDOverCANModule will only request PID that are specified in Decoder Dictionary @@ -375,7 +432,7 @@ TEST_F( OBDOverCANModuleTest, RequestPartialPIDFromNotExtendedIDECUTest ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds and no DTC request - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); @@ -394,10 +451,9 @@ TEST_F( OBDOverCANModuleTest, RequestPartialPIDFromNotExtendedIDECUTest ) decoderDictPtr->signalIDsToCollect.insert( 0xC1 ); // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + 2 ) ); // Expected value for PID signals - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::OXYGEN_SENSOR1_1 ) | 0 << 8, (double)0x10 / 200 }, { toUType( EmissionPIDs::OXYGEN_SENSOR1_1 ) | 1 << 8, (double)0x20 * 100 / 128 - 100 }, @@ -407,8 +463,8 @@ TEST_F( OBDOverCANModuleTest, RequestPartialPIDFromNotExtendedIDECUTest ) CollectedSignal signal; for ( size_t idx = 0; idx < expectedPIDSignalValue.size(); ++idx ) { - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); } ASSERT_TRUE( obdModule.getSignalBufferPtr()->empty() ); } @@ -445,7 +501,7 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds and no DTC request - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); @@ -464,10 +520,9 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) decoderDictPtr->signalIDsToCollect.insert( 0xC1 ); // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + 4 ) ); // Expected value for PID signals - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::OXYGEN_SENSOR1_1 ) | 0 << 8, (double)0x10 / 200 }, { toUType( EmissionPIDs::OXYGEN_SENSOR1_1 ) | 1 << 8, (double)0x20 * 100 / 128 - 100 }, @@ -477,8 +532,8 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) CollectedSignal signal; for ( size_t idx = 0; idx < expectedPIDSignalValue.size(); ++idx ) { - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); } ASSERT_TRUE( obdModule.getSignalBufferPtr()->empty() ); @@ -490,7 +545,6 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) decoderDictPtr->signalIDsToCollect.insert( 0x0E ); // publish the new decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval ) ); expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 36 }, { toUType( EmissionPIDs::OXYGEN_SENSOR1_1 ) | 0 << 8, (double)0x10 / 200 }, @@ -500,8 +554,8 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) // Verify all PID Signals are correctly decoded for ( size_t idx = 0; idx < expectedPIDSignalValue.size(); ++idx ) { - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); } ASSERT_TRUE( obdModule.getSignalBufferPtr()->empty() ); @@ -545,9 +599,8 @@ TEST_F( OBDOverCANModuleTest, RequestEmissionPIDAndDTCFromExtendedIDECUTest ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds, and DTCs every 2 seconds - constexpr uint32_t startupTime = 4; // 4 seconds - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds - constexpr uint32_t obdDTCRequestInterval = 2; // Request DTC every 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second + constexpr uint32_t obdDTCRequestInterval = 1; // Request DTC every 1 seconds ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); @@ -557,28 +610,27 @@ TEST_F( OBDOverCANModuleTest, RequestEmissionPIDAndDTCFromExtendedIDECUTest ) // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); initInspectionMatrix( obdModule ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + startupTime ) ); // This is the expected value for PID signals. - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 70 }, { toUType( EmissionPIDs::VEHICLE_SPEED ), 35 }, { 0xC1, 0xAA } }; // Verify produced PID signals are correctly decoded CollectedSignal signal; - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); // Verify produced DTC Buffer is correct. 4 codes for ECM , 0 codes for TCM DTCInfo dtcInfo; - ASSERT_TRUE( obdModule.getActiveDTCBufferPtr()->pop( dtcInfo ) ); + WAIT_ASSERT_TRUE( obdModule.getActiveDTCBufferPtr()->pop( dtcInfo ) ); ASSERT_EQ( dtcInfo.mDTCCodes.size(), 4 ); ASSERT_EQ( dtcInfo.mSID, SID::STORED_DTC ); ASSERT_EQ( dtcInfo.mDTCCodes[0], "P0143" ); @@ -609,9 +661,8 @@ TEST_F( OBDOverCANModuleTest, RequestPIDAndDTCFromNonExtendedIDECUTest ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds, and DTCs every 2 seconds - constexpr uint32_t startupTime = 4; // 4 seconds - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds - constexpr uint32_t obdDTCRequestInterval = 2; // Request DTC every 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second + constexpr uint32_t obdDTCRequestInterval = 1; // Request DTC every 1 seconds ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); @@ -620,28 +671,27 @@ TEST_F( OBDOverCANModuleTest, RequestPIDAndDTCFromNonExtendedIDECUTest ) // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); initInspectionMatrix( obdModule ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + startupTime ) ); // This is the expected value for PID signals. - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 70 }, { toUType( EmissionPIDs::VEHICLE_SPEED ), 35 }, { 0xC1, 0xAA } }; // Verify produced PID signals are correctly decoded CollectedSignal signal; - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); // Verify produced DTC Buffer is correct. 4 codes for ECM , 0 codes for TCM DTCInfo dtcInfo; - ASSERT_TRUE( obdModule.getActiveDTCBufferPtr()->pop( dtcInfo ) ); + WAIT_ASSERT_TRUE( obdModule.getActiveDTCBufferPtr()->pop( dtcInfo ) ); ASSERT_EQ( dtcInfo.mDTCCodes.size(), 4 ); ASSERT_EQ( dtcInfo.mSID, SID::STORED_DTC ); ASSERT_EQ( dtcInfo.mDTCCodes[0], "P0143" ); @@ -672,7 +722,7 @@ TEST_F( OBDOverCANModuleTest, BroadcastRequestsStandardIDs ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds and no DTC request - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, true ) ); @@ -681,21 +731,20 @@ TEST_F( OBDOverCANModuleTest, BroadcastRequestsStandardIDs ) auto decoderDictPtr = initDecoderDictionary(); // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + 4 ) ); // Expected value for PID signals - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 70 }, { toUType( EmissionPIDs::VEHICLE_SPEED ), 35 } }; // Verify all PID Signals are correctly decoded CollectedSignal signal; - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); } TEST_F( OBDOverCANModuleTest, BroadcastRequestsExtendedIDs ) @@ -723,7 +772,7 @@ TEST_F( OBDOverCANModuleTest, BroadcastRequestsExtendedIDs ) ecus[1].mThread.create( ecuResponse, &ecus[1] ); // Request PIDs every 2 seconds and no DTC request - constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds + constexpr uint32_t obdPIDRequestInterval = 1; // 1 second constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request ASSERT_TRUE( obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, true ) ); @@ -732,19 +781,18 @@ TEST_F( OBDOverCANModuleTest, BroadcastRequestsExtendedIDs ) auto decoderDictPtr = initDecoderDictionary(); // publish decoder dictionary to OBD module obdModule.onChangeOfActiveDictionary( decoderDictPtr, VehicleDataSourceProtocol::OBD ); - std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval + 4 ) ); // Expected value for PID signals - std::map expectedPIDSignalValue = { + std::map expectedPIDSignalValue = { { toUType( EmissionPIDs::ENGINE_LOAD ), 60 }, { toUType( EmissionPIDs::ENGINE_COOLANT_TEMPERATURE ), 70 }, { toUType( EmissionPIDs::VEHICLE_SPEED ), 35 } }; // Verify all PID Signals are correctly decoded CollectedSignal signal; - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); - ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); - ASSERT_DOUBLE_EQ( signal.value, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); + WAIT_ASSERT_TRUE( obdModule.getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( signal.value.value.doubleVal, expectedPIDSignalValue[signal.signalID] ); } diff --git a/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp b/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp index e948cbe7..d79b8920 100644 --- a/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp +++ b/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp @@ -7,6 +7,7 @@ #include "IActiveDecoderDictionaryListener.h" #include "Signal.h" #include "Thread.h" +#include "WaitUntil.h" #include "businterfaces/CANDataSource.h" #include #include @@ -24,6 +25,7 @@ using namespace Aws::IoTFleetWise::DataInspection; using namespace Aws::IoTFleetWise::VehicleNetwork; using namespace Aws::IoTFleetWise::DataManagement; using namespace Aws::IoTFleetWise::Platform::Linux; +using namespace Aws::IoTFleetWise::TestingSupport; static int setup() @@ -450,7 +452,7 @@ class VehicleDataSourceBinderTest : public ::testing::Test VehicleDataSourceConfig canSourceConfig; canSourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); canSourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - canSourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + canSourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); canSourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector canSourceConfigs = { canSourceConfig }; canSourcePtr = std::make_shared(); @@ -466,8 +468,8 @@ class VehicleDataSourceBinderTest : public ::testing::Test canConsumerPtr = std::make_shared(); canConsumerPtr2 = std::make_shared(); - ASSERT_TRUE( canConsumerPtr->init( 0, canSignalBufferPtr, 1000 ) ); - ASSERT_TRUE( canConsumerPtr2->init( 1, canSignalBufferPtr, 1000 ) ); + ASSERT_TRUE( canConsumerPtr->init( 0, canSignalBufferPtr, 100 ) ); + ASSERT_TRUE( canConsumerPtr2->init( 1, canSignalBufferPtr, 100 ) ); canConsumerPtr->setCANBufferPtr( canRawBufferPtr ); canConsumerPtr2->setCANBufferPtr( canRawBufferPtr ); ASSERT_TRUE( binder.connect() ); @@ -497,22 +499,24 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectCANFrame binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify raw CAN Frames are collected correctly CollectedCanRawFrame rawCANMsg; - ASSERT_TRUE( canConsumerPtr->getCANBufferPtr()->pop( rawCANMsg ) ); + struct can_frame frame = {}; + auto sendAndPop = [&] { + sendTestMessage( socketFD, frame ); + return canConsumerPtr->getCANBufferPtr()->pop( rawCANMsg ); + }; + WAIT_ASSERT_TRUE( sendAndPop() ); ASSERT_EQ( 8, rawCANMsg.size ); for ( int i = 0; i < rawCANMsg.size; ++i ) { ASSERT_EQ( frame.data[i], rawCANMsg.data[i] ); } - ASSERT_TRUE( canConsumerPtr2->getCANBufferPtr()->pop( rawCANMsg ) ); + auto sendAndPop2 = [&] { + sendTestMessage( socketFD, frame ); + return canConsumerPtr2->getCANBufferPtr()->pop( rawCANMsg ); + }; + WAIT_ASSERT_TRUE( sendAndPop2() ); ASSERT_EQ( 8, rawCANMsg.size ); for ( int i = 0; i < rawCANMsg.size; ++i ) { @@ -529,21 +533,24 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectSelectedS binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify signals are decoded and collected correctly CollectedSignal signal; - ASSERT_TRUE( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ); + auto sendAndPop = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumerPtr->getSignalBufferPtr()->pop( signal ); + }; + WAIT_ASSERT_TRUE( sendAndPop() ); ASSERT_EQ( 0x123, signal.signalID ); - ASSERT_DOUBLE_EQ( 0x0804, signal.value ); - ASSERT_TRUE( canConsumerPtr2->getSignalBufferPtr()->pop( signal ) ); + ASSERT_DOUBLE_EQ( 0x0804, signal.value.value.doubleVal ); + auto sendAndPop2 = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumerPtr2->getSignalBufferPtr()->pop( signal ); + }; + WAIT_ASSERT_TRUE( sendAndPop2() ); ASSERT_EQ( 0x123, signal.signalID ); - ASSERT_DOUBLE_EQ( 0x0804, signal.value ); + ASSERT_DOUBLE_EQ( 0x0804, signal.value.value.doubleVal ); } /** @brief In this test, no signals in the CAN Frame will be collected based on decoder dictionary @@ -554,17 +561,20 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestNotCollectSignal binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify NO signals are decoded and collected based on decoder dictionary CollectedSignal signal; - ASSERT_FALSE( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ); - ASSERT_FALSE( canConsumerPtr2->getSignalBufferPtr()->pop( signal ) ); + auto sendAndPop = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumerPtr->getSignalBufferPtr()->pop( signal ); + }; + DELAY_ASSERT_FALSE( sendAndPop() ); + auto sendAndPop2 = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumerPtr2->getSignalBufferPtr()->pop( signal ); + }; + DELAY_ASSERT_FALSE( sendAndPop2() ); } /** @brief In this test, only one signal from the CAN Frame to @@ -576,31 +586,19 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectSignalBuf binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - - auto f = []( int socketFD, struct can_frame frame, int msgCnt ) { - for ( int i = 0; i < msgCnt; ++i ) + // Verify signals are decoded and collected correctly + std::unordered_map collectedSignals; + auto sendPopAndGetCollectedSize = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + CollectedSignal signal; + if ( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ) { - sendTestMessage( socketFD, frame ); + collectedSignals[signal.signalID] = signal.value.value.doubleVal; } + return collectedSignals.size(); }; - - std::thread canMessageThread( f, socketFD, frame, 1 ); - canMessageThread.join(); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - - // Verify signals are decoded and collected correctly - std::unordered_map collectedSignals; - CollectedSignal signal; - while ( !canConsumerPtr->getSignalBufferPtr()->empty() ) - { - canConsumerPtr->getSignalBufferPtr()->pop( signal ); - collectedSignals[signal.signalID] = signal.value; - } - ASSERT_EQ( 2, collectedSignals.size() ); + WAIT_ASSERT_EQ( 2U, sendPopAndGetCollectedSize() ); ASSERT_EQ( 1, collectedSignals.count( 0x111 ) ); ASSERT_EQ( 1, collectedSignals.count( 0x528 ) ); if ( collectedSignals.count( 0x111 ) > 0 ) @@ -622,22 +620,19 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectSignalBuf binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify signals are decoded and collected correctly std::unordered_map collectedSignals; - CollectedSignal signal; - while ( !canConsumerPtr->getSignalBufferPtr()->empty() ) - { - canConsumerPtr->getSignalBufferPtr()->pop( signal ); - collectedSignals[signal.signalID] = signal.value; - } - ASSERT_EQ( 4, collectedSignals.size() ); + auto sendPopAndGetCollectedSize = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + CollectedSignal signal; + if ( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ) + { + collectedSignals[signal.signalID] = signal.value.value.doubleVal; + } + return collectedSignals.size(); + }; + WAIT_ASSERT_EQ( 4U, sendPopAndGetCollectedSize() ); ASSERT_EQ( 1, collectedSignals.count( 0x111 ) ); ASSERT_EQ( 0x0040, collectedSignals[0x111] ); ASSERT_EQ( 1, collectedSignals.count( 0x528 ) ); @@ -657,22 +652,19 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectSignalBuf binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify signals are decoded and collected correctly std::unordered_map collectedSignals; - CollectedSignal signal; - while ( !canConsumerPtr->getSignalBufferPtr()->empty() ) - { - canConsumerPtr->getSignalBufferPtr()->pop( signal ); - collectedSignals[signal.signalID] = signal.value; - } - ASSERT_EQ( 4, collectedSignals.size() ); + struct can_frame frame = {}; + auto sendPopAndGetCollectedSize = [&] { + sendTestMessage( socketFD, frame ); + CollectedSignal signal; + if ( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ) + { + collectedSignals[signal.signalID] = signal.value.value.doubleVal; + } + return collectedSignals.size(); + }; + WAIT_ASSERT_EQ( 4U, sendPopAndGetCollectedSize() ); ASSERT_EQ( 1, collectedSignals.count( 0x111 ) ); ASSERT_EQ( 0x0040, collectedSignals[0x111] ); ASSERT_EQ( 1, collectedSignals.count( 0x528 ) ); @@ -708,22 +700,19 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestCollectSignalBuf binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); - struct can_frame frame = {}; - sendTestExtendedIdMessage( socketFD, frame ); - // Sleep for sometime on this thread to allow the other thread to finish - // As SocketCanBusChannel and CANDataConsumer wait 1 second we must - // wait more than 2 seconds here - std::this_thread::sleep_for( std::chrono::seconds( 3 ) ); - // Verify signals are decoded and collected correctly std::unordered_map collectedSignals; - CollectedSignal signal; - while ( !canConsumerPtr->getSignalBufferPtr()->empty() ) - { - canConsumerPtr->getSignalBufferPtr()->pop( signal ); - collectedSignals[signal.signalID] = signal.value; - } - ASSERT_EQ( 4, collectedSignals.size() ); + struct can_frame frame = {}; + auto sendPopAndGetCollectedSize = [&] { + sendTestExtendedIdMessage( socketFD, frame ); + CollectedSignal signal; + if ( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ) + { + collectedSignals[signal.signalID] = signal.value.value.doubleVal; + } + return collectedSignals.size(); + }; + WAIT_ASSERT_EQ( 4U, sendPopAndGetCollectedSize() ); ASSERT_EQ( 1, collectedSignals.count( 0x111 ) ); ASSERT_EQ( 0x0040, collectedSignals[0x111] ); ASSERT_EQ( 1, collectedSignals.count( 0x528 ) ); @@ -771,18 +760,21 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestChangeDecoderDic // update dictionary while thread is still busy decoding. This test check whether Vehicle Data // Consumer can gracefully handle such multi thread scenario. binder.onChangeOfActiveDictionary( canDictionarySharedPtr, VehicleDataSourceProtocol::RAW_SOCKET ); + canMessageThread.join(); - std::this_thread::sleep_for( std::chrono::seconds( 4 ) ); // Verify signals are decoded and collected correctly std::unordered_map collectedSignals; - CollectedSignal signal; - while ( !canConsumerPtr->getSignalBufferPtr()->empty() ) - { - canConsumerPtr->getSignalBufferPtr()->pop( signal ); - collectedSignals[signal.signalID] = signal.value; - } - // make sure we still receive the two signals. - ASSERT_EQ( 2, collectedSignals.size() ); + auto sendPopAndGetCollectedSize = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + CollectedSignal signal; + if ( canConsumerPtr->getSignalBufferPtr()->pop( signal ) ) + { + collectedSignals[signal.signalID] = signal.value.value.doubleVal; + } + return collectedSignals.size(); + }; + WAIT_ASSERT_EQ( 2U, sendPopAndGetCollectedSize() ); ASSERT_EQ( 1, collectedSignals.count( 0x111 ) ); ASSERT_EQ( 1, collectedSignals.count( 0x528 ) ); if ( collectedSignals.count( 0x111 ) > 0 ) @@ -803,28 +795,18 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderTestDiscardInputBuff { // set decoder dictionary as invalid binder.onChangeOfActiveDictionary( nullptr, VehicleDataSourceProtocol::RAW_SOCKET ); - // give one second for all producer and consumer to shut down - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - struct can_frame frame = {}; - auto f = []( int socketFD, struct can_frame frame, int msgCnt ) { - for ( int i = 0; i < msgCnt; ++i ) - { - sendTestMessage( socketFD, frame ); - } - }; - // Create a separate thread to send 8 CAN Frames - std::thread canMessageThread( f, socketFD, frame, 8 ); - // Wait until thread complete. - canMessageThread.join(); - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // Verify no signals were collected due to missing decoder dictionary - ASSERT_TRUE( canConsumerPtr->getSignalBufferPtr()->empty() ); + auto sendAndCheckConsumerEmpty = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumerPtr->getSignalBufferPtr()->empty(); + }; + DELAY_ASSERT_TRUE( sendAndCheckConsumerEmpty() ); // Now we provide Vehicle Data Binder a valid decoder dictionary binder.onChangeOfActiveDictionary( std::make_shared( generateDecoderDictionary4() ), VehicleDataSourceProtocol::RAW_SOCKET ); - // As the network channels just woken up and the consumer input queue is empty, we should still - // expect empty output queue - ASSERT_TRUE( canConsumerPtr->getSignalBufferPtr()->empty() ); + WAIT_ASSERT_FALSE( sendAndCheckConsumerEmpty() ); } /** @brief In this test, we validate the startup and the shutdown APIs. @@ -841,7 +823,7 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderStartupAndShutdownCy VehicleDataSourceConfig canSourceConfig; canSourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); canSourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - canSourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + canSourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); canSourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector canSourceConfigs = { canSourceConfig }; ASSERT_TRUE( canSource->init( canSourceConfigs ) ); @@ -853,7 +835,7 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderStartupAndShutdownCy canConsumer = std::make_shared(); - ASSERT_TRUE( canConsumer->init( 0, signalBufferPtr, 1000 ) ); + ASSERT_TRUE( canConsumer->init( 0, signalBufferPtr, 100 ) ); canConsumer->setCANBufferPtr( canRawBufferPtr ); ASSERT_TRUE( networkBinder.connect() ); ASSERT_TRUE( networkBinder.addVehicleDataSource( canSource ) ); @@ -861,27 +843,30 @@ TEST_F( VehicleDataSourceBinderTest, VehicleDataSourceBinderStartupAndShutdownCy // Initially Channels and Consumers should be running but in a sleep mode // We send few messages on the bus and check that they are neither consumed // by the Channel nor by the consumer - struct can_frame frame = {}; - sendTestMessage( socketFD, frame ); - // Sleep to accommodate the polling frequency of the threads. - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - ASSERT_TRUE( canSource->getBuffer()->empty() ); - ASSERT_TRUE( canConsumer->getCANBufferPtr()->empty() ); + auto sendAndCheckSourceEmpty = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canSource->getBuffer()->empty(); + }; + DELAY_ASSERT_TRUE( sendAndCheckSourceEmpty() ); + auto sendAndCheckConsumerEmpty = [&] { + struct can_frame frame = {}; + sendTestMessage( socketFD, frame ); + return canConsumer->getCANBufferPtr()->empty(); + }; + DELAY_ASSERT_TRUE( sendAndCheckConsumerEmpty() ); // Pass a null decoder manifest, and check that both the channel and the consumer // are still sleeping. binder.onChangeOfActiveDictionary( nullptr, VehicleDataSourceProtocol::RAW_SOCKET ); - sendTestMessage( socketFD, frame ); - // Sleep to accommodate the polling frequency of the threads. - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); - ASSERT_TRUE( canSource->getBuffer()->empty() ); - ASSERT_TRUE( canConsumer->getCANBufferPtr()->empty() ); + + DELAY_ASSERT_TRUE( sendAndCheckSourceEmpty() ); + DELAY_ASSERT_TRUE( sendAndCheckConsumerEmpty() ); // Pass a correct decoder Manifest and Make sure that channel and consumer // consumed the data. dictionary = std::make_shared( generateDecoderDictionary1() ); networkBinder.onChangeOfActiveDictionary( dictionary, VehicleDataSourceProtocol::RAW_SOCKET ); - std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); - sendTestMessage( socketFD, frame ); - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); - ASSERT_FALSE( canConsumer->getCANBufferPtr()->empty() ); + + WAIT_ASSERT_FALSE( sendAndCheckSourceEmpty() ); + WAIT_ASSERT_FALSE( sendAndCheckConsumerEmpty() ); ASSERT_TRUE( networkBinder.disconnect() ); } diff --git a/src/datamanagement/datainspection/test/valgrind.supp b/src/datamanagement/datainspection/test/valgrind.supp index 17d9a8d5..fb93ef2c 100644 --- a/src/datamanagement/datainspection/test/valgrind.supp +++ b/src/datamanagement/datainspection/test/valgrind.supp @@ -30,3 +30,12 @@ fun:*add_persistence_guid* ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/datamanagement/datamanager/include/CollectionSchemeManager.h b/src/datamanagement/datamanager/include/CollectionSchemeManager.h index bf47d5bf..ddb99d09 100644 --- a/src/datamanagement/datamanager/include/CollectionSchemeManager.h +++ b/src/datamanagement/datamanager/include/CollectionSchemeManager.h @@ -13,7 +13,6 @@ #include "ICollectionSchemeManager.h" #include "IDecoderManifest.h" #include "Listener.h" -#include "LoggingModule.h" #include "SchemaListener.h" #include "Signal.h" #include "Thread.h" @@ -198,10 +197,10 @@ class CollectionSchemeManager : public ICollectionSchemeManager, */ static void doWork( void *data ); - TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); + static TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); /** - * @brief template function for generate a message on an event for mLogger usage + * @brief template function for generate a message on an event for logging * Include Event printed in string msg, collectionScheme ID, startTime, stopTime of the collectionScheme, and * current timestamp all in seconds. * @param msg string for log; @@ -217,7 +216,7 @@ class CollectionSchemeManager : public ICollectionSchemeManager, const TimePoint &currTime ); /** - * @brief supporting function for mLogger + * @brief supporting function for logging * Prints out enabled CollectionScheme ID string and Idle CollectionScheme ID string * @param enableStr string for enabled CollectionScheme IDs; * @param idleStr string for Idle CollectionScheme IDs; @@ -225,7 +224,7 @@ class CollectionSchemeManager : public ICollectionSchemeManager, void printExistingCollectionSchemes( std::string &enableStr, std::string &idleStr ); /** - * @brief supporting function for mLogger + * @brief supporting function for logging * Prints status when main thread wakes up from notification or timer return. * The status includes flag mUpdateAvailable, and currTime in seconds. * @param wakeupStr string to print status; @@ -310,7 +309,7 @@ class CollectionSchemeManager : public ICollectionSchemeManager, static const std::string CHECKIN; // Supported Network Protocol. This list will expand when new protocol added static constexpr std::array SUPPORTED_NETWORK_PROTOCOL = { - VehicleDataSourceProtocol::RAW_SOCKET, VehicleDataSourceProtocol::OBD }; + { VehicleDataSourceProtocol::RAW_SOCKET, VehicleDataSourceProtocol::OBD } }; Thread mThread; // Atomic flag to signal the state of main thread. If true, we should stop @@ -321,7 +320,6 @@ class CollectionSchemeManager : public ICollectionSchemeManager, // Platform signal that wakes up main thread Platform::Linux::Signal mWait; std::shared_ptr mClock = ClockHandler::getClock(); - LoggingModule mLogger; // Shared pointer to a SchemaListener Object allow CollectionSchemeManagement to send data to Schema SchemaListenerPtr mSchemaListenerPtr; @@ -338,6 +336,13 @@ class CollectionSchemeManager : public ICollectionSchemeManager, // Time interval in ms to send checkin message uint64_t mCheckinIntervalInMsec{ DEFAULT_CHECKIN_INTERVAL_IN_MILLISECOND }; + // Get the Signal Type from DM + inline SignalType + getSignalType( const SignalID signalID ) + { + return mDecoderManifest->getSignalType( signalID ); + } + protected: /* * PM Local storage of CollectionSchemeList and mDecoderManifest so that PM can work on these objects diff --git a/src/datamanagement/datamanager/include/Schema.h b/src/datamanagement/datamanager/include/Schema.h index f97aa6f4..d4da0421 100644 --- a/src/datamanagement/datamanager/include/Schema.h +++ b/src/datamanagement/datamanager/include/Schema.h @@ -87,18 +87,15 @@ class Schema : public ThreadListeners, publi */ struct DecoderManifestCb : IReceiverCallback { - LoggingModule &mLogger; //< Logger used to allow the callback to publish a log - Schema &mSchema; //< Member variable to the Schema object which will receive the data + Schema &mSchema; //< Member variable to the Schema object which will receive the data /** * @brief Constructor that will initialize the member variables * * @param collectionSchemeIngestion Reference to a Schema object which allow this struct to pass data to - * @param logger Logger object allowing logs to be published by this struct */ - DecoderManifestCb( Schema &collectionSchemeIngestion, LoggingModule &logger ) - : mLogger( logger ) - , mSchema( collectionSchemeIngestion ) + DecoderManifestCb( Schema &collectionSchemeIngestion ) + : mSchema( collectionSchemeIngestion ) { } @@ -108,8 +105,7 @@ class Schema : public ThreadListeners, publi // Check for a empty input data if ( ( buf == nullptr ) || ( size == 0 ) ) { - mLogger.error( "DecoderManifestCb::onDataReceived", - "Received empty CollectionScheme List data from Cloud" ); + FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); return; } @@ -119,13 +115,13 @@ class Schema : public ThreadListeners, publi // Try to copy the binary data into the decoderManifest object if ( !decoderManifestPtr->copyData( buf, size ) ) { - mLogger.error( "DecoderManifestCb::onDataReceived", "DecoderManifest copyData from IoT core failed" ); + FWE_LOG_ERROR( "DecoderManifest copyData from IoT core failed" ); return; } // Successful copy, so we cache the decoderManifest in the Schema object mSchema.setDecoderManifest( decoderManifestPtr ); - mLogger.trace( "DecoderManifestCb::onDataReceived", "Received Decoder Manifest in PI DecoderManifestCb" ); + FWE_LOG_TRACE( "Received Decoder Manifest in PI DecoderManifestCb" ); } } mDecoderManifestCb; @@ -135,18 +131,15 @@ class Schema : public ThreadListeners, publi */ struct CollectionSchemeListCb : IReceiverCallback { - LoggingModule &mLogger; //< Logger used to allow the callback to publish a log - Schema &mSchema; //< Member variable to the Schema object which will receive the data + Schema &mSchema; //< Member variable to the Schema object which will receive the data /** * @brief Constructor that will initialize the member variables * * @param collectionSchemeIngestion Reference to a Schema object which allow this struct to pass data to - * @param logger Logger object allowing logs to be published by this struct */ - CollectionSchemeListCb( Schema &collectionSchemeIngestion, LoggingModule &logger ) - : mLogger( logger ) - , mSchema( collectionSchemeIngestion ) + CollectionSchemeListCb( Schema &collectionSchemeIngestion ) + : mSchema( collectionSchemeIngestion ) { } @@ -156,8 +149,7 @@ class Schema : public ThreadListeners, publi // Check for a empty input data if ( ( buf == nullptr ) || ( size == 0 ) ) { - mLogger.error( "DecoderManifestCb::onDataReceived", - "Received empty CollectionScheme List data from Cloud" ); + FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); return; } @@ -167,23 +159,17 @@ class Schema : public ThreadListeners, publi // Try to copy the binary data into the collectionSchemeList object if ( !collectionSchemeListPtr->copyData( buf, size ) ) { - mLogger.error( "DecoderManifestCb::onDataReceived", - "CollectionSchemeList copyData from IoT core failed" ); + FWE_LOG_ERROR( "CollectionSchemeList copyData from IoT core failed" ); return; } // Successful copy, so we cache the collectionSchemeList in the Schema object mSchema.setCollectionSchemeList( collectionSchemeListPtr ); - mLogger.trace( "CollectionSchemeListCb::onDataReceived", "Received CollectionSchemeList" ); + FWE_LOG_TRACE( "Received CollectionSchemeList" ); } } mCollectionSchemeListCb; private: - /** - * @brief Logger used to log output. This logger is fed into the callbacks. - */ - LoggingModule mLogger; - /** * @brief ISender object used to interface with cloud to send Checkins */ diff --git a/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp b/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp index 7c2f5cd8..4b4e0e02 100644 --- a/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp +++ b/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp @@ -6,6 +6,7 @@ #include "CollectionSchemeManager.h" #include "DecoderManifestIngestion.h" #include "EnumUtility.h" +#include "LoggingModule.h" #include #include @@ -50,11 +51,11 @@ CollectionSchemeManager::sendCheckin() } checkinLogStr += checkinMsg[i]; } - mLogger.trace( "CollectionSchemeManager::sendCheckin", "CHECKIN: " + checkinLogStr ); + FWE_LOG_TRACE( "CHECKIN: " + checkinLogStr ); if ( mSchemaListenerPtr == nullptr ) { - mLogger.error( "CollectionSchemeManager::sendCheckin", "Cannot set the checkin message" ); + FWE_LOG_ERROR( "Cannot set the checkin message" ); return false; } else @@ -74,8 +75,7 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) if ( mSchemaPersistency == nullptr ) { - mLogger.error( "CollectionSchemeManager::retrieve", - "Failed to acquire a valid handle on the scheme local persistency module" ); + FWE_LOG_ERROR( "Failed to acquire a valid handle on the scheme local persistency module" ); return false; } switch ( retrieveType ) @@ -89,15 +89,14 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) errStr = "Failed to retrieve the DecoderManifest from the persistency module due to an error: "; break; default: - mLogger.error( "CollectionSchemeManager::retrieve", - "Unknown error: " + std::to_string( toUType( retrieveType ) ) ); + FWE_LOG_ERROR( "Unknown error: " + std::to_string( toUType( retrieveType ) ) ); return false; } protoSize = mSchemaPersistency->getSize( retrieveType ); if ( protoSize <= 0 ) { - mLogger.info( "CollectionSchemeManager::retrieve", infoStr + "zero" ); + FWE_LOG_INFO( infoStr + "zero" ); return false; } protoOutput.resize( protoSize ); @@ -106,10 +105,10 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) { auto error = mSchemaPersistency->getErrorString( ret ); errStr += error != nullptr ? error : "Unknown error"; - mLogger.error( "CollectionSchemeManager::retrieve", errStr ); + FWE_LOG_ERROR( errStr ); return false; } - mLogger.info( "CollectionSchemeManager::retrieve", infoStr + std::to_string( protoSize ) + " successfully" ); + FWE_LOG_INFO( infoStr + std::to_string( protoSize ) + " successfully" ); if ( retrieveType == DataType::COLLECTION_SCHEME_LIST ) { // updating mCollectionSchemeList @@ -145,18 +144,17 @@ CollectionSchemeManager::store( DataType storeType ) if ( mSchemaPersistency == nullptr ) { - mLogger.error( "CollectionSchemeManager::store", - "Failed to acquire a valid handle on the scheme local persistency module" ); + FWE_LOG_ERROR( "Failed to acquire a valid handle on the scheme local persistency module" ); return; } if ( ( storeType == DataType::COLLECTION_SCHEME_LIST ) && ( mCollectionSchemeList == nullptr ) ) { - mLogger.error( "CollectionSchemeManager::store", "Invalid CollectionSchemeList" ); + FWE_LOG_ERROR( "Invalid CollectionSchemeList" ); return; } if ( ( storeType == DataType::DECODER_MANIFEST ) && ( mDecoderManifest == nullptr ) ) { - mLogger.error( "CollectionSchemeManager::store", "Invalid DecoderManifest" ); + FWE_LOG_ERROR( "Invalid DecoderManifest" ); return; } switch ( storeType ) @@ -170,14 +168,13 @@ CollectionSchemeManager::store( DataType storeType ) logStr = "The DecoderManifest"; break; default: - mLogger.error( "CollectionSchemeManager::store", - "cannot store unsupported type of " + std::to_string( toUType( storeType ) ) ); + FWE_LOG_ERROR( "cannot store unsupported type of " + std::to_string( toUType( storeType ) ) ); return; } if ( protoInput.empty() ) { - mLogger.error( "CollectionSchemeManager::store", logStr + " data size is zero" ); + FWE_LOG_ERROR( logStr + " data size is zero" ); return; } ret = mSchemaPersistency->write( protoInput.data(), protoInput.size(), storeType ); @@ -186,11 +183,11 @@ CollectionSchemeManager::store( DataType storeType ) logStr += " because of this error: "; auto error = mSchemaPersistency->getErrorString( ret ); logStr += error != nullptr ? error : "Unknown error"; - mLogger.error( "CollectionSchemeManager::store", "failed to persist " + logStr ); + FWE_LOG_ERROR( "failed to persist " + logStr ); } else { - mLogger.trace( "CollectionSchemeManager::store", logStr + " persisted successfully" ); + FWE_LOG_TRACE( logStr + " persisted successfully" ); } } } // namespace DataManagement diff --git a/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp b/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp index dcfceee1..ee21ca6b 100644 --- a/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp +++ b/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp @@ -3,6 +3,7 @@ // Includes #include "CollectionSchemeManager.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -53,11 +54,11 @@ CollectionSchemeManager::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.error( "CollectionSchemeManager::start", "Thread failed to start" ); + FWE_LOG_ERROR( "Thread failed to start" ); } else { - mLogger.info( "CollectionSchemeManager::start", "Thread started" ); + FWE_LOG_INFO( "Thread started" ); mThread.setThreadName( "fwDMColSchMngr" ); } return mThread.isValid(); @@ -77,7 +78,7 @@ CollectionSchemeManager::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.info( "CollectionSchemeManager::stop", "Thread stopped" ); + FWE_LOG_INFO( "Collection Scheme Thread stopped" ); return true; } @@ -87,7 +88,7 @@ CollectionSchemeManager::shouldStop() const return mShouldStop.load( std::memory_order_relaxed ); } -/* supporting functions for mLogger */ +/* supporting functions for logging */ void CollectionSchemeManager::printEventLogMsg( std::string &msg, const std::string &id, @@ -175,8 +176,7 @@ CollectionSchemeManager::doWork( void *data ) } else { - collectionSchemeManager->mLogger.trace( "CollectionSchemeManager::doWork", - " Using a locally defined decoder dictionary " ); + FWE_LOG_TRACE( " Using a locally defined decoder dictionary " ); } do { @@ -199,10 +199,10 @@ CollectionSchemeManager::doWork( void *data ) if ( enabledCollectionSchemeMapChanged ) { TraceModule::get().sectionBegin( TraceSection::MANAGER_EXTRACTION ); - collectionSchemeManager->mLogger.trace( - "CollectionSchemeManager::doWork", + FWE_LOG_TRACE( + "Start extraction because of changed active collection schemes at system time " + - std::to_string( checkTime.systemTimeMs ) ); + std::to_string( checkTime.systemTimeMs ) ); /* * Extract InspectionMatrix from mEnabledCollectionSchemeMap * @@ -243,23 +243,19 @@ CollectionSchemeManager::doWork( void *data ) ->canMessageDecoderMethod.cbegin() ->second.size() : 0 ); - collectionSchemeManager->mLogger.info( - "CollectionSchemeManager::doWork", - "FWE activated Decoder Manifest:" + std::string( " using decoder manifest:" ) + - collectionSchemeManager->currentDecoderManifestID + " resulting in decoding rules for " + - std::to_string( decoderDictionaryMap.size() ) + - " protocols. Decoder CAN channels: " + decoderCanChannels + " and OBD PIDs:" + obdPids ); + FWE_LOG_INFO( "FWE activated Decoder Manifest:" + std::string( " using decoder manifest:" ) + + collectionSchemeManager->currentDecoderManifestID + " resulting in decoding rules for " + + std::to_string( decoderDictionaryMap.size() ) + + " protocols. Decoder CAN channels: " + decoderCanChannels + " and OBD PIDs:" + obdPids ); } std::string canInfo; std::string enabled; std::string idle; collectionSchemeManager->printExistingCollectionSchemes( enabled, idle ); // coverity[check_return : SUPPRESS] - collectionSchemeManager->mLogger.info( - "CollectionSchemeManager::doWork", - "FWE activated collection schemes:" + enabled + - " using decoder manifest:" + collectionSchemeManager->currentDecoderManifestID + " resulting in " + - std::to_string( inspectionMatrixOutput->conditions.size() ) + " inspection conditions" ); + FWE_LOG_INFO( "FWE activated collection schemes:" + enabled + " using decoder manifest:" + + collectionSchemeManager->currentDecoderManifestID + " resulting in " + + std::to_string( inspectionMatrixOutput->conditions.size() ) + " inspection conditions" ); TraceModule::get().sectionEnd( TraceSection::MANAGER_EXTRACTION ); } /* @@ -280,15 +276,14 @@ CollectionSchemeManager::doWork( void *data ) { uint32_t waitTimeMs = static_cast( collectionSchemeManager->mTimeLine.top().time.monotonicTimeMs - currentMonotonicTime ); - collectionSchemeManager->mLogger.trace( "CollectionSchemeManager::doWork", - "Going to wait for " + std::to_string( waitTimeMs ) + " ms" ); + FWE_LOG_TRACE( "Going to wait for " + std::to_string( waitTimeMs ) + " ms" ); collectionSchemeManager->mWait.wait( waitTimeMs ); } /* now it is either timer expires, an update arrives from PI, or stop() is called */ collectionSchemeManager->updateAvailable(); std::string wakeupStr; collectionSchemeManager->printWakeupStatus( wakeupStr ); - collectionSchemeManager->mLogger.trace( "CollectionSchemeManager::doWork", wakeupStr ); + FWE_LOG_TRACE( wakeupStr ); } while ( !collectionSchemeManager->shouldStop() ); } @@ -339,9 +334,8 @@ CollectionSchemeManager::init( uint32_t checkinIntervalMsec, CANInterfaceIDTranslator &canIDTranslator ) { mCANIDTranslator = canIDTranslator; - mLogger.trace( "CollectionSchemeManager::init", - "CollectionSchemeManager initialised with a checkin interval of: " + - std::to_string( checkinIntervalMsec ) + " ms" ); + FWE_LOG_TRACE( "CollectionSchemeManager initialised with a checkin interval of: " + + std::to_string( checkinIntervalMsec ) + " ms" ); if ( checkinIntervalMsec > 0 ) { mCheckinIntervalInMsec = checkinIntervalMsec; @@ -393,22 +387,19 @@ CollectionSchemeManager::processDecoderManifest() { if ( ( mDecoderManifest == nullptr ) || ( !mDecoderManifest->build() ) ) { - mLogger.error( "CollectionSchemeManager::processDecoderManifest", - " Failed to process the upcoming DecoderManifest." ); + FWE_LOG_ERROR( " Failed to process the upcoming DecoderManifest." ); return false; } // build is successful if ( mDecoderManifest->getID() == currentDecoderManifestID ) { - mLogger.trace( "CollectionSchemeManager::processDecoderManifest", - "Ignoring new decoder manifest with same name: " + currentDecoderManifestID ); + FWE_LOG_TRACE( "Ignoring new decoder manifest with same name: " + currentDecoderManifestID ); // no change in decoder manifest return false; } - mLogger.trace( "CollectionSchemeManager::processDecoderManifest", - "Replace decoder manifest " + currentDecoderManifestID + " with " + mDecoderManifest->getID() + - " while " + std::to_string( mEnabledCollectionSchemeMap.size() ) + " active and " + - std::to_string( mIdleCollectionSchemeMap.size() ) + " idle collection schemes loaded" ); + FWE_LOG_TRACE( "Replace decoder manifest " + currentDecoderManifestID + " with " + mDecoderManifest->getID() + + " while " + std::to_string( mEnabledCollectionSchemeMap.size() ) + " active and " + + std::to_string( mIdleCollectionSchemeMap.size() ) + " idle collection schemes loaded" ); // store the new DM, update currentDecoderManifestID currentDecoderManifestID = mDecoderManifest->getID(); store( DataType::DECODER_MANIFEST ); @@ -439,8 +430,7 @@ CollectionSchemeManager::processCollectionScheme() { if ( ( mCollectionSchemeList == nullptr ) || ( !mCollectionSchemeList->build() ) ) { - mLogger.error( "CollectionSchemeManager::processCollectionScheme", - "Incoming CollectionScheme does not exist or fails to build!" ); + FWE_LOG_ERROR( "Incoming CollectionScheme does not exist or fails to build!" ); return false; } // Build is successful. Store collectionScheme @@ -463,11 +453,10 @@ CollectionSchemeManager::calculateMonotonicTime( const TimePoint &currTime, Time TimePoint convertedTime = timePointFromSystemTime( currTime, systemTimeMs ); if ( ( convertedTime.systemTimeMs == 0 ) && ( convertedTime.monotonicTimeMs == 0 ) ) { - mLogger.error( "CollectionSchemeManager::timePointFromSystemTime", - "The system time " + std::to_string( systemTimeMs ) + - " corresponds to a time in the past before the monotonic" + - " clock started ticking. Current system time: " + std::to_string( currTime.systemTimeMs ) + - ". Current monotonic time: " + std::to_string( currTime.monotonicTimeMs ) ); + FWE_LOG_ERROR( "The system time " + std::to_string( systemTimeMs ) + + " corresponds to a time in the past before the monotonic" + + " clock started ticking. Current system time: " + std::to_string( currTime.systemTimeMs ) + + ". Current monotonic time: " + std::to_string( currTime.monotonicTimeMs ) ); return TimePoint{ systemTimeMs, 0 }; } return convertedTime; @@ -496,10 +485,9 @@ CollectionSchemeManager::rebuildMapsandTimeLine( const TimePoint &currTime ) { // Encounters a collectionScheme that does not have matching DM // Rebuild has to bail out. Call cleanupCollectionSchemes() before exiting. - mLogger.trace( "CollectionSchemeManager::rebuildMapsandTimeLine", - "CollectionScheme does not have matching DM ID. Current DM ID: " + currentDecoderManifestID + - " but collection scheme " + collectionScheme->getCollectionSchemeID() + " needs " + - collectionScheme->getDecoderManifestID() ); + FWE_LOG_TRACE( "CollectionScheme does not have matching DM ID. Current DM ID: " + currentDecoderManifestID + + " but collection scheme " + collectionScheme->getCollectionSchemeID() + " needs " + + collectionScheme->getDecoderManifestID() ); cleanupCollectionSchemes(); return false; @@ -526,7 +514,7 @@ CollectionSchemeManager::rebuildMapsandTimeLine( const TimePoint &currTime ) std::string enableStr; std::string idleStr; printExistingCollectionSchemes( enableStr, idleStr ); - mLogger.trace( "CollectionSchemeManager::rebuildMapsandTimeLine", enableStr + idleStr ); + FWE_LOG_TRACE( enableStr + idleStr ); return ret; } @@ -558,9 +546,8 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) { // Encounters a collectionScheme that does not have matching DM // Rebuild has to bail out. Call cleanupCollectionSchemes() before exiting. - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", - "CollectionScheme does not have matching DM ID: " + currentDecoderManifestID + " " + - collectionScheme->getDecoderManifestID() ); + FWE_LOG_TRACE( "CollectionScheme does not have matching DM ID: " + currentDecoderManifestID + " " + + collectionScheme->getDecoderManifestID() ); cleanupCollectionSchemes(); return false; @@ -598,7 +585,7 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) std::string completedStr; completedStr = "Stopping enabled CollectionScheme: "; printEventLogMsg( completedStr, id, startTime, stopTime, currTime ); - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", completedStr ); + FWE_LOG_TRACE( completedStr ); } else if ( stopTime != currCollectionScheme->getExpiryTime() ) { @@ -621,7 +608,7 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) std::string startStr; startStr = "Starting idle collectionScheme now: "; printEventLogMsg( startStr, id, startTime, stopTime, currTime ); - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", startStr ); + FWE_LOG_TRACE( startStr ); } else if ( ( startTime > currTime.systemTimeMs ) && ( ( startTime != currCollectionScheme->getStartTime() ) || @@ -643,7 +630,7 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) std::string addStr; addStr = "Adding new collectionScheme: "; printEventLogMsg( addStr, id, startTime, stopTime, currTime ); - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", addStr ); + FWE_LOG_TRACE( addStr ); if ( ( startTime <= currTime.systemTimeMs ) && ( stopTime > currTime.systemTimeMs ) ) { mEnabledCollectionSchemeMap[id] = collectionScheme; @@ -660,7 +647,8 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) } /* Check in newCollectionSchemeIDs set, if any Idle collectionScheme is missing from the set*/ std::string removeStr; - for ( auto it = mIdleCollectionSchemeMap.begin(); it != mIdleCollectionSchemeMap.end(); ) + auto it = mIdleCollectionSchemeMap.begin(); + while ( it != mIdleCollectionSchemeMap.end() ) { if ( newCollectionSchemeIDs.find( it->first ) == newCollectionSchemeIDs.end() ) { @@ -673,7 +661,8 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) } } /* Check in newCollectionSchemeIDs set, if any enabled collectionScheme is missing from the set*/ - for ( auto it = mEnabledCollectionSchemeMap.begin(); it != mEnabledCollectionSchemeMap.end(); ) + it = mEnabledCollectionSchemeMap.begin(); + while ( it != mEnabledCollectionSchemeMap.end() ) { if ( newCollectionSchemeIDs.find( it->first ) == newCollectionSchemeIDs.end() ) { @@ -688,13 +677,12 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) } if ( !removeStr.empty() ) { - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", - "Removing collectionSchemes missing from PI updates: " + removeStr ); + FWE_LOG_TRACE( "Removing collectionSchemes missing from PI updates: " + removeStr ); } std::string enableStr; std::string idleStr; printExistingCollectionSchemes( enableStr, idleStr ); - mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", enableStr + idleStr ); + FWE_LOG_TRACE( enableStr + idleStr ); return ret; } @@ -791,8 +779,7 @@ CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) // client request, this dataPair is obsolete, just drop it // keep searching for next valid TimePoint // to set up timer - mLogger.trace( "CollectionSchemeManager::checkTimeLine", - "CollectionScheme not found: " + topCollectionSchemeID ); + FWE_LOG_TRACE( "CollectionScheme not found: " + topCollectionSchemeID ); mTimeLine.pop(); continue; } @@ -820,12 +807,11 @@ CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) // this dataPair has a valid collectionScheme ID, but the start time or stop time is already updated // not equal to topTime any more; This is an obsolete dataPair. Simply drop it and move on // to next pair - mLogger.trace( "CollectionSchemeManager::checkTimeLine", - "Found collectionScheme: " + topCollectionSchemeID + - " but time does not match: " - "topTime " + - std::to_string( topTime.systemTimeMs ) + " timeFromCollectionScheme " + - std::to_string( timeOfInterest ) ); + FWE_LOG_TRACE( "Found collectionScheme: " + topCollectionSchemeID + + " but time does not match: " + "topTime " + + std::to_string( topTime.systemTimeMs ) + " timeFromCollectionScheme " + + std::to_string( timeOfInterest ) ); mTimeLine.pop(); continue; } @@ -848,7 +834,7 @@ CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) currCollectionScheme->getStartTime(), currCollectionScheme->getExpiryTime(), topTime ); - mLogger.info( "CollectionSchemeManager::checkTimeLine", enableStr ); + FWE_LOG_INFO( enableStr ); } else { @@ -860,7 +846,7 @@ CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) currCollectionScheme->getStartTime(), currCollectionScheme->getExpiryTime(), topTime ); - mLogger.info( "CollectionSchemeManager::checkTimeLine", disableStr ); + FWE_LOG_INFO( disableStr ); mEnabledCollectionSchemeMap.erase( topCollectionSchemeID ); } } @@ -875,9 +861,8 @@ CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) } if ( !mTimeLine.empty() ) { - mLogger.trace( "CollectionSchemeManager::checkTimeLine", - "Top pair: " + std::to_string( mTimeLine.top().time.monotonicTimeMs ) + " " + - mTimeLine.top().id + " currTime: " + std::to_string( currTime.monotonicTimeMs ) ); + FWE_LOG_TRACE( "Top pair: " + std::to_string( mTimeLine.top().time.monotonicTimeMs ) + " " + + mTimeLine.top().id + " currTime: " + std::to_string( currTime.monotonicTimeMs ) ); } return ret; } diff --git a/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp b/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp index fc7f22c2..adcb310e 100644 --- a/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp +++ b/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp @@ -3,6 +3,7 @@ // Includes #include "CollectionSchemeManager.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -14,7 +15,8 @@ namespace IoTFleetWise namespace DataManagement { -constexpr std::array CollectionSchemeManager::SUPPORTED_NETWORK_PROTOCOL; +// NOLINT below due to C++17 warning of redundant declarations that are required to maintain C++14 compatibility +constexpr std::array CollectionSchemeManager::SUPPORTED_NETWORK_PROTOCOL; // NOLINT void CollectionSchemeManager::decoderDictionaryExtractor( std::map> &decoderDictionaryMap ) @@ -30,8 +32,7 @@ CollectionSchemeManager::decoderDictionaryExtractor( auto networkType = mDecoderManifest->getNetworkProtocol( signalInfo.signalID ); if ( networkType == VehicleDataSourceProtocol::INVALID_PROTOCOL ) { - mLogger.warn( "CollectionSchemeManager::decoderDictionaryExtractor", - "Invalid protocol provided for signal : " + std::to_string( signalInfo.signalID ) ); + FWE_LOG_WARN( "Invalid protocol provided for signal : " + std::to_string( signalInfo.signalID ) ); // This signal contains invalid network protocol, cannot include it onto decoder dictionary continue; } @@ -50,8 +51,7 @@ CollectionSchemeManager::decoderDictionaryExtractor( auto canChannelID = mCANIDTranslator.getChannelNumericID( interfaceId ); if ( canChannelID == INVALID_CAN_SOURCE_NUMERIC_ID ) { - mLogger.warn( "CollectionSchemeManager::decoderDictionaryExtractor", - "Invalid Interface ID provided: " + interfaceId ); + FWE_LOG_WARN( "Invalid Interface ID provided: " + interfaceId ); } else { @@ -152,8 +152,7 @@ CollectionSchemeManager::decoderDictionaryExtractor( auto canChannelID = mCANIDTranslator.getChannelNumericID( canFrameInfo.interfaceID ); if ( canChannelID == INVALID_CAN_SOURCE_NUMERIC_ID ) { - mLogger.warn( "CollectionSchemeManager::decoderDictionaryExtractor", - "Invalid Interface ID provided:" + canFrameInfo.interfaceID ); + FWE_LOG_WARN( "Invalid Interface ID provided:" + canFrameInfo.interfaceID ); } else { diff --git a/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp b/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp index 65b1e0cd..3b1f9cbf 100644 --- a/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp +++ b/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp @@ -3,6 +3,7 @@ // Includes #include "CollectionSchemeManager.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -38,6 +39,7 @@ CollectionSchemeManager::addConditionData( const ICollectionSchemePtr &collectio inspectionSignal.minimumSampleIntervalMs = collectionSignals[i].minimumSampleIntervalMs; inspectionSignal.fixedWindowPeriod = collectionSignals[i].fixedWindowPeriod; inspectionSignal.isConditionOnlySignal = collectionSignals[i].isConditionOnlySignal; + inspectionSignal.signalType = getSignalType( collectionSignals[i].signalID ); conditionData.signals.emplace_back( inspectionSignal ); } @@ -51,8 +53,7 @@ CollectionSchemeManager::addConditionData( const ICollectionSchemePtr &collectio CANFrame.minimumSampleIntervalMs = collectionCANFrames[i].minimumSampleIntervalMs; if ( CANFrame.channelID == INVALID_CAN_SOURCE_NUMERIC_ID ) { - mLogger.warn( "CollectionSchemeManager::addConditionData", - "Invalid Interface ID provided: " + collectionCANFrames[i].interfaceID ); + FWE_LOG_WARN( "Invalid Interface ID provided: " + collectionCANFrames[i].interfaceID ); } else { diff --git a/src/datamanagement/datamanager/src/Schema.cpp b/src/datamanagement/datamanager/src/Schema.cpp index 91d0149a..0c3d01c9 100644 --- a/src/datamanagement/datamanager/src/Schema.cpp +++ b/src/datamanagement/datamanager/src/Schema.cpp @@ -17,8 +17,8 @@ using namespace Aws::IoTFleetWise::OffboardConnectivity; Schema::Schema( std::shared_ptr receiverDecoderManifest, std::shared_ptr receiverCollectionSchemeList, std::shared_ptr sender ) - : mDecoderManifestCb( *this, mLogger ) - , mCollectionSchemeListCb( *this, mLogger ) + : mDecoderManifestCb( *this ) + , mCollectionSchemeListCb( *this ) , mSender( std::move( sender ) ) { // Register the listeners @@ -56,13 +56,13 @@ Schema::sendCheckin( const std::vector &documentARNs ) if ( !mProtoCheckinMsg.SerializeToString( &mProtoCheckinMsgOutput ) ) { - mLogger.error( "Schema::sendCheckin", "Checkin serialization failed" ); + FWE_LOG_ERROR( "Checkin serialization failed" ); return false; } else { // transmit the data to the cloud - mLogger.trace( "Schema::sendCheckin", "Sending a Checkin message to the backend" ); + FWE_LOG_TRACE( "Sending a Checkin message to the backend" ); return transmitCheckin(); } } @@ -72,16 +72,16 @@ Schema::transmitCheckin() { if ( mSender == nullptr ) { - mLogger.error( "Schema::transmitCheckin", "Invalid sender instance" ); + FWE_LOG_ERROR( "Invalid sender instance" ); return false; } - auto res = mSender->send( reinterpret_cast( mProtoCheckinMsgOutput.data() ), - mProtoCheckinMsgOutput.size() ); + auto res = mSender->sendBuffer( reinterpret_cast( mProtoCheckinMsgOutput.data() ), + mProtoCheckinMsgOutput.size() ); if ( res == ConnectivityError::Success ) { - mLogger.trace( "Schema::transmitCheckin", "Checkin Message sent to the backend" ); + FWE_LOG_TRACE( "Checkin Message sent to the backend" ); // Trace log for more verbose Checkin Info std::string checkinDebugString; @@ -98,7 +98,7 @@ Schema::transmitCheckin() } checkinDebugString += "]"; - mLogger.trace( "Schema::transmitCheckin", checkinDebugString ); + FWE_LOG_TRACE( checkinDebugString ); return true; } else if ( res == ConnectivityError::NoConnection ) @@ -107,8 +107,7 @@ Schema::transmitCheckin() } else { - mLogger.error( "Schema::transmitCheckin", - "offboardconnectivity error, will retry sending the checkin message" ); + FWE_LOG_ERROR( "offboardconnectivity error, will retry sending the checkin message" ); return false; } } diff --git a/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp b/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp index b4570b1f..82a09706 100644 --- a/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp +++ b/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionSchemeManagerTest.h" +#include "WaitUntil.h" + +using namespace Aws::IoTFleetWise::TestingSupport; /**********************test body ***********************************************/ TEST( CollectionSchemeManagerTest, StopMainTest ) @@ -11,9 +14,9 @@ TEST( CollectionSchemeManagerTest, StopMainTest ) test.init( 50, nullptr, canIDTranslator ); test.myRegisterListener(); ASSERT_TRUE( test.connect() ); - std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); + /* stopping idling main thread */ - ASSERT_TRUE( test.disconnect() ); + WAIT_ASSERT_TRUE( test.disconnect() ); /* build DMs */ ASSERT_TRUE( test.connect() ); @@ -38,9 +41,9 @@ TEST( CollectionSchemeManagerTest, StopMainTest ) test.myInvokeDecoderManifest(); std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); test.myInvokeCollectionScheme(); - std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); + /* stopping main thread servicing a collectionScheme ending in 25 seconds */ - ASSERT_TRUE( test.disconnect() ); + WAIT_ASSERT_TRUE( test.disconnect() ); } TEST( CollectionSchemeManagerTest, CollectionSchemeUpdateCallBackTest ) @@ -212,6 +215,6 @@ TEST( CollectionSchemeManagerTest, MockProducerTest ) testList2.clear(); test.mPlTest = std::make_shared( testList2 ); test.myInvokeCollectionScheme(); - std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) ); - ASSERT_TRUE( test.disconnect() ); + + WAIT_ASSERT_TRUE( test.disconnect() ); } diff --git a/src/datamanagement/datamanager/test/SchemaTest.cpp b/src/datamanagement/datamanager/test/SchemaTest.cpp index 3f23321c..aad535fa 100644 --- a/src/datamanagement/datamanager/test/SchemaTest.cpp +++ b/src/datamanagement/datamanager/test/SchemaTest.cpp @@ -4,6 +4,7 @@ #include "Schema.h" #include "AwsIotChannel.h" #include "AwsIotConnectivityModule.h" + #include "ClockHandler.h" #include "CollectionSchemeIngestion.h" #include "CollectionSchemeIngestionList.h" @@ -44,10 +45,10 @@ class MockSender : public ISender } ConnectivityError - send( const std::uint8_t *buf, - size_t size, - struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = - CollectionSchemeParams() ) override + sendBuffer( const std::uint8_t *buf, + size_t size, + struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = + CollectionSchemeParams() ) override { static_cast( collectionSchemeParams ); // Currently not implemented, hence unused @@ -59,7 +60,7 @@ class MockSender : public ISender } }; -TEST( CollectionSchemeIgestionTest, CollectionSchemeIgestionClass ) +TEST( CollectionSchemeIngestionTest, CollectionSchemeIngestionClass ) { // Create a dummy AwsIotConnectivityModule object so that we can create dummy IReceiver objects to pass to the // constructor. Note that the MQTT callback aspect of CollectionSchemeProtoBuilder will not be used in this test. @@ -120,7 +121,7 @@ class CheckinTest : public ::testing::Test } }; -TEST( CollectionSchemeIgestionTest, Checkins ) +TEST( CollectionSchemeIngestionTest, Checkins ) { // Create a dummy AwsIotConnectivityModule object so that we can create dummy IReceiver objects auto awsIotModule = std::make_shared(); diff --git a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h index 79e9680f..d29ad95c 100644 --- a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h +++ b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h @@ -10,7 +10,6 @@ #include "CollectionSchemeManager.h" #include "DecoderManifestIngestion.h" #include "Listener.h" -#include "LoggingModule.h" #include #include #include diff --git a/src/datamanagement/datamanager/test/valgrind.supp b/src/datamanagement/datamanager/test/valgrind.supp index 17d9a8d5..fb93ef2c 100644 --- a/src/datamanagement/datamanager/test/valgrind.supp +++ b/src/datamanagement/datamanager/test/valgrind.supp @@ -30,3 +30,12 @@ fun:*add_persistence_guid* ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/datamanagement/types/include/CANDataTypes.h b/src/datamanagement/types/include/CANDataTypes.h index 652ff63d..bf2a3f2e 100644 --- a/src/datamanagement/types/include/CANDataTypes.h +++ b/src/datamanagement/types/include/CANDataTypes.h @@ -4,6 +4,7 @@ #pragma once // Includes +#include "SignalTypes.h" #include "TimeTypes.h" #include "datatypes/VehicleDataSourceTypes.h" #include @@ -18,18 +19,56 @@ namespace DataManagement using namespace Aws::IoTFleetWise::VehicleNetwork; using namespace Aws::IoTFleetWise::Platform::Linux; +union CANPhysicalValue { + double doubleVal; + uint64_t uint64Val; + int64_t int64Val; +}; + +struct CANPhysicalValueType +{ + CANPhysicalValue signalValue; + SignalType signalType; + + template + CANPhysicalValueType( T val, SignalType type ) + : signalType( type ) + { + switch ( signalType ) + { + case SignalType::UINT64: + signalValue.uint64Val = static_cast( val ); + break; + case SignalType::INT64: + signalValue.int64Val = static_cast( val ); + break; + default: + signalValue.doubleVal = static_cast( val ); + } + } + + SignalType + getType() const + { + return signalType; + } +}; + struct CANDecodedSignal { - CANDecodedSignal( uint32_t signalID, int64_t rawValue, double physicalValue ) + + CANDecodedSignal( uint32_t signalID, int64_t rawValue, CANPhysicalValueType physicalValue, SignalType signalTypeIn ) : mSignalID( signalID ) , mRawValue( rawValue ) , mPhysicalValue( physicalValue ) + , mSignalType( signalTypeIn ) { } uint32_t mSignalID; int64_t mRawValue; - double mPhysicalValue; + CANPhysicalValueType mPhysicalValue; + SignalType mSignalType{ SignalType::DOUBLE }; }; struct CANFrameInfo diff --git a/src/datamanagement/types/include/CollectionInspectionAPITypes.h b/src/datamanagement/types/include/CollectionInspectionAPITypes.h index d456166e..5fa2bdd1 100644 --- a/src/datamanagement/types/include/CollectionInspectionAPITypes.h +++ b/src/datamanagement/types/include/CollectionInspectionAPITypes.h @@ -84,6 +84,7 @@ struct InspectionMatrixSignalCollectionInfo bool isConditionOnlySignal; /**< Should the collected signals be sent to cloud or are the number * of samples in the buffer only necessary for condition evaluation */ + SignalType signalType{ SignalType::DOUBLE }; }; struct InspectionMatrixCanFrameCollectionInfo @@ -126,12 +127,12 @@ struct CollectedCanRawFrame CollectedCanRawFrame() = default; CollectedCanRawFrame( CANRawFrameID frameIDIn, CANChannelNumericID channelIdIn, - Timestamp receiveTimeIn, + Timestamp receiveTime, std::array &dataIn, uint8_t sizeIn ) : frameID( frameIDIn ) , channelId( channelIdIn ) - , receiveTime( receiveTimeIn ) + , receiveTime( receiveTime ) , data( dataIn ) , size( sizeIn ) { @@ -143,26 +144,212 @@ struct CollectedCanRawFrame uint8_t size{ 0 }; }; +union SignalValue { + int64_t int64Val; + float floatVal; + double doubleVal; + bool boolVal; + uint8_t uint8Val; + int8_t int8Val; + uint16_t uint16Val; + int16_t int16Val; + uint32_t uint32Val; + int32_t int32Val; + uint64_t uint64Val; + SignalValue & + operator=( const uint8_t value ) + { + uint8Val = value; + return *this; + } + + SignalValue & + operator=( const uint16_t value ) + { + uint16Val = value; + return *this; + } + + SignalValue & + operator=( const uint32_t value ) + { + uint32Val = value; + return *this; + } + + SignalValue & + operator=( const uint64_t value ) + { + uint64Val = value; + return *this; + } + + SignalValue & + operator=( const int8_t value ) + { + int8Val = value; + return *this; + } + + SignalValue & + operator=( const int16_t value ) + { + int16Val = value; + return *this; + } + SignalValue & + operator=( const int32_t value ) + { + int32Val = value; + return *this; + } + SignalValue & + operator=( const int64_t value ) + { + int64Val = value; + return *this; + } + + SignalValue & + operator=( const float value ) + { + floatVal = value; + return *this; + } + + SignalValue & + operator=( const double value ) + { + doubleVal = value; + return *this; + } + SignalValue & + operator=( const bool value ) + { + boolVal = value; + return *this; + } +}; + +struct SignalValueWrapper +{ + SignalValue value{ 0 }; + SignalType type{ SignalType::DOUBLE }; + + SignalValueWrapper() = default; + ~SignalValueWrapper() = default; + SignalValueWrapper( const SignalValueWrapper & ) = default; + SignalValueWrapper &operator=( const SignalValueWrapper & ) = default; + SignalValueWrapper( SignalValueWrapper && ) = default; + SignalValueWrapper &operator=( SignalValueWrapper && ) = default; + + template + SignalValueWrapper( T sigValue, SignalType sigType ) + { + setVal( sigValue, sigType ); + } + + // For Backward Compatibility + SignalValueWrapper & + operator=( const double sigValue ) + { + value = sigValue; + type = SignalType::DOUBLE; + return *this; + } + + template + void + setVal( const T sigValue, SignalType sigType ) + { + value = sigValue; + type = sigType; + } + + SignalType + getType() const + { + return type; + } +}; + struct CollectedSignal { + SignalID signalID{ INVALID_SIGNAL_ID }; + Timestamp receiveTime{ 0 }; + SignalValueWrapper value; + CollectedSignal() = default; - CollectedSignal( SignalID signalIDIn, Timestamp receiveTimeIn, double valueIn ) + // Backward Compatibility + template + CollectedSignal( SignalID signalIDIn, Timestamp receiveTime, T sigValue ) : signalID( signalIDIn ) - , receiveTime( receiveTimeIn ) - , value( valueIn ) + , receiveTime( receiveTime ) { + value.setVal( static_cast( sigValue ), SignalType::DOUBLE ); } - SignalID signalID{ INVALID_SIGNAL_ID }; - Timestamp receiveTime{ 0 }; - double value{ 0.0 }; + template + CollectedSignal( SignalID signalIDIn, Timestamp receiveTime, T sigValue, SignalType sigType ) + : signalID( signalIDIn ) + , receiveTime( receiveTime ) + { + switch ( sigType ) + { + case SignalType::UINT8: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::INT8: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::UINT16: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::INT16: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::UINT32: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::INT32: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::UINT64: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::INT64: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::FLOAT: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::DOUBLE: + value.setVal( static_cast( sigValue ), sigType ); + break; + case SignalType::BOOLEAN: + value.setVal( static_cast( sigValue ), sigType ); + break; + } + } + + SignalType + getType() const + { + return value.getType(); + } + + SignalValueWrapper + getValue() const + { + return value; + } }; using SignalBuffer = - boost::lockfree::queue; /**< multi NetworkChannel Consumers fill this queue and only one instance - of the Inspection and Collection Engine consumes it. It is used for Can - and OBD based signals */ + boost::lockfree::queue; /**< multi NetworkChannel Consumers fill this queue and only one + instance of the Inspection and Collection Engine consumes it. It is used + for Can and OBD based signals */ using CANBuffer = boost::lockfree::queue; /**< contains only raw can messages which at least one collectionScheme needs to publish in a raw format. multi diff --git a/src/datamanagement/types/include/Geohash.h b/src/datamanagement/types/include/Geohash.h index 3d78388d..d9b193ae 100644 --- a/src/datamanagement/types/include/Geohash.h +++ b/src/datamanagement/types/include/Geohash.h @@ -18,6 +18,8 @@ namespace DataInspection * See more details about Geohash at wikipedia: https://en.wikipedia.org/wiki/Geohash * */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class Geohash { public: diff --git a/src/datamanagement/types/include/OBDDataTypes.h b/src/datamanagement/types/include/OBDDataTypes.h index b9818379..5a259073 100644 --- a/src/datamanagement/types/include/OBDDataTypes.h +++ b/src/datamanagement/types/include/OBDDataTypes.h @@ -25,7 +25,34 @@ using namespace Aws::IoTFleetWise::VehicleNetwork; using namespace Aws::IoTFleetWise::Platform::Linux; using namespace Aws::IoTFleetWise::Platform::Utility; -using SignalValue = double; +union OBDValue { + double doubleVal; + uint64_t uint64Val; + int64_t int64Val; +}; + +struct OBDSignal +{ + OBDValue signalValue; + SignalType signalType; + + template + OBDSignal( T val, SignalType type ) + : signalType( type ) + { + switch ( signalType ) + { + case SignalType::UINT64: + signalValue.uint64Val = static_cast( val ); + break; + case SignalType::INT64: + signalValue.int64Val = static_cast( val ); + break; + default: + signalValue.doubleVal = static_cast( val ); + } + } +}; // List of OBD Service IDs/ Modes enum class SIDs : uint32_t @@ -202,12 +229,12 @@ struct DTCInfo }; // List of Emission related PIDs requested -// on the bus and there physical values +// on the bus and their physical values // e.g. PID = 0x0C( RPM) struct EmissionInfo { SID mSID; - std::map mPIDsToValues; + std::map mPIDsToValues; }; // Structure of a single PID OBD request. diff --git a/src/datamanagement/types/include/SignalTypes.h b/src/datamanagement/types/include/SignalTypes.h index 37eee8f3..5b285334 100644 --- a/src/datamanagement/types/include/SignalTypes.h +++ b/src/datamanagement/types/include/SignalTypes.h @@ -37,6 +37,27 @@ static const CANInterfaceID INVALID_CAN_INTERFACE_ID{}; using SignalID = uint32_t; static constexpr SignalID INVALID_SIGNAL_ID = 0xFFFFFFFF; +/** + * @brief VSS supported datatypes + * https://covesa.github.io/vehicle_signal_specification/rule_set/data_entry/data_types/ + * We currently supports 11 datatypes + * We don't support string yet until cloud can support it + */ +enum struct SignalType +{ + UINT8 = 0, + INT8 = 1, + UINT16 = 2, + INT16 = 3, + UINT32 = 4, + INT32 = 5, + UINT64 = 6, + INT64 = 7, + FLOAT = 8, + DOUBLE = 9, + BOOLEAN = 10 +}; + /** * @brief Format that defines a CAN Signal Format */ @@ -82,6 +103,11 @@ struct CANSignalFormat */ bool mIsMultiplexorSignal{ false }; + /** + * @brief The datatype of the signal. The default is double for backward compatibility + */ + SignalType mSignalType{ SignalType::DOUBLE }; + /** * @brief If mIsMultiplexorSignal is true, this value will be the value e.g. m0. If false, the value will be maxbit8 */ diff --git a/src/datamanagement/types/test/valgrind.supp b/src/datamanagement/types/test/valgrind.supp new file mode 100644 index 00000000..00c906ed --- /dev/null +++ b/src/datamanagement/types/test/valgrind.supp @@ -0,0 +1,8 @@ +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/executionmanagement/CMakeLists.txt b/src/executionmanagement/CMakeLists.txt index f99ee94c..cb84620e 100644 --- a/src/executionmanagement/CMakeLists.txt +++ b/src/executionmanagement/CMakeLists.txt @@ -37,7 +37,6 @@ target_link_libraries( aws-iot-fleetwise-edge ${libraryTargetName} IoTFleetWise::Platform::Linux - pthread -Xlinker -Map=aws-iot-fleetwise-edge.map ) @@ -77,7 +76,6 @@ if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/em-example-config.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/executionmanagement/include/IoTFleetWiseEngine.h b/src/executionmanagement/include/IoTFleetWiseEngine.h index 79dad060..7ba6d789 100644 --- a/src/executionmanagement/include/IoTFleetWiseEngine.h +++ b/src/executionmanagement/include/IoTFleetWiseEngine.h @@ -9,7 +9,6 @@ #include "CacheAndPersist.h" #include "ClockHandler.h" #include "CollectionInspectionWorkerThread.h" -#include "CollectionScheme.h" #include "CollectionSchemeManager.h" #include "DataCollectionSender.h" #ifdef FWE_FEATURE_CAMERA @@ -19,7 +18,6 @@ #include "IWaveGpsSource.h" #endif #include "IDataReadyToPublishListener.h" -#include "LoggingModule.h" #include "OBDOverCANModule.h" #include "RemoteProfiler.h" #include "Schema.h" @@ -90,24 +88,6 @@ class IoTFleetWiseEngine : public IDataReadyToPublishListener */ bool checkAndSendRetrievedData(); - /** - * @brief Attach a vehicle data source to IoTFleetWise. All functions in the data source must be - * thread safe. The source instance is needed so that FleetWise can access its output data - * buffer ( holding the vehicle data messages ) and to register to the connect and disconnect - * events. A vehicle data consumer will be attached to the source. - * This function can be called either on startup or runtime. - * The life cycle of the source is managed by the caller ( e.g. init, connect, disconnect). - */ - void attachVehicleDataSource( VehicleDataSourcePtr vehicleDataSource ); - - /** - * @brief Detach a vehicle data source to IoTFleetWise. No further data produced by this source - * will be visible to IoTFleetWise. - * This function can be called either on shutdown or runtime. - * The life cycle of the source is managed by the caller ( e.g. init, connect, disconnect). - */ - static void detachVehicleDataSource( VehicleDataSourcePtr vehicleDataSource ); - private: // atomic state of the bus. If true, we should stop bool shouldStop() const; @@ -133,10 +113,8 @@ class IoTFleetWiseEngine : public IDataReadyToPublishListener Timer mPrintMetricsCyclicTimer; uint64_t mPrintMetricsCyclicPeriodMs{ 0 }; // default to 0 which means no cyclic printing - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); std::unique_ptr mVehicleDataSourceBinder; - CollectionSchemePtr mCollectionScheme; std::shared_ptr mOBDOverCANModule; std::shared_ptr mDataCollectionSender; diff --git a/src/executionmanagement/src/IoTFleetWiseEngine.cpp b/src/executionmanagement/src/IoTFleetWiseEngine.cpp index 44d658af..b8cfbeac 100644 --- a/src/executionmanagement/src/IoTFleetWiseEngine.cpp +++ b/src/executionmanagement/src/IoTFleetWiseEngine.cpp @@ -6,7 +6,7 @@ #include "AwsBootstrap.h" #include "CANDataConsumer.h" #include "CollectionInspectionAPITypes.h" -#include "CollectionSchemeJSONParser.h" +#include "LoggingModule.h" #include "TraceModule.h" #include "businterfaces/AbstractVehicleDataSource.h" #include "businterfaces/CANDataSource.h" @@ -66,10 +66,6 @@ IoTFleetWiseEngine::IoTFleetWiseEngine() IoTFleetWiseEngine::~IoTFleetWiseEngine() { - if ( mCollectionScheme ) - { - mCollectionScheme->clear(); - } // To make sure the thread stops during teardown of tests. if ( isAlive() ) { @@ -78,19 +74,6 @@ IoTFleetWiseEngine::~IoTFleetWiseEngine() setLogForwarding( nullptr ); } -void -IoTFleetWiseEngine::attachVehicleDataSource( VehicleDataSourcePtr vehicleDataSource ) -{ - mVehicleDataSource = std::move( vehicleDataSource ); -} - -void -IoTFleetWiseEngine::detachVehicleDataSource( VehicleDataSourcePtr vehicleDataSource ) -{ - // TODO - static_cast( vehicleDataSource ); -} - bool IoTFleetWiseEngine::connect( const Json::Value &config ) { @@ -105,7 +88,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) persistencyPath, config["staticConfig"]["persistency"]["persistencyPartitionMaxSize"].asInt() ); if ( !mPersistDecoderManifestCollectionSchemesAndData->init() ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init persistency library" ); + FWE_LOG_ERROR( "Failed to init persistency library" ); } if ( config["staticConfig"]["persistency"].isMember( "persistencyUploadRetryIntervalMs" ) ) { @@ -188,14 +171,10 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mAwsIotChannelSendCheckin = mAwsIotModule->createNewChannel( nullptr ); mAwsIotChannelSendCheckin->setTopic( config["staticConfig"]["mqttConnection"]["checkinTopic"].asString() ); - // These parameters need to be added to the Config file to enable the feature : - // useJsonBasedCollectionScheme mDataCollectionSender = std::make_shared( mAwsIotChannelSendCanData, - config["staticConfig"]["internalParameters"]["useJsonBasedCollection"].asBool(), config["staticConfig"]["publishToCloudParameters"]["maxPublishMessageCount"].asUInt(), - canIDTranslator, - persistencyPath ); + canIDTranslator ); // Pass on the AWS SDK Bootsrap handle to the IoTModule. auto bootstrapPtr = AwsBootstrap::getInstance().getClientBootStrap(); @@ -211,7 +190,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) config["staticConfig"]["mqttConnection"]["clientId"].asString(), bootstrapPtr, true ); - /*************************Connectivity `bootstrap end***************************************/ + /*************************Connectivity bootstrap end***************************************/ /*************************Remote Profiling bootstrap begin**********************************/ if ( config["staticConfig"].isMember( "remoteProfilerDefaultValues" ) ) @@ -251,8 +230,9 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) config["staticConfig"]["remoteProfilerDefaultValues"]["profilerPrefix"].asString() ); if ( !mRemoteProfiler->start() ) { - mLogger.warn( "IoTFleetWiseEngine::connect", - "Failed to start the Remote Profiler - No remote profiling available until FWE restart" ); + FWE_LOG_WARN( + + "Failed to start the Remote Profiler - No remote profiling available until FWE restart" ); } setLogForwarding( mRemoteProfiler.get() ); } @@ -285,15 +265,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) config["staticConfig"]["internalParameters"]["dataReductionProbabilityDisabled"].asBool() ) ) || ( !mCollectionInspectionWorkerThread->start() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init and start the Inspection Engine" ); + FWE_LOG_ERROR( "Failed to init and start the Inspection Engine" ); return false; } // Make sure the Inspection Engine can notify the Bootstrap thread about ready to be // published data. if ( !mCollectionInspectionWorkerThread->subscribeListener( this ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed register the Engine Thread to the Inspection Module" ); + FWE_LOG_ERROR( "Failed register the Engine Thread to the Inspection Module" ); return false; } @@ -301,33 +280,12 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) /*************************CollectionScheme Ingestion bootstrap begin*********************************/ - // These parameters need to be added to the Config file to enable the feature : - // jsonBasedCollectionSchemeFilename - // JsonBasedCollectionScheme - if ( config["staticConfig"]["internalParameters"]["useJsonBasedCollectionScheme"].asBool() ) - { - // The main purpose to keep this code is for fast testing by enabling json collectionScheme as a file - CollectionSchemeJSONParser parser( - config["staticConfig"]["internalParameters"]["jsonBasedCollectionSchemeFilename"].asString() ); - - if ( ( !parser.parse() ) || ( !parser.getCollectionScheme() ) || - ( !parser.getCollectionScheme()->isValid() ) ) - { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to Parse the Collection Scheme" ); - return false; - } - - mCollectionScheme = parser.getCollectionScheme(); - } - else - { - // CollectionScheme Ingestion module executes in the context for the offboardconnectivity thread. Upcoming - // messages are expected to come either on the decoder manifest topic or the collectionScheme topic or both - // ( eventually ). - mSchemaPtr = std::make_shared( mAwsIotChannelReceiveDecoderManifest, - mAwsIotChannelReceiveCollectionSchemeList, - mAwsIotChannelSendCheckin ); - } + // CollectionScheme Ingestion module executes in the context for the offboardconnectivity thread. Upcoming + // messages are expected to come either on the decoder manifest topic or the collectionScheme topic or both + // ( eventually ). + mSchemaPtr = std::make_shared( mAwsIotChannelReceiveDecoderManifest, + mAwsIotChannelReceiveCollectionSchemeList, + mAwsIotChannelSendCheckin ); /*****************************CollectionScheme Management bootstrap begin*****************************/ @@ -340,7 +298,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mPersistDecoderManifestCollectionSchemesAndData, canIDTranslator ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Failed to init the CollectionScheme Manager" ); return false; } @@ -349,8 +307,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !mSchemaPtr->subscribeListener( static_cast( mCollectionSchemeManagerPtr.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed register the CollectionScheme Manager to the CollectionScheme Ingestion Module" ); + FWE_LOG_ERROR( "Failed register the CollectionScheme Manager to the CollectionScheme Ingestion Module" ); return false; } @@ -359,8 +316,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !mCollectionSchemeManagerPtr->subscribeListener( static_cast( mCollectionInspectionWorkerThread.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed register the Inspection Engine to the CollectionScheme Manager Module" ); + FWE_LOG_ERROR( "Failed register the Inspection Engine to the CollectionScheme Manager Module" ); return false; } @@ -374,7 +330,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mVehicleDataSourceBinder = std::make_unique(); if ( ( mVehicleDataSourceBinder == nullptr ) || ( !mVehicleDataSourceBinder->connect() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the Vehicle DataSource binder" ); + FWE_LOG_ERROR( "Failed to initialize the Vehicle DataSource binder" ); return false; } @@ -403,9 +359,8 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) bool success = stringToCanTimestampType( timestampTypeInput, canTimestampType ); if ( !success ) { - mLogger.warn( "IoTFleetWiseEngine::connect", - "Invalid can timestamp type provided: " + timestampTypeInput + - " so default to Software" ); + FWE_LOG_WARN( "Invalid can timestamp type provided: " + timestampTypeInput + + " so default to Software" ); } } auto canSourcePtr = std::make_shared( canTimestampType ); @@ -413,7 +368,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( canSourcePtr == nullptr || canConsumerPtr == nullptr ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to create consumer/producer" ); + FWE_LOG_ERROR( "Failed to create consumer/producer" ); return false; } // Initialize the consumer/producers @@ -426,7 +381,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) signalBufferPtr, config["staticConfig"]["threadIdleTimes"]["canDecoderThreadIdleTimeMs"].asUInt() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the producers/consumers" ); + FWE_LOG_ERROR( "Failed to initialize the producers/consumers" ); return false; } else @@ -440,14 +395,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // Handshake the binder and the channel if ( !mVehicleDataSourceBinder->addVehicleDataSource( canSourcePtr ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to add a network channel" ); + FWE_LOG_ERROR( "Failed to add a network channel" ); return false; } if ( !mVehicleDataSourceBinder->bindConsumerToVehicleDataSource( canConsumerPtr, canSourcePtr->getVehicleDataSourceID() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to Bind Consumers to Producers" ); + FWE_LOG_ERROR( "Failed to Bind Consumers to Producers" ); return false; } } @@ -472,41 +427,38 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mOBDOverCANModule = obdOverCANModule; if ( !mOBDOverCANModule->connect() ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to connect OBD over CAN module" ); + FWE_LOG_ERROR( "Failed to connect OBD over CAN module" ); return false; } if ( !mCollectionSchemeManagerPtr->subscribeListener( static_cast( mOBDOverCANModule.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed to register the OBD Module to the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Failed to register the OBD Module to the CollectionScheme Manager" ); return false; } if ( !mCollectionSchemeManagerPtr->subscribeListener( static_cast( mOBDOverCANModule.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed to register the OBD Module to the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Failed to register the OBD Module to the CollectionScheme Manager" ); return false; } } } else { - mLogger.error( "IoTFleetWiseEngine::connect", "obdOverCANModule already initialised" ); + FWE_LOG_ERROR( "obdOverCANModule already initialised" ); } } else { - mLogger.error( "IoTFleetWiseEngine::connect", interfaceName["type"].asString() + " is not supported" ); + FWE_LOG_ERROR( interfaceName["type"].asString() + " is not supported" ); } } // Register Vehicle Data Source Binder as listener for CollectionScheme Manager if ( !mCollectionSchemeManagerPtr->subscribeListener( mVehicleDataSourceBinder.get() ) ) { - mLogger.error( - "IoTFleetWiseEngine::connect", + FWE_LOG_ERROR( "Could not register the vehicle data source binder as a listener to the collection campaign manager" ); return false; } @@ -518,7 +470,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // read from persistent memory: if ( !mCollectionSchemeManagerPtr->connect() ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to start the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Failed to start the CollectionScheme Manager" ); return false; } /****************************CollectionScheme Manager bootstrap end*************************/ @@ -552,8 +504,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } else { - mLogger.warn( "IoTFleetWiseEngine::connect", - "Unsupported Transport config provided for a DDS Node, skipping it" ); + FWE_LOG_WARN( "Unsupported Transport config provided for a DDS Node, skipping it" ); continue; } @@ -564,8 +515,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } else { - mLogger.warn( "IoTFleetWiseEngine::connect", - "Unsupported Device type provided for a DDS Node, skipping it" ); + FWE_LOG_WARN( "Unsupported Device type provided for a DDS Node, skipping it" ); continue; } @@ -586,7 +536,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // Init the Module if ( ( mDataOverDDSModule == nullptr ) || ( !mDataOverDDSModule->init( ddsNodes ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the DDS Module" ); + FWE_LOG_ERROR( "Failed to initialize the DDS Module" ); return false; } // Register the DDS Module as a listener to the Inspection Engine and connect it. @@ -594,14 +544,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) static_cast( mDataOverDDSModule.get() ) ) ) || ( !mDataOverDDSModule->connect() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", "Failed to connect the DDS Module" ); + FWE_LOG_ERROR( "Failed to connect the DDS Module" ); return false; } - mLogger.info( "IoTFleetWiseEngine::connect", "DDS Module connected" ); + FWE_LOG_INFO( "DDS Module connected" ); } else { - mLogger.info( "IoTFleetWiseEngine::connect", "DDS Module disabled" ); + FWE_LOG_INFO( "DDS Module disabled" ); } /********************************DDS Module bootstrap end*********************************/ @@ -613,7 +563,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) bool iWaveInitSuccessful = false; if ( config["staticConfig"].isMember( "iWaveGpsExample" ) ) { - mLogger.trace( "IoTFleetWiseEngine::connect", "Found 'iWaveGpsExample' section in config file" ); + FWE_LOG_TRACE( "Found 'iWaveGpsExample' section in config file" ); std::vector iWaveGpsConfigs( 1 ); for ( auto const &key : config["staticConfig"]["iWaveGpsExample"].getMemberNames() ) { @@ -643,15 +593,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !mCollectionSchemeManagerPtr->subscribeListener( static_cast( mIWaveGpsSource.get() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Failed to register the IWaveGps to the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Failed to register the IWaveGps to the CollectionScheme Manager" ); return false; } mIWaveGpsSource->start(); } else { - mLogger.error( "IoTFleetWiseEngine::connect", "IWaveGps initialization failed" ); + FWE_LOG_ERROR( "IWaveGps initialization failed" ); return false; } /********************************IWave GPS Example NMEA reader end******************************/ @@ -662,12 +611,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } catch ( const std::exception &e ) { - mLogger.error( "IoTFleetWiseEngine::connect", - "Fatal Error during AWS IoT FleetWise Bootstrap: " + std::string( e.what() ) ); + FWE_LOG_ERROR( "Fatal Error during AWS IoT FleetWise Bootstrap: " + std::string( e.what() ) ); return false; } - mLogger.info( "IoTFleetWiseEngine::connect", "Engine Connected" ); + FWE_LOG_INFO( "Engine Connected" ); return true; } @@ -675,6 +623,12 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) bool IoTFleetWiseEngine::disconnect() { +#ifdef FWE_EXAMPLE_IWAVEGPS + if ( mIWaveGpsSource ) + { + mIWaveGpsSource->stop(); + } +#endif #ifdef FWE_FEATURE_CAMERA if ( mDataOverDDSModule ) { @@ -683,7 +637,7 @@ IoTFleetWiseEngine::disconnect() ( !mDataOverDDSModule->disconnect() ) ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not disconnect DDS Module" ); + FWE_LOG_ERROR( "Could not disconnect DDS Module" ); return false; } } @@ -693,37 +647,43 @@ IoTFleetWiseEngine::disconnect() { if ( !mOBDOverCANModule->disconnect() ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not disconnect OBD over CAN module" ); + FWE_LOG_ERROR( "Could not disconnect OBD over CAN module" ); return false; } } if ( !mCollectionInspectionWorkerThread->stop() ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not stop the Inspection Engine" ); + FWE_LOG_ERROR( "Could not stop the Inspection Engine" ); return false; } setLogForwarding( nullptr ); if ( ( mRemoteProfiler != nullptr ) && ( !mRemoteProfiler->stop() ) ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not stop the Remote Profiler" ); + FWE_LOG_ERROR( "Could not stop the Remote Profiler" ); return false; } if ( !mCollectionSchemeManagerPtr->disconnect() ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not stop the CollectionScheme Manager" ); + FWE_LOG_ERROR( "Could not stop the CollectionScheme Manager" ); return false; } // Stop the Binder if ( mVehicleDataSourceBinder && ( !mVehicleDataSourceBinder->disconnect() ) ) { - mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not disconnect the Binder" ); + FWE_LOG_ERROR( "Could not disconnect the Binder" ); return false; } - mLogger.info( "IoTFleetWiseEngine::disconnect", "Engine Disconnected" ); + + if ( mAwsIotModule->isAlive() && ( !mAwsIotModule->disconnect() ) ) + { + FWE_LOG_ERROR( "Could not disconnect the off-board connectivity" ); + return false; + } + FWE_LOG_INFO( "Engine Disconnected" ); TraceModule::get().sectionEnd( TraceSection::FWE_SHUTDOWN ); TraceModule::get().print(); return true; @@ -739,11 +699,11 @@ IoTFleetWiseEngine::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "IoTFleetWiseEngine::start", "Engine Thread failed to start" ); + FWE_LOG_TRACE( "Engine Thread failed to start" ); } else { - mLogger.trace( "IoTFleetWiseEngine::start", "Engine Thread started" ); + FWE_LOG_TRACE( "Engine Thread started" ); mThread.setThreadName( "fwEMEngine" ); } @@ -830,23 +790,20 @@ IoTFleetWiseEngine::doWork( void *data ) } if ( timeTrigger > 0 ) { - engine->mLogger.trace( - "IoTFleetWiseEngine::doWork", - "Waiting for: " + std::to_string( timeTrigger ) + " seconds. Persistency " + - std::to_string( engine->mPersistencyUploadRetryIntervalMs ) + " configured, " + - std::to_string( engine->mRetrySendingPersistedDataTimer.getElapsedMs().count() ) + - " timer. Cyclic Metrics Print:" + std::to_string( engine->mPrintMetricsCyclicPeriodMs ) + - " configured, " + std::to_string( engine->mPrintMetricsCyclicTimer.getElapsedMs().count() ) + - " timer." ); + FWE_LOG_TRACE( "Waiting for :" + std::to_string( timeTrigger ) + " seconds. Persistency " + + std::to_string( engine->mPersistencyUploadRetryIntervalMs ) + " configured, " + + std::to_string( engine->mRetrySendingPersistedDataTimer.getElapsedMs().count() ) + + " timer. Cyclic Metrics Print:" + std::to_string( engine->mPrintMetricsCyclicPeriodMs ) + + " configured, " + + std::to_string( engine->mPrintMetricsCyclicTimer.getElapsedMs().count() ) + " timer." ); engine->mWait.wait( static_cast( timeTrigger * 1000 ) ); } else { engine->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); elapsedTimeUs += static_cast( engine->mTimer.getElapsedMs().count() ); - engine->mLogger.trace( "IoTFleetWiseEngine::doWork", "Event Arrived" ); - engine->mLogger.trace( "IoTFleetWiseEngine::doWork", - "Time Elapsed waiting for the Event : " + std::to_string( elapsedTimeUs ) ); + FWE_LOG_TRACE( "Event Arrived" ); + FWE_LOG_TRACE( "Time Elapsed waiting for the Event : " + std::to_string( elapsedTimeUs ) ); } // Dequeues the collected data queue and sends the data to cloud @@ -868,19 +825,57 @@ IoTFleetWiseEngine::doWork( void *data ) firstSignalValues += " ..."; break; } - firstSignalValues += std::to_string( s.signalID ) + ":" + std::to_string( s.value ) + ","; + auto signalValue = s.getValue(); + firstSignalValues += std::to_string( s.signalID ) + ":"; + switch ( signalValue.getType() ) + { + case SignalType::UINT8: + firstSignalValues += std::to_string( signalValue.value.uint8Val ) + ","; + break; + case SignalType::INT8: + firstSignalValues += std::to_string( signalValue.value.int8Val ) + ","; + break; + case SignalType::UINT16: + firstSignalValues += std::to_string( signalValue.value.uint16Val ) + ","; + break; + case SignalType::INT16: + firstSignalValues += std::to_string( signalValue.value.int16Val ) + ","; + break; + case SignalType::UINT32: + firstSignalValues += std::to_string( signalValue.value.uint32Val ) + ","; + break; + case SignalType::INT32: + firstSignalValues += std::to_string( signalValue.value.int32Val ) + ","; + break; + case SignalType::UINT64: + firstSignalValues += std::to_string( signalValue.value.uint64Val ) + ","; + break; + case SignalType::INT64: + firstSignalValues += std::to_string( signalValue.value.int64Val ) + ","; + break; + case SignalType::FLOAT: + firstSignalValues += std::to_string( signalValue.value.floatVal ) + ","; + break; + case SignalType::DOUBLE: + firstSignalValues += std::to_string( signalValue.value.doubleVal ) + ","; + break; + case SignalType::BOOLEAN: + firstSignalValues += std::to_string( static_cast( signalValue.value.boolVal ) ) + ","; + break; + default: + firstSignalValues += std::to_string( signalValue.value.doubleVal ) + ","; + break; + } } firstSignalValues += "]"; - engine->mLogger.info( - "IoTFleetWiseEngine::doWork", - "FWE data ready to send with eventID " + - std::to_string( triggeredCollectionSchemeDataPtr->eventID ) + " from " + - triggeredCollectionSchemeDataPtr->metaData.collectionSchemeID + - " Signals: " + std::to_string( triggeredCollectionSchemeDataPtr->signals.size() ) + " " + - firstSignalValues + firstSignalTimestamp + - " raw CAN frames: " + std::to_string( triggeredCollectionSchemeDataPtr->canFrames.size() ) + - " DTCs: " + std::to_string( triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.size() ) + - " Geohash: " + triggeredCollectionSchemeDataPtr->mGeohashInfo.mGeohashString ); + FWE_LOG_INFO( "FWE data ready to send with eventID " + + std::to_string( triggeredCollectionSchemeDataPtr->eventID ) + " from " + + triggeredCollectionSchemeDataPtr->metaData.collectionSchemeID + + " Signals:" + std::to_string( triggeredCollectionSchemeDataPtr->signals.size() ) + " " + + firstSignalValues + firstSignalTimestamp + " raw CAN frames:" + + std::to_string( triggeredCollectionSchemeDataPtr->canFrames.size() ) + + " DTCs:" + std::to_string( triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.size() ) + + " Geohash:" + triggeredCollectionSchemeDataPtr->mGeohashInfo.mGeohashString ); engine->mDataCollectionSender->send( triggeredCollectionSchemeDataPtr ); } ); TraceModule::get().setVariable( TraceVariable::QUEUE_INSPECTION_TO_SENDER, consumedElements ); @@ -927,8 +922,7 @@ IoTFleetWiseEngine::checkAndSendRetrievedData() if ( status == ErrorCode::SUCCESS ) { ConnectivityError res = ConnectivityError::Success; - mLogger.trace( "IoTFleetWiseEngine::checkAndSendRetrievedData", - "Number of Payloads to transmit : " + std::to_string( payloads.size() ) ); + FWE_LOG_TRACE( "Number of Payloads to transmit : " + std::to_string( payloads.size() ) ); for ( const auto &payload : payloads ) { @@ -937,34 +931,31 @@ IoTFleetWiseEngine::checkAndSendRetrievedData() if ( res != ConnectivityError::Success ) { // Error occurred in the transmission - mLogger.error( "IoTFleetWiseEngine::checkAndSendRetrievedData", - "Payload transmission failed, will be retried on the next bootup" ); + FWE_LOG_ERROR( "Payload transmission failed, will be retried on the next bootup" ); break; } else { - mLogger.trace( "IoTFleetWiseEngine::checkAndSendRetrievedData", - "Payload has been successfully sent to the backend" ); + FWE_LOG_TRACE( "Payload has been successfully sent to the backend" ); } } if ( res == ConnectivityError::Success ) { // All the stored data has been transmitted, erase the file contents mPersistDecoderManifestCollectionSchemesAndData->erase( DataType::EDGE_TO_CLOUD_PAYLOAD ); - mLogger.info( "IoTFleetWiseEngine::checkAndSendRetrievedData", - "All " + std::to_string( payloads.size() ) + " Payloads successfully sent to the backend" ); + FWE_LOG_INFO( "All " + std::to_string( payloads.size() ) + " Payloads successfully sent to the backend" ); return true; } return false; } else if ( status == ErrorCode::EMPTY ) { - mLogger.trace( "IoTFleetWiseEngine::checkAndSendRetrievedData", "No Payloads to Retrieve" ); + FWE_LOG_TRACE( "No Payloads to Retrieve" ); return true; } else { - mLogger.error( "IoTFleetWiseEngine::checkAndSendRetrievedData", "Payload Retrieval Failed" ); + FWE_LOG_ERROR( "Payload Retrieval Failed" ); return false; } } diff --git a/src/executionmanagement/src/main.cpp b/src/executionmanagement/src/main.cpp index 2ef6e127..44587641 100644 --- a/src/executionmanagement/src/main.cpp +++ b/src/executionmanagement/src/main.cpp @@ -75,9 +75,9 @@ main( int argc, char *argv[] ) try { printVersion(); - if ( argc != 2 ) + if ( argc < 2 ) { - std::cout << "error: invalid argument - only a config file is required" << std::endl; + std::cout << "error: no config file provided" << std::endl; return EXIT_FAILURE; } diff --git a/src/executionmanagement/test/IoTFleetWiseEngineTest.cpp b/src/executionmanagement/test/IoTFleetWiseEngineTest.cpp index 1c89b2e7..4e617c4c 100644 --- a/src/executionmanagement/test/IoTFleetWiseEngineTest.cpp +++ b/src/executionmanagement/test/IoTFleetWiseEngineTest.cpp @@ -5,13 +5,15 @@ #include "IoTFleetWiseEngine.h" #include "IoTFleetWiseConfig.h" #include "LogLevel.h" +#include "WaitUntil.h" +#include #include -#include - #include #include #include +#include +using namespace Aws::IoTFleetWise::TestingSupport; using namespace Aws::IoTFleetWise::ExecutionManagement; using namespace Aws::IoTFleetWise::DataManagement; @@ -96,10 +98,10 @@ TEST_F( IoTFleetWiseEngineTest, CheckPublishDataQueue ) ASSERT_TRUE( engine.mCollectedDataReadyToPublish->push( collectedDataPtr ) ); ASSERT_TRUE( engine.start() ); - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - ASSERT_TRUE( engine.isAlive() ); - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - ASSERT_TRUE( engine.disconnect() ); + + WAIT_ASSERT_TRUE( engine.isAlive() ); + + WAIT_ASSERT_TRUE( engine.disconnect() ); ASSERT_TRUE( engine.stop() ); } diff --git a/src/executionmanagement/test/valgrind.supp b/src/executionmanagement/test/valgrind.supp index 604f7ddf..eb4305b4 100644 --- a/src/executionmanagement/test/valgrind.supp +++ b/src/executionmanagement/test/valgrind.supp @@ -36,7 +36,6 @@ __libc_csu_init Memcheck:Leak match-leak-kinds: reachable - fun:malloc ... fun:__libc_csu_init ... diff --git a/src/offboardconnectivity/api/include/ISender.h b/src/offboardconnectivity/api/include/ISender.h index 492a524b..b379b600 100644 --- a/src/offboardconnectivity/api/include/ISender.h +++ b/src/offboardconnectivity/api/include/ISender.h @@ -66,7 +66,7 @@ class ISender * * @return SUCCESS if connection is established. */ - virtual ConnectivityError send( + virtual ConnectivityError sendBuffer( const std::uint8_t *buf, size_t size, struct CollectionSchemeParams collectionSchemeParams = CollectionSchemeParams() ) = 0; diff --git a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp index 630ecf8b..b18096f5 100644 --- a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp +++ b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp @@ -10,7 +10,6 @@ using namespace Aws::IoTFleetWise::Platform::Linux; namespace { -constexpr char ALLOCATION_TAG[] = "AWS-SDK"; constexpr size_t NUM_THREADS = 1; constexpr size_t MAX_HOSTS = 1; constexpr size_t MAX_TTL = 5; @@ -35,7 +34,7 @@ struct AwsBootstrap::Impl auto &memMgr = AwsSDKMemoryManager::getInstance(); mOptions.memoryManagementOptions.memoryManager = &memMgr; - auto clientBootstrapFn = [this]() { + auto clientBootstrapFn = [this]() -> std::shared_ptr { // You need an event loop group to process IO events. // If you only have a few connections, 1 thread is ideal Aws::Crt::Io::EventLoopGroup eventLoopGroup( NUM_THREADS ); @@ -43,11 +42,12 @@ struct AwsBootstrap::Impl { auto errString = Crt::ErrorDebugString( eventLoopGroup.LastError() ); auto errLog = errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ); - mLogger.error( "AwsBootstrap::Impl::Impl", "Event Loop Group Creation failed with error " + errLog ); + FWE_LOG_ERROR( "Event Loop Group Creation failed with error " + errLog ); } else { Aws::Crt::Io::DefaultHostResolver defaultHostResolver( eventLoopGroup, MAX_HOSTS, MAX_TTL ); + constexpr char ALLOCATION_TAG[] = "AWS-SDK"; auto bootstrap = Aws::MakeShared( ALLOCATION_TAG, eventLoopGroup, defaultHostResolver ); mBootstrap = bootstrap.get(); @@ -62,7 +62,7 @@ struct AwsBootstrap::Impl ~Impl() { Aws::ShutdownAPI( mOptions ); - mLogger.trace( "AwsBootstrap::Impl::~Impl", "AWS API ShutDown Completed" ); + FWE_LOG_TRACE( "AWS API ShutDown Completed" ); } Impl( const Impl & ) = delete; @@ -76,7 +76,6 @@ struct AwsBootstrap::Impl return mBootstrap; } - Platform::Linux::LoggingModule mLogger; Aws::SDKOptions mOptions; /** diff --git a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsSDKMemoryManager.cpp b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsSDKMemoryManager.cpp index 61be6e0f..248fe6df 100644 --- a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsSDKMemoryManager.cpp +++ b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsSDKMemoryManager.cpp @@ -3,6 +3,7 @@ #include "AwsSDKMemoryManager.h" #include +#include namespace Aws { diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotChannel.h b/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotChannel.h index 83870547..adba04a4 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotChannel.h +++ b/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotChannel.h @@ -6,10 +6,10 @@ // Includes #include "IReceiver.h" #include "ISender.h" -#include "LoggingModule.h" #include "PayloadManager.h" #include #include +#include #include #include #include @@ -60,6 +60,8 @@ using Aws::IoTFleetWise::OffboardConnectivity::ConnectivityError; * constructor must be established before anything meaningful can be done with this class * @see AwsIotConnectivityModule */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class AwsIotChannel : public Aws::IoTFleetWise::OffboardConnectivity::ISender, public Aws::IoTFleetWise::OffboardConnectivity::IReceiver { @@ -108,9 +110,10 @@ class AwsIotChannel : public Aws::IoTFleetWise::OffboardConnectivity::ISender, size_t getMaxSendSize() const override; - ConnectivityError send( const std::uint8_t *buf, - size_t size, - struct CollectionSchemeParams collectionSchemeParams = CollectionSchemeParams() ) override; + ConnectivityError sendBuffer( + const std::uint8_t *buf, + size_t size, + struct CollectionSchemeParams collectionSchemeParams = CollectionSchemeParams() ) override; bool isTopicValid() @@ -148,7 +151,6 @@ class AwsIotChannel : public Aws::IoTFleetWise::OffboardConnectivity::ISender, std::shared_ptr mPayloadManager; std::string mTopicName; std::atomic mSubscribed; - Aws::IoTFleetWise::Platform::Linux::LoggingModule mLogger; bool mSubscribeAsynchronously; }; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotConnectivityModule.h b/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotConnectivityModule.h index 191c9b4c..26299523 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotConnectivityModule.h +++ b/src/offboardconnectivity/implementation/aws/iotcpp/include/AwsIotConnectivityModule.h @@ -6,9 +6,9 @@ // Includes #include "AwsIotChannel.h" #include "Listener.h" -#include "LoggingModule.h" #include "RetryThread.h" #include +#include #include #include @@ -27,6 +27,8 @@ using namespace Aws::IoTFleetWise::Platform::Linux; /** * @brief bootstrap of the Aws Iot SDK. Only one object of this should normally exist * */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class AwsIotConnectivityModule : public IRetryable, public IConnectivityModule { public: @@ -127,7 +129,6 @@ class AwsIotConnectivityModule : public IRetryable, public IConnectivityModule Aws::Crt::String mEndpointUrl; Aws::Crt::ByteCursor mPrivateKey{ 0, nullptr }; Aws::Crt::String mClientId; - Platform::Linux::LoggingModule mLogger; std::shared_ptr mConnection; std::unique_ptr mMqttClient; RetryThread mRetryThread; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/include/PayloadManager.h b/src/offboardconnectivity/implementation/aws/iotcpp/include/PayloadManager.h index de7f0143..0a8795fd 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/include/PayloadManager.h +++ b/src/offboardconnectivity/implementation/aws/iotcpp/include/PayloadManager.h @@ -6,7 +6,6 @@ // Includes #include "CacheAndPersist.h" #include "ISender.h" -#include "LoggingModule.h" #include #include #include @@ -65,7 +64,6 @@ class PayloadManager ErrorCode retrieveData( std::vector &data ); private: - Aws::IoTFleetWise::Platform::Linux::LoggingModule mLogger; std::shared_ptr mPersistencyPtr; /** @@ -80,10 +78,10 @@ class PayloadManager * * @return true if prep was successful, false if error occurred */ - bool preparePayload( uint8_t *const buf, - size_t size, - const std::string &data, - const struct CollectionSchemeParams &collectionSchemeParams ); + static bool preparePayload( uint8_t *const buf, + size_t size, + const std::string &data, + const struct CollectionSchemeParams &collectionSchemeParams ); }; } // namespace OffboardConnectivityAwsIot } // namespace IoTFleetWise diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/include/RemoteProfiler.h b/src/offboardconnectivity/implementation/aws/iotcpp/include/RemoteProfiler.h index aae9a552..468c6d4e 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/include/RemoteProfiler.h +++ b/src/offboardconnectivity/implementation/aws/iotcpp/include/RemoteProfiler.h @@ -61,10 +61,16 @@ class RemoteProfiler : public IMetricsReceiver, public ILogger * Can be called from multiple threads. * * @param level the log level used to decide if log entry should be uploaded + * @param filename the name of the file which emitted the log message + * @param lineNumber line number * @param function the name of the function which emitted the log message * @param logEntry the actual log message */ - void logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) override; + void logMessage( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) override; /** * @brief implements IMetricsReceiver and uploads metrics over MQTT @@ -131,7 +137,6 @@ class RemoteProfiler : public IMetricsReceiver, public ILogger std::shared_ptr fLogSender; std::mutex fThreadMutex; std::mutex loggingMutex; - LoggingModule fLogger; Signal fWait; Json::Value fMetricsRoot; Json::Value fLogRoot; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/include/RetryThread.h b/src/offboardconnectivity/implementation/aws/iotcpp/include/RetryThread.h index afded7ed..458e60ec 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/include/RetryThread.h +++ b/src/offboardconnectivity/implementation/aws/iotcpp/include/RetryThread.h @@ -3,7 +3,6 @@ #pragma once -#include "LoggingModule.h" #include "Thread.h" #include @@ -93,8 +92,6 @@ class RetryThread uint32_t fCurrentWaitTime; - LoggingModule fLogger; - Thread fThread; std::atomic fShouldStop; std::mutex fThreadMutex; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp index 500f2dfb..4a8f4d95 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp @@ -3,6 +3,7 @@ #include "AwsIotChannel.h" #include "AwsIotConnectivityModule.h" +#include "LoggingModule.h" #include "TraceModule.h" #include @@ -43,7 +44,7 @@ AwsIotChannel::setTopic( const std::string &topicNameRef, bool subscribeAsynchro { if ( topicNameRef.empty() ) { - mLogger.error( "AwsIotChannel::setTopic", "Empty ingestion topic name provided" ); + FWE_LOG_ERROR( "Empty ingestion topic name provided" ); } mSubscribeAsynchronously = subscribeAsynchronously; mTopicName = topicNameRef; @@ -55,12 +56,12 @@ AwsIotChannel::subscribe() std::lock_guard connectivityLock( mConnectivityMutex ); if ( !isTopicValid() ) { - mLogger.error( "AwsIotChannel::subscribe", "Empty ingestion topic name provided" ); + FWE_LOG_ERROR( "Empty ingestion topic name provided" ); return ConnectivityError::NotConfigured; } if ( !isAliveNotThreadSafe() ) { - mLogger.error( "AwsIotChannel::subscribe", "MQTT Connection not established, failed to subscribe" ); + FWE_LOG_ERROR( "MQTT Connection not established, failed to subscribe" ); return ConnectivityError::NoConnection; } auto connection = mConnectivityModule->getConnection(); @@ -78,7 +79,7 @@ AwsIotChannel::subscribe() (void)dup; (void)retain; os << "Message received on topic " << topic << " payload length: " << byteBuf.len; - mLogger.trace( "AwsIotChannel::subscribeTopic", os.str() ); + FWE_LOG_TRACE( os.str() ); notifyListeners( &IReceiverCallback::onDataReceived, byteBuf.buffer, byteBuf.len ); }; @@ -98,29 +99,28 @@ AwsIotChannel::subscribe() { auto errString = aws_error_debug_str( errorCode ); TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::SUBSCRIBE_ERROR ); - mLogger.error( "AwsIotChannel::subscribeTopic", "Subscribe failed with error" ); - mLogger.error( "AwsIotChannel::subscribeTopic", - errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); + FWE_LOG_ERROR( "Subscribe failed with error" ); + FWE_LOG_ERROR( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); } else { if ( ( packetId == 0u ) || ( QoS == Mqtt::QOS::AWS_MQTT_QOS_FAILURE ) ) { TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::SUBSCRIBE_REJECT ); - mLogger.error( "AwsIotChannel::subscribeTopic", "Subscribe rejected by the Remote broker" ); + FWE_LOG_ERROR( "Subscribe rejected by the Remote broker" ); } else { std::ostringstream os; os << "Subscribe on topic " << topic << " on packetId " << packetId << " succeeded"; - mLogger.trace( "AwsIotChannel::subscribeTopic", os.str() ); + FWE_LOG_TRACE( os.str() ); mSubscribed = true; } subscribeFinishedPromise.set_value(); } }; - mLogger.trace( "AwsIotChannel::subscribeTopic", "Subscribing..." ); + FWE_LOG_TRACE( "Subscribing..." ); connection->Subscribe( mTopicName.c_str(), Mqtt::QOS::AWS_MQTT_QOS_AT_LEAST_ONCE, onMessage, onSubAck ); // Blocked call until subscribe finished this call should quickly either fail or succeed but @@ -142,24 +142,24 @@ AwsIotChannel::getMaxSendSize() const } ConnectivityError -AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSchemeParams collectionSchemeParams ) +AwsIotChannel::sendBuffer( const std::uint8_t *buf, size_t size, struct CollectionSchemeParams collectionSchemeParams ) { std::lock_guard connectivityLock( mConnectivityMutex ); if ( !isTopicValid() ) { - mLogger.warn( "AwsIotChannel::send", "Invalid topic provided" ); + FWE_LOG_WARN( "Invalid topic provided" ); return ConnectivityError::NotConfigured; } if ( ( buf == nullptr ) || ( size == 0 ) ) { - mLogger.warn( "AwsIotChannel::send", "No valid data provided" ); + FWE_LOG_WARN( "No valid data provided" ); return ConnectivityError::WrongInputData; } if ( size > getMaxSendSize() ) { - mLogger.warn( "AwsIotChannel::send", "Payload provided is too long" ); + FWE_LOG_WARN( "Payload provided is too long" ); return ConnectivityError::WrongInputData; } @@ -171,11 +171,11 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche if ( isDataPersisted ) { - mLogger.trace( "AwsIotChannel::send", "Payload has persisted successfully on disk" ); + FWE_LOG_TRACE( "Payload has persisted successfully on disk" ); } else { - mLogger.warn( "AwsIotChannel::send", "Payload has not been persisted" ); + FWE_LOG_WARN( "Payload has not been persisted" ); } } return ConnectivityError::NoConnection; @@ -185,21 +185,20 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche if ( ( mMaximumIotSDKHeapMemoryBytes != 0 ) && ( currentMemoryUsage > mMaximumIotSDKHeapMemoryBytes ) ) { mConnectivityModule->releaseMemoryUsage( size ); - mLogger.error( "AwsIotChannel::send", - "Not sending out the message with size " + std::to_string( size ) + - " because IoT device SDK allocated the maximum defined memory. Currently allocated " + - std::to_string( currentMemoryUsage ) ); + FWE_LOG_ERROR( "Not sending out the message with size " + std::to_string( size ) + + " because IoT device SDK allocated the maximum defined memory. Currently allocated " + + std::to_string( currentMemoryUsage ) ); if ( mPayloadManager != nullptr ) { bool isDataPersisted = mPayloadManager->storeData( buf, size, collectionSchemeParams ); if ( isDataPersisted ) { - mLogger.trace( "AwsIotChannel::send", "Data was persisted successfully" ); + FWE_LOG_TRACE( "Data was persisted successfully" ); } else { - mLogger.warn( "AwsIotChannel::send", "Data was not persisted and is lost" ); + FWE_LOG_WARN( "Data was not persisted and is lost" ); } } return ConnectivityError::QuotaReached; @@ -224,14 +223,13 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche } if ( ( packetId != 0U ) && ( errorCode == 0 ) ) { - mLogger.trace( "AwsIotChannel::send", - "Operation on packetId " + std::to_string( packetId ) + " Succeeded" ); + FWE_LOG_TRACE( "Operation on packetId " + std::to_string( packetId ) + " Succeeded" ); } else { auto errSting = aws_error_debug_str( errorCode ); std::string errLog = errSting != nullptr ? std::string( errSting ) : std::string( "Unknown error" ); - mLogger.error( "AwsIotChannel::send", std::string( "Operation failed with error" ) + errLog ); + FWE_LOG_ERROR( std::string( "Operation failed with error" ) + errLog ); } }; connection->Publish( mTopicName.c_str(), Mqtt::QOS::AWS_MQTT_QOS_AT_MOST_ONCE, false, payload, onPublishComplete ); @@ -247,13 +245,14 @@ AwsIotChannel::unsubscribe() auto connection = mConnectivityModule->getConnection(); std::promise unsubscribeFinishedPromise; - mLogger.trace( "AwsIotChannel::unsubscribe", "Unsubscribing..." ); + FWE_LOG_TRACE( "Unsubscribing..." ); connection->Unsubscribe( mTopicName.c_str(), [&]( Mqtt::MqttConnection &mqttConnection, uint16_t packetId, int errorCode ) { (void)mqttConnection; (void)packetId; (void)errorCode; - mLogger.trace( "AwsIotChannel::unsubscribe", "Unsubscribed" ); + FWE_LOG_TRACE( "Unsubscribed" ); + mSubscribed = false; unsubscribeFinishedPromise.set_value(); } ); // Blocked call until subscribe finished this call should quickly either fail or succeed but diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp index b5b1f832..2ca3e300 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp @@ -4,7 +4,7 @@ #include "AwsIotConnectivityModule.h" #include "AwsBootstrap.h" #include "AwsSDKMemoryManager.h" - +#include "LoggingModule.h" #include "TraceModule.h" #include @@ -72,7 +72,7 @@ AwsIotConnectivityModule::connect( const std::string &privateKey, return false; } - mLogger.info( "AwsIotConnectivityModule::connect", "Establishing an MQTT Connection" ); + FWE_LOG_INFO( "Establishing an MQTT Connection" ); // Connection callbacks setupCallbacks(); @@ -105,7 +105,7 @@ AwsIotConnectivityModule::resetConnection() mConnectionCompletedPromise = std::promise(); if ( mConnectionEstablished ) { - mLogger.info( "AwsIotConnectivityModule::disconnect", "Closing the MQTT Connection" ); + FWE_LOG_INFO( "Closing the MQTT Connection" ); if ( mConnection->Disconnect() ) { mConnectionClosedPromise.get_future().wait(); @@ -120,6 +120,11 @@ AwsIotConnectivityModule::resetConnection() bool AwsIotConnectivityModule::disconnect() { + for ( auto channel : mChannels ) + { + channel->unsubscribe(); + channel->invalidateConnection(); + } mRetryThread.stop(); return resetConnection(); } @@ -138,9 +143,8 @@ AwsIotConnectivityModule::setupCallbacks() { auto errString = ErrorDebugString( errorCode ); TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::CONNECTION_FAILED ); - mLogger.error( "AwsIotConnectivityModule::connect", "Connection failed with error" ); - mLogger.error( "AwsIotConnectivityModule::connect", - errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); + FWE_LOG_ERROR( "Connection failed with error" ); + FWE_LOG_ERROR( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); mConnectionCompletedPromise.set_value( false ); } else @@ -148,13 +152,13 @@ AwsIotConnectivityModule::setupCallbacks() if ( returnCode != Mqtt::ReturnCode::AWS_MQTT_CONNECT_ACCEPTED ) { TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::CONNECTION_REJECTED ); - mLogger.error( "AwsIotConnectivityModule::connect", "Connection failed with mqtt return code" ); - mLogger.error( "AwsIotConnectivityModule::connect", std::to_string( (int)returnCode ) ); + FWE_LOG_ERROR( "Connection failed with mqtt return code" ); + FWE_LOG_ERROR( std::to_string( (int)returnCode ) ); mConnectionCompletedPromise.set_value( false ); } else { - mLogger.info( "AwsIotConnectivityModule::connect", "Connection completed successfully" ); + FWE_LOG_INFO( "Connection completed successfully" ); mConnectionCompletedPromise.set_value( true ); } } @@ -167,7 +171,7 @@ AwsIotConnectivityModule::setupCallbacks() std::string errorString = "The MQTT Connection has been interrupted due to: "; auto errStr = ErrorDebugString( error ); errorString.append( errStr != nullptr ? std::string( errStr ) : std::string( "Unknown error" ) ); - mLogger.error( "AwsIotConnectivityModule::setupCallbacks", errorString ); + FWE_LOG_ERROR( errorString ); mConnected = false; }; @@ -176,13 +180,13 @@ AwsIotConnectivityModule::setupCallbacks() (void)connectCode; (void)sessionPresent; TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::CONNECTION_RESUMED ); - mLogger.info( "AwsIotConnectivityModule::setupCallbacks", "The MQTT Connection has resumed" ); + FWE_LOG_INFO( "The MQTT Connection has resumed" ); mConnected = true; }; auto onDisconnect = [&]( Mqtt::MqttConnection &mqttConnection ) { (void)mqttConnection; - mLogger.info( "AwsIotConnectivityModule::setupCallbacks", "The MQTT Connection is closed" ); + FWE_LOG_INFO( "The MQTT Connection is closed" ); mConnectionClosedPromise.set_value(); mConnected = false; mConnectionEstablished = false; @@ -205,7 +209,7 @@ AwsIotConnectivityModule::setupCallbacks() (void)retain; (void)qos; os << "Data received on the topic: " << topic << " with a payload length of: " << payload.len; - mLogger.trace( "AwsIotConnectivityModule::setupCallbacks", os.str() ); + FWE_LOG_TRACE( os.str() ); } ); } @@ -229,21 +233,19 @@ AwsIotConnectivityModule::createMqttConnection( Aws::Crt::Io::ClientBootstrap *c { if ( ( mCertificate.len == 0 ) || ( mPrivateKey.len == 0 ) || mEndpointUrl.empty() || mClientId.empty() ) { - mLogger.error( "AwsIotConnectivityModule::connect", - "Please provide X.509 Certificate, private Key, endpoint and client-Id" ); + FWE_LOG_ERROR( "Please provide X.509 Certificate, private Key, endpoint and client-Id" ); return false; } if ( clientBootstrap == nullptr ) { - mLogger.error( "AwsIotConnectivityModule::connect", "ClientBootstrap failed with error" ); + FWE_LOG_ERROR( "ClientBootstrap failed with error" ); return false; } else if ( !( *clientBootstrap ) ) { auto errString = ErrorDebugString( clientBootstrap->LastError() ); - mLogger.error( "AwsIotConnectivityModule::connect", "ClientBootstrap failed with error" ); - mLogger.error( "AwsIotConnectivityModule::connect", - errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); + FWE_LOG_ERROR( "ClientBootstrap failed with error" ); + FWE_LOG_ERROR( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); return false; } @@ -260,9 +262,8 @@ AwsIotConnectivityModule::createMqttConnection( Aws::Crt::Io::ClientBootstrap *c if ( !clientConfig ) { auto errString = ErrorDebugString( clientConfig.LastError() ); - mLogger.error( "AwsIotConnectivityModule::connect", "Client Configuration initialization failed with error" ); - mLogger.error( "AwsIotConnectivityModule::connect", - errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); + FWE_LOG_ERROR( "Client Configuration initialization failed with error" ); + FWE_LOG_ERROR( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); return false; } /* @@ -273,9 +274,8 @@ AwsIotConnectivityModule::createMqttConnection( Aws::Crt::Io::ClientBootstrap *c if ( !*mMqttClient ) { auto errString = ErrorDebugString( mMqttClient->LastError() ); - mLogger.error( "AwsIotConnectivityModule::connect", "MQTT Client Creation failed with error" ); - mLogger.error( "AwsIotConnectivityModule::connect", - errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); + FWE_LOG_ERROR( "MQTT Client Creation failed with error" ); + FWE_LOG_ERROR( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); return false; } @@ -287,7 +287,7 @@ AwsIotConnectivityModule::createMqttConnection( Aws::Crt::Io::ClientBootstrap *c { auto errString = ErrorDebugString( mMqttClient->LastError() ); auto errLog = errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ); - mLogger.error( "AwsIotConnectivityModule::connect", "MQTT Connection Creation failed with error " + errLog ); + FWE_LOG_ERROR( "MQTT Connection Creation failed with error " + errLog ); return false; } return true; @@ -301,11 +301,11 @@ AwsIotConnectivityModule::attempt() std::string error = "The MQTT Connection failed due to: "; auto errString = ErrorDebugString( mConnection->LastError() ); error.append( errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); - mLogger.warn( "AwsIotConnectivityModule::attempt", error ); + FWE_LOG_WARN( error ); return RetryStatus::RETRY; } - mLogger.trace( "AwsIotConnectivityModule::attempt", "Waiting of connection completed callback" ); + FWE_LOG_TRACE( "Waiting of connection completed callback" ); mConnectionEstablished = true; // Block until the connection establishes or fails. // If the connection fails, the module will also fail. @@ -339,9 +339,5 @@ AwsIotConnectivityModule::onFinished( RetryStatus code ) AwsIotConnectivityModule::~AwsIotConnectivityModule() { - for ( auto channel : mChannels ) - { - channel->invalidateConnection(); - } disconnect(); } diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp index 5f467a83..62b3cb21 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "PayloadManager.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -24,7 +25,7 @@ PayloadManager::preparePayload( uint8_t *const buf, if ( buf == nullptr ) { TraceModule::get().incrementVariable( TraceVariable::PM_MEMORY_NULL ); - mLogger.error( "PayloadManager::preparePayload", "Payload provided is empty" ); + FWE_LOG_ERROR( "Payload provided is empty" ); return false; } @@ -35,7 +36,7 @@ PayloadManager::preparePayload( uint8_t *const buf, if ( size < ( data.size() + hdrSize ) ) { TraceModule::get().incrementVariable( TraceVariable::PM_MEMORY_INSUFFICIENT ); - mLogger.error( "PayloadManager::preparePayload", "Payload Buffer size not sufficient" ); + FWE_LOG_ERROR( "Payload Buffer size not sufficient" ); return false; } @@ -57,7 +58,7 @@ PayloadManager::storeData( const std::uint8_t *buf, bool isDataPersisted = false; if ( collectionSchemeParams.persist ) { - mLogger.trace( "PayloadManager::storeData", "The schema activates data persistency" ); + FWE_LOG_TRACE( "The schema activates data persistency" ); std::string payload; if ( buf != nullptr ) { @@ -68,14 +69,12 @@ PayloadManager::storeData( const std::uint8_t *buf, // compress it anyway for storage if ( !collectionSchemeParams.compression ) { - mLogger.trace( "PayloadManager::storeData", - "CollectionScheme does not activate compression, but will apply compression for local " + FWE_LOG_TRACE( "CollectionScheme does not activate compression, but will apply compression for local " "persistency anyway" ); if ( snappy::Compress( payload.data(), payload.size(), &compressedData ) == 0u ) { TraceModule::get().incrementVariable( TraceVariable::PM_COMPRESS_ERROR ); - mLogger.error( "PayloadManager::storeData", - "Error occurred when compressing the payload. The payload is likely corrupted." ); + FWE_LOG_ERROR( "Error occurred when compressing the payload. The payload is likely corrupted." ); return isDataPersisted; } } @@ -87,34 +86,33 @@ PayloadManager::storeData( const std::uint8_t *buf, size_t totalWriteSize = compressedData.size() + sizeof( PayloadHeader ); // Allocate a bigger buffer to prefix payload header to the payload - std::unique_ptr writeBuffer( new uint8_t[totalWriteSize]() ); + std::vector writeBuffer( totalWriteSize ); // Add metadata to the payload before storage - if ( !preparePayload( writeBuffer.get(), totalWriteSize, compressedData, collectionSchemeParams ) ) + if ( !preparePayload( writeBuffer.data(), totalWriteSize, compressedData, collectionSchemeParams ) ) { - mLogger.error( "PayloadManager::storeData", "Error occurred during payload preparation" ); + FWE_LOG_ERROR( "Error occurred during payload preparation" ); return isDataPersisted; } - ErrorCode status = mPersistencyPtr->write( writeBuffer.get(), totalWriteSize, DataType::EDGE_TO_CLOUD_PAYLOAD ); + ErrorCode status = + mPersistencyPtr->write( writeBuffer.data(), totalWriteSize, DataType::EDGE_TO_CLOUD_PAYLOAD ); if ( status == ErrorCode::SUCCESS ) { // set the ErrorCode::SUCCESSful storage flag to true isDataPersisted = true; - mLogger.trace( "PayloadManager::storeData", - "Payload of size: " + std::to_string( totalWriteSize ) + - " Bytes (header: " + std::to_string( sizeof( PayloadHeader ) ) + - ") has been ErrorCode::SUCCESSfully persisted" ); + FWE_LOG_TRACE( "Payload of size : " + std::to_string( totalWriteSize ) + " Bytes (header: " + + std::to_string( sizeof( PayloadHeader ) ) + ") has been ErrorCode::SUCCESSfully persisted" ); } else { TraceModule::get().incrementVariable( TraceVariable::PM_STORE_ERROR ); - mLogger.error( "PayloadManager::storeData", "Failed to persist data on disk" ); + FWE_LOG_ERROR( "Failed to persist data on disk" ); } } else { - mLogger.trace( "PayloadManager::storeData", "CollectionScheme does not activate persistency on disk" ); + FWE_LOG_TRACE( "CollectionScheme does not activate persistency on disk" ); } return isDataPersisted; } @@ -130,8 +128,8 @@ PayloadManager::retrieveData( std::vector &data ) } // Parsed data will be stored here - std::unique_ptr readBuffer( new uint8_t[readSize] ); - ErrorCode status = mPersistencyPtr->read( readBuffer.get(), readSize, DataType::EDGE_TO_CLOUD_PAYLOAD ); + std::vector readBuffer( readSize ); + ErrorCode status = mPersistencyPtr->read( readBuffer.data(), readSize, DataType::EDGE_TO_CLOUD_PAYLOAD ); if ( status != ErrorCode::SUCCESS ) { @@ -149,7 +147,7 @@ PayloadManager::retrieveData( std::vector &data ) { size_t j = 0; PayloadHeader payloadHdr{}; - memcpy( &payloadHdr, &( readBuffer.get()[pos] ), sizeof( PayloadHeader ) ); + memcpy( &payloadHdr, &( readBuffer[pos] ), sizeof( PayloadHeader ) ); pos += sizeof( PayloadHeader ); // capture the size of the payload @@ -159,7 +157,7 @@ PayloadManager::retrieveData( std::vector &data ) dataString.clear(); for ( j = 0; ( j < size ) && ( ( pos + j ) < readSize ); ++j ) { - dataString += ( readBuffer.get()[pos + j] ); // NOLINT(clang-diagnostic-sign-conversion) + dataString += static_cast( readBuffer[pos + j] ); } std::string payloadData; @@ -167,15 +165,13 @@ PayloadManager::retrieveData( std::vector &data ) // uncompress if the collectionScheme did not require compression if ( !payloadHdr.compressionRequired ) { - mLogger.trace( "PayloadManager::retrieveData", - "CollectionScheme does not require compression, uncompress " + - std::to_string( dataString.size() ) + - " bytes before transmitting the " - "persisted data." ); + FWE_LOG_TRACE( "CollectionScheme does not require compression, uncompress " + + std::to_string( dataString.size() ) + + " bytes before transmitting the " + "persisted data." ); if ( !snappy::Uncompress( dataString.data(), dataString.size(), &payloadData ) ) { - mLogger.error( - "PayloadManager::retrieveData", + FWE_LOG_ERROR( "Error occurred while un-compressing the payload from disk. The payload is likely corrupted." ); return ErrorCode::INVALID_DATA; } @@ -189,8 +185,7 @@ PayloadManager::retrieveData( std::vector &data ) pos += j; } } - mLogger.info( "PayloadManager::retrieveData", - "Payload of Size: " + std::to_string( readSize ) + " Bytes has been loaded from disk" ); + FWE_LOG_INFO( "Payload of Size: " + std::to_string( readSize ) + " Bytes has been loaded from disk" ); return ErrorCode::SUCCESS; } diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp index 0f43f82c..7cef4cf0 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp @@ -27,7 +27,6 @@ RemoteProfiler::RemoteProfiler( std::shared_ptr metricsSender, , fProfilerPrefix( std::move( profilerPrefix ) ) , fCurrentUserPayloadInLogRoot( 0 ) { - std::unique_ptr consoleLogger( new ConsoleLogger() ); initLogStructure(); fLastCPURUsage.reportCPUUsageInfo(); Aws::IoTFleetWise::Platform::Linux::CPUUsageInfo::reportPerThreadUsageData( fLastThreadUsage ); @@ -50,11 +49,10 @@ RemoteProfiler::sendMetricsOut() builder["indentation"] = ""; // If you want whitespace-less output const std::string output = Json::writeString( builder, fMetricsRoot ); uint32_t ret = static_cast( - fMetricsSender->send( reinterpret_cast( output.c_str() ), output.length() ) ); + fMetricsSender->sendBuffer( reinterpret_cast( output.c_str() ), output.length() ) ); if ( static_cast( ConnectivityError::Success ) != ret ) { - fLogger.error( "RemoteProfiler::sendMetricsOut", - "Send error " + std::to_string( static_cast( ret ) ) ); + FWE_LOG_ERROR( "Send error " + std::to_string( static_cast( ret ) ) ); } fMetricsRoot.clear(); fCurrentMetricsPending = 0; @@ -76,17 +74,20 @@ RemoteProfiler::sendLogsOut() if ( ( fLogSender != nullptr ) && ( fCurrentUserPayloadInLogRoot > 0 ) ) { uint32_t ret = static_cast( - fLogSender->send( reinterpret_cast( output.c_str() ), output.length() ) ); + fLogSender->sendBuffer( reinterpret_cast( output.c_str() ), output.length() ) ); if ( static_cast( ConnectivityError::Success ) != ret ) { - fLogger.error( "RemoteProfiler::sendLogsOut", - "Send error " + std::to_string( static_cast( ret ) ) ); + FWE_LOG_ERROR( " Send error " + std::to_string( static_cast( ret ) ) ); } } } void -RemoteProfiler::logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) +RemoteProfiler::logMessage( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) { if ( level < fLogLevelThreshold ) { @@ -95,9 +96,12 @@ RemoteProfiler::logMessage( LogLevel level, const std::string &function, const s Json::Value logNode; logNode["logLevel"] = levelToString( level ); + logNode["logFile"] = filename; + logNode["logLineNumber"] = lineNumber; logNode["logFunction"] = function; logNode["logEntry"] = logEntry; - uint32_t size = static_cast( function.length() + logEntry.length() + JSON_MAX_OVERHEAD_BYTES_PER_LOG ); + uint32_t size = static_cast( filename.length() + function.length() + logEntry.length() + + JSON_MAX_OVERHEAD_BYTES_PER_LOG ); bool sendOutBeforeAdding = false; { std::lock_guard lock( loggingMutex ); @@ -142,14 +146,13 @@ RemoteProfiler::start() { if ( fMetricsSender == nullptr ) { - fLogger.error( "RemoteProfiler::start", "Trying to start without sender" ); + FWE_LOG_ERROR( "Trying to start without sender" ); return false; } if ( ( ( fInitialLogMaxInterval == 0 ) && ( fLogLevelThreshold != LogLevel::Off ) ) || ( ( fInitialLogMaxInterval != 0 ) && ( fLogLevelThreshold == LogLevel::Off ) ) ) { - fLogger.warn( "RemoteProfiler::start", - "Logging is turned off by putting LogLevel Threshold to Off but log max interval is not " + FWE_LOG_WARN( "Logging is turned off by putting LogLevel Threshold to Off but log max interval is not " "0, which is implausible" ); } // Prevent concurrent stop/init @@ -159,11 +162,11 @@ RemoteProfiler::start() fShouldStop.store( false ); if ( !fThread.create( doWork, this ) ) { - fLogger.trace( "RemoteProfiler::start", "Remote Profiler Thread failed to start" ); + FWE_LOG_TRACE( "Remote Profiler Thread failed to start" ); } else { - fLogger.trace( "RemoteProfiler::start", "Remote Profiler Thread started" ); + FWE_LOG_TRACE( "Remote Profiler Thread started" ); fThread.setThreadName( "fwCNProfiler" ); } @@ -180,12 +183,12 @@ RemoteProfiler::stop() std::lock_guard lock( fThreadMutex ); fShouldStop.store( true, std::memory_order_relaxed ); - fLogger.trace( "RemoteProfiler::stop", "Request stop" ); + FWE_LOG_TRACE( "Request stop" ); fWait.notify(); fThread.release(); initLogStructure(); fMetricsRoot.clear(); - fLogger.trace( "RemoteProfiler::stop", "Stop finished" ); + FWE_LOG_TRACE( "Stop finished" ); fShouldStop.store( false, std::memory_order_relaxed ); return !fThread.isActive(); } diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp index 65f3bf5f..00ab1951 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "RetryThread.h" +#include "LoggingModule.h" using namespace Aws::IoTFleetWise::OffboardConnectivityAwsIot; @@ -14,6 +15,7 @@ RetryThread::RetryThread( IRetryable &retryable, uint32_t startBackoffMs, uint32 , fCurrentWaitTime( 0 ) , fShouldStop( false ) { + // coverity[misra_cpp_2008_rule_5_2_10_violation] For std::atomic this must be performed in a single statement fInstance = fInstanceCounter++; } @@ -27,11 +29,11 @@ RetryThread::start() fShouldStop.store( false ); if ( !fThread.create( doWork, this ) ) { - fLogger.trace( "RetryThread::start", "Retry Thread failed to start" ); + FWE_LOG_TRACE( "Retry Thread failed to start" ); } else { - fLogger.trace( "RetryThread::start", "Retry Thread started" ); + FWE_LOG_TRACE( "Retry Thread started" ); fThread.setThreadName( "fwCNRetry" + std::to_string( fInstance ) ); } @@ -48,7 +50,7 @@ RetryThread::stop() std::lock_guard lock( fThreadMutex ); fShouldStop.store( true ); - fLogger.trace( "RetryThread::stop", "Request stop" ); + FWE_LOG_TRACE( "Request stop" ); fWait.notify(); fThread.release(); fShouldStop.store( false, std::memory_order_relaxed ); @@ -65,18 +67,16 @@ RetryThread::doWork( void *data ) RetryStatus result = retryThread->fRetryable.attempt(); if ( result != RetryStatus::RETRY ) { - retryThread->fLogger.trace( "RetryThread::doWork", - "Finished with code " + std::to_string( static_cast( result ) ) ); + FWE_LOG_TRACE( "Finished with code " + std::to_string( static_cast( result ) ) ); retryThread->fRetryable.onFinished( result ); return; } - retryThread->fLogger.trace( "RetryThread::doWork", - "Current retry time is: " + std::to_string( retryThread->fCurrentWaitTime ) ); + FWE_LOG_TRACE( "Current retry time is: " + std::to_string( retryThread->fCurrentWaitTime ) ); retryThread->fWait.wait( retryThread->fCurrentWaitTime ); // exponential backoff retryThread->fCurrentWaitTime = std::min( retryThread->fCurrentWaitTime * 2, retryThread->fMaxBackoffMs ); } // If thread is shutdown without succeeding signal abort - retryThread->fLogger.trace( "RetryThread::doWork", "Stop thread with ABORT" ); + FWE_LOG_TRACE( "Stop thread with ABORT" ); retryThread->fRetryable.onFinished( RetryStatus::ABORT ); } diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/test/src/AwsIotConnectivityModuleTest.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/test/src/AwsIotConnectivityModuleTest.cpp index 1acc5186..d63e422d 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/test/src/AwsIotConnectivityModuleTest.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/test/src/AwsIotConnectivityModuleTest.cpp @@ -268,7 +268,7 @@ TEST_F( AwsIotConnectivityModuleTest, sendWithoutTopic ) std::shared_ptr m = std::make_shared(); AwsIotChannel c( m.get(), nullptr ); std::uint8_t input[] = { 0xca, 0xfe }; - ASSERT_EQ( c.send( input, sizeof( input ) ), ConnectivityError::NotConfigured ); + ASSERT_EQ( c.sendBuffer( input, sizeof( input ) ), ConnectivityError::NotConfigured ); c.invalidateConnection(); } @@ -279,7 +279,7 @@ TEST_F( AwsIotConnectivityModuleTest, sendWithoutConnection ) AwsIotChannel c( m.get(), nullptr ); std::uint8_t input[] = { 0xca, 0xfe }; c.setTopic( "topic" ); - ASSERT_EQ( c.send( input, sizeof( input ) ), ConnectivityError::NoConnection ); + ASSERT_EQ( c.sendBuffer( input, sizeof( input ) ), ConnectivityError::NoConnection ); c.invalidateConnection(); } @@ -291,7 +291,7 @@ TEST_F( AwsIotConnectivityModuleTest, sendWrongInput ) AwsIotChannel c( m.get(), nullptr ); ASSERT_TRUE( m->connect( "key", "cert", "endpoint", "clientIdTest", bootstrap ) ); c.setTopic( "topic" ); - ASSERT_EQ( c.send( nullptr, 10 ), ConnectivityError::WrongInputData ); + ASSERT_EQ( c.sendBuffer( nullptr, 10 ), ConnectivityError::WrongInputData ); con->OnDisconnect( *con ); c.invalidateConnection(); } @@ -306,7 +306,7 @@ TEST_F( AwsIotConnectivityModuleTest, sendTooBig ) c.setTopic( "topic" ); std::vector a; a.resize( c.getMaxSendSize() + 1U ); - ASSERT_EQ( c.send( a.data(), a.size() ), ConnectivityError::WrongInputData ); + ASSERT_EQ( c.sendBuffer( a.data(), a.size() ), ConnectivityError::WrongInputData ); con->OnDisconnect( *con ); c.invalidateConnection(); } @@ -336,15 +336,15 @@ TEST_F( AwsIotConnectivityModuleTest, sendMultiple ) } ) ); // Queue 2 packets - ASSERT_EQ( c.send( input, sizeof( input ) ), ConnectivityError::Success ); - ASSERT_EQ( c.send( input, sizeof( input ) ), ConnectivityError::Success ); + ASSERT_EQ( c.sendBuffer( input, sizeof( input ) ), ConnectivityError::Success ); + ASSERT_EQ( c.sendBuffer( input, sizeof( input ) ), ConnectivityError::Success ); // Confirm 1st (success as packetId is 1---v): completeHandlers.front().operator()( *con, 1, 0 ); completeHandlers.pop_front(); // Queue another: - ASSERT_EQ( c.send( input, sizeof( input ) ), ConnectivityError::Success ); + ASSERT_EQ( c.sendBuffer( input, sizeof( input ) ), ConnectivityError::Success ); // Confirm 2nd (success as packetId is 2---v): completeHandlers.front().operator()( *con, 2, 0 ); @@ -383,7 +383,8 @@ TEST_F( AwsIotConnectivityModuleTest, sdkRAMExceeded ) memMgr.AllocateMemory( 50 * AwsIotChannel::MAXIMUM_IOT_SDK_HEAP_MEMORY_BYTES, alignof( std::size_t ) ); ASSERT_NE( alloc3, nullptr ); - ASSERT_EQ( c.send( input.data(), input.size() * sizeof( std::uint8_t ) ), ConnectivityError::QuotaReached ); + ASSERT_EQ( c.sendBuffer( input.data(), input.size() * sizeof( std::uint8_t ) ), + ConnectivityError::QuotaReached ); memMgr.FreeMemory( alloc3 ); } { @@ -393,7 +394,7 @@ TEST_F( AwsIotConnectivityModuleTest, sdkRAMExceeded ) auto alloc4 = memMgr.AllocateMemory( AwsIotChannel::MAXIMUM_IOT_SDK_HEAP_MEMORY_BYTES - ( offset + required ), alignof( std::size_t ) ); ASSERT_NE( alloc4, nullptr ); - ASSERT_EQ( c.send( input.data(), sizeof( input ) ), ConnectivityError::QuotaReached ); + ASSERT_EQ( c.sendBuffer( input.data(), sizeof( input ) ), ConnectivityError::QuotaReached ); memMgr.FreeMemory( alloc4 ); // check that allocation and hence send succeed when there is just enough memory @@ -415,7 +416,7 @@ TEST_F( AwsIotConnectivityModuleTest, sdkRAMExceeded ) return true; } ) ); - ASSERT_EQ( c.send( input.data(), sizeof( input ) ), ConnectivityError::Success ); + ASSERT_EQ( c.sendBuffer( input.data(), sizeof( input ) ), ConnectivityError::Success ); memMgr.FreeMemory( alloc5 ); // // Confirm 1st (success as packetId is 1---v): diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/test/src/RemoteProfilerTest.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/test/src/RemoteProfilerTest.cpp index af3c48e2..b35620e7 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/test/src/RemoteProfilerTest.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/test/src/RemoteProfilerTest.cpp @@ -31,10 +31,10 @@ class MockSender : public ISender } ConnectivityError - send( const std::uint8_t *buf, - size_t size, - struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = - CollectionSchemeParams() ) override + sendBuffer( const std::uint8_t *buf, + size_t size, + struct Aws::IoTFleetWise::OffboardConnectivity::CollectionSchemeParams collectionSchemeParams = + CollectionSchemeParams() ) override { static_cast( collectionSchemeParams ); // Currently not implemented, hence unused std::cout << buf << std::endl; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/test/valgrind.supp b/src/offboardconnectivity/implementation/aws/iotcpp/test/valgrind.supp index 8873b108..0fdf9f6f 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/test/valgrind.supp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/test/valgrind.supp @@ -6,3 +6,12 @@ fun:aws_io_library_init ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/platform/linux/logmanagement/include/ConsoleLogger.h b/src/platform/linux/logmanagement/include/ConsoleLogger.h index c0a927be..5c14a33b 100644 --- a/src/platform/linux/logmanagement/include/ConsoleLogger.h +++ b/src/platform/linux/logmanagement/include/ConsoleLogger.h @@ -10,15 +10,6 @@ #include #include -namespace Color -{ -static const std::string red{ "\x1b[31m" }; -static const std::string yellow{ "\x1b[33m" }; -static const std::string blue{ "\x1b[34m" }; -static const std::string normal; -static const std::string reset{ "\x1b[0m" }; -} // namespace Color - namespace Aws { namespace IoTFleetWise @@ -43,12 +34,19 @@ class ConsoleLogger : public ILogger /** * @brief Logs a log message to the standard output. Includes current Thread ID and timestamp. - * The log message has this structure : [Thread : ID] [Time] [Level] [function]: [Message] + * The log message has this structure : [Thread : ID] [Time] [Level] [filename:lineNumber] [function]: + * [Message] * @param level log level + * @param filename file that emitted the log + * @param lineNumber line number * @param function calling function * @param logEntry actual message */ - void logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) override; + void logMessage( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) override; private: /** diff --git a/src/platform/linux/logmanagement/include/ILogger.h b/src/platform/linux/logmanagement/include/ILogger.h index 511263a1..a53cf81b 100644 --- a/src/platform/linux/logmanagement/include/ILogger.h +++ b/src/platform/linux/logmanagement/include/ILogger.h @@ -25,10 +25,16 @@ class ILogger * @brief Logs a log message in different way depending on the implementation class * * @param level log level + * @param filename calling file + * @param lineNumber line number * @param function calling function * @param logEntry actual message */ - virtual void logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) = 0; + virtual void logMessage( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) = 0; /** * @brief converts the Log Level enum to a human readable string diff --git a/src/platform/linux/logmanagement/include/LoggingModule.h b/src/platform/linux/logmanagement/include/LoggingModule.h index b49a79f8..f22692e7 100644 --- a/src/platform/linux/logmanagement/include/LoggingModule.h +++ b/src/platform/linux/logmanagement/include/LoggingModule.h @@ -9,6 +9,50 @@ #include #include +/** + * @brief Log INFO function + * @param logEntry the message to be logged + */ +#define FWE_LOG_INFO( logEntry ) \ + { \ + constexpr const char *shortFilename = getShortFilename( __FILE__ ); \ + LoggingModule::log( \ + LogLevel::Info, shortFilename, static_cast( __LINE__ ), __FUNCTION__, ( logEntry ) ); \ + } + +/** + * @brief Log WARN function + * @param logEntry the message to be logged + */ +#define FWE_LOG_WARN( logEntry ) \ + { \ + constexpr const char *shortFilename = getShortFilename( __FILE__ ); \ + LoggingModule::log( \ + LogLevel::Warning, shortFilename, static_cast( __LINE__ ), __FUNCTION__, ( logEntry ) ); \ + } + +/** + * @brief Log ERROR function + * @param logEntry the message to be logged + */ +#define FWE_LOG_ERROR( logEntry ) \ + { \ + constexpr const char *shortFilename = getShortFilename( __FILE__ ); \ + LoggingModule::log( \ + LogLevel::Error, shortFilename, static_cast( __LINE__ ), __FUNCTION__, ( logEntry ) ); \ + } + +/** + * @brief Log TRACE function + * @param logEntry the message to be logged + */ +#define FWE_LOG_TRACE( logEntry ) \ + { \ + constexpr const char *shortFilename = getShortFilename( __FILE__ ); \ + LoggingModule::log( \ + LogLevel::Trace, shortFilename, static_cast( __LINE__ ), __FUNCTION__, ( logEntry ) ); \ + } + namespace Aws { namespace IoTFleetWise @@ -17,6 +61,43 @@ namespace Platform { namespace Linux { + +/** + * @brief Recursive function to extract short filename from __FILE__ at compile time + * @param path path to the file, e.g. __FILE__ in the beginning + * @param lastFolder last parsed subfolder - full path to the file with subfolder in the beginning + * @return extracted file name + */ +static constexpr const char * +extractFilename( const char *path, const char *lastFolder ) +{ + // Cannot iterate more, end of path, lastFolder is file + if ( *path == '\0' ) + { + return lastFolder; + } + // Next subfolder found, repeat recursion for the subfolder + else if ( *path == '/' ) + { + return extractFilename( path + 1, path + 1 ); + } + // Move path pointer until new subfolder or end of path will be found + else + { + return extractFilename( path + 1, lastFolder ); + } +} + +/** + * @brief Get short filename from __FILE__ at compile time + * @param path path to the file, e.g. __FILE__ + * @return extracted file name + */ +static constexpr const char * +getShortFilename( const char *path ) +{ + return extractFilename( path, path ); +} /** * @brief Logging API. Used by all modules of the software to forward log entries * to a console logger instance. @@ -27,45 +108,28 @@ class LoggingModule static const uint64_t LOG_AGGREGATION_TIME_MS = 1000; /*< Periodic logging for one module should have a maximum frequency of this */ - LoggingModule(); - /** - * @brief Logs an Error - * @param function Calling function - * @param logEntry actual messages + * @brief Log function - calls ConsoleLogger + * @param level log level + * @param filename file that emitted the log + * @param lineNumber line in the file + * @param function calling function + * @param logEntry actual message */ - void error( const std::string &function, const std::string &logEntry ); - /** - * @brief Logs a Warning - * @param function Calling function - * @param logEntry actual messages - */ - void warn( const std::string &function, const std::string &logEntry ); - /** - * @brief Logs an Info - * @param function Calling function - * @param logEntry actual messages - */ - void info( const std::string &function, const std::string &logEntry ); - /** - * @brief Logs a Trace - * @param function Calling function - * @param logEntry actual messages - */ - void trace( const std::string &function, const std::string &logEntry ); - /** - * @brief Logs bytes in a vector - * @param function Calling function - * @param logEntry actual messages - * @param inputBytes bytes in vector to be printed - */ - void traceBytesInVector( const std::string &function, - const std::string &logEntry, - const std::vector &inputBytes ); - -private: - ConsoleLogger mLogger; + static void log( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ); }; + +/** + * @brief Transforms bytes in vector to string + * @param inputBytes bytes in vector to be printed + * @return string of transformed bytes input + */ +std::string getStringFromBytes( const std::vector &inputBytes ); + } // namespace Linux } // namespace Platform } // namespace IoTFleetWise diff --git a/src/platform/linux/logmanagement/include/TraceModule.h b/src/platform/linux/logmanagement/include/TraceModule.h index c9035683..a0b1ec6a 100644 --- a/src/platform/linux/logmanagement/include/TraceModule.h +++ b/src/platform/linux/logmanagement/include/TraceModule.h @@ -5,7 +5,6 @@ // Includes #include "EnumUtility.h" -#include "LoggingModule.h" #include #include #include @@ -46,8 +45,7 @@ enum class TraceVariable READ_SOCKET_FRAMES_16, READ_SOCKET_FRAMES_17, READ_SOCKET_FRAMES_18, - READ_SOCKET_FRAMES_19, - READ_SOCKET_FRAMES_MAX = READ_SOCKET_FRAMES_19, + READ_SOCKET_FRAMES_19, // If you add more, update references to this QUEUE_SOCKET_TO_CONSUMER_0, QUEUE_SOCKET_TO_CONSUMER_1, QUEUE_SOCKET_TO_CONSUMER_2, @@ -67,8 +65,7 @@ enum class TraceVariable QUEUE_SOCKET_TO_CONSUMER_16, QUEUE_SOCKET_TO_CONSUMER_17, QUEUE_SOCKET_TO_CONSUMER_18, - QUEUE_SOCKET_TO_CONSUMER_19, - QUEUE_SOCKET_TO_CONSUMER_MAX = QUEUE_SOCKET_TO_CONSUMER_19, + QUEUE_SOCKET_TO_CONSUMER_19, // If you add more, update references to this QUEUE_INSPECTION_TO_SENDER, MAX_SYSTEMTIME_KERNELTIME_DIFF, PM_MEMORY_NULL, @@ -89,6 +86,8 @@ enum class TraceVariable CE_PROCESSED_SIGNALS, CE_PROCESSED_CAN_FRAMES, CE_TRIGGERS, + OBD_POSSIBLE_PRECISION_LOSS_UINT64, + OBD_POSSIBLE_PRECISION_LOSS_INT64, TRACE_VARIABLE_SIZE }; @@ -141,8 +140,7 @@ enum class TraceSection CAN_DECODER_CYCLE_16, CAN_DECODER_CYCLE_17, CAN_DECODER_CYCLE_18, - CAN_DECODER_CYCLE_19, - CAN_DECODER_CYCLE_MAX = CAN_DECODER_CYCLE_19, + CAN_DECODER_CYCLE_19, // If you add more, update references to this TRACE_SECTION_SIZE }; /** @@ -439,8 +437,6 @@ class TraceModule struct AtomicVariableData mAtomicVariableData[toUType( TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE )]; struct SectionData mSectionData[toUType( TraceSection::TRACE_SECTION_SIZE )]; - - LoggingModule mLogger; }; } // namespace Linux } // namespace Platform diff --git a/src/platform/linux/logmanagement/src/ConsoleLogger.cpp b/src/platform/linux/logmanagement/src/ConsoleLogger.cpp index f9407d66..557db60c 100644 --- a/src/platform/linux/logmanagement/src/ConsoleLogger.cpp +++ b/src/platform/linux/logmanagement/src/ConsoleLogger.cpp @@ -22,6 +22,15 @@ namespace Platform { namespace Linux { +namespace Color +{ +static const std::string red{ "\x1b[31m" }; +static const std::string yellow{ "\x1b[33m" }; +static const std::string blue{ "\x1b[34m" }; +static const std::string normal; +static const std::string reset{ "\x1b[0m" }; +} // namespace Color + LogLevel gSystemWideLogLevel; LogColorOption gLogColorOption = LogColorOption::Auto; @@ -36,7 +45,11 @@ setLogForwarding( ILogger *logForwarder ) } void -forwardLog( LogLevel level, const std::string &function, const std::string &logEntry ) +forwardLog( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) { if ( gLogForwarder == nullptr ) { @@ -49,7 +62,7 @@ forwardLog( LogLevel level, const std::string &function, const std::string &logE } else { - gLogForwarder->logMessage( level, function, logEntry ); + gLogForwarder->logMessage( level, filename, lineNumber, function, logEntry ); } } @@ -68,19 +81,25 @@ ConsoleLogger::ConsoleLogger() } void -ConsoleLogger::logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) +ConsoleLogger::logMessage( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) { if ( level >= gSystemWideLogLevel ) { - std::printf( "%s[Thread: %" PRIu64 "] [%s] [%s] [%s]: [%s]%s\n", + std::printf( "%s[Thread: %" PRIu64 "] [%s] [%s] [%s:%i] [%s()]: [%s]%s\n", levelToColor( level ).c_str(), currentThreadId(), timeAsString().c_str(), levelToString( level ).c_str(), + filename.c_str(), + lineNumber, function.c_str(), logEntry.c_str(), mColorEnabled ? Color::reset.c_str() : "" ); - forwardLog( level, function, logEntry ); + forwardLog( level, filename, lineNumber, function, logEntry ); } } diff --git a/src/platform/linux/logmanagement/src/LoggingModule.cpp b/src/platform/linux/logmanagement/src/LoggingModule.cpp index a1bb2fa0..de00e9ab 100644 --- a/src/platform/linux/logmanagement/src/LoggingModule.cpp +++ b/src/platform/linux/logmanagement/src/LoggingModule.cpp @@ -16,36 +16,20 @@ namespace Platform { namespace Linux { -LoggingModule::LoggingModule() = default; void -LoggingModule::error( const std::string &function, const std::string &logEntry ) -{ - mLogger.logMessage( LogLevel::Error, function, logEntry ); -} - -void -LoggingModule::warn( const std::string &function, const std::string &logEntry ) -{ - mLogger.logMessage( LogLevel::Warning, function, logEntry ); -} - -void -LoggingModule::info( const std::string &function, const std::string &logEntry ) -{ - mLogger.logMessage( LogLevel::Info, function, logEntry ); +LoggingModule::log( LogLevel level, + const std::string &filename, + const uint32_t lineNumber, + const std::string &function, + const std::string &logEntry ) +{ + static ConsoleLogger logger; + logger.logMessage( level, filename, lineNumber, function, logEntry ); } -void -LoggingModule::trace( const std::string &function, const std::string &logEntry ) -{ - mLogger.logMessage( LogLevel::Trace, function, logEntry ); -} - -void -LoggingModule::traceBytesInVector( const std::string &function, - const std::string &logEntry, - const std::vector &inputBytes ) +std::string +getStringFromBytes( const std::vector &inputBytes ) { std::stringstream stream_bytes; @@ -62,8 +46,7 @@ LoggingModule::traceBytesInVector( const std::string &function, stream_bytes << std::hex << std::uppercase << std::setfill( '0' ) << std::setw( 2 * sizeof( uint8_t ) ) << static_cast( inputBytes[i] ) << " "; } - const std::string logMsg = logEntry + ": " + stream_bytes.str(); - mLogger.logMessage( LogLevel::Trace, function, logMsg ); + return stream_bytes.str(); } } // namespace Linux diff --git a/src/platform/linux/logmanagement/src/TraceModule.cpp b/src/platform/linux/logmanagement/src/TraceModule.cpp index deda5caa..d4799885 100644 --- a/src/platform/linux/logmanagement/src/TraceModule.cpp +++ b/src/platform/linux/logmanagement/src/TraceModule.cpp @@ -4,6 +4,7 @@ // Includes #include "TraceModule.h" +#include "LoggingModule.h" #include #include @@ -178,6 +179,10 @@ TraceModule::getVariableName( TraceVariable variable ) return "CeCCnt"; case TraceVariable::CE_TRIGGERS: return "CeTrgCnt"; + case TraceVariable::OBD_POSSIBLE_PRECISION_LOSS_UINT64: + return "ObdPrecU64"; + case TraceVariable::OBD_POSSIBLE_PRECISION_LOSS_INT64: + return "ObdPrecI64"; default: return "UNKNOWN"; } @@ -387,13 +392,12 @@ TraceModule::print() auto &v = mVariableData[i]; auto variableNamePtr = getVariableName( static_cast( i ) ); auto variableName = variableNamePtr != nullptr ? variableNamePtr : "Unknown variable name"; - mLogger.trace( "TraceModule::print", - std::string{ " TraceModule-ConsoleLogging-Variable '" } + variableName + "' [" + - std::to_string( i ) + "] current value: [" + std::to_string( v.mCurrentValue ) + - "] max value since last print: " - "[" + - std::to_string( v.mMaxValue ) + "] overall max value: [" + - std::to_string( v.mMaxValueAllTime ) + "]" ); + FWE_LOG_TRACE( std::string{ " TraceModule-ConsoleLogging-Variable '" } + variableName + "' [" + + std::to_string( i ) + "] current value: [" + std::to_string( v.mCurrentValue ) + + "] max value since last print: " + "[" + + std::to_string( v.mMaxValue ) + "] overall max value: [" + std::to_string( v.mMaxValueAllTime ) + + "]" ); } for ( auto i = 0; i < toUType( TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ); i++ ) { @@ -401,13 +405,12 @@ TraceModule::print() auto atomicVariableNamePtr = getAtomicVariableName( static_cast( i ) ); auto atomicVariableName = atomicVariableNamePtr != nullptr ? atomicVariableNamePtr : "Unknown atomic variable name"; - mLogger.trace( "TraceModule::print", - std::string{ " TraceModule-ConsoleLogging-TraceAtomicVariable '" } + atomicVariableName + "' [" + - std::to_string( i ) + "] current value: [" + std::to_string( v.mCurrentValue.load() ) + - "] max value since " - "last print: [" + - std::to_string( v.mMaxValue ) + "] overall max value: [" + - std::to_string( v.mMaxValueAllTime ) + "]" ); + FWE_LOG_TRACE( std::string{ " TraceModule-ConsoleLogging-TraceAtomicVariable '" } + atomicVariableName + "' [" + + std::to_string( i ) + "] current value: [" + std::to_string( v.mCurrentValue.load() ) + + "] max value since " + "last print: [" + + std::to_string( v.mMaxValue ) + "] overall max value: [" + std::to_string( v.mMaxValueAllTime ) + + "]" ); } for ( auto i = 0; i < toUType( TraceSection::TRACE_SECTION_SIZE ); i++ ) { @@ -415,19 +418,18 @@ TraceModule::print() auto currentHitCounter = v.mHitCounter - ( v.mCurrentlyActive ? 0 : 1 ); auto sectionNamePtr = getSectionName( static_cast( i ) ); auto sectionName = sectionNamePtr != nullptr ? sectionNamePtr : "Unknown section name"; - mLogger.trace( "TraceModule::print", - std::string{ " TraceModule-ConsoleLogging-Section '" } + sectionName + "' [" + - std::to_string( i ) + "] times section executed: [" + std::to_string( v.mHitCounter ) + - "] avg execution time: " - "[" + - std::to_string( ( v.mHitCounter == 0 ? 0 : v.mTimeSpentSum / v.mHitCounter ) ) + - "] max execution time since last print: [" + std::to_string( v.mMaxSpent ) + "] overall: [" + - std::to_string( v.mMaxSpentAllTime ) + - "] avg interval between execution: " - "[" + - std::to_string( ( currentHitCounter == 0 ? 0 : v.mIntervalSum / currentHitCounter ) ) + - "] max interval since last print: [" + std::to_string( v.mMaxInterval ) + "] overall: [" + - std::to_string( v.mMaxIntervalAllTime ) + "]" ); + FWE_LOG_TRACE( std::string{ " TraceModule-ConsoleLogging-Section '" } + sectionName + "' [" + + std::to_string( i ) + "] times section executed: [" + std::to_string( v.mHitCounter ) + + "] avg execution time: " + "[" + + std::to_string( ( v.mHitCounter == 0 ? 0 : v.mTimeSpentSum / v.mHitCounter ) ) + + "] max execution time since last print: [" + std::to_string( v.mMaxSpent ) + "] overall: [" + + std::to_string( v.mMaxSpentAllTime ) + + "] avg interval between execution: " + "[" + + std::to_string( ( currentHitCounter == 0 ? 0 : v.mIntervalSum / currentHitCounter ) ) + + "] max interval since last print: [" + std::to_string( v.mMaxInterval ) + "] overall: [" + + std::to_string( v.mMaxIntervalAllTime ) + "]" ); } std::fflush( stdout ); diff --git a/src/platform/linux/persistencymanagement/include/CacheAndPersist.h b/src/platform/linux/persistencymanagement/include/CacheAndPersist.h index 22511c9f..a3f06620 100644 --- a/src/platform/linux/persistencymanagement/include/CacheAndPersist.h +++ b/src/platform/linux/persistencymanagement/include/CacheAndPersist.h @@ -5,7 +5,6 @@ // Includes #include "ICacheAndPersist.h" -#include "LoggingModule.h" #include #include #include @@ -110,7 +109,6 @@ class CacheAndPersist : public ICacheAndPersist std::string mCollectionSchemeListFile; std::string mCollectedDataFile; size_t mMaxPersistencePartitionSize; - LoggingModule mLogger; /** * @brief checks if the specified file exists, if not creates a new one diff --git a/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp b/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp index 2445d9f6..685c0868 100644 --- a/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp +++ b/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp @@ -3,6 +3,7 @@ // Includes #include "CacheAndPersist.h" +#include "LoggingModule.h" #include #include #include @@ -26,24 +27,24 @@ CacheAndPersist::init() { if ( createFile( mDecoderManifestFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", "Failed to create decoder manifest file" ); + FWE_LOG_ERROR( "Failed to create decoder manifest file" ); return false; } if ( createFile( mCollectionSchemeListFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", "Failed to create collectionScheme list file" ); + FWE_LOG_ERROR( "Failed to create collectionScheme list file" ); return false; } if ( createFile( mCollectedDataFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", "Failed to create collected data file" ); + FWE_LOG_ERROR( "Failed to create collected data file" ); return false; } - mLogger.info( "PersistencyManagement::init", "Persistency library successfully initialised" ); + FWE_LOG_INFO( "Persistency library successfully initialised" ); return true; } @@ -114,7 +115,7 @@ CacheAndPersist::write( const uint8_t *bufPtr, size_t size, DataType dataType ) default: status = ErrorCode::INVALID_DATATYPE; - mLogger.error( "PersistencyManagement::write", "Invalid data type specified" ); + FWE_LOG_ERROR( "Invalid data type specified" ); return status; } @@ -132,7 +133,7 @@ CacheAndPersist::write( const uint8_t *bufPtr, size_t size, DataType dataType ) if ( !file.is_open() ) { status = ErrorCode::FILESYSTEM_ERROR; - mLogger.error( "PersistencyManagement::write", "Could not open file" ); + FWE_LOG_ERROR( "Could not open file" ); } else { @@ -140,7 +141,7 @@ CacheAndPersist::write( const uint8_t *bufPtr, size_t size, DataType dataType ) if ( !file.good() ) { status = ErrorCode::FILESYSTEM_ERROR; - mLogger.error( "PersistencyManagement::write", "Error writing to the file" ); + FWE_LOG_ERROR( "Error writing to the file" ); } file.close(); } @@ -170,7 +171,7 @@ CacheAndPersist::getSize( DataType dataType ) break; default: - mLogger.error( "PersistencyManagement::getSize", "Invalid data type specified" ); + FWE_LOG_ERROR( "Invalid data type specified" ); return INVALID_FILE_SIZE; } @@ -210,7 +211,7 @@ CacheAndPersist::read( uint8_t *const readBufPtr, size_t size, DataType dataType default: status = ErrorCode::INVALID_DATATYPE; - mLogger.error( "PersistencyManagement::read", "Invalid data type specified" ); + FWE_LOG_ERROR( "Invalid data type specified" ); return status; } @@ -218,7 +219,7 @@ CacheAndPersist::read( uint8_t *const readBufPtr, size_t size, DataType dataType if ( !file.is_open() ) { - mLogger.error( "PersistencyManagement::read", "Error opening file" ); + FWE_LOG_ERROR( "Error opening file" ); status = ErrorCode::FILESYSTEM_ERROR; } else @@ -235,7 +236,7 @@ CacheAndPersist::read( uint8_t *const readBufPtr, size_t size, DataType dataType // coverity[uninit_use_in_call : SUPPRESS] if ( file.fail() ) { - mLogger.error( "PersistencyManagement::read", "Error reading file" ); + FWE_LOG_ERROR( "Error reading file" ); status = ErrorCode::FILESYSTEM_ERROR; } } @@ -267,7 +268,7 @@ CacheAndPersist::erase( DataType dataType ) default: status = ErrorCode::INVALID_DATATYPE; - mLogger.error( "PersistencyManagement::erase", "Invalid data type specified" ); + FWE_LOG_ERROR( "Invalid data type specified" ); return status; } @@ -277,7 +278,7 @@ CacheAndPersist::erase( DataType dataType ) if ( !file.is_open() ) { status = ErrorCode::FILESYSTEM_ERROR; - mLogger.error( "PersistencyManagement::erase", "Error erasing the file" ); + FWE_LOG_ERROR( "Error erasing the file" ); } else { diff --git a/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h b/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h index 2973897b..ceeffe47 100644 --- a/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h +++ b/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h @@ -22,6 +22,8 @@ namespace Linux /** * @brief Utility class to track and report CPU commutative time usage. */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class CPUUsageInfo { public: diff --git a/src/platform/linux/resourcemanagement/include/MemoryUsageInfo.h b/src/platform/linux/resourcemanagement/include/MemoryUsageInfo.h index d85d808a..956760ed 100644 --- a/src/platform/linux/resourcemanagement/include/MemoryUsageInfo.h +++ b/src/platform/linux/resourcemanagement/include/MemoryUsageInfo.h @@ -5,6 +5,7 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes +#include #include namespace Aws diff --git a/src/platform/linux/test/valgrind.supp b/src/platform/linux/test/valgrind.supp new file mode 100644 index 00000000..00c906ed --- /dev/null +++ b/src/platform/linux/test/valgrind.supp @@ -0,0 +1,8 @@ +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/platform/linux/threadingmanagement/include/Signal.h b/src/platform/linux/threadingmanagement/include/Signal.h index 5db12806..26baa50b 100644 --- a/src/platform/linux/threadingmanagement/include/Signal.h +++ b/src/platform/linux/threadingmanagement/include/Signal.h @@ -21,6 +21,8 @@ namespace Linux /** * @brief Wrapper on top of a condition variable. Helps Thread state transitions. */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class Signal { public: diff --git a/src/platform/linux/threadingmanagement/src/Thread.cpp b/src/platform/linux/threadingmanagement/src/Thread.cpp index 16b623df..52a5c41b 100644 --- a/src/platform/linux/threadingmanagement/src/Thread.cpp +++ b/src/platform/linux/threadingmanagement/src/Thread.cpp @@ -86,10 +86,6 @@ Thread::isValid() const void * Thread::workerFunctionWrapper( void *params ) { - // POSIX settings - pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, nullptr ); - pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, nullptr ); - ThreadSettings *threadSettings = static_cast( params ); Thread *self = threadSettings->mSelf; diff --git a/src/platform/linux/timemanagement/src/ClockHandler.cpp b/src/platform/linux/timemanagement/src/ClockHandler.cpp index e49126fb..b9b24ba8 100644 --- a/src/platform/linux/timemanagement/src/ClockHandler.cpp +++ b/src/platform/linux/timemanagement/src/ClockHandler.cpp @@ -37,7 +37,9 @@ class ChronoClock : public Clock auto timeNow = std::chrono::system_clock::now(); auto ms = std::chrono::duration_cast( timeNow.time_since_epoch() ).count() % 1000; auto timeNowFormatted = std::chrono::system_clock::to_time_t( timeNow ); - timeAsString << std::put_time( std::gmtime( &timeNowFormatted ), "%FT%T." ) << std::setfill( '0' ) + struct tm tmStruct = {}; + // coverity[misra_cpp_2008_rule_18_0_4_violation] No C++14 method exists to convert from time_t to struct tm + timeAsString << std::put_time( gmtime_r( &timeNowFormatted, &tmStruct ), "%FT%T." ) << std::setfill( '0' ) << std::setw( 3 ) << ms << "Z"; return timeAsString.str(); } diff --git a/src/testingsupport/CMakeLists.txt b/src/testingsupport/CMakeLists.txt index eeb93fdf..cba58a1d 100644 --- a/src/testingsupport/CMakeLists.txt +++ b/src/testingsupport/CMakeLists.txt @@ -34,19 +34,24 @@ install( FILES include/Faketime.h include/Testing.h + include/WaitUntil.h DESTINATION include ) ### Tests ### -if(${BUILD_TESTING} AND FWE_TEST_FAKETIME) +if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") + if(FWE_TEST_FAKETIME) + set(EXTRA_TEST_FILES ${EXTRA_TEST_FILES} test/FakeSystemTimeTest.cpp) + endif() set( testSources - test/FakeSystemTimeTest.cpp + test/WaitUntilTest.cpp + ${EXTRA_TEST_FILES} ) - # Add the executable targets + # Add the executable targets foreach(testSource ${testSources}) # Need a name for each exec so use filename w/o extension get_filename_component(testName ${testSource} NAME_WE) @@ -61,7 +66,9 @@ if(${BUILD_TESTING} AND FWE_TEST_FAKETIME) IoTFleetWise::TestingSupport ) - add_unit_test_with_faketime(${testName}) + if(FWE_TEST_FAKETIME) + add_unit_test_with_faketime(${testName}) + endif() install(TARGETS ${testName} RUNTIME DESTINATION bin/tests) endforeach() diff --git a/src/testingsupport/include/Testing.h b/src/testingsupport/include/Testing.h index d40162bc..431cd14d 100644 --- a/src/testingsupport/include/Testing.h +++ b/src/testingsupport/include/Testing.h @@ -4,7 +4,9 @@ #pragma once // Includes +#include "SignalTypes.h" #include "TimeTypes.h" +#include namespace Aws { @@ -15,6 +17,7 @@ namespace TestingSupport using TimePoint = Aws::IoTFleetWise::Platform::Linux::TimePoint; using Timestamp = Aws::IoTFleetWise::Platform::Linux::Timestamp; +using SignalType = Aws::IoTFleetWise::DataManagement::SignalType; TimePoint operator+( const TimePoint &time, Timestamp increment ) @@ -43,6 +46,147 @@ operator==( const TimePoint &left, const TimePoint &right ) return left.systemTimeMs == right.systemTimeMs && left.monotonicTimeMs == right.monotonicTimeMs; } +template +constexpr SignalType +getSignalType() +{ + return SignalType::DOUBLE; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::UINT8; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::INT8; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::UINT16; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::INT16; +} +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::UINT32; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::INT32; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::UINT64; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::INT64; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::FLOAT; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::DOUBLE; +} + +template <> +constexpr SignalType +getSignalType() +{ + return SignalType::BOOLEAN; +} + +const auto allSignalTypes = testing::Values( SignalType::UINT8, + SignalType::INT8, + SignalType::UINT16, + SignalType::INT16, + SignalType::UINT32, + SignalType::INT32, + SignalType::UINT64, + SignalType::INT64, + SignalType::FLOAT, + SignalType::DOUBLE, + SignalType::BOOLEAN ); + +const auto signedSignalTypes = testing::Values( + SignalType::INT8, SignalType::INT16, SignalType::INT32, SignalType::INT64, SignalType::FLOAT, SignalType::DOUBLE ); + +/** + * @brief Converts SignalType to a string to be used in parametrized tests + * + * For more details, see: + * + * http://google.github.io/googletest/advanced.html#specifying-names-for-value-parameterized-test-parameters + * + * @param info + * @return A string that can be used as the parameter name + */ +std::string +signalTypeToString( const testing::TestParamInfo &info ) +{ + SignalType signalType = info.param; + switch ( signalType ) + { + case SignalType::UINT8: + return "UINT8"; + case SignalType::INT8: + return "INT8"; + case SignalType::UINT16: + return "UINT16"; + case SignalType::INT16: + return "INT16"; + case SignalType::UINT32: + return "UINT32"; + case SignalType::INT32: + return "INT32"; + case SignalType::UINT64: + return "UINT64"; + case SignalType::INT64: + return "INT64"; + case SignalType::FLOAT: + return "FLOAT"; + case SignalType::DOUBLE: + return "DOUBLE"; + case SignalType::BOOLEAN: + return "BOOLEAN"; + default: + throw std::invalid_argument( "Unsupported signal type" ); + } +} + } // namespace TestingSupport } // namespace IoTFleetWise } // namespace Aws diff --git a/src/testingsupport/include/WaitUntil.h b/src/testingsupport/include/WaitUntil.h new file mode 100644 index 00000000..6ae6594e --- /dev/null +++ b/src/testingsupport/include/WaitUntil.h @@ -0,0 +1,121 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include +#include + +#define WAIT_VAR_EXPAND( x, y ) x##y +#define WAIT_VAR( x, y ) WAIT_VAR_EXPAND( x, y ) + +/* + The following WAIT_ASSERT_* are adding extra retrial capability above the GoogleTest framework. + Some test cases need longer time to process before get expected outcome, so we need to wait and retry. +*/ +#define WAIT_ASSERT_TRUE( val ) ASSERT_TRUE( waitUntil( [&] { return ( val ); } ) ) +#define WAIT_ASSERT_FALSE( val ) ASSERT_TRUE( waitUntil( [&] { return !( val ); } ) ) + +#define WAIT_ASSERT_EQ( val1, val2 ) \ + auto WAIT_VAR( val1_, __LINE__ ) = val1; \ + auto WAIT_VAR( val2_, __LINE__ ) = val2; \ + if ( WAIT_VAR( val1_, __LINE__ ) != WAIT_VAR( val2_, __LINE__ ) ) \ + { \ + waitUntil( [&] { \ + WAIT_VAR( val1_, __LINE__ ) = val1; \ + WAIT_VAR( val2_, __LINE__ ) = val2; \ + return WAIT_VAR( val1_, __LINE__ ) == WAIT_VAR( val2_, __LINE__ ); \ + } ); \ + } \ + ASSERT_EQ( WAIT_VAR( val1_, __LINE__ ), WAIT_VAR( val2_, __LINE__ ) ) << "where val1 is " #val1 ", val2 is " #val2 + +#define WAIT_ASSERT_GT( val1, val2 ) \ + auto WAIT_VAR( val1_, __LINE__ ) = val1; \ + auto WAIT_VAR( val2_, __LINE__ ) = val2; \ + if ( WAIT_VAR( val1_, __LINE__ ) <= WAIT_VAR( val2_, __LINE__ ) ) \ + { \ + waitUntil( [&] { \ + WAIT_VAR( val1_, __LINE__ ) = val1; \ + WAIT_VAR( val2_, __LINE__ ) = val2; \ + return WAIT_VAR( val1_, __LINE__ ) > WAIT_VAR( val2_, __LINE__ ); \ + } ); \ + } \ + ASSERT_GT( WAIT_VAR( val1_, __LINE__ ), WAIT_VAR( val2_, __LINE__ ) ) << "where val1 is " #val1 ", val2 is " #val2 + +#define WAIT_ASSERT_LT( val1, val2 ) \ + auto WAIT_VAR( val1_, __LINE__ ) = val1; \ + auto WAIT_VAR( val2_, __LINE__ ) = val2; \ + if ( WAIT_VAR( val1_, __LINE__ ) >= WAIT_VAR( val2_, __LINE__ ) ) \ + { \ + waitUntil( [&] { \ + WAIT_VAR( val1_, __LINE__ ) = val1; \ + WAIT_VAR( val2_, __LINE__ ) = val2; \ + return WAIT_VAR( val1_, __LINE__ ) < WAIT_VAR( val2_, __LINE__ ); \ + } ); \ + } \ + ASSERT_LT( WAIT_VAR( val1_, __LINE__ ), WAIT_VAR( val2_, __LINE__ ) ) << "where val1 is " #val1 ", val2 is " #val2 + +/* + The following DELAYED_ASSERT_* are adding extra retrial capability above the GoogleTest framework. + Some test cases need to be continuously evaluated, and asserted only after the timeout occurs. +*/ +#define DELAY_ASSERT_TRUE( val ) ASSERT_TRUE( waitDelay( [&] { return ( val ); } ) ) +#define DELAY_ASSERT_FALSE( val ) ASSERT_FALSE( waitDelay( [&] { return ( val ); } ) ) + +namespace Aws +{ +namespace IoTFleetWise +{ +namespace TestingSupport +{ + +const auto WAIT_TIME_OUT = std::chrono::seconds( 5 ); + +/** + * @brief Wait and retry until the result of func becomes true + * @param func: The func needs to be retried. + * @return True when function returns true, or false if a timeout occurs. + */ +bool +waitUntil( std::function func ) +{ + auto retry_interval_ms = std::chrono::milliseconds( 10 ); + auto startTime = std::chrono::steady_clock::now(); + while ( !func() ) + { + auto elapsedTime = std::chrono::steady_clock::now() - startTime; + if ( elapsedTime >= WAIT_TIME_OUT ) + { + return false; + } + std::this_thread::sleep_for( retry_interval_ms ); + } + return true; +} + +/** + * @brief Repeatedly call the func, then return the last result after the timeout occurs + * @param func: The func needs to be retried. + * @return The last result of the func after the timeout. + */ +bool +waitDelay( std::function func ) +{ + auto retry_interval_ms = std::chrono::milliseconds( 10 ); + auto startTime = std::chrono::steady_clock::now(); + for ( ;; ) + { + auto res = func(); + auto elapsedTime = std::chrono::steady_clock::now() - startTime; + if ( elapsedTime >= WAIT_TIME_OUT ) + { + return res; + } + std::this_thread::sleep_for( retry_interval_ms ); + } +} + +} // namespace TestingSupport +} // namespace IoTFleetWise +} // namespace Aws diff --git a/src/testingsupport/test/WaitUntilTest.cpp b/src/testingsupport/test/WaitUntilTest.cpp new file mode 100644 index 00000000..8bcee975 --- /dev/null +++ b/src/testingsupport/test/WaitUntilTest.cpp @@ -0,0 +1,79 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#include "WaitUntil.h" +#include +#include +#include +#include +using namespace Aws::IoTFleetWise::TestingSupport; +using namespace std; + +TEST( TimerTest, waitUntilTest ) +{ + // A determent function with negative return, it will retry for `WAIT_TIME_OUT` + auto startTime = std::chrono::steady_clock::now(); + waitUntil( [] { return 1 == 2; } ); + auto elapsedTime = std::chrono::steady_clock::now() - startTime; + ASSERT_LT( WAIT_TIME_OUT, elapsedTime ); + + // A determent function with positive return, it won't retry or wait for `WAIT_TIME_OUT` + startTime = std::chrono::steady_clock::now(); + waitUntil( [] { return 1 == 1; } ); + elapsedTime = std::chrono::steady_clock::now() - startTime; + ASSERT_GT( WAIT_TIME_OUT, elapsedTime ); +} + +TEST( TimerTest, waitAssertEQ ) +{ + int val_1 = 1; + int val_expected = 2; + std::thread changeVal( [&val_1, val_expected]() { + std::this_thread::sleep_for( std::chrono::milliseconds( 5 ) ); + val_1 = val_expected; + } ); + changeVal.join(); + WAIT_ASSERT_EQ( val_1, val_expected ); +} + +TEST( TimerTest, expectTwoDiffValueTestToFail ) +{ + int val_1 = 1; + int val_expected = 2; + GTEST_SKIP() << "Skipping this single test"; // comment out when test locally if necessary + WAIT_ASSERT_EQ( val_1, val_expected ); +} + +TEST( TimerTest, waitAssertTrue ) +{ + std::vector signal{ 1 }; + WAIT_ASSERT_TRUE( !signal.empty() ); +} + +TEST( TimerTest, delayAssertTrue ) +{ + int i = 100; + auto countdown = [&] { + if ( i == 0 ) + { + return true; + } + i--; + return false; + }; + DELAY_ASSERT_TRUE( countdown() ); +} + +TEST( TimerTest, delayAssertFalse ) +{ + int i = 100; + auto countdown = [&] { + if ( i == 0 ) + { + return false; + } + i--; + return true; + }; + DELAY_ASSERT_FALSE( countdown() ); +} diff --git a/src/testingsupport/test/valgrind.supp b/src/testingsupport/test/valgrind.supp new file mode 100644 index 00000000..00c906ed --- /dev/null +++ b/src/testingsupport/test/valgrind.supp @@ -0,0 +1,8 @@ +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/src/vehiclenetwork/include/businterfaces/CANDataSource.h b/src/vehiclenetwork/include/businterfaces/CANDataSource.h index fb7eabfc..b2312a58 100644 --- a/src/vehiclenetwork/include/businterfaces/CANDataSource.h +++ b/src/vehiclenetwork/include/businterfaces/CANDataSource.h @@ -7,7 +7,6 @@ // Includes #include "AbstractVehicleDataSource.h" #include "ClockHandler.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -58,6 +57,8 @@ stringToCanTimestampType( std::string const ×tampType, CAN_TIMESTAMP_TYPE & * @brief Linux CAN Bus implementation. Uses Raw Sockets to listen to CAN * data on 1 single CAN IF. */ +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once +// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once class CANDataSource : public AbstractVehicleDataSource { public: @@ -110,7 +111,6 @@ class CANDataSource : public AbstractVehicleDataSource std::atomic mShouldSleep{ false }; mutable std::mutex mThreadMutex; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); int mSocket{ -1 }; Platform::Linux::Signal mWait; diff --git a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h index 1c09d6ae..80c5072e 100644 --- a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h +++ b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h @@ -6,7 +6,6 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes #include "ClockHandler.h" -#include "LoggingModule.h" #include "Timer.h" #include "datatypes/ISOTPOverCANOptions.h" #include @@ -50,7 +49,7 @@ class ISOTPOverCANReceiver * @brief Close the Socket between the source and the destination * @return True if success, False otherwise */ - bool disconnect(); + bool disconnect() const; /** * @brief Checks the health state of the connection. @@ -81,7 +80,6 @@ class ISOTPOverCANReceiver private: ISOTPOverCANReceiverOptions mReceiverOptions; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); int mSocket{}; }; diff --git a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSender.h b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSender.h index 0ff35e2a..d53d73d0 100644 --- a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSender.h +++ b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSender.h @@ -6,7 +6,6 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes #include "ClockHandler.h" -#include "LoggingModule.h" #include "Timer.h" #include "datatypes/ISOTPOverCANOptions.h" #include @@ -50,7 +49,7 @@ class ISOTPOverCANSender * @brief Close the Socket between the source and the destination * @return True if success, False otherwise */ - bool disconnect(); + bool disconnect() const; /** * @brief Checks the health state of the connection. @@ -64,12 +63,11 @@ class ISOTPOverCANSender * @param pduData byte array * @return True if send, False otherwise */ - bool sendPDU( const std::vector &pduData ); + bool sendPDU( const std::vector &pduData ) const; private: ISOTPOverCANSenderOptions mSenderOptions; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); int mSocket{}; }; diff --git a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h index d0c2844d..4d3bf8ac 100644 --- a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h +++ b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h @@ -6,7 +6,6 @@ #if defined( IOTFLEETWISE_LINUX ) // Includes #include "ClockHandler.h" -#include "LoggingModule.h" #include "Timer.h" #include "datatypes/ISOTPOverCANOptions.h" #include @@ -96,7 +95,6 @@ class ISOTPOverCANSenderReceiver private: ISOTPOverCANSenderReceiverOptions mSenderReceiverOptions; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); int mSocket{}; std::string mStreamRxID; diff --git a/src/vehiclenetwork/include/datatypes/VehicleDataSourceTypes.h b/src/vehiclenetwork/include/datatypes/VehicleDataSourceTypes.h index 17af169e..ce04d1f2 100644 --- a/src/vehiclenetwork/include/datatypes/VehicleDataSourceTypes.h +++ b/src/vehiclenetwork/include/datatypes/VehicleDataSourceTypes.h @@ -54,7 +54,7 @@ enum class VehicleDataSourceState // ECU IDs enum class ECUID { - INVALID_ECU_ID, + INVALID_ECU_ID = 0, BROADCAST_ID = 0x7DF, BROADCAST_EXTENDED_ID = 0x18DB33F1, LOWEST_ECU_EXTENDED_RX_ID = 0x18DAF100, diff --git a/src/vehiclenetwork/include/dds/CameraDataPublisher.h b/src/vehiclenetwork/include/dds/CameraDataPublisher.h index da31e289..61a3acd7 100644 --- a/src/vehiclenetwork/include/dds/CameraDataPublisher.h +++ b/src/vehiclenetwork/include/dds/CameraDataPublisher.h @@ -7,7 +7,6 @@ #include "CameraPubSubTypes.h" #include "ClockHandler.h" #include "IDDSPublisher.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -81,7 +80,6 @@ class CameraDataPublisher : public IDDSPublisher std::atomic mRequestCompleted{ true }; mutable std::mutex mThreadMutex; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); Platform::Linux::Signal mWait; DomainParticipant *mDDSParticipant{ nullptr }; diff --git a/src/vehiclenetwork/include/dds/CameraDataSubscriber.h b/src/vehiclenetwork/include/dds/CameraDataSubscriber.h index c5f200e6..c3c3d5cc 100644 --- a/src/vehiclenetwork/include/dds/CameraDataSubscriber.h +++ b/src/vehiclenetwork/include/dds/CameraDataSubscriber.h @@ -7,7 +7,6 @@ #include "CameraPubSubTypes.h" #include "ClockHandler.h" #include "IDDSSubscriber.h" -#include "LoggingModule.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -94,7 +93,6 @@ class CameraDataSubscriber : public IDDSSubscriber std::atomic mNewResponseReceived{ false }; mutable std::mutex mThreadMutex; Timer mTimer; - LoggingModule mLogger; std::shared_ptr mClock = ClockHandler::getClock(); Platform::Linux::Signal mWait; CameraDataItem mDataItem; diff --git a/src/vehiclenetwork/src/CANDataSource.cpp b/src/vehiclenetwork/src/CANDataSource.cpp index baceaa14..4ffd86fd 100644 --- a/src/vehiclenetwork/src/CANDataSource.cpp +++ b/src/vehiclenetwork/src/CANDataSource.cpp @@ -6,6 +6,7 @@ #include "businterfaces/CANDataSource.h" #include "ClockHandler.h" #include "EnumUtility.h" +#include "LoggingModule.h" #include "TraceModule.h" #include #include @@ -58,13 +59,13 @@ CANDataSource::init( const std::vector &sourceConfigs ) // one single thread. if ( ( sourceConfigs.size() > 1 ) || sourceConfigs.empty() ) { - mLogger.error( "CANDataSource::init", "Only one source config is supported" ); + FWE_LOG_ERROR( "Only one source config is supported" ); return false; } auto settingsIterator = sourceConfigs[0].transportProperties.find( std::string( INTERFACE_NAME_KEY ) ); if ( settingsIterator == sourceConfigs[0].transportProperties.end() ) { - mLogger.error( "CANDataSource::init", "Could not find interfaceName in the config" ); + FWE_LOG_ERROR( "Could not find interfaceName in the config" ); return false; } else @@ -77,7 +78,7 @@ CANDataSource::init( const std::vector &sourceConfigs ) settingsIterator = sourceConfigs[0].transportProperties.find( std::string( THREAD_IDLE_TIME_KEY ) ); if ( settingsIterator == sourceConfigs[0].transportProperties.end() ) { - mLogger.error( "CANDataSource::init", "Could not find threadIdleTimeMs in the config" ); + FWE_LOG_ERROR( "Could not find threadIdleTimeMs in the config" ); return false; } else @@ -88,8 +89,7 @@ CANDataSource::init( const std::vector &sourceConfigs ) } catch ( const std::exception &e ) { - mLogger.error( "CANDataSource::init", - "Could not cast the threadIdleTimeMs, invalid input: " + std::string( e.what() ) ); + FWE_LOG_ERROR( "Could not cast the threadIdleTimeMs, invalid input: " + std::string( e.what() ) ); return false; } } @@ -97,7 +97,7 @@ CANDataSource::init( const std::vector &sourceConfigs ) settingsIterator = sourceConfigs[0].transportProperties.find( std::string( PROTOCOL_NAME_KEY ) ); if ( settingsIterator == sourceConfigs[0].transportProperties.end() ) { - mLogger.error( "CANDataSource::init", "Could not find protocolName in the config" ); + FWE_LOG_ERROR( "Could not find protocolName in the config" ); return false; } else @@ -122,11 +122,11 @@ CANDataSource::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CANDataSource::start", "Thread failed to start" ); + FWE_LOG_TRACE( "CAN Data Source Thread failed to start" ); } else { - mLogger.trace( "CANDataSource::start", "Thread started" ); + FWE_LOG_TRACE( "CAN Data Source Thread started" ); mThread.setThreadName( "fwVNLinuxCAN" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -136,8 +136,7 @@ void CANDataSource::suspendDataAcquisition() { // Go back to sleep - mLogger.trace( "CANDataSource::suspendDataAcquisition", - "Going to sleep until a the resume signal. CAN Data Source: " + std::to_string( mID ) ); + FWE_LOG_TRACE( "Going to sleep until a the resume signal. CAN Data Source: " + std::to_string( mID ) ); mShouldSleep.store( true, std::memory_order_relaxed ); } @@ -145,8 +144,7 @@ void CANDataSource::resumeDataAcquisition() { - mLogger.trace( "CANDataSource::resumeDataAcquisition", - "Resuming Network data acquisition on Data Source: " + std::to_string( mID ) ); + FWE_LOG_TRACE( "Resuming Network data acquisition on Data Source: " + std::to_string( mID ) ); // Make sure the thread does not sleep anymore mResumeTime = mClock->systemTimeSinceEpochMs(); mShouldSleep.store( false ); @@ -162,7 +160,7 @@ CANDataSource::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CANDataSource::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); return !mThread.isActive(); } @@ -181,6 +179,9 @@ CANDataSource::shouldSleep() const Timestamp CANDataSource::extractTimestamp( struct msghdr *msgHeader ) { + // This is a Linux header macro + // coverity[misra_cpp_2008_rule_5_2_9_violation] + // coverity[autosar_cpp14_m5_2_9_violation] // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) struct cmsghdr *currentHeader = CMSG_FIRSTHDR( msgHeader ); Timestamp timestamp = 0; @@ -241,8 +242,7 @@ CANDataSource::doWork( void *data ) { // We either just started or there was a decoder manifest update that we can't use // We should sleep - dataSource->mLogger.trace( "CANDataSource::doWork", - "No valid decoding dictionary available, channel going to sleep" ); + FWE_LOG_TRACE( "No valid decoding dictionary available, Channel going to sleep" ); dataSource->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); wokeUpFromSleep = true; } @@ -253,8 +253,7 @@ CANDataSource::doWork( void *data ) struct iovec frame_buffer[PARALLEL_RECEIVED_FRAMES_FROM_KERNEL]; struct mmsghdr msg[PARALLEL_RECEIVED_FRAMES_FROM_KERNEL]; // we expect only one timestamp to return - char cmsgReturnBuffer[PARALLEL_RECEIVED_FRAMES_FROM_KERNEL][CMSG_SPACE( sizeof( struct scm_timestamping ) )] = { - { 0 } }; + char cmsgReturnBuffer[PARALLEL_RECEIVED_FRAMES_FROM_KERNEL][CMSG_SPACE( sizeof( struct scm_timestamping ) )]{}; // Setup all buffer to receive data for ( int i = 0; i < PARALLEL_RECEIVED_FRAMES_FROM_KERNEL; i++ ) @@ -281,15 +280,15 @@ CANDataSource::doWork( void *data ) TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::NOT_TIME_MONOTONIC_FRAMES ); } // After waking up the Socket Can old messages in the kernel queue need to be ignored - if ( ( !wokeUpFromSleep ) || ( timestamp >= dataSource->mResumeTime ) ) + if ( !wokeUpFromSleep ) { lastFrameTime = timestamp; dataSource->receivedMessages++; TraceVariable traceFrames = static_cast( dataSource->mID + toUType( TraceVariable::READ_SOCKET_FRAMES_0 ) ); - TraceModule::get().setVariable( ( traceFrames < TraceVariable::READ_SOCKET_FRAMES_MAX ) + TraceModule::get().setVariable( ( traceFrames < TraceVariable::READ_SOCKET_FRAMES_19 ) ? traceFrames - : TraceVariable::READ_SOCKET_FRAMES_MAX, + : TraceVariable::READ_SOCKET_FRAMES_19, dataSource->receivedMessages ); rawData.reserve( frame[i].len ); for ( size_t j = 0; j < frame[i].len; ++j ) @@ -304,12 +303,12 @@ CANDataSource::doWork( void *data ) dataSource->discardedMessages++; TraceModule::get().setVariable( TraceVariable::DISCARDED_FRAMES, dataSource->discardedMessages ); - dataSource->mLogger.warn( "CANDataSource::doWork", "Circular Buffer is full" ); + FWE_LOG_WARN( "Circular Buffer is full" ); } } else { - dataSource->mLogger.warn( "CANDataSource::doWork", "Message is not valid" ); + FWE_LOG_WARN( "Message is not valid" ); } } } @@ -318,11 +317,11 @@ CANDataSource::doWork( void *data ) if ( logTimer.getElapsedMs().count() > static_cast( LoggingModule::LOG_AGGREGATION_TIME_MS ) ) { // Nothing is in the ring buffer to consume. Go to idle mode for some time. - dataSource->mLogger.trace( - "CANDataSource::doWork", + FWE_LOG_TRACE( + "Activations: " + std::to_string( activations ) + - ". Waiting for some data to come. Idling for :" + std::to_string( dataSource->mIdleTimeMs ) + - " ms, processed " + std::to_string( dataSource->receivedMessages ) + " frames" ); + ". Waiting for some data to come. Idling for :" + std::to_string( dataSource->mIdleTimeMs ) + + " ms, processed " + std::to_string( dataSource->receivedMessages ) + " frames" ); activations = 0; logTimer.reset(); } @@ -352,13 +351,12 @@ CANDataSource::connect() { if ( mForceCanFD ) { - mLogger.error( "CANDataSource::connect", "setsockopt CAN_RAW_FD_FRAMES FAILED" ); + FWE_LOG_ERROR( "setsockopt CAN_RAW_FD_FRAMES FAILED" ); return false; } else { - mLogger.info( "CANDataSource::connect", - "setsockopt CAN_RAW_FD_FRAMES FAILED, falling back to regular CAN" ); + FWE_LOG_INFO( "setsockopt CAN_RAW_FD_FRAMES FAILED, falling back to regular CAN" ); } } @@ -371,7 +369,7 @@ CANDataSource::connect() if ( ioctl( mSocket, SIOCGIFINDEX, &interfaceRequest ) != 0 ) { - mLogger.error( "CANDataSource::connect", "CAN Interface with name " + mIfName + " is not accessible" ); + FWE_LOG_ERROR( "CAN Interface with name " + mIfName + " is not accessible" ); close( mSocket ); return false; } @@ -382,8 +380,7 @@ CANDataSource::connect() SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE ); if ( setsockopt( mSocket, SOL_SOCKET, SO_TIMESTAMPING, ×tampFlags, sizeof( timestampFlags ) ) != 0 ) { - mLogger.error( "CANDataSource::connect", - "Hardware timestamp not supported by socket but requested by config" ); + FWE_LOG_ERROR( "Hardware timestamp not supported by socket but requested by config" ); close( mSocket ); return false; } diff --git a/src/vehiclenetwork/src/CameraDataPublisher.cpp b/src/vehiclenetwork/src/CameraDataPublisher.cpp index 57d53370..c12417d1 100644 --- a/src/vehiclenetwork/src/CameraDataPublisher.cpp +++ b/src/vehiclenetwork/src/CameraDataPublisher.cpp @@ -4,6 +4,7 @@ // Includes #include "dds/CameraDataPublisher.h" #include "ClockHandler.h" +#include "LoggingModule.h" #include #include #include @@ -28,7 +29,7 @@ CameraDataPublisher::~CameraDataPublisher() stop(); } - // Clean up the ressources + // Clean up the resources if ( mDDSWriter != nullptr ) { mDDSPublisher->delete_datawriter( mDDSWriter ); @@ -75,7 +76,7 @@ CameraDataPublisher::init( const DDSDataSourceConfig &dataSourceConfig ) } else if ( dataSourceConfig.transportType == DDSTransportType::TCP ) { - mLogger.trace( "CameraDataPublisher::init", "TCP Transport is NOT yet supported" ); + FWE_LOG_TRACE( "TCP Transport is NOT yet supported" ); return false; } // Create the DDS participant @@ -121,11 +122,11 @@ CameraDataPublisher::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CameraDataPublisher::start", "Thread failed to start" ); + FWE_LOG_TRACE( "Thread failed to start" ); } else { - mLogger.trace( "CameraDataPublisher::start", "Thread started" ); + FWE_LOG_TRACE( "Thread started" ); mThread.setThreadName( "fwVNDDSCamPub" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -139,7 +140,7 @@ CameraDataPublisher::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CameraDataPublisher::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); return !mThread.isActive(); } @@ -166,7 +167,7 @@ CameraDataPublisher::doWork( void *data ) { publisher->mDDSWriter->write( &publisher->mRequest ); publisher->mRequestCompleted.store( true ); - publisher->mLogger.trace( "CameraDataPublisher::doWork", "Data request send to the remote node" ); + FWE_LOG_TRACE( "Data request send to the remote node" ); } } } @@ -198,7 +199,7 @@ CameraDataPublisher::on_publication_matched( DataWriter *writer, const Publicati if ( info.current_count_change == 1 ) { mIsAlive.store( true, std::memory_order_relaxed ); - mLogger.trace( "CameraDataPublisher::on_publication_matched", "A subscriber is available" ); + FWE_LOG_TRACE( "A subscriber is available" ); } else if ( info.current_count_change == -1 ) { @@ -219,7 +220,7 @@ CameraDataPublisher::publishDataRequest( const DDSDataRequest &dataRequest ) mRequestCompleted.store( false ); } - mLogger.trace( "CameraDataPublisher::publishDataRequest", "Request queued for sending" ); + FWE_LOG_TRACE( "Request queued for sending" ); mWait.notify(); } diff --git a/src/vehiclenetwork/src/CameraDataSubscriber.cpp b/src/vehiclenetwork/src/CameraDataSubscriber.cpp index a0fc9ffc..b0007c08 100644 --- a/src/vehiclenetwork/src/CameraDataSubscriber.cpp +++ b/src/vehiclenetwork/src/CameraDataSubscriber.cpp @@ -4,6 +4,7 @@ // Includes #include "dds/CameraDataSubscriber.h" #include "ClockHandler.h" +#include "LoggingModule.h" #include #include #include @@ -29,7 +30,7 @@ CameraDataSubscriber::~CameraDataSubscriber() stop(); } - // Clean up the ressources + // Clean up the resources if ( mDDSReader != nullptr ) { mDDSSubscriber->delete_datareader( mDDSReader ); @@ -75,7 +76,7 @@ CameraDataSubscriber::init( const DDSDataSourceConfig &dataSourceConfig ) } else if ( dataSourceConfig.transportType == DDSTransportType::TCP ) { - mLogger.trace( "CameraDataSubscriber::init", "TCP Transport is NOT yet supported" ); + FWE_LOG_TRACE( "TCP Transport is NOT yet supported" ); return false; } // Create the DDS participant @@ -124,11 +125,11 @@ CameraDataSubscriber::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CameraDataSubscriber::start", "Thread failed to start" ); + FWE_LOG_TRACE( "Thread failed to start" ); } else { - mLogger.trace( "CameraDataSubscriber::start", "Thread started" ); + FWE_LOG_TRACE( "Thread started" ); mThread.setThreadName( "fwVNDDSCamSub" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -142,7 +143,7 @@ CameraDataSubscriber::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CameraDataSubscriber::stop", "Thread stopped" ); + FWE_LOG_TRACE( "Thread stopped" ); return !mThread.isActive(); } @@ -177,13 +178,11 @@ CameraDataSubscriber::doWork( void *data ) { subscriber->notifyListeners( &SensorDataListener::onSensorArtifactAvailable, cameraArtifact ); - subscriber->mLogger.info( "CameraDataSubscriber::doWork", - "Data Collected from the Camera and made available" ); + FWE_LOG_INFO( "Data Collected from the Camera and made available" ); } else { - subscriber->mLogger.error( "CameraDataSubscriber::doWork", - "Could not persist the data received into disk" ); + FWE_LOG_ERROR( "Could not persist the data received into disk" ); } // Reset the response @@ -218,7 +217,7 @@ CameraDataSubscriber::on_subscription_matched( DataReader *reader, const Subscri if ( info.current_count_change == 1 ) { mIsAlive.store( true, std::memory_order_relaxed ); - mLogger.trace( "CameraDataSubscriber::on_subscription_matched", "A publisher is available" ); + FWE_LOG_TRACE( "A publisher is available" ); } else if ( info.current_count_change == -1 ) { @@ -235,7 +234,7 @@ CameraDataSubscriber::on_data_available( DataReader *reader ) if ( info.valid_data ) { mNewResponseReceived.store( true, std::memory_order_relaxed ); - mLogger.trace( "CameraDataSubscriber::on_data_available", "Data received from the DDS Node" ); + FWE_LOG_TRACE( "Data received from the DDS Node" ); mWait.notify(); } } diff --git a/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp b/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp index 37b99821..c308c0e5 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp @@ -5,6 +5,7 @@ // Includes #include "businterfaces/ISOTPOverCANReceiver.h" #include "ClockHandler.h" +#include "LoggingModule.h" #include #include #include @@ -62,8 +63,7 @@ ISOTPOverCANReceiver::connect() mSocket = socket( PF_CAN, SOCK_DGRAM /*| SOCK_NONBLOCK*/, CAN_ISOTP ); if ( mSocket < 0 ) { - mLogger.error( "ISOTPOverCANReceiver::connect", - "Failed to create the ISOTP Socket to IF: " + mReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to create the ISOTP Socket to IF: " + mReceiverOptions.mSocketCanIFName ); return false; } @@ -74,7 +74,7 @@ ISOTPOverCANReceiver::connect() if ( ( retOptFlag < 0 ) || ( retFrameCtrFlag < 0 ) ) { - mLogger.error( "ISOTPOverCANReceiver::connect", "Failed to set ISO-TP socket option flags" ); + FWE_LOG_ERROR( "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -85,27 +85,23 @@ ISOTPOverCANReceiver::connect() // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) if ( bind( mSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { - mLogger.error( "ISOTPOverCANReceiver::connect", - "Failed to bind the ISOTP Socket to IF: " + mReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to bind the ISOTP Socket to IF: " + mReceiverOptions.mSocketCanIFName ); close( mSocket ); return false; } - mLogger.trace( "ISOTPOverCANReceiver::connect", - "ISOTP Socket connected to IF: " + mReceiverOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP Socket connected to IF: " + mReceiverOptions.mSocketCanIFName ); return true; } bool -ISOTPOverCANReceiver::disconnect() +ISOTPOverCANReceiver::disconnect() const { if ( close( mSocket ) < 0 ) { - mLogger.error( "ISOTPOverCANReceiver::connect", - "Failed to disconnect the ISOTP Socket from IF: " + mReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to disconnect the ISOTP Socket from IF: " + mReceiverOptions.mSocketCanIFName ); return false; } - mLogger.trace( "ISOTPOverCANReceiver::disconnect", - "ISOTP Socket disconnected from IF: " + mReceiverOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP Socket disconnected from IF: " + mReceiverOptions.mSocketCanIFName ); return true; } @@ -136,7 +132,7 @@ ISOTPOverCANReceiver::receivePDU( std::vector &pduData ) pduData.resize( MAX_PDU_SIZE ); // coverity[check_return : SUPPRESS] int bytesRead = static_cast( read( mSocket, pduData.data(), MAX_PDU_SIZE ) ); - mLogger.trace( "ISOTPOverCANReceiver::receivePDU", "Received a PDU of size: " + std::to_string( bytesRead ) ); + FWE_LOG_TRACE( "Received a PDU of size: " + std::to_string( bytesRead ) ); // Remove the unnecessary bytes from the PDU container. if ( bytesRead > 0 ) { diff --git a/src/vehiclenetwork/src/ISOTPOverCANSender.cpp b/src/vehiclenetwork/src/ISOTPOverCANSender.cpp index 91c3649c..9835cf42 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANSender.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANSender.cpp @@ -5,6 +5,7 @@ // Includes #include "businterfaces/ISOTPOverCANSender.h" #include "ClockHandler.h" +#include "LoggingModule.h" #include #include #include @@ -50,8 +51,7 @@ ISOTPOverCANSender::connect() mSocket = socket( PF_CAN, SOCK_DGRAM /*| SOCK_NONBLOCK*/, CAN_ISOTP ); if ( mSocket < 0 ) { - mLogger.error( "ISOTPOverCANSender::connect", - "Failed to create the ISOTP Socket to IF: " + mSenderOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to create the ISOTP Socket to IF: " + mSenderOptions.mSocketCanIFName ); return false; } @@ -59,7 +59,7 @@ ISOTPOverCANSender::connect() int retOptFlag = setsockopt( mSocket, SOL_CAN_ISOTP, CAN_ISOTP_OPTS, &optionalFlags, sizeof( optionalFlags ) ); if ( retOptFlag < 0 ) { - mLogger.error( "ISOTPOverCANSender::connect", "Failed to set ISO-TP socket option flags" ); + FWE_LOG_ERROR( "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -70,26 +70,23 @@ ISOTPOverCANSender::connect() // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) if ( bind( mSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { - mLogger.error( "ISOTPOverCANSender::connect", - "Failed to bind the ISOTP Socket to IF: " + mSenderOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to bind the ISOTP Socket to IF: " + mSenderOptions.mSocketCanIFName ); close( mSocket ); return false; } - mLogger.trace( "ISOTPOverCANSender::connect", "ISOTP Socket connected to IF: " + mSenderOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP Socket connected to IF: " + mSenderOptions.mSocketCanIFName ); return true; } bool -ISOTPOverCANSender::disconnect() +ISOTPOverCANSender::disconnect() const { if ( close( mSocket ) < 0 ) { - mLogger.error( "ISOTPOverCANSender::connect", - "Failed to disconnect the ISOTP Socket from IF: " + mSenderOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to disconnect the ISOTP Socket from IF: " + mSenderOptions.mSocketCanIFName ); return false; } - mLogger.trace( "ISOTPOverCANSender::disconnect", - "ISOTP Socket disconnected from IF: " + mSenderOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP Socket disconnected from IF: " + mSenderOptions.mSocketCanIFName ); return true; } @@ -104,10 +101,10 @@ ISOTPOverCANSender::isAlive() const } bool -ISOTPOverCANSender::sendPDU( const std::vector &pduData ) +ISOTPOverCANSender::sendPDU( const std::vector &pduData ) const { int bytesWritten = static_cast( write( mSocket, pduData.data(), pduData.size() ) ); - mLogger.trace( "ISOTPOverCANSender::sendPDU", "Sent a PDU of size: " + std::to_string( bytesWritten ) ); + FWE_LOG_TRACE( "Dent a PDU of size: " + std::to_string( bytesWritten ) ); return ( ( bytesWritten > 0 ) && ( bytesWritten == static_cast( pduData.size() ) ) ); } diff --git a/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp b/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp index 9fe1cbd0..3629064f 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp @@ -5,6 +5,7 @@ // Includes #include "businterfaces/ISOTPOverCANSenderReceiver.h" #include "ClockHandler.h" +#include "LoggingModule.h" #include #include #include @@ -67,9 +68,8 @@ ISOTPOverCANSenderReceiver::connect() mSocket = socket( PF_CAN, SOCK_DGRAM, CAN_ISOTP ); if ( mSocket < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::connect", - "Failed to create the ISOTP rx id " + mStreamRxID + - " to IF: " + mSenderReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to create the ISOTP rx id " + mStreamRxID + + " to IF:" + mSenderReceiverOptions.mSocketCanIFName ); return false; } @@ -81,7 +81,7 @@ ISOTPOverCANSenderReceiver::connect() if ( ( retOptFlag < 0 ) || ( retFrameCtrFlag < 0 ) ) { - mLogger.error( "ISOTPOverCANSenderReceiver::connect", "Failed to set ISO-TP socket option flags" ); + FWE_LOG_ERROR( "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -93,14 +93,12 @@ ISOTPOverCANSenderReceiver::connect() // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) if ( bind( mSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::connect", - "Failed to bind the ISOTP rx id " + mStreamRxID + - " to IF: " + mSenderReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( " Failed to bind the ISOTP rx id " + mStreamRxID + + " to IF: " + mSenderReceiverOptions.mSocketCanIFName ); close( mSocket ); return false; } - mLogger.trace( "ISOTPOverCANSenderReceiver::connect", - "ISOTP rx id " + mStreamRxID + " connected to IF: " + mSenderReceiverOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP rx id " + mStreamRxID + " connected to IF: " + mSenderReceiverOptions.mSocketCanIFName ); return true; } @@ -109,13 +107,11 @@ ISOTPOverCANSenderReceiver::disconnect() { if ( close( mSocket ) < 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::connect", - "Failed to disconnect the ISOTP rx id " + mStreamRxID + - " from IF: " + mSenderReceiverOptions.mSocketCanIFName ); + FWE_LOG_ERROR( "Failed to disconnect the ISOTP rx id " + mStreamRxID + + " from IF: " + mSenderReceiverOptions.mSocketCanIFName ); return false; } - mLogger.trace( "ISOTPOverCANSenderReceiver::disconnect", - "ISOTP rx id " + mStreamRxID + " disconnected from IF: " + mSenderReceiverOptions.mSocketCanIFName ); + FWE_LOG_TRACE( "ISOTP rx id " + mStreamRxID + " disconnected from IF: " + mSenderReceiverOptions.mSocketCanIFName ); return true; } @@ -148,9 +144,8 @@ ISOTPOverCANSenderReceiver::flush( uint32_t timeout ) auto readRes = read( mSocket, flushBuffer.data(), MAX_PDU_SIZE ); if ( readRes <= 0 ) { - mLogger.error( "ISOTPOverCANSenderReceiver::flush", - "Failed to read PDU from socket: " + mStreamRxID + " with error code " + - std::to_string( readRes ) ); + FWE_LOG_ERROR( "Failed to read PDU from socket: " + mStreamRxID + " with error code " + + std::to_string( readRes ) ); } return pollNeededTime; } @@ -166,15 +161,13 @@ ISOTPOverCANSenderReceiver::receivePDU( std::vector &pduData ) { // Responses are not always expected, so use trace level logging. E.g. supported PID requests for // unsupported PIDs can be ignored by some ECUs. - mLogger.trace( "ISOTPOverCANSenderReceiver::receivePDU", - "Timeout reading PDU from socket: " + mStreamRxID ); + FWE_LOG_TRACE( "Timeout reading PDU from socket: " + mStreamRxID ); return false; } if ( res < 0 ) { - mLogger.warn( "ISOTPOverCANSenderReceiver::receivePDU", - "Failed to read PDU from socket: " + mStreamRxID + " with error code " + - std::to_string( res ) ); + FWE_LOG_WARN( "Failed to read PDU from socket: " + mStreamRxID + " with error code " + + std::to_string( res ) ); // Error (<0) or timeout (==0): return false; } @@ -192,9 +185,8 @@ ISOTPOverCANSenderReceiver::receivePDU( std::vector &pduData ) { pduData.resize( 0 ); } - mLogger.traceBytesInVector( "ISOTPOverCANSenderReceiver::receivePDU", - "Socket: " + mStreamRxID + " received a PDU of size " + std::to_string( bytesRead ), - pduData ); + FWE_LOG_TRACE( "Socket: " + mStreamRxID + " received a PDU of size " + std::to_string( bytesRead ) + ": " + + getStringFromBytes( pduData ) ); return bytesRead > 0; } @@ -204,9 +196,8 @@ ISOTPOverCANSenderReceiver::sendPDU( const std::vector &pduData ) { auto socket = mSenderReceiverOptions.mBroadcastSocket < 0 ? mSocket : mSenderReceiverOptions.mBroadcastSocket; int bytesWritten = static_cast( write( socket, pduData.data(), pduData.size() ) ); - mLogger.traceBytesInVector( "ISOTPOverCANSenderReceiver::sendPDU", - "Socket: " + mStreamRxID + " sent a PDU of size " + std::to_string( bytesWritten ), - pduData ); + FWE_LOG_TRACE( "Socket: " + mStreamRxID + " sent a PDU of size " + std::to_string( bytesWritten ) + ": " + + getStringFromBytes( pduData ) ); return ( ( bytesWritten > 0 ) && ( bytesWritten == static_cast( pduData.size() ) ) ); } diff --git a/src/vehiclenetwork/test/CANDataSourceTest.cpp b/src/vehiclenetwork/test/CANDataSourceTest.cpp index e9883419..afda7302 100644 --- a/src/vehiclenetwork/test/CANDataSourceTest.cpp +++ b/src/vehiclenetwork/test/CANDataSourceTest.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "businterfaces/CANDataSource.h" +#include "WaitUntil.h" #include #include #include @@ -15,6 +16,7 @@ #include #include +using namespace Aws::IoTFleetWise::TestingSupport; using namespace Aws::IoTFleetWise::VehicleNetwork; static void @@ -99,7 +101,7 @@ class LocalDataSourceEventListener : public VehicleDataSourceListener bool gotDisConnectCallback; }; -static void +static bool sendTestMessage( int socketFD ) { struct can_frame frame = {}; @@ -110,10 +112,11 @@ sendTestMessage( int socketFD ) frame.data[i] = i; } ssize_t bytesWritten = write( socketFD, &frame, sizeof( struct can_frame ) ); - ASSERT_EQ( bytesWritten, sizeof( struct can_frame ) ); + EXPECT_EQ( bytesWritten, sizeof( struct can_frame ) ); + return true; } -static void +static bool sendTestFDMessage( int socketFD ) { struct canfd_frame frame = {}; @@ -124,10 +127,11 @@ sendTestFDMessage( int socketFD ) frame.data[i] = i; } ssize_t bytesWritten = write( socketFD, &frame, sizeof( struct canfd_frame ) ); - ASSERT_EQ( bytesWritten, sizeof( struct canfd_frame ) ); + EXPECT_EQ( bytesWritten, sizeof( struct canfd_frame ) ); + return true; } -static void +static bool sendTestMessageExtendedID( int socketFD ) { struct can_frame frame = {}; @@ -139,7 +143,8 @@ sendTestMessageExtendedID( int socketFD ) frame.data[i] = i; } ssize_t bytesWritten = write( socketFD, &frame, sizeof( struct can_frame ) ); - ASSERT_EQ( bytesWritten, sizeof( struct can_frame ) ); + EXPECT_EQ( bytesWritten, sizeof( struct can_frame ) ); + return true; } class CANDataSourceTest : public ::testing::Test @@ -174,7 +179,7 @@ TEST_F( CANDataSourceTest, testAquireDataFromNetwork ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -189,11 +194,8 @@ TEST_F( CANDataSourceTest, testAquireDataFromNetwork ) ASSERT_EQ( dataSource.getVehicleDataSourceIfName(), "vcan0" ); ASSERT_EQ( dataSource.getVehicleDataSourceProtocol(), VehicleDataSourceProtocol::RAW_SOCKET ); ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); - sendTestMessage( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; - ASSERT_TRUE( dataSource.getBuffer()->pop( msg ) ); + WAIT_ASSERT_TRUE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_TRUE( dataSource.disconnect() ); ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); ASSERT_TRUE( listener.gotDisConnectCallback ); @@ -209,7 +211,7 @@ TEST_F( CANDataSourceTest, testDoNotAcquireDataFromNetwork ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -225,13 +227,9 @@ TEST_F( CANDataSourceTest, testDoNotAcquireDataFromNetwork ) ASSERT_EQ( dataSource.getVehicleDataSourceIfName(), "vcan0" ); ASSERT_EQ( dataSource.getVehicleDataSourceProtocol(), VehicleDataSourceProtocol::RAW_SOCKET ); ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); - - sendTestMessage( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; // No messages should be in the buffer - ASSERT_FALSE( dataSource.getBuffer()->pop( msg ) ); + DELAY_ASSERT_FALSE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_TRUE( dataSource.disconnect() ); // Here the frame will be read from the socket ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); ASSERT_TRUE( listener.gotDisConnectCallback ); @@ -249,7 +247,7 @@ TEST_F( CANDataSourceTest, testNetworkDataAquisitionStateChange ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -266,33 +264,23 @@ TEST_F( CANDataSourceTest, testNetworkDataAquisitionStateChange ) ASSERT_EQ( dataSource.getVehicleDataSourceProtocol(), VehicleDataSourceProtocol::RAW_SOCKET ); ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); // Send a message on the bus. - sendTestMessage( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; // No messages should be in the buffer - ASSERT_FALSE( dataSource.getBuffer()->pop( msg ) ); + DELAY_ASSERT_FALSE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); // Activate consumption on the bus and make sure the channel buffer has items. dataSource.resumeDataAcquisition(); - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); - // Make sure old messages in kernel queue are ignored - ASSERT_FALSE( dataSource.getBuffer()->pop( msg ) ); - // Send a message on the bus. - sendTestMessage( socketFD ); - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); + // Send a message on the bus. // 1 message should be in the buffer as the channel is active. - ASSERT_TRUE( dataSource.getBuffer()->pop( msg ) ); + WAIT_ASSERT_TRUE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); // Interrupt data acquisition and make sure that the channel now does not consume data // anymore. dataSource.suspendDataAcquisition(); // Send a message on the bus. - sendTestMessage( socketFD ); - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); // No messages should be in the buffer - ASSERT_FALSE( dataSource.getBuffer()->pop( msg ) ); + DELAY_ASSERT_FALSE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_TRUE( dataSource.disconnect() ); ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); @@ -324,7 +312,7 @@ TEST_F( CANDataSourceTest, testCanFDSocketMode ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN-FD" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -342,12 +330,8 @@ TEST_F( CANDataSourceTest, testCanFDSocketMode ) ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); // Send a CAN-FD message on the bus. - sendTestFDMessage( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; - ASSERT_TRUE( dataSource.getBuffer()->pop( msg ) ); + WAIT_ASSERT_TRUE( sendTestFDMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_TRUE( dataSource.disconnect() ); ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); ASSERT_TRUE( listener.gotDisConnectCallback ); @@ -362,7 +346,7 @@ TEST_F( CANDataSourceTest, testSendRegularID ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -377,11 +361,8 @@ TEST_F( CANDataSourceTest, testSendRegularID ) ASSERT_EQ( dataSource.getVehicleDataSourceIfName(), "vcan0" ); ASSERT_EQ( dataSource.getVehicleDataSourceProtocol(), VehicleDataSourceProtocol::RAW_SOCKET ); ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); - sendTestMessage( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; - ASSERT_TRUE( dataSource.getBuffer()->pop( msg ) ); + WAIT_ASSERT_TRUE( sendTestMessage( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_EQ( msg.getMessageID(), 0x123 ); ASSERT_TRUE( dataSource.disconnect() ); ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); @@ -397,7 +378,7 @@ TEST_F( CANDataSourceTest, testExtractExtendedID ) VehicleDataSourceConfig sourceConfig; sourceConfig.transportProperties.emplace( "interfaceName", "vcan0" ); sourceConfig.transportProperties.emplace( "protocolName", "CAN" ); - sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "1000" ); + sourceConfig.transportProperties.emplace( "threadIdleTimeMs", "100" ); sourceConfig.maxNumberOfVehicleDataMessages = 1000; std::vector sourceConfigs = { sourceConfig }; CANDataSource dataSource; @@ -412,11 +393,8 @@ TEST_F( CANDataSourceTest, testExtractExtendedID ) ASSERT_EQ( dataSource.getVehicleDataSourceIfName(), "vcan0" ); ASSERT_EQ( dataSource.getVehicleDataSourceProtocol(), VehicleDataSourceProtocol::RAW_SOCKET ); ASSERT_EQ( dataSource.getVehicleDataSourceType(), VehicleDataSourceType::CAN_SOURCE ); - sendTestMessageExtendedID( socketFD ); - // Sleep for sometime on this thread to allow the other thread to finish - std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); VehicleDataMessage msg; - ASSERT_TRUE( dataSource.getBuffer()->pop( msg ) ); + WAIT_ASSERT_TRUE( sendTestMessageExtendedID( socketFD ) && dataSource.getBuffer()->pop( msg ) ); ASSERT_EQ( msg.getMessageID(), 0x80000123 ); ASSERT_TRUE( dataSource.disconnect() ); ASSERT_TRUE( dataSource.unSubscribeListener( &listener ) ); diff --git a/src/vehiclenetwork/test/CameraDataPublisherTest.cpp b/src/vehiclenetwork/test/CameraDataPublisherTest.cpp index 0c7c34db..b36f5c4f 100644 --- a/src/vehiclenetwork/test/CameraDataPublisherTest.cpp +++ b/src/vehiclenetwork/test/CameraDataPublisherTest.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "dds/CameraDataPublisher.h" +#include "WaitUntil.h" #include #include #include @@ -16,6 +17,7 @@ #include using namespace Aws::IoTFleetWise::VehicleNetwork; +using namespace Aws::IoTFleetWise::TestingSupport; class TestSubscriber : public DataReaderListener { @@ -206,9 +208,9 @@ TEST( CameraDataPublisherTest, testSendDataUPDTransport ) DDSDataRequest dataRequest{ 123, 1, 1 }; publisher.publishDataRequest( dataRequest ); // Give some time so that the Subscriber receives the message - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // Verify that the data arrived - ASSERT_EQ( subscriber.dataItem.dataItemId(), 123 ); + WAIT_ASSERT_EQ( subscriber.dataItem.dataItemId(), 123U ); ASSERT_TRUE( publisher.disconnect() ); ASSERT_FALSE( publisher.isAlive() ); } @@ -256,9 +258,9 @@ TEST( CameraDataPublisherTest, testSendDataSHMTransport ) DDSDataRequest dataRequest{ 123, 1, 1 }; publisher.publishDataRequest( dataRequest ); // Give some time so that the Subscriber receives the message - std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); + // Verify that the data arrived - ASSERT_EQ( subscriber.dataItem.dataItemId(), 123 ); + WAIT_ASSERT_EQ( subscriber.dataItem.dataItemId(), 123U ); ASSERT_TRUE( publisher.disconnect() ); ASSERT_FALSE( publisher.isAlive() ); } diff --git a/src/vehiclenetwork/test/CameraDataSubscriberTest.cpp b/src/vehiclenetwork/test/CameraDataSubscriberTest.cpp index 531cb2dd..30f311f8 100644 --- a/src/vehiclenetwork/test/CameraDataSubscriberTest.cpp +++ b/src/vehiclenetwork/test/CameraDataSubscriberTest.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "dds/CameraDataSubscriber.h" +#include "WaitUntil.h" #include #include #include @@ -16,6 +17,7 @@ #include #include +using namespace Aws::IoTFleetWise::TestingSupport; using namespace Aws::IoTFleetWise::VehicleNetwork; /** @@ -512,8 +514,8 @@ TEST( CameraDataSubscriberTest, testReceiveDataAndPersistUDPMultipleImages ) publisher.publishTestDataWithRealPNG( "Image1.png", std::string( currentDir ) + "/CameraSubscriberTestPNG.png" ); // Give some time for the worker to wake up and consume the message. - std::this_thread::sleep_for( std::chrono::seconds( 5 ) ); - ASSERT_TRUE( dataListener.gotNotification ); + + WAIT_ASSERT_TRUE( dataListener.gotNotification ); ASSERT_EQ( dataListener.artifact.path, config.temporaryCacheLocation + "Image1.png" ); // Verify that what we send on DDS is exactly what we received i.e the same PNG file. ASSERT_TRUE( @@ -524,9 +526,9 @@ TEST( CameraDataSubscriberTest, testReceiveDataAndPersistUDPMultipleImages ) std::string( currentDir ) + "/CameraSubscriberTestPNG.png" ); // Give some time for the worker to wake up and consume the message. - std::this_thread::sleep_for( std::chrono::seconds( 5 ) ); - ASSERT_TRUE( dataListener.gotNotification ); - ASSERT_EQ( dataListener.artifact.path, config.temporaryCacheLocation + "Image2.png" ); + + WAIT_ASSERT_TRUE( dataListener.gotNotification ); + WAIT_ASSERT_EQ( dataListener.artifact.path, config.temporaryCacheLocation + "Image2.png" ); // Verify that what we send on DDS is exactly what we received i.e the same PNG file. ASSERT_TRUE( areIdentical( std::string( currentDir ) + "/CameraSubscriberTestPNG.png", dataListener.artifact.path ) ); diff --git a/src/vehiclenetwork/test/valgrind.supp b/src/vehiclenetwork/test/valgrind.supp index 802d199e..e794ed1c 100644 --- a/src/vehiclenetwork/test/valgrind.supp +++ b/src/vehiclenetwork/test/valgrind.supp @@ -6,3 +6,12 @@ fun:sem_open ... } + +{ + __libc_csu_init + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:__libc_csu_init + ... +} diff --git a/tools/arm64.list b/tools/arm64.list index 67425a22..ad371fe2 100644 --- a/tools/arm64.list +++ b/tools/arm64.list @@ -1,7 +1,7 @@ -deb [arch=arm64] http://ports.ubuntu.com/ bionic main restricted -deb [arch=arm64] http://ports.ubuntu.com/ bionic-updates main restricted -deb [arch=arm64] http://ports.ubuntu.com/ bionic universe -deb [arch=arm64] http://ports.ubuntu.com/ bionic-updates universe -deb [arch=arm64] http://ports.ubuntu.com/ bionic multiverse -deb [arch=arm64] http://ports.ubuntu.com/ bionic-updates multiverse -deb [arch=arm64] http://ports.ubuntu.com/ bionic-backports main restricted universe multiverse +deb [arch=arm64] http://ports.ubuntu.com/ focal main restricted +deb [arch=arm64] http://ports.ubuntu.com/ focal-updates main restricted +deb [arch=arm64] http://ports.ubuntu.com/ focal universe +deb [arch=arm64] http://ports.ubuntu.com/ focal-updates universe +deb [arch=arm64] http://ports.ubuntu.com/ focal multiverse +deb [arch=arm64] http://ports.ubuntu.com/ focal-updates multiverse +deb [arch=arm64] http://ports.ubuntu.com/ focal-backports main restricted universe multiverse diff --git a/tools/armhf.list b/tools/armhf.list index e6bf7bcf..b876ea34 100644 --- a/tools/armhf.list +++ b/tools/armhf.list @@ -1,7 +1,7 @@ -deb [arch=armhf] http://ports.ubuntu.com/ bionic main restricted -deb [arch=armhf] http://ports.ubuntu.com/ bionic-updates main restricted -deb [arch=armhf] http://ports.ubuntu.com/ bionic universe -deb [arch=armhf] http://ports.ubuntu.com/ bionic-updates universe -deb [arch=armhf] http://ports.ubuntu.com/ bionic multiverse -deb [arch=armhf] http://ports.ubuntu.com/ bionic-updates multiverse -deb [arch=armhf] http://ports.ubuntu.com/ bionic-backports main restricted universe multiverse +deb [arch=armhf] http://ports.ubuntu.com/ focal main restricted +deb [arch=armhf] http://ports.ubuntu.com/ focal-updates main restricted +deb [arch=armhf] http://ports.ubuntu.com/ focal universe +deb [arch=armhf] http://ports.ubuntu.com/ focal-updates universe +deb [arch=armhf] http://ports.ubuntu.com/ focal multiverse +deb [arch=armhf] http://ports.ubuntu.com/ focal-updates multiverse +deb [arch=armhf] http://ports.ubuntu.com/ focal-backports main restricted universe multiverse diff --git a/tools/build-dist.sh b/tools/build-dist.sh index 091eb702..5192a243 100755 --- a/tools/build-dist.sh +++ b/tools/build-dist.sh @@ -1,11 +1,19 @@ #!/bin/bash +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 set -euo pipefail +if (($#<1)); then + echo "Error: Output binary not provided" >&2 + exit -1 +fi +OUTPUT_BINARY=`realpath $1` + rm -rf build/dist mkdir build/dist cd build/dist -cp -r ../src/executionmanagement/aws-iot-fleetwise-edge \ +cp -r ${OUTPUT_BINARY} \ ../../LICENSE \ ../../THIRD-PARTY-LICENSES \ ../../configuration \ diff --git a/tools/build-fwe-cross-arm64.sh b/tools/build-fwe-cross-arm64.sh index 957c7456..eff58551 100755 --- a/tools/build-fwe-cross-arm64.sh +++ b/tools/build-fwe-cross-arm64.sh @@ -4,6 +4,8 @@ set -eo pipefail +NATIVE_PREFIX="/usr/local/`gcc -dumpmachine`" +export PATH=${NATIVE_PREFIX}/bin:${PATH} mkdir -p build && cd build cmake \ -DFWE_STATIC_LINK=On \ diff --git a/tools/build-fwe-cross-armhf.sh b/tools/build-fwe-cross-armhf.sh index 940d4070..c87cbea0 100755 --- a/tools/build-fwe-cross-armhf.sh +++ b/tools/build-fwe-cross-armhf.sh @@ -4,6 +4,8 @@ set -eo pipefail +NATIVE_PREFIX="/usr/local/`gcc -dumpmachine`" +export PATH=${NATIVE_PREFIX}/bin:${PATH} mkdir -p build && cd build cmake \ -DFWE_STATIC_LINK=On \ diff --git a/tools/build-fwe-native.sh b/tools/build-fwe-native.sh index 21cbac18..9994cfac 100755 --- a/tools/build-fwe-native.sh +++ b/tools/build-fwe-native.sh @@ -4,11 +4,14 @@ set -eo pipefail +PREFIX="/usr/local/`gcc -dumpmachine`" +export PATH=${PREFIX}/bin:${PATH} mkdir -p build && cd build cmake \ -DFWE_STATIC_LINK=On \ -DFWE_STRIP_SYMBOLS=On \ -DFWE_SECURITY_COMPILE_FLAGS=On \ -DFWE_TEST_FAKETIME=On \ + -DCMAKE_PREFIX_PATH=${PREFIX} \ .. make -j`nproc` diff --git a/tools/cansim/canigen.py b/tools/cansim/canigen.py index f5a25f7f..9cc52f74 100644 --- a/tools/cansim/canigen.py +++ b/tools/cansim/canigen.py @@ -1,6 +1,5 @@ import json import select -import sys import time from datetime import datetime from threading import Thread @@ -16,11 +15,11 @@ from prompt_toolkit.completion import NestedCompleter, PathCompleter, WordCompleter -class canigen: - __BROADCAST_ID_STANDARD = 0x7DF - __BROADCAST_ID_EXTENDED = 0x18DB33F1 - __MAX_TX_ID_STANDARD = 0x7EF - __MIN_RX_ID_EXTENDED = 0x18DA00F1 +class Canigen: + _BROADCAST_ID_STANDARD = 0x7DF + _BROADCAST_ID_EXTENDED = 0x18DB33F1 + _MAX_TX_ID_STANDARD = 0x7EF + _MIN_RX_ID_EXTENDED = 0x18DA00F1 def __init__( self, @@ -30,91 +29,94 @@ def __init__( values_filename=None, obd_config_filename=None, default_cycle_time_ms=100, + obd_answer_reverse_order=False, ): - self.__stop = False - self.__interface = interface - self.__output_file = None - self.__sig_names = [] + self._stop = False + self._interface = interface + self._output_file = None + self._sig_names = [] + self._obd_answer_reverse_order = obd_answer_reverse_order fd = False - self.__values = {"sig": {}, "pid": {}, "dtc": {}} - if not database_filename is None: - self.__db = cantools.database.load_file(database_filename) - for msg in self.__db.messages: + self._values = {"sig": {}, "pid": {}, "dtc": {}} + if database_filename is not None: + self._db = cantools.database.load_file(database_filename) + for msg in self._db.messages: if not fd and msg.length > 8: fd = True for sig in msg.signals: - self.__sig_names.append(sig.name) - self.__values["sig"][sig.name] = ( + self._sig_names.append(sig.name) + self._values["sig"][sig.name] = ( sig.offset if sig.initial is None else sig.initial ) - if not values_filename is None: - self.__values = self.__load_json(values_filename) - if not output_filename is None: - self.__output_file = open(output_filename, "w") + if values_filename is not None: + self._values = self._load_json(values_filename) + if output_filename is not None: + self._output_file = open(output_filename, "w") else: - self.__can_bus = can.interface.Bus(self.__interface, bustype="socketcan", fd=fd) - self.__obd_config = {} - self.__pid_names = [] - self.__dtc_names = [] - if not obd_config_filename is None: - self.__obd_config = self.__load_json(obd_config_filename) - for ecu in self.__obd_config["ecus"]: + self._can_bus = can.interface.Bus(self._interface, bustype="socketcan", fd=fd) + self._obd_config = {} + self._pid_names = [] + self._dtc_names = [] + if obd_config_filename is not None: + self._obd_config = self._load_json(obd_config_filename) + for ecu in self._obd_config["ecus"]: for pid_name in ecu["pids"]: - self.__pid_names.append(pid_name) - if not pid_name in self.__values["pid"]: - self.__values["pid"][pid_name] = 0.0 + self._pid_names.append(pid_name) + if pid_name not in self._values["pid"]: + self._values["pid"][pid_name] = 0.0 for dtc_name in ecu["dtcs"]: - self.__dtc_names.append(dtc_name) - if not dtc_name in self.__values["dtc"]: - self.__values["dtc"][dtc_name] = 0.0 + self._dtc_names.append(dtc_name) + if dtc_name not in self._values["dtc"]: + self._values["dtc"][dtc_name] = 0.0 - self.__threads = [] - if not database_filename is None: - for msg in self.__db.messages: + self._threads = [] + if database_filename is not None: + for msg in self._db.messages: cycle_time = msg.cycle_time if cycle_time is None or cycle_time == 0: cycle_time = default_cycle_time_ms print( - f"Warning: Cycle time is None or zero for frame '{msg.name}', setting it to default of {default_cycle_time_ms} ms" + f"Warning: Cycle time is None or zero for frame '{msg.name}'," + f" setting it to default of {default_cycle_time_ms} ms" ) thread = Thread( - target=self.__sig_thread, + target=self._sig_thread, args=( msg.name, cycle_time, ), ) thread.start() - self.__threads.append(thread) - if not obd_config_filename is None: - for ecu in self.__obd_config["ecus"]: - thread = Thread(target=self.__obd_thread, args=(ecu,)) + self._threads.append(thread) + if obd_config_filename is not None: + for ecu in self._obd_config["ecus"]: + thread = Thread(target=self._obd_thread, args=(ecu,)) thread.start() - self.__threads.append(thread) + self._threads.append(thread) def stop(self): - self.__stop = True - for thread in self.__threads: + self._stop = True + for thread in self._threads: thread.join() - if self.__output_file: - self.__output_file.close() + if self._output_file: + self._output_file.close() - def __load_json(self, filename): + def _load_json(self, filename): try: - with open(filename, "r") as fp: + with open(filename) as fp: return json.load(fp) - except: + except Exception: print("error: failed to load " + filename) raise - def __save_json(self, filename, data): + def _save_json(self, filename, data): try: with open(filename, "w") as fp: return json.dump(data, fp, sort_keys=True, indent=4) - except: + except Exception: print("error: failed to save " + filename) - def __write_frame(self, msg, data): + def _write_frame(self, msg, data): if msg.is_extended_frame: can_id = "%07X" % msg.frame_id else: @@ -122,23 +124,25 @@ def __write_frame(self, msg, data): data_hex = "" for byte in data: data_hex += "%02X" % byte - self.__output_file.write( - "(%f) %s %s#%s\n" % (datetime.now().timestamp(), self.__interface, can_id, data_hex) + self._output_file.write( + "({:f}) {} {}#{}\n".format( + datetime.now().timestamp(), self._interface, can_id, data_hex + ) ) - def __sig_thread(self, msg_name, cycle_time): - while not self.__stop: - msg = self.__db.get_message_by_name(msg_name) + def _sig_thread(self, msg_name, cycle_time): + while not self._stop: + msg = self._db.get_message_by_name(msg_name) vals = {} for sig in msg.signals: - if not sig.name in self.__values["sig"]: - val = self.__values["sig"][sig.name] = 0 + if sig.name not in self._values["sig"]: + val = self._values["sig"][sig.name] = 0 else: - val = self.__values["sig"][sig.name] + val = self._values["sig"][sig.name] vals[sig.name] = 0 if val is None else val data = msg.encode(vals) - if not self.__output_file is None: - self.__write_frame(msg, data) + if self._output_file is not None: + self._write_frame(msg, data) else: frame = can.Message( is_extended_id=msg.is_extended_frame, @@ -146,13 +150,13 @@ def __sig_thread(self, msg_name, cycle_time): arbitration_id=msg.frame_id, data=data, ) - self.__can_bus.send(frame) + self._can_bus.send(frame) time.sleep(cycle_time / 1000.0) - def __get_supported_pids(self, num_range, ecu): + def _get_supported_pids(self, num_range, ecu): supported = False out = [0, 0, 0, 0] - for name, data in ecu["pids"].items(): + for data in ecu["pids"].values(): pid_num = int(data["num"], 0) if pid_num >= num_range and pid_num < (num_range + 0x20): i = int((pid_num - num_range - 1) / 8) @@ -161,49 +165,49 @@ def __get_supported_pids(self, num_range, ecu): supported = True return supported, out - def __encode_pid_data(self, num, ecu): + def _encode_pid_data(self, num, ecu): for name, data in ecu["pids"].items(): if num == int(data["num"], 0): - val = int((self.__values["pid"][name] + data["offset"]) * data["scale"]) + val = int((self._values["pid"][name] + data["offset"]) * data["scale"]) out = [] for i in range(data["size"]): out.append((val >> ((data["size"] - i - 1) * 8)) & 0xFF) return out return None - def __create_isotp_socket(self, txid, rxid, zero_padding): + def _create_isotp_socket(self, txid, rxid, zero_padding): s = isotp.socket() if zero_padding: s.set_opts(txpad=0, rxpad=0) addressing_mode = ( isotp.AddressingMode.Normal_11bits - if txid <= self.__MAX_TX_ID_STANDARD + if txid <= self._MAX_TX_ID_STANDARD else isotp.AddressingMode.Normal_29bits ) s.bind( - self.__interface, isotp.Address(addressing_mode=addressing_mode, rxid=rxid, txid=txid) + self._interface, + isotp.Address(addressing_mode=addressing_mode, rxid=rxid, txid=txid), ) return s - def __obd_thread(self, ecu): + def _obd_thread(self, ecu): isotp_socket_phys = None create_socket = True - while not self.__stop: + while not self._stop: if create_socket: create_socket = False if isotp_socket_phys: - time.sleep( - 1 - ) # Wait one sec, to avoid high CPU usage in the case of persistent bus errors + # Wait one sec, to avoid high CPU usage in the case of persistent bus errors + time.sleep(1) txid = int(ecu["tx_id"], 0) - if txid <= self.__MAX_TX_ID_STANDARD: + if txid <= self._MAX_TX_ID_STANDARD: rxid_phys = txid - 8 - rxid_func = self.__BROADCAST_ID_STANDARD + rxid_func = self._BROADCAST_ID_STANDARD else: - rxid_phys = self.__MIN_RX_ID_EXTENDED + ((txid & 0xFF) << 8) - rxid_func = self.__BROADCAST_ID_EXTENDED - isotp_socket_phys = self.__create_isotp_socket(txid, rxid_phys, ecu["zero_padding"]) - isotp_socket_func = self.__create_isotp_socket(txid, rxid_func, ecu["zero_padding"]) + rxid_phys = self._MIN_RX_ID_EXTENDED + ((txid & 0xFF) << 8) + rxid_func = self._BROADCAST_ID_EXTENDED + isotp_socket_phys = self._create_isotp_socket(txid, rxid_phys, ecu["zero_padding"]) + isotp_socket_func = self._create_isotp_socket(txid, rxid_func, ecu["zero_padding"]) try: res = select.select([isotp_socket_phys, isotp_socket_func], [], [], 0.5) @@ -221,9 +225,9 @@ def __obd_thread(self, ecu): tx = [0x7F, sid, 0x11] # NRC Service not supported elif sid == 0x01: # PID while len(rx) > 0: - pid_num = rx.pop(0) + pid_num = rx.pop(-1 if self._obd_answer_reverse_order else 0) if (pid_num % 0x20) == 0: # Supported PIDs - supported, data = self.__get_supported_pids(pid_num, ecu) + supported, data = self._get_supported_pids(pid_num, ecu) if ( pid_num == 0 or supported @@ -231,14 +235,14 @@ def __obd_thread(self, ecu): ): tx += [pid_num] + data else: - data = self.__encode_pid_data(pid_num, ecu) + data = self._encode_pid_data(pid_num, ecu) if data is not None: tx += [pid_num] + data elif sid == 0x03: # DTCs num_dtcs = 0 dtc_data = [] for dtc_name in ecu["dtcs"]: - if self.__values["dtc"][dtc_name]: + if self._values["dtc"][dtc_name]: dtc_num = int(ecu["dtcs"][dtc_name]["num"], 16) dtc_data.append((dtc_num >> 8) & 0xFF) dtc_data.append(dtc_num & 0xFF) @@ -251,48 +255,50 @@ def __obd_thread(self, ecu): isotp_socket_phys.send(bytearray(tx)) def get_sig_names(self): - return self.__sig_names + return self._sig_names def get_pid_names(self): - return self.__pid_names + return self._pid_names def get_dtc_names(self): - return self.__dtc_names + return self._dtc_names def set_value(self, val_type, name, value): - self.__values[val_type][name] = value + self._values[val_type][name] = value def set_sig(self, name, value): - self.__values["sig"][name] = value + self._values["sig"][name] = value def set_pid(self, name, value): - self.__values["pid"][name] = value + self._values["pid"][name] = value def set_dtc(self, name, value): - self.__values["dtc"][name] = value + self._values["dtc"][name] = value def get_value(self, val_type, name): - return self.__values[val_type][name] + return self._values[val_type][name] def get_sig(self, name): - return self.__values["sig"][name] + return self._values["sig"][name] def get_pid(self, name): - return self.__values["pid"][name] + return self._values["pid"][name] def get_dtc(self, name): - return self.__values["dtc"][name] + return self._values["dtc"][name] def load_values(self, filename): - self.__values = self.__load_json(filename) + self._values = self._load_json(filename) def save_values(self, filename): - self.__save_json(filename, self.__values) + self._save_json(filename, self._values) if __name__ == "__main__": parser = argparse.ArgumentParser( - description="Generates SocketCAN messages interactively according to a DBC file and OBD config" + description=( + "Generates SocketCAN messages interactively according to a DBC file and OBD config" + ) ) parser.add_argument("-i", "--interface", required=True, help="CAN interface, e.g. vcan0") parser.add_argument("-d", "--database", help="DBC file") @@ -305,7 +311,13 @@ def save_values(self, filename): print("error: --interface argument is required") exit(1) - c = canigen(args.interface, args.output_filename, args.database, args.values, args.obd_config) + c = Canigen( + args.interface, + args.output_filename, + args.database, + args.values, + args.obd_config, + ) sig_completer = WordCompleter(c.get_sig_names()) path_completer = PathCompleter() @@ -343,24 +355,24 @@ def print_help(): elif cmd[0] == "set": try: c.set_value(cmd[1], cmd[2], float(cmd[3])) - except: + except Exception: print("error: invalid value") elif cmd[0] == "get": print(c.get_value(cmd[1], cmd[2])) elif cmd[0] == "load": try: c.load_values(cmd[1]) - except: + except Exception: pass elif cmd[0] == "save": c.save_values(cmd[1]) else: print_help() - except: + except Exception: print("error: invalid command") print_help() except KeyboardInterrupt: pass - except: + except Exception: print("error: unknown") c.stop() diff --git a/tools/cansim/cansim.py b/tools/cansim/cansim.py index 5d74d840..aec4cc11 100755 --- a/tools/cansim/cansim.py +++ b/tools/cansim/cansim.py @@ -15,7 +15,7 @@ parser.add_argument("-o", "--only-obd", action="store_true", help="Only generate OBD messages") args = parser.parse_args() -can_sim = canigen.canigen( +can_sim = canigen.Canigen( interface=args.interface, database_filename=None if args.only_obd else "hscan.dbc", obd_config_filename="obd_config.json", @@ -50,5 +50,5 @@ def set_with_print(func, name, val): except KeyboardInterrupt: print("Stopping...") can_sim.stop() -except: +except Exception: raise diff --git a/tools/cansim/run-cansim.sh b/tools/cansim/run-cansim.sh index 12ed8b7d..212ef06d 100755 --- a/tools/cansim/run-cansim.sh +++ b/tools/cansim/run-cansim.sh @@ -20,4 +20,4 @@ if (($1>0)) && ! cangw -L | grep -q "cangw -A -s vcan0 -d vcan$1 -e"; then fi # Start the CAN simulator: for instance numbers greater than zero, only OBD is simulated -/usr/bin/python3.7 /usr/share/cansim/cansim.py --interface "vcan$1" `(($1>0)) && echo "--only-obd"` +/usr/bin/python3 /usr/share/cansim/cansim.py --interface "vcan$1" `(($1>0)) && echo "--only-obd"` diff --git a/tools/cfn-templates/fwdemo.yml b/tools/cfn-templates/fwdemo.yml index ed0d2bf7..47b62e7c 100644 --- a/tools/cfn-templates/fwdemo.yml +++ b/tools/cfn-templates/fwdemo.yml @@ -402,42 +402,42 @@ Resources: - !Sub arn:aws:iot:${IoTCoreRegion}:${AWS::AccountId}:cert/* - !Sub arn:aws:iot:${IoTCoreRegion}:${AWS::AccountId}:policy/${AWS::StackName}-policy Mappings: - # Ubuntu 18.04 arm64 AMIs + # Ubuntu 20.04 arm64 AMIs AMIRegionMap: ap-northeast-1: - AMIID: ami-078fe86fa4c333481 + AMIID: ami-0836b08b6e50975e0 ap-northeast-2: - AMIID: ami-08b051fc14e6c551e + AMIID: ami-09a9b3cefb0428387 ap-northeast-3: - AMIID: ami-02882efe4f6434b3c + AMIID: ami-0e48a9cf92bd86508 ap-south-1: - AMIID: ami-04f6f742e1d9012e3 + AMIID: ami-0a20a058ee035d49c ap-southeast-1: - AMIID: ami-062e2ec9a8bfa02d6 + AMIID: ami-04a46a6d4dbeb5fe0 ap-southeast-2: - AMIID: ami-0ac142889d7d97567 + AMIID: ami-0c9be6cb7d01a9066 ca-central-1: - AMIID: ami-07ba772924ecc689f + AMIID: ami-0c4c276bcaf3911b1 eu-central-1: - AMIID: ami-01bced7e7239dbd82 + AMIID: ami-048c3444604e23b5c eu-north-1: - AMIID: ami-00320b1b198c6f31e + AMIID: ami-04a8d27b5fe65dd51 eu-west-1: - AMIID: ami-07648455888dfc767 + AMIID: ami-0ea366b1f105cb0aa eu-west-2: - AMIID: ami-0fa14d6dc09479348 + AMIID: ami-06b427ade4da0da55 eu-west-3: - AMIID: ami-0dc556c21e5099c75 + AMIID: ami-06cc80fe7e768f974 sa-east-1: - AMIID: ami-0bd03f2c1034d9845 + AMIID: ami-081f3905bf0562cdd us-east-1: - AMIID: ami-08353a25e80beea3e + AMIID: ami-0620aa8714211d0af us-east-2: - AMIID: ami-026141f3d5c6d2d0c + AMIID: ami-0bc02c3c09aaee8ea us-west-1: - AMIID: ami-0437ad1b6a022fafe + AMIID: ami-038e08160883bc1f9 us-west-2: - AMIID: ami-0327006c87b23e535 + AMIID: ami-0c4dfe348469b0ae5 FleetSizeEc2InstanceTypeMap: "1": InstanceType: m6g.xlarge diff --git a/tools/cfn-templates/fwdev.yml b/tools/cfn-templates/fwdev.yml index 5a8336bb..c1f2fb42 100644 --- a/tools/cfn-templates/fwdev.yml +++ b/tools/cfn-templates/fwdev.yml @@ -146,42 +146,42 @@ Resources: DeleteOnTermination: "true" Encrypted: "true" Mappings: - # Ubuntu 18.04 arm64 AMIs + # Ubuntu 20.04 arm64 AMIs AMIRegionMap: ap-northeast-1: - AMIID: ami-078fe86fa4c333481 + AMIID: ami-0836b08b6e50975e0 ap-northeast-2: - AMIID: ami-08b051fc14e6c551e + AMIID: ami-09a9b3cefb0428387 ap-northeast-3: - AMIID: ami-02882efe4f6434b3c + AMIID: ami-0e48a9cf92bd86508 ap-south-1: - AMIID: ami-04f6f742e1d9012e3 + AMIID: ami-0a20a058ee035d49c ap-southeast-1: - AMIID: ami-062e2ec9a8bfa02d6 + AMIID: ami-04a46a6d4dbeb5fe0 ap-southeast-2: - AMIID: ami-0ac142889d7d97567 + AMIID: ami-0c9be6cb7d01a9066 ca-central-1: - AMIID: ami-07ba772924ecc689f + AMIID: ami-0c4c276bcaf3911b1 eu-central-1: - AMIID: ami-01bced7e7239dbd82 + AMIID: ami-048c3444604e23b5c eu-north-1: - AMIID: ami-00320b1b198c6f31e + AMIID: ami-04a8d27b5fe65dd51 eu-west-1: - AMIID: ami-07648455888dfc767 + AMIID: ami-0ea366b1f105cb0aa eu-west-2: - AMIID: ami-0fa14d6dc09479348 + AMIID: ami-06b427ade4da0da55 eu-west-3: - AMIID: ami-0dc556c21e5099c75 + AMIID: ami-06cc80fe7e768f974 sa-east-1: - AMIID: ami-0bd03f2c1034d9845 + AMIID: ami-081f3905bf0562cdd us-east-1: - AMIID: ami-08353a25e80beea3e + AMIID: ami-0620aa8714211d0af us-east-2: - AMIID: ami-026141f3d5c6d2d0c + AMIID: ami-0bc02c3c09aaee8ea us-west-1: - AMIID: ami-0437ad1b6a022fafe + AMIID: ami-038e08160883bc1f9 us-west-2: - AMIID: ami-0327006c87b23e535 + AMIID: ami-0c4dfe348469b0ae5 Outputs: Ec2InstanceId: Description: "EC2 instance ID" diff --git a/tools/cloud/README.md b/tools/cloud/README.md index a2db3c2e..485be7ec 100644 --- a/tools/cloud/README.md +++ b/tools/cloud/README.md @@ -2,12 +2,16 @@ ## Prerequisites -The demo applies for Python 3.7 + environment. Install the dependencies: +The demo applies for Python 3.8+ environment. Install the dependencies: - sudo ./install-deps.sh +```bash +sudo ./install-deps.sh +``` ## Running the Demo Run the demo: - ./demo.sh +```bash +./demo.sh +``` diff --git a/tools/cloud/clean-up.sh b/tools/cloud/clean-up.sh index aa3211ec..1c030e86 100755 --- a/tools/cloud/clean-up.sh +++ b/tools/cloud/clean-up.sh @@ -17,18 +17,23 @@ parse_args() { case $1 in --vehicle-name) VEHICLE_NAME=$2 + shift ;; --fleet-size) FLEET_SIZE=$2 + shift ;; --timestamp) TIMESTAMP=$2 + shift ;; --endpoint-url) ENDPOINT_URL=$2 + shift ;; --region) REGION=$2 + shift ;; --help) echo "Usage: $0 [OPTION]" diff --git a/tools/cloud/dbc-to-json.py b/tools/cloud/dbc-to-json.py index c4be5a9a..0e4c93c1 100755 --- a/tools/cloud/dbc-to-json.py +++ b/tools/cloud/dbc-to-json.py @@ -13,13 +13,13 @@ db = cantools.database.load_file(sys.argv[1]) -with open("network-interfaces.json", "r") as f: +with open("network-interfaces.json") as f: network_interfaces = json.load(f) for interface in network_interfaces: if interface["type"] == "CAN_INTERFACE": interface_id = interface["interfaceId"] -signalDecodersToAdd = [] +signal_decoders_to_add = [] for message in db.messages: for signal in message.signals: @@ -47,16 +47,16 @@ else: signal_to_add["startBit"] = signal.start - signalDecodersToAdd.append( + signal_decoders_to_add.append( { "type": "CAN_SIGNAL", "canSignal": signal_to_add, - "fullyQualifiedName": "Vehicle.{}.{}".format(message.name, signal.name), + "fullyQualifiedName": f"Vehicle.{message.name}.{signal.name}", "interfaceId": interface_id, } ) -out = json.dumps(signalDecodersToAdd, indent=4, sort_keys=True) +out = json.dumps(signal_decoders_to_add, indent=4, sort_keys=True) if len(sys.argv) < 3: print(out) diff --git a/tools/cloud/dbc-to-nodes.py b/tools/cloud/dbc-to-nodes.py index fa51c07d..602c9ca5 100755 --- a/tools/cloud/dbc-to-nodes.py +++ b/tools/cloud/dbc-to-nodes.py @@ -28,7 +28,8 @@ signals[message_text] = set() if signal.name in signals[message_text]: print( - f"Signal {signal.name} occurs multiple times in the message {message_text}, only the first occurrence will be used" + f"Signal {signal.name} occurs multiple times in the message {message_text}, only" + " the first occurrence will be used" ) continue signals[message_text].add(signal.name) @@ -61,9 +62,9 @@ node["sensor"]["description"] = signal.comment if signal.unit: node["sensor"]["unit"] = signal.unit - if not signal.minimum is None and datatype != "BOOLEAN": + if signal.minimum is not None and datatype != "BOOLEAN": node["sensor"]["min"] = signal.minimum - if not signal.maximum is None and datatype != "BOOLEAN": + if signal.maximum is not None and datatype != "BOOLEAN": node["sensor"]["max"] = signal.maximum nodes.append(node) diff --git a/tools/cloud/demo.sh b/tools/cloud/demo.sh index e68eb0dc..7859f185 100755 --- a/tools/cloud/demo.sh +++ b/tools/cloud/demo.sh @@ -29,24 +29,30 @@ parse_args() { case $1 in --vehicle-name) VEHICLE_NAME=$2 + shift ;; --fleet-size) FLEET_SIZE=$2 + shift ;; --clean-up) CLEAN_UP=true ;; --campaign-file) CAMPAIGN_FILE=$2 + shift ;; --dbc-file) DBC_FILE=$2 + shift ;; --endpoint-url) ENDPOINT_URL=$2 + shift ;; --region) REGION=$2 + shift ;; --force-registration) FORCE_REGISTRATION=true @@ -246,9 +252,9 @@ fi VEHICLE_NODE=`cat vehicle-node.json` OBD_NODES=`cat obd-nodes.json` if [ "${DBC_FILE}" == "" ]; then - DBC_NODES=`python3.7 dbc-to-nodes.py ${DEFAULT_DBC_FILE}` + DBC_NODES=`python3 dbc-to-nodes.py ${DEFAULT_DBC_FILE}` else - DBC_NODES=`python3.7 dbc-to-nodes.py ${DBC_FILE}` + DBC_NODES=`python3 dbc-to-nodes.py ${DBC_FILE}` fi echo "Checking for existing signal catalog..." @@ -410,7 +416,7 @@ if [ "${DBC_FILE}" == "" ]; then --name ${NAME}-decoder-manifest \ --network-file-definitions "${NETWORK_FILE_DEFINITIONS}" | jq -r .arn else - SIGNAL_DECODERS=`python3.7 dbc-to-json.py ${DBC_FILE}` + SIGNAL_DECODERS=`python3 dbc-to-json.py ${DBC_FILE}` aws iotfleetwise update-decoder-manifest \ ${ENDPOINT_URL_OPTION} --region ${REGION} \ --name ${NAME}-decoder-manifest \ @@ -590,7 +596,7 @@ aws timestream-query query \ if [ "${DBC_FILE}" == "" ]; then echo "Converting to HTML..." OUTPUT_FILE_HTML="${NAME}.html" - python3.7 timestream-to-html.py ${NAME}-timestream-result.json ${OUTPUT_FILE_HTML} + python3 timestream-to-html.py ${NAME}-timestream-result.json ${OUTPUT_FILE_HTML} echo "You can now view the collected data." echo "----------------------------------" diff --git a/tools/cloud/install-deps.sh b/tools/cloud/install-deps.sh index ce46cf93..4cd2fe3d 100755 --- a/tools/cloud/install-deps.sh +++ b/tools/cloud/install-deps.sh @@ -4,14 +4,11 @@ set -eo pipefail -# Install Python 3.7 and pip -apt update && apt install -y python3.7 python3-setuptools curl -curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -python3.7 get-pip.py --user -rm get-pip.py +# Install Python 3 and pip +apt update && apt install -y python3 python3-pip # Install pip packages -python3.7 -m pip install \ +pip3 install \ wrapt==1.10.0 \ plotly==5.3.1 \ pandas==1.3.4 \ diff --git a/tools/cloud/timestream-to-html.py b/tools/cloud/timestream-to-html.py index 8d64d8a1..e3540293 100755 --- a/tools/cloud/timestream-to-html.py +++ b/tools/cloud/timestream-to-html.py @@ -12,7 +12,7 @@ print("Usage: python3 " + sys.argv[0] + " []") exit(-1) -with open(sys.argv[1], "r") as fp: +with open(sys.argv[1]) as fp: data = json.load(fp) columns = {} @@ -25,7 +25,7 @@ def get_val(row, column): return ( None - if not column in columns or not "ScalarValue" in row["Data"][columns[column]] + if column not in columns or "ScalarValue" not in row["Data"][columns[column]] else row["Data"][columns[column]]["ScalarValue"] ) @@ -35,9 +35,9 @@ def get_val(row, column): ts = get_val(row, "time") signal_name = get_val(row, "measure_name") val = get_val(row, "measure_value::double") - if val == None: + if val is None: val = get_val(row, "measure_value::bigint") - if val == None: + if val is None: val = get_val(row, "measure_value::boolean") != "false" df.at[ts, signal_name] = float(val) diff --git a/tools/cloud/timestream-to-mdf.py b/tools/cloud/timestream-to-mdf.py index 157bce5d..e5d5db47 100755 --- a/tools/cloud/timestream-to-mdf.py +++ b/tools/cloud/timestream-to-mdf.py @@ -15,7 +15,7 @@ # # 3. Then install the following Python packages: # -# python3.7 -m pip install pandas asammdf +# pip3 install pandas asammdf # import json @@ -28,7 +28,7 @@ print("Usage: python3 " + sys.argv[0] + " ") exit(-1) -with open(sys.argv[1], "r") as fp: +with open(sys.argv[1]) as fp: data = json.load(fp) columns = {} @@ -41,7 +41,7 @@ def get_val(row, column): return ( None - if not "ScalarValue" in row["Data"][columns[column]] + if "ScalarValue" not in row["Data"][columns[column]] else row["Data"][columns[column]]["ScalarValue"] ) @@ -52,7 +52,7 @@ def get_val(row, column): ts = pd.Timestamp(ts).value / 10**9 signal_name = get_val(row, "measure_name") val = get_val(row, "measure_value::double") - if val == None: + if val is None: val = get_val(row, "measure_value::bigint") df.at[ts, signal_name] = float(val) df.sort_index(inplace=True) diff --git a/tools/code_check/compile_db_remove_test.py b/tools/code_check/compile_db_remove_test.py index 41f1e1bb..6fc211b2 100755 --- a/tools/code_check/compile_db_remove_test.py +++ b/tools/code_check/compile_db_remove_test.py @@ -9,13 +9,13 @@ cmake_build_dir = sys.argv[1] lines = [] -with open(cmake_build_dir + "/compile_commands.json", "r") as f: +with open(cmake_build_dir + "/compile_commands.json") as f: lines = f.readlines() f.close() index = 0 while index < len(lines): - x = re.search('"command": ".+iotcpp\/test\/include.+', lines[index]) + x = re.search(r'"command": ".+iotcpp\/test\/include.+', lines[index]) if x: del lines[index - 2 : index + 3] # remove a json block index = index - 3 diff --git a/tools/configure-fwe.sh b/tools/configure-fwe.sh index 2c872312..26fcede9 100755 --- a/tools/configure-fwe.sh +++ b/tools/configure-fwe.sh @@ -43,33 +43,47 @@ parse_args() { case $1 in --input-config-file) INPUT_CONFIG_FILE=$2 + shift ;; --output-config-file) OUTPUT_CONFIG_FILE=$2 + shift ;; --vehicle-name) VEHICLE_NAME=$2 + shift ;; --endpoint-url) ENDPOINT_URL=$2 + shift ;; --certificate-file) CERTIFICATE_FILE=$2 + shift ;; --private-key-file) PRIVATE_KEY_FILE=$2 + shift ;; --can-bus0) CAN_BUS0=$2 + shift ;; --persistency-path) PERSISTENCY_PATH=$2 + shift ;; --topic-prefix) TOPIC_PREFIX=$2 + shift ;; --log-level) LOG_LEVEL=$2 + shift + ;; + --log-color) + LOG_COLOR=$2 + shift ;; --help) echo "Usage: $0 [OPTION]" diff --git a/tools/container/Dockerfile b/tools/container/Dockerfile index 4d933a02..907f0d33 100644 --- a/tools/container/Dockerfile +++ b/tools/container/Dockerfile @@ -1,7 +1,7 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 -FROM public.ecr.aws/ubuntu/ubuntu:18.04 +FROM public.ecr.aws/ubuntu/ubuntu:20.04 # Provided by buildx, e.g.: 'linux/amd64', 'linux/arm64', etc.: ARG TARGETPLATFORM diff --git a/tools/deploy/fwe@.service b/tools/deploy/fwe@.service index 5152765d..0391279d 100644 --- a/tools/deploy/fwe@.service +++ b/tools/deploy/fwe@.service @@ -6,7 +6,7 @@ Wants=network-online.target setup-socketcan.service [Service] Restart=always RestartSec=1 -ExecStart=/usr/bin/aws-iot-fleetwise-edge /etc/aws-iot-fleetwise/config-%i.json +ExecStart=/usr/bin/run-fwe.sh %i [Install] WantedBy=multi-user.target diff --git a/tools/deploy/run-fwe.sh b/tools/deploy/run-fwe.sh new file mode 100755 index 00000000..e68840e9 --- /dev/null +++ b/tools/deploy/run-fwe.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -e + +if [ $# -eq 0 ]; then + echo "Instance number not provided" + exit 1 +fi + +EXTRA_ARGS="" + +/usr/bin/aws-iot-fleetwise-edge /etc/aws-iot-fleetwise/config-$1.json ${EXTRA_ARGS} diff --git a/tools/install-cansim.sh b/tools/install-cansim.sh index bd4ce8af..0aad1147 100755 --- a/tools/install-cansim.sh +++ b/tools/install-cansim.sh @@ -11,6 +11,7 @@ parse_args() { case $1 in --bus-count) BUS_COUNT=$2 + shift ;; --help) echo "Usage: $0 [OPTION]" @@ -24,14 +25,11 @@ parse_args() { parse_args "$@" -# Install Python 3.7 and pip -apt update && apt install -y python3.7 python3-setuptools curl -curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -python3.7 get-pip.py --user -rm get-pip.py +# Install Python 3 and pip +apt update && apt install -y python3 python3-pip # Install pip packages -python3.7 -m pip install \ +pip3 install \ wrapt==1.10.0 \ cantools==36.4.0 \ prompt_toolkit==3.0.21 \ diff --git a/tools/install-deps-cross-arm64.sh b/tools/install-deps-cross-arm64.sh index b9cc3365..cea1fb93 100755 --- a/tools/install-deps-cross-arm64.sh +++ b/tools/install-deps-cross-arm64.sh @@ -4,7 +4,11 @@ set -euo pipefail +SCRIPT_DIR=$(dirname $(realpath "$0")) +source ${SCRIPT_DIR}/install-deps-versions.sh + WITH_CAMERA_SUPPORT="false" +USE_CACHE="true" parse_args() { while [ "$#" -gt 0 ]; do @@ -12,9 +16,15 @@ parse_args() { --with-camera-support) WITH_CAMERA_SUPPORT="true" ;; + --native-prefix) + NATIVE_PREFIX="$2" + USE_CACHE="false" + shift + ;; --help) echo "Usage: $0 [OPTION]" - echo " --with-camera-support Installs dependencies required for camera support" + echo " --with-camera-support Install dependencies for camera support" + echo " --native-prefix Native install prefix" exit 0 ;; esac @@ -30,32 +40,52 @@ if [ "${ARCH}" == "arm64" ]; then exit -1 fi -cp tools/arm64.list /etc/apt/sources.list.d/ -mkdir -p /usr/local/aarch64-linux-gnu/lib/cmake/ -cp tools/arm64-toolchain.cmake /usr/local/aarch64-linux-gnu/lib/cmake/ - +cp ${SCRIPT_DIR}/arm64.list /etc/apt/sources.list.d/ dpkg --add-architecture arm64 sed -i "s/deb http/deb [arch=${ARCH}] http/g" /etc/apt/sources.list apt update apt install -y \ - libssl-dev:arm64 \ - libboost-system-dev:arm64 \ - libboost-log-dev:arm64 \ - libboost-thread-dev:arm64 \ build-essential \ - crossbuild-essential-arm64 \ cmake \ - unzip \ + crossbuild-essential-arm64 \ + curl \ git \ + libboost-log-dev:arm64 \ + libboost-system-dev:arm64 \ + libboost-thread-dev:arm64 \ + libsnappy-dev:arm64 \ + libssl-dev:arm64 \ + unzip \ wget \ - curl \ - zlib1g-dev:arm64 \ - libsnappy-dev:arm64 + zlib1g-dev:arm64 + +if ${WITH_CAMERA_SUPPORT}; then + apt install -y \ + default-jre \ + libasio-dev \ + qemu-user-binfmt +fi -mkdir -p deps-cross-arm64 && cd deps-cross-arm64 +if [ ! -f /usr/include/linux/can/isotp.h ]; then + git clone https://github.com/hartkopp/can-isotp.git + cd can-isotp + git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 + cp include/uapi/linux/can/isotp.h /usr/include/linux/can + cd .. + rm -rf can-isotp +fi -if [ ! -d jsoncpp ]; then - git clone -b 1.7.4 https://github.com/open-source-parsers/jsoncpp.git +if [ -z "${NATIVE_PREFIX+x}" ]; then + NATIVE_PREFIX="/usr/local/`gcc -dumpmachine`" +fi + +if ! ${USE_CACHE} || [ ! -d /usr/local/aarch64-linux-gnu ] || [ ! -d ${NATIVE_PREFIX} ]; then + mkdir -p /usr/local/aarch64-linux-gnu/lib/cmake/ + mkdir -p ${NATIVE_PREFIX} + cp ${SCRIPT_DIR}/arm64-toolchain.cmake /usr/local/aarch64-linux-gnu/lib/cmake/ + mkdir deps-cross-arm64 && cd deps-cross-arm64 + + git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp mkdir build && cd build cmake \ @@ -67,47 +97,33 @@ if [ ! -d jsoncpp ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-3.21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-cpp-3.21.7.tar.gz - tar -zxf protobuf-cpp-3.21.7.tar.gz - cd protobuf-3.21.7 + wget -q https://github.com/protocolbuffers/protobuf/releases/download/${VERSION_PROTOBUF_RELEASE}/protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + tar -zxf protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + cd protobuf-${VERSION_PROTOBUF} mkdir build && cd build - ../configure + ../configure --prefix=${NATIVE_PREFIX} + make install -j`nproc` cd .. mkdir build_arm64 && cd build_arm64 CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \ ../configure --host=aarch64-linux --prefix=/usr/local/aarch64-linux-gnu + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C protobuf-3.21.7/build -make install -j`nproc` -C protobuf-3.21.7/build_arm64 - -if [ ! -d can-isotp ]; then - git clone https://github.com/hartkopp/can-isotp.git - cd can-isotp - git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 - cd .. -fi -cp can-isotp/include/uapi/linux/can/isotp.h /usr/include/linux/can -if [ ! -d curl-7.86.0 ]; then - wget -q https://github.com/curl/curl/releases/download/curl-7_86_0/curl-7.86.0.tar.gz - tar -zxf curl-7.86.0.tar.gz - cd curl-7.86.0 + wget -q https://github.com/curl/curl/releases/download/${VERSION_CURL_RELEASE}/curl-${VERSION_CURL}.tar.gz + tar -zxf curl-${VERSION_CURL}.tar.gz + cd curl-${VERSION_CURL} mkdir build && cd build LDFLAGS="-static" PKG_CONFIG="pkg-config --static" CC=aarch64-linux-gnu-gcc ../configure \ --disable-shared --enable-static --disable-ldap --enable-ipv6 --with-ssl --disable-unix-sockets \ - --disable-rtsp --host=aarch64-linux --prefix=/usr/local/aarch64-linux-gnu + --disable-rtsp --without-zstd --host=aarch64-linux --prefix=/usr/local/aarch64-linux-gnu + make install -j`nproc` V=1 LDFLAGS="-static" cd ../.. -fi -make install -j`nproc` -C curl-7.86.0/build V=1 LDFLAGS="-static" -if [ ! -d aws-sdk-cpp ]; then - git clone -b 1.9.253 --recursive https://github.com/aws/aws-sdk-cpp.git + git clone -b ${VERSION_AWS_SDK_CPP} --recursive https://github.com/aws/aws-sdk-cpp.git cd aws-sdk-cpp mkdir build && cd build cmake \ @@ -121,36 +137,27 @@ if [ ! -d aws-sdk-cpp ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C aws-sdk-cpp/build -# AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: -if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then - apt install -y \ - default-jre \ - libasio-dev \ - qemu-user-binfmt - - if [ ! -d tinyxml2 ]; then - git clone -b 6.0.0 https://github.com/leethomason/tinyxml2.git + # AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: + if ${WITH_CAMERA_SUPPORT}; then + git clone -b ${VERSION_TINYXML2} https://github.com/leethomason/tinyxml2.git cd tinyxml2 mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_STATIC_LIBS=ON \ - -DBUILD_TESTING=OFF \ + -DBUILD_TESTS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C tinyxml2/build - if [ ! -d foonathan_memory_vendor ]; then - git clone -b v1.1.0 https://github.com/eProsima/foonathan_memory_vendor.git + git clone -b ${VERSION_FOONATHAN_MEMORY_VENDOR} https://github.com/eProsima/foonathan_memory_vendor.git cd foonathan_memory_vendor mkdir build && cd build cmake \ @@ -160,49 +167,46 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C foonathan_memory_vendor/build - if [ ! -d Fast-CDR ]; then - git clone -b v1.0.21 https://github.com/eProsima/Fast-CDR.git + git clone -b ${VERSION_FAST_CDR} https://github.com/eProsima/Fast-CDR.git cd Fast-CDR mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-CDR/build - if [ ! -d Fast-DDS ]; then - git clone -b v2.3.4 https://github.com/eProsima/Fast-DDS.git + git clone -b ${VERSION_FAST_DDS} https://github.com/eProsima/Fast-DDS.git cd Fast-DDS mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-DDS/build - if [ ! -d Fast-DDS-Gen ]; then - git clone -b v2.0.1 --recursive https://github.com/eProsima/Fast-DDS-Gen.git + git clone -b ${VERSION_FAST_DDS_GEN} --recursive https://github.com/eProsima/Fast-DDS-Gen.git cd Fast-DDS-Gen ./gradlew assemble + mkdir -p ${NATIVE_PREFIX}/share/fastddsgen/java + cp share/fastddsgen/java/fastddsgen.jar ${NATIVE_PREFIX}/share/fastddsgen/java + cp scripts/fastddsgen ${NATIVE_PREFIX}/bin cd .. fi - mkdir -p /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/share/fastddsgen/java/fastddsgen.jar /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/scripts/fastddsgen /usr/local/bin -fi -ldconfig + cd .. + rm -rf deps-cross-arm64 +fi diff --git a/tools/install-deps-cross-armhf.sh b/tools/install-deps-cross-armhf.sh index f538e0ed..0ae36ba3 100755 --- a/tools/install-deps-cross-armhf.sh +++ b/tools/install-deps-cross-armhf.sh @@ -4,7 +4,11 @@ set -euo pipefail +SCRIPT_DIR=$(dirname $(realpath "$0")) +source ${SCRIPT_DIR}/install-deps-versions.sh + WITH_CAMERA_SUPPORT="false" +USE_CACHE="true" parse_args() { while [ "$#" -gt 0 ]; do @@ -12,9 +16,15 @@ parse_args() { --with-camera-support) WITH_CAMERA_SUPPORT="true" ;; + --native-prefix) + NATIVE_PREFIX="$2" + USE_CACHE="false" + shift + ;; --help) echo "Usage: $0 [OPTION]" - echo " --with-camera-support Installs dependencies required for camera support" + echo " --with-camera-support Install dependencies for camera support" + echo " --native-prefix Native install prefix" exit 0 ;; esac @@ -30,32 +40,52 @@ if [ "${ARCH}" == "armhf" ]; then exit -1 fi -cp tools/armhf.list /etc/apt/sources.list.d/ -mkdir -p /usr/local/arm-linux-gnueabihf/lib/cmake/ -cp tools/armhf-toolchain.cmake /usr/local/arm-linux-gnueabihf/lib/cmake/ - +cp ${SCRIPT_DIR}/armhf.list /etc/apt/sources.list.d/ dpkg --add-architecture armhf sed -i "s/deb http/deb [arch=${ARCH}] http/g" /etc/apt/sources.list apt update apt install -y \ - libssl-dev:armhf \ - libboost-system-dev:armhf \ - libboost-log-dev:armhf \ - libboost-thread-dev:armhf \ build-essential \ - crossbuild-essential-armhf \ cmake \ - unzip \ + crossbuild-essential-armhf \ + curl \ git \ + libboost-log-dev:armhf \ + libboost-system-dev:armhf \ + libboost-thread-dev:armhf \ + libsnappy-dev:armhf \ + libssl-dev:armhf \ + unzip \ wget \ - curl \ - zlib1g-dev:armhf \ - libsnappy-dev:armhf + zlib1g-dev:armhf + +if ${WITH_CAMERA_SUPPORT}; then + apt install -y \ + default-jre \ + libasio-dev \ + qemu-user-binfmt +fi -mkdir -p deps-cross-armhf && cd deps-cross-armhf +if [ ! -f /usr/include/linux/can/isotp.h ]; then + git clone https://github.com/hartkopp/can-isotp.git + cd can-isotp + git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 + cp include/uapi/linux/can/isotp.h /usr/include/linux/can + cd .. + rm -rf can-isotp +fi -if [ ! -d jsoncpp ]; then - git clone -b 1.7.4 https://github.com/open-source-parsers/jsoncpp.git +if [ -z "${NATIVE_PREFIX+x}" ]; then + NATIVE_PREFIX="/usr/local/`gcc -dumpmachine`" +fi + +if ! ${USE_CACHE} || [ ! -d /usr/local/arm-linux-gnueabihf ] || [ ! -d ${NATIVE_PREFIX} ]; then + mkdir -p /usr/local/arm-linux-gnueabihf/lib/cmake/ + mkdir -p ${NATIVE_PREFIX} + cp ${SCRIPT_DIR}/armhf-toolchain.cmake /usr/local/arm-linux-gnueabihf/lib/cmake/ + mkdir deps-cross-armhf && cd deps-cross-armhf + + git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp mkdir build && cd build cmake \ @@ -67,47 +97,33 @@ if [ ! -d jsoncpp ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-3.21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-cpp-3.21.7.tar.gz - tar -zxf protobuf-cpp-3.21.7.tar.gz - cd protobuf-3.21.7 + wget -q https://github.com/protocolbuffers/protobuf/releases/download/${VERSION_PROTOBUF_RELEASE}/protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + tar -zxf protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + cd protobuf-${VERSION_PROTOBUF} mkdir build && cd build - ../configure + ../configure --prefix=${NATIVE_PREFIX} + make install -j`nproc` cd .. mkdir build_armhf && cd build_armhf CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ \ ../configure --host=arm-linux --prefix=/usr/local/arm-linux-gnueabihf + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C protobuf-3.21.7/build -make install -j`nproc` -C protobuf-3.21.7/build_armhf - -if [ ! -d can-isotp ]; then - git clone https://github.com/hartkopp/can-isotp.git - cd can-isotp - git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 - cd .. -fi -cp can-isotp/include/uapi/linux/can/isotp.h /usr/include/linux/can -if [ ! -d curl-7.86.0 ]; then - wget -q https://github.com/curl/curl/releases/download/curl-7_86_0/curl-7.86.0.tar.gz - tar -zxf curl-7.86.0.tar.gz - cd curl-7.86.0 + wget -q https://github.com/curl/curl/releases/download/${VERSION_CURL_RELEASE}/curl-${VERSION_CURL}.tar.gz + tar -zxf curl-${VERSION_CURL}.tar.gz + cd curl-${VERSION_CURL} mkdir build && cd build LDFLAGS="-static" PKG_CONFIG="pkg-config --static" CC=arm-linux-gnueabihf-gcc ../configure \ --disable-shared --enable-static --disable-ldap --enable-ipv6 --with-ssl --disable-unix-sockets \ - --disable-rtsp --host=arm-linux --prefix=/usr/local/arm-linux-gnueabihf + --disable-rtsp --without-zstd --host=arm-linux --prefix=/usr/local/arm-linux-gnueabihf + make install -j`nproc` V=1 LDFLAGS="-static" cd ../.. -fi -make install -j`nproc` -C curl-7.86.0/build V=1 LDFLAGS="-static" -if [ ! -d aws-sdk-cpp ]; then - git clone -b 1.9.253 --recursive https://github.com/aws/aws-sdk-cpp.git + git clone -b ${VERSION_AWS_SDK_CPP} --recursive https://github.com/aws/aws-sdk-cpp.git cd aws-sdk-cpp mkdir build && cd build cmake \ @@ -121,19 +137,12 @@ if [ ! -d aws-sdk-cpp ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C aws-sdk-cpp/build -# AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: -if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then - apt install -y \ - default-jre \ - libasio-dev \ - qemu-user-binfmt - - if [ ! -d tinyxml2 ]; then - git clone -b 6.0.0 https://github.com/leethomason/tinyxml2.git + # AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: + if ${WITH_CAMERA_SUPPORT}; then + git clone -b ${VERSION_TINYXML2} https://github.com/leethomason/tinyxml2.git cd tinyxml2 mkdir build && cd build cmake \ @@ -145,12 +154,10 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C tinyxml2/build - if [ ! -d foonathan_memory_vendor ]; then - git clone -b v1.1.0 https://github.com/eProsima/foonathan_memory_vendor.git + git clone -b ${VERSION_FOONATHAN_MEMORY_VENDOR} https://github.com/eProsima/foonathan_memory_vendor.git cd foonathan_memory_vendor mkdir build && cd build cmake \ @@ -160,49 +167,46 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C foonathan_memory_vendor/build - if [ ! -d Fast-CDR ]; then - git clone -b v1.0.21 https://github.com/eProsima/Fast-CDR.git + git clone -b ${VERSION_FAST_CDR} https://github.com/eProsima/Fast-CDR.git cd Fast-CDR mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-CDR/build - if [ ! -d Fast-DDS ]; then - git clone -b v2.3.4 https://github.com/eProsima/Fast-DDS.git + git clone -b ${VERSION_FAST_DDS} https://github.com/eProsima/Fast-DDS.git cd Fast-DDS mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ + -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-DDS/build - if [ ! -d Fast-DDS-Gen ]; then - git clone -b v2.0.1 --recursive https://github.com/eProsima/Fast-DDS-Gen.git + git clone -b ${VERSION_FAST_DDS_GEN} --recursive https://github.com/eProsima/Fast-DDS-Gen.git cd Fast-DDS-Gen ./gradlew assemble + mkdir -p ${NATIVE_PREFIX}/share/fastddsgen/java + cp share/fastddsgen/java/fastddsgen.jar ${NATIVE_PREFIX}/share/fastddsgen/java + cp scripts/fastddsgen ${NATIVE_PREFIX}/bin cd .. fi - mkdir -p /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/share/fastddsgen/java/fastddsgen.jar /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/scripts/fastddsgen /usr/local/bin -fi -ldconfig + cd .. + rm -rf deps-cross-armhf +fi diff --git a/tools/install-deps-native.sh b/tools/install-deps-native.sh index 1e2058e6..d918ef56 100755 --- a/tools/install-deps-native.sh +++ b/tools/install-deps-native.sh @@ -4,7 +4,12 @@ set -euo pipefail +SCRIPT_DIR=$(dirname $(realpath "$0")) +source ${SCRIPT_DIR}/install-deps-versions.sh + WITH_CAMERA_SUPPORT="false" +USE_CACHE="true" +INSTALL_BUILD_TIME_DEPS="true" parse_args() { while [ "$#" -gt 0 ]; do @@ -12,9 +17,19 @@ parse_args() { --with-camera-support) WITH_CAMERA_SUPPORT="true" ;; + --prefix) + PREFIX="$2" + USE_CACHE="false" + shift + ;; + --runtime-only) + INSTALL_BUILD_TIME_DEPS="false" + ;; --help) echo "Usage: $0 [OPTION]" - echo " --with-camera-support Installs dependencies required for camera support" + echo " --with-camera-support Install dependencies for camera support" + echo " --runtime-only Install only runtime dependencies" + echo " --prefix Install prefix" exit 0 ;; esac @@ -24,31 +39,53 @@ parse_args() { parse_args "$@" -apt update -apt install -y \ - libssl-dev \ - libboost-system-dev \ - libboost-log-dev \ - libboost-thread-dev \ - build-essential \ - cmake \ - faketime \ - unzip \ - git \ - wget \ - zlib1g-dev \ - libsnappy-dev \ - doxygen \ - graphviz \ - clang-format-10 \ - clang-tidy-10 -update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-10 1000 -update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-10 1000 - -mkdir -p deps-native && cd deps-native - -if [ ! -d jsoncpp ]; then - git clone -b 1.7.4 https://github.com/open-source-parsers/jsoncpp.git +if ${INSTALL_BUILD_TIME_DEPS}; then + apt update + apt install -y \ + build-essential \ + clang-format-10 \ + clang-tidy-10 \ + cmake \ + doxygen \ + faketime \ + git \ + graphviz \ + libboost-log-dev \ + libboost-system-dev \ + libboost-thread-dev \ + libsnappy-dev \ + libssl-dev \ + unzip \ + wget \ + zlib1g-dev + update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-10 1000 + update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-10 1000 +fi + +if ${INSTALL_BUILD_TIME_DEPS} && ${WITH_CAMERA_SUPPORT}; then + apt install -y \ + default-jre \ + libasio-dev +fi + +if ${INSTALL_BUILD_TIME_DEPS} && [ ! -f /usr/include/linux/can/isotp.h ]; then + git clone https://github.com/hartkopp/can-isotp.git + cd can-isotp + git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 + cp include/uapi/linux/can/isotp.h /usr/include/linux/can + cd .. + rm -rf can-isotp +fi + +if [ -z "${PREFIX+x}" ]; then + PREFIX="/usr/local/`gcc -dumpmachine`" +fi + +if ${INSTALL_BUILD_TIME_DEPS} && ( ! ${USE_CACHE} || [ ! -d ${PREFIX} ] ); then + mkdir -p ${PREFIX} + mkdir deps-native && cd deps-native + + git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp mkdir build && cd build cmake \ @@ -57,42 +94,29 @@ if [ ! -d jsoncpp ]; then -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DJSONCPP_WITH_TESTS=Off \ -DJSONCPP_WITH_POST_BUILD_UNITTEST=Off \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-3.21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-cpp-3.21.7.tar.gz - tar -zxf protobuf-cpp-3.21.7.tar.gz - cd protobuf-3.21.7 + wget -q https://github.com/protocolbuffers/protobuf/releases/download/${VERSION_PROTOBUF_RELEASE}/protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + tar -zxf protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + cd protobuf-${VERSION_PROTOBUF} mkdir build && cd build - ../configure + ../configure --prefix=${PREFIX} + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C protobuf-3.21.7/build - -if [ ! -d can-isotp ]; then - git clone https://github.com/hartkopp/can-isotp.git - cd can-isotp - git checkout beb4650660179963a8ed5b5cbf2085cc1b34f608 - cd .. -fi -cp can-isotp/include/uapi/linux/can/isotp.h /usr/include/linux/can -if [ ! -d curl-7.86.0 ]; then - wget -q https://github.com/curl/curl/releases/download/curl-7_86_0/curl-7.86.0.tar.gz - tar -zxf curl-7.86.0.tar.gz - cd curl-7.86.0 + wget -q https://github.com/curl/curl/releases/download/${VERSION_CURL_RELEASE}/curl-${VERSION_CURL}.tar.gz + tar -zxf curl-${VERSION_CURL}.tar.gz + cd curl-${VERSION_CURL} mkdir build && cd build LDFLAGS="-static" PKG_CONFIG="pkg-config --static" ../configure --disable-shared --enable-static \ - --disable-ldap --enable-ipv6 --with-ssl --disable-unix-sockets --disable-rtsp + --disable-ldap --enable-ipv6 --with-ssl --disable-unix-sockets --disable-rtsp --without-zstd --prefix=${PREFIX} + make install -j`nproc` V=1 LDFLAGS="-static" cd ../.. -fi -make install -j`nproc` -C curl-7.86.0/build V=1 LDFLAGS="-static" -if [ ! -d aws-sdk-cpp ]; then - git clone -b 1.9.253 --recursive https://github.com/aws/aws-sdk-cpp.git + git clone -b ${VERSION_AWS_SDK_CPP} --recursive https://github.com/aws/aws-sdk-cpp.git cd aws-sdk-cpp mkdir build && cd build cmake \ @@ -102,82 +126,73 @@ if [ ! -d aws-sdk-cpp ]; then -DBUILD_ONLY='s3-crt;iot' \ -DAWS_CUSTOM_MEMORY_MANAGEMENT=ON \ -DZLIB_LIBRARY=/usr/lib/$(gcc -dumpmachine)/libz.a \ - -DCURL_LIBRARY=/usr/local/lib/libcurl.a \ + -DCURL_LIBRARY=${PREFIX}/lib/libcurl.a \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C aws-sdk-cpp/build -if [ ! -d googletest ]; then - git clone -b release-1.10.0 https://github.com/google/googletest.git + git clone -b ${VERSION_GOOGLE_TEST} https://github.com/google/googletest.git cd googletest mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C googletest/build -if [ ! -d benchmark ]; then - git clone -b v1.6.1 https://github.com/google/benchmark.git + git clone -b ${VERSION_GOOGLE_BENCHMARK} https://github.com/google/benchmark.git cd benchmark mkdir build && cd build cmake \ + -DBUILD_SHARED_LIBS=OFF \ -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on \ -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. -fi -make install -j`nproc` -C benchmark/build -# AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: -if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then - apt install -y \ - default-jre \ - libasio-dev - - if [ ! -d tinyxml2 ]; then - git clone -b 6.0.0 https://github.com/leethomason/tinyxml2.git + # AWS IoT FleetWise Edge camera support requires Fast-DDS and its dependencies: + if ${WITH_CAMERA_SUPPORT}; then + git clone -b ${VERSION_TINYXML2} https://github.com/leethomason/tinyxml2.git cd tinyxml2 mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_STATIC_LIBS=ON \ - -DBUILD_TESTING=OFF \ + -DBUILD_TESTS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=On \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C tinyxml2/build - if [ ! -d foonathan_memory_vendor ]; then - git clone -b v1.1.0 https://github.com/eProsima/foonathan_memory_vendor.git + git clone -b ${VERSION_FOONATHAN_MEMORY_VENDOR} https://github.com/eProsima/foonathan_memory_vendor.git cd foonathan_memory_vendor mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C foonathan_memory_vendor/build - if [ ! -d Fast-CDR ]; then - git clone -b v1.0.21 https://github.com/eProsima/Fast-CDR.git + git clone -b ${VERSION_FAST_CDR} https://github.com/eProsima/Fast-CDR.git cd Fast-CDR mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-CDR/build - if [ ! -d Fast-DDS ]; then - git clone -b v2.3.4 https://github.com/eProsima/Fast-DDS.git + git clone -b ${VERSION_FAST_DDS} https://github.com/eProsima/Fast-DDS.git cd Fast-DDS mkdir build && cd build cmake \ @@ -185,20 +200,20 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \ + -DCMAKE_INSTALL_PREFIX=${PREFIX} \ .. + make install -j`nproc` cd ../.. - fi - make install -j`nproc` -C Fast-DDS/build - if [ ! -d Fast-DDS-Gen ]; then - git clone -b v2.0.1 --recursive https://github.com/eProsima/Fast-DDS-Gen.git + git clone -b ${VERSION_FAST_DDS_GEN} --recursive https://github.com/eProsima/Fast-DDS-Gen.git cd Fast-DDS-Gen ./gradlew assemble + mkdir -p ${PREFIX}/share/fastddsgen/java + cp share/fastddsgen/java/fastddsgen.jar ${PREFIX}/share/fastddsgen/java + cp scripts/fastddsgen ${PREFIX}/bin cd .. fi - mkdir -p /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/share/fastddsgen/java/fastddsgen.jar /usr/local/share/fastddsgen/java - cp Fast-DDS-Gen/scripts/fastddsgen /usr/local/bin -fi -ldconfig + cd .. + rm -rf deps-native +fi diff --git a/tools/install-deps-versions.sh b/tools/install-deps-versions.sh new file mode 100755 index 00000000..b3ff82e8 --- /dev/null +++ b/tools/install-deps-versions.sh @@ -0,0 +1,14 @@ +#!/bin/bash +export VERSION_JSON_CPP="1.7.4" +export VERSION_PROTOBUF="3.21.7" +export VERSION_PROTOBUF_RELEASE="v21.7" +export VERSION_CURL="7.86.0" +export VERSION_CURL_RELEASE="curl-7_86_0" +export VERSION_AWS_SDK_CPP="1.9.253" +export VERSION_TINYXML2="6.0.0" +export VERSION_FOONATHAN_MEMORY_VENDOR="v1.1.0" +export VERSION_FAST_CDR="v1.0.21" +export VERSION_FAST_DDS="v2.3.4" +export VERSION_FAST_DDS_GEN="v2.0.1" +export VERSION_GOOGLE_TEST="release-1.10.0" +export VERSION_GOOGLE_BENCHMARK="v1.6.1" diff --git a/tools/install-fwe.sh b/tools/install-fwe.sh index 0be5ac81..47e3a312 100755 --- a/tools/install-fwe.sh +++ b/tools/install-fwe.sh @@ -9,6 +9,7 @@ set -e mkdir -p /var/aws-iot-fleetwise cp build/src/executionmanagement/aws-iot-fleetwise-edge /usr/bin/ +cp tools/deploy/run-fwe.sh /usr/bin/ cp tools/deploy/fwe@.service /lib/systemd/system/ ./tools/deploy/start-and-enable-fwe.sh diff --git a/tools/install-socketcan.sh b/tools/install-socketcan.sh index c4e24293..a382440f 100755 --- a/tools/install-socketcan.sh +++ b/tools/install-socketcan.sh @@ -11,6 +11,7 @@ parse_args() { case $1 in --bus-count) BUS_COUNT=$2 + shift ;; --help) echo "Usage: $0 [OPTION]" @@ -24,12 +25,14 @@ parse_args() { parse_args "$@" -# Install packages -apt update && apt install -y can-utils +if ! command -v cansend > /dev/null; then + # Install packages + apt update && apt install -y can-utils +fi # For EC2, the SocketCAN modules vcan and can-gw are included in a separate package: if uname -r | grep -q aws; then - apt install -y linux-modules-extra-aws + apt update && apt install -y linux-modules-extra-aws fi # Install can-isotp kernel module if not installed diff --git a/tools/provision.sh b/tools/provision.sh index fa2e131c..a1c9ed9f 100755 --- a/tools/provision.sh +++ b/tools/provision.sh @@ -14,30 +14,41 @@ CERT_OUT_FILE="certificate.pem" PRIVATE_KEY_OUT_FILE="private-key.key" ENDPOINT_URL_OUT_FILE="" VEHICLE_NAME_OUT_FILE="" +ONLY_CLEAN_UP=false parse_args() { while [ "$#" -gt 0 ]; do case $1 in --vehicle-name) VEHICLE_NAME=$2 + shift ;; --certificate-pem-outfile) CERT_OUT_FILE=$2 + shift ;; --private-key-outfile) PRIVATE_KEY_OUT_FILE=$2 + shift ;; --endpoint-url-outfile) ENDPOINT_URL_OUT_FILE=$2 + shift ;; --vehicle-name-outfile) VEHICLE_NAME_OUT_FILE=$2 + shift ;; --endpoint-url) ENDPOINT_URL=$2 + shift ;; --region) REGION=$2 + shift + ;; + --only-clean-up) + ONLY_CLEAN_UP=true ;; --help) echo "Usage: $0 [OPTION]" @@ -48,6 +59,7 @@ parse_args() { echo " --vehicle-name-outfile Vehicle name output file" echo " --endpoint-url The endpoint URL used for AWS CLI calls" echo " --region The region used for AWS CLI calls, default: ${REGION}" + echo " --only-clean-up Clean up resources created by previous runs of this script" exit 0 ;; esac @@ -75,6 +87,35 @@ fi NAME="${VEHICLE_NAME}-${TIMESTAMP}" +if [ ${ONLY_CLEAN_UP} == true ]; then + + PRINCIPAL_ARN=$(aws iot list-thing-principals --thing-name ${VEHICLE_NAME} --region ${REGION} | jq -r ".principals[0]") + CERTIFICATE_ID=$(echo ${PRINCIPAL_ARN} | cut -d'/' -f2 ) + POLICY_NAME=$(aws iot list-principal-policies --principal ${PRINCIPAL_ARN} --region ${REGION} | jq -r ".policies[0].policyName") + + RETRY_COUNTER=10 + while ! aws iot delete-thing --thing-name ${VEHICLE_NAME} --region ${REGION} + do + # Delete depending resources + aws iot detach-thing-principal --thing-name ${VEHICLE_NAME} --principal ${PRINCIPAL_ARN} --region ${REGION} || true + aws iot detach-principal-policy --policy-name "${POLICY_NAME}" --principal ${PRINCIPAL_ARN} --region ${REGION} || true + aws iot delete-policy --policy-name "${POLICY_NAME}" --region ${REGION} || true + aws iot update-certificate --certificate-id ${CERTIFICATE_ID} --new-status INACTIVE --region ${REGION} || true + aws iot delete-certificate --certificate-id ${CERTIFICATE_ID} --region ${REGION} || true + + echo "Wait one second before next retry" + sleep 1 + if [ "${RETRY_COUNTER}" -eq "0" ]; then + echo "Failed aws iot delete-thing" + exit 1 + fi + ((RETRY_COUNTER--)) + done + echo "Successfully deleted iot thing" + exit 0 + +fi + echo -n "Date: " date --rfc-3339=seconds diff --git a/tools/yocto/README.md b/tools/yocto/README.md index 3600afa1..fca26522 100644 --- a/tools/yocto/README.md +++ b/tools/yocto/README.md @@ -11,7 +11,7 @@ This folder provides an additional meta layer on top of BSP 28.0, in order to ad ## Prerequisites -Run the following script to install the prerequisites on an Ubuntu 18.04 host machine (assuming you +Run the following script to install the prerequisites on an Ubuntu 20.04 host machine (assuming you have unzipped `aws-iot-fleetwise-edge.zip` to `~/aws-iot-fleetwise-edge`): sudo ~/aws-iot-fleetwise-edge/tools/install-deps-yocto.sh diff --git a/tools/yocto/build_s32g274ardb2ubuntu/conf/local.conf b/tools/yocto/build_s32g274ardb2ubuntu/conf/local.conf index 0991e146..bd14ce13 100644 --- a/tools/yocto/build_s32g274ardb2ubuntu/conf/local.conf +++ b/tools/yocto/build_s32g274ardb2ubuntu/conf/local.conf @@ -29,7 +29,7 @@ SSTATE_PKG_SUFFIX = "txz" SSTATE_PKG_TARZIPPROG = "xz" # Ubuntu Version -UBUNTU_TARGET_VERSION = "18.04.5" +UBUNTU_TARGET_VERSION = "20.04.1" # Additional recipes IMAGE_INSTALL_append = " \