diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4543357e..c2e1375e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,10 @@ name: CI +permissions: + id-token: write + contents: write + on: push: branches: [ '*' ] @@ -12,8 +16,6 @@ on: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} jobs: build-amd64: @@ -61,15 +63,19 @@ jobs: find linux -name aws-iot-fleetwise-edge -exec chmod +x {} \; - uses: docker/setup-qemu-action@v2 - uses: docker/setup-buildx-action@v2 - - uses: docker/login-action@v2 + - uses: aws-actions/configure-aws-credentials@v1 + if: github.ref_type == 'tag' + with: + role-to-assume: ${{ secrets.PUBLIC_ECR_PUSH_ROLE }} + aws-region: us-east-1 + - uses: aws-actions/amazon-ecr-login@v1 + if: github.ref_type == 'tag' with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ env.GITHUB_TOKEN }} + registry-type: public - id: meta uses: docker/metadata-action@v4 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: public.ecr.aws/aws-iot-fleetwise-edge/aws-iot-fleetwise-edge - uses: docker/build-push-action@v3 with: context: . diff --git a/CHANGELOG.md b/CHANGELOG.md index bb34b032..e6297908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## v1.0.3 (Jan 9, 2023) + +Features: +* Added OBD broadcast support to send functional rather than physical requests to ECUs to improve compatibility with a broader range of vehicles. + This behavior does however increase CAN bus load. The config option `broadcastRequests` can be set to `false` to disable it. + +Bugfixes: +* Fix `CollectionSchemeManager` and `CollectionInspectionEngine` to use monotonic clock + This now makes check-in and data collection work even when the system time jumps. + Please note that the timestamp present in check-in and collected data may still represent the system time, which means that newly collected data may + be sent with a timestamp that is earlier than the previous sent data in case the system time is changed to some time in the past. + +Improvements: +* Logs now show time in ISO 8601 format and UTC. +* Added optional config `logColor` for controlling ANSI colors in the logs. Valid values: `Auto`, `Yes`, `No`. Default value is `Auto`, which will make + the agent try to detect whether stdout can interpret the ANSI color escape sequences. +* A containerized version of the edge agent is available from AWS ECR Public Gallery: https://gallery.ecr.aws/aws-iot-fleetwise-edge/aws-iot-fleetwise-edge. +* Improve CERT-CPP compliance. +* Improve quick start guide and demo script. +* Clarify the meaning of the `startBit`. + ## v1.0.2 (Nov 28, 2022) Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index f1430df2..15730d37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10.2) -project(iotfleetwise VERSION 1.0.2) +project(iotfleetwise VERSION 1.0.3) # AWS IoT FleetWise Edge uses C++14 for compatibility reasons with # Automotive middlewares ( Adaptive AUTOSAR, ROS2) @@ -38,7 +38,7 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -include(CMakeGraphVizOptions.cmake) +include(cmake/graphviz.cmake) include(cmake/compiler_gcc.cmake) include(cmake/protobufs.cmake) if(FWE_FEATURE_CAMERA) diff --git a/cmake/doxygen.cmake b/cmake/doxygen.cmake index d4815942..a3991c9e 100644 --- a/cmake/doxygen.cmake +++ b/cmake/doxygen.cmake @@ -31,6 +31,7 @@ if(DOXYGEN_FOUND) set(DOXYGEN_TEMPLATE_RELATIONS YES) set(DOXYGEN_TOC_INCLUDE_HEADINGS 5) set(DOXYGEN_UML_LOOK YES) + set(DOXYGEN_EXCLUDE_PATTERNS "*.md") doxygen_add_docs( doc_doxygen diff --git a/CMakeGraphVizOptions.cmake b/cmake/graphviz.cmake similarity index 100% rename from CMakeGraphVizOptions.cmake rename to cmake/graphviz.cmake diff --git a/configuration/static-config.json b/configuration/static-config.json index fff548e8..7e8a9413 100644 --- a/configuration/static-config.json +++ b/configuration/static-config.json @@ -15,7 +15,8 @@ "interfaceName": "vcan0", "obdStandard": "J1979", "pidRequestIntervalSeconds": 0, - "dtcRequestIntervalSeconds": 0 + "dtcRequestIntervalSeconds": 0, + "broadcastRequests": true }, "interfaceId": "2", "type": "obdInterface" diff --git a/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md b/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md index daf8aa21..c42a9853 100644 --- a/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md +++ b/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md @@ -93,6 +93,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ && ../tools/configure-fwe.sh \ --input-config-file ~/aws-iot-fleetwise-edge/configuration/static-config.json \ --output-config-file config-0.json \ + --log-color Yes \ --vehicle-name `cat vehicle-name.txt` \ --endpoint-url `cat endpoint.txt` \ --can-bus0 can0 \ @@ -126,7 +127,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ 1. Run the following **_on the S32G_** to view and follow the AWS IoT FleetWise Edge Agent log (press CTRL+C to exit): ```bash - sudo journalctl -fu fwe@0 + sudo journalctl -fu fwe@0 --output=cat ``` ## Collect OBD Data 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 3d540472..f44582e6 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 @@ -109,6 +109,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ && ../tools/configure-fwe.sh \ --input-config-file ~/aws-iot-fleetwise-edge/configuration/static-config.json \ --output-config-file config-0.json \ + --log-color Yes \ --vehicle-name `cat vehicle-name.txt` \ --endpoint-url `cat endpoint.txt` \ --can-bus0 vcan0 \ @@ -150,7 +151,7 @@ mkdir -p ~/aws-iot-fleetwise-deploy && cd ~/aws-iot-fleetwise-deploy \ 1. Run the following **_on the R-Car S4 Spider board_** to view and follow the AWS IoT FleetWise Edge Agent log (press CTRL+C to exit): ```bash - sudo journalctl -fu fwe@0 + sudo journalctl -fu fwe@0 --output=cat ``` ## Collect OBD Data diff --git a/docs/dev-guide/edge-agent-dev-guide.md b/docs/dev-guide/edge-agent-dev-guide.md index ef19dfd6..e58b7d35 100644 --- a/docs/dev-guide/edge-agent-dev-guide.md +++ b/docs/dev-guide/edge-agent-dev-guide.md @@ -29,14 +29,14 @@ You can use the included sample C++ application to learn more about AWS IoT Flee # AWS IoT FleetWise quick start demo -This guide is intended to quickly demonstrate the basic features of AWS IoT FleetWise by firstly building AWS IoT FleetWise Edge Agent and running it on an AWS EC2 instance representing one or more simulated vehicles. A script is then run using the AWS CLI to control AWS IoT FleetWise Cloud in order collect data from the vehicle. +This guide is intended to quickly demonstrate the basic features of AWS IoT FleetWise by firstly deploying the AWS IoT FleetWise Edge Agent to an AWS EC2 instance representing one or more simulated vehicles. A script is then run using the AWS CLI to control AWS IoT FleetWise Cloud in order collect data from the vehicle. This guide showcases AWS IoT FleetWise at a high level. If you are interested in exploring AWS IoT FleetWise at a more detailed technical level, see [Getting started with AWS IoT FleetWise Edge Agent](#getting-started-with-aws-iot-fleetwise-edge-agent). **Topics:** - [Prerequisites for quick start demo](#prerequisites-for-quick-start-demo) -- [Build the AWS IoT FleetWise Edge Agent software](#build-the-aws-iot-fleetwise-edge-agent-software) +- [Deploy the AWS IoT FleetWise Edge Agent software](#deploy-the-aws-iot-fleetwise-edge-agent-software) - [Use the AWS IoT FleetWise cloud demo](#use-the-aws-iot-fleetwise-cloud-demo) - [Explore collected data](#explore-collected-data) @@ -46,15 +46,15 @@ This guide assumes you have already logged in to the AWS console in your desired - Note: AWS IoT FleetWise is currently available in US East (N. Virginia) and Europe (Frankfurt). -## Build the AWS IoT FleetWise Edge Agent software +## Deploy the AWS IoT FleetWise Edge Agent software -An AWS CloudFormation template is used to build AWS IoT FleetWise Edge Agent using AWS CodeBuild and deploy it to a new AWS EC2 instance using AWS CodeDeploy. +An AWS CloudFormation template is used to deploy the AWS IoT FleetWise Edge Agent to a new AWS EC2 instance. 1. Click here to [**Launch CloudFormation Template**](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/quickcreate?templateUrl=https%3A%2F%2Faws-iot-fleetwise.s3.us-west-2.amazonaws.com%2Flatest%2Fcfn-templates%2Ffwdemo.yml&stackName=fwdemo). 1. (Optional) You can increase the number of simulated vehicles by updating the `FleetSize` parameter. You can also specify the region IoT Things are created in by updating the `IoTCoreRegion` parameter. 1. Select the checkbox next to _‘I acknowledge that AWS CloudFormation might create IAM resources with custom names.’_ 1. Choose **Create stack**. -1. Wait until the status of the Stack is ‘CREATE_COMPLETE’, this will take approximately 15 minutes. +1. Wait until the status of the Stack is ‘CREATE_COMPLETE’, this will take approximately 10 minutes. AWS IoT FleetWise Edge Agent software has been deployed to an AWS EC2 Graviton (ARM64) Instance along with credentials that allow it to connect to AWS IoT Core. CAN data is also being generated on the EC2 instance to simulate periodic hard-braking events. The AWS IoT FleetWise Cloud demo script in the following section will deploy a campaign to the simulated fleet of vehicles to capture the engine torque when a hard braking-event occurs. @@ -63,14 +63,12 @@ AWS IoT FleetWise Edge Agent software has been deployed to an AWS EC2 Graviton ( The instructions below will register your AWS account for AWS IoT FleetWise, create a demonstration vehicle model, register the virtual vehicle created in the previous section and run a campaign to collect data from it. 1. Open the AWS CloudShell: [Launch CloudShell](https://console.aws.amazon.com/cloudshell/home) -1. Copy and paste the following commands to clone the latest AWS IoT FleetWise Edge Agent software from GitHub, install the dependencies of the cloud demo script and enable IoT FleetWise commands in the AWS CLI. +1. Copy and paste the following commands to clone the latest AWS IoT FleetWise Edge Agent software from GitHub and install the dependencies of the cloud demo script. ```bash git clone https://github.com/aws/aws-iot-fleetwise-edge.git ~/aws-iot-fleetwise-edge \ && cd ~/aws-iot-fleetwise-edge/tools/cloud \ - && pip3 install wrapt==1.10.0 plotly==5.3.1 pandas==1.3.4 cantools==36.4.0 \ - && aws configure add-model --service-model file://iotfleetwise-2021-06-17.json \ - --service-name iotfleetwise + && pip3 install wrapt==1.10.0 plotly==5.3.1 pandas==1.3.4 cantools==36.4.0 ``` The AWS IoT FleetWise Cloud demo script performs the following: @@ -189,7 +187,8 @@ An Ubuntu 18.04 development machine with 200GB free disk space will be required. 1. Install the AWS IoT FleetWise Edge Agent dependencies - Commands below will: + Commands below will: + 1. Install the following Ubuntu packages: `libssl-dev libboost-system-dev libboost-log-dev libboost-thread-dev build-essential cmake unzip git wget curl zlib1g-dev libcurl4-openssl-dev libsnappy-dev default-jre libasio-dev`. Additionally it installs the following: `jsoncpp protobuf aws-sdk-cpp` 1. Install the following Ubuntu packages: `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. @@ -224,6 +223,7 @@ An Ubuntu 18.04 development machine with 200GB free disk space will be required. && sudo ./tools/configure-fwe.sh \ --input-config-file configuration/static-config.json \ --output-config-file /etc/aws-iot-fleetwise/config-0.json \ + --log-color Yes \ --vehicle-name `cat /etc/aws-iot-fleetwise/vehicle-name.txt` \ --endpoint-url `cat /etc/aws-iot-fleetwise/endpoint.txt` \ --can-bus0 vcan0 \ @@ -235,23 +235,20 @@ An Ubuntu 18.04 development machine with 200GB free disk space will be required. 1. Run the following to view and follow the AWS IoT FleetWise Edge Agent log. You can open a new SSH session with the development machine and run this command to follow the log in real time as the campaign is deployed in the next section. To exit the logs, use CTRL + C. ```bash - sudo journalctl -fu fwe@0 + sudo journalctl -fu fwe@0 --output=cat ``` ### Run the AWS IoT FleetWise demo script The instructions below will register your AWS account for AWS IoT FleetWise, create a demonstration vehicle model, register the virtual vehicle created in the previous section, and run a campaign to collect data from it. -1. Run the following _on the development machine_ to install the dependencies of the AWS IoT FleetWise Cloud demo script and add AWS IoT FleetWise commands to the AWS CLI: +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` ```bash cd ~/aws-iot-fleetwise-edge/tools/cloud \ - && sudo -H ./install-deps.sh \ - && aws configure add-model \ - --service-model file://iotfleetwise-2021-06-17.json \ - --service-name iotfleetwise + && sudo -H ./install-deps.sh ``` 1. Run the following to explore the AWS IoT FleetWise CLI: @@ -314,7 +311,7 @@ The instructions below will register your AWS account for AWS IoT FleetWise, cre ./demo.sh --vehicle-name fwdemo-ec2 --campaign-file campaign-obd-heartbeat.json --region eu-central-1 ``` -1. Run the following _on the development machine_ to import your custom DBC file. You also have to provide your custom campaign file. There is no support of simulation of custom signals so you have to test data collection with the real vehicle or custom simulator. +1. Run the following _on the development machine_ to import your custom DBC file. You also have to provide your custom campaign file. There is no support of simulation of custom signals so you have to test data collection with the real vehicle or custom simulator. ```bash ./demo.sh --vehicle-name fwdemo-ec2 --dbc-file --campaign-file @@ -326,7 +323,6 @@ The instructions below will register your AWS account for AWS IoT FleetWise, cre ./demo.sh --vehicle-name fwdemo-ec2 --dbc-file --campaign-file --region eu-central-1 ``` - ## Getting started with AWS IoT FleetWise Edge Agent on NXP S32G [Getting started with AWS IoT FleetWise Edge Agent on NXP S32G](./edge-agent-dev-guide-nxp-s32g.md) @@ -1372,7 +1368,8 @@ Customers can set the System level logging severity externally via the software | | persistencyPartitionMaxSize | Maximum size allocated for persistency (Bytes) | integer | | | persistencyUploadRetryIntervalMs | Interval to wait before retrying to upload persisted signal data (in milliseconds). After successfully uploading, the persisted signal data will be cleared. Only signal data that could not be uploaded will be persisted. (in milliseconds) | integer | | internalParameters | readyToPublishDataBufferSize | Size of the buffer used for storing ready to publish, filtered data | integer | -| | systemWideLogLevel | Sets logging level severity- Trace, Info, Warning, Error | string | +| | systemWideLogLevel | Sets logging level severity: `Trace`, `Info`, `Warning`, `Error` | string | +| | logColor | Whether logs should be colored: `Auto`, `Yes`, `No`. Default to `Auto`, meaning the agent will try to detect whether colored output is supported (for example when connected to a tty) | string | | | dataReductionProbabilityDisabled | Disables probability-based DDC (only for debug purpose) | boolean | | | metricsCyclicPrintIntervalMs | Sets the interval in milliseconds how often the application metrics should be printed to stdout. Default 0 means never | string | | publishToCloudParameters | maxPublishMessageCount | Maximum messages that can be published to the cloud in one payload | integer | @@ -1395,7 +1392,7 @@ The device software has been designed with security principles in mind. Security - Data at rest: the current version of the software does not encrypt the data at rest i.e. during persistency. It’s assumed that the software operates in a secure partition that the OEM puts in place and rely on the OEM secure storage infrastructure that is applied for all IO operations happening in the gateway e.g. via HSM, OEM crypto stack. - Access to vehicle CAN data: the device software assumes that the software operates in a secure execution partition, that guarantees that if needed, the CAN traffic is encrypted/decrypted by the OEM Crypto stack (either on chip/HSM or via separate core running the crypto stack). -The device software can be extended to invoke cryptography APIs to encrypt and decrypt the data as per the need. +The device software can be extended to invoke cryptography APIs to encrypt and decrypt the data as per the need. The device software has been designed to be deployed in a non safety relevant in-vehicle domain/partition. Due to its use of dynamic memory allocation, this software is not suited for deployment on real time/lock step/safety cores. @@ -1403,7 +1400,7 @@ The device software has been designed to be deployed in a non safety relevant in You can use the cmake build option, `FWE_SECURITY_COMPILE_FLAGS`, to enable security-related compile options when building the binary. Consult the compiler manual for the effect of each option in `./cmake/compiler_gcc.cmake`. This flag is already enabled in the default [native compilation script](./tools/build-fwe-native.sh) and [cross compilation script for ARM64](./tools/build-fwe-cross-arm64.sh) -Customers are encouraged to store key materials on hardware modules, such as hardware security module (HSM), Trusted Platform Modules (TPM), or other cryptographic elements. +Customers are encouraged to store key materials on hardware modules, such as hardware security module (HSM), Trusted Platform Modules (TPM), or other cryptographic elements. A HSM is a removable or external device that can generate, store, and manage RSA keys used in asymmetric encryption. A TPM is a cryptographic processor present on most commercial PCs and servers. Please refer to [AWS IoT Security Best Practices](https://docs.aws.amazon.com/iot/latest/developerguide/security-best-practices.html) for recommended security best practices. diff --git a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md index 415c4717..bc3fa2d9 100644 --- a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md +++ b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md @@ -329,6 +329,7 @@ On the development machine, create an IoT thing and provision its credentials by && ../tools/configure-fwe.sh \ --input-config-file ~/aws-iot-fleetwise-edge/configuration/static-config.json \ --output-config-file config-0.json \ + --log-color Yes \ --vehicle-name `cat vehicle-name.txt` \ --endpoint-url `cat endpoint.txt` \ --can-bus0 can0 \ @@ -364,13 +365,13 @@ On the development machine, create an IoT thing and provision its credentials by 1. On the TCU, view and follow the AWS IoT FleetWise Edge Agent log (press CTRL+C to exit) by running the following command: ```bash - journalctl -fu fwe@0 + journalctl -fu fwe@0 --output=cat ``` The following line appears, confirming the AWS IoT FleetWise Edge Agent successfully connected to AWS IoT Core: ``` - [INFO] [AwsIotConnectivityModule::connect]: [Connection completed successfully.] + [INFO ] [AwsIotConnectivityModule::connect] [Connection completed successfully] ``` ## Step 6: Connect the TCU to the vehicle diff --git a/docs/rpi-tutorial/raspberry-pi-tutorial.md b/docs/rpi-tutorial/raspberry-pi-tutorial.md index 99222865..15422c1b 100644 --- a/docs/rpi-tutorial/raspberry-pi-tutorial.md +++ b/docs/rpi-tutorial/raspberry-pi-tutorial.md @@ -143,6 +143,7 @@ The AWS IoT FleetWise Edge Agent binary and its configuration files are packaged && ../tools/configure-fwe.sh \ --input-config-file ~/aws-iot-fleetwise-edge/configuration/static-config.json \ --output-config-file config-0.json \ + --log-color Yes \ --vehicle-name `cat vehicle-name.txt` \ --endpoint-url `cat endpoint.txt` \ --can-bus0 can0 \ @@ -196,11 +197,11 @@ The AWS IoT FleetWise Edge Agent binary and its configuration files are packaged 1. To verify the IoT FleetWise Edge Agent is running and is connected to the cloud, check the Edge Agent log files: ``` - sudo journalctl -fu fwe@0 + sudo journalctl -fu fwe@0 --output=cat ``` - Look for this message to verify: ``` - [INFO] [AwsIotConnectivityModule::connect]: [Connection completed successfully.] + [INFO ] [AwsIotConnectivityModule::connect] [Connection completed successfully] ``` - Use the [troubleshooting information and solutions](https://docs.aws.amazon.com/iot-fleetwise/latest/developerguide/troubleshooting.html) in the AWS IoT FleetWise Developer Guide to help resolve issues with AWS IoT FleetWise Edge Agent. diff --git a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json index 6231eab9..a18fbec8 100644 --- a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json +++ b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json @@ -204,6 +204,11 @@ "type": "string", "description": "Set log level severity- Trace, Info, Warning, Error" }, + "logColor": { + "type": "string", + "enum": ["Auto", "Yes", "No"], + "description": "Whether the logs should be colored. Default to auto." + }, "dataReductionProbabilityDisabled": { "type": "boolean", "description": "Disables the whole probability-based DDC,can be used for debugging" diff --git a/src/datamanagement/custom/CMakeLists.txt b/src/datamanagement/custom/CMakeLists.txt index de1375d7..86284395 100644 --- a/src/datamanagement/custom/CMakeLists.txt +++ b/src/datamanagement/custom/CMakeLists.txt @@ -52,8 +52,6 @@ install( if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - find_library(GMOCK_LIB NAMES gmock) @@ -80,13 +78,12 @@ if(${BUILD_TESTING}) PRIVATE include) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main - GTest::GTest + IoTFleetWise::TestingSupport ${GMOCK_LIB} ) diff --git a/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp b/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp index 3ce4d5f6..12389396 100644 --- a/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp +++ b/src/datamanagement/custom/example/iwavegps/src/IWaveGpsSource.cpp @@ -100,7 +100,7 @@ IWaveGpsSource::pollData() if ( foundValid && mSignalBufferPtr != nullptr ) { mValidCoordinateCounter++; - auto timestamp = mClock->timeSinceEpochMs(); + auto timestamp = mClock->systemTimeSinceEpochMs(); mSignalBufferPtr->push( CollectedSignal( getSignalIdFromStartBit( mLatitudeStartBit ), timestamp, lastValidLatitude ) ); mSignalBufferPtr->push( @@ -210,7 +210,7 @@ IWaveGpsSource::init( const std::vector &sourceConfigs if ( sourceConfigs.size() > 1 || sourceConfigs.empty() ) { - mLogger.error( "IWaveGpsSource::init", " Only one source config is supported " ); + mLogger.error( "IWaveGpsSource::init", "Only one source config is supported" ); return false; } auto settingsIterator = sourceConfigs[0].transportProperties.find( std::string( PATH_TO_NMEA ) ); diff --git a/src/datamanagement/custom/generic/src/CustomDataSource.cpp b/src/datamanagement/custom/generic/src/CustomDataSource.cpp index aaf046cb..37286e12 100644 --- a/src/datamanagement/custom/generic/src/CustomDataSource.cpp +++ b/src/datamanagement/custom/generic/src/CustomDataSource.cpp @@ -33,11 +33,11 @@ CustomDataSource::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CustomDataSource::start", " Consumer Thread failed to start " ); + mLogger.trace( "CustomDataSource::start", "Thread failed to start" ); } else { - mLogger.trace( "CustomDataSource::start", " Consumer Thread started " ); + mLogger.trace( "CustomDataSource::start", "Thread started" ); mThread.setThreadName( getThreadName() ); } @@ -65,7 +65,7 @@ CustomDataSource::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CustomDataSource::stop", " CustomDataSource Thread stopped " ); + mLogger.trace( "CustomDataSource::stop", "Thread stopped" ); return !mThread.isActive(); } @@ -93,7 +93,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 " ); + "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 diff --git a/src/datamanagement/datacollection/CMakeLists.txt b/src/datamanagement/datacollection/CMakeLists.txt index bca17c52..249f5c91 100644 --- a/src/datamanagement/datacollection/CMakeLists.txt +++ b/src/datamanagement/datacollection/CMakeLists.txt @@ -50,7 +50,6 @@ install( include/CollectionSchemeIngestion.h include/CollectionSchemeIngestionList.h include/CollectionSchemeJSONParser.h - include/CollectionSchemeListener.h include/DataCollectionJSONWriter.h include/DataCollectionProtoWriter.h include/DataCollectionSender.h @@ -62,8 +61,6 @@ install( if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - find_library(GMOCK_LIB NAMES gmock) @@ -90,14 +87,13 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} Boost::filesystem - GTest::Main - GTest::GTest + IoTFleetWise::TestingSupport ${GMOCK_LIB} ) diff --git a/src/datamanagement/datacollection/include/CollectionScheme.h b/src/datamanagement/datacollection/include/CollectionScheme.h index 78c77686..579d60c5 100644 --- a/src/datamanagement/datacollection/include/CollectionScheme.h +++ b/src/datamanagement/datacollection/include/CollectionScheme.h @@ -47,10 +47,10 @@ struct EventTrigger bool isValid() const { - return ( mTriggerType == TriggerType::SIGNALVALUE && mSignalID > 0 && - mValuePredicate.mCondition != PredicateCondition::EVERY ) || - ( mTriggerType == TriggerType::TIMEPOINT && mValuePredicate.mCondition == PredicateCondition::EVERY && - mValuePredicate.mValue > 0.0 ); + 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 @@ -81,7 +81,6 @@ class CollectionScheme const EventTriggers &getEventTriggers() const; const EventTrigger &getTimeTrigger() const; - void insertMessageToBeWatched( const uint32_t &messageID, const EventTriggers &triggers ); void insertMessageToCollected( const uint32_t &messageID, const CANMessageFormat &messageFormat ); void insertSignalTriggerToMessage( const uint32_t &messageID, const EventTrigger &trigger ); void clear(); diff --git a/src/datamanagement/datacollection/include/CollectionSchemeListener.h b/src/datamanagement/datacollection/include/CollectionSchemeListener.h deleted file mode 100644 index 4ed0b740..00000000 --- a/src/datamanagement/datacollection/include/CollectionSchemeListener.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -// Includes - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace DataManagement -{ - -struct CollectionSchemeListener -{ - virtual ~CollectionSchemeListener() = default; - - /** - * @brief Invoked as soon as new collectionScheme is available - * For now this function is only used to notify but in the future as a parameter the new - * collectionScheme could be given if creating the collectionScheme is moved from inside the Engine - * thread into a separate thread - */ - virtual void onNewCollectionSchemeAvailable() = 0; -}; -} // namespace DataManagement -} // namespace IoTFleetWise -} // namespace Aws \ No newline at end of file diff --git a/src/datamanagement/datacollection/include/DataCollectionSender.h b/src/datamanagement/datacollection/include/DataCollectionSender.h index 94f47b38..ef11b7f8 100644 --- a/src/datamanagement/datacollection/include/DataCollectionSender.h +++ b/src/datamanagement/datacollection/include/DataCollectionSender.h @@ -99,14 +99,6 @@ class DataCollectionSender */ void setCollectionSchemeParameters( const TriggeredCollectionSchemeDataPtr &triggeredCollectionSchemeDataPtr ); - /** - * @brief Get the collection event ID for the data to be serialized - * - * @return collection event ID - */ - - uint32_t getCollectionEventId() const; - /** * @brief Serialize and send the protobuf data to the cloud */ diff --git a/src/datamanagement/datacollection/src/CollectionScheme.cpp b/src/datamanagement/datacollection/src/CollectionScheme.cpp index 5b3deb8b..ed7364eb 100644 --- a/src/datamanagement/datacollection/src/CollectionScheme.cpp +++ b/src/datamanagement/datacollection/src/CollectionScheme.cpp @@ -16,8 +16,8 @@ namespace DataManagement bool CollectionScheme::isValid() { - return ( !mMessageIDsToBeWatched.empty() && !mEventTriggers.empty() ) || - ( !mMessageIDsToBeCollected.empty() && mTimeTrigger.isValid() ); + return ( ( !mMessageIDsToBeWatched.empty() ) && ( !mEventTriggers.empty() ) ) || + ( ( !mMessageIDsToBeCollected.empty() ) && ( mTimeTrigger.isValid() ) ); } void @@ -187,8 +187,8 @@ CollectionScheme::shouldTriggerUpload( const CANFrameInfo &frameInfo, EventTrigg { 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].mTriggerType == TriggerType::SIGNALVALUE ) && + ( it->second[j].mSignalID == frameInfo.mSignals[i].mSignalID ) ) { if ( it->second[j].mValuePredicate.mCondition == PredicateCondition::LESS ) { diff --git a/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp b/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp index e4453bb5..6fd710bf 100644 --- a/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp +++ b/src/datamanagement/datacollection/src/CollectionSchemeIngestion.cpp @@ -40,7 +40,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." ); + mLogger.error( "CollectionSchemeIngestion::build", "CollectionScheme does not have ID or DM ID" ); return false; } @@ -48,11 +48,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." ); + mLogger.error( "CollectionSchemeIngestion::build", "CollectionScheme end time comes before start time" ); return false; } - mLogger.trace( "CollectionSchemeIngestion::build()", + mLogger.trace( "CollectionSchemeIngestion::build", "Building CollectionScheme with ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); // Build Collected Signals @@ -71,9 +71,8 @@ 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." ); + mLogger.trace( "CollectionSchemeIngestion::build", + "Adding signalID: " + std::to_string( signalInfo.signalID ) + " to list of signals to collect" ); mCollectedSignals.emplace_back( signalInfo ); } @@ -92,7 +91,7 @@ CollectionSchemeIngestion::build() rawCAN.sampleBufferSize = rawCanFrame.sample_buffer_size(); rawCAN.minimumSampleIntervalMs = rawCanFrame.minimum_sample_period_ms(); - mLogger.trace( "CollectionSchemeIngestion::build()", + mLogger.trace( "CollectionSchemeIngestion::build", "Adding rawCAN frame to collect ID: " + std::to_string( rawCAN.frameID ) + " node ID: " + rawCAN.interfaceID ); mCollectedRawCAN.emplace_back( rawCAN ); @@ -106,7 +105,7 @@ CollectionSchemeIngestion::build() getNumberOfNodes( mProtoCollectionSchemeMessagePtr->condition_based_collection_scheme().condition_tree(), Aws::IoTFleetWise::DataInspection::MAX_EQUATION_DEPTH ); - mLogger.info( "CollectionSchemeIngestion::build()", + mLogger.info( "CollectionSchemeIngestion::build", "CollectionScheme is Condition Based. Building AST with " + std::to_string( numNodes ) + " nodes" ); @@ -118,18 +117,18 @@ CollectionSchemeIngestion::build() serializeNode( mProtoCollectionSchemeMessagePtr->condition_based_collection_scheme().condition_tree(), currentIndex, Aws::IoTFleetWise::DataInspection::MAX_EQUATION_DEPTH ); - mLogger.info( "CollectionSchemeIngestion::build()", "AST complete." ); + mLogger.info( "CollectionSchemeIngestion::build", "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()", + 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." ); + " ms" ); mExpressionNodes.emplace_back(); ExpressionNode ¤tNode = mExpressionNodes.back(); @@ -139,7 +138,7 @@ CollectionSchemeIngestion::build() } else { - mLogger.error( "CollectionSchemeIngestion::build()", "COLLECTION_SCHEME_TYPE_NOT_SET" ); + mLogger.error( "CollectionSchemeIngestion::build", "COLLECTION_SCHEME_TYPE_NOT_SET" ); } // Build Image capture collection info @@ -162,7 +161,7 @@ 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()", + mLogger.info( "CollectionSchemeIngestion::build", "Adding Image capture settings for DeviceID: " + std::to_string( imageCaptureData.deviceID ) ); @@ -170,12 +169,11 @@ CollectionSchemeIngestion::build() } else { - mLogger.warn( "CollectionSchemeIngestion::build()", - "Unsupported Image capture settings provided, skipping" ); + mLogger.warn( "CollectionSchemeIngestion::build", "Unsupported Image capture settings provided, skipping" ); } } - mLogger.info( "CollectionSchemeIngestion::build()", + mLogger.info( "CollectionSchemeIngestion::build", "Successfully built CollectionScheme ID: " + mProtoCollectionSchemeMessagePtr->campaign_arn() ); // Set ready flag to true @@ -404,7 +402,7 @@ CollectionSchemeIngestion::serializeNode( const CollectionSchemesMsg::ConditionN ExpressionNode *left = serializeNode( node.node_operator().left_child(), nextIndex, remainingDepth - 1 ); currentNode->left = left; // Not operator is unary and has only left child - if ( currentNode->nodeType != ExpressionNodeType::OPERATOR_LOGICAL_NOT && + if ( ( currentNode->nodeType != ExpressionNodeType::OPERATOR_LOGICAL_NOT ) && node.node_operator().has_right_child() ) { mLogger.trace( "CollectionSchemeIngestion::serializeNode", "Processing right child" ); diff --git a/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp b/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp index 614ca8c8..a900b3c4 100644 --- a/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp +++ b/src/datamanagement/datacollection/src/CollectionSchemeIngestionList.cpp @@ -35,17 +35,17 @@ CollectionSchemeIngestionList::copyData( const std::uint8_t *inputBuffer, const mReady = false; // check for a null input buffer or size set to 0 - if ( inputBuffer == nullptr || size == 0 ) + if ( ( inputBuffer == nullptr ) || ( size == 0 ) ) { // Error, input buffer empty or invalid - mLogger.error( "CollectionSchemeIngestionList::copyData()", "Input buffer empty" ); + mLogger.error( "CollectionSchemeIngestionList::copyData", "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" ); + mLogger.error( "CollectionSchemeIngestionList::copyData", "Collection Schema document is too big, ignoring" ); return false; } @@ -55,11 +55,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." ); + mLogger.error( "CollectionSchemeIngestionList::copyData", "Copied data size doesn't match" ); return false; } - mLogger.trace( "CollectionSchemeIngestionList::copyData()", "Collection Scheme Data copied successfully." ); + mLogger.trace( "CollectionSchemeIngestionList::copyData", "Collection Scheme Data copied successfully" ); return true; } @@ -80,12 +80,12 @@ CollectionSchemeIngestionList::build() // version of the headers we compiled with. GOOGLE_PROTOBUF_VERIFY_VERSION; - mLogger.trace( "CollectionSchemeIngestionList::build()", "Building CollectionScheme List" ); + mLogger.trace( "CollectionSchemeIngestionList::build", "Building CollectionScheme list" ); // Ensure that we have data to parse - if ( mProtoBinaryData.empty() || mProtoBinaryData.data() == nullptr ) + if ( mProtoBinaryData.empty() || ( mProtoBinaryData.data() == nullptr ) ) { - mLogger.error( "CollectionSchemeIngestionList::build()", "Input buffer empty" ); + mLogger.error( "CollectionSchemeIngestionList::build", "Input buffer empty" ); // Error, input buffer empty or invalid return false; } @@ -95,7 +95,7 @@ CollectionSchemeIngestionList::build() static_cast( mProtoBinaryData.size() ) ) ) { // Error parsing proto binary - mLogger.error( "CollectionSchemeIngestionList::build()", "Error parsing collectionSchemes.proto binary" ); + mLogger.error( "CollectionSchemeIngestionList::build", "Error parsing collectionSchemes.proto binary" ); return false; } @@ -115,7 +115,7 @@ CollectionSchemeIngestionList::build() // Check to see if it successfully builds if ( pICPPtr->build() ) { - mLogger.trace( "CollectionSchemeIngestionList::build()", + mLogger.trace( "CollectionSchemeIngestionList::build", "Adding CollectionScheme index: " + std::to_string( i ) + " of " + std::to_string( mCollectionSchemeListMsg.collection_schemes_size() ) ); @@ -125,12 +125,12 @@ CollectionSchemeIngestionList::build() } else { - mLogger.error( "CollectionSchemeIngestionList::build()", - "CollectionScheme index: " + std::to_string( i ) + " failed to build. Dropping it. " ); + mLogger.error( "CollectionSchemeIngestionList::build", + "CollectionScheme index: " + std::to_string( i ) + " failed to build, dropping it" ); } } - mLogger.trace( "CollectionSchemeIngestionList::build()", "Building CollectionScheme List complete." ); + mLogger.trace( "CollectionSchemeIngestionList::build", "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 index cbcafc22..2ffb2776 100644 --- a/src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp +++ b/src/datamanagement/datacollection/src/CollectionSchemeJSONParser.cpp @@ -33,7 +33,7 @@ CollectionSchemeJSONParser::parse() bool success = parseFromStream( builder, collectionSchemeFile, &root, &errs ); if ( !success ) { - mLogger.error( "CollectionSchemeJSONParser::parse", " Failed to parse the collectionScheme file:" + mPath ); + mLogger.error( "CollectionSchemeJSONParser::parse", "Failed to parse the collectionScheme file: " + mPath ); return false; } mCollectionScheme->setVersion( root["version"].asString() ); @@ -125,7 +125,7 @@ CollectionSchemeJSONParser::parse() } else { - mLogger.error( "CollectionSchemeJSONParser::parse", " Failed to open the collectionScheme file:" + mPath ); + mLogger.error( "CollectionSchemeJSONParser::parse", "Failed to open the collectionScheme file: " + mPath ); return false; } } diff --git a/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp b/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp index 3e1a199d..7d448e8d 100644 --- a/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp +++ b/src/datamanagement/datacollection/src/DataCollectionJSONWriter.cpp @@ -85,7 +85,8 @@ DataCollectionJSONWriter::flushToFile() static constexpr char SEP = '-'; std::ostringstream oss; - oss << "IoTFleetWise" << SEP << "Data" << SEP << eventId << SEP << std::to_string( mClock->timeSinceEpochMs() ); + oss << "IoTFleetWise" << SEP << "Data" << SEP << eventId << SEP + << std::to_string( mClock->systemTimeSinceEpochMs() ); return flushToFile( oss.str() ); } diff --git a/src/datamanagement/datacollection/src/DataCollectionSender.cpp b/src/datamanagement/datacollection/src/DataCollectionSender.cpp index ddc02fbf..258d895f 100644 --- a/src/datamanagement/datacollection/src/DataCollectionSender.cpp +++ b/src/datamanagement/datacollection/src/DataCollectionSender.cpp @@ -251,12 +251,6 @@ DataCollectionSender::setCollectionSchemeParameters( mCollectionSchemeParams.priority = triggeredCollectionSchemeDataPtr->metaData.priority; } -uint32_t -DataCollectionSender::getCollectionEventId() const -{ - return mCollectionEventID; -} - } // namespace DataManagement } // namespace IoTFleetWise } // namespace Aws diff --git a/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp b/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp index 161175be..11bca658 100644 --- a/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp +++ b/src/datamanagement/datacollection/test/DataCollectionJSONWriterTest.cpp @@ -90,7 +90,6 @@ class DataCollectionJSONWriterTest : public ::testing::TestWithParammetaData.decoderID = "456"; // Set the trigger time to current time auto testClock = ClockHandler::getClock(); - Timestamp testTriggerTime = testClock->timeSinceEpochMs(); + Timestamp testTriggerTime = testClock->systemTimeSinceEpochMs(); triggeredCollectionSchemeDataPtr->triggerTime = testTriggerTime; uint32_t collectionEventID = std::rand(); @@ -87,7 +87,7 @@ TEST_F( DataCollectionProtoWriterTest, TestDTCData ) triggeredCollectionSchemeDataPtr->metaData.decoderID = "456"; // Set the trigger time to current time auto testClock = ClockHandler::getClock(); - Timestamp testTriggerTime = testClock->timeSinceEpochMs(); + Timestamp testTriggerTime = testClock->systemTimeSinceEpochMs(); triggeredCollectionSchemeDataPtr->triggerTime = testTriggerTime; uint32_t collectionEventID = std::rand(); @@ -144,7 +144,7 @@ TEST_F( DataCollectionProtoWriterTest, TestGeohash ) triggeredCollectionSchemeDataPtr->metaData.decoderID = "456"; // Set the trigger time to current time auto testClock = ClockHandler::getClock(); - Timestamp testTriggerTime = testClock->timeSinceEpochMs(); + Timestamp testTriggerTime = testClock->systemTimeSinceEpochMs(); triggeredCollectionSchemeDataPtr->triggerTime = testTriggerTime; uint32_t collectionEventID = std::rand(); diff --git a/src/datamanagement/datadecoding/CMakeLists.txt b/src/datamanagement/datadecoding/CMakeLists.txt index 1c4676f3..1e390e2b 100644 --- a/src/datamanagement/datadecoding/CMakeLists.txt +++ b/src/datamanagement/datadecoding/CMakeLists.txt @@ -48,8 +48,6 @@ install( if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - find_library(GMOCK_LIB NAMES gmock) @@ -70,14 +68,13 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} Boost::filesystem - GTest::Main - GTest::GTest + IoTFleetWise::TestingSupport ${GMOCK_LIB} ) diff --git a/src/datamanagement/datadecoding/include/IDecoderDictionary.h b/src/datamanagement/datadecoding/include/IDecoderDictionary.h index 752eaecc..bc4b086e 100644 --- a/src/datamanagement/datadecoding/include/IDecoderDictionary.h +++ b/src/datamanagement/datadecoding/include/IDecoderDictionary.h @@ -83,19 +83,9 @@ operator<( const SignalMetaData &lhs, const SignalMetaData &rhs ) inline bool operator==( const SignalMetaData &lhs, const SignalMetaData &rhs ) { - return lhs.signalId == rhs.signalId && lhs.dataType == rhs.dataType; + return ( lhs.signalId == rhs.signalId ) && ( lhs.dataType == rhs.dataType ); } -/** - * @brief Synthetic Data decoder dictionary to be used to decode messages based on signal data type. - * - * The key of dictionary is the Message Identifier. The value is a list of signal data primitive types. - */ -struct SyntheticDecoderDictionary : DecoderDictionary -{ - std::unordered_map> genericMessageDecoderMethod; -}; - /** * @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 c63686a0..0f9ddb6c 100644 --- a/src/datamanagement/datadecoding/include/IDecoderManifest.h +++ b/src/datamanagement/datadecoding/include/IDecoderManifest.h @@ -144,10 +144,10 @@ struct PIDSignalDecoderFormat bool operator==( const PIDSignalDecoderFormat &other ) const { - return mPidResponseLength == other.mPidResponseLength && mServiceMode == other.mServiceMode && - mPID == other.mPID && mScaling == other.mScaling && mOffset == other.mOffset && - mStartByte == other.mStartByte && mByteLength == other.mByteLength && - mBitRightShift == other.mBitRightShift && mBitMaskLength == other.mBitMaskLength; + return ( mPidResponseLength == other.mPidResponseLength ) && ( mServiceMode == other.mServiceMode ) && + ( mPID == other.mPID ) && ( mScaling == other.mScaling ) && ( mOffset == other.mOffset ) && + ( mStartByte == other.mStartByte ) && ( mByteLength == other.mByteLength ) && + ( mBitRightShift == other.mBitRightShift ) && ( mBitMaskLength == other.mBitMaskLength ); } }; diff --git a/src/datamanagement/datadecoding/src/CANDecoder.cpp b/src/datamanagement/datadecoding/src/CANDecoder.cpp index f0a293d1..9a346ca8 100644 --- a/src/datamanagement/datadecoding/src/CANDecoder.cpp +++ b/src/datamanagement/datadecoding/src/CANDecoder.cpp @@ -5,7 +5,7 @@ #include "CANDecoder.h" #include #include -#define MASK64( nbits ) ( ( 0xffffffffffffffffULL ) >> ( 64 - ( nbits ) ) ) +#define MASK64( nbits ) ( ( 0xFFFFFFFFFFFFFFFFULL ) >> ( 64 - ( nbits ) ) ) namespace Aws { @@ -36,8 +36,8 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, 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 " ); + "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() ) @@ -55,13 +55,13 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, if ( signalIDsToCollect.find( format.mSignals[i].mSignalID ) != signalIDsToCollect.end() ) { // Skip the signals that don't match the MUX value - if ( multiplexorValue != UINT8_MAX && format.mSignals[i].mMultiplexorValue != multiplexorValue ) + if ( ( multiplexorValue != UINT8_MAX ) && ( format.mSignals[i].mMultiplexorValue != multiplexorValue ) ) { continue; } if ( ( format.mSignals[i].mFirstBitPosition >= frameSizeInBits ) || - ( format.mSignals[i].mSizeInBits < 1 ) || ( format.mSignals[i].mSizeInBits > frameSizeInBits ) ) + ( ( format.mSignals[i].mSizeInBits < 1 ) || ( format.mSignals[i].mSizeInBits > frameSizeInBits ) ) ) { // Wrongly coded Signal, skip it mLogger.error( "CANDecoder::decodeCANMessage", "Signal Out of Range" ); @@ -88,7 +88,7 @@ CANDecoder::decodeCANMessage( const uint8_t *frameData, } // Message decoding time - decodedMessage.mDecodingTime = mClock->timeSinceEpochMs(); + decodedMessage.mDecodingTime = mClock->systemTimeSinceEpochMs(); // Should not harm, callers will ignore the return code. return errorCounter == 0; } @@ -104,6 +104,9 @@ CANDecoder::extractSignalFromFrame( const uint8_t *frameData, const CANSignalFor uint8_t endByte = 0U; // Write first bits to result + // NOTE: The start bit here is different from how it appears in a DBC file. In a DBC file, the + // start bit indicates the LSB for little endian and MSB for big endian signals. + // But AWS IoT Fleetwise considers start bit to always be the LSB regardless of endianess. uint64_t result = frameData[startByte] >> startBitInByte; // Write residual bytes diff --git a/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp b/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp index 63dffa87..2aa5a6e9 100644 --- a/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp +++ b/src/datamanagement/datadecoding/src/DecoderManifestIngestion.cpp @@ -47,8 +47,8 @@ DecoderManifestIngestion::getCANMessageFormat( CANRawFrameID canID, CANInterface } // Check if the message for this CANRawFrameID and interfaceID exists - if ( mCANMessageFormatDictionary.count( interfaceID ) > 0 && - mCANMessageFormatDictionary.at( interfaceID ).count( canID ) > 0 ) + if ( ( mCANMessageFormatDictionary.count( interfaceID ) > 0 ) && + ( mCANMessageFormatDictionary.at( interfaceID ).count( canID ) > 0 ) ) { // It exists, so return it return mCANMessageFormatDictionary.at( interfaceID ).at( canID ); @@ -116,16 +116,16 @@ bool DecoderManifestIngestion::copyData( const std::uint8_t *inputBuffer, const size_t size ) { // check for a null input buffer or size set to 0 - if ( inputBuffer == nullptr || size == 0 ) + if ( ( inputBuffer == nullptr ) || ( size == 0 ) ) { - mLogger.error( "DecoderManifestIngestion::copyData()", "Input buffer invalid" ); + mLogger.error( "DecoderManifestIngestion::copyData", "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()", + mLogger.error( "DecoderManifestIngestion::copyData", "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." ); + mLogger.error( "DecoderManifestIngestion::copyData", "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." ); + mLogger.trace( "DecoderManifestIngestion::copyData", "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." ); + mLogger.error( "DecoderManifestIngestion::build", "Failed to build due to an empty Decoder Manifest" ); // Error, input buffer empty or invalid return false; } @@ -169,13 +169,13 @@ 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." ); + mLogger.error( "DecoderManifestIngestion::build", "Failed to parse DecoderManifest proto" ); // Error parsing proto binary return false; } // Do some validation of the DecoderManifest. Either CAN or OBD or both should be specified. - if ( mProtoDecoderManifest.can_signals_size() == 0 && mProtoDecoderManifest.obd_pid_signals_size() == 0 ) + if ( ( mProtoDecoderManifest.can_signals_size() == 0 ) && ( mProtoDecoderManifest.obd_pid_signals_size() == 0 ) ) { // Error, missing required decoding information in the Decoder mProtoDecoderManifest mLogger.error( @@ -221,8 +221,8 @@ DecoderManifestIngestion::build() // existing one. // First check if CANMessageFormat exists for this message id and node id - if ( mCANMessageFormatDictionary.count( canSignal.interface_id() ) == 1 && - mCANMessageFormatDictionary[canSignal.interface_id()].count( canSignal.message_id() ) == 1 ) + if ( ( mCANMessageFormatDictionary.count( canSignal.interface_id() ) == 1 ) && + ( mCANMessageFormatDictionary[canSignal.interface_id()].count( canSignal.message_id() ) == 1 ) ) { // CANMessageFormat exists for a given node id and message id. Add this signal format to it mCANMessageFormatDictionary[canSignal.interface_id()][canSignal.message_id()].mSignals.emplace_back( @@ -281,7 +281,7 @@ DecoderManifestIngestion::build() mSignalToPIDDictionary[pidSignal.signal_id()] = obdPIDSignalDecoderFormat; } - mLogger.trace( "DecoderManifestIngestion::build", "Decoder Manifest build succeeded." ); + mLogger.trace( "DecoderManifestIngestion::build", "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 02482fa4..23a830d8 100644 --- a/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp +++ b/src/datamanagement/datadecoding/src/OBDDataDecoder.cpp @@ -8,7 +8,7 @@ #include #include constexpr int POSITIVE_ECU_RESPONSE_BASE = 0x40; -#define IS_BIT_SET( var, pos ) ( ( var ) & ( 1 << ( pos ) ) ) +#define IS_BIT_SET( var, pos ) ( ( ( var ) & ( 1 << ( pos ) ) ) != 0 ) namespace Aws { @@ -32,8 +32,8 @@ OBDDataDecoder::decodeSupportedPIDs( const SID &sid, // If the input size is less than 6 ( Response byte + Requested PID + 4 data bytes ) // or if the input size minus SID is not a multiple of 5 // this is also not a valid input - if ( inputData.size() < 6 || POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] || - ( inputData.size() - 1 ) % 5 != 0 ) + 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" ); return false; @@ -59,8 +59,8 @@ 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 ) ); + mLogger.warn( "OBDDataDecoder::decodeSupportedPIDs", + "Invalid PID for support range: " + std::to_string( basePID ) ); break; } baseIdx = i; @@ -79,9 +79,9 @@ OBDDataDecoder::decodeSupportedPIDs( const SID &sid, // To remain consistent with the spec, we don't want to mix Supported PID IDs with // PIDs. We validate that the PID received is supported by the software, but also // exclude the Supported PID IDs from the output list - if ( decodedID != INVALID_PID && - std::find( supportedPIDRange.begin(), supportedPIDRange.end(), decodedID ) == - supportedPIDRange.end() ) + if ( ( decodedID != INVALID_PID ) && + ( std::find( supportedPIDRange.begin(), supportedPIDRange.end(), decodedID ) == + supportedPIDRange.end() ) ) { supportedPIDs.emplace_back( decodedID ); } @@ -112,14 +112,14 @@ OBDDataDecoder::decodeEmissionPIDs( const SID &sid, // If the input size is less than 3 ( Positive Response + Response byte + Requested PID ) // 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] ) + if ( ( inputData.size() < 3 ) || ( POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] ) ) { mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid response to PID request" ); return false; } if ( mDecoderDictionaryConstPtr == nullptr ) { - mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid Decoder Dictionary!" ); + mLogger.warn( "OBDDataDecoder::decodeEmissionPIDs", "Invalid Decoder Dictionary" ); return false; } // Validate 1) The PIDs in response match with expected PID; 2) Total length of PID response matches with Decoder @@ -208,7 +208,7 @@ OBDDataDecoder::decodeDTCs( const SID &sid, const std::vector &inputDat // First look at whether we received a positive response // The positive response can be identified by 0x40 + SID. // If an ECU has no DTCs, it should respond with 2 Bytes ( 1 for Positive response + 1 number of DTCs( 0) ) - if ( inputData.size() < 2 || POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] ) + if ( ( inputData.size() < 2 ) || ( POSITIVE_ECU_RESPONSE_BASE + toUType( sid ) != inputData[0] ) ) { return false; } @@ -290,9 +290,9 @@ OBDDataDecoder::decodeVIN( const std::vector &inputData, std::string &v // The positive response can be identified by 0x40 + SID. // The response is usually 1 byte of the positive response, 1 byte for the InfoType(PID), 1 byte for the number of // data item. - if ( inputData.size() < 3 || - POSITIVE_ECU_RESPONSE_BASE + toUType( vehicleIdentificationNumberRequest.mSID ) != inputData[0] || - vehicleIdentificationNumberRequest.mPID != inputData[1] ) + if ( ( inputData.size() < 3 ) || + ( POSITIVE_ECU_RESPONSE_BASE + toUType( vehicleIdentificationNumberRequest.mSID ) != inputData[0] ) || + ( vehicleIdentificationNumberRequest.mPID != inputData[1] ) ) { return false; } @@ -311,7 +311,7 @@ OBDDataDecoder::isPIDResponseValid( const std::vector &pids, const std::vec { // 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 ) + if ( ( responseByteIndex >= ecuResponse.size() ) || ( ecuResponse[responseByteIndex] != pid ) ) { mLogger.warn( "OBDDataDecoder::isPIDResponseValid", "Cannot find PID " + std::to_string( pid ) + " in ECU response" ); @@ -347,12 +347,12 @@ OBDDataDecoder::isFormulaValid( PID pid, CANSignalFormat formula ) // 2. Last Bit Position (first bit + sizeInBits) has to be less than or equal to last bit position of PID response // length // 3. If mSizeInBits are greater or equal than 8, both mSizeInBits and first bit position has to be multiple of 8 - if ( mDecoderDictionaryConstPtr->find( pid ) != mDecoderDictionaryConstPtr->end() && - formula.mFirstBitPosition < mDecoderDictionaryConstPtr->at( pid ).mSizeInBytes * BYTE_SIZE && + if ( ( mDecoderDictionaryConstPtr->find( pid ) != mDecoderDictionaryConstPtr->end() ) && + ( formula.mFirstBitPosition < mDecoderDictionaryConstPtr->at( pid ).mSizeInBytes * BYTE_SIZE ) && ( formula.mSizeInBits + formula.mFirstBitPosition <= mDecoderDictionaryConstPtr->at( pid ).mSizeInBytes * BYTE_SIZE ) && - ( formula.mSizeInBits < 8 || - ( ( formula.mSizeInBits & 0x7 ) == 0 && ( formula.mFirstBitPosition & 0x7 ) == 0 ) ) ) + ( ( formula.mSizeInBits < 8 ) || + ( ( ( formula.mSizeInBits & 0x7 ) == 0 ) && ( ( formula.mFirstBitPosition & 0x7 ) == 0 ) ) ) ) { isValid = true; } diff --git a/src/datamanagement/datainspection/CMakeLists.txt b/src/datamanagement/datainspection/CMakeLists.txt index c26caf51..1f4a33de 100644 --- a/src/datamanagement/datainspection/CMakeLists.txt +++ b/src/datamanagement/datainspection/CMakeLists.txt @@ -86,8 +86,6 @@ endif() if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - # Copy the json file required for the test application file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/di-collection-scheme-example.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR} ) @@ -101,12 +99,12 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_unit_test(${testName}) add_valgrind_test(${testName}) diff --git a/src/datamanagement/datainspection/include/CANDataConsumer.h b/src/datamanagement/datainspection/include/CANDataConsumer.h index bd4ace7d..10204326 100644 --- a/src/datamanagement/datainspection/include/CANDataConsumer.h +++ b/src/datamanagement/datainspection/include/CANDataConsumer.h @@ -94,8 +94,6 @@ class CANDataConsumer : public IVehicleDataConsumer // Decodes the messages and puts the results in the output buffer. static void doWork( void *data ); - bool switchCollectionSchemeIfNeeded(); - Thread mThread; std::atomic mShouldStop{ false }; std::atomic mShouldSleep{ false }; diff --git a/src/datamanagement/datainspection/include/CollectionInspectionEngine.h b/src/datamanagement/datainspection/include/CollectionInspectionEngine.h index af8d159c..74f1c5d6 100644 --- a/src/datamanagement/datainspection/include/CollectionInspectionEngine.h +++ b/src/datamanagement/datainspection/include/CollectionInspectionEngine.h @@ -55,7 +55,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * @return at least one condition is true * */ - bool evaluateConditions( InspectionTimestamp currentTime ); + bool evaluateConditions( const TimePoint ¤tTime ); /** * @brief Copy for a triggered condition data out of the signal buffer @@ -71,7 +71,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * * @return if dataReadyToBeSent() is false a nullptr otherwise the collected data will be returned */ - std::shared_ptr collectNextDataToSend( InspectionTimestamp currentTime, + std::shared_ptr collectNextDataToSend( const TimePoint ¤tTime, uint32_t &waitTimeMs ); /** * @brief Give a new signal to the collection engine to cached it @@ -86,7 +86,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre * @param receiveTime timestamp at which time was the signal seen on the physical bus * @param value the signal value as double */ - void addNewSignal( InspectionSignalID id, InspectionTimestamp receiveTime, InspectionValue value ); + void addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, InspectionValue value ); /** * @brief Add new raw CAN Frame history buffer. If frame is not needed call will be just ignored @@ -103,7 +103,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre */ void addNewRawCanFrame( CANRawFrameID canID, CANChannelNumericID channelID, - InspectionTimestamp receiveTime, + const TimePoint &receiveTime, std::array &buffer, uint8_t size ); @@ -277,7 +277,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre 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*/ - InspectionTimestamp mLastSample{ 0 }; + TimePoint mLastSample{ 0, 0 }; std::vector mWindowFunctionData; /**< every signal buffer can have multiple windows over different time periods*/ std::bitset @@ -344,7 +344,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre uint32_t mSize{ 0 }; uint32_t mCurrentPosition{ mSize - 1 }; // position in ringbuffer uint32_t mCounter{ 0 }; - InspectionTimestamp mLastSample{ 0 }; + TimePoint mLastSample{ 0, 0 }; }; /** @@ -357,7 +357,7 @@ class CollectionInspectionEngine : public IActiveConditionProcessor, public Thre { } InspectionTimestamp mLastDataTimestampPublished{ 0 }; - InspectionTimestamp mLastTrigger{ 0 }; + TimePoint mLastTrigger{ 0, 0 }; std::unordered_map mEvaluationSignals; // for fast lookup signals used for evaluation std::unordered_map diff --git a/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h b/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h index 6ebac686..0e7500aa 100644 --- a/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h +++ b/src/datamanagement/datainspection/include/CollectionInspectionWorkerThread.h @@ -111,6 +111,8 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, static void doWork( void *data ); + TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); + CollectionInspectionEngine fCollectionInspectionEngine; std::shared_ptr fInputSignalBuffer; diff --git a/src/datamanagement/datainspection/include/DataReduction.h b/src/datamanagement/datainspection/include/DataReduction.h index fbf02bb6..b3ff5630 100644 --- a/src/datamanagement/datainspection/include/DataReduction.h +++ b/src/datamanagement/datainspection/include/DataReduction.h @@ -45,8 +45,8 @@ class DataReduction bool shallSendData( double collectionSchemeProbability ) { - return ( mDisableProbability || - ( collectionSchemeProbability > 0.0 && generateNewRandomNumber() <= collectionSchemeProbability ) ); + return ( mDisableProbability || ( ( collectionSchemeProbability > 0.0 ) && + ( generateNewRandomNumber() <= collectionSchemeProbability ) ) ); } private: diff --git a/src/datamanagement/datainspection/include/OBDOverCANECU.h b/src/datamanagement/datainspection/include/OBDOverCANECU.h index 0175342f..10e43ed7 100644 --- a/src/datamanagement/datainspection/include/OBDOverCANECU.h +++ b/src/datamanagement/datainspection/include/OBDOverCANECU.h @@ -40,6 +40,7 @@ class OBDOverCANECU * @param txId CAN Transmit ID * @param isExtendedId CAN ID is standard(11-bit) or extended(29-bit) * @param signalBufferPtr Signal Buffer shared pointer + * @param broadcastSocket Sending broadcast requests by using broadcast socket * @return True if initialization of ISO-TP is successful */ bool init( const std::string &gatewayCanInterfaceName, @@ -47,7 +48,8 @@ class OBDOverCANECU const uint32_t rxId, const uint32_t txId, bool isExtendedId, - SignalBufferPtr &signalBufferPtr ); + SignalBufferPtr &signalBufferPtr, + int broadcastSocket ); /** * @brief Returns the health state of the ISO-TP Connection. @@ -59,27 +61,35 @@ class OBDOverCANECU * @brief Get the supported PIDs from ECU * * @param sid Service Mode - * @return true if successfully get the supported PID list from ECU + * @return Number of requests made to ECU */ - bool requestReceiveSupportedPIDs( const SID sid ); + size_t requestReceiveSupportedPIDs( const SID sid ); /** * @brief request PIDs from ECU * * @param sid Service Mode. e.g: 1 * @return true if software received the PID response correctly from ECU - * @return false if software didn't receive the PID response correctly from ECU + * @return Number of requests made to ECU */ - bool requestReceiveEmissionPIDs( const SID sid ); + size_t requestReceiveEmissionPIDs( const SID sid ); /** * @brief get DTC from ECU * * @param dtcInfo DTCInfo is a structure contains a list of DTC codes + * @param numRequests Number of requests sent to ECU * @return true if software received the DTC response correctly from ECU * @return false if software didn't receive the DTC response correctly from ECU */ - bool getDTCData( DTCInfo &dtcInfo ); + bool getDTCData( DTCInfo &dtcInfo, size_t &numRequests ); + + /** + * @brief Flush socket to ignore the received data + * @param timeout poll timeout + * @return Time(Ms) needed for poll + */ + uint32_t flush( uint32_t timeout ); /** * @brief Get the CAN Receiver ID @@ -116,8 +126,6 @@ class OBDOverCANECU */ bool getRequestedPIDs( const SID sid, std::vector &requestedPIDs ) const; - // Issues a supported PID request to the specific ECU and SID - bool requestSupportedPIDs( const SID sid ); // Receives the supported PID request to the specific ECU and SID bool receiveSupportedPIDs( const SID sid, SupportedPIDs &supportedPIDs ); diff --git a/src/datamanagement/datainspection/include/OBDOverCANModule.h b/src/datamanagement/datainspection/include/OBDOverCANModule.h index 898aa3ce..a5d743bd 100644 --- a/src/datamanagement/datainspection/include/OBDOverCANModule.h +++ b/src/datamanagement/datainspection/include/OBDOverCANModule.h @@ -50,14 +50,16 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive * is running. Typically on the Gateway ECU. * @param pidRequestIntervalSeconds Interval in seconds used to schedule PID requests * @param dtcRequestIntervalSeconds Interval in seconds used to schedule DTC requests + * @param broadcastRequests Broadcast requests to all ECUs - required by some vehicles * @return True if successful. False if both pidRequestIntervalSeconds * and dtcRequestIntervalSeconds are zero i.e. no collection */ bool init( SignalBufferPtr signalBufferPtr, ActiveDTCBufferPtr activeDTCBufferPtr, const std::string &gatewayCanInterfaceName, - const uint32_t &pidRequestIntervalSeconds, - const uint32_t &dtcRequestIntervalSeconds = 0 ); + uint32_t pidRequestIntervalSeconds, + uint32_t dtcRequestIntervalSeconds, + bool broadcastRequests ); /** * @brief Creates an ISO-TP connection to the Engine/Transmission ECUs. Starts the * Keep Alive cyclic thread. @@ -78,22 +80,13 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive */ bool isAlive(); - /** - * @brief A callback function to be invoked when there's a new Decoder Dictionary. If the networkProtocol - * is OBD, this module will update the decoder dictionary. - * - * @param dictionary decoder dictionary - * @param networkProtocol network protocol which can be OBD - */ + // From IActiveDecoderDictionaryListener + // We need this to know whether PIDs should be requested or not void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, VehicleDataSourceProtocol networkProtocol ) override; - /** - * @brief A callback function to be invoked when there's a new Inspection Matrix. The inspection - * matrix will specify whether or not we shall collect DTC - * - * @param activeConditions Inspection Matrix - */ + // From IActiveConditionProcessor + // We need this to know whether DTCs should be requested or not void onChangeInspectionMatrix( const std::shared_ptr &activeConditions ) override; /** @@ -129,14 +122,16 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive bool autoDetectECUs( bool isExtendedID, std::vector &canIDResponses ); // calculate ECU CAN Transmit ID from Receiver ID - static constexpr uint32_t getTxIDByRxID( uint32_t rxId ); + static constexpr uint32_t getTxIDByRxID( bool isExtendedID, uint32_t rxId ); /** * @brief Initialize ECUs by detected CAN IDs + * @param isExtendedID When true, 29-bit messages were detected, otherwise 11-bit * @param canIDResponse Detected CAN ID via broadcast request + * @param broadcastSocket Broadcast socket for sending request. Can be -1 to send using physical socket. * @return True if all OBDOverCANECU modules are initialized successfully for ECUs */ - bool initECUs( std::vector &canIDResponse ); + bool initECUs( bool isExtendedID, std::vector &canIDResponse, int broadcastSocket ); // Start the thread bool start(); @@ -155,7 +150,22 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive static void doWork( void *data ); // This function will assign PIDs to each ECU - bool assignPIDsToECUs(); + void assignPIDsToECUs(); + /** + * @brief Open an ISO-TP broadcast socket to send requests for all ECUs + * @param isExtendedId Whether the broadcast ID is in extended format (29-bit) or standard format (11 bit) + * @return Broadcast socket, or -1 on error + */ + int openISOTPBroadcastSocket( bool isExtendedId ); + /** + * @brief Flush ecus sockets to ignore received data from broadcast request. If mBroadcastRequests is false, + * no flushing will be performed. + * @param count The number of responses to be flushed + * @param exceptECU Flush all ECUs except this one + */ + void flush( size_t count, std::shared_ptr &exceptECU ); + + static void calcSleepTime( uint32_t requestIntervalSeconds, const Timer &timer, int64_t &outputSleepTime ); Thread mThread; std::atomic mShouldStop{ false }; @@ -176,6 +186,8 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive ActiveDTCBufferPtr mActiveDTCBufferPtr; uint32_t mPIDRequestIntervalSeconds{ 0 }; uint32_t mDTCRequestIntervalSeconds{ 0 }; + bool mBroadcastRequests{ false }; + int mBroadcastSocket{ -1 }; std::string mGatewayCanInterfaceName; Timer mDTCTimer; Timer mPIDTimer; @@ -197,7 +209,6 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive static constexpr uint32_t MASKING_SHIFT_BITS = 8; // Shift 8 bits static constexpr uint32_t MASKING_TEMPLATE_TX_ID = 0x18DA00F1; // All 29-bit tx id has the same bytes static constexpr uint32_t MASKING_REMOVE_BYTE = 0x8; - static constexpr uint32_t P2_TIMEOUT_DEFAULT_MS = 1000; // Set 1000 milliseconds timeout for ECU auto detection }; } // namespace DataInspection } // namespace IoTFleetWise diff --git a/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp b/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp index b5d25b3a..83eb9342 100644 --- a/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp +++ b/src/datamanagement/datainspection/src/CollectionInspectionEngine.cpp @@ -42,19 +42,19 @@ CollectionInspectionEngine::isSignalPartOfEval( const struct ExpressionNode *exp InspectionSignalID signalID, int remainingStackDepth ) { - if ( remainingStackDepth <= 0 || expression == nullptr ) + if ( ( remainingStackDepth <= 0 ) || ( expression == nullptr ) ) { return false; } - if ( expression->nodeType == ExpressionNodeType::SIGNAL || - expression->nodeType == ExpressionNodeType::WINDOWFUNCTION ) + if ( ( expression->nodeType == ExpressionNodeType::SIGNAL ) || + ( expression->nodeType == ExpressionNodeType::WINDOWFUNCTION ) ) { return expression->signalID == signalID; } else if ( expression->nodeType == ExpressionNodeType::GEOHASHFUNCTION ) { - return expression->function.geohashFunction.latitudeSignalID == signalID || - expression->function.geohashFunction.longitudeSignalID == signalID; + return ( expression->function.geohashFunction.latitudeSignalID == signalID ) || + ( expression->function.geohashFunction.longitudeSignalID == signalID ); } // Recursion limited depth through last parameter bool leftRet = isSignalPartOfEval( expression->left, signalID, remainingStackDepth - 1 ); @@ -115,8 +115,8 @@ CollectionInspectionEngine::onChangeInspectionMatrix( bool found = false; for ( auto &buf : mCanFrameBuffers ) { - if ( buf.mFrameID == c.frameID && buf.mChannelID == c.channelID && - buf.mMinimumSampleIntervalMs == c.minimumSampleIntervalMs ) + if ( ( buf.mFrameID == c.frameID ) && ( buf.mChannelID == c.channelID ) && + ( buf.mMinimumSampleIntervalMs == c.minimumSampleIntervalMs ) ) { found = true; buf.mSize = std::max( buf.mSize, c.sampleBufferSize ); @@ -145,7 +145,7 @@ CollectionInspectionEngine::onChangeInspectionMatrix( break; } } - if ( buf != nullptr && isSignalPartOfEval( ac.mCondition.condition, s.signalID, MAX_EQUATION_DEPTH ) ) + if ( ( buf != nullptr ) && isSignalPartOfEval( ac.mCondition.condition, s.signalID, MAX_EQUATION_DEPTH ) ) { buf->mConditionsThatEvaluateOnThisSignal.set( conditionIndex ); ac.mEvaluationSignals[s.signalID] = buf; @@ -247,13 +247,13 @@ CollectionInspectionEngine::updateAllFixedWindowFunctions( InspectionTimestamp t } bool -CollectionInspectionEngine::evaluateConditions( InspectionTimestamp currentTime ) +CollectionInspectionEngine::evaluateConditions( const TimePoint ¤tTime ) { bool oneConditionIsTrue = false; // if any sampling window times out there is a new value available to be processed by a condition - if ( currentTime >= mNextWindowFunctionTimesOut ) + if ( currentTime.monotonicTimeMs >= mNextWindowFunctionTimesOut ) { - updateAllFixedWindowFunctions( currentTime ); + updateAllFixedWindowFunctions( currentTime.monotonicTimeMs ); } auto conditionsToEvaluate = ( mConditionsWithConditionCurrentlyTrue | mConditionsWithInputSignalChanged ) & mConditionsNotTriggeredWaitingPublished; @@ -269,17 +269,19 @@ CollectionInspectionEngine::evaluateConditions( InspectionTimestamp currentTime if ( conditionsToEvaluate.test( i ) ) { ActiveCondition &condition = mConditions[i]; - if ( ( currentTime >= condition.mLastTrigger + condition.mCondition.minimumPublishInterval ) ) + if ( ( ( condition.mLastTrigger.systemTimeMs == 0 ) && ( condition.mLastTrigger.monotonicTimeMs == 0 ) ) || + ( currentTime.monotonicTimeMs >= + condition.mLastTrigger.monotonicTimeMs + condition.mCondition.minimumPublishIntervalMs ) ) { InspectionValue result = 0; bool resultBool = false; mConditionsWithInputSignalChanged.reset( i ); ExpressionErrorCode ret = eval( condition.mCondition.condition, condition, result, resultBool, MAX_EQUATION_DEPTH ); - if ( ret == ExpressionErrorCode::SUCCESSFUL && resultBool ) + if ( ( ret == ExpressionErrorCode::SUCCESSFUL ) && resultBool ) { - if ( !condition.mCondition.triggerOnlyOnRisingEdge || - !mConditionsWithConditionCurrentlyTrue.test( i ) ) + if ( ( !condition.mCondition.triggerOnlyOnRisingEdge ) || + ( !mConditionsWithConditionCurrentlyTrue.test( i ) ) ) { mConditionsNotTriggeredWaitingPublished.reset( i ); condition.mLastTrigger = currentTime; @@ -313,7 +315,7 @@ CollectionInspectionEngine::collectLastSignals( InspectionSignalID id, // Iterate through all sampling intervals of the signal for ( auto &buf : mSignalBuffers[id] ) { - if ( buf.mMinimumSampleIntervalMs == minimumSamplingInterval && buf.mSize > 0 ) + if ( ( buf.mMinimumSampleIntervalMs == minimumSamplingInterval ) && ( buf.mSize > 0 ) ) { int pos = static_cast( buf.mCurrentPosition ); for ( uint32_t i = 0; i < std::min( maxNumberOfSignalsToCollect, buf.mCounter ); i++ ) @@ -328,7 +330,7 @@ CollectionInspectionEngine::collectLastSignals( InspectionSignalID id, pos = 0; } auto &sample = buf.mBuffer[static_cast( pos )]; - if ( !sample.isAlreadyConsumed( conditionId ) || !mSendDataOnlyOncePerCondition ) + if ( ( !sample.isAlreadyConsumed( conditionId ) ) || ( !mSendDataOnlyOncePerCondition ) ) { output.emplace_back( id, sample.mTimestamp, sample.mValue ); sample.setAlreadyConsumed( conditionId, true ); @@ -352,8 +354,8 @@ CollectionInspectionEngine::collectLastCanFrames( CANRawFrameID canID, { for ( auto &buf : mCanFrameBuffers ) { - if ( buf.mFrameID == canID && buf.mChannelID == channelID && - buf.mMinimumSampleIntervalMs == minimumSamplingInterval ) + if ( ( buf.mFrameID == canID ) && ( buf.mChannelID == channelID ) && + ( buf.mMinimumSampleIntervalMs == minimumSamplingInterval ) ) { int pos = static_cast( buf.mCurrentPosition ); for ( uint32_t i = 0; i < std::min( maxNumberOfSignalsToCollect, buf.mCounter ); i++ ) @@ -368,7 +370,7 @@ CollectionInspectionEngine::collectLastCanFrames( CANRawFrameID canID, pos = 0; } auto &sample = buf.mBuffer[static_cast( pos )]; - if ( !sample.isAlreadyConsumed( conditionId ) || !mSendDataOnlyOncePerCondition ) + if ( ( !sample.isAlreadyConsumed( conditionId ) ) || ( !mSendDataOnlyOncePerCondition ) ) { output.emplace_back( canID, channelID, sample.mTimestamp, sample.mBuffer, sample.mSize ); sample.setAlreadyConsumed( conditionId, true ); @@ -388,7 +390,7 @@ CollectionInspectionEngine::collectData( ActiveCondition &condition, { std::shared_ptr collectedData = std::make_shared(); collectedData->metaData = condition.mCondition.metaData; - collectedData->triggerTime = condition.mLastTrigger; + collectedData->triggerTime = condition.mLastTrigger.systemTimeMs; // Pack signals for ( auto &s : condition.mCondition.signals ) { @@ -416,7 +418,7 @@ CollectionInspectionEngine::collectData( ActiveCondition &condition, } // Pack active DTCs if any if ( condition.mCondition.includeActiveDtcs && - ( !isActiveDTCsConsumed( conditionId ) || mSendDataOnlyOncePerCondition ) ) + ( ( !isActiveDTCsConsumed( conditionId ) ) || mSendDataOnlyOncePerCondition ) ) { collectedData->mDTCInfo = mActiveDTCs; setActiveDTCsConsumed( conditionId, true ); @@ -433,7 +435,7 @@ CollectionInspectionEngine::collectData( ActiveCondition &condition, } std::shared_ptr -CollectionInspectionEngine::collectNextDataToSend( InspectionTimestamp currentTime, uint32_t &waitTimeMs ) +CollectionInspectionEngine::collectNextDataToSend( const TimePoint ¤tTime, uint32_t &waitTimeMs ) { uint32_t minimumWaitTimeMs = std::numeric_limits::max(); if ( mConditionsNotTriggeredWaitingPublished.all() ) @@ -450,7 +452,9 @@ CollectionInspectionEngine::collectNextDataToSend( InspectionTimestamp currentTi if ( !mConditionsNotTriggeredWaitingPublished.test( mNextConditionToCollectedIndex ) ) { auto &condition = mConditions[mNextConditionToCollectedIndex]; - if ( currentTime >= condition.mLastTrigger + condition.mCondition.afterDuration ) + if ( ( ( condition.mLastTrigger.systemTimeMs == 0 ) && ( condition.mLastTrigger.monotonicTimeMs == 0 ) ) || + ( currentTime.monotonicTimeMs >= + condition.mLastTrigger.monotonicTimeMs + condition.mCondition.afterDuration ) ) { mConditionsNotTriggeredWaitingPublished.set( mNextConditionToCollectedIndex ); // Send message out only with a certain probability. If probabilityToSend==0 @@ -458,7 +462,7 @@ CollectionInspectionEngine::collectNextDataToSend( InspectionTimestamp currentTi if ( mDataReduction.shallSendData( condition.mCondition.probabilityToSend ) ) { // Generate the Event ID and pack it into the active Condition - condition.mEventID = generateEventID( currentTime ); + condition.mEventID = generateEventID( currentTime.systemTimeMs ); // Check if we need more data from other sensors evaluateAndTriggerRichSensorCapture( condition ); // Return the collected data @@ -466,16 +470,18 @@ CollectionInspectionEngine::collectNextDataToSend( InspectionTimestamp currentTi auto cd = collectData( condition, mNextConditionToCollectedIndex, newestSignalTimeStamp ); // After collecting the data set the newest timestamp from any data that was // collected - condition.mLastDataTimestampPublished = std::min( newestSignalTimeStamp, currentTime ); + condition.mLastDataTimestampPublished = + std::min( newestSignalTimeStamp, currentTime.monotonicTimeMs ); return cd; } } else { - minimumWaitTimeMs = std::min( - minimumWaitTimeMs, - static_cast( ( condition.mLastTrigger + condition.mCondition.afterDuration ) - - currentTime ) ); + minimumWaitTimeMs = + std::min( minimumWaitTimeMs, + static_cast( ( condition.mLastTrigger.monotonicTimeMs + + condition.mCondition.afterDuration ) - + currentTime.monotonicTimeMs ) ); } } mNextConditionToCollectedIndex++; @@ -515,9 +521,7 @@ CollectionInspectionEngine::evaluateAndTriggerRichSensorCapture( const ActiveCon } void -CollectionInspectionEngine::addNewSignal( InspectionSignalID id, - InspectionTimestamp receiveTime, - InspectionValue value ) +CollectionInspectionEngine::addNewSignal( InspectionSignalID id, const TimePoint &receiveTime, InspectionValue value ) { if ( mSignalBuffers.find( id ) == mSignalBuffers.end() || mSignalBuffers[id].empty() ) { @@ -527,9 +531,10 @@ CollectionInspectionEngine::addNewSignal( InspectionSignalID id, // 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 || - ( receiveTime >= buf.mLastSample + buf.mMinimumSampleIntervalMs ) ) ) + 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 ) @@ -537,13 +542,13 @@ CollectionInspectionEngine::addNewSignal( InspectionSignalID id, buf.mCurrentPosition = 0; } buf.mBuffer[buf.mCurrentPosition].mValue = value; - buf.mBuffer[buf.mCurrentPosition].mTimestamp = receiveTime; + 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, mNextWindowFunctionTimesOut ); + window.addValue( value, receiveTime.monotonicTimeMs, mNextWindowFunctionTimesOut ); } mConditionsWithInputSignalChanged |= buf.mConditionsThatEvaluateOnThisSignal; } @@ -553,17 +558,18 @@ CollectionInspectionEngine::addNewSignal( InspectionSignalID id, void CollectionInspectionEngine::addNewRawCanFrame( CANRawFrameID canID, CANChannelNumericID channelID, - InspectionTimestamp receiveTime, + const TimePoint &receiveTime, std::array &buffer, uint8_t size ) { for ( auto &buf : mCanFrameBuffers ) { - if ( buf.mFrameID == canID && buf.mChannelID == channelID ) + if ( ( buf.mFrameID == canID ) && ( buf.mChannelID == channelID ) ) { - if ( buf.mSize > 0 && buf.mSize <= buf.mBuffer.size() && - ( buf.mMinimumSampleIntervalMs == 0 || - ( receiveTime >= buf.mLastSample + buf.mMinimumSampleIntervalMs ) ) ) + 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 ) @@ -576,7 +582,7 @@ CollectionInspectionEngine::addNewRawCanFrame( CANRawFrameID canID, { buf.mBuffer[buf.mCurrentPosition].mBuffer[i] = buffer[i]; } - buf.mBuffer[buf.mCurrentPosition].mTimestamp = receiveTime; + buf.mBuffer[buf.mCurrentPosition].mTimestamp = receiveTime.systemTimeMs; buf.mBuffer[buf.mCurrentPosition].setAlreadyConsumed( ALL_CONDITIONS, false ); buf.mCounter++; buf.mLastSample = receiveTime; @@ -598,7 +604,7 @@ CollectionInspectionEngine::getLatestSignalValue( InspectionSignalID id, InspectionValue &result ) { auto mapLookup = condition.mEvaluationSignals.find( id ); - if ( mapLookup == condition.mEvaluationSignals.end() || mapLookup->second == nullptr ) + if ( ( mapLookup == condition.mEvaluationSignals.end() ) || ( mapLookup->second == nullptr ) ) { mLogger.warn( "CollectionInspectionEngine::getLatestSignalValue", "SIGNAL_NOT_FOUND" ); // Signal not collected by any active condition @@ -621,7 +627,7 @@ CollectionInspectionEngine::getSampleWindowFunction( WindowFunction function, InspectionValue &result ) { auto mapLookup = condition.mEvaluationFunctions.find( signalID ); - if ( mapLookup == condition.mEvaluationFunctions.end() || mapLookup->second == nullptr ) + if ( ( mapLookup == condition.mEvaluationFunctions.end() ) || ( mapLookup->second == nullptr ) ) { // Signal not collected by any active condition return ExpressionErrorCode::SIGNAL_NOT_FOUND; @@ -668,7 +674,7 @@ CollectionInspectionEngine::getGeohashFunctionNode( const struct ExpressionNode if ( status != ExpressionErrorCode::SUCCESSFUL ) { mLogger.warn( "CollectionInspectionEngine::getGeohashFunctionNode", - "Unable to evaluate Geohash due to missing latitude signal!" ); + "Unable to evaluate Geohash due to missing latitude signal" ); return status; } InspectionValue longitude = 0; @@ -676,7 +682,7 @@ CollectionInspectionEngine::getGeohashFunctionNode( const struct ExpressionNode if ( status != ExpressionErrorCode::SUCCESSFUL ) { mLogger.warn( "CollectionInspectionEngine::getGeohashFunctionNode", - "Unable to evaluate Geohash due to missing longitude signal!" ); + "Unable to evaluate Geohash due to missing longitude signal" ); return status; } resultValueBool = mGeohashFunctionNode.evaluateGeohash( latitude, @@ -693,7 +699,7 @@ CollectionInspectionEngine::eval( const struct ExpressionNode *expression, bool &resultValueBool, int remainingStackDepth ) { - if ( remainingStackDepth <= 0 || expression == nullptr ) + if ( ( remainingStackDepth <= 0 ) || ( expression == nullptr ) ) { mLogger.warn( "CollectionInspectionEngine::eval", "STACK_DEPTH_REACHED or nullptr" ); return ExpressionErrorCode::STACK_DEPTH_REACHED; diff --git a/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp b/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp index 04917641..7a06cb93 100644 --- a/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp +++ b/src/datamanagement/datainspection/src/CollectionInspectionWorkerThread.cpp @@ -35,11 +35,11 @@ CollectionInspectionWorkerThread::init( const std::shared_ptr &inp bool CollectionInspectionWorkerThread::start() { - if ( fInputCANBuffer == nullptr || fInputCANBuffer == nullptr || fInputActiveDTCBuffer == nullptr || - fOutputCollectedData == nullptr ) + if ( ( fInputCANBuffer == nullptr ) || ( fInputCANBuffer == nullptr ) || ( fInputActiveDTCBuffer == nullptr ) || + ( fOutputCollectedData == nullptr ) ) { fLogger.error( "CollectionInspectionWorkerThread::start", - " Collection Engine cannot be started without correct configurations " ); + "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 " ); + fLogger.trace( "CollectionInspectionWorkerThread::start", "Inspection Thread failed to start" ); } else { - fLogger.trace( "CollectionInspectionWorkerThread::start", " Inspection Thread started " ); + fLogger.trace( "CollectionInspectionWorkerThread::start", "Inspection Thread started" ); fThread.setThreadName( "fwDICollInsEng" ); } @@ -63,16 +63,16 @@ CollectionInspectionWorkerThread::start() bool CollectionInspectionWorkerThread::stop() { - if ( !fThread.isValid() || !fThread.isActive() ) + if ( ( !fThread.isValid() ) || ( !fThread.isActive() ) ) { return true; } std::lock_guard lock( fThreadMutex ); fShouldStop.store( true, std::memory_order_relaxed ); - fLogger.trace( "CollectionInspectionWorkerThread::stop", " Request stop " ); + fLogger.trace( "CollectionInspectionWorkerThread::stop", "Request stop" ); fWait.notify(); fThread.release(); - fLogger.trace( "CollectionInspectionWorkerThread::stop", " Stop finished " ); + fLogger.trace( "CollectionInspectionWorkerThread::stop", "Stop finished" ); fShouldStop.store( false, std::memory_order_relaxed ); return !fThread.isActive(); } @@ -92,7 +92,7 @@ CollectionInspectionWorkerThread::onChangeInspectionMatrix( fUpdatedInspectionMatrix = activeConditions; fUpdatedInspectionMatrixAvailable = true; fLogger.trace( "CollectionInspectionWorkerThread::onChangeInspectionMatrix", - " new inspection matrix handed over " ); + "New inspection matrix handed over" ); // Wake up the thread. fWait.notify(); } @@ -110,7 +110,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) CollectionInspectionWorkerThread *consumer = static_cast( data ); Timestamp lastInputTimeEvaluated = 0; - Timestamp lastTimeEvaluated = 0; + TimePoint lastTimeEvaluated = { 0, 0 }; Timestamp lastTraceOutput = 0; uint64_t inputCounterSinceLastEvaluate = 0; uint32_t statisticInputMessagesProcessed = 0; @@ -138,13 +138,17 @@ CollectionInspectionWorkerThread::doWork( void *data ) CollectedSignal inputSignal( 0, 0, 0.0 ); std::array buf = {}; CollectedCanRawFrame inputCANFrame( 0, 0, 0, buf, 0 ); + TimePoint currentTime = consumer->fClock->timeSinceEpoch(); // Consume any new signals and pass them over to the inspection Engine if ( consumer->fInputSignalBuffer->pop( inputSignal ) ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); + TraceModule::get().incrementVariable( TraceVariable::CE_PROCESSED_SIGNALS ); readyToSleep = false; consumer->fCollectionInspectionEngine.addNewSignal( - inputSignal.signalID, inputSignal.receiveTime, inputSignal.value ); + inputSignal.signalID, + consumer->calculateMonotonicTime( currentTime, inputSignal.receiveTime ), + inputSignal.value ); latestSignalTime = std::max( latestSignalTime, inputSignal.receiveTime ); inputCounterSinceLastEvaluate++; statisticInputMessagesProcessed++; @@ -153,12 +157,14 @@ CollectionInspectionWorkerThread::doWork( void *data ) if ( consumer->fInputCANBuffer->pop( inputCANFrame ) ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_CAN ); + TraceModule::get().incrementVariable( TraceVariable::CE_PROCESSED_CAN_FRAMES ); readyToSleep = false; - consumer->fCollectionInspectionEngine.addNewRawCanFrame( inputCANFrame.frameID, - inputCANFrame.channelId, - inputCANFrame.receiveTime, - inputCANFrame.data, - inputCANFrame.size ); + consumer->fCollectionInspectionEngine.addNewRawCanFrame( + inputCANFrame.frameID, + inputCANFrame.channelId, + consumer->calculateMonotonicTime( currentTime, inputCANFrame.receiveTime ), + inputCANFrame.data, + inputCANFrame.size ); latestSignalTime = std::max( latestSignalTime, inputCANFrame.receiveTime ); inputCounterSinceLastEvaluate++; statisticInputMessagesProcessed++; @@ -182,26 +188,27 @@ CollectionInspectionWorkerThread::doWork( void *data ) ( inputCounterSinceLastEvaluate >= 256 ) ) { lastInputTimeEvaluated = latestSignalTime; - lastTimeEvaluated = consumer->fClock->timeSinceEpochMs(); + lastTimeEvaluated = consumer->fClock->timeSinceEpoch(); consumer->fCollectionInspectionEngine.evaluateConditions( lastTimeEvaluated ); inputCounterSinceLastEvaluate = 0; } // before going to sleep do another evaluation if last evaluation is more than EVALUATE_INTERVAL_MS ago - if ( readyToSleep && - ( ( consumer->fClock->timeSinceEpochMs() - lastTimeEvaluated ) >= EVALUATE_INTERVAL_MS ) ) + if ( readyToSleep && ( ( consumer->fClock->monotonicTimeSinceEpochMs() - + lastTimeEvaluated.monotonicTimeMs ) >= EVALUATE_INTERVAL_MS ) ) { lastInputTimeEvaluated = latestSignalTime; - lastTimeEvaluated = consumer->fClock->timeSinceEpochMs(); + lastTimeEvaluated = consumer->fClock->timeSinceEpoch(); consumer->fCollectionInspectionEngine.evaluateConditions( lastTimeEvaluated ); inputCounterSinceLastEvaluate = 0; } uint32_t waitTimeMs = consumer->fIdleTimeMs; std::shared_ptr collectedData = - consumer->fCollectionInspectionEngine.collectNextDataToSend( consumer->fClock->timeSinceEpochMs(), + consumer->fCollectionInspectionEngine.collectNextDataToSend( consumer->fClock->timeSinceEpoch(), waitTimeMs ); - while ( collectedData != nullptr && !consumer->shouldStop() ) + while ( ( collectedData != nullptr ) && ( !consumer->shouldStop() ) ) { + TraceModule::get().incrementVariable( TraceVariable::CE_TRIGGERS ); if ( !consumer->fOutputCollectedData->push( collectedData ) ) { consumer->fLogger.warn( "CollectionInspectionWorkerThread::doWork", @@ -213,7 +220,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) consumer->notifyListeners<>( &IDataReadyToPublishListener::onDataReadyToPublish ); } collectedData = consumer->fCollectionInspectionEngine.collectNextDataToSend( - consumer->fClock->timeSinceEpochMs(), waitTimeMs ); + consumer->fClock->timeSinceEpoch(), waitTimeMs ); } if ( readyToSleep ) @@ -221,7 +228,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) // Nothing is in the ring buffer to consume. Go to idle mode for some time. uint32_t timeToWait = std::min( waitTimeMs, consumer->fIdleTimeMs ); // Print only every THREAD_IDLE_TIME_MS to avoid console spam - if ( consumer->fClock->timeSinceEpochMs() > + if ( consumer->fClock->monotonicTimeSinceEpochMs() > ( lastTraceOutput + LoggingModule::LOG_AGGREGATION_TIME_MS ) ) { consumer->fLogger.trace( @@ -235,7 +242,7 @@ CollectionInspectionWorkerThread::doWork( void *data ) activations = 0; statisticInputMessagesProcessed = 0; statisticDataSentOut = 0; - lastTraceOutput = consumer->fClock->timeSinceEpochMs(); + lastTraceOutput = consumer->fClock->monotonicTimeSinceEpochMs(); } consumer->fWait.wait( timeToWait ); } @@ -248,6 +255,22 @@ CollectionInspectionWorkerThread::doWork( void *data ) } while ( !consumer->shouldStop() ); } +TimePoint +CollectionInspectionWorkerThread::calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ) +{ + 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 ) ); + return TimePoint{ systemTimeMs, 0 }; + } + return convertedTime; +} + bool CollectionInspectionWorkerThread::isAlive() { diff --git a/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp b/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp index a3965973..06ddf29c 100644 --- a/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp +++ b/src/datamanagement/datainspection/src/dds/DataOverDDSModule.cpp @@ -6,7 +6,6 @@ #include "dds/CameraDataPublisher.h" #include "dds/CameraDataSubscriber.h" #include -#include #include #include namespace Aws @@ -47,7 +46,7 @@ DataOverDDSModule::init( const DDSDataSourcesConfig &ddsDataSourcesConfig ) case SensorSourceType::CAMERA: publisher = std::make_unique(); subscriber = std::make_unique(); - if ( !publisher->init( config ) || !subscriber->init( config ) ) + if ( ( !publisher->init( config ) ) || ( !subscriber->init( config ) ) ) { mLogger.error( "DataOverDDSModule::init", "Failed to init the Publisher/Subscriber" ); return false; @@ -70,7 +69,7 @@ DataOverDDSModule::init( const DDSDataSourcesConfig &ddsDataSourcesConfig ) break; } } - return !mPublishers.empty() && !mSubscribers.empty() && mPublishers.size() == mSubscribers.size(); + return ( !mPublishers.empty() ) && ( !mSubscribers.empty() ) && ( mPublishers.size() == mSubscribers.size() ); } bool @@ -83,11 +82,11 @@ DataOverDDSModule::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "DataOverDDSModule::start", " DataOverDDSModule Thread failed to start" ); + mLogger.trace( "DataOverDDSModule::start", "DataOverDDSModule Thread failed to start" ); } else { - mLogger.trace( "DataOverDDSModule::start", " DataOverDDSModule Thread started" ); + mLogger.trace( "DataOverDDSModule::start", "DataOverDDSModule Thread started" ); mThread.setThreadName( "fwDIDDSModule" ); } @@ -143,7 +142,7 @@ 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: " + + "Received an event for a Source that's not configured, Source ID: " + std::to_string( eventItem.sourceID ) ); } else @@ -158,7 +157,7 @@ DataOverDDSModule::doWork( void *data ) publishIterator->second->publishDataRequest( request ); DDSModule->mLogger.trace( "DataOverDDSModule::doWork", - " Send a request to the DDS Network upon eventID: " + std::to_string( eventItem.eventID ) + + "Send a request to the DDS Network upon eventID: " + std::to_string( eventItem.eventID ) + " to DeviceID " + std::to_string( eventItem.sourceID ) ); } } @@ -179,14 +178,14 @@ DataOverDDSModule::connect() for ( auto &sub : mSubscribers ) { // Register the module as a listener of the Subscriber - if ( !sub->subscribeListener( this ) || !sub->connect() ) + if ( ( !sub->subscribeListener( this ) ) || ( !sub->connect() ) ) { - mLogger.error( "DataOverDDSModule::connect", " Failed to connect Subscriber" ); + mLogger.error( "DataOverDDSModule::connect", "Failed to connect Subscriber" ); return false; } else { - mLogger.trace( "DataOverDDSModule::connect", " Subscriber connected" ); + mLogger.trace( "DataOverDDSModule::connect", "Subscriber connected" ); } } @@ -194,12 +193,12 @@ DataOverDDSModule::connect() { if ( !pub.second->connect() ) { - mLogger.error( "DataOverDDSModule::connect", " Failed to connect Publisher" ); + mLogger.error( "DataOverDDSModule::connect", "Failed to connect Publisher" ); return false; } else { - mLogger.trace( "DataOverDDSModule::connect", " Publisher connected" ); + mLogger.trace( "DataOverDDSModule::connect", "Publisher connected" ); } } } @@ -216,14 +215,14 @@ DataOverDDSModule::disconnect() // First disconnect the Subscribers and the Publishers for ( auto &sub : mSubscribers ) { - if ( !sub->unSubscribeListener( this ) || !sub->disconnect() ) + if ( ( !sub->unSubscribeListener( this ) ) || ( !sub->disconnect() ) ) { - mLogger.error( "DataOverDDSModule::disconnect", " Failed to disconnect Subscriber" ); + mLogger.error( "DataOverDDSModule::disconnect", "Failed to disconnect Subscriber" ); return false; } else { - mLogger.trace( "DataOverDDSModule::disconnect", " Subscriber disconnected" ); + mLogger.trace( "DataOverDDSModule::disconnect", "Subscriber disconnected" ); } } @@ -231,12 +230,12 @@ DataOverDDSModule::disconnect() { if ( !pub.second->disconnect() ) { - mLogger.error( "DataOverDDSModule::disconnect", " Failed to disconnect Publisher" ); + mLogger.error( "DataOverDDSModule::disconnect", "Failed to disconnect Publisher" ); return false; } else { - mLogger.trace( "DataOverDDSModule::disconnect", " Publisher disconnected" ); + mLogger.trace( "DataOverDDSModule::disconnect", "Publisher disconnected" ); } } } @@ -254,7 +253,7 @@ DataOverDDSModule::isAlive() { if ( !sub->isAlive() ) { - mLogger.error( "DataOverDDSModule::isAlive", " Subscriber not alive" ); + mLogger.error( "DataOverDDSModule::isAlive", "Subscriber not alive" ); return false; } } @@ -281,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 " ); + mLogger.trace( "DataOverDDSModule::onEventOfInterestDetected", "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 68956a9f..868b15d1 100644 --- a/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp +++ b/src/datamanagement/datainspection/src/diag/OBDOverCANECU.cpp @@ -3,9 +3,7 @@ // Includes #include "OBDOverCANECU.h" -// #include "EnumUtility.h" #include "TraceModule.h" -// #include #include #include @@ -24,13 +22,15 @@ OBDOverCANECU::init( const std::string &gatewayCanInterfaceName, const uint32_t rxId, const uint32_t txId, bool isExtendedId, - SignalBufferPtr &signalBufferPtr ) + SignalBufferPtr &signalBufferPtr, + int broadcastSocket ) { ISOTPOverCANSenderReceiverOptions optionsECU; optionsECU.mSocketCanIFName = gatewayCanInterfaceName; optionsECU.mSourceCANId = txId; optionsECU.mDestinationCANId = rxId; optionsECU.mIsExtendedId = isExtendedId; + optionsECU.mBroadcastSocket = broadcastSocket; mOBDDataDecoder = obdDataDecoder; mSignalBufferPtr = signalBufferPtr; @@ -50,11 +50,17 @@ OBDOverCANECU::init( const std::string &gatewayCanInterfaceName, return true; } -bool +uint32_t +OBDOverCANECU::flush( uint32_t timeout ) +{ + mLogger.trace( "OBDOverCANECU::flushSocket", "Flushed socket for ECU with ecu id: " + mStreamRxID ); + return mISOTPSenderReceiver.flush( timeout ); +} + +size_t OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) { - // Function will return true if it receive supported PIDs from the ECU - bool requestStatus = false; + size_t numRequests = 0; static_assert( supportedPIDRange.size() <= 8, "Array length for supported PID range shall be less or equal than 8" ); if ( mISOTPSenderReceiver.isAlive() ) @@ -70,14 +76,11 @@ OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) auto pidList = std::vector( supportedPIDRange.begin(), supportedPIDRange.begin() + std::min( MAX_PID_RANGE, supportedPIDRange.size() ) ); + numRequests++; if ( requestPIDs( sid, pidList ) ) { // Wait and process the response - if ( receiveSupportedPIDs( sid, allSupportedPIDs ) ) - { - requestStatus = true; - } - else + if ( !receiveSupportedPIDs( sid, allSupportedPIDs ) ) { TraceModule::get().incrementVariable( TraceVariable::OBD_ENG_PID_REQ_ERROR ); // log warning as all emissions-related OBD ECUs which support at least one of the @@ -90,29 +93,24 @@ OBDOverCANECU::requestReceiveSupportedPIDs( const SID sid ) if ( MAX_PID_RANGE < supportedPIDRange.size() ) { pidList = std::vector( supportedPIDRange.begin() + MAX_PID_RANGE, supportedPIDRange.end() ); + numRequests++; if ( requestPIDs( sid, pidList ) ) { // Wait and process the response - if ( receiveSupportedPIDs( sid, allSupportedPIDs ) ) - { - requestStatus = true; - } + receiveSupportedPIDs( sid, allSupportedPIDs ); } } - if ( requestStatus ) - { - mSupportedPIDs.emplace( sid, allSupportedPIDs ); - mLogger.traceBytesInVector( "OBDOverCANECU::requestReceiveSupportedPIDs", - "ECU " + mStreamRxID + " supports PIDs for SID " + - std::to_string( toUType( sid ) ), - allSupportedPIDs ); - } + mSupportedPIDs.emplace( sid, allSupportedPIDs ); + mLogger.traceBytesInVector( "OBDOverCANECU::requestReceiveSupportedPIDs", + "ECU " + mStreamRxID + " supports PIDs for SID " + + std::to_string( toUType( sid ) ), + allSupportedPIDs ); } } - return requestStatus; + return numRequests; } -bool +size_t OBDOverCANECU::requestReceiveEmissionPIDs( const SID sid ) { EmissionInfo info; @@ -120,7 +118,8 @@ OBDOverCANECU::requestReceiveEmissionPIDs( const SID sid ) // Request the PIDs ( up to 6 at a time ) // To not overwhelm the bus, we split the PIDs into group of 6 // and wait for the response. - if ( getRequestedPIDs( sid, pids ) && !pids.empty() ) + size_t numRequests = 0; + if ( getRequestedPIDs( sid, pids ) && ( !pids.empty() ) ) { SupportedPIDs::iterator pidItr = pids.begin(); while ( pidItr != pids.end() ) @@ -130,7 +129,7 @@ OBDOverCANECU::requestReceiveEmissionPIDs( const SID sid ) if ( !info.mPIDsToValues.empty() ) { - auto receptionTime = mClock->timeSinceEpochMs(); + auto receptionTime = mClock->systemTimeSinceEpochMs(); for ( auto const &signals : info.mPIDsToValues ) { // Note Signal buffer is a multi producer single consumer queue. Besides current thread, @@ -144,18 +143,19 @@ OBDOverCANECU::requestReceiveEmissionPIDs( const SID sid ) "Signal Buffer full with ECU " + mStreamRxID ); } mLogger.trace( "OBDOverCANECU::requestReceiveEmissionPIDs", - "Received Signal " + std::to_string( signals.first ) + " : " + + "Received Signal " + std::to_string( signals.first ) + ": " + std::to_string( signals.second ) + " for ECU: " + mStreamRxID ); } } } - return !info.mPIDsToValues.empty(); + return numRequests; } bool -OBDOverCANECU::getDTCData( DTCInfo &dtcInfo ) +OBDOverCANECU::getDTCData( DTCInfo &dtcInfo, size_t &numRequests ) { bool successfulDTCRequest = false; + numRequests = 1; if ( requestReceiveDTCs( SID::STORED_DTC, dtcInfo ) ) { successfulDTCRequest = true; @@ -176,7 +176,7 @@ OBDOverCANECU::requestReceivePIDs( SupportedPIDs::iterator &pidItr, EmissionInfo &info ) { std::vector currPIDs; - while ( currPIDs.size() < MAX_PID_RANGE && pidItr != pids.end() ) + while ( ( currPIDs.size() < MAX_PID_RANGE ) && ( pidItr != pids.end() ) ) { currPIDs.push_back( *pidItr++ ); } @@ -199,23 +199,6 @@ OBDOverCANECU::requestReceivePIDs( SupportedPIDs::iterator &pidItr, } } -bool -OBDOverCANECU::requestSupportedPIDs( const SID sid ) -{ - mLogger.trace( "OBDOverCANECU::requestSupportedPIDs", - "Start to request supported PID data for SID: " + std::to_string( toUType( sid ) ) + - " with ECU: " + mStreamRxID ); - - mTxPDU.clear(); - // Every ECU should support such kind of request. - // J1979 8.1 - // First insert the SID - mTxPDU.emplace_back( static_cast( sid ) ); - // Then insert the PID ranges - mTxPDU.insert( mTxPDU.end(), std::begin( supportedPIDRange ), std::end( supportedPIDRange ) ); - return mISOTPSenderReceiver.sendPDU( mTxPDU ); -} - bool OBDOverCANECU::receiveSupportedPIDs( const SID sid, SupportedPIDs &supportedPIDs ) { @@ -224,10 +207,9 @@ OBDOverCANECU::receiveSupportedPIDs( const SID sid, SupportedPIDs &supportedPIDs // decoded according to J1979 8.1.2.2 if ( !mISOTPSenderReceiver.receivePDU( ecuResponse ) ) { - mLogger.warn( "OBDOverCANECU::receiveSupportedPIDs", "Failed to receive PIDs for ECU " + mStreamRxID ); return false; } - if ( !ecuResponse.empty() && mOBDDataDecoder->decodeSupportedPIDs( sid, ecuResponse, supportedPIDs ) ) + if ( ( !ecuResponse.empty() ) && mOBDDataDecoder->decodeSupportedPIDs( sid, ecuResponse, supportedPIDs ) ) { return true; } @@ -302,7 +284,7 @@ OBDOverCANECU::receiveDTCs( const SID sid, DTCInfo &info ) return false; } // The info structure will be appended with the new decoded DTCs - if ( !ecuResponse.empty() && mOBDDataDecoder->decodeDTCs( sid, ecuResponse, info ) ) + if ( ( !ecuResponse.empty() ) && mOBDDataDecoder->decodeDTCs( sid, ecuResponse, info ) ) { return true; } diff --git a/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp b/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp index 12d228b1..2daf4521 100644 --- a/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp +++ b/src/datamanagement/datainspection/src/diag/OBDOverCANModule.cpp @@ -5,10 +5,12 @@ #include "OBDOverCANModule.h" #include "EnumUtility.h" #include "TraceModule.h" +#include "datatypes/ISOTPOverCANOptions.h" #include #include #include #include +#include #include #include #include @@ -21,13 +23,13 @@ namespace IoTFleetWise { 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; -constexpr uint32_t OBDOverCANModule::P2_TIMEOUT_DEFAULT_MS; OBDOverCANModule::~OBDOverCANModule() { @@ -42,11 +44,12 @@ bool OBDOverCANModule::init( SignalBufferPtr signalBufferPtr, ActiveDTCBufferPtr activeDTCBufferPtr, const std::string &gatewayCanInterfaceName, - const uint32_t &pidRequestIntervalSeconds, - const uint32_t &dtcRequestIntervalSeconds ) + uint32_t pidRequestIntervalSeconds, + uint32_t dtcRequestIntervalSeconds, + bool broadcastRequests ) { // Sanity check - if ( pidRequestIntervalSeconds == 0 && dtcRequestIntervalSeconds == 0 ) + 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" ); @@ -54,7 +57,7 @@ OBDOverCANModule::init( SignalBufferPtr signalBufferPtr, return false; } - if ( signalBufferPtr.get() == nullptr || activeDTCBufferPtr.get() == nullptr ) + if ( ( signalBufferPtr.get() == nullptr ) || ( activeDTCBufferPtr.get() == nullptr ) ) { mLogger.error( "OBDOverCANModule::init", "Received Buffer nullptr" ); return false; @@ -70,6 +73,7 @@ OBDOverCANModule::init( SignalBufferPtr signalBufferPtr, mGatewayCanInterfaceName = gatewayCanInterfaceName; mPIDRequestIntervalSeconds = pidRequestIntervalSeconds; mDTCRequestIntervalSeconds = dtcRequestIntervalSeconds; + mBroadcastRequests = broadcastRequests; return true; } @@ -88,11 +92,11 @@ OBDOverCANModule::start() mShouldRequestDTCs.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "OBDOverCANModule::start", " OBD Module Thread failed to start " ); + mLogger.trace( "OBDOverCANModule::start", "Thread failed to start" ); } else { - mLogger.trace( "OBDOverCANModule::start", " OBD Module Thread started" ); + mLogger.trace( "OBDOverCANModule::start", "Thread started" ); mThread.setThreadName( "fwDIOBDModule" ); } @@ -102,19 +106,23 @@ OBDOverCANModule::start() bool OBDOverCANModule::stop() { - if ( !mThread.isValid() || !mThread.isActive() ) + if ( ( !mThread.isValid() ) || ( !mThread.isActive() ) ) { return true; } std::lock_guard lock( mThreadMutex ); mShouldStop.store( true, std::memory_order_relaxed ); - mLogger.trace( "OBDOverCANModule::stop", " OBD Module Thread requested to stop " ); + mLogger.trace( "OBDOverCANModule::stop", "Thread requested to stop" ); mWait.notify(); mDataAvailableWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "OBDOverCANModule::stop", " OBD Module Thread stopped " ); + mLogger.trace( "OBDOverCANModule::stop", "Thread stopped" ); + if ( ( mBroadcastSocket >= 0 ) && ( close( mBroadcastSocket ) < 0 ) ) + { + mLogger.error( "OBDOverCANModule::stop", "Failed to close broadcastSocket." ); + } return !mThread.isActive(); } @@ -130,13 +138,13 @@ OBDOverCANModule::doWork( void *data ) OBDOverCANModule *obdModule = static_cast( data ); // First we will auto detect ECUs bool finishECUsDetection = false; - while ( !finishECUsDetection && !obdModule->shouldStop() ) + while ( ( !finishECUsDetection ) && ( !obdModule->shouldStop() ) ) { std::vector canIDResponses; // If we don't have an OBD decoder manifest and we should not request DTCs, // Take the thread to sleep - if ( !obdModule->mShouldRequestDTCs.load( std::memory_order_relaxed ) && - ( !obdModule->mDecoderDictionaryPtr || obdModule->mDecoderDictionaryPtr->empty() ) ) + if ( ( !obdModule->mShouldRequestDTCs.load( std::memory_order_relaxed ) ) && + ( ( !obdModule->mDecoderDictionaryPtr ) || obdModule->mDecoderDictionaryPtr->empty() ) ) { obdModule->mLogger.trace( "OBDOverCANModule::doWork", @@ -144,21 +152,34 @@ OBDOverCANModule::doWork( void *data ) obdModule->mDataAvailableWait.wait( Platform::Linux::Signal::WaitWithPredicate ); } // Now we will determine whether the ECUs are using extended IDs - obdModule->autoDetectECUs( false, canIDResponses ); + bool isExtendedID = false; + obdModule->autoDetectECUs( isExtendedID, canIDResponses ); if ( canIDResponses.empty() ) { - obdModule->autoDetectECUs( true, canIDResponses ); + isExtendedID = true; + obdModule->autoDetectECUs( isExtendedID, canIDResponses ); } obdModule->mLogger.trace( "OBDOverCANModule::doWork", "Detect size of ECUs:" + std::to_string( canIDResponses.size() ) ); if ( !canIDResponses.empty() ) { + // If broadcast mode is enabled, open the broadcast socket: + if ( obdModule->mBroadcastRequests ) + { + obdModule->mBroadcastSocket = obdModule->openISOTPBroadcastSocket( isExtendedID ); + if ( obdModule->mBroadcastSocket < 0 ) + { + // Failure to open broadcast socket is non recoverable, hence we will send signal out to terminate + std::raise( SIGUSR1 ); + return; + } + } // Initialize ECU for each CAN ID in canIDResponse - if ( !obdModule->initECUs( canIDResponses ) ) + 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" ); + "Fatal Error. OBDOverCANECU failed to init. Check CAN ISO-TP module" ); std::raise( SIGUSR1 ); return; } @@ -168,7 +189,7 @@ OBDOverCANModule::doWork( void *data ) else { obdModule->mLogger.trace( "OBDOverCANModule::doWork", - " Waiting for :" + std::to_string( SLEEP_TIME_SECS ) + " seconds" ); + "Waiting for: " + std::to_string( SLEEP_TIME_SECS ) + " seconds" ); obdModule->mWait.wait( static_cast( SLEEP_TIME_SECS * 1000 ) ); } } @@ -190,12 +211,11 @@ OBDOverCANModule::doWork( void *data ) obdModule->mDecoderManifestAvailable.store( false, std::memory_order_relaxed ); } // Request PID if decoder dictionary is valid - if ( obdModule->mDecoderDictionaryPtr && !obdModule->mDecoderDictionaryPtr->empty() ) + if ( obdModule->mDecoderDictionaryPtr && ( !obdModule->mDecoderDictionaryPtr->empty() ) ) { // Is it time to request PIDs ? - // If so, send the requests then reschedule PID requests - if ( obdModule->mPIDRequestIntervalSeconds > 0 && - obdModule->mPIDTimer.getElapsedSeconds() >= obdModule->mPIDRequestIntervalSeconds ) + if ( ( obdModule->mPIDRequestIntervalSeconds > 0 ) && + ( obdModule->mPIDTimer.getElapsedSeconds() >= obdModule->mPIDRequestIntervalSeconds ) ) { // besides this thread, onChangeOfActiveDictionary can update mPIDsToRequestPerECU. // Use mutex to ensure only one thread is doing the update. @@ -203,14 +223,16 @@ OBDOverCANModule::doWork( void *data ) // This should execute only once if ( !hasAcquiredSupportedPIDs ) { - hasAcquiredSupportedPIDs = obdModule->assignPIDsToECUs(); + hasAcquiredSupportedPIDs = true; + obdModule->assignPIDsToECUs(); } + // Reschedule + obdModule->mPIDTimer.reset(); for ( auto ecu : obdModule->mECUs ) { - ecu->requestReceiveEmissionPIDs( SID::CURRENT_STATS ); + auto numRequests = ecu->requestReceiveEmissionPIDs( SID::CURRENT_STATS ); + obdModule->flush( numRequests, ecu ); } - // Reschedule - obdModule->mPIDTimer.reset(); } } // Request DTC if specified by inspection matrix @@ -218,14 +240,21 @@ OBDOverCANModule::doWork( void *data ) { bool successfulDTCRequest = false; DTCInfo dtcInfo; - dtcInfo.receiveTime = obdModule->mClock->timeSinceEpochMs(); - // Request then reschedule DTC requests stored DTCs from each ECU - if ( obdModule->mDTCRequestIntervalSeconds > 0 && - obdModule->mDTCTimer.getElapsedSeconds() >= obdModule->mDTCRequestIntervalSeconds ) + dtcInfo.receiveTime = obdModule->mClock->systemTimeSinceEpochMs(); + // Request stored DTCs from each ECU + if ( ( obdModule->mDTCRequestIntervalSeconds > 0 ) && + ( obdModule->mDTCTimer.getElapsedSeconds() >= obdModule->mDTCRequestIntervalSeconds ) ) { + // Reschedule + obdModule->mDTCTimer.reset(); for ( auto ecu : obdModule->mECUs ) { - successfulDTCRequest = ecu->getDTCData( dtcInfo ); + size_t numRequests = 0; + if ( ecu->getDTCData( dtcInfo, numRequests ) ) + { + successfulDTCRequest = true; + } + obdModule->flush( numRequests, ecu ); } // Also DTCInfo strutcs without any DTCs must be pushed to the queue because it means // there was a OBD request that did not return any SID::STORED_DTCs @@ -235,23 +264,69 @@ 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!" ); + obdModule->mLogger.warn( "OBDOverCANModule::doWork", "DTC Buffer full" ); } } - // Reschedule - obdModule->mDTCTimer.reset(); } } // Wait for the next cycle - uint32_t sleepTime = - obdModule->mDTCRequestIntervalSeconds > 0 - ? std::min( obdModule->mPIDRequestIntervalSeconds, obdModule->mDTCRequestIntervalSeconds ) - : obdModule->mPIDRequestIntervalSeconds; + int64_t sleepTime = INT64_MAX; + calcSleepTime( obdModule->mPIDRequestIntervalSeconds, obdModule->mPIDTimer, sleepTime ); + calcSleepTime( obdModule->mDTCRequestIntervalSeconds, obdModule->mDTCTimer, sleepTime ); + if ( sleepTime < 0 ) + { + obdModule->mLogger.warn( "OBDOverCANModule::doWork", + "Request time overdue by " + std::to_string( sleepTime ) + " ms" ); + } + else + { + obdModule->mLogger.trace( "OBDOverCANModule::doWork", + "Waiting for: " + std::to_string( sleepTime ) + " ms" ); + obdModule->mWait.wait( static_cast( sleepTime ) ); + } + } +} - obdModule->mLogger.trace( "OBDOverCANModule::doWork", - " Waiting for :" + std::to_string( sleepTime ) + " seconds" ); - obdModule->mWait.wait( static_cast( sleepTime * 1000 ) ); +void +OBDOverCANModule::calcSleepTime( uint32_t requestIntervalSeconds, const Timer &timer, int64_t &outputSleepTime ) +{ + if ( requestIntervalSeconds > 0 ) + { + auto sleepTime = ( static_cast( requestIntervalSeconds ) * 1000 ) - timer.getElapsedMs().count(); + if ( sleepTime < outputSleepTime ) + { + outputSleepTime = sleepTime; + } + } +} + +void +OBDOverCANModule::flush( size_t count, std::shared_ptr &exceptECU ) +{ + if ( !mBroadcastRequests ) + { + return; + } + uint32_t timeLeftMs = P2_TIMEOUT_DEFAULT_MS; + for ( auto ecu : mECUs ) + { + if ( ecu == exceptECU ) + { + continue; + } + for ( size_t i = 0; i < count; i++ ) + { + uint32_t timeNeededMs = ecu->flush( timeLeftMs ); + if ( timeNeededMs >= timeLeftMs ) + { + timeLeftMs = 0; + } + else + { + timeLeftMs -= timeNeededMs; + } + } } } @@ -264,18 +339,18 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI // After 1 second timeout and stop ECU detection constexpr uint32_t MAX_WAITING_MS = 1000; // Open a CAN raw socket - int mSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); - if ( mSocket < 0 ) + int rawSocket = socket( PF_CAN, SOCK_RAW, CAN_RAW ); + if ( rawSocket < 0 ) { - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to create socket!" ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to create socket" ); return false; } // Set the IF name strncpy( interfaceRequest.ifr_name, mGatewayCanInterfaceName.c_str(), sizeof( interfaceRequest.ifr_name ) - 1 ); - if ( ioctl( mSocket, SIOCGIFINDEX, &interfaceRequest ) != 0 ) + if ( ioctl( rawSocket, SIOCGIFINDEX, &interfaceRequest ) != 0 ) { - close( mSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "CAN interface is not accessible." ); + close( rawSocket ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "CAN interface is not accessible" ); return false; } @@ -283,25 +358,25 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI interfaceAddress.can_ifindex = interfaceRequest.ifr_ifindex; // Bind the socket - if ( bind( mSocket, reinterpret_cast( &interfaceAddress ), sizeof( interfaceAddress ) ) < 0 ) + if ( bind( rawSocket, reinterpret_cast( &interfaceAddress ), sizeof( interfaceAddress ) ) < 0 ) { - close( mSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to bind." ); + close( rawSocket ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to bind" ); return false; } // Set frame can_id and flags - frame.can_id = ( isExtendedID ) ? ( ( uint32_t )( ECUID::BROADCAST_EXTENDED_ID ) | CAN_EFF_FLAG ) - : (uint32_t)ECUID::BROADCAST_ID; - frame.can_dlc = 8; // CAN DLC - frame.data[0] = 02; // Single frame data length - frame.data[1] = 01; // Service ID 01: Show current data - frame.data[2] = 00; // PID 00: PIDs supported [01-20] + frame.can_id = + isExtendedID ? ( (uint32_t)ECUID::BROADCAST_EXTENDED_ID | CAN_EFF_FLAG ) : (uint32_t)ECUID::BROADCAST_ID; + frame.can_dlc = 8; // CAN DLC + frame.data[0] = 2; // Single frame data length + frame.data[1] = 1; // Service ID 01: Show current data + frame.data[2] = 0; // PID 00: PIDs supported [01-20] // Send broadcast request - if ( write( mSocket, &frame, sizeof( struct can_frame ) ) != sizeof( struct can_frame ) ) + if ( write( rawSocket, &frame, sizeof( struct can_frame ) ) != sizeof( struct can_frame ) ) { - close( mSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to write." ); + close( rawSocket ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to write" ); return false; } mLogger.trace( "OBDOverCANModule::autoDetectECUs", "Sent broadcast request" ); @@ -318,12 +393,12 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI ", time to stop ECUs' detection" ); break; } - struct pollfd pfd = { mSocket, POLLIN, 0 }; - int res = poll( &pfd, 1U, static_cast( OBDOverCANModule::P2_TIMEOUT_DEFAULT_MS ) ); + struct pollfd pfd = { rawSocket, POLLIN, 0 }; + int res = poll( &pfd, 1U, static_cast( P2_TIMEOUT_DEFAULT_MS ) ); if ( res < 0 ) { - close( mSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Poll error." ); + close( rawSocket ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Poll error" ); return false; } if ( res == 0 ) // Time out @@ -331,22 +406,22 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI break; } // Get response - if ( recv( mSocket, &frame, sizeof( struct can_frame ), 0 ) < 0 ) + if ( recv( rawSocket, &frame, sizeof( struct can_frame ), 0 ) < 0 ) { - close( mSocket ); - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to read response." ); + close( rawSocket ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to read response" ); return false; } // 11-bit range 7E8, 7E9, 7EA ... 7EF ==> [7E8, 7EF] // 29-bit range: [18DAF100, 18DAF1FF] - auto frameCANId = ( isExtendedID ) ? ( frame.can_id & CAN_EFF_MASK ) : frame.can_id; - auto smallestCANId = ( isExtendedID ) ? ( uint32_t )( ECUID::LOWEST_ECU_EXTENDED_RX_ID ) - : ( uint32_t )( ECUID::LOWEST_ECU_RX_ID ); - auto biggestCANId = ( isExtendedID ) ? ( uint32_t )( ECUID::HIGHEST_ECU_EXTENDED_RX_ID ) - : ( uint32_t )( ECUID::HIGHEST_ECU_RX_ID ); + auto frameCANId = isExtendedID ? ( frame.can_id & CAN_EFF_MASK ) : frame.can_id; + auto smallestCANId = + isExtendedID ? (uint32_t)ECUID::LOWEST_ECU_EXTENDED_RX_ID : (uint32_t)ECUID::LOWEST_ECU_RX_ID; + auto biggestCANId = + isExtendedID ? (uint32_t)ECUID::HIGHEST_ECU_EXTENDED_RX_ID : (uint32_t)ECUID::HIGHEST_ECU_RX_ID; // Check if CAN ID is valid - if ( smallestCANId <= frameCANId && frameCANId <= biggestCANId ) + if ( ( smallestCANId <= frameCANId ) && ( frameCANId <= biggestCANId ) ) { canIDResponses.push_back( frameCANId ); } @@ -360,16 +435,64 @@ OBDOverCANModule::autoDetectECUs( bool isExtendedID, std::vector &canI mLogger.trace( "OBDOverCANModule::autoDetectECUs", "ECU with rx_id: " + stream_rx.str() ); } // Close the socket - if ( close( mSocket ) < 0 ) + if ( close( rawSocket ) < 0 ) { - mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to close socket." ); + mLogger.error( "OBDOverCANModule::autoDetectECUs", "Failed to close socket" ); return false; } return true; } +int +OBDOverCANModule::openISOTPBroadcastSocket( bool isExtendedID ) +{ + // Socket CAN parameters + struct sockaddr_can interfaceAddress = {}; + struct can_isotp_options optionalFlags = {}; + + // Set the source + interfaceAddress.can_addr.tp.tx_id = + isExtendedID ? (uint32_t)ECUID::BROADCAST_EXTENDED_ID | CAN_EFF_FLAG : (uint32_t)ECUID::BROADCAST_ID; + // Set flags to stop flow control messages being used for this socket + optionalFlags.flags |= CAN_ISOTP_TX_PADDING | CAN_ISOTP_LISTEN_MODE | CAN_ISOTP_SF_BROADCAST; + + // Open a Socket + 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 ); + 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" ); + close( broadcastSocket ); + return -1; + } + // CAN PF and Interface Index + interfaceAddress.can_family = AF_CAN; + interfaceAddress.can_ifindex = static_cast( if_nametoindex( mGatewayCanInterfaceName.c_str() ) ); + + // Bind the socket + // 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 ); + close( broadcastSocket ); + return -1; + } + mLogger.trace( "ISOTPOverCANSenderReceiver::openISOTPBroadcastSocket", + "ISOTP Socket connected to IF: " + mGatewayCanInterfaceName ); + return broadcastSocket; +} + constexpr uint32_t -OBDOverCANModule::getTxIDByRxID( uint32_t rxId ) +OBDOverCANModule::getTxIDByRxID( bool isExtendedID, uint32_t rxId ) { // Calculate tx_id according to rx_id, operators are following: // If is 29-bit, e.g. rx_id = 0x18DAF159: @@ -378,63 +501,48 @@ OBDOverCANModule::getTxIDByRxID( uint32_t rxId ) // 0x5900 | 0x18DA00F1 = 0x18DA59F1 = tx_id // If is 11-bit, e.g. rx_id = 0x7E8: // rx_id - 0x8 = 0x7E0 = tx_id - uint32_t txId = ( rxId > ( uint32_t )( ECUID::HIGHEST_ECU_RX_ID ) ) - ? ( ( rxId & MASKING_GET_BYTE ) << MASKING_SHIFT_BITS ) | MASKING_TEMPLATE_TX_ID + return isExtendedID ? ( ( rxId & MASKING_GET_BYTE ) << MASKING_SHIFT_BITS ) | MASKING_TEMPLATE_TX_ID : rxId - MASKING_REMOVE_BYTE; - return txId; } bool -OBDOverCANModule::initECUs( std::vector &canIDResponses ) +OBDOverCANModule::initECUs( bool isExtendedID, std::vector &canIDResponses, int broadcastSocket ) { - bool initStatus = true; // create a set of CAN ID in case there's duplication auto canIDSet = std::set( canIDResponses.begin(), canIDResponses.end() ); - for ( auto canID : canIDSet ) + for ( auto rxID : canIDSet ) { - auto obdOverCANECU = std::make_shared(); - - // Send physical request: - auto rxID = canID; - auto txID = getTxIDByRxID( rxID ); - - // Check if CAN ID is 11-bit or 29-bit - bool isExtendedId = ( (uint32_t)canID > ( uint32_t )( ECUID::HIGHEST_ECU_RX_ID ) ) ? true : false; - if ( obdOverCANECU->init( - mGatewayCanInterfaceName, mOBDDataDecoder, rxID, txID, isExtendedId, mSignalBufferPtr ) ) - { - mECUs.push_back( obdOverCANECU ); - } - else + auto ecu = std::make_shared(); + if ( !ecu->init( mGatewayCanInterfaceName, + mOBDDataDecoder, + rxID, + getTxIDByRxID( isExtendedID, rxID ), + isExtendedID, + mSignalBufferPtr, + broadcastSocket ) ) { - initStatus = false; - mLogger.error( "OBDOverCANModule::initECUs", - "Failed to initialize OBDOverCANECU module for ECU " + std::to_string( rxID ) ); + return false; } + mECUs.push_back( ecu ); } mLogger.trace( "OBDOverCANModule::initialECUs", "Initialize ECUs in size of: " + std::to_string( mECUs.size() ) ); - return initStatus; + return true; } -bool +void OBDOverCANModule::assignPIDsToECUs() { - bool status = false; // clear the PID allocation table mPIDAssigned.clear(); for ( auto &ecu : mECUs ) { // Get supported PIDs. Edge agent will either request it from ECU or get it from the buffer - if ( ecu->requestReceiveSupportedPIDs( SID::CURRENT_STATS ) ) - { - // Allocate PID to each ECU to request. Note that if the PID has been already assigned, it will not be - // reassigned to another ECU - ecu->updatePIDRequestList( - SID::CURRENT_STATS, mPIDsRequestedByDecoderDict[SID::CURRENT_STATS], mPIDAssigned ); - status = true; - } + auto numRequests = ecu->requestReceiveSupportedPIDs( SID::CURRENT_STATS ); + flush( numRequests, ecu ); + // Allocate PID to each ECU to request. Note that if the PID has been already assigned, it will not be + // reassigned to another ECU + ecu->updatePIDRequestList( SID::CURRENT_STATS, mPIDsRequestedByDecoderDict[SID::CURRENT_STATS], mPIDAssigned ); } - return status; } bool @@ -452,7 +560,7 @@ OBDOverCANModule::disconnect() bool OBDOverCANModule::isAlive() { - if ( !mThread.isValid() || !mThread.isActive() ) + if ( ( !mThread.isValid() ) || ( !mThread.isActive() ) ) { return false; } @@ -539,12 +647,7 @@ OBDOverCANModule::onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &di // If the program already know the supported PIDs from ECU, below two update will update // For each ecu update the PIDs requested by the Dict - mPIDAssigned.clear(); - for ( auto &ecu : mECUs ) - { - ecu->updatePIDRequestList( - SID::CURRENT_STATS, mPIDsRequestedByDecoderDict[SID::CURRENT_STATS], mPIDAssigned ); - } + assignPIDsToECUs(); // Pass on the decoder manifest to the OBD Decoder and wake up the thread. // Before that we should interrupt the thread so that no further decoding diff --git a/src/datamanagement/datainspection/src/location/GeohashFunctionNode.cpp b/src/datamanagement/datainspection/src/location/GeohashFunctionNode.cpp index b904d052..ca263eff 100644 --- a/src/datamanagement/datainspection/src/location/GeohashFunctionNode.cpp +++ b/src/datamanagement/datainspection/src/location/GeohashFunctionNode.cpp @@ -33,7 +33,8 @@ GeohashFunctionNode::evaluateGeohash( double latitude, { // mLogger.info( "GeohashFunctionNode::evaluateGeohash", "Geohash calculated: " + currentGeohashString ); // First we want to make sure both geohash string has the valid format for comparison - if ( this->mGeohashInfo.mGeohashString.length() >= precision && currentGeohashString.length() >= precision ) + if ( ( this->mGeohashInfo.mGeohashString.length() >= precision ) && + ( currentGeohashString.length() >= precision ) ) { // We compare the front part of string at given precision if ( currentGeohashString.substr( 0, precision ) != diff --git a/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp b/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp index b67cb395..c97b4b9a 100644 --- a/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp +++ b/src/datamanagement/datainspection/src/vehicledatasource/CANDataConsumer.cpp @@ -5,7 +5,6 @@ #include "CANDataConsumer.h" #include "TraceModule.h" #include -#include #include #include @@ -32,7 +31,7 @@ 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 " ); + mLogger.trace( "CANDataConsumer::init", "Init Failed due to bufferPtr as nullptr" ); return false; } else @@ -54,7 +53,7 @@ CANDataConsumer::suspendDataConsumption() { // Go back to sleep mLogger.trace( "CANDataConsumer::suspendDataConsumption", - "Going to sleep until a the resume signal. Consumer : " + std::to_string( mDataSourceID ) ); + "Going to sleep until a the resume signal. Consumer: " + std::to_string( mDataSourceID ) ); mShouldSleep.store( true, std::memory_order_relaxed ); } @@ -91,7 +90,7 @@ CANDataConsumer::resumeDataConsumption( ConstDecoderDictionaryConstPtr &dictiona } } mLogger.trace( "CANDataConsumer::resumeDataConsumption", - " Changing Decoder Dictionary on Consumer :" + std::to_string( mID ) + + "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 ); @@ -101,7 +100,7 @@ CANDataConsumer::resumeDataConsumption( ConstDecoderDictionaryConstPtr &dictiona else { mLogger.error( "CANDataConsumer::resumeDataConsumption", - " Received invalid decoder dictionary :" + std::to_string( mID ) ); + "Received invalid decoder dictionary: " + std::to_string( mID ) ); } } } @@ -119,11 +118,11 @@ CANDataConsumer::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CANDataConsumer::start", " Consumer Thread failed to start " ); + mLogger.trace( "CANDataConsumer::start", "Thread failed to start" ); } else { - mLogger.trace( "CANDataConsumer::start", " Consumer Thread started " ); + mLogger.trace( "CANDataConsumer::start", "Thread started" ); mThread.setThreadName( "fwDIConsumer" + std::to_string( mID ) ); } @@ -138,7 +137,7 @@ CANDataConsumer::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CANDataConsumer::stop", " Consumer Thread stopped " ); + mLogger.trace( "CANDataConsumer::stop", "Thread stopped" ); return !mThread.isActive(); } @@ -196,6 +195,12 @@ CANDataConsumer::doWork( void *data ) std::array, 8> lastFrameIds{}; // .first=can id, .second=counter uint8_t lastFrameIdPos = 0; uint32_t processedFramesCounter = 0; + + TraceSection traceSection = + ( ( consumer->mDataSourceID + toUType( TraceSection::CAN_DECODER_CYCLE_0 ) < + toUType( TraceSection::CAN_DECODER_CYCLE_MAX ) ) + ? static_cast( consumer->mDataSourceID + toUType( TraceSection::CAN_DECODER_CYCLE_0 ) ) + : TraceSection::CAN_DECODER_CYCLE_MAX ); do { activations++; @@ -204,11 +209,12 @@ 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 " ); + "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 // woken up. + TraceModule::get().sectionBegin( traceSection ); } // Below section utilize decoder dictionary to perform CAN message decoding and collection. // Use a Mutex to prevent updating decoder dictionary in the middle of CAN Frame processing. @@ -267,9 +273,9 @@ CANDataConsumer::doWork( void *data ) const auto &collectType = currentMessageDecoderMethod.collectType; // Only used for TRACE log level logging - if ( collectType == CANMessageCollectType::RAW || - collectType == CANMessageCollectType::RAW_AND_DECODE || - collectType == CANMessageCollectType::DECODE ) + if ( ( collectType == CANMessageCollectType::RAW ) || + ( collectType == CANMessageCollectType::RAW_AND_DECODE ) || + ( collectType == CANMessageCollectType::DECODE ) ) { bool found = false; for ( auto &p : lastFrameIds ) @@ -294,9 +300,9 @@ CANDataConsumer::doWork( void *data ) } // Check if we want to collect RAW CAN Frame; If so we also need to ensure Buffer is valid - if ( consumer->mCANBufferPtr.get() != nullptr && - ( collectType == CANMessageCollectType::RAW || - collectType == CANMessageCollectType::RAW_AND_DECODE ) ) + if ( ( consumer->mCANBufferPtr.get() != nullptr ) && + ( ( collectType == CANMessageCollectType::RAW ) || + ( collectType == CANMessageCollectType::RAW_AND_DECODE ) ) ) { // prepare the raw CAN Frame struct CollectedCanRawFrame canRawFrame; @@ -317,7 +323,7 @@ CANDataConsumer::doWork( void *data ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_CAN ); - consumer->mLogger.warn( "CANDataConsumer::doWork", "RAW CAN Frame Buffer Full! " ); + consumer->mLogger.warn( "CANDataConsumer::doWork", "RAW CAN Frame Buffer Full" ); } else { @@ -329,9 +335,9 @@ CANDataConsumer::doWork( void *data ) } } // check if we want to decode can frame into signals and collect signals - if ( consumer->mSignalBufferPtr.get() != nullptr && - ( collectType == CANMessageCollectType::DECODE || - collectType == CANMessageCollectType::RAW_AND_DECODE ) ) + if ( ( consumer->mSignalBufferPtr.get() != nullptr ) && + ( ( collectType == CANMessageCollectType::DECODE ) || + ( collectType == CANMessageCollectType::RAW_AND_DECODE ) ) ) { if ( format.isValid() ) { @@ -353,7 +359,7 @@ CANDataConsumer::doWork( void *data ) { TraceModule::get().decrementAtomicVariable( TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS ); - consumer->mLogger.warn( "CANDataConsumer::doWork", "Signal Buffer Full! " ); + consumer->mLogger.warn( "CANDataConsumer::doWork", "Signal Buffer Full" ); } else { @@ -369,7 +375,7 @@ CANDataConsumer::doWork( void *data ) { // The decoding was not fully successful consumer->mLogger.warn( "CANDataConsumer::doWork", - "CAN Frame " + std::to_string( messageId ) + " decoding failed! " ); + "CAN Frame " + std::to_string( messageId ) + " decoding failed" ); } } else @@ -404,7 +410,9 @@ CANDataConsumer::doWork( void *data ) activations = 0; logTimer.reset(); } + TraceModule::get().sectionEnd( traceSection ); consumer->mWait.wait( consumer->mIdleTime ); + TraceModule::get().sectionBegin( traceSection ); } } while ( !consumer->shouldStop() ); } @@ -412,8 +420,8 @@ CANDataConsumer::doWork( void *data ) bool CANDataConsumer::connect() { - if ( mInputBufferPtr.get() != nullptr && mSignalBufferPtr.get() != nullptr && mCANBufferPtr.get() != nullptr && - start() ) + if ( ( mInputBufferPtr.get() != nullptr ) && ( mSignalBufferPtr.get() != nullptr ) && + ( mCANBufferPtr.get() != nullptr ) && start() ) { return true; } diff --git a/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp b/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp index a490e6c8..44028e85 100644 --- a/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp +++ b/src/datamanagement/datainspection/src/vehicledatasource/VehicleDataSourceBinder.cpp @@ -27,7 +27,7 @@ bool VehicleDataSourceBinder::addVehicleDataSource( VehicleDataSourcePtr source ) { // Check if the data source is valid - if ( source.get() == nullptr || source->getVehicleDataSourceID() == INVALID_DATA_SOURCE_ID ) + if ( ( source.get() == nullptr ) || ( source->getVehicleDataSourceID() == INVALID_DATA_SOURCE_ID ) ) { mLogger.error( "VehicleDataSourceBinder::attachVehicleDataSource", "Invalid vehicle data source" ); return false; @@ -56,7 +56,7 @@ VehicleDataSourceBinder::addVehicleDataSource( VehicleDataSourcePtr source ) else { mLogger.error( "VehicleDataSourceBinder::attachVehicleDataSource", - "Could not connect the vehicle data source with ID: " + + "Could not connect the vehicle data source with ID: " + std::to_string( source->getVehicleDataSourceID() ) ); return false; } @@ -79,7 +79,7 @@ VehicleDataSourceBinder::removeVehicleDataSource( const VehicleDataSourceID &id if ( sourceIterator == mIdsToDataSources.end() ) { mLogger.error( "VehicleDataSourceBinder::removeVehicleDataSource", - "Attempting to remove a vehicle data source that was not added." ); + "Attempting to remove a vehicle data source that was not added" ); return false; } backupSource = sourceIterator->second; @@ -111,10 +111,10 @@ VehicleDataSourceBinder::bindConsumerToVehicleDataSource( VehicleDataConsumerPtr const VehicleDataSourceID &id ) { // Check if the channelID and the consumer are valid - if ( consumer.get() == nullptr || id == INVALID_DATA_SOURCE_ID ) + if ( ( consumer.get() == nullptr ) || ( id == INVALID_DATA_SOURCE_ID ) ) { mLogger.error( "VehicleDataSourceBinder::bindConsumerToVehicleDataSource", - "Invalid consumer instance or data source" ); + "Invalid consumer instance or data source" ); return false; } // First lookup the data source and check if it's registered @@ -151,7 +151,7 @@ VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource( const VehicleDataS if ( id == INVALID_DATA_SOURCE_ID ) { mLogger.error( "VehicleDataSourceBinder::unBindConsumerFromVehicleDataSource", - "Invalid consumer instance or data source" ); + "Invalid consumer instance or data source" ); return false; } @@ -226,7 +226,7 @@ VehicleDataSourceBinder::reConnectConsumer( const VehicleDataSourceID &id ) backupConsumer = consumerIterator->second; } // reConnect the consumer. Make sure that the consumer is not alive already - if ( backupConsumer != nullptr && !backupConsumer->isAlive() ) + if ( ( backupConsumer != nullptr ) && ( !backupConsumer->isAlive() ) ) { return backupConsumer->connect(); } @@ -246,11 +246,11 @@ VehicleDataSourceBinder::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "VehicleDataSourceBinder::start", " Binder Thread failed to start " ); + mLogger.trace( "VehicleDataSourceBinder::start", "Binder Thread failed to start" ); } else { - mLogger.trace( "VehicleDataSourceBinder::start", " Binder Thread started " ); + mLogger.trace( "VehicleDataSourceBinder::start", "Binder Thread started" ); mThread.setThreadName( "fwDIBinder" ); } @@ -297,7 +297,7 @@ VehicleDataSourceBinder::doWork( void *data ) 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 ) ); + "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 @@ -320,7 +320,7 @@ VehicleDataSourceBinder::doWork( void *data ) if ( binder->reConnectConsumer( sourceID.first ) ) { binder->mLogger.trace( "VehicleDataSourceBinder::doWork", - "Reconnected Source ID : " + std::to_string( sourceID.first ) ); + "Reconnected Source ID: " + std::to_string( sourceID.first ) ); } } else if ( sourceID.second == VehicleDataSourceState::DISCONNECTED ) @@ -329,7 +329,7 @@ VehicleDataSourceBinder::doWork( void *data ) if ( binder->disconnectConsumer( sourceID.first ) ) { binder->mLogger.trace( "VehicleDataSourceBinder::doWork", - "Disconnected Source ID : " + std::to_string( sourceID.first ) ); + "Disconnected Source ID: " + std::to_string( sourceID.first ) ); } } } @@ -406,7 +406,7 @@ VehicleDataSourceBinder::disconnect() } else { - mLogger.trace( "VehicleDataSourceBinder::disconnect", " Consumer disconnected" ); + mLogger.trace( "VehicleDataSourceBinder::disconnect", "Consumer disconnected" ); } } } @@ -423,13 +423,13 @@ VehicleDataSourceBinder::disconnect() if ( !source.second->disconnect() ) { mLogger.error( "VehicleDataSourceBinder::disconnect", - "Failed to disconnect Data source ID : " + std::to_string( source.first ) ); + "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" ); + "Data source ID: " + std::to_string( source.first ) + " disconnected" ); } } } @@ -446,7 +446,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 " ); + mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", "Decoder Manifest received" ); // Start with the consumers, make sure that wake up first so that they pick up // the data for decoding immediately @@ -465,7 +465,7 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst { consumer.second->resumeDataConsumption( dictionary ); mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Resuming Consumption on Consumer :" + + "Resuming Consumption on Consumer: " + std::to_string( consumer.second->getConsumerID() ) ); } } ); @@ -477,7 +477,7 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst { source.second->resumeDataAcquisition(); mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Resuming Consumption on Data source : " + + "Resuming Consumption on Data source: " + std::to_string( source.second->getVehicleDataSourceID() ) ); } } ); @@ -492,7 +492,7 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst { consumer.second->suspendDataConsumption(); mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Interrupting Consumption on Consumer :" + + "Interrupting Consumption on Consumer: " + std::to_string( consumer.second->getConsumerID() ) ); } } ); @@ -504,7 +504,7 @@ VehicleDataSourceBinder::onChangeOfActiveDictionary( ConstDecoderDictionaryConst { source.second->suspendDataAcquisition(); mLogger.trace( "VehicleDataSourceBinder::onChangeOfActiveDictionary", - "Interrupting Consumption on Data source : " + + "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 6b1bddee..2b1f2628 100644 --- a/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp +++ b/src/datamanagement/datainspection/test/CollectionInspectionEngineTest.cpp @@ -2,12 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionInspectionEngine.h" +#include "Testing.h" #include #include #include using namespace Aws::IoTFleetWise::DataInspection; using namespace Aws::IoTFleetWise::DataManagement; +using namespace Aws::IoTFleetWise::TestingSupport; class CollectionInspectionEngineTest : public ::testing::Test { @@ -363,7 +365,7 @@ TEST_F( CollectionInspectionEngineTest, EndlessCondition ) collectionSchemes->conditions[0].condition = &endless; engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -384,8 +386,8 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBuffer ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); // All signal come at the same timestamp 160000000 + 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 ); @@ -414,11 +416,11 @@ TEST_F( CollectionInspectionEngineTest, TooBigForSignalBufferOverflow ) c1.minimumSampleIntervalMs = 0; collectionSchemes->conditions[0].canFrames.push_back( c1 ); - collectionSchemes->conditions[0].minimumPublishInterval = 500; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 500; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -445,7 +447,7 @@ TEST_F( CollectionInspectionEngineTest, SignalBufferErasedAfterNewConditions ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -480,7 +482,7 @@ TEST_F( CollectionInspectionEngineTest, CollectBurstWithoutSubsampling ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -533,11 +535,11 @@ TEST_F( CollectionInspectionEngineTest, ZeroSignalsOnlyDTCCollection ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; DTCInfo dtcInfo; dtcInfo.mDTCCodes.push_back( "B1217" ); dtcInfo.mSID = SID::STORED_DTC; - dtcInfo.receiveTime = timestamp; + dtcInfo.receiveTime = timestamp.systemTimeMs; engine.setActiveDTCs( dtcInfo ); timestamp += 1000; engine.evaluateConditions( timestamp ); @@ -561,7 +563,7 @@ TEST_F( CollectionInspectionEngineTest, CollectRawCanFrames ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; std::array buf = { 0xDE, 0xAD, 0xBE, 0xEF, 0x0, 0x0, 0x0, 0x0 }; engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp, buf, sizeof( buf ) ); @@ -592,7 +594,7 @@ TEST_F( CollectionInspectionEngineTest, CollectRawCanFDFrames ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; std::array buf = { 0xDE, 0xAD, 0xBE, 0xEF, 0x0, 0x0, 0x0, 0x0, 0xDE, 0xAD, 0xBE, 0xEF, 0x0, 0x0, 0x0, 0x0 }; engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp, buf, sizeof( buf ) ); @@ -635,17 +637,23 @@ TEST_F( CollectionInspectionEngineTest, MultipleCanSubsampling ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; std::array buf = { 0xDE, 0xAD, 0xBE, 0xEF, 0x0, 0x0, 0x0, 0x0 }; - engine.addNewRawCanFrame( - c1.frameID, c1.channelID, timestamp, buf, sizeof( buf ) ); // this message in goes with both subsampling + engine.addNewRawCanFrame( c1.frameID, + c1.channelID, + timestamp, + buf, + sizeof( buf ) ); // this message in goes with both subsampling engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp + 100, buf, sizeof( buf ) ); // 100 ms subsampling engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp + 200, buf, sizeof( buf ) ); // 100 ms subsampling engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp + 250, buf, sizeof( buf ) ); // ignored engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp + 300, buf, sizeof( buf ) ); // 100 ms subsampling engine.addNewRawCanFrame( c1.frameID, c1.channelID, timestamp + 400, buf, sizeof( buf ) ); // 100 ms subsampling - engine.addNewRawCanFrame( - c1.frameID, c1.channelID, timestamp + 500, buf, sizeof( buf ) ); // this message in goes with both subsampling + engine.addNewRawCanFrame( c1.frameID, + c1.channelID, + timestamp + 500, + buf, + sizeof( buf ) ); // this message in goes with both subsampling engine.evaluateConditions( timestamp ); @@ -679,7 +687,7 @@ TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInCon addSignalToCollect( collectionSchemes->conditions[0], s5 ); collectionSchemes->conditions[0].condition = getTwoSignalsBiggerCondition( s1.signalID, 150.0, s3.signalID, 155.0 ).get(); - collectionSchemes->conditions[0].minimumPublishInterval = 10000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; InspectionMatrixSignalCollectionInfo s2{}; s2.signalID = s1.signalID; @@ -702,11 +710,11 @@ TEST_F( CollectionInspectionEngineTest, MultipleSubsamplingOfSameSignalUsedInCon addSignalToCollect( collectionSchemes->conditions[1], s6 ); collectionSchemes->conditions[1].condition = getTwoSignalsBiggerCondition( s2.signalID, 165.0, s4.signalID, 170.0 ).get(); - collectionSchemes->conditions[1].minimumPublishInterval = 10000; + collectionSchemes->conditions[1].minimumPublishIntervalMs = 10000; engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; for ( int i = 0; i < 100; i++ ) { @@ -764,7 +772,7 @@ TEST_F( CollectionInspectionEngineTest, MultipleFixedWindowsOfSameSignalUsedInCo s5.fixedWindowPeriod = 0; addSignalToCollect( collectionSchemes->conditions[0], s5 ); collectionSchemes->conditions[0].condition = getLastAvgWindowBiggerCondition( s1.signalID, 150.0 ).get(); - collectionSchemes->conditions[0].minimumPublishInterval = 10000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; InspectionMatrixSignalCollectionInfo s2{}; s2.signalID = s1.signalID; @@ -780,11 +788,11 @@ TEST_F( CollectionInspectionEngineTest, MultipleFixedWindowsOfSameSignalUsedInCo s6.fixedWindowPeriod = 250; addSignalToCollect( collectionSchemes->conditions[1], s6 ); collectionSchemes->conditions[1].condition = getLastAvgWindowBiggerCondition( s2.signalID, 150.0 ).get(); - collectionSchemes->conditions[1].minimumPublishInterval = 10000; + collectionSchemes->conditions[1].minimumPublishIntervalMs = 10000; engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; for ( int i = 0; i < 300; i++ ) { @@ -837,7 +845,7 @@ TEST_F( CollectionInspectionEngineTest, Subsampling ) collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -870,12 +878,12 @@ TEST_F( CollectionInspectionEngineTest, SendoutEverySignalOnlyOnce ) addSignalToCollect( collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishInterval = 10000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -908,12 +916,12 @@ TEST_F( CollectionInspectionEngineTest, HearbeatInterval ) addSignalToCollect( collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishInterval = 10000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -968,7 +976,7 @@ TEST_F( CollectionInspectionEngineTest, TwoCollectionSchemesWithDifferentNumberO engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; for ( int i = 0; i < 10000; i++ ) { timestamp++; @@ -1021,7 +1029,7 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle getTwoSignalsBiggerCondition( s1.signalID, -100.0, s2.signalID, -500.0 ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -1052,7 +1060,7 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsInConditionAndOneSignalToColle 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 ); + ASSERT_EQ( collectedData->triggerTime, timestamp.systemTimeMs ); } // Default is to send data only out once per collectionScheme @@ -1067,12 +1075,12 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalOnlyOncePerCollectionS addSignalToCollect( collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishInterval = 5000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 5000; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -1105,12 +1113,12 @@ TEST_F( CollectionInspectionEngineTest, SendOutEverySignalNotOnlyOncePerCollecti addSignalToCollect( collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishInterval = 5000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 5000; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); uint32_t waitTimeMs = 0; @@ -1149,7 +1157,7 @@ TEST_F( CollectionInspectionEngineTest, MoreCollectionSchemesThanSupported ) } engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; uint32_t waitTimeMs = 0; engine.addNewSignal( s1.signalID, timestamp, 0.1 ); engine.evaluateConditions( timestamp ); @@ -1196,7 +1204,7 @@ TEST_F( CollectionInspectionEngineTest, GeohashFunctionNodeTrigger ) collectionSchemes->conditions[0].condition = getGeohashFunctionCondition( lat.signalID, lon.signalID, 5 ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; // Before GPS signal is ready, we ask Inspection Engine to evaluate Geohash ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); uint32_t waitTimeMs = 0; @@ -1283,7 +1291,7 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) collectionSchemes->conditions[0].afterDuration = 2000; engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -1294,7 +1302,7 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) EXPECT_GE( waitTimeMs, 2000 ); timestamp += 1000; - Timestamp timestamp0 = timestamp; + TimePoint timestamp0 = timestamp; engine.addNewSignal( s3.signalID, timestamp, 2000.0 ); engine.addNewSignal( s1.signalID, timestamp, -90.0 ); engine.addNewSignal( s2.signalID, timestamp, -480.0 ); @@ -1304,7 +1312,7 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) EXPECT_EQ( waitTimeMs, 2000 ); timestamp += 1000; - Timestamp timestamp1 = timestamp; + TimePoint timestamp1 = timestamp; engine.addNewSignal( s3.signalID, timestamp, 3000.0 ); engine.addNewSignal( s1.signalID, timestamp, -95.0 ); engine.addNewSignal( s2.signalID, timestamp, -485.0 ); @@ -1314,7 +1322,7 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) EXPECT_EQ( waitTimeMs, 1000 ); timestamp += 500; - Timestamp timestamp2 = timestamp; + TimePoint timestamp2 = timestamp; engine.addNewSignal( s3.signalID, timestamp, 4000.0 ); engine.addNewSignal( s1.signalID, timestamp, -9000.0 ); engine.addNewSignal( s2.signalID, timestamp, -9000.0 ); @@ -1323,7 +1331,7 @@ TEST_F( CollectionInspectionEngineTest, CollectWithAfterTime ) ASSERT_EQ( engine.collectNextDataToSend( timestamp, waitTimeMs ), nullptr ); timestamp += 500; - Timestamp timestamp3 = timestamp; + TimePoint timestamp3 = timestamp; engine.addNewSignal( s3.signalID, timestamp, 5000.0 ); engine.addNewSignal( s1.signalID, timestamp, -9100.0 ); engine.addNewSignal( s2.signalID, timestamp, -9100.0 ); @@ -1335,12 +1343,12 @@ 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_EQ( collectedData->signals[0].receiveTime, timestamp3 ); + ASSERT_EQ( collectedData->signals[0].receiveTime, timestamp3.systemTimeMs ); ASSERT_EQ( collectedData->signals[1].value, 4000.0 ); - ASSERT_EQ( collectedData->signals[1].receiveTime, timestamp2 ); + ASSERT_EQ( collectedData->signals[1].receiveTime, timestamp2.systemTimeMs ); ASSERT_EQ( collectedData->signals[2].value, 3000.0 ); - ASSERT_EQ( collectedData->signals[2].receiveTime, timestamp1 ); - ASSERT_EQ( collectedData->triggerTime, timestamp0 ); + ASSERT_EQ( collectedData->signals[2].receiveTime, timestamp1.systemTimeMs ); + ASSERT_EQ( collectedData->triggerTime, timestamp0.systemTimeMs ); } TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) @@ -1355,7 +1363,7 @@ TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) addSignalToCollect( collectionSchemes->conditions[0], s1 ); // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishInterval = 10000; + collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); // Set probability to send to 50% @@ -1363,7 +1371,7 @@ TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; uint32_t waitTimeMs = 0; const uint32_t NR_OF_HEARTBEAT_INTERVALS = 1000; @@ -1378,7 +1386,7 @@ TEST_F( CollectionInspectionEngineTest, ProbabilityToSendTest ) numberOfDataToSend++; } // Increase time stamp by heartbeat interval to trigger new message - timestamp += collectionSchemes->conditions[0].minimumPublishInterval; + timestamp += collectionSchemes->conditions[0].minimumPublishIntervalMs; } // Probability to get less than 50 or more than NR_OF_HEARTBEAT_INTERVALS-50 is small if @@ -1406,7 +1414,7 @@ TEST_F( CollectionInspectionEngineTest, AvgWindowCondition ) collectionSchemes->conditions[0].condition = getLastAvgWindowBiggerCondition( s1.signalID, -50.0 ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; double currentValue = -110.0f; double increasePerSample = ( 100.0 ) / static_cast( s1.fixedWindowPeriod ); uint32_t waitTimeMs = 0; @@ -1451,7 +1459,7 @@ TEST_F( CollectionInspectionEngineTest, PrevLastAvgWindowCondition ) collectionSchemes->conditions[0].condition = getPrevLastAvgWindowBiggerCondition( s1.signalID, -50.0 ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; uint32_t waitTimeMs = 0; // Fill the prev last window with 0.0 for ( uint32_t i = 0; i < s1.fixedWindowPeriod; i++ ) @@ -1487,7 +1495,7 @@ TEST_F( CollectionInspectionEngineTest, MultiWindowCondition ) collectionSchemes->conditions[0].condition = getMultiFixedWindowCondition( s1.signalID ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = 16000000; + 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 ); @@ -1523,7 +1531,7 @@ TEST_F( CollectionInspectionEngineTest, TestNotEqualOperator ) collectionSchemes->conditions[0].condition = getNotEqualCondition( s1.signalID, s2.signalID ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -1565,7 +1573,7 @@ TEST_F( CollectionInspectionEngineTest, TwoSignalsRatioCondition ) getTwoSignalsRatioCondition( s1.signalID, 0.001, s2.signalID, 0.5 ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + 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 ); @@ -1606,7 +1614,7 @@ TEST_F( CollectionInspectionEngineTest, UnknownExpressionNode ) collectionSchemes->conditions[0].condition = getUnknownCondition( s1.signalID ).get(); engine.onChangeInspectionMatrix( consCollectionSchemes ); - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; // Expression should be false: (1.0 <= Unknown) engine.addNewSignal( s1.signalID, timestamp, 1.0 ); engine.evaluateConditions( timestamp ); @@ -1720,8 +1728,8 @@ TEST_F( CollectionInspectionEngineTest, RandomDataTest ) const int TIME_TO_SIMULATE_IN_MS = 5000; const int SIGNALS_PER_MS = 20; - uint32_t const START_TIMESTAMP = 1600000; - uint32_t timestamp = START_TIMESTAMP; + TimePoint START_TIMESTAMP = { 160000000, 100 }; + TimePoint timestamp = START_TIMESTAMP; uint32_t counter = 0; uint32_t dataCollected = 0; @@ -1762,7 +1770,7 @@ TEST_F( CollectionInspectionEngineTest, RandomDataTest ) TEST_F( CollectionInspectionEngineTest, NoCollectionSchemes ) { CollectionInspectionEngine engine; - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; engine.onChangeInspectionMatrix( consCollectionSchemes ); ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); } diff --git a/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp b/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp index 0aaedadf..62da5af0 100644 --- a/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp +++ b/src/datamanagement/datainspection/test/CollectionInspectionWorkerThreadTest.cpp @@ -111,7 +111,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectBurstWithoutSubsampling ) collectionSchemes->conditions[0].signals.push_back( s1 ); collectionSchemes->conditions[0].condition = getSignalsBiggerCondition( s1.signalID, 1 ).get(); worker.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = fClock->timeSinceEpochMs(); + Timestamp timestamp = fClock->systemTimeSinceEpochMs(); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.1 ) ); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 0.2 ) ); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1.5 ) ); @@ -171,7 +171,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectionQueueFull ) collectionSchemes->conditions[3].signals.push_back( s1 ); collectionSchemes->conditions[3].condition = getAlwaysTrueCondition().get(); worker.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = fClock->timeSinceEpochMs(); + Timestamp timestamp = fClock->systemTimeSinceEpochMs(); signalBufferPtr->push( CollectedSignal( s1.signalID, timestamp, 1 ) ); worker.onNewDataAvailable(); std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); @@ -200,7 +200,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeDataWithoutNotify ) collectionSchemes->conditions[0].signals.push_back( s1 ); collectionSchemes->conditions[0].condition = getSignalsBiggerCondition( s1.signalID, 1 ).get(); worker.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = fClock->timeSinceEpochMs(); + Timestamp timestamp = fClock->systemTimeSinceEpochMs(); std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); @@ -244,7 +244,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH dtcInfo.mDTCCodes.emplace_back( "P0143" ); dtcInfo.mDTCCodes.emplace_back( "C0196" ); dtcInfo.mSID = SID::STORED_DTC; - dtcInfo.receiveTime = fClock->timeSinceEpochMs(); + dtcInfo.receiveTime = fClock->systemTimeSinceEpochMs(); ASSERT_TRUE( dtcInfo.hasItems() ); // Push the DTCs to the buffer ASSERT_TRUE( activeDTCBufferPtr->push( dtcInfo ) ); @@ -260,7 +260,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH // Make sure that DTCs should be collected collectionSchemes->conditions[0].includeActiveDtcs = true; inspectionWorker.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = fClock->timeSinceEpochMs(); + Timestamp timestamp = fClock->systemTimeSinceEpochMs(); std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); // Push the signals so that the condition is met @@ -283,10 +283,10 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH dtcInfo.mDTCCodes.emplace_back( "B0148" ); dtcInfo.mDTCCodes.emplace_back( "U0148" ); dtcInfo.mSID = SID::STORED_DTC; - dtcInfo.receiveTime = fClock->timeSinceEpochMs(); + dtcInfo.receiveTime = fClock->systemTimeSinceEpochMs(); // Push the DTCs to the buffer ASSERT_TRUE( activeDTCBufferPtr->push( dtcInfo ) ); - timestamp = fClock->timeSinceEpochMs(); + 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 ) ); @@ -318,7 +318,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH dtcInfo.mDTCCodes.emplace_back( "P0143" ); dtcInfo.mDTCCodes.emplace_back( "C0196" ); dtcInfo.mSID = SID::STORED_DTC; - dtcInfo.receiveTime = fClock->timeSinceEpochMs(); + dtcInfo.receiveTime = fClock->systemTimeSinceEpochMs(); ASSERT_TRUE( dtcInfo.hasItems() ); // Push the DTCs to the buffer ASSERT_TRUE( activeDTCBufferPtr->push( dtcInfo ) ); @@ -334,7 +334,7 @@ TEST_F( CollectionInspectionWorkerThreadTest, ConsumeActiveDTCsCollectionSchemeH // Make sure that DTCs should NOT be collected collectionSchemes->conditions[0].includeActiveDtcs = false; inspectionWorker.onChangeInspectionMatrix( consCollectionSchemes ); - Timestamp timestamp = fClock->timeSinceEpochMs(); + Timestamp timestamp = fClock->systemTimeSinceEpochMs(); std::this_thread::sleep_for( std::chrono::milliseconds( 50 ) ); // Push the signals so that the condition is met diff --git a/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp b/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp index dbe6c70f..ef2942f8 100644 --- a/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp +++ b/src/datamanagement/datainspection/test/DataOverDDSModuleTest.cpp @@ -4,6 +4,7 @@ #include "DataOverDDSModule.h" #include "CollectionInspectionEngine.h" +#include "Testing.h" #include "dds/CameraDataPublisher.h" #include "dds/CameraDataSubscriber.h" #include "dds/DDSDataTypes.h" @@ -15,6 +16,8 @@ #include using namespace Aws::IoTFleetWise::DataInspection; +using namespace Aws::IoTFleetWise::TestingSupport; + class TestDDSModule : public DataOverDDSModule { @@ -595,7 +598,7 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleReceiveNotificationFromInspectionE matrixCollectInfo.isConditionOnlySignal = true; condition.signals.push_back( matrixCollectInfo ); condition.afterDuration = 3; - condition.minimumPublishInterval = 0; + condition.minimumPublishIntervalMs = 0; condition.includeImageCapture = true; // Create the Image data capture setting with 1 device InspectionMatrixImageCollectionInfo imageCollectionInfoItem = { @@ -618,7 +621,7 @@ TEST( DataOverDDSModuleTest, DataOverDDSModuleReceiveNotificationFromInspectionE // Set the matrix engine.onChangeInspectionMatrix( std::make_shared( matrix ) ); // Start the inspection - uint64_t timestamp = 160000000; + TimePoint timestamp = { 160000000, 100 }; uint32_t waitTimeMs = 0; ASSERT_TRUE( engine.evaluateConditions( timestamp ) ); // Wait for the afterDuration before checking diff --git a/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp b/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp index cf2848e9..45060e7d 100644 --- a/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp +++ b/src/datamanagement/datainspection/test/OBDOverCANModuleTest.cpp @@ -2,18 +2,17 @@ // SPDX-License-Identifier: Apache-2.0 #include "OBDOverCANModule.h" -#include "EnumUtility.h" #include "OBDDataTypes.h" #include "businterfaces/ISOTPOverCANReceiver.h" #include "datatypes/OBDDataTypesUnitTestOnly.h" #include -#include -#include -#include - #include #include +#include +#include +#include #include +#include using namespace Aws::IoTFleetWise::DataInspection; @@ -63,7 +62,7 @@ initInspectionMatrix( OBDOverCANModule &module ) matrixCollectInfo.isConditionOnlySignal = true; condition.signals.push_back( matrixCollectInfo ); condition.afterDuration = 3; - condition.minimumPublishInterval = 0; + condition.minimumPublishIntervalMs = 0; condition.probabilityToSend = 1.0; condition.includeActiveDtcs = true; condition.triggerOnlyOnRisingEdge = false; @@ -116,8 +115,30 @@ initDecoderDictionary() struct ECUMock { - ISOTPOverCANSenderReceiver mECU; - uint32_t mSourceCANId; + void + init( ECUID broadcastRxId, ECU_ID_MOCK physicalRxId, ECU_ID_MOCK physicalTxId ) + { + ISOTPOverCANReceiverOptions broadcastOptions; + // Broadcast + broadcastOptions.mSocketCanIFName = "vcan0"; + broadcastOptions.mSourceCANId = (unsigned)ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED; + broadcastOptions.mIsExtendedId = (unsigned)broadcastRxId > CAN_SFF_MASK; + broadcastOptions.mDestinationCANId = (unsigned)broadcastRxId; + broadcastOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; + ASSERT_TRUE( mBroadcastReceiver.init( broadcastOptions ) ); + ASSERT_TRUE( mBroadcastReceiver.connect() ); + + ISOTPOverCANSenderReceiverOptions ecuOptions; + ecuOptions.mSocketCanIFName = "vcan0"; + ecuOptions.mIsExtendedId = (unsigned)physicalRxId > CAN_SFF_MASK; + ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; + ecuOptions.mSourceCANId = (unsigned)physicalTxId; + ecuOptions.mDestinationCANId = (unsigned)physicalRxId; + ASSERT_TRUE( mPhysicalSenderReceiver.init( ecuOptions ) ); + ASSERT_TRUE( mPhysicalSenderReceiver.connect() ); + } + ISOTPOverCANReceiver mBroadcastReceiver; + ISOTPOverCANSenderReceiver mPhysicalSenderReceiver; std::vector mSupportedPIDResponse1; std::vector mSupportedPIDResponse2; std::vector mRequestPID1; @@ -129,64 +150,63 @@ struct ECUMock Thread mThread; }; +// This function will be run in a separate thread to mock ECU response to Edge Agent OBD requests void -ecuBroadcastResponse( void *ecuMock ) +ecuResponse( void *ecuMock ) { auto ecuMockPtr = static_cast( ecuMock ); - std::vector rxPDUData; - if ( ecuMockPtr->mECU.receivePDU( rxPDUData ) ) + while ( !ecuMockPtr->mShouldStop ) { - if ( rxPDUData == std::vector{ 0x01, 0x00 } ) + struct pollfd pfds[] = { { ecuMockPtr->mBroadcastReceiver.getSocket(), POLLIN, 0 }, + { ecuMockPtr->mPhysicalSenderReceiver.getSocket(), POLLIN, 0 } }; + int res = poll( pfds, 2U, 100 ); // 100 ms poll time + if ( res <= 0 ) + { + continue; + } + std::vector rxPDUData; + if ( pfds[0].revents != 0 ) { - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mSupportedPIDResponse1 ); + ecuMockPtr->mBroadcastReceiver.receivePDU( rxPDUData ); + } + else if ( pfds[1].revents != 0 ) + { + ecuMockPtr->mPhysicalSenderReceiver.receivePDU( rxPDUData ); } else { - // Do Nothing, this message is not recognized by ECU + continue; } - } -} -// This function will be run in a separate thread to mock ECU response to Edge Agent OBD requests -void -ecuResponse( void *ecuMock ) -{ - auto ecuMockPtr = static_cast( ecuMock ); - std::vector rxPDUData; - while ( !ecuMockPtr->mShouldStop.load( std::memory_order_relaxed ) ) - { - if ( ecuMockPtr->mECU.receivePDU( rxPDUData ) ) + if ( rxPDUData == std::vector{ 0x01, 0x00 } ) + { + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mSupportedPIDResponse1 ); + } + else if ( rxPDUData == std::vector{ 0x01, 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0 } ) + { + // Edge Agent is querying supported PIDs + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mSupportedPIDResponse1 ); + } + else if ( rxPDUData == std::vector{ 0x01, 0xC0, 0xE0 } ) + { + // Edge Agent is querying supported PIDs + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mSupportedPIDResponse2 ); + } + else if ( rxPDUData == ecuMockPtr->mRequestPID1 ) + { + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mPIDResponse1 ); + } + else if ( rxPDUData == ecuMockPtr->mRequestPID2 ) + { + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mPIDResponse2 ); + } + else if ( rxPDUData == std::vector{ 0x03 } ) { - if ( rxPDUData == std::vector{ 0x01, 0x00 } ) - { - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mSupportedPIDResponse1 ); - } - else if ( rxPDUData == std::vector{ 0x01, 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0 } ) - { - // Edge Agent is querying supported PIDs - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mSupportedPIDResponse1 ); - } - else if ( rxPDUData == std::vector{ 0x01, 0xC0, 0xE0 } ) - { - // Edge Agent is querying supported PIDs - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mSupportedPIDResponse2 ); - } - else if ( rxPDUData == ecuMockPtr->mRequestPID1 ) - { - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mPIDResponse1 ); - } - else if ( rxPDUData == ecuMockPtr->mRequestPID2 ) - { - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mPIDResponse2 ); - } - else if ( rxPDUData == std::vector{ 0x03 } ) - { - ecuMockPtr->mECU.sendPDU( ecuMockPtr->mDTCResponse ); - } - else - { - // Do Nothing, this message is not recognized by ECU - } + ecuMockPtr->mPhysicalSenderReceiver.sendPDU( ecuMockPtr->mDTCResponse ); + } + else + { + // Do Nothing, this message is not recognized by ECU } } } @@ -211,7 +231,8 @@ class OBDOverCANModuleTest : public ::testing::Test { ecuMock.mShouldStop.store( true, std::memory_order_relaxed ); ecuMock.mThread.release(); - ASSERT_TRUE( ecuMock.mECU.disconnect() ); + ASSERT_TRUE( ecuMock.mBroadcastReceiver.disconnect() ); + ASSERT_TRUE( ecuMock.mPhysicalSenderReceiver.disconnect() ); } ASSERT_TRUE( obdModule.disconnect() ); } @@ -226,16 +247,16 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitFailure ) { constexpr uint32_t obdPIDRequestInterval = 0; // 0 seconds constexpr uint32_t obdDTCRequestInterval = 0; // 0 seconds - ASSERT_FALSE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_FALSE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); } -TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitTestSuccess_LinuxCANDep ) +TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitTestSuccess ) { constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds constexpr uint32_t obdDTCRequestInterval = 2; // 2 seconds - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); ASSERT_TRUE( obdModule.disconnect() ); } @@ -244,8 +265,8 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleInitTestFailure ) { constexpr uint32_t obdPIDRequestInterval = 0; // 2 seconds constexpr uint32_t obdDTCRequestInterval = 0; // 2 seconds - ASSERT_FALSE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_FALSE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); } TEST_F( OBDOverCANModuleTest, OBDOverCANModuleAndDecoderManifestLifecycle ) @@ -257,8 +278,6 @@ 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; - std::vector ecmTxPDUData; - std::vector expectedECMPIDs; constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds constexpr uint32_t obdDTCRequestInterval = 2; // 2 seconds @@ -271,8 +290,8 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleAndDecoderManifestLifecycle ) engineECUOptions.mDestinationCANId = toUType( ECU_ID_MOCK::ENGINE_ECU_TX ); ASSERT_TRUE( engineECU.init( engineECUOptions ) ); ASSERT_TRUE( engineECU.connect() ); - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // No Requests should be seen on the bus as it hasn't received a valid decoder dictionary yet. std::this_thread::sleep_for( std::chrono::seconds( obdPIDRequestInterval ) ); @@ -284,66 +303,29 @@ TEST_F( OBDOverCANModuleTest, OBDOverCANModuleAndDecoderManifestLifecycle ) TEST_F( OBDOverCANModuleTest, RequestPIDFromNotExtendedIDECUTest ) { // Setup ECU Mock - ISOTPOverCANSenderReceiverOptions ecuOptions; - ecus = std::vector( 4 ); - ecuOptions.mSocketCanIFName = "vcan0"; - ecuOptions.mIsExtendedId = false; - ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[0].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[0].mECU.connect() ); - ecus[0].mSourceCANId = ecuOptions.mSourceCANId; + ecus = std::vector( 2 ); + + ecus[0].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::ENGINE_ECU_TX, ECU_ID_MOCK::ENGINE_ECU_RX ); ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; - ecus[0].mThread.create( ecuBroadcastResponse, &ecus[0] ); - - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_TX ); - ASSERT_TRUE( ecus[1].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[1].mECU.connect() ); - ecus[1].mSourceCANId = ecuOptions.mSourceCANId; - ecus[1].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].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::TRANSMISSION_ECU_TX, ECU_ID_MOCK::TRANSMISSION_ECU_RX ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[1].mRequestPID1 = { 0x01, 0x04, 0x05 }; - ecus[1].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x05, 0x6E }; - ecus[1].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; - ecus[1].mShouldStop.store( false ); + ecus[1].mRequestPID1 = { 0x01, 0x0D }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23 }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; ecus[1].mThread.create( ecuResponse, &ecus[1] ); - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[2].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[2].mECU.connect() ); - ecus[2].mSourceCANId = ecuOptions.mSourceCANId; - ecus[2].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[2].mThread.create( ecuBroadcastResponse, &ecus[2] ); - - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_TX ); - ASSERT_TRUE( ecus[3].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[3].mECU.connect() ); - ecus[3].mSourceCANId = ecuOptions.mSourceCANId; - ecus[3].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[3].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[3].mRequestPID1 = { 0x01, 0x0D }; - ecus[3].mPIDResponse1 = { 0x41, 0x0D, 0x23 }; - ecus[3].mDTCResponse = { 0x43, 0x00 }; - ecus[3].mShouldStop.store( false ); - ecus[3].mThread.create( ecuResponse, &ecus[3] ); - // Request PIDs every 2 seconds and no DTC request constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // Create decoder dictionary auto decoderDictPtr = initDecoderDictionary(); @@ -374,66 +356,29 @@ TEST_F( OBDOverCANModuleTest, RequestPIDFromNotExtendedIDECUTest ) TEST_F( OBDOverCANModuleTest, RequestPartialPIDFromNotExtendedIDECUTest ) { // Setup ECU Mock - ISOTPOverCANSenderReceiverOptions ecuOptions; - ecus = std::vector( 4 ); - ecuOptions.mSocketCanIFName = "vcan0"; - ecuOptions.mIsExtendedId = false; - ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[0].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[0].mECU.connect() ); - ecus[0].mSourceCANId = ecuOptions.mSourceCANId; + ecus = std::vector( 2 ); + + ecus[0].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::ENGINE_ECU_TX, ECU_ID_MOCK::ENGINE_ECU_RX ); ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x80, 0xF0, 0x00 }; - ecus[0].mThread.create( ecuBroadcastResponse, &ecus[0] ); - - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_TX ); - ASSERT_TRUE( ecus[1].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[1].mECU.connect() ); - ecus[1].mSourceCANId = ecuOptions.mSourceCANId; - ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x80, 0xF0, 0x00 }; - ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[1].mRequestPID1 = { 0x01, 0x04, 0x14 }; - ecus[1].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x14, 0x10, 0x20 }; - ecus[1].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; - ecus[1].mShouldStop.store( false ); + ecus[0].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; + ecus[0].mRequestPID1 = { 0x01, 0x04, 0x14 }; + ecus[0].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x14, 0x10, 0x20 }; + ecus[0].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::TRANSMISSION_ECU_TX, ECU_ID_MOCK::TRANSMISSION_ECU_RX ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x10, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; ecus[1].mThread.create( ecuResponse, &ecus[1] ); - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[2].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[2].mECU.connect() ); - ecus[2].mSourceCANId = ecuOptions.mSourceCANId; - ecus[2].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[2].mThread.create( ecuBroadcastResponse, &ecus[2] ); - - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_TX ); - ASSERT_TRUE( ecus[3].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[3].mECU.connect() ); - ecus[3].mSourceCANId = ecuOptions.mSourceCANId; - ecus[3].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[3].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x10, 0x00, 0x00 }; - ecus[3].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; - ecus[3].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; - ecus[3].mDTCResponse = { 0x43, 0x00 }; - ecus[3].mShouldStop.store( false ); - ecus[3].mThread.create( ecuResponse, &ecus[3] ); - // Request PIDs every 2 seconds and no DTC request constexpr uint32_t obdPIDRequestInterval = 2; // 2 seconds constexpr uint32_t obdDTCRequestInterval = 0; // no DTC request - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // Create decoder dictionary auto decoderDictPtr = initDecoderDictionary(); @@ -468,77 +413,42 @@ TEST_F( OBDOverCANModuleTest, RequestPartialPIDFromNotExtendedIDECUTest ) ASSERT_TRUE( obdModule.getSignalBufferPtr()->empty() ); } -// This test is to validate that OBDOverCANModule can udpate the PID request list when receiving new decoder manifest +// This test is to validate that OBDOverCANModule can update the PID request list when receiving new decoder manifest // In this test scenario, decoder dictionary will first request PID 0x04, 0x14 and 0x0D; then it will switch // to 0x05, 0x14 and 0x0C. TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) { // Setup ECU Mock - ISOTPOverCANSenderReceiverOptions ecuOptions; - ecus = std::vector( 4 ); - - ecuOptions.mSocketCanIFName = "vcan0"; - ecuOptions.mIsExtendedId = true; - ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[0].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[0].mECU.connect() ); - ecus[0].mSourceCANId = ecuOptions.mSourceCANId; - ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x80, 0xF1, 0x00 }; - ecus[0].mThread.create( ecuBroadcastResponse, &ecus[0] ); - - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_TX ); - ASSERT_TRUE( ecus[1].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[1].mECU.connect() ); - ecus[1].mSourceCANId = ecuOptions.mSourceCANId; - ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x80, 0xF0, 0x00 }; - ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[1].mRequestPID1 = { 0x01, 0x04, 0x14 }; - ecus[1].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x14, 0x10, 0x20 }; - ecus[1].mRequestPID2 = { 0x01, 0x05, 0x14 }; - ecus[1].mPIDResponse2 = { 0x41, 0x05, 0x4C, 0x14, 0x10, 0x20 }; - ecus[1].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; - ecus[1].mShouldStop.store( false ); - ecus[1].mThread.create( ecuResponse, &ecus[1] ); + ecus = std::vector( 2 ); - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[2].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[2].mECU.connect() ); - ecus[2].mSourceCANId = ecuOptions.mSourceCANId; - ecus[2].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x18, 0x00, 0x00 }; - ecus[2].mThread.create( ecuBroadcastResponse, &ecus[2] ); - - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_TX ); - ASSERT_TRUE( ecus[3].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[3].mECU.connect() ); - ecus[3].mSourceCANId = ecuOptions.mSourceCANId; - ecus[3].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x18, 0x00, 0x00 }; - ecus[3].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x10, 0x00, 0x00 }; - ecus[3].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; - ecus[3].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; - ecus[3].mRequestPID2 = { 0x01, 0x0C, 0xC1 }; - ecus[3].mPIDResponse2 = { 0x41, 0x0C, 0x0F, 0xA0, 0xC1, 0xAA }; - ecus[3].mDTCResponse = { 0x43, 0x00 }; - ecus[3].mShouldStop.store( false ); - ecus[3].mThread.create( ecuResponse, &ecus[3] ); + ecus[0].init( + ECUID::BROADCAST_EXTENDED_ID, ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED, ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED ); + ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x80, 0xF0, 0x00 }; + ecus[0].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; + ecus[0].mRequestPID1 = { 0x01, 0x04, 0x14 }; + ecus[0].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x14, 0x10, 0x20 }; + ecus[0].mRequestPID2 = { 0x01, 0x05, 0x14 }; + ecus[0].mPIDResponse2 = { 0x41, 0x05, 0x4C, 0x14, 0x10, 0x20 }; + ecus[0].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_EXTENDED_ID, + ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED, + ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x18, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x10, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; + ecus[1].mRequestPID2 = { 0x01, 0x0C, 0xC1 }; + ecus[1].mPIDResponse2 = { 0x41, 0x0C, 0x0F, 0xA0, 0xC1, 0xAA }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; + 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 obdDTCRequestInterval = 0; // no DTC request - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // Create decoder dictionary auto decoderDictPtr = initDecoderDictionary(); @@ -613,69 +523,34 @@ TEST_F( OBDOverCANModuleTest, DecoderDictionaryUpdatePIDsToCollectTest ) TEST_F( OBDOverCANModuleTest, RequestEmissionPIDAndDTCFromExtendedIDECUTest ) { // Setup ECU Mock - ISOTPOverCANSenderReceiverOptions ecuOptions; - ecus = std::vector( 4 ); - - ecuOptions.mSocketCanIFName = "vcan0"; - ecuOptions.mIsExtendedId = true; - ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[0].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[0].mECU.connect() ); - ecus[0].mSourceCANId = ecuOptions.mSourceCANId; + ecus = std::vector( 2 ); + + ecus[0].init( + ECUID::BROADCAST_EXTENDED_ID, ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED, ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED ); ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; - ecus[0].mThread.create( ecuBroadcastResponse, &ecus[0] ); - - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_TX ); - ASSERT_TRUE( ecus[1].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[1].mECU.connect() ); - ecus[1].mSourceCANId = ecuOptions.mSourceCANId; - ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; - ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[1].mRequestPID1 = { 0x01, 0x04, 0x05 }; - ecus[1].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x05, 0x6E }; - ecus[1].mDTCResponse = { 0x43, 0x04, 0x01, 0x43, 0x41, 0x96, 0x81, 0x48, 0xC1, 0x48 }; - ecus[1].mShouldStop.store( false ); + 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].mDTCResponse = { 0x43, 0x04, 0x01, 0x43, 0x41, 0x96, 0x81, 0x48, 0xC1, 0x48 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_EXTENDED_ID, + ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED, + ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x00, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; ecus[1].mThread.create( ecuResponse, &ecus[1] ); - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[2].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[2].mECU.connect() ); - ecus[2].mSourceCANId = ecuOptions.mSourceCANId; - ecus[2].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[2].mThread.create( ecuBroadcastResponse, &ecus[2] ); - - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_TX ); - ASSERT_TRUE( ecus[3].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[3].mECU.connect() ); - ecus[3].mSourceCANId = ecuOptions.mSourceCANId; - ecus[3].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[3].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x00, 0x00, 0x00 }; - ecus[3].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; - ecus[3].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; - ecus[3].mDTCResponse = { 0x43, 0x00 }; - ecus[3].mShouldStop.store( false ); - ecus[3].mThread.create( ecuResponse, &ecus[3] ); - // 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 - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); // Create decoder dictionary auto decoderDictPtr = initDecoderDictionary(); @@ -715,69 +590,31 @@ TEST_F( OBDOverCANModuleTest, RequestEmissionPIDAndDTCFromExtendedIDECUTest ) TEST_F( OBDOverCANModuleTest, RequestPIDAndDTCFromNonExtendedIDECUTest ) { // Setup ECU Mock - ISOTPOverCANSenderReceiverOptions ecuOptions; - ecus = std::vector( 4 ); - - ecuOptions.mSocketCanIFName = "vcan0"; - ecuOptions.mIsExtendedId = false; - ecuOptions.mP2TimeoutMs = P2_TIMEOUT_DEFAULT_MS; - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[0].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[0].mECU.connect() ); - ecus[0].mSourceCANId = ecuOptions.mSourceCANId; + ecus = std::vector( 2 ); + + ecus[0].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::ENGINE_ECU_TX, ECU_ID_MOCK::ENGINE_ECU_RX ); ecus[0].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; - ecus[0].mThread.create( ecuBroadcastResponse, &ecus[0] ); - - ecuOptions.mSourceCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED : ECU_ID_MOCK::ENGINE_ECU_TX ); - ASSERT_TRUE( ecus[1].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[1].mECU.connect() ); - ecus[1].mSourceCANId = ecuOptions.mSourceCANId; - ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x18, 0x00, 0x00, 0x00 }; - ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; - ecus[1].mRequestPID1 = { 0x01, 0x04, 0x05 }; - ecus[1].mPIDResponse1 = { 0x41, 0x04, 0x99, 0x05, 0x6E }; - ecus[1].mDTCResponse = { 0x43, 0x04, 0x01, 0x43, 0x41, 0x96, 0x81, 0x48, 0xC1, 0x48 }; - ecus[1].mShouldStop.store( false ); + 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].mDTCResponse = { 0x43, 0x04, 0x01, 0x43, 0x41, 0x96, 0x81, 0x48, 0xC1, 0x48 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::TRANSMISSION_ECU_TX, ECU_ID_MOCK::TRANSMISSION_ECU_RX ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x00, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; ecus[1].mThread.create( ecuResponse, &ecus[1] ); - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = - toUType( ecuOptions.mIsExtendedId ? ECUID::BROADCAST_EXTENDED_ID : ECUID::BROADCAST_ID ); - ASSERT_TRUE( ecus[2].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[2].mECU.connect() ); - ecus[2].mSourceCANId = ecuOptions.mSourceCANId; - ecus[2].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[2].mThread.create( ecuBroadcastResponse, &ecus[2] ); - - ecuOptions.mSourceCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_RX ); - ecuOptions.mDestinationCANId = toUType( ecuOptions.mIsExtendedId ? ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED - : ECU_ID_MOCK::TRANSMISSION_ECU_TX ); - ASSERT_TRUE( ecus[3].mECU.init( ecuOptions ) ); - ASSERT_TRUE( ecus[3].mECU.connect() ); - ecus[3].mSourceCANId = ecuOptions.mSourceCANId; - ecus[3].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; - ecus[3].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x80, 0x00, 0x00, 0x00 }; - ecus[3].mRequestPID1 = { 0x01, 0x0D, 0xC1 }; - ecus[3].mPIDResponse1 = { 0x41, 0x0D, 0x23, 0xC1, 0xAA }; - ecus[3].mDTCResponse = { 0x43, 0x00 }; - ecus[3].mShouldStop.store( false ); - ecus[3].mThread.create( ecuResponse, &ecus[3] ); - // 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 - ASSERT_TRUE( - obdModule.init( signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval ) ); + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, false ) ); ASSERT_TRUE( obdModule.connect() ); auto decoderDictPtr = initDecoderDictionary(); // publish decoder dictionary to OBD module @@ -812,3 +649,102 @@ TEST_F( OBDOverCANModuleTest, RequestPIDAndDTCFromNonExtendedIDECUTest ) ASSERT_EQ( dtcInfo.mDTCCodes[2], "B0148" ); ASSERT_EQ( dtcInfo.mDTCCodes[3], "U0148" ); } + +TEST_F( OBDOverCANModuleTest, BroadcastRequestsStandardIDs ) +{ + // Setup ECU Mock + ecus = std::vector( 2 ); + + ecus[0].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::ENGINE_ECU_TX, ECU_ID_MOCK::ENGINE_ECU_RX ); + 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].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_ID, ECU_ID_MOCK::TRANSMISSION_ECU_TX, ECU_ID_MOCK::TRANSMISSION_ECU_RX ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23 }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; + 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 obdDTCRequestInterval = 0; // no DTC request + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, true ) ); + ASSERT_TRUE( obdModule.connect() ); + // Create decoder dictionary + 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 = { + { 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] ); +} + +TEST_F( OBDOverCANModuleTest, BroadcastRequestsExtendedIDs ) +{ + // Setup ECU Mock + ecus = std::vector( 2 ); + + ecus[0].init( + ECUID::BROADCAST_EXTENDED_ID, ECU_ID_MOCK::ENGINE_ECU_TX_EXTENDED, ECU_ID_MOCK::ENGINE_ECU_RX_EXTENDED ); + 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].mDTCResponse = { 0x43, 0x02, 0x01, 0x43, 0x41, 0x96 }; + ecus[0].mThread.create( ecuResponse, &ecus[0] ); + + ecus[1].init( ECUID::BROADCAST_EXTENDED_ID, + ECU_ID_MOCK::TRANSMISSION_ECU_TX_EXTENDED, + ECU_ID_MOCK::TRANSMISSION_ECU_RX_EXTENDED ); + ecus[1].mSupportedPIDResponse1 = { 0x41, 0x00, 0x00, 0x08, 0x00, 0x00 }; + ecus[1].mSupportedPIDResponse2 = { 0x41, 0xC0, 0x00, 0x00, 0x00, 0x00 }; + ecus[1].mRequestPID1 = { 0x01, 0x0D }; + ecus[1].mPIDResponse1 = { 0x41, 0x0D, 0x23 }; + ecus[1].mDTCResponse = { 0x43, 0x00 }; + 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 obdDTCRequestInterval = 0; // no DTC request + ASSERT_TRUE( obdModule.init( + signalBufferPtr, activeDTCBufferPtr, "vcan0", obdPIDRequestInterval, obdDTCRequestInterval, true ) ); + ASSERT_TRUE( obdModule.connect() ); + // Create decoder dictionary + 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 = { + { 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] ); +} diff --git a/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp b/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp index 45ac896b..e948cbe7 100644 --- a/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp +++ b/src/datamanagement/datainspection/test/VehicleDataSourceBinderTest.cpp @@ -803,6 +803,8 @@ 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 ) diff --git a/src/datamanagement/datamanager/CMakeLists.txt b/src/datamanagement/datamanager/CMakeLists.txt index 7a14a5df..237ea729 100644 --- a/src/datamanagement/datamanager/CMakeLists.txt +++ b/src/datamanagement/datamanager/CMakeLists.txt @@ -55,8 +55,6 @@ install( if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - find_library(GMOCK_LIB NAMES gmock) @@ -88,13 +86,12 @@ if(${BUILD_TESTING}) include test/include) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main - GTest::GTest + IoTFleetWise::TestingSupport ${GMOCK_LIB} ) diff --git a/src/datamanagement/datamanager/include/CollectionSchemeManager.h b/src/datamanagement/datamanager/include/CollectionSchemeManager.h index 5d00a39d..bf47d5bf 100644 --- a/src/datamanagement/datamanager/include/CollectionSchemeManager.h +++ b/src/datamanagement/datamanager/include/CollectionSchemeManager.h @@ -34,14 +34,25 @@ using namespace Aws::IoTFleetWise::Platform::Linux; using SchemaListenerPtr = std::shared_ptr; /* TimeData is used in mTimeline, the second parameter in the pair is a CollectionScheme ID */ -using TimeData = std::pair; +struct TimeData +{ + TimePoint time; + std::string id; + + bool + operator>( const TimeData &other ) const + { + return ( this->time.monotonicTimeMs > other.time.monotonicTimeMs ) || + ( ( this->time.monotonicTimeMs == other.time.monotonicTimeMs ) && ( this->id > other.id ) ); + } +}; /** * @brief main CollectionScheme Management entity - responsible for the following: * 1. Listens to collectionScheme ingestion to get CollectionSchemeList and DecoderManifest * 2. Process CollectionSchemeList to generate timeLine in chronological order, organize CollectionSchemeList into Enabled and Idle lists; - * 3. Wait for timer to elapse on TimePointInMsecond along timeLine chronologically, re-org Enabled and Idle list; + * 3. Wait for timer to elapse along timeLine chronologically, re-org Enabled and Idle list; * 4. Extract decoding dictionary and propagate to Vehicle Data Consumer; * 5. Extract Inspection Matrix and propagate to Inspection Engine; * 6. Delete expired collectionSchemes from Enabled list, or removed collectionScheme from existing list per Cloud @@ -187,6 +198,8 @@ class CollectionSchemeManager : public ICollectionSchemeManager, */ static void doWork( void *data ); + TimePoint calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ); + /** * @brief template function for generate a message on an event for mLogger usage * Include Event printed in string msg, collectionScheme ID, startTime, stopTime of the collectionScheme, and @@ -199,9 +212,9 @@ class CollectionSchemeManager : public ICollectionSchemeManager, */ static void printEventLogMsg( std::string &msg, const std::string &id, - const TimePointInMsec &startTime, - const TimePointInMsec &stopTime, - const TimePointInMsec &currTime ); + const Timestamp &startTime, + const Timestamp &stopTime, + const TimePoint &currTime ); /** * @brief supporting function for mLogger @@ -247,11 +260,11 @@ class CollectionSchemeManager : public ICollectionSchemeManager, bool isCollectionSchemeLoaded(); protected: - bool rebuildMapsandTimeLine( const TimePointInMsec &currTime ) override; + bool rebuildMapsandTimeLine( const TimePoint &currTime ) override; - bool updateMapsandTimeLine( const TimePointInMsec &currTime ) override; + bool updateMapsandTimeLine( const TimePoint &currTime ) override; - bool checkTimeLine( const TimePointInMsec &currTime ) override; + bool checkTimeLine( const TimePoint &currTime ) override; /** * @brief This function extract the decoder dictionary from decoder manifest and polices diff --git a/src/datamanagement/datamanager/include/ICollectionSchemeManager.h b/src/datamanagement/datamanager/include/ICollectionSchemeManager.h index 45900bac..0fc56ba6 100644 --- a/src/datamanagement/datamanager/include/ICollectionSchemeManager.h +++ b/src/datamanagement/datamanager/include/ICollectionSchemeManager.h @@ -16,8 +16,6 @@ namespace DataManagement { using namespace Aws::IoTFleetWise::Platform::Linux::PersistencyManagement; using namespace Aws::IoTFleetWise::DataInspection; -/* when TimePointInMsec is used, it should refer to milliseconds since Epoch */ -using TimePointInMsec = uint64_t; class ICollectionSchemeManager { @@ -44,7 +42,7 @@ class ICollectionSchemeManager * @param currTime time in seconds when main thread wakes up; * @return true when enabled collectionScheme map is updated. */ - virtual bool rebuildMapsandTimeLine( const TimePointInMsec &currTime ) = 0; + virtual bool rebuildMapsandTimeLine( const TimePoint &currTime ) = 0; /** * @brief Updates existing enabled collectionScheme map, idle collectionScheme map, and time line; @@ -55,7 +53,7 @@ class ICollectionSchemeManager * @param currTime time in seconds when main thread wakes up; * @return true when enabled collectionScheme map is updated. */ - virtual bool updateMapsandTimeLine( const TimePointInMsec &currTime ) = 0; + virtual bool updateMapsandTimeLine( const TimePoint &currTime ) = 0; /** * @brief works on TimeData popped from mTimeLine to decide whether to disable/enable a collectionScheme @@ -63,7 +61,7 @@ class ICollectionSchemeManager * @param currTime time in seconds when main thread wakes up; * @return true when enabled collectionScheme map is updated. */ - virtual bool checkTimeLine( const TimePointInMsec &currTime ) = 0; + virtual bool checkTimeLine( const TimePoint &currTime ) = 0; /** * @brief Extract from enabled collectionSchemes and aggregate into inspectMatrix diff --git a/src/datamanagement/datamanager/include/Schema.h b/src/datamanagement/datamanager/include/Schema.h index 2dc71b89..f97aa6f4 100644 --- a/src/datamanagement/datamanager/include/Schema.h +++ b/src/datamanagement/datamanager/include/Schema.h @@ -106,10 +106,10 @@ class Schema : public ThreadListeners, publi onDataReceived( const uint8_t *buf, size_t size ) override { // Check for a empty input data - if ( buf == nullptr || size == 0 ) + if ( ( buf == nullptr ) || ( size == 0 ) ) { mLogger.error( "DecoderManifestCb::onDataReceived", - "Received empty CollectionScheme List data from Cloud." ); + "Received empty CollectionScheme List data from Cloud" ); return; } @@ -119,7 +119,7 @@ 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." ); + mLogger.error( "DecoderManifestCb::onDataReceived", "DecoderManifest copyData from IoT core failed" ); return; } @@ -154,10 +154,10 @@ class Schema : public ThreadListeners, publi onDataReceived( const uint8_t *buf, size_t size ) override { // Check for a empty input data - if ( buf == nullptr || size == 0 ) + if ( ( buf == nullptr ) || ( size == 0 ) ) { mLogger.error( "DecoderManifestCb::onDataReceived", - "Received empty CollectionScheme List data from Cloud." ); + "Received empty CollectionScheme List data from Cloud" ); return; } @@ -168,7 +168,7 @@ class Schema : public ThreadListeners, publi if ( !collectionSchemeListPtr->copyData( buf, size ) ) { mLogger.error( "DecoderManifestCb::onDataReceived", - "CollectionSchemeList copyData from IoT core failed." ); + "CollectionSchemeList copyData from IoT core failed" ); return; } diff --git a/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp b/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp index c8d3265e..7c2f5cd8 100644 --- a/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp +++ b/src/datamanagement/datamanager/src/CheckinAndPersistency.cpp @@ -19,8 +19,8 @@ using namespace Aws::IoTFleetWise::Platform::Utility; void CollectionSchemeManager::prepareCheckinTimer() { - TimePointInMsec currTime = mClock->timeSinceEpochMs(); - TimeData checkinData = std::make_pair( currTime, CHECKIN ); + auto currTime = mClock->timeSinceEpoch(); + TimeData checkinData = TimeData{ currTime, CHECKIN }; mTimeLine.push( checkinData ); } @@ -29,27 +29,32 @@ CollectionSchemeManager::sendCheckin() { // Create a list of active collectionSchemes and the current decoder manifest and send it to cloud std::vector checkinMsg; - std::string checkinLogStr; for ( auto it = mEnabledCollectionSchemeMap.begin(); it != mEnabledCollectionSchemeMap.end(); it++ ) { checkinMsg.emplace_back( it->first ); - checkinLogStr += it->first + ' '; } for ( auto it = mIdleCollectionSchemeMap.begin(); it != mIdleCollectionSchemeMap.end(); it++ ) { checkinMsg.emplace_back( it->first ); - checkinLogStr += it->first + ' '; } if ( !currentDecoderManifestID.empty() ) { checkinMsg.emplace_back( currentDecoderManifestID ); - checkinLogStr += currentDecoderManifestID; } - mLogger.trace( "CollectionSchemeManager::sendCheckin ", "CHECKIN " + checkinLogStr ); + std::string checkinLogStr; + for ( size_t i = 0; i < checkinMsg.size(); i++ ) + { + if ( i > 0 ) + { + checkinLogStr += ", "; + } + checkinLogStr += checkinMsg[i]; + } + mLogger.trace( "CollectionSchemeManager::sendCheckin", "CHECKIN: " + checkinLogStr ); if ( mSchemaListenerPtr == nullptr ) { - mLogger.error( "CollectionSchemeManager::sendCheckin", "Cannot set the checkin message " ); + mLogger.error( "CollectionSchemeManager::sendCheckin", "Cannot set the checkin message" ); return false; } else @@ -70,29 +75,29 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) if ( mSchemaPersistency == nullptr ) { mLogger.error( "CollectionSchemeManager::retrieve", - "Failed to acquire a valid handle on the scheme local persistency module " ); + "Failed to acquire a valid handle on the scheme local persistency module" ); return false; } switch ( retrieveType ) { case DataType::COLLECTION_SCHEME_LIST: infoStr = "Retrieved a CollectionSchemeList of size "; - errStr = "Failed to retrieve the CollectionSchemeList from the persistency module due to an error :"; + errStr = "Failed to retrieve the CollectionSchemeList from the persistency module due to an error: "; break; case DataType::DECODER_MANIFEST: infoStr = "Retrieved a DecoderManifest of size "; - errStr = "Failed to retrieve the DecoderManifest from the persistency module due to an error :"; + 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 ) ) ); + "Unknown error: " + std::to_string( toUType( retrieveType ) ) ); return false; } protoSize = mSchemaPersistency->getSize( retrieveType ); if ( protoSize <= 0 ) { - mLogger.info( "CollectionSchemeManager::retrieve", infoStr + "zero." ); + mLogger.info( "CollectionSchemeManager::retrieve", infoStr + "zero" ); return false; } protoOutput.resize( protoSize ); @@ -104,7 +109,7 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) mLogger.error( "CollectionSchemeManager::retrieve", errStr ); return false; } - mLogger.info( "CollectionSchemeManager::retrieve", infoStr + std::to_string( protoSize ) + " successfully." ); + mLogger.info( "CollectionSchemeManager::retrieve", infoStr + std::to_string( protoSize ) + " successfully" ); if ( retrieveType == DataType::COLLECTION_SCHEME_LIST ) { // updating mCollectionSchemeList @@ -115,6 +120,9 @@ CollectionSchemeManager::retrieve( DataType retrieveType ) mCollectionSchemeList->copyData( protoOutput.data(), protoSize ); mProcessCollectionScheme = true; } + // currently this if will be always true as it can be only DECODER_MANIFEST or COLLECTION_SCHEME_LIST but for + // readability leave it as else if instead of else + // coverity[autosar_cpp14_m0_1_2_violation] else if ( retrieveType == DataType::DECODER_MANIFEST ) { // updating mDecoderManifest @@ -141,12 +149,12 @@ CollectionSchemeManager::store( DataType storeType ) "Failed to acquire a valid handle on the scheme local persistency module" ); return; } - if ( storeType == DataType::COLLECTION_SCHEME_LIST && mCollectionSchemeList == nullptr ) + if ( ( storeType == DataType::COLLECTION_SCHEME_LIST ) && ( mCollectionSchemeList == nullptr ) ) { mLogger.error( "CollectionSchemeManager::store", "Invalid CollectionSchemeList" ); return; } - if ( storeType == DataType::DECODER_MANIFEST && mDecoderManifest == nullptr ) + if ( ( storeType == DataType::DECODER_MANIFEST ) && ( mDecoderManifest == nullptr ) ) { mLogger.error( "CollectionSchemeManager::store", "Invalid DecoderManifest" ); return; @@ -169,7 +177,7 @@ CollectionSchemeManager::store( DataType storeType ) if ( protoInput.empty() ) { - mLogger.error( "CollectionSchemeManager::store", logStr + " data size is zero." ); + mLogger.error( "CollectionSchemeManager::store", logStr + " data size is zero" ); return; } ret = mSchemaPersistency->write( protoInput.data(), protoInput.size(), storeType ); @@ -182,7 +190,7 @@ CollectionSchemeManager::store( DataType storeType ) } else { - mLogger.trace( "CollectionSchemeManager::store", logStr + " persisted successfully." ); + mLogger.trace( "CollectionSchemeManager::store", logStr + " persisted successfully" ); } } } // namespace DataManagement diff --git a/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp b/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp index 9cb94250..dcfceee1 100644 --- a/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp +++ b/src/datamanagement/datamanager/src/CollectionSchemeManager.cpp @@ -4,6 +4,7 @@ // Includes #include "CollectionSchemeManager.h" #include "TraceModule.h" +#include #include #include #include @@ -14,6 +15,7 @@ namespace IoTFleetWise { namespace DataManagement { + const std::string CollectionSchemeManager::CHECKIN = "Checkin"; CollectionSchemeManager::CollectionSchemeManager( std::string dm_id ) : currentDecoderManifestID( std::move( dm_id ) ) @@ -51,11 +53,11 @@ CollectionSchemeManager::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.error( "CollectionSchemeManager::start", " Collection Scheme Thread failed to start " ); + mLogger.error( "CollectionSchemeManager::start", "Thread failed to start" ); } else { - mLogger.info( "CollectionSchemeManager::start", " Collection Scheme Thread started " ); + mLogger.info( "CollectionSchemeManager::start", "Thread started" ); mThread.setThreadName( "fwDMColSchMngr" ); } return mThread.isValid(); @@ -75,7 +77,7 @@ CollectionSchemeManager::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.info( "CollectionSchemeManager::stop", " Collection Scheme Thread stopped " ); + mLogger.info( "CollectionSchemeManager::stop", "Thread stopped" ); return true; } @@ -89,14 +91,15 @@ CollectionSchemeManager::shouldStop() const void CollectionSchemeManager::printEventLogMsg( std::string &msg, const std::string &id, - const TimePointInMsec &startTime, - const TimePointInMsec &stopTime, - const TimePointInMsec &currTime ) + const Timestamp &startTime, + const Timestamp &stopTime, + const TimePoint &currTime ) { msg += "ID( " + id + " )"; msg += "Start( " + std::to_string( startTime ) + " milliseconds )"; msg += "Stop( " + std::to_string( stopTime ) + " milliseconds )"; - msg += "at Current( " + std::to_string( currTime ) + " milliseconds )."; + msg += "at Current System Time ( " + std::to_string( currTime.systemTimeMs ) + " milliseconds )."; + msg += "at Current Monotonic Time ( " + std::to_string( currTime.monotonicTimeMs ) + " milliseconds )."; } void @@ -119,10 +122,10 @@ CollectionSchemeManager::printExistingCollectionSchemes( std::string &enableStr, void CollectionSchemeManager::printWakeupStatus( std::string &wakeupStr ) const { - wakeupStr = " Waking up to update the CollectionScheme: "; - wakeupStr += mProcessCollectionScheme ? "Yes." : "No."; + wakeupStr = "Waking up to update the CollectionScheme: "; + wakeupStr += mProcessCollectionScheme ? "Yes" : "No"; wakeupStr += " and the DecoderManifest: "; - wakeupStr += mProcessDecoderManifest ? "Yes." : "No."; + wakeupStr += mProcessDecoderManifest ? "Yes" : "No"; } // Clears both enabled collectionScheme map and idle collectionScheme map @@ -139,16 +142,16 @@ CollectionSchemeManager::cleanupCollectionSchemes() mIdleCollectionSchemeMap.clear(); // when cleaning up mTimeLine checkIn event needs to be preserved - TimeData saveTimeData = { 0, "" }; + TimeData saveTimeData = { { 0, 0 }, "" }; while ( !mTimeLine.empty() ) { - if ( mTimeLine.top().second == CHECKIN ) + if ( mTimeLine.top().id == CHECKIN ) { saveTimeData = mTimeLine.top(); } mTimeLine.pop(); } - if ( saveTimeData.first != 0 ) + if ( saveTimeData.time.monotonicTimeMs != 0 ) { mTimeLine.push( saveTimeData ); } @@ -191,15 +194,15 @@ CollectionSchemeManager::doWork( void *data ) enabledCollectionSchemeMapChanged |= collectionSchemeManager->processCollectionScheme(); TraceModule::get().sectionEnd( TraceSection::MANAGER_COLLECTION_BUILD ); } - auto checkTime = collectionSchemeManager->mClock->timeSinceEpochMs(); + auto checkTime = collectionSchemeManager->mClock->timeSinceEpoch(); enabledCollectionSchemeMapChanged |= collectionSchemeManager->checkTimeLine( checkTime ); if ( enabledCollectionSchemeMapChanged ) { TraceModule::get().sectionBegin( TraceSection::MANAGER_EXTRACTION ); collectionSchemeManager->mLogger.trace( "CollectionSchemeManager::doWork", - "Start extraction because of changed active collection schemes at time " + - std::to_string( checkTime ) ); + "Start extraction because of changed active collection schemes at system time " + + std::to_string( checkTime.systemTimeMs ) ); /* * Extract InspectionMatrix from mEnabledCollectionSchemeMap * @@ -233,9 +236,9 @@ CollectionSchemeManager::doWork( void *data ) ? decoderDictionaryMap[VehicleDataSourceProtocol::RAW_SOCKET]->canMessageDecoderMethod.size() : 0 ); std::string obdPids = std::to_string( - ( decoderDictionaryMap.find( VehicleDataSourceProtocol::OBD ) != decoderDictionaryMap.end() && - decoderDictionaryMap[VehicleDataSourceProtocol::OBD] != nullptr && - !decoderDictionaryMap[VehicleDataSourceProtocol::OBD]->canMessageDecoderMethod.empty() ) + ( ( decoderDictionaryMap.find( VehicleDataSourceProtocol::OBD ) != decoderDictionaryMap.end() ) && + ( decoderDictionaryMap[VehicleDataSourceProtocol::OBD] != nullptr ) && + ( !decoderDictionaryMap[VehicleDataSourceProtocol::OBD]->canMessageDecoderMethod.empty() ) ) ? decoderDictionaryMap[VehicleDataSourceProtocol::OBD] ->canMessageDecoderMethod.cbegin() ->second.size() @@ -264,19 +267,22 @@ CollectionSchemeManager::doWork( void *data ) * check if it is a valid timePoint, it can be obsoleted if start Time or stop Time gets updated * It should be always valid because Checkin is default to be running all the time */ - auto currentTime = collectionSchemeManager->mClock->timeSinceEpochMs(); + auto currentMonotonicTime = collectionSchemeManager->mClock->monotonicTimeSinceEpochMs(); if ( collectionSchemeManager->mTimeLine.empty() ) { collectionSchemeManager->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); } - else if ( currentTime >= collectionSchemeManager->mTimeLine.top().first ) + else if ( currentMonotonicTime >= collectionSchemeManager->mTimeLine.top().time.monotonicTimeMs ) { // Next checkin time has already expired } else { - uint32_t waitTime = static_cast( collectionSchemeManager->mTimeLine.top().first - currentTime ); - collectionSchemeManager->mWait.wait( waitTime ); + 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" ); + collectionSchemeManager->mWait.wait( waitTimeMs ); } /* now it is either timer expires, an update arrives from PI, or stop() is called */ collectionSchemeManager->updateAvailable(); @@ -334,8 +340,8 @@ CollectionSchemeManager::init( uint32_t checkinIntervalMsec, { mCANIDTranslator = canIDTranslator; mLogger.trace( "CollectionSchemeManager::init", - "CollectionSchemeManager initialised with a checkin interval of : " + - std::to_string( checkinIntervalMsec ) + " ms." ); + "CollectionSchemeManager initialised with a checkin interval of: " + + std::to_string( checkinIntervalMsec ) + " ms" ); if ( checkinIntervalMsec > 0 ) { mCheckinIntervalInMsec = checkinIntervalMsec; @@ -370,7 +376,7 @@ CollectionSchemeManager::isAlive() bool CollectionSchemeManager::isCollectionSchemeLoaded() { - return ( !mEnabledCollectionSchemeMap.empty() || !mIdleCollectionSchemeMap.empty() ); + return ( ( !mEnabledCollectionSchemeMap.empty() ) || ( !mIdleCollectionSchemeMap.empty() ) ); } /* @@ -385,7 +391,7 @@ CollectionSchemeManager::isCollectionSchemeLoaded() bool CollectionSchemeManager::processDecoderManifest() { - if ( mDecoderManifest == nullptr || !mDecoderManifest->build() ) + if ( ( mDecoderManifest == nullptr ) || ( !mDecoderManifest->build() ) ) { mLogger.error( "CollectionSchemeManager::processDecoderManifest", " Failed to process the upcoming DecoderManifest." ); @@ -416,7 +422,7 @@ CollectionSchemeManager::processDecoderManifest() else { // collectionScheme maps are empty - return rebuildMapsandTimeLine( mClock->timeSinceEpochMs() ); + return rebuildMapsandTimeLine( mClock->timeSinceEpoch() ); } } @@ -431,7 +437,7 @@ CollectionSchemeManager::processDecoderManifest() bool CollectionSchemeManager::processCollectionScheme() { - if ( mCollectionSchemeList == nullptr || !mCollectionSchemeList->build() ) + if ( ( mCollectionSchemeList == nullptr ) || ( !mCollectionSchemeList->build() ) ) { mLogger.error( "CollectionSchemeManager::processCollectionScheme", "Incoming CollectionScheme does not exist or fails to build!" ); @@ -442,13 +448,29 @@ CollectionSchemeManager::processCollectionScheme() if ( isCollectionSchemeLoaded() ) { // there are existing collectionSchemes, try to update the existing one - return updateMapsandTimeLine( mClock->timeSinceEpochMs() ); + return updateMapsandTimeLine( mClock->timeSinceEpoch() ); } else { // collectionScheme maps are empty - return rebuildMapsandTimeLine( mClock->timeSinceEpochMs() ); + return rebuildMapsandTimeLine( mClock->timeSinceEpoch() ); + } +} + +TimePoint +CollectionSchemeManager::calculateMonotonicTime( const TimePoint &currTime, Timestamp systemTimeMs ) +{ + 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 ) ); + return TimePoint{ systemTimeMs, 0 }; } + return convertedTime; } /* @@ -457,7 +479,7 @@ CollectionSchemeManager::processCollectionScheme() * true. Otherwise, it returns false. */ bool -CollectionSchemeManager::rebuildMapsandTimeLine( const TimePointInMsec &currTime ) +CollectionSchemeManager::rebuildMapsandTimeLine( const TimePoint &currTime ) { bool ret = false; std::vector collectionSchemeList; @@ -483,20 +505,21 @@ CollectionSchemeManager::rebuildMapsandTimeLine( const TimePointInMsec &currTime return false; } // collectionScheme does not have matching DM, can't rebuild. Exit - TimePointInMsec startTime = collectionScheme->getStartTime(); - TimePointInMsec stopTime = collectionScheme->getExpiryTime(); + Timestamp startTime = collectionScheme->getStartTime(); + Timestamp stopTime = collectionScheme->getExpiryTime(); std::string id = collectionScheme->getCollectionSchemeID(); - if ( startTime > currTime ) + if ( startTime > currTime.systemTimeMs ) { /* for idleCollectionSchemes, push both startTime and stopTime to timeLine */ mIdleCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( std::make_pair( startTime, id ) ); - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, startTime ), id } ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); } - else if ( stopTime > currTime ) - { /* At rebuild, if a collectionScheme's startTime has already passed, enable collectionScheme immediately */ + else if ( stopTime > currTime.systemTimeMs ) + { /* At rebuild, if a collectionScheme's startTime has already passed, enable collectionScheme immediately + */ mEnabledCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); ret = true; } } @@ -518,7 +541,7 @@ CollectionSchemeManager::rebuildMapsandTimeLine( const TimePointInMsec &currTime * Returns true when mEnabledCollectionSchemeMap changes. */ bool -CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime ) +CollectionSchemeManager::updateMapsandTimeLine( const TimePoint &currTime ) { bool ret = false; std::unordered_set newCollectionSchemeIDs; @@ -556,8 +579,8 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime * and also check if it is to be enabled immediately. * */ - TimePointInMsec startTime = collectionScheme->getStartTime(); - TimePointInMsec stopTime = collectionScheme->getExpiryTime(); + Timestamp startTime = collectionScheme->getStartTime(); + Timestamp stopTime = collectionScheme->getExpiryTime(); std::string id = collectionScheme->getCollectionSchemeID(); newCollectionSchemeIDs.insert( id ); @@ -567,7 +590,7 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime { /* found collectionScheme in Enabled map. this collectionScheme is running, check for StopTime only */ ICollectionSchemePtr currCollectionScheme = itEnabled->second; - if ( stopTime <= currTime ) + if ( stopTime <= currTime.systemTimeMs ) { /* This collectionScheme needs to stop immediately */ mEnabledCollectionSchemeMap.erase( id ); @@ -575,39 +598,40 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime std::string completedStr; completedStr = "Stopping enabled CollectionScheme: "; printEventLogMsg( completedStr, id, startTime, stopTime, currTime ); - mLogger.trace( "collectionSchemeManager::updateMapsandTimeLine ", completedStr ); + mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", completedStr ); } else if ( stopTime != currCollectionScheme->getExpiryTime() ) { /* StopTime changes on that collectionScheme, update with new CollectionScheme */ mEnabledCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); } } else if ( itIdle != mIdleCollectionSchemeMap.end() ) { /* found in Idle map, need to check both StartTime and StopTime */ ICollectionSchemePtr currCollectionScheme = itIdle->second; - if ( startTime <= currTime && stopTime > currTime ) + if ( ( startTime <= currTime.systemTimeMs ) && ( stopTime > currTime.systemTimeMs ) ) { /* this collectionScheme needs to start immediately */ mIdleCollectionSchemeMap.erase( id ); mEnabledCollectionSchemeMap[id] = collectionScheme; ret = true; - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); std::string startStr; startStr = "Starting idle collectionScheme now: "; printEventLogMsg( startStr, id, startTime, stopTime, currTime ); - mLogger.trace( "collectionSchemeManager::updateMapsandTimeLine ", startStr ); + mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", startStr ); } - else if ( startTime > currTime && ( ( startTime != currCollectionScheme->getStartTime() ) || - ( stopTime != currCollectionScheme->getExpiryTime() ) ) ) + else if ( ( startTime > currTime.systemTimeMs ) && + ( ( startTime != currCollectionScheme->getStartTime() ) || + ( stopTime != currCollectionScheme->getExpiryTime() ) ) ) { // this collectionScheme is an idle collectionScheme, and its startTime or ExpiryTime // or both need updated mIdleCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( make_pair( startTime, id ) ); - mTimeLine.push( make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, startTime ), id } ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); } } else @@ -619,18 +643,18 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime std::string addStr; addStr = "Adding new collectionScheme: "; printEventLogMsg( addStr, id, startTime, stopTime, currTime ); - mLogger.trace( "collectionSchemeManager::updateMapsandTimeLine ", addStr ); - if ( startTime <= currTime && stopTime > currTime ) + mLogger.trace( "CollectionSchemeManager::updateMapsandTimeLine", addStr ); + if ( ( startTime <= currTime.systemTimeMs ) && ( stopTime > currTime.systemTimeMs ) ) { mEnabledCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); ret = true; } - else if ( startTime > currTime ) + else if ( startTime > currTime.systemTimeMs ) { mIdleCollectionSchemeMap[id] = collectionScheme; - mTimeLine.push( std::make_pair( startTime, id ) ); - mTimeLine.push( std::make_pair( stopTime, id ) ); + mTimeLine.push( { calculateMonotonicTime( currTime, startTime ), id } ); + mTimeLine.push( { calculateMonotonicTime( currTime, stopTime ), id } ); } } } @@ -695,10 +719,10 @@ CollectionSchemeManager::updateMapsandTimeLine( const TimePointInMsec &currTime * returns true when enabled map changes; */ bool -CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) +CollectionSchemeManager::checkTimeLine( const TimePoint &currTime ) { bool ret = false; - if ( mTimeLine.empty() || currTime < mTimeLine.top().first ) + if ( ( mTimeLine.empty() ) || ( currTime.monotonicTimeMs < mTimeLine.top().time.monotonicTimeMs ) ) { // Timer has not expired, do nothing return ret; @@ -706,14 +730,14 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) while ( !mTimeLine.empty() ) { const auto &topPair = mTimeLine.top(); - const std::string &topCollectionSchemeID = topPair.second; - const TimePointInMsec &topTime = topPair.first; + const std::string &topCollectionSchemeID = topPair.id; + const TimePoint &topTime = topPair.time; if ( topCollectionSchemeID == CHECKIN ) { // for checkin, we are about to // either serve current checkin event, and move on to search for next timePoint to set up timer; // or we find current checkin for setting up next timer, then we are done here; - if ( currTime < topTime ) + if ( currTime.monotonicTimeMs < topTime.monotonicTimeMs ) { // Successfully locate next checkin as timePoint to set up timer // time to exit @@ -728,9 +752,9 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) { if ( mCheckinIntervalInMsec > 0 ) { - TimePointInMsec nextCheckinTime = currTime + mCheckinIntervalInMsec; - TimeData newPair = std::make_pair( nextCheckinTime, CHECKIN ); - mTimeLine.push( newPair ); + TimePoint nextCheckinTime = { currTime.systemTimeMs + mCheckinIntervalInMsec, + currTime.monotonicTimeMs + mCheckinIntervalInMsec }; + mTimeLine.push( { nextCheckinTime, CHECKIN } ); } // else, no checkin message is scheduled. } @@ -740,9 +764,9 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) // Calculate the minimum retry interval uint64_t minimumCheckinInterval = std::min( static_cast( RETRY_CHECKIN_INTERVAL_IN_MILLISECOND ), mCheckinIntervalInMsec ); - TimePointInMsec nextCheckinTime = currTime + minimumCheckinInterval; - TimeData newPair = std::make_pair( nextCheckinTime, CHECKIN ); - mTimeLine.push( newPair ); + TimePoint nextCheckinTime = { currTime.systemTimeMs + minimumCheckinInterval, + currTime.monotonicTimeMs + minimumCheckinInterval }; + mTimeLine.push( { nextCheckinTime, CHECKIN } ); } // after sending checkin, the work on this dataPair is done, move to next dataPair @@ -767,7 +791,7 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) // client request, this dataPair is obsolete, just drop it // keep searching for next valid TimePoint // to set up timer - mLogger.trace( "CollectionSchemeManager::checkTimeLine ", + mLogger.trace( "CollectionSchemeManager::checkTimeLine", "CollectionScheme not found: " + topCollectionSchemeID ); mTimeLine.pop(); continue; @@ -776,7 +800,7 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) } // found it, continue examining topTime ICollectionSchemePtr currCollectionScheme; - TimePointInMsec timeOfInterest = 0ULL; + Timestamp timeOfInterest = 0ULL; if ( foundInEnabled ) { // This collectionScheme is found in mEnabledCollectionSchemeMap @@ -791,16 +815,16 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) currCollectionScheme = mIdleCollectionSchemeMap[topCollectionSchemeID]; timeOfInterest = currCollectionScheme->getStartTime(); } - if ( timeOfInterest != topTime ) + if ( timeOfInterest != topTime.systemTimeMs ) { // 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 + + mLogger.trace( "CollectionSchemeManager::checkTimeLine", + "Found collectionScheme: " + topCollectionSchemeID + " but time does not match: " "topTime " + - std::to_string( topTime ) + " timeFromCollectionScheme " + + std::to_string( topTime.systemTimeMs ) + " timeFromCollectionScheme " + std::to_string( timeOfInterest ) ); mTimeLine.pop(); continue; @@ -808,7 +832,7 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) // now we have a dataPair with valid collectionScheme ID, and valid start/stop time // Check if it is time to enable/disable this collectionScheme, or else // topTime is far down the timeline, it is a timePoint to set up next timer. - if ( topTime <= currTime ) + if ( topTime.monotonicTimeMs <= currTime.monotonicTimeMs ) { ret = true; // it is time to enable or disable this collectionScheme @@ -824,7 +848,7 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) currCollectionScheme->getStartTime(), currCollectionScheme->getExpiryTime(), topTime ); - mLogger.info( "CollectionSchemeManager::checkTimeLine ", enableStr ); + mLogger.info( "CollectionSchemeManager::checkTimeLine", enableStr ); } else { @@ -836,7 +860,7 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) currCollectionScheme->getStartTime(), currCollectionScheme->getExpiryTime(), topTime ); - mLogger.info( "CollectionSchemeManager::checkTimeLine ", disableStr ); + mLogger.info( "CollectionSchemeManager::checkTimeLine", disableStr ); mEnabledCollectionSchemeMap.erase( topCollectionSchemeID ); } } @@ -851,9 +875,9 @@ CollectionSchemeManager::checkTimeLine( const TimePointInMsec &currTime ) } if ( !mTimeLine.empty() ) { - mLogger.trace( "CollectionSchemeManager::checkTimeLine ", - "top pair: " + std::to_string( mTimeLine.top().first ) + " " + mTimeLine.top().second + - " currTime: " + std::to_string( currTime ) ); + mLogger.trace( "CollectionSchemeManager::checkTimeLine", + "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 13d151fe..fc7f22c2 100644 --- a/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp +++ b/src/datamanagement/datamanager/src/DecoderDictionaryExtractor.cpp @@ -13,6 +13,7 @@ namespace IoTFleetWise { namespace DataManagement { + constexpr std::array CollectionSchemeManager::SUPPORTED_NETWORK_PROTOCOL; void CollectionSchemeManager::decoderDictionaryExtractor( @@ -165,8 +166,9 @@ CollectionSchemeManager::decoderDictionaryExtractor( } // check if we already have entry for CAN Frame. If not, it means this CAN Frame doesn't contain any // Signals to decode, hence the collectType will be RAW only. - if ( canDecoderDictionaryPtr->canMessageDecoderMethod[canChannelID].find( canFrameInfo.frameID ) == - canDecoderDictionaryPtr->canMessageDecoderMethod[canChannelID].end() ) + auto decoderMethod = + canDecoderDictionaryPtr->canMessageDecoderMethod[canChannelID].find( canFrameInfo.frameID ); + if ( decoderMethod == canDecoderDictionaryPtr->canMessageDecoderMethod[canChannelID].end() ) { // there's entry for CANChannelNumericID but no corresponding canFrameID CANMessageDecoderMethod canMessageDecoderMethod; @@ -176,11 +178,12 @@ CollectionSchemeManager::decoderDictionaryExtractor( } else { - // This CAN Frame contains signal to be decoded. As we need to collect both CAN Frame and - // signal, set the collectType as RAW_AND_DECODE - canDecoderDictionaryPtr->canMessageDecoderMethod.at( canChannelID ) - .at( canFrameInfo.frameID ) - .collectType = CANMessageCollectType::RAW_AND_DECODE; + if ( decoderMethod->second.collectType == CANMessageCollectType::DECODE ) + { + // This CAN Frame contains signal to be decoded. As we need to collect both CAN Frame and + // signal, set the collectType as RAW_AND_DECODE + decoderMethod->second.collectType = CANMessageCollectType::RAW_AND_DECODE; + } } } } diff --git a/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp b/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp index 7ad008a0..65b1e0cd 100644 --- a/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp +++ b/src/datamanagement/datamanager/src/InspectionMatrixExtractor.cpp @@ -18,7 +18,7 @@ void CollectionSchemeManager::addConditionData( const ICollectionSchemePtr &collectionScheme, ConditionWithCollectedData &conditionData ) { - conditionData.minimumPublishInterval = collectionScheme->getMinimumPublishIntervalMs(); + conditionData.minimumPublishIntervalMs = collectionScheme->getMinimumPublishIntervalMs(); conditionData.afterDuration = collectionScheme->getAfterDurationMs(); conditionData.includeActiveDtcs = collectionScheme->isActiveDTCsIncluded(); conditionData.triggerOnlyOnRisingEdge = collectionScheme->isTriggerOnlyOnRisingEdge(); @@ -52,7 +52,7 @@ CollectionSchemeManager::addConditionData( const ICollectionSchemePtr &collectio if ( CANFrame.channelID == INVALID_CAN_SOURCE_NUMERIC_ID ) { mLogger.warn( "CollectionSchemeManager::addConditionData", - "Invalid Interface ID provided:" + collectionCANFrames[i].interfaceID ); + "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 5a83618a..91d0149a 100644 --- a/src/datamanagement/datamanager/src/Schema.cpp +++ b/src/datamanagement/datamanager/src/Schema.cpp @@ -52,7 +52,7 @@ Schema::sendCheckin( const std::vector &documentARNs ) } // Add the timestamp - mProtoCheckinMsg.set_timestamp_ms_epoch( mClock->timeSinceEpochMs() ); + mProtoCheckinMsg.set_timestamp_ms_epoch( mClock->systemTimeSinceEpochMs() ); if ( !mProtoCheckinMsg.SerializeToString( &mProtoCheckinMsgOutput ) ) { @@ -90,9 +90,13 @@ Schema::transmitCheckin() for ( int i = 0; i < mProtoCheckinMsg.document_arns_size(); i++ ) { - checkinDebugString += " " + mProtoCheckinMsg.document_arns( i ); + if ( i > 0 ) + { + checkinDebugString += ", "; + } + checkinDebugString += mProtoCheckinMsg.document_arns( i ); } - checkinDebugString += " ]. "; + checkinDebugString += "]"; mLogger.trace( "Schema::transmitCheckin", checkinDebugString ); return true; diff --git a/src/datamanagement/datamanager/test/CheckinAndPersistencyTest.cpp b/src/datamanagement/datamanager/test/CheckinAndPersistencyTest.cpp index f4da4eb9..9d60db78 100644 --- a/src/datamanagement/datamanager/test/CheckinAndPersistencyTest.cpp +++ b/src/datamanagement/datamanager/test/CheckinAndPersistencyTest.cpp @@ -33,10 +33,10 @@ TEST( CollectionSchemeManagerTest2, checkInScheduleLogicTest ) // setup maps NiceMock gmocktest( strDecoderManifestID1, mapEnable, mapEmpty ); std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); + TimePoint currTime = testClock->timeSinceEpoch(); // create mTimeLine std::priority_queue, std::greater> testTimeLine; - TimeData dataPair = std::make_pair( currTime, "Checkin" ); + TimeData dataPair = { currTime, "Checkin" }; testTimeLine.push( dataPair ); // test code CANInterfaceIDTranslator canIDTranslator; @@ -45,8 +45,8 @@ TEST( CollectionSchemeManagerTest2, checkInScheduleLogicTest ) gmocktest.checkTimeLine( currTime ); // We should have popped one item from the TimeLine, but also scheduled another one for the next cycle. TimeData topPair = gmocktest.getTimeLine().top(); - ASSERT_EQ( topPair.first, currTime + 200 ); - ASSERT_EQ( topPair.second, "Checkin" ); + ASSERT_EQ( topPair.time.monotonicTimeMs, currTime.monotonicTimeMs + 200 ); + ASSERT_EQ( topPair.id, "Checkin" ); } /** @brief diff --git a/src/datamanagement/datamanager/test/CollectionSchemeManagerGtest.cpp b/src/datamanagement/datamanager/test/CollectionSchemeManagerGtest.cpp index 6b752230..d89fda4d 100644 --- a/src/datamanagement/datamanager/test/CollectionSchemeManagerGtest.cpp +++ b/src/datamanagement/datamanager/test/CollectionSchemeManagerGtest.cpp @@ -3,12 +3,14 @@ #include "CollectionSchemeManagerMock.h" #include "CollectionSchemeManagerTest.h" +#include "Testing.h" #include using ::testing::_; using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; +using namespace Aws::IoTFleetWise::TestingSupport; /** @brief * This test validates the life cycle of the Collection Schemes as they get @@ -23,13 +25,13 @@ TEST( CollectionSchemeManagerGtest, RebuildUpdateAndTimeLineTest ) std::string strDecoderManifestIDCollectionScheme1 = "DM1"; std::string strDecoderManifestIDCollectionScheme2 = "DM2"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startIdleTime = currTime + 10; - TimePointInMsec stopIdleTime = currTime + 50; + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startIdleTime = currTime.systemTimeMs + 10; + Timestamp stopIdleTime = currTime.systemTimeMs + 50; - TimePointInMsec startEnableTime = currTime - 50; - TimePointInMsec stopEnableTime = currTime + 10; - TimePointInMsec stopDisableTime = currTime - 10; + Timestamp startEnableTime = currTime.systemTimeMs - 50; + Timestamp stopEnableTime = currTime.systemTimeMs + 10; + Timestamp stopDisableTime = currTime.systemTimeMs - 10; // build decodermanifest, collectionScheme, collectionSchemeList std::shared_ptr testDM1 = std::make_shared(); std::shared_ptr collectionScheme1 = std::make_shared(); @@ -108,15 +110,15 @@ TEST( CollectionSchemeManagerGtest, updateMapsandTimeLineTest_ADD_DELETE ) std::string strDecoderManifestIDCollectionScheme1 = "DM1"; std::string strDecoderManifestIDCollectionScheme2 = "DM2"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startIdleTime = currTime + 10; - TimePointInMsec stopIdleTime = currTime + 50; + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startIdleTime = currTime.systemTimeMs + 10; + Timestamp stopIdleTime = currTime.systemTimeMs + 50; - TimePointInMsec startEnableTime = currTime - 50; - TimePointInMsec stopEnableTime = currTime + 10; + Timestamp startEnableTime = currTime.systemTimeMs - 50; + Timestamp stopEnableTime = currTime.systemTimeMs + 10; - TimePointInMsec startBadTime = currTime - 50; - TimePointInMsec stopBadTime = currTime - 10; + Timestamp startBadTime = currTime.systemTimeMs - 50; + Timestamp stopBadTime = currTime.systemTimeMs - 10; // build decodermanifest, collectionScheme, collectionSchemeList std::shared_ptr testDM1 = std::make_shared(); std::shared_ptr collectionScheme1 = std::make_shared(); @@ -211,18 +213,18 @@ TEST( CollectionSchemeManagerGtest, updateMapsandTimeLineTest_IDLE_BRANCHES ) std::string strDecoderManifestIDCollectionScheme1 = "DM1"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startIdleTime = currTime + 10; - TimePointInMsec stopIdleTime = currTime + 50; + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startIdleTime = currTime.systemTimeMs + 10; + Timestamp stopIdleTime = currTime.systemTimeMs + 50; - TimePointInMsec startEnableTime = currTime - 20; - TimePointInMsec stopEnableTime = currTime + 10; + Timestamp startEnableTime = currTime.systemTimeMs - 20; + Timestamp stopEnableTime = currTime.systemTimeMs + 10; - TimePointInMsec start1Time = currTime + 50; - TimePointInMsec stop1Time = currTime - 10; + Timestamp start1Time = currTime.systemTimeMs + 50; + Timestamp stop1Time = currTime.systemTimeMs - 10; - TimePointInMsec start2Time = currTime - 50; - TimePointInMsec stop2Time = currTime - 10; + Timestamp start2Time = currTime.systemTimeMs - 50; + Timestamp stop2Time = currTime.systemTimeMs - 10; // build decodermanifest, collectionScheme, collectionSchemeList std::shared_ptr testDM1 = std::make_shared(); @@ -328,18 +330,18 @@ TEST( CollectionSchemeManagerGtest, updateMapsandTimeLineTest_ENABLED_BRANCHES ) std::string strDecoderManifestIDCollectionScheme1 = "DM1"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startExpTime = currTime + 10; - TimePointInMsec stopExpTime = currTime; + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startExpTime = currTime.systemTimeMs + 10; + Timestamp stopExpTime = currTime.systemTimeMs; - TimePointInMsec startEnableTime = currTime - 20; - TimePointInMsec stopEnableTime = currTime + 50; + Timestamp startEnableTime = currTime.systemTimeMs - 20; + Timestamp stopEnableTime = currTime.systemTimeMs + 50; - TimePointInMsec start1Time = currTime; - TimePointInMsec stop1Time = currTime + 50; + Timestamp start1Time = currTime.systemTimeMs; + Timestamp stop1Time = currTime.systemTimeMs + 50; - TimePointInMsec start2Time = currTime - 50; - TimePointInMsec stop2Time = currTime + 100; + Timestamp start2Time = currTime.systemTimeMs - 50; + Timestamp stop2Time = currTime.systemTimeMs + 100; // build decodermanifest, collectionScheme, collectionSchemeList std::shared_ptr testDM1 = std::make_shared(); @@ -428,7 +430,7 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_CHECKIN_UNFOUNDCOLLECTIONS std::string strCollectionSchemeIDCollectionScheme2 = "COLLECTIONSCHEME2"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); + TimePoint currTime = testClock->timeSinceEpoch(); // create empty collectionScheme map std::map mapEmpty; @@ -438,15 +440,15 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_CHECKIN_UNFOUNDCOLLECTIONS // setup maps NiceMock gmocktest( strDecoderManifestID1, mapEmpty, mapIdle ); - EXPECT_CALL( *collectionScheme2, getStartTime() ).WillOnce( Return( currTime + 20 ) ); + EXPECT_CALL( *collectionScheme2, getStartTime() ).WillOnce( Return( currTime.systemTimeMs + 20 ) ); // create mTimeLine std::priority_queue, std::greater> testTimeLine; - TimeData dataPair = std::make_pair( currTime, "Checkin" ); + TimeData dataPair = { currTime, "Checkin" }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime, strCollectionSchemeIDCollectionScheme1 ); + dataPair = { currTime, strCollectionSchemeIDCollectionScheme1 }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime, strCollectionSchemeIDCollectionScheme2 ); + dataPair = { currTime, strCollectionSchemeIDCollectionScheme2 }; testTimeLine.push( dataPair ); // test code @@ -473,7 +475,7 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_IDLE_BRANCHES ) std::string strCollectionSchemeIDCollectionScheme2 = "COLLECTIONSCHEME2"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); + TimePoint currTime = testClock->timeSinceEpoch(); // create empty collectionScheme map std::shared_ptr collectionScheme1 = std::make_shared(); @@ -485,25 +487,27 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_IDLE_BRANCHES ) // setup maps NiceMock gmocktest( strDecoderManifestID1, mapEmpty, mapIdle ); - EXPECT_CALL( *collectionScheme1, getStartTime() ).WillOnce( Return( currTime ) ).WillOnce( Return( currTime ) ); - EXPECT_CALL( *collectionScheme1, getExpiryTime() ).WillOnce( Return( currTime + 100 ) ); + EXPECT_CALL( *collectionScheme1, getStartTime() ) + .WillOnce( Return( currTime.systemTimeMs ) ) + .WillOnce( Return( currTime.systemTimeMs ) ); + EXPECT_CALL( *collectionScheme1, getExpiryTime() ).WillOnce( Return( currTime.systemTimeMs + 100 ) ); EXPECT_CALL( *collectionScheme2, getStartTime() ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ); - EXPECT_CALL( *collectionScheme2, getExpiryTime() ).WillOnce( Return( currTime + 200 ) ); + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ); + EXPECT_CALL( *collectionScheme2, getExpiryTime() ).WillOnce( Return( currTime.systemTimeMs + 200 ) ); // create mTimeLine std::priority_queue, std::greater> testTimeLine; - TimeData dataPair = std::make_pair( currTime, "Checkin" ); + TimeData dataPair = { currTime, "Checkin" }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime, strCollectionSchemeIDCollectionScheme1 ); + dataPair = { currTime, strCollectionSchemeIDCollectionScheme1 }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime + 10, strCollectionSchemeIDCollectionScheme2 ); + dataPair = { currTime + 10, strCollectionSchemeIDCollectionScheme2 }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime + 20, strCollectionSchemeIDCollectionScheme2 ); + dataPair = { currTime + 20, strCollectionSchemeIDCollectionScheme2 }; testTimeLine.push( dataPair ); // test code @@ -528,7 +532,7 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_ENABLED_BRANCHES ) std::string strCollectionSchemeIDCollectionScheme2 = "COLLECTIONSCHEME2"; std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); + TimePoint currTime = testClock->timeSinceEpoch(); // create empty collectionScheme map std::shared_ptr collectionScheme1 = std::make_shared(); @@ -540,25 +544,27 @@ TEST( CollectionSchemeManagerGtest, checkTimeLineTest_ENABLED_BRANCHES ) // setup maps NiceMock gmocktest( strDecoderManifestID1, mapEnable, mapEmpty ); - EXPECT_CALL( *collectionScheme1, getExpiryTime() ).WillOnce( Return( currTime ) ).WillOnce( Return( currTime ) ); - EXPECT_CALL( *collectionScheme1, getStartTime() ).WillOnce( Return( currTime - 100 ) ); + EXPECT_CALL( *collectionScheme1, getExpiryTime() ) + .WillOnce( Return( currTime.systemTimeMs ) ) + .WillOnce( Return( currTime.systemTimeMs ) ); + EXPECT_CALL( *collectionScheme1, getStartTime() ).WillOnce( Return( currTime.systemTimeMs - 100 ) ); EXPECT_CALL( *collectionScheme2, getExpiryTime() ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ) - .WillOnce( Return( currTime + 20 ) ); - EXPECT_CALL( *collectionScheme2, getStartTime() ).WillOnce( Return( currTime - 200 ) ); + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ) + .WillOnce( Return( currTime.systemTimeMs + 20 ) ); + EXPECT_CALL( *collectionScheme2, getStartTime() ).WillOnce( Return( currTime.systemTimeMs - 200 ) ); // create mTimeLine std::priority_queue, std::greater> testTimeLine; - TimeData dataPair = std::make_pair( currTime, "Checkin" ); + TimeData dataPair = { currTime, "Checkin" }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime, strCollectionSchemeIDCollectionScheme1 ); + dataPair = { currTime, strCollectionSchemeIDCollectionScheme1 }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime + 10, strCollectionSchemeIDCollectionScheme2 ); + dataPair = { currTime + 10, strCollectionSchemeIDCollectionScheme2 }; testTimeLine.push( dataPair ); - dataPair = std::make_pair( currTime + 20, strCollectionSchemeIDCollectionScheme2 ); + dataPair = { currTime + 20, strCollectionSchemeIDCollectionScheme2 }; testTimeLine.push( dataPair ); // test code diff --git a/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp b/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp index 3958e0a9..b4570b1f 100644 --- a/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp +++ b/src/datamanagement/datamanager/test/CollectionSchemeManagerTest.cpp @@ -23,9 +23,9 @@ TEST( CollectionSchemeManagerTest, StopMainTest ) /* build collectionScheme list1 */ std::shared_ptr testClock = ClockHandler::getClock(); /* mock currTime, and 3 collectionSchemes */ - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startTime = currTime + SECOND_TO_MILLISECOND( 1 ); - TimePointInMsec stopTime = startTime + SECOND_TO_MILLISECOND( 25 ); + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startTime = currTime.systemTimeMs + SECOND_TO_MILLISECOND( 1 ); + Timestamp stopTime = startTime + SECOND_TO_MILLISECOND( 25 ); ICollectionSchemePtr collectionScheme = std::make_shared( "COLLECTIONSCHEME1", "DM1", startTime, stopTime ); testList1.emplace_back( collectionScheme ); @@ -135,14 +135,14 @@ TEST( CollectionSchemeManagerTest, MockProducerTest ) /* build collectionScheme list1 */ std::shared_ptr testClock = ClockHandler::getClock(); - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startTime = currTime + 100; - TimePointInMsec stopTime = startTime + 500; + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startTime = currTime.systemTimeMs + 100; + Timestamp stopTime = startTime + 500; ICollectionSchemePtr collectionScheme = std::make_shared( "COLLECTIONSCHEME1", "DM1", startTime, stopTime ); testList1.emplace_back( collectionScheme ); - startTime = currTime + 300; + startTime = currTime.systemTimeMs + 300; stopTime = startTime + 500; collectionScheme = std::make_shared( "COLLECTIONSCHEME2", "DM1", startTime, stopTime ); testList1.emplace_back( collectionScheme ); @@ -167,8 +167,8 @@ TEST( CollectionSchemeManagerTest, MockProducerTest ) /* add COLLECTIONSCHEME3 */ std::cout << COUT_GTEST_MGT << "Step3: add COLLECTIONSCHEME3 " << ANSI_TXT_DFT << std::endl; - currTime = testClock->timeSinceEpochMs(); - startTime = currTime + 100; + currTime = testClock->timeSinceEpoch(); + startTime = currTime.systemTimeMs + 100; stopTime = startTime + 500; collectionScheme = std::make_shared( "COLLECTIONSCHEME3", "DM1", startTime, stopTime ); testList2.emplace_back( collectionScheme ); @@ -193,12 +193,12 @@ TEST( CollectionSchemeManagerTest, MockProducerTest ) std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); /* build list3 with DM2 */ - currTime = testClock->timeSinceEpochMs(); - startTime = currTime + 100; + currTime = testClock->timeSinceEpoch(); + startTime = currTime.systemTimeMs + 100; stopTime = startTime + 500; collectionScheme = std::make_shared( "COLLECTIONSCHEME4", "DM2", startTime, stopTime ); testList3.emplace_back( collectionScheme ); - startTime = currTime + 200; + startTime = currTime.systemTimeMs + 200; stopTime = startTime + 500; collectionScheme = std::make_shared( "COLLECTIONSCHEME5", "DM2", startTime, stopTime ); testList3.emplace_back( collectionScheme ); diff --git a/src/datamanagement/datamanager/test/DecoderDictionaryExtractorTest.cpp b/src/datamanagement/datamanager/test/DecoderDictionaryExtractorTest.cpp index 8dbc1c3e..5cd60213 100644 --- a/src/datamanagement/datamanager/test/DecoderDictionaryExtractorTest.cpp +++ b/src/datamanagement/datamanager/test/DecoderDictionaryExtractorTest.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "CollectionSchemeManagerTest.h" +#include "Testing.h" + +using namespace Aws::IoTFleetWise::TestingSupport; /** @brief * This test aims to test CollectionScheme Manager's Decoder Dictionary Extractor functionality @@ -84,13 +87,13 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) test.init( 0, nullptr, canIDTranslator ); std::shared_ptr testClock = ClockHandler::getClock(); /* mock currTime, and 3 collectionSchemes */ - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startTime1 = currTime; - TimePointInMsec stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); - TimePointInMsec startTime2 = startTime1; - TimePointInMsec stopTime2 = startTime2 + SECOND_TO_MILLISECOND( 5 ); - TimePointInMsec startTime3 = startTime1 + SECOND_TO_MILLISECOND( 6 ); - TimePointInMsec stopTime3 = startTime3 + SECOND_TO_MILLISECOND( 5 ); + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startTime1 = currTime.systemTimeMs; + Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); + Timestamp startTime2 = startTime1; + Timestamp stopTime2 = startTime2 + SECOND_TO_MILLISECOND( 5 ); + Timestamp startTime3 = startTime1 + SECOND_TO_MILLISECOND( 6 ); + Timestamp stopTime3 = startTime3 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) std::unordered_map> signalToFrameAndNodeID; @@ -427,7 +430,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) ICollectionSchemeListPtr PL2 = std::make_shared( list2 ); test2.setCollectionSchemeList( PL2 ); // Both collectionScheme1 and collectionScheme2 are expected to be enabled - ASSERT_TRUE( test2.updateMapsandTimeLine( 1635951061244 ) ); + ASSERT_TRUE( test2.updateMapsandTimeLine( { 1635951061244, 100 } ) ); // Invoke Decoder Dictionary Extractor function std::map> decoderDictionaryMap2; test2.decoderDictionaryExtractor( decoderDictionaryMap2 ); @@ -483,9 +486,9 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorNoSignalsTest ) test.init( 0, nullptr, canIDTranslator ); std::shared_ptr testClock = ClockHandler::getClock(); /* mock currTime, and 3 collectionSchemes */ - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startTime1 = currTime; - TimePointInMsec stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startTime1 = currTime.systemTimeMs; + Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) std::unordered_map> signalToFrameAndNodeID; @@ -542,9 +545,9 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorFirstRawFrameThenSi test.init( 0, nullptr, canIDTranslator ); std::shared_ptr testClock = ClockHandler::getClock(); /* mock currTime, and 3 collectionSchemes */ - TimePointInMsec currTime = testClock->timeSinceEpochMs(); - TimePointInMsec startTime1 = currTime; - TimePointInMsec stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); + TimePoint currTime = testClock->timeSinceEpoch(); + Timestamp startTime1 = currTime.systemTimeMs; + Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) std::unordered_map> signalToFrameAndNodeID; diff --git a/src/datamanagement/datamanager/test/InspectionMatrixExtractorTest.cpp b/src/datamanagement/datamanager/test/InspectionMatrixExtractorTest.cpp index 9e181ffe..1bb5c692 100644 --- a/src/datamanagement/datamanager/test/InspectionMatrixExtractorTest.cpp +++ b/src/datamanagement/datamanager/test/InspectionMatrixExtractorTest.cpp @@ -149,7 +149,7 @@ TEST( CollectionSchemeManager, InpsectionMatrixExtractorTreeTest ) test.setDecoderManifest( DM1 ); test.setCollectionSchemeList( PL1 ); // All three polices are expected to be enabled - ASSERT_TRUE( test.updateMapsandTimeLine( 0 ) ); + ASSERT_TRUE( test.updateMapsandTimeLine( { 0, 0 } ) ); std::shared_ptr output = std::make_shared(); test.inspectionMatrixExtractor( output ); @@ -202,7 +202,7 @@ TEST( CollectionSchemeManager, InpsectionMatrixExtractorConditionDataTest ) test.setDecoderManifest( DM1 ); test.setCollectionSchemeList( PL1 ); - ASSERT_TRUE( test.updateMapsandTimeLine( 0 ) ); + ASSERT_TRUE( test.updateMapsandTimeLine( { 0, 0 } ) ); std::shared_ptr output = std::make_shared(); test.inspectionMatrixExtractor( output ); for ( auto conditionData : output->conditions ) diff --git a/src/datamanagement/datamanager/test/SchemaTest.cpp b/src/datamanagement/datamanager/test/SchemaTest.cpp index 528b52cc..3f23321c 100644 --- a/src/datamanagement/datamanager/test/SchemaTest.cpp +++ b/src/datamanagement/datamanager/test/SchemaTest.cpp @@ -116,7 +116,7 @@ class CheckinTest : public ::testing::Test // Make sure the checkin time is after the time we took at the start of the test ASSERT_GE( sentCheckin.timestamp_ms_epoch(), timeBeforeCheckin ); // Make sure the checkin time is before or equal to this time - ASSERT_LE( sentCheckin.timestamp_ms_epoch(), clock->timeSinceEpochMs() ); + ASSERT_LE( sentCheckin.timestamp_ms_epoch(), clock->systemTimeSinceEpochMs() ); } }; @@ -133,7 +133,7 @@ TEST( CollectionSchemeIgestionTest, Checkins ) mockSender ); std::shared_ptr clock = ClockHandler::getClock(); - Timestamp timeBeforeCheckin = clock->timeSinceEpochMs(); + Timestamp timeBeforeCheckin = clock->systemTimeSinceEpochMs(); // Create list of Arns std::vector sampleDocList; diff --git a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h index 242e800a..07c981d4 100644 --- a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h +++ b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerMock.h @@ -93,19 +93,19 @@ class mockCollectionSchemeManagerTest : public CollectionSchemeManager } bool - rebuildMapsandTimeLine( const TimePointInMsec &currTime ) + rebuildMapsandTimeLine( const TimePoint &currTime ) { return CollectionSchemeManager::rebuildMapsandTimeLine( currTime ); } bool - updateMapsandTimeLine( const TimePointInMsec &currTime ) + updateMapsandTimeLine( const TimePoint &currTime ) { return CollectionSchemeManager::updateMapsandTimeLine( currTime ); } bool - checkTimeLine( const TimePointInMsec &currTime ) + checkTimeLine( const TimePoint &currTime ) { return CollectionSchemeManager::checkTimeLine( currTime ); } diff --git a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerTest.h b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerTest.h index f15a815f..b1bbb150 100644 --- a/src/datamanagement/datamanager/test/include/CollectionSchemeManagerTest.h +++ b/src/datamanagement/datamanager/test/include/CollectionSchemeManagerTest.h @@ -392,17 +392,17 @@ class CollectionSchemeManagerTest : public CollectionSchemeManager CollectionSchemeManager::updateAvailable(); } bool - rebuildMapsandTimeLine( const TimePointInMsec &currTime ) + rebuildMapsandTimeLine( const TimePoint &currTime ) { return ( CollectionSchemeManager::rebuildMapsandTimeLine( currTime ) ); } bool - updateMapsandTimeLine( const TimePointInMsec &currTime ) + updateMapsandTimeLine( const TimePoint &currTime ) { return CollectionSchemeManager::updateMapsandTimeLine( currTime ); } bool - checkTimeLine( const TimePointInMsec &currTime ) + checkTimeLine( const TimePoint &currTime ) { return ( CollectionSchemeManager::checkTimeLine( currTime ) ); } diff --git a/src/datamanagement/types/CMakeLists.txt b/src/datamanagement/types/CMakeLists.txt index d0855011..255a1739 100644 --- a/src/datamanagement/types/CMakeLists.txt +++ b/src/datamanagement/types/CMakeLists.txt @@ -5,11 +5,7 @@ set(libraryTargetName iotfleetwise.datamanagement.types) set(libraryAliasName IoTFleetWise::DataManagementTypes) set(SRCS - src/CollectionInspectionAPITypes.cpp - src/CANDataTypes.cpp - src/Geohash.cpp - src/GeohashInfo.cpp - src/OBDDataTypes.cpp + src/Geohash.cpp ) add_library( @@ -55,7 +51,6 @@ if(${BUILD_TESTING}) testSources test/GeohashTest.cpp ) - find_package(GTest REQUIRED) # Add the executable targets foreach(testSource ${testSources}) @@ -63,12 +58,12 @@ if(${BUILD_TESTING}) get_filename_component(testName ${testSource} NAME_WE) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_test(NAME ${testName} COMMAND ${testName} --gtest_output=xml:report-${testName}.xml) add_valgrind_test(${testName}) diff --git a/src/datamanagement/types/include/CollectionInspectionAPITypes.h b/src/datamanagement/types/include/CollectionInspectionAPITypes.h index 7063f1b1..455dea5e 100644 --- a/src/datamanagement/types/include/CollectionInspectionAPITypes.h +++ b/src/datamanagement/types/include/CollectionInspectionAPITypes.h @@ -99,7 +99,7 @@ struct ConditionWithCollectedData const ExpressionNode *condition; /**< points into InspectionMatrix.expressionNodes; * Raw pointer is used as needed for efficient AST and ConditionWithCollectedData * never exists without the relevant InspectionMatrix */ - uint32_t minimumPublishInterval; + uint32_t minimumPublishIntervalMs; uint32_t afterDuration; std::vector signals; std::vector canFrames; diff --git a/src/datamanagement/types/include/MessageTypes.h b/src/datamanagement/types/include/MessageTypes.h index ca5e970b..567f4612 100644 --- a/src/datamanagement/types/include/MessageTypes.h +++ b/src/datamanagement/types/include/MessageTypes.h @@ -34,8 +34,8 @@ struct CANMessageFormat bool operator==( const CANMessageFormat &other ) const { - return mMessageID == other.mMessageID && mSizeInBytes == other.mSizeInBytes && mSignals == other.mSignals && - mIsMultiplexed == other.mIsMultiplexed; + return ( mMessageID == other.mMessageID ) && ( mSizeInBytes == other.mSizeInBytes ) && + ( mSignals == other.mSignals ) && ( mIsMultiplexed == other.mIsMultiplexed ); } /** diff --git a/src/datamanagement/types/include/OBDDataTypes.h b/src/datamanagement/types/include/OBDDataTypes.h index a47a545b..b9818379 100644 --- a/src/datamanagement/types/include/OBDDataTypes.h +++ b/src/datamanagement/types/include/OBDDataTypes.h @@ -124,154 +124,6 @@ class PIDSignalFormula } }; -// Struct represent PID information: id, return length and formula for each signal -struct PIDInfo -{ - PID pid; // id for PID, used to query ECU - size_t retLen; // expected number of bytes in response - std::vector - formulas; // formula per signal. For multi-signal PID, this would contains multiple formulas. -}; - -// clang-format off -// Subset of Emission related PIDs that are supported by this SW -// Every new PID we support should be updated on those next -// structs -enum class EmissionPIDs -{ - PIDS_SUPPORTED_01_20 = 0X00, - FUEL_SYSTEM_STATUS = 0X03, - ENGINE_LOAD = 0X04, - ENGINE_COOLANT_TEMPERATURE = 0X05, - SHORT_TERM_FUEL_TRIM_BANK_1 = 0X06, - LONG_TERM_FUEL_TRIM_BANK_1 = 0X07, - SHORT_TERM_FUEL_TRIM_BANK_2 = 0X08, - LONG_TERM_FUEL_TRIM_BANK_2 = 0X09, - FUEL_PRESSURE = 0X0A, - INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 0X0B, - ENGINE_SPEED = 0X0C, - VEHICLE_SPEED = 0X0D, - TIMING_ADVANCE = 0X0E, - INTAKE_AIR_FLOW_TEMPERATURE = 0X0F, - MAF_RATE = 0X10, - THROTTLE_POSITION = 0X11, - OXYGEN_SENSORS_PRESENT = 0X13, - OXYGEN_SENSOR1_1 = 0X14, - OXYGEN_SENSOR2_1 = 0X15, - OXYGEN_SENSOR3_1 = 0X16, - OXYGEN_SENSOR4_1 = 0X17, - OXYGEN_SENSOR5_1 = 0X18, - OXYGEN_SENSOR6_1 = 0X19, - OXYGEN_SENSOR7_1 = 0X1A, - OXYGEN_SENSOR8_1 = 0X1B, - RUNTIME_SINCE_ENGINE_START = 0X1F, - PIDS_SUPPORTED_21_40 = 0X20, - DISTANCE_TRAVELED_WITH_MIL = 0X21, - FUEL_RAIL_PRESSURE = 0X22, - FUEL_RAIL_GAUGE_PRESSURE = 0X23, - OXYGEN_SENSOR1_2 = 0X24, - OXYGEN_SENSOR2_2 = 0X25, - OXYGEN_SENSOR3_2 = 0X26, - OXYGEN_SENSOR4_2 = 0X27, - OXYGEN_SENSOR5_2 = 0X28, - OXYGEN_SENSOR6_2 = 0X29, - OXYGEN_SENSOR7_2 = 0X2A, - OXYGEN_SENSOR8_2 = 0X2B, - EGR_ERROR = 0X2D, - FUEL_TANK_LEVEL = 0X2F, - WARM_UPS_SINCE_CODES_CLEARED = 0X30, - DISTANCE_TRAVELED_SINCE_CLEARED_DTC = 0X31, - EVAP_SYSTEM_VAPOR_PRESSURE = 0X32, - ABSOLUTE_BAROMETRIC_PRESSURE = 0X33, - OXYGEN_SENSOR1_3 = 0X34, - OXYGEN_SENSOR2_3 = 0X35, - OXYGEN_SENSOR3_3 = 0X36, - OXYGEN_SENSOR4_3 = 0X37, - OXYGEN_SENSOR5_3 = 0X38, - OXYGEN_SENSOR6_3 = 0X39, - OXYGEN_SENSOR7_3 = 0X3A, - OXYGEN_SENSOR8_3 = 0X3B, - CATALYST_TEMPERATURE_BANK1_SENSOR1 = 0X3C, - CATALYST_TEMPERATURE_BANK2_SENSOR1 = 0X3D, - CATALYST_TEMPERATURE_BANK1_SENSOR2 = 0X3E, - CATALYST_TEMPERATURE_BANK2_SENSOR2 = 0X3F, - PIDS_SUPPORTED_41_60 = 0X40, - CONTROL_MODULE_VOLTAGE = 0X42, - ABSOLUTE_LOAD_VALUE = 0X43, - COMMANDED_AIR_FUEL_EQUIVALENCE_RATIO = 0X44, - RELATIVE_THROTTLE_POSITION = 0X45, - AMBIENT_AIR_TEMPERATURE = 0X46, - ABSOLUTE_THROTTLE_POSITION_B = 0X47, - ABSOLUTE_THROTTLE_POSITION_C = 0X48, - ACCELERATOR_PEDAL_POSITION_D = 0X49, - ACCELERATOR_PEDAL_POSITION_E = 0X4A, - ACCELERATOR_PEDAL_POSITION_F = 0X4B, - TIME_RUN_WITH_MIL_ON = 0X4D, - TIME_SINCE_TROUBLE_CODES_CLEARED = 0X4E, - FUEL_TYPE = 0X51, - ALCOHOL_FUEL_PERCENTAGE = 0X52, - FUEL_RAIL_ABSOLUTE_PRESSURE = 0X59, - RELATIVE_ACCELERATOR_PEDAL_POSITION = 0X5A, - HYBRID_BATTERY_PACK_REMAINING_LIFE = 0X5B, - ENGINE_OIL_TEMPERATURE = 0X5C, - FUEL_INJECTION_TIMING = 0X5D, - ENGINE_FUEL_RATE = 0X5E, - PIDS_SUPPORTED_61_80 = 0X60, - DRIVER_DEMAND_PERCENT_TORQUE = 0X61, - ACTUAL_PERCENT_TORQUE = 0X62, - ENGINE_REFERENCE_PERCENT_TORQUE = 0X63, - ENGINE_PERCENT_TORQUE_DATA = 0X64, - MASS_AIR_FLOW_SENSOR = 0X66, - ENGINE_COOLANT_TEMPERATURE_1_2 = 0X67, - INTAKE_AIR_TEMPERATURE_SENSOR = 0X68, - COMMANDED_EGR_AND_EGR_ERROR = 0X69, - COMMANDED_DIESEL_INTAKE_AIR_FLOW_CONTROL_AND_RELATIVE_INTAKE_AIR_FLOW_POSITION = 0X6A, - EXHAUST_GAS_RECIRCULATION_TEMPERATURE = 0X6B, - COMMANDED_THROTTLE_ACTUATOR_CONTROL_AND_RELATIVE_THROTTLE_POSITION = 0X6C, - FUEL_PRESSURE_CONTROL_SYSTEM = 0X6D, - INJECTION_PRESSURE_CONTROL_SYSTEM = 0X6E, - TURBOCHARGER_COMPRESSOR_INLET_PRESSURE = 0X6F, - BOOST_PRESSURE_CONTROL = 0X70, - VARIABLE_GEOMETRY_TURBO_CONTROL = 0X71, - WASTEGATE_CONTROL = 0X72, - EXHAUST_PRESSURE = 0X73, - TURBOCHARGER_RPM = 0X74, - TURBOCHARGER_TEMPERATURE_A = 0X75, - TURBOCHARGER_TEMPERATURE_B = 0X76, - CHARGE_AIR_COOLER_TEMPERATURE = 0X77, - EXHAUST_GAS_TEMPERATURE_BANK1 = 0X78, - EXHAUST_GAS_TEMPERATURE_BANK2 = 0X79, - DIESEL_PARTICULATE_FILTER1 = 0X7A, - DIESEL_PARTICULATE_FILTER2 = 0X7B, - DIESEL_PARTICULATE_FILTER_TEMPERATURE = 0X7C, - ENGINE_RUN_TIME = 0X7F, - PIDS_SUPPORTED_81_A0 = 0X80, - NOX_SENSOR = 0X83, - MANIFOLD_SURFACE_TEMPERATURE = 0X84, - NOX_REAGENT_SYSTEM = 0X85, - PARTICULATE_MATTER_SENSOR = 0X86, - INTAKE_MANIFOLD_ABSOLUTE_PRESSURE_A_B = 0X87, - O2_SENSOR_WIDE_RANGE = 0X8C, - THROTTLE_POSITION_G = 0X8D, - ENGINE_FRICTION_PERCENT_TORQUE = 0X8E, - FUEL_SYSTEM_CONTROL = 0X92, - EXHAUST_GAS_TEMPERATURE_SENSORA = 0X98, - EXHAUST_GAS_TEMPERATURE_SENSORB = 0X99, - HYBRID_EV_VEHICLE_SYSTEM_DATA_BATTERY_VOLTAGE = 0X9A, - DIESEL_EXHAUST_FLUID_SENSOR_DATA = 0X9B, - O2_SENSOR_DATA = 0X9C, - FUEL_RATE = 0X9D, - ENGINE_EXHAUST_FLOW_RATE = 0X9E, - FUEL_SYSTEM_PERCENTAGE_USE = 0X9F, - PIDS_SUPPORTED_A1_C0 = 0XA0, - CYLINDER_FUEL_RATE = 0XA2, - TRANSMISSION_ACTUAL_GEAR = 0XA4, - ODOMETER = 0XA6, - PIDS_SUPPORTED_C1_E0 = 0XC0, - HVESS_RECOMMENDED_MAX_SOC = 0xC1 -}; -// clang-format on - static constexpr uint8_t SUPPORTED_PID_STEP = 0x20; static constexpr std::array supportedPIDRange = { { 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 } }; diff --git a/src/datamanagement/types/include/SignalTypes.h b/src/datamanagement/types/include/SignalTypes.h index b7d8ea01..d0004bef 100644 --- a/src/datamanagement/types/include/SignalTypes.h +++ b/src/datamanagement/types/include/SignalTypes.h @@ -28,7 +28,7 @@ using CANChannelNumericID = uint32_t; static constexpr CANChannelNumericID INVALID_CAN_SOURCE_NUMERIC_ID = 0xFFFFFFFF; using CANInterfaceID = std::string; -const CANInterfaceID INVALID_CAN_INTERFACE_ID{}; +static const CANInterfaceID INVALID_CAN_INTERFACE_ID{}; /** * @brief Signal ID is an ID provided by Cloud that is unique across all signals found in the vehicle regardless of @@ -105,10 +105,11 @@ struct CANSignalFormat bool operator==( const CANSignalFormat &other ) const { - return mSignalID == other.mSignalID && mIsBigEndian == other.mIsBigEndian && mIsSigned == other.mIsSigned && - mFirstBitPosition == other.mFirstBitPosition && mSizeInBits == other.mSizeInBits && - mOffset == other.mOffset && mFactor == other.mFactor && - mIsMultiplexorSignal == other.mIsMultiplexorSignal && mMultiplexorValue == other.mMultiplexorValue; + return ( mSignalID == other.mSignalID ) && ( mIsBigEndian == other.mIsBigEndian ) && + ( mIsSigned == other.mIsSigned ) && ( mFirstBitPosition == other.mFirstBitPosition ) && + ( mSizeInBits == other.mSizeInBits ) && ( mOffset == other.mOffset ) && ( mFactor == other.mFactor ) && + ( mIsMultiplexorSignal == other.mIsMultiplexorSignal ) && + ( mMultiplexorValue == other.mMultiplexorValue ); } /** diff --git a/src/datamanagement/types/src/CANDataTypes.cpp b/src/datamanagement/types/src/CANDataTypes.cpp deleted file mode 100644 index 853703c6..00000000 --- a/src/datamanagement/types/src/CANDataTypes.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CANDataTypes.h" \ No newline at end of file diff --git a/src/datamanagement/types/src/CollectionInspectionAPITypes.cpp b/src/datamanagement/types/src/CollectionInspectionAPITypes.cpp deleted file mode 100644 index bf4ca7fc..00000000 --- a/src/datamanagement/types/src/CollectionInspectionAPITypes.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CollectionInspectionAPITypes.h" diff --git a/src/datamanagement/types/src/Geohash.cpp b/src/datamanagement/types/src/Geohash.cpp index cfd83bbe..bdd16602 100644 --- a/src/datamanagement/types/src/Geohash.cpp +++ b/src/datamanagement/types/src/Geohash.cpp @@ -22,7 +22,8 @@ Geohash::encode( double lat, double lon, uint8_t precision, uint64_t &hashBits ) static_assert( sizeof( hashBits ) * 8 >= MAX_PRECISION * BASE32_BITS, "Not enough bits to support maximum precision" ); - if ( precision > MAX_PRECISION || lat < LAT_MIN || lat > LAT_MAX || lon < LON_MIN || lon > LON_MAX ) + if ( ( precision > MAX_PRECISION ) || ( lat < LAT_MIN ) || ( lat > LAT_MAX ) || ( lon < LON_MIN ) || + ( lon > LON_MAX ) ) { // INVALID INPUT, need to return as we cannot proceed for calculation return false; @@ -86,7 +87,8 @@ Geohash::encode( double lat, double lon, uint8_t precision, uint64_t &hashBits ) bool Geohash::encode( double lat, double lon, uint8_t precision, std::string &hashString ) { - if ( precision > MAX_PRECISION || lat < LAT_MIN || lat > LAT_MAX || lon < LON_MIN || lon > LON_MAX ) + if ( ( precision > MAX_PRECISION ) || ( lat < LAT_MIN ) || ( lat > LAT_MAX ) || ( lon < LON_MIN ) || + ( lon > LON_MAX ) ) { // INVALID INPUT, need to return as we cannot proceed for calculation return false; diff --git a/src/datamanagement/types/src/GeohashInfo.cpp b/src/datamanagement/types/src/GeohashInfo.cpp deleted file mode 100644 index b0a90dae..00000000 --- a/src/datamanagement/types/src/GeohashInfo.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "GeohashInfo.h" \ No newline at end of file diff --git a/src/datamanagement/types/src/OBDDataTypes.cpp b/src/datamanagement/types/src/OBDDataTypes.cpp deleted file mode 100644 index f7d1edf4..00000000 --- a/src/datamanagement/types/src/OBDDataTypes.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "OBDDataTypes.h" diff --git a/src/executionmanagement/CMakeLists.txt b/src/executionmanagement/CMakeLists.txt index 8036e90a..79a0df58 100644 --- a/src/executionmanagement/CMakeLists.txt +++ b/src/executionmanagement/CMakeLists.txt @@ -78,8 +78,6 @@ if(${BUILD_TESTING}) - find_package(GTest REQUIRED) - file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/em-example-config.json DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) @@ -98,12 +96,12 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_unit_test(${testName}) diff --git a/src/executionmanagement/include/IoTFleetWiseEngine.h b/src/executionmanagement/include/IoTFleetWiseEngine.h index bbba1650..79dad060 100644 --- a/src/executionmanagement/include/IoTFleetWiseEngine.h +++ b/src/executionmanagement/include/IoTFleetWiseEngine.h @@ -10,7 +10,6 @@ #include "ClockHandler.h" #include "CollectionInspectionWorkerThread.h" #include "CollectionScheme.h" -#include "CollectionSchemeListener.h" #include "CollectionSchemeManager.h" #include "DataCollectionSender.h" #ifdef FWE_FEATURE_CAMERA diff --git a/src/executionmanagement/src/IoTFleetWiseEngine.cpp b/src/executionmanagement/src/IoTFleetWiseEngine.cpp index 8d71eb90..44d658af 100644 --- a/src/executionmanagement/src/IoTFleetWiseEngine.cpp +++ b/src/executionmanagement/src/IoTFleetWiseEngine.cpp @@ -105,7 +105,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 " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init persistency library" ); } if ( config["staticConfig"]["persistency"].isMember( "persistencyUploadRetryIntervalMs" ) ) { @@ -251,9 +251,8 @@ 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 " ); + mLogger.warn( "IoTFleetWiseEngine::connect", + "Failed to start the Remote Profiler - No remote profiling available until FWE restart" ); } setLogForwarding( mRemoteProfiler.get() ); } @@ -277,16 +276,16 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // Init and start the Inspection Engine mCollectionInspectionWorkerThread = std::make_shared(); - if ( !mCollectionInspectionWorkerThread->init( + if ( ( !mCollectionInspectionWorkerThread->init( signalBufferPtr, canRawBufferPtr, activeDTCBufferPtr, mCollectedDataReadyToPublish, config["staticConfig"]["threadIdleTimes"]["inspectionThreadIdleTimeMs"].asUInt(), - config["staticConfig"]["internalParameters"]["dataReductionProbabilityDisabled"].asBool() ) || - !mCollectionInspectionWorkerThread->start() ) + config["staticConfig"]["internalParameters"]["dataReductionProbabilityDisabled"].asBool() ) ) || + ( !mCollectionInspectionWorkerThread->start() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to init and start the Inspection Engine " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init and start the Inspection Engine" ); return false; } // Make sure the Inspection Engine can notify the Bootstrap thread about ready to be @@ -294,7 +293,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !mCollectionInspectionWorkerThread->subscribeListener( this ) ) { mLogger.error( "IoTFleetWiseEngine::connect", - " Failed register the Engine Thread to the Inspection Module " ); + "Failed register the Engine Thread to the Inspection Module" ); return false; } @@ -311,9 +310,10 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) CollectionSchemeJSONParser parser( config["staticConfig"]["internalParameters"]["jsonBasedCollectionSchemeFilename"].asString() ); - if ( !parser.parse() || !parser.getCollectionScheme() || !parser.getCollectionScheme()->isValid() ) + if ( ( !parser.parse() ) || ( !parser.getCollectionScheme() ) || + ( !parser.getCollectionScheme()->isValid() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to Parse the Collection Scheme " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to Parse the Collection Scheme" ); return false; } @@ -340,7 +340,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mPersistDecoderManifestCollectionSchemesAndData, canIDTranslator ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to init the CollectionScheme Manager " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to init the CollectionScheme Manager" ); return false; } @@ -350,7 +350,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) static_cast( mCollectionSchemeManagerPtr.get() ) ) ) { mLogger.error( "IoTFleetWiseEngine::connect", - " Failed register the CollectionScheme Manager to the CollectionScheme Ingestion Module " ); + "Failed register the CollectionScheme Manager to the CollectionScheme Ingestion Module" ); return false; } @@ -360,7 +360,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) static_cast( mCollectionInspectionWorkerThread.get() ) ) ) { mLogger.error( "IoTFleetWiseEngine::connect", - " Failed register the Inspection Engine to the CollectionScheme Manager Module " ); + "Failed register the Inspection Engine to the CollectionScheme Manager Module" ); return false; } @@ -372,9 +372,9 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) auto obdOverCANModuleInit = false; // Start the vehicle data source binder mVehicleDataSourceBinder = std::make_unique(); - if ( mVehicleDataSourceBinder == nullptr || !mVehicleDataSourceBinder->connect() ) + if ( ( mVehicleDataSourceBinder == nullptr ) || ( !mVehicleDataSourceBinder->connect() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to initialize the Vehicle DataSource binder " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the Vehicle DataSource binder" ); return false; } @@ -404,7 +404,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !success ) { mLogger.warn( "IoTFleetWiseEngine::connect", - " Invalid can timestamp type provided: " + timestampTypeInput + + "Invalid can timestamp type provided: " + timestampTypeInput + " so default to Software" ); } } @@ -413,20 +413,20 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( canSourcePtr == nullptr || canConsumerPtr == nullptr ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to create consumer/producer " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to create consumer/producer" ); return false; } // Initialize the consumer/producers // Currently we limit 1 channel to a single consumer. We can always extend this // if we want to process the data coming from 1 channel to multiple consumers. - if ( !canSourcePtr->init( canSourceConfigs ) || - !canConsumerPtr->init( + if ( ( !canSourcePtr->init( canSourceConfigs ) ) || + ( !canConsumerPtr->init( static_cast( canIDTranslator.getChannelNumericID( interfaceName["interfaceId"].asString() ) ), signalBufferPtr, - config["staticConfig"]["threadIdleTimes"]["canDecoderThreadIdleTimeMs"].asUInt() ) ) + config["staticConfig"]["threadIdleTimes"]["canDecoderThreadIdleTimeMs"].asUInt() ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to initialize the producers/consumers " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the producers/consumers" ); return false; } else @@ -440,14 +440,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 " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to add a network channel" ); return false; } if ( !mVehicleDataSourceBinder->bindConsumerToVehicleDataSource( canConsumerPtr, canSourcePtr->getVehicleDataSourceID() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to Bind Consumers to Producers " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to Bind Consumers to Producers" ); return false; } } @@ -457,13 +457,16 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) { auto obdOverCANModule = std::make_shared(); obdOverCANModuleInit = true; + const auto &broadcastRequests = interfaceName[OBD_INTERFACE_TYPE]["broadcastRequests"]; // Init returns false if no collection is configured: if ( obdOverCANModule->init( signalBufferPtr, activeDTCBufferPtr, interfaceName[OBD_INTERFACE_TYPE]["interfaceName"].asString(), interfaceName[OBD_INTERFACE_TYPE]["pidRequestIntervalSeconds"].asUInt(), - interfaceName[OBD_INTERFACE_TYPE]["dtcRequestIntervalSeconds"].asUInt() ) ) + interfaceName[OBD_INTERFACE_TYPE]["dtcRequestIntervalSeconds"].asUInt(), + // Broadcast mode is enabled by default if not defined in config: + broadcastRequests.isNull() || broadcastRequests.asBool() ) ) { // Connect the OBD Module mOBDOverCANModule = obdOverCANModule; @@ -477,14 +480,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) static_cast( mOBDOverCANModule.get() ) ) ) { mLogger.error( "IoTFleetWiseEngine::connect", - " Failed to register the OBD Module to the CollectionScheme Manager" ); + "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" ); + "Failed to register the OBD Module to the CollectionScheme Manager" ); return false; } } @@ -515,7 +518,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // read from persistent memory: if ( !mCollectionSchemeManagerPtr->connect() ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to start the CollectionScheme Manager " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to start the CollectionScheme Manager" ); return false; } /****************************CollectionScheme Manager bootstrap end*************************/ @@ -550,7 +553,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) else { mLogger.warn( "IoTFleetWiseEngine::connect", - " Unsupported Transport config provided for a DDS Node, skipping it" ); + "Unsupported Transport config provided for a DDS Node, skipping it" ); continue; } @@ -562,7 +565,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) else { mLogger.warn( "IoTFleetWiseEngine::connect", - " Unsupported Device type provided for a DDS Node, skipping it" ); + "Unsupported Device type provided for a DDS Node, skipping it" ); continue; } @@ -581,24 +584,24 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) { mDataOverDDSModule.reset( new DataOverDDSModule() ); // Init the Module - if ( mDataOverDDSModule == nullptr || !mDataOverDDSModule->init( ddsNodes ) ) + if ( ( mDataOverDDSModule == nullptr ) || ( !mDataOverDDSModule->init( ddsNodes ) ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to initialize the DDS Module " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to initialize the DDS Module" ); return false; } // Register the DDS Module as a listener to the Inspection Engine and connect it. - if ( !mCollectionInspectionWorkerThread->subscribeToEvents( - static_cast( mDataOverDDSModule.get() ) ) || - !mDataOverDDSModule->connect() ) + if ( ( !mCollectionInspectionWorkerThread->subscribeToEvents( + static_cast( mDataOverDDSModule.get() ) ) ) || + ( !mDataOverDDSModule->connect() ) ) { - mLogger.error( "IoTFleetWiseEngine::connect", " Failed to connect the DDS Module " ); + mLogger.error( "IoTFleetWiseEngine::connect", "Failed to connect the DDS Module" ); return false; } - mLogger.info( "IoTFleetWiseEngine::connect", " DDS Module connected " ); + mLogger.info( "IoTFleetWiseEngine::connect", "DDS Module connected" ); } else { - mLogger.info( "IoTFleetWiseEngine::connect", " DDS Module disabled " ); + mLogger.info( "IoTFleetWiseEngine::connect", "DDS Module disabled" ); } /********************************DDS Module bootstrap end*********************************/ @@ -641,14 +644,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) static_cast( mIWaveGpsSource.get() ) ) ) { mLogger.error( "IoTFleetWiseEngine::connect", - " Failed to register the IWaveGps to the CollectionScheme Manager" ); + "Failed to register the IWaveGps to the CollectionScheme Manager" ); return false; } mIWaveGpsSource->start(); } else { - mLogger.error( "IoTFleetWiseEngine::connect", " IWaveGps initialization failed " ); + mLogger.error( "IoTFleetWiseEngine::connect", "IWaveGps initialization failed" ); return false; } /********************************IWave GPS Example NMEA reader end******************************/ @@ -660,7 +663,7 @@ 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() ) ); + "Fatal Error during AWS IoT FleetWise Bootstrap: " + std::string( e.what() ) ); return false; } @@ -675,9 +678,9 @@ IoTFleetWiseEngine::disconnect() #ifdef FWE_FEATURE_CAMERA if ( mDataOverDDSModule ) { - if ( !mCollectionInspectionWorkerThread->unSubscribeFromEvents( - static_cast( mDataOverDDSModule.get() ) ) || - !mDataOverDDSModule->disconnect() ) + if ( ( !mCollectionInspectionWorkerThread->unSubscribeFromEvents( + static_cast( mDataOverDDSModule.get() ) ) ) || + ( !mDataOverDDSModule->disconnect() ) ) { mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not disconnect DDS Module" ); @@ -702,7 +705,7 @@ IoTFleetWiseEngine::disconnect() } setLogForwarding( nullptr ); - if ( mRemoteProfiler != nullptr && !mRemoteProfiler->stop() ) + if ( ( mRemoteProfiler != nullptr ) && ( !mRemoteProfiler->stop() ) ) { mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not stop the Remote Profiler" ); return false; @@ -715,7 +718,7 @@ IoTFleetWiseEngine::disconnect() } // Stop the Binder - if ( mVehicleDataSourceBinder && !mVehicleDataSourceBinder->disconnect() ) + if ( mVehicleDataSourceBinder && ( !mVehicleDataSourceBinder->disconnect() ) ) { mLogger.error( "IoTFleetWiseEngine::disconnect", "Could not disconnect the Binder" ); return false; @@ -736,11 +739,11 @@ IoTFleetWiseEngine::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "IoTFleetWiseEngine::start", " Engine Thread failed to start " ); + mLogger.trace( "IoTFleetWiseEngine::start", "Engine Thread failed to start" ); } else { - mLogger.trace( "IoTFleetWiseEngine::start", " Engine Thread started " ); + mLogger.trace( "IoTFleetWiseEngine::start", "Engine Thread started" ); mThread.setThreadName( "fwEMEngine" ); } @@ -829,7 +832,7 @@ IoTFleetWiseEngine::doWork( void *data ) { engine->mLogger.trace( "IoTFleetWiseEngine::doWork", - "Waiting for :" + std::to_string( timeTrigger ) + " seconds. Persistency " + + "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 ) + @@ -873,19 +876,19 @@ IoTFleetWiseEngine::doWork( void *data ) "FWE data ready to send with eventID " + std::to_string( triggeredCollectionSchemeDataPtr->eventID ) + " from " + triggeredCollectionSchemeDataPtr->metaData.collectionSchemeID + - " Signals:" + std::to_string( triggeredCollectionSchemeDataPtr->signals.size() ) + " " + + " 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 ); + " 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 ); - if ( ( engine->mPersistencyUploadRetryIntervalMs > 0 && + if ( ( ( engine->mPersistencyUploadRetryIntervalMs > 0 ) && ( static_cast( engine->mRetrySendingPersistedDataTimer.getElapsedMs().count() ) >= engine->mPersistencyUploadRetryIntervalMs ) ) || - ( !uploadedPersistedDataOnce && + ( ( !uploadedPersistedDataOnce ) && ( static_cast( engine->mRetrySendingPersistedDataTimer.getElapsedMs().count() ) >= IoTFleetWiseEngine::FAST_RETRY_UPLOAD_PERSISTED_INTERVAL_MS ) ) ) { @@ -896,7 +899,7 @@ IoTFleetWiseEngine::doWork( void *data ) uploadedPersistedDataOnce |= engine->checkAndSendRetrievedData(); } } - if ( engine->mPrintMetricsCyclicPeriodMs > 0 && + if ( ( engine->mPrintMetricsCyclicPeriodMs > 0 ) && ( static_cast( engine->mPrintMetricsCyclicTimer.getElapsedMs().count() ) >= engine->mPrintMetricsCyclicPeriodMs ) ) { diff --git a/src/executionmanagement/src/IoTFleetWiseVersion.cpp.in b/src/executionmanagement/src/IoTFleetWiseVersion.cpp.in index cdedc547..c4f19221 100644 --- a/src/executionmanagement/src/IoTFleetWiseVersion.cpp.in +++ b/src/executionmanagement/src/IoTFleetWiseVersion.cpp.in @@ -1,14 +1,14 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -#include "IoTFleetWiseVersion.h" +// To use the variable #include "IoTFleetWiseVersion.h" // This file will be filled by CMAKE configure_file with the right values and placed in the build folder -const char VERSION_GIT_COMMIT_SHA[] = "@VERSION_GIT_SHA@"; -const char VERSION_GIT_TAG[] = "@VERSION_GIT_TAG@"; -const char VERSION_BUILD_TIME[] = "@VERSION_CURRENT_TIME@"; -const char VERSION_PROJECT_VERSION[] = "@PROJECT_VERSION@"; +extern const char VERSION_GIT_COMMIT_SHA[] = "@VERSION_GIT_SHA@"; +extern const char VERSION_GIT_TAG[] = "@VERSION_GIT_TAG@"; +extern const char VERSION_BUILD_TIME[] = "@VERSION_CURRENT_TIME@"; +extern const char VERSION_PROJECT_VERSION[] = "@PROJECT_VERSION@"; -const char VERSION_PROJECT_VERSION_MAJOR[] = "@PROJECT_VERSION_MAJOR@"; -const char VERSION_PROJECT_VERSION_MINOR[] = "@PROJECT_VERSION_MINOR@"; -const char VERSION_PROJECT_VERSION_PATCH[] = "@PROJECT_VERSION_PATCH@"; \ No newline at end of file +extern const char VERSION_PROJECT_VERSION_MAJOR[] = "@PROJECT_VERSION_MAJOR@"; +extern const char VERSION_PROJECT_VERSION_MINOR[] = "@PROJECT_VERSION_MINOR@"; +extern const char VERSION_PROJECT_VERSION_PATCH[] = "@PROJECT_VERSION_PATCH@"; \ No newline at end of file diff --git a/src/executionmanagement/src/main.cpp b/src/executionmanagement/src/main.cpp index 17cd10fb..2ef6e127 100644 --- a/src/executionmanagement/src/main.cpp +++ b/src/executionmanagement/src/main.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Includes +#include "ConsoleLogger.h" #include "IoTFleetWiseConfig.h" #include "IoTFleetWiseEngine.h" #include "IoTFleetWiseVersion.h" @@ -12,26 +13,16 @@ using namespace Aws::IoTFleetWise::ExecutionManagement; -static std::atomic mSignal( false ); -static std::atomic mExitCode( 0 ); +// coverity[autosar_cpp14_a2_11_1_violation] +static volatile sig_atomic_t mSignal = 0; // volatile has to be used since it will be modified by a signal handler, + // executed as result of an asynchronous interrupt -static void +extern "C" void signalHandler( int signum ) { - static_cast( signum ); // unused parameter - std::cout << "Stopping AWS IoT FleetWise Edge Service " << std::endl; - - mSignal.store( true ); -} - -static void -fatalSignalHandler( int signum ) -{ - static_cast( signum ); // unused parameter - std::cout << "Fatal error, stopping AWS IoT FleetWise Edge Service " << std::endl; - - mSignal.store( true ); - mExitCode.store( -1 ); + // Very few things are safe in a signal handler. So we never do anything other than set the atomic int, not even + // print a message: https://stackoverflow.com/a/16891799 + mSignal = signum; } static void @@ -42,57 +33,100 @@ printVersion() } static void -setSystemWideLogLevel( const Json::Value &config ) +configureLogging( const Json::Value &config ) { Aws::IoTFleetWise::Platform::Linux::LogLevel logLevel = Aws::IoTFleetWise::Platform::Linux::LogLevel::Trace; stringToLogLevel( config["staticConfig"]["internalParameters"]["systemWideLogLevel"].asString(), logLevel ); gSystemWideLogLevel = logLevel; -} -int -main( int argc, char *argv[] ) -{ - printVersion(); - if ( argc != 2 ) + auto logColorOption = Aws::IoTFleetWise::Platform::Linux::LogColorOption::Auto; + if ( config["staticConfig"]["internalParameters"].isMember( "logColor" ) ) { - std::cout << "error: invalid argument - only a config file is required" << std::endl; - return EXIT_FAILURE; + std::string logColorConfig = config["staticConfig"]["internalParameters"]["logColor"].asString(); + if ( !stringToLogColorOption( logColorConfig, logColorOption ) ) + { + std::cout << "Invalid logColor config: " << logColorConfig << std::endl; + } } + gLogColorOption = logColorOption; +} - IoTFleetWiseEngine engine; - signal( SIGINT, signalHandler ); - signal( SIGTERM, signalHandler ); - signal( SIGUSR1, fatalSignalHandler ); - std::string configFilename = argv[1]; - Json::Value config; - if ( !IoTFleetWiseConfig::read( configFilename, config ) ) +static int +signalToExitCode( int signalNumber ) +{ + switch ( signalNumber ) { - std::cout << " AWS IoT FleetWise Edge Service failed to read config file: " + configFilename << std::endl; - return EXIT_FAILURE; + case SIGUSR1: + std::cout << "Fatal error, stopping AWS IoT FleetWise Edge Service " << std::endl; + return -1; + case SIGINT: + case SIGTERM: + std::cout << "Stopping AWS IoT FleetWise Edge Service " << std::endl; + return 0; + default: + std::cout << "Received unexpected signal " << signalNumber << std::endl; + return 0; } - // Set system wide log level - setSystemWideLogLevel( config ); +} - // Connect the Engine - if ( engine.connect( config ) && engine.start() ) - { - std::cout << " AWS IoT FleetWise Edge Service Started successfully " << std::endl; - } - else +int +main( int argc, char *argv[] ) +{ + try { + printVersion(); + if ( argc != 2 ) + { + std::cout << "error: invalid argument - only a config file is required" << std::endl; + return EXIT_FAILURE; + } + + signal( SIGINT, signalHandler ); + signal( SIGTERM, signalHandler ); + signal( SIGUSR1, signalHandler ); + std::string configFilename = argv[1]; + Json::Value config; + if ( !IoTFleetWiseConfig::read( configFilename, config ) ) + { + std::cout << " AWS IoT FleetWise Edge Service failed to read config file: " + configFilename << std::endl; + return EXIT_FAILURE; + } + // Set system wide log level + configureLogging( config ); + + IoTFleetWiseEngine engine; + // Connect the Engine + if ( engine.connect( config ) && engine.start() ) + { + std::cout << " AWS IoT FleetWise Edge Service Started successfully " << std::endl; + } + else + { + return EXIT_FAILURE; + } + + while ( mSignal == 0 ) + { + sleep( 1 ); + } + int exitCode = signalToExitCode( mSignal ); + if ( engine.stop() && engine.disconnect() ) + { + std::cout << " AWS IoT FleetWise Edge Service Stopped successfully " << std::endl; + return exitCode; + } + + std::cout << " AWS IoT FleetWise Edge Service Stopped with errors " << std::endl; return EXIT_FAILURE; } - - while ( !mSignal.load() ) + catch ( const std::exception &e ) { - sleep( 1 ); + std::cout << "Unhandled exception: " << std::string( e.what() ) << std::endl; + return EXIT_FAILURE; } - if ( engine.stop() && engine.disconnect() ) + catch ( ... ) { - std::cout << " AWS IoT FleetWise Edge Service Stopped successfully " << std::endl; - return mExitCode.load(); + std::cout << "Unknown exception" << std::endl; + return EXIT_FAILURE; } - - std::cout << " AWS IoT FleetWise Edge Service Stopped with errors " << std::endl; - return EXIT_FAILURE; } diff --git a/src/offboardconnectivity/api/include/IConnectionTypes.h b/src/offboardconnectivity/api/include/IConnectionTypes.h index 49ff6626..2f75544e 100644 --- a/src/offboardconnectivity/api/include/IConnectionTypes.h +++ b/src/offboardconnectivity/api/include/IConnectionTypes.h @@ -18,7 +18,7 @@ namespace OffboardConnectivity */ enum class ConnectivityError { - Success, /**< everything OK, still no guarantee that data was transmitted correctly */ + Success = 0, /**< everything OK, still no guarantee that data was transmitted correctly */ NoConnection, /**< currently no connection, the Connectivity module will try to reestablish it automatically */ QuotaReached, /**< quota reached for example outgoing queue full so please try again after few milliseconds */ NotConfigured, /**< the object used was not configured correctly */ diff --git a/src/offboardconnectivity/implementation/aws/bootstrap/include/AwsBootstrap.h b/src/offboardconnectivity/implementation/aws/bootstrap/include/AwsBootstrap.h index f4c4b3d5..a779690a 100644 --- a/src/offboardconnectivity/implementation/aws/bootstrap/include/AwsBootstrap.h +++ b/src/offboardconnectivity/implementation/aws/bootstrap/include/AwsBootstrap.h @@ -26,7 +26,7 @@ namespace OffboardConnectivityAwsIot class AwsBootstrap { public: - ~AwsBootstrap(); + ~AwsBootstrap() = default; AwsBootstrap( const AwsBootstrap & ) = delete; AwsBootstrap &operator=( const AwsBootstrap & ) = delete; diff --git a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp index 703084df..630ecf8b 100644 --- a/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp +++ b/src/offboardconnectivity/implementation/aws/bootstrap/src/AwsBootstrap.cpp @@ -92,8 +92,6 @@ AwsBootstrap::AwsBootstrap() mImpl = std::make_unique(); } -AwsBootstrap::~AwsBootstrap() = default; - AwsBootstrap & AwsBootstrap::getInstance() { diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/CMakeLists.txt b/src/offboardconnectivity/implementation/aws/iotcpp/CMakeLists.txt index a1dc12d5..74bbabb1 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/CMakeLists.txt +++ b/src/offboardconnectivity/implementation/aws/iotcpp/CMakeLists.txt @@ -50,8 +50,6 @@ add_library(${libraryAliasName} ALIAS ${libraryTargetName}) if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - find_library(GMOCK_LIB NAMES gmock) @@ -75,8 +73,7 @@ if(${BUILD_TESTING}) PRIVATE IoTFleetWise::OffboardConnectivityAwsBootstrap IoTFleetWise::OffboardConnectivity - GTest::Main - GTest::GTest + IoTFleetWise::TestingSupport ${GMOCK_MAIN_LIBRARY} ${GMOCK_LIB} ${SNAPPY_LIBRARIES} @@ -106,12 +103,12 @@ if(${BUILD_TESTING}) add_unit_test(${testName}) add_valgrind_test(${testName}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport IoTFleetWise::Proto ${SNAPPY_LIBRARIES} ) diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp index 074bd800..500f2dfb 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotChannel.cpp @@ -104,15 +104,15 @@ AwsIotChannel::subscribe() } else { - if ( packetId == 0u || QoS == Mqtt::QOS::AWS_MQTT_QOS_FAILURE ) + 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." ); + mLogger.error( "AwsIotChannel::subscribeTopic", "Subscribe rejected by the Remote broker" ); } else { std::ostringstream os; - os << "Subscribe on topic " << topic << " on packetId " << packetId << " succeeded" << std::endl; + os << "Subscribe on topic " << topic << " on packetId " << packetId << " succeeded"; mLogger.trace( "AwsIotChannel::subscribeTopic", os.str() ); mSubscribed = true; } @@ -120,7 +120,7 @@ AwsIotChannel::subscribe() } }; - mLogger.trace( "AwsIotChannel::subscribeTopic", "Subscribing.." ); + mLogger.trace( "AwsIotChannel::subscribeTopic", "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 @@ -151,7 +151,7 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche return ConnectivityError::NotConfigured; } - if ( buf == nullptr || size == 0 ) + if ( ( buf == nullptr ) || ( size == 0 ) ) { mLogger.warn( "AwsIotChannel::send", "No valid data provided" ); return ConnectivityError::WrongInputData; @@ -182,7 +182,7 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche } uint64_t currentMemoryUsage = mConnectivityModule->reserveMemoryUsage( size ); - if ( mMaximumIotSDKHeapMemoryBytes != 0 && currentMemoryUsage > mMaximumIotSDKHeapMemoryBytes ) + if ( ( mMaximumIotSDKHeapMemoryBytes != 0 ) && ( currentMemoryUsage > mMaximumIotSDKHeapMemoryBytes ) ) { mConnectivityModule->releaseMemoryUsage( size ); mLogger.error( "AwsIotChannel::send", @@ -210,11 +210,11 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche auto payload = ByteBufNewCopy( DefaultAllocator(), (const uint8_t *)buf, size ); auto onPublishComplete = - [payload, size, this]( Mqtt::MqttConnection &mqttConnection, uint16_t packetId, int errorCode ) { + [payload, size, this]( Mqtt::MqttConnection &mqttConnection, uint16_t packetId, int errorCode ) mutable { /* This call means that the data was handed over to some lower level in the stack but not that the data is actually sent on the bus or removed from RAM*/ (void)mqttConnection; - aws_byte_buf_clean_up( (Aws::Crt::ByteBuf *)&payload ); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) + aws_byte_buf_clean_up( &payload ); { std::lock_guard connectivityLambdaLock( mConnectivityLambdaMutex ); if ( mConnectivityModule != nullptr ) @@ -222,7 +222,7 @@ AwsIotChannel::send( const std::uint8_t *buf, size_t size, struct CollectionSche mConnectivityModule->releaseMemoryUsage( size ); } } - if ( packetId != 0U && errorCode == 0 ) + if ( ( packetId != 0U ) && ( errorCode == 0 ) ) { mLogger.trace( "AwsIotChannel::send", "Operation on packetId " + std::to_string( packetId ) + " Succeeded" ); @@ -247,7 +247,7 @@ AwsIotChannel::unsubscribe() auto connection = mConnectivityModule->getConnection(); std::promise unsubscribeFinishedPromise; - mLogger.trace( "AwsIotChannel::unsubscribe", "Unsubscribing ..." ); + mLogger.trace( "AwsIotChannel::unsubscribe", "Unsubscribing..." ); connection->Unsubscribe( mTopicName.c_str(), [&]( Mqtt::MqttConnection &mqttConnection, uint16_t packetId, int errorCode ) { (void)mqttConnection; diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp index 09845653..b5b1f832 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/AwsIotConnectivityModule.cpp @@ -154,7 +154,7 @@ AwsIotConnectivityModule::setupCallbacks() } else { - mLogger.info( "AwsIotConnectivityModule::connect", "Connection completed successfully." ); + mLogger.info( "AwsIotConnectivityModule::connect", "Connection completed successfully" ); mConnectionCompletedPromise.set_value( true ); } } @@ -164,7 +164,7 @@ AwsIotConnectivityModule::setupCallbacks() auto onInterrupted = [&]( Mqtt::MqttConnection &mqttConnection, int error ) { (void)mqttConnection; TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::CONNECTION_INTERRUPTED ); - std::string errorString = " The MQTT Connection has been interrupted due to: "; + 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 ); @@ -227,21 +227,21 @@ AwsIotConnectivityModule::renameEventLoopTask() bool AwsIotConnectivityModule::createMqttConnection( Aws::Crt::Io::ClientBootstrap *clientBootstrap ) { - if ( mCertificate.len == 0 || mPrivateKey.len == 0 || mEndpointUrl.empty() || mClientId.empty() ) + 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" ); + "Please provide X.509 Certificate, private Key, endpoint and client-Id" ); return false; } if ( clientBootstrap == nullptr ) { - mLogger.error( "AwsIotConnectivityModule::connect", " ClientBootstrap failed with error " ); + mLogger.error( "AwsIotConnectivityModule::connect", "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", "ClientBootstrap failed with error" ); mLogger.error( "AwsIotConnectivityModule::connect", errString != nullptr ? std::string( errString ) : std::string( "Unknown error" ) ); return false; @@ -298,7 +298,7 @@ AwsIotConnectivityModule::attempt() { if ( !mConnection->Connect( mClientId.c_str(), false, MQTT_CONNECT_KEEP_ALIVE_SECONDS, MQTT_PING_TIMOUT_MS ) ) { - std::string error = " The MQTT Connection failed due to: "; + 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 ); diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp index 62fb27fd..5f467a83 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/PayloadManager.cpp @@ -102,7 +102,7 @@ PayloadManager::storeData( const std::uint8_t *buf, // set the ErrorCode::SUCCESSful storage flag to true isDataPersisted = true; mLogger.trace( "PayloadManager::storeData", - "Payload of size : " + std::to_string( totalWriteSize ) + + "Payload of size: " + std::to_string( totalWriteSize ) + " Bytes (header: " + std::to_string( sizeof( PayloadHeader ) ) + ") has been ErrorCode::SUCCESSfully persisted" ); } @@ -157,7 +157,7 @@ PayloadManager::retrieveData( std::vector &data ) // Clear the data string before parsing new payload dataString.clear(); - for ( j = 0; j < size && ( ( pos + j ) < readSize ); ++j ) + for ( j = 0; ( j < size ) && ( ( pos + j ) < readSize ); ++j ) { dataString += ( readBuffer.get()[pos + j] ); // NOLINT(clang-diagnostic-sign-conversion) } @@ -190,7 +190,7 @@ PayloadManager::retrieveData( std::vector &data ) } } mLogger.info( "PayloadManager::retrieveData", - "Payload of Size : " + std::to_string( readSize ) + " Bytes has been loaded from disk" ); + "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 7e79ece8..0f43f82c 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/RemoteProfiler.cpp @@ -31,7 +31,7 @@ RemoteProfiler::RemoteProfiler( std::shared_ptr metricsSender, initLogStructure(); fLastCPURUsage.reportCPUUsageInfo(); Aws::IoTFleetWise::Platform::Linux::CPUUsageInfo::reportPerThreadUsageData( fLastThreadUsage ); - fLastTimeExecutionEnvironmentMetricsCollected = fClock->timeSinceEpochMs(); + fLastTimeExecutionEnvironmentMetricsCollected = fClock->monotonicTimeSinceEpochMs(); } void @@ -49,11 +49,12 @@ RemoteProfiler::sendMetricsOut() Json::StreamWriterBuilder builder; builder["indentation"] = ""; // If you want whitespace-less output const std::string output = Json::writeString( builder, fMetricsRoot ); - auto ret = fMetricsSender->send( reinterpret_cast( output.c_str() ), output.length() ); - if ( ConnectivityError::Success != ret ) + uint32_t ret = static_cast( + fMetricsSender->send( 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 ) ) ); + "Send error " + std::to_string( static_cast( ret ) ) ); } fMetricsRoot.clear(); fCurrentMetricsPending = 0; @@ -68,17 +69,18 @@ RemoteProfiler::sendLogsOut() std::lock_guard lock( loggingMutex ); Json::StreamWriterBuilder builder; builder["indentation"] = ""; // If you want whitespace-less output - const std::string output = Json::writeString( builder, fLogRoot ); + output = Json::writeString( builder, fLogRoot ); initLogStructure(); } - if ( fLogSender != nullptr && fCurrentUserPayloadInLogRoot > 0 ) + if ( ( fLogSender != nullptr ) && ( fCurrentUserPayloadInLogRoot > 0 ) ) { - auto ret = fLogSender->send( reinterpret_cast( output.c_str() ), output.length() ); - if ( ConnectivityError::Success != ret ) + uint32_t ret = static_cast( + fLogSender->send( 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 ) ) ); + "Send error " + std::to_string( static_cast( ret ) ) ); } } } @@ -140,15 +142,15 @@ RemoteProfiler::start() { if ( fMetricsSender == nullptr ) { - fLogger.error( "RemoteProfiler::start", " Trying to start without sender " ); + fLogger.error( "RemoteProfiler::start", "Trying to start without sender" ); return false; } - if ( ( fInitialLogMaxInterval == 0 && fLogLevelThreshold != LogLevel::Off ) || - ( fInitialLogMaxInterval != 0 && fLogLevelThreshold == LogLevel::Off ) ) + 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 " - "0, which is implausible. " ); + "Logging is turned off by putting LogLevel Threshold to Off but log max interval is not " + "0, which is implausible" ); } // Prevent concurrent stop/init std::lock_guard lock( fThreadMutex ); @@ -157,11 +159,11 @@ RemoteProfiler::start() fShouldStop.store( false ); if ( !fThread.create( doWork, this ) ) { - fLogger.trace( "RemoteProfiler::start", " Remote Profiler Thread failed to start " ); + fLogger.trace( "RemoteProfiler::start", "Remote Profiler Thread failed to start" ); } else { - fLogger.trace( "RemoteProfiler::start", " Remote Profiler Thread started " ); + fLogger.trace( "RemoteProfiler::start", "Remote Profiler Thread started" ); fThread.setThreadName( "fwCNProfiler" ); } @@ -171,19 +173,19 @@ RemoteProfiler::start() bool RemoteProfiler::stop() { - if ( !fThread.isValid() || !fThread.isActive() ) + if ( ( !fThread.isValid() ) || ( !fThread.isActive() ) ) { return true; } std::lock_guard lock( fThreadMutex ); fShouldStop.store( true, std::memory_order_relaxed ); - fLogger.trace( "RemoteProfiler::stop", " Request stop " ); + fLogger.trace( "RemoteProfiler::stop", "Request stop" ); fWait.notify(); fThread.release(); initLogStructure(); fMetricsRoot.clear(); - fLogger.trace( "RemoteProfiler::stop", " Stop finished " ); + fLogger.trace( "RemoteProfiler::stop", "Stop finished" ); fShouldStop.store( false, std::memory_order_relaxed ); return !fThread.isActive(); } @@ -193,7 +195,7 @@ RemoteProfiler::collectExecutionEnvironmentMetrics() { CPUUsageInfo lastUsage = fLastCPURUsage; fLastCPURUsage.reportCPUUsageInfo(); - Timestamp currentTime = fClock->timeSinceEpochMs(); + Timestamp currentTime = fClock->monotonicTimeSinceEpochMs(); double secondsBetweenCollection = static_cast( currentTime - fLastTimeExecutionEnvironmentMetricsCollected ) / 1000.0; fLastTimeExecutionEnvironmentMetricsCollected = currentTime; @@ -228,7 +230,7 @@ RemoteProfiler::doWork( void *data ) RemoteProfiler *profiler = static_cast( data ); while ( !profiler->fShouldStop ) { - if ( profiler->fInitialUploadInterval == 0 && profiler->fInitialLogMaxInterval == 0 ) + if ( ( profiler->fInitialUploadInterval == 0 ) && ( profiler->fInitialLogMaxInterval == 0 ) ) { profiler->fWait.wait( Signal::WaitWithPredicate ); } @@ -240,7 +242,7 @@ RemoteProfiler::doWork( void *data ) profiler->fInitialLogMaxInterval == 0 ? std::numeric_limits::max() : profiler->fInitialLogMaxInterval ) ) ); } - Timestamp currentTime = profiler->fClock->timeSinceEpochMs(); + Timestamp currentTime = profiler->fClock->monotonicTimeSinceEpochMs(); if ( profiler->fShouldStop || ( ( profiler->fLastTimeMetricsSentOut + profiler->fInitialUploadInterval ) < currentTime ) ) { diff --git a/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp b/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp index be451893..4c6b0ffa 100644 --- a/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp +++ b/src/offboardconnectivity/implementation/aws/iotcpp/src/RetryThread.cpp @@ -27,11 +27,11 @@ RetryThread::start() fShouldStop.store( false ); if ( !fThread.create( doWork, this ) ) { - fLogger.trace( "RetryThread::start", " Retry Thread failed to start " ); + fLogger.trace( "RetryThread::start", "Retry Thread failed to start" ); } else { - fLogger.trace( "RetryThread::start", " Retry Thread started " ); + fLogger.trace( "RetryThread::start", "Retry Thread started" ); fThread.setThreadName( "fwCNRetry" + std::to_string( fInstance ) ); } @@ -48,7 +48,7 @@ RetryThread::stop() std::lock_guard lock( fThreadMutex ); fShouldStop.store( true ); - fLogger.trace( "RetryThread::stop", " Request stop " ); + fLogger.trace( "RetryThread::stop", "Request stop" ); fWait.notify(); fThread.release(); fShouldStop.store( false, std::memory_order_relaxed ); @@ -66,17 +66,17 @@ RetryThread::doWork( void *data ) if ( result != RetryStatus::RETRY ) { retryThread->fLogger.trace( "RetryThread::doWork", - " Finished with code " + std::to_string( static_cast( result ) ) ); + "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 ) ); + "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" ); + retryThread->fLogger.trace( "RetryThread::doWork", "Stop thread with ABORT" ); retryThread->fRetryable.onFinished( RetryStatus::ABORT ); } \ No newline at end of file diff --git a/src/platform/linux/CMakeLists.txt b/src/platform/linux/CMakeLists.txt index e3362644..20cec941 100644 --- a/src/platform/linux/CMakeLists.txt +++ b/src/platform/linux/CMakeLists.txt @@ -104,7 +104,6 @@ set( if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) find_package(benchmark REQUIRED) # Add the executable targets @@ -114,12 +113,12 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_unit_test(${testName}) @@ -135,7 +134,7 @@ if(${BUILD_TESTING}) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE diff --git a/src/platform/linux/logmanagement/include/ConsoleLogger.h b/src/platform/linux/logmanagement/include/ConsoleLogger.h index 68e0446e..308ea7df 100644 --- a/src/platform/linux/logmanagement/include/ConsoleLogger.h +++ b/src/platform/linux/logmanagement/include/ConsoleLogger.h @@ -10,6 +10,15 @@ #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 @@ -21,11 +30,12 @@ namespace Linux /** * @brief This logger instance logs messages to the standard output. */ + class ConsoleLogger : public ILogger { public: ~ConsoleLogger() override = default; - ConsoleLogger() = default; + ConsoleLogger(); ConsoleLogger( const ConsoleLogger & ) = delete; ConsoleLogger &operator=( const ConsoleLogger & ) = delete; ConsoleLogger( ConsoleLogger && ) = delete; @@ -53,7 +63,47 @@ class ConsoleLogger : public ILogger * @return Thread ID. */ static uint64_t currentThreadId(); + + /** + * @brief converts the Log Level enum to a color for logging + * @param level the log level enum to convert + * @return empty string if unrecognized LogLevel + * */ + const std::string &levelToColor( LogLevel level ) const; + + bool mColorEnabled; }; + +enum class LogColorOption +{ + Auto, + Yes, + No +}; + +inline bool +stringToLogColorOption( const std::string level, LogColorOption &outLogColorOption ) +{ + if ( level == "Auto" ) + { + outLogColorOption = Aws::IoTFleetWise::Platform::Linux::LogColorOption::Auto; + } + else if ( level == "Yes" ) + { + outLogColorOption = Aws::IoTFleetWise::Platform::Linux::LogColorOption::Yes; + } + else if ( level == "No" ) + { + outLogColorOption = Aws::IoTFleetWise::Platform::Linux::LogColorOption::No; + } + else + { + return false; + } + return true; +} + +extern LogColorOption gLogColorOption; } // 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 8b1f3cca..a6495867 100644 --- a/src/platform/linux/logmanagement/include/TraceModule.h +++ b/src/platform/linux/logmanagement/include/TraceModule.h @@ -23,6 +23,7 @@ using namespace Aws::IoTFleetWise::Platform::Utility; /** * Different Variables defined at compile time used by all other modules * For verbose print to work it needs to be also added to getVariableName() + * Only add items at the end and do not delete items * */ enum class TraceVariable { @@ -85,9 +86,15 @@ enum class TraceVariable OBD_KEEP_ALIVE_ERROR, DISCARDED_FRAMES, CAN_POLLING_TIMESTAMP_COUNTER, + CE_PROCESSED_SIGNALS, + CE_PROCESSED_CAN_FRAMES, + CE_TRIGGERS, TRACE_VARIABLE_SIZE }; +/** + * Only add items at the end and do not delete items + */ enum class TraceAtomicVariable { QUEUE_CONSUMER_TO_INSPECTION_SIGNALS = 0, @@ -105,6 +112,7 @@ enum class TraceAtomicVariable /** * Different Sections defined at compile time used by all other modules * For verbose print to work it needs to be also added to getSectionName() + * Only add items at the end and do not delete items * */ enum class TraceSection { @@ -114,6 +122,27 @@ enum class TraceSection MANAGER_DECODER_BUILD, MANAGER_COLLECTION_BUILD, MANAGER_EXTRACTION, + CAN_DECODER_CYCLE_0, + CAN_DECODER_CYCLE_1, + CAN_DECODER_CYCLE_2, + CAN_DECODER_CYCLE_3, + CAN_DECODER_CYCLE_4, + CAN_DECODER_CYCLE_5, + CAN_DECODER_CYCLE_6, + CAN_DECODER_CYCLE_7, + CAN_DECODER_CYCLE_8, + CAN_DECODER_CYCLE_9, + CAN_DECODER_CYCLE_10, + CAN_DECODER_CYCLE_11, + CAN_DECODER_CYCLE_12, + CAN_DECODER_CYCLE_13, + CAN_DECODER_CYCLE_14, + CAN_DECODER_CYCLE_15, + CAN_DECODER_CYCLE_16, + CAN_DECODER_CYCLE_17, + CAN_DECODER_CYCLE_18, + CAN_DECODER_CYCLE_19, + CAN_DECODER_CYCLE_MAX = CAN_DECODER_CYCLE_19, TRACE_SECTION_SIZE }; /** @@ -167,11 +196,11 @@ class TraceModule void setVariable( TraceVariable variable, uint64_t value ) { - if ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) + auto index = toUType( variable ); + if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) ) { - mVariableData[toUType( variable )].mCurrentValue = value; - mVariableData[toUType( variable )].mMaxValue = - std::max( value, mVariableData[toUType( variable )].mMaxValue ); + mVariableData[index].mCurrentValue = value; + mVariableData[index].mMaxValue = std::max( value, mVariableData[index].mMaxValue ); } } @@ -188,9 +217,10 @@ class TraceModule void addToVariable( TraceVariable variable, uint64_t value ) { - if ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) + auto index = toUType( variable ); + if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) ) { - setVariable( variable, mVariableData[toUType( variable )].mCurrentValue + value ); + setVariable( variable, mVariableData[index].mCurrentValue + value ); } } @@ -225,12 +255,12 @@ class TraceModule void addToAtomicVariable( TraceAtomicVariable variable, uint64_t add ) { - if ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) + auto index = toUType( variable ); + if ( ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) && ( index >= 0 ) ) { - uint64_t currentValue = mAtomicVariableData[toUType( variable )].mCurrentValue.fetch_add( add ); + uint64_t currentValue = mAtomicVariableData[index].mCurrentValue.fetch_add( add ); // If two threads add or increment in parallel the max value might be wrong - mAtomicVariableData[toUType( variable )].mMaxValue = - std::max( currentValue + add, mAtomicVariableData[toUType( variable )].mMaxValue ); + mAtomicVariableData[index].mMaxValue = std::max( currentValue + add, mAtomicVariableData[index].mMaxValue ); } } @@ -268,9 +298,10 @@ class TraceModule void subtractFromAtomicVariable( TraceAtomicVariable variable, uint64_t sub ) { - if ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) + auto index = toUType( variable ); + if ( ( variable < TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE ) && ( index >= 0 ) ) { - mAtomicVariableData[toUType( variable )].mCurrentValue.fetch_sub( sub ); + mAtomicVariableData[index].mCurrentValue.fetch_sub( sub ); } } @@ -302,9 +333,10 @@ class TraceModule uint64_t getVariableMax( TraceVariable variable ) { - if ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) + auto index = toUType( variable ); + if ( ( variable < TraceVariable::TRACE_VARIABLE_SIZE ) && ( index >= 0 ) ) { - return mVariableData[toUType( variable )].mMaxValue; + return mVariableData[index].mMaxValue; } return 0; } diff --git a/src/platform/linux/logmanagement/src/ConsoleLogger.cpp b/src/platform/linux/logmanagement/src/ConsoleLogger.cpp index 002a5ba8..f9407d66 100644 --- a/src/platform/linux/logmanagement/src/ConsoleLogger.cpp +++ b/src/platform/linux/logmanagement/src/ConsoleLogger.cpp @@ -23,6 +23,7 @@ namespace Platform namespace Linux { LogLevel gSystemWideLogLevel; +LogColorOption gLogColorOption = LogColorOption::Auto; static std::mutex gLogForwardingMutex; static ILogger *gLogForwarder = nullptr; @@ -52,19 +53,33 @@ forwardLog( LogLevel level, const std::string &function, const std::string &logE } } +ConsoleLogger::ConsoleLogger() +{ + if ( ( gLogColorOption == LogColorOption::Yes ) || + // Connected to the terminal + ( ( gLogColorOption == LogColorOption::Auto ) && ( isatty( fileno( stdout ) ) != 0 ) ) ) + { + mColorEnabled = true; + } + else + { + mColorEnabled = false; + } +} + void ConsoleLogger::logMessage( LogLevel level, const std::string &function, const std::string &logEntry ) { if ( level >= gSystemWideLogLevel ) { - std::printf( "[Thread : %" PRIu64 "] [%s] [%s] [%s]: [%s] ", + std::printf( "%s[Thread: %" PRIu64 "] [%s] [%s] [%s]: [%s]%s\n", + levelToColor( level ).c_str(), currentThreadId(), timeAsString().c_str(), levelToString( level ).c_str(), function.c_str(), - logEntry.c_str() ); - std::printf( "\n" ); - std::fflush( stdout ); + logEntry.c_str(), + mColorEnabled ? Color::reset.c_str() : "" ); forwardLog( level, function, logEntry ); } } @@ -73,15 +88,37 @@ std::string ConsoleLogger::timeAsString() { auto clock = ClockHandler::getClock(); - return clock->timestampToString(); + return clock->currentTimeToIsoString(); +} + +const std::string & +ConsoleLogger::levelToColor( LogLevel level ) const +{ + if ( !mColorEnabled ) + { + return Color::normal; + } + + switch ( level ) + { + case LogLevel::Error: + return Color::red; + case LogLevel::Warning: + return Color::yellow; + case LogLevel::Trace: + return Color::blue; + case LogLevel::Info: + default: + return Color::normal; + } } const std::string & ILogger::levelToString( LogLevel level ) { static const std::string error( "ERROR" ); - static const std::string warn( "WARN" ); - static const std::string info( "INFO" ); + static const std::string warn( "WARN " ); // Note: extra space to align the log columns + static const std::string info( "INFO " ); // Note: extra space to align the log columns static const std::string trace( "TRACE" ); static const std::string none; diff --git a/src/platform/linux/logmanagement/src/TraceModule.cpp b/src/platform/linux/logmanagement/src/TraceModule.cpp index b5c9666f..7ca12d47 100644 --- a/src/platform/linux/logmanagement/src/TraceModule.cpp +++ b/src/platform/linux/logmanagement/src/TraceModule.cpp @@ -19,18 +19,17 @@ namespace Linux void TraceModule::sectionBegin( TraceSection section ) { - if ( section < TraceSection::TRACE_SECTION_SIZE ) + auto index = toUType( section ); + if ( ( section < TraceSection::TRACE_SECTION_SIZE ) && ( index >= 0 ) ) { auto time = std::chrono::high_resolution_clock::now(); - mSectionData[toUType( section )].mLastStartTime = time; - mSectionData[toUType( section )].mCurrentlyActive = true; - if ( mSectionData[toUType( section )].mHitCounter > 0 ) + mSectionData[index].mLastStartTime = time; + mSectionData[index].mCurrentlyActive = true; + if ( mSectionData[index].mHitCounter > 0 ) { - double interval = - std::chrono::duration( ( time - mSectionData[toUType( section )].mLastEndTime ) ).count(); - mSectionData[toUType( section )].mIntervalSum += interval; - mSectionData[toUType( section )].mMaxInterval = - std::max( mSectionData[toUType( section )].mMaxInterval, interval ); + double interval = std::chrono::duration( ( time - mSectionData[index].mLastEndTime ) ).count(); + mSectionData[index].mIntervalSum += interval; + mSectionData[index].mMaxInterval = std::max( mSectionData[index].mMaxInterval, interval ); } } } @@ -38,16 +37,16 @@ TraceModule::sectionBegin( TraceSection section ) void TraceModule::sectionEnd( TraceSection section ) { - if ( section < TraceSection::TRACE_SECTION_SIZE && mSectionData[toUType( section )].mCurrentlyActive ) + auto index = toUType( section ); + if ( ( section < TraceSection::TRACE_SECTION_SIZE ) && ( index >= 0 ) && mSectionData[index].mCurrentlyActive ) { auto time = std::chrono::high_resolution_clock::now(); - mSectionData[toUType( section )].mLastEndTime = time; - double spent = - std::chrono::duration( ( time - mSectionData[toUType( section )].mLastStartTime ) ).count(); - mSectionData[toUType( section )].mHitCounter++; - mSectionData[toUType( section )].mCurrentlyActive = false; - mSectionData[toUType( section )].mTimeSpentSum += spent; - mSectionData[toUType( section )].mMaxSpent = std::max( mSectionData[toUType( section )].mMaxSpent, spent ); + mSectionData[index].mLastEndTime = time; + double spent = std::chrono::duration( ( time - mSectionData[index].mLastStartTime ) ).count(); + mSectionData[index].mHitCounter++; + mSectionData[index].mCurrentlyActive = false; + mSectionData[index].mTimeSpentSum += spent; + mSectionData[index].mMaxSpent = std::max( mSectionData[index].mMaxSpent, spent ); } } @@ -173,6 +172,12 @@ TraceModule::getVariableName( TraceVariable variable ) return "FrmE0"; case TraceVariable::CAN_POLLING_TIMESTAMP_COUNTER: return "CanPollTCnt"; + case TraceVariable::CE_PROCESSED_SIGNALS: + return "CeSCnt"; + case TraceVariable::CE_PROCESSED_CAN_FRAMES: + return "CeCCnt"; + case TraceVariable::CE_TRIGGERS: + return "CeTrgCnt"; default: return "UNKNOWN"; } @@ -223,6 +228,46 @@ TraceModule::getSectionName( TraceSection section ) return "COL_BUILD"; case TraceSection::MANAGER_EXTRACTION: return "EXTRACT"; + case TraceSection::CAN_DECODER_CYCLE_0: + return "CD_0"; + case TraceSection::CAN_DECODER_CYCLE_1: + return "CD_1"; + case TraceSection::CAN_DECODER_CYCLE_2: + return "CD_2"; + case TraceSection::CAN_DECODER_CYCLE_3: + return "CD_3"; + case TraceSection::CAN_DECODER_CYCLE_4: + return "CD_4"; + case TraceSection::CAN_DECODER_CYCLE_5: + return "CD_5"; + case TraceSection::CAN_DECODER_CYCLE_6: + return "CD_6"; + case TraceSection::CAN_DECODER_CYCLE_7: + return "CD_7"; + case TraceSection::CAN_DECODER_CYCLE_8: + return "CD_8"; + case TraceSection::CAN_DECODER_CYCLE_9: + return "CD_9"; + case TraceSection::CAN_DECODER_CYCLE_10: + return "CD_10"; + case TraceSection::CAN_DECODER_CYCLE_11: + return "CD_11"; + case TraceSection::CAN_DECODER_CYCLE_12: + return "CD_12"; + case TraceSection::CAN_DECODER_CYCLE_13: + return "CD_13"; + case TraceSection::CAN_DECODER_CYCLE_14: + return "CD_14"; + case TraceSection::CAN_DECODER_CYCLE_15: + return "CD_15"; + case TraceSection::CAN_DECODER_CYCLE_16: + return "CD_16"; + case TraceSection::CAN_DECODER_CYCLE_17: + return "CD_17"; + case TraceSection::CAN_DECODER_CYCLE_18: + return "CD_18"; + case TraceSection::CAN_DECODER_CYCLE_19: + return "CD_19"; default: return "UNKNOWN"; } diff --git a/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp b/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp index eef5f569..9313203a 100644 --- a/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp +++ b/src/platform/linux/persistencymanagement/src/CacheAndPersist.cpp @@ -26,24 +26,24 @@ CacheAndPersist::init() { if ( createFile( mDecoderManifestFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", " Failed to create decoder manifest file " ); + mLogger.error( "PersistencyManagement::init", "Failed to create decoder manifest file" ); return false; } if ( createFile( mCollectionSchemeListFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", " Failed to create collectionScheme list file " ); + mLogger.error( "PersistencyManagement::init", "Failed to create collectionScheme list file" ); return false; } if ( createFile( mCollectedDataFile ) != ErrorCode::SUCCESS ) { - mLogger.error( "PersistencyManagement::init", " Failed to create collected data file " ); + mLogger.error( "PersistencyManagement::init", "Failed to create collected data file" ); return false; } - mLogger.info( "PersistencyManagement::init", " Persistency library successfully initialised. " ); + mLogger.info( "PersistencyManagement::init", "Persistency library successfully initialised" ); return true; } @@ -114,7 +114,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 " ); + mLogger.error( "PersistencyManagement::write", "Invalid data type specified" ); return status; } @@ -132,7 +132,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 " ); + mLogger.error( "PersistencyManagement::write", "Could not open file" ); } else { @@ -140,7 +140,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 " ); + mLogger.error( "PersistencyManagement::write", "Error writing to the file" ); } file.close(); } @@ -170,7 +170,7 @@ CacheAndPersist::getSize( DataType dataType ) break; default: - mLogger.error( "PersistencyManagement::getSize", " Invalid data type specified " ); + mLogger.error( "PersistencyManagement::getSize", "Invalid data type specified" ); return INVALID_FILE_SIZE; } @@ -210,7 +210,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 " ); + mLogger.error( "PersistencyManagement::read", "Invalid data type specified" ); return status; } @@ -218,7 +218,7 @@ CacheAndPersist::read( uint8_t *const readBufPtr, size_t size, DataType dataType if ( !file.is_open() ) { - mLogger.error( "PersistencyManagement::read", " Error opening file" ); + mLogger.error( "PersistencyManagement::read", "Error opening file" ); status = ErrorCode::FILESYSTEM_ERROR; } else @@ -235,7 +235,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" ); + mLogger.error( "PersistencyManagement::read", "Error reading file" ); status = ErrorCode::FILESYSTEM_ERROR; } } @@ -267,7 +267,7 @@ CacheAndPersist::erase( DataType dataType ) default: status = ErrorCode::INVALID_DATATYPE; - mLogger.error( "PersistencyManagement::erase", " Invalid data type specified " ); + mLogger.error( "PersistencyManagement::erase", "Invalid data type specified" ); return status; } @@ -277,7 +277,7 @@ CacheAndPersist::erase( DataType dataType ) if ( !file.is_open() ) { status = ErrorCode::FILESYSTEM_ERROR; - mLogger.error( "PersistencyManagement::erase", " Error erasing the file " ); + mLogger.error( "PersistencyManagement::erase", "Error erasing the file" ); } else { diff --git a/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h b/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h index 04939e56..2973897b 100644 --- a/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h +++ b/src/platform/linux/resourcemanagement/include/CPUUsageInfo.h @@ -45,6 +45,10 @@ class CPUUsageInfo inline double getCPUPercentage( const ThreadCPUUsageInfo &previousUsage, const double &elapsedSeconds ) const { + if ( elapsedSeconds == 0.0 ) + { + return 0.0; + } double userSpaceTime = ( mUserSpaceTime - previousUsage.mUserSpaceTime ); double kernelSpaceTime = ( mKernelSpaceTime - previousUsage.mKernelSpaceTime ); return round( ( ( userSpaceTime + kernelSpaceTime ) / elapsedSeconds ) * 10000.0 ) / 100.0; @@ -152,6 +156,10 @@ CPUUsageInfo::getNumCPUCores() const inline double CPUUsageInfo::getCPUPercentage( const CPUUsageInfo &previousUsage, const double &elapsedSeconds ) const { + if ( elapsedSeconds == 0.0 ) + { + return 0.0; + } double userTime = ( mUserSpaceTime - previousUsage.getUserSpaceTime() ); double systemTime = ( mKernelSpaceTime - previousUsage.getKernelSpaceTime() ); return round( ( userTime + systemTime ) / elapsedSeconds * 10000.0 ) / 100.0; @@ -160,6 +168,10 @@ CPUUsageInfo::getCPUPercentage( const CPUUsageInfo &previousUsage, const double inline double CPUUsageInfo::getTotalCPUPercentage( const CPUUsageInfo &previousUsage, const double &elapsedSeconds ) const { + if ( ( mNumCPUCores == 0 ) || ( elapsedSeconds == 0.0 ) ) + { + return 0.0; + } double userTime = ( mUserSpaceTime - previousUsage.getUserSpaceTime() ) / mNumCPUCores; double systemTime = ( mKernelSpaceTime - previousUsage.getKernelSpaceTime() ) / mNumCPUCores; return round( ( userTime + systemTime ) / elapsedSeconds * 10000.0 ) / 100.0; diff --git a/src/platform/linux/resourcemanagement/src/CPUUsageInfo.cpp b/src/platform/linux/resourcemanagement/src/CPUUsageInfo.cpp index 84ca171e..868cde0b 100644 --- a/src/platform/linux/resourcemanagement/src/CPUUsageInfo.cpp +++ b/src/platform/linux/resourcemanagement/src/CPUUsageInfo.cpp @@ -79,7 +79,7 @@ CPUUsageInfo::reportPerThreadUsageData( CPUUsageInfo::ThreadCPUUsageInfos &threa while ( ( dp = readdir( taskDir ) ) != nullptr ) { std::string taskFileName = dp->d_name; - if ( taskFileName.length() > 0 && taskFileName[0] != '.' ) + if ( ( taskFileName.length() > 0 ) && ( taskFileName[0] != '.' ) ) { FILE *fp = nullptr; std::string pathToThreadCPUUsageInfo = "/proc/self/task/" + taskFileName + "/stat"; @@ -123,7 +123,7 @@ CPUUsageInfo::reportPerThreadUsageData( CPUUsageInfo::ThreadCPUUsageInfos &threa { if ( currentField == 2 ) { - if ( commStringFinished && *c == ' ' ) + if ( commStringFinished && ( *c == ' ' ) ) { currentField++; } @@ -153,7 +153,7 @@ CPUUsageInfo::reportPerThreadUsageData( CPUUsageInfo::ThreadCPUUsageInfos &threa int64_t uTime = strtoll( utimeString.c_str(), nullptr, 10 ); int64_t sTime = strtoll( stimeString.c_str(), nullptr, 10 ); - if ( uTime != LONG_MAX && uTime >= 0 && sTime != LONG_MAX && sTime >= 0 ) + if ( ( uTime != LONG_MAX ) && ( uTime >= 0 ) && ( sTime != LONG_MAX ) && ( sTime >= 0 ) ) { threadCPUUsageInfos.emplace_back( CPUUsageInfo::ThreadCPUUsageInfo{ tid, diff --git a/src/platform/linux/resourcemanagement/src/MemoryUsageInfo.cpp b/src/platform/linux/resourcemanagement/src/MemoryUsageInfo.cpp index 4b716265..16691be5 100644 --- a/src/platform/linux/resourcemanagement/src/MemoryUsageInfo.cpp +++ b/src/platform/linux/resourcemanagement/src/MemoryUsageInfo.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include namespace Aws diff --git a/src/platform/linux/threadingmanagement/include/Thread.h b/src/platform/linux/threadingmanagement/include/Thread.h index 0cb82ba6..2f343354 100644 --- a/src/platform/linux/threadingmanagement/include/Thread.h +++ b/src/platform/linux/threadingmanagement/include/Thread.h @@ -69,6 +69,9 @@ class Thread */ static void SetCurrentThreadName( const std::string &name ); + // callback called from thread implementation library like pthread + static void *workerFunctionWrapper( void *params ); + private: struct ThreadSettings { @@ -76,7 +79,6 @@ class Thread WorkerFunction mWorkerFunction{ nullptr }; void *mParams{ nullptr }; }; - static void *workerFunctionWrapper( void *params ); unsigned long getThreadID() const; diff --git a/src/platform/linux/threadingmanagement/src/Thread.cpp b/src/platform/linux/threadingmanagement/src/Thread.cpp index f516a69e..16b623df 100644 --- a/src/platform/linux/threadingmanagement/src/Thread.cpp +++ b/src/platform/linux/threadingmanagement/src/Thread.cpp @@ -7,7 +7,6 @@ #include "Thread.h" #include #include -#include namespace Aws { @@ -18,6 +17,15 @@ namespace Platform namespace Linux { +extern "C" +{ + static void * + workerFunctionWrapperC( void *params ) + { + return Thread::workerFunctionWrapper( params ); + } +} + bool Thread::create( WorkerFunction workerFunction, void *execParam ) { @@ -28,7 +36,7 @@ Thread::create( WorkerFunction workerFunction, void *execParam ) mDone.store( false ); mTerminateSignal = std::make_unique(); - if ( pthread_create( &mThread, nullptr, Thread::workerFunctionWrapper, &mExecParams ) != 0 ) + if ( pthread_create( &mThread, nullptr, workerFunctionWrapperC, &mExecParams ) != 0 ) { mThreadId = 0; @@ -54,7 +62,7 @@ Thread::release() // Wait till the Predicate mTerminateSignal->wait( Signal::WaitWithPredicate ); - if ( mThread != 0u && pthread_join( mThread, nullptr ) != 0 ) + if ( ( mThread != 0u ) && ( pthread_join( mThread, nullptr ) != 0 ) ) { return false; } diff --git a/src/platform/linux/timemanagement/include/Clock.h b/src/platform/linux/timemanagement/include/Clock.h index 0c300bdb..de713793 100644 --- a/src/platform/linux/timemanagement/include/Clock.h +++ b/src/platform/linux/timemanagement/include/Clock.h @@ -17,28 +17,69 @@ namespace Linux { /** - * @brief Clock API. Offers the system time since EPOCH. + * @brief Clock API. Offers the time based on multiple clocks. */ class Clock { public: /** - * @brief Computes the timestamp since epoch from the system clock + * @brief Computes the timestamp since Unix epoch from the system clock + * + * This should not be used for measuring intervals, elapsed time, duration, etc. Use + * monotonicTimeSinceEpochMs() instead. + * * @return timestamp in milliseconds */ - virtual Timestamp timeSinceEpochMs() const = 0; + virtual Timestamp systemTimeSinceEpochMs() const = 0; /** - * @brief Convert the current time to "%Y-%m-%d %I:%M:%S %p" format. + * @brief Computes the timestamp since epoch from a monotonic clock + * + * Note that epoch in this case is not the Unix timestamp epoch, but rather it can be + * any arbitrary moment (e.g. since the system started) + * + * @return timestamp in milliseconds + */ + virtual Timestamp monotonicTimeSinceEpochMs() const = 0; + + /** + * @brief Computes the timestamp since epoch from multiple clocks + * + * Note that epoch in this case is not necessarily the Unix timestamp epoch. For a monotonic clock, + * for example, it can be any arbitrary moment (e.g. since the system started). + * + * @return a TimePoint struct containing the time based on different clocks. + * WARNING: Since there is no way to atomically get the clock from multiple sources, those times could be + * slightly out of sync, especially if the thread is interrupted between different clock calls. + */ + virtual TimePoint timeSinceEpoch() const = 0; + + /** + * @brief Convert the current time to ISO 8601 format. * @return current time in a string format */ - virtual std::string timestampToString() const = 0; + virtual std::string currentTimeToIsoString() const = 0; /** * @brief virtual destructor */ virtual ~Clock() = default; }; + +/** + * @brief Computes the monotonic timestamp corresponding to the given system timestamp + * + * This is intended to be used when the timestamp is extracted from the data as system time only. + * But when calculating intervals we need to use a monotonic clock to be resilient to system time changes. + * So this function can be used to calculate a monotonic time based on the current time. + * + * Please note that this is not always possible. In situations where the calculated monotonic time would + * be negative, TimePoint {0, 0} is returned. + * + * @return a TimePoint struct containing the given system time and the corresponding monotonic time + */ +TimePoint timePointFromSystemTime( const TimePoint &currTime, Timestamp systemTimeMs ); + } // namespace Linux } // namespace Platform } // namespace IoTFleetWise diff --git a/src/platform/linux/timemanagement/include/TimeTypes.h b/src/platform/linux/timemanagement/include/TimeTypes.h index 7f9141d0..007ba6cc 100644 --- a/src/platform/linux/timemanagement/include/TimeTypes.h +++ b/src/platform/linux/timemanagement/include/TimeTypes.h @@ -18,6 +18,20 @@ namespace Linux using Timestamp = std::uint64_t; +/** + * @brief Represents a time point based on different clocks + * + * A particular use case for this is when passing down the current time as a parameter. + * Depending on the situation either system time or a monotonic time should be used, so + * it is preferable to pass this struct and let the implementation decide which one is + * needed. + */ +struct TimePoint +{ + Timestamp systemTimeMs; + Timestamp monotonicTimeMs; +}; + } // namespace Linux } // namespace Platform } // namespace IoTFleetWise diff --git a/src/platform/linux/timemanagement/include/Timer.h b/src/platform/linux/timemanagement/include/Timer.h index ccc95ca7..d5a29c28 100644 --- a/src/platform/linux/timemanagement/include/Timer.h +++ b/src/platform/linux/timemanagement/include/Timer.h @@ -23,7 +23,6 @@ class Timer public: using Clock = std::chrono::steady_clock; using Duration = Clock::duration; - using DurationUs = std::chrono::microseconds; using DurationMs = std::chrono::milliseconds; using TimePoint = Clock::time_point; diff --git a/src/platform/linux/timemanagement/src/ClockHandler.cpp b/src/platform/linux/timemanagement/src/ClockHandler.cpp index a1112c9c..e49126fb 100644 --- a/src/platform/linux/timemanagement/src/ClockHandler.cpp +++ b/src/platform/linux/timemanagement/src/ClockHandler.cpp @@ -23,7 +23,7 @@ class ChronoClock : public Clock { public: Timestamp - timeSinceEpochMs() const override + systemTimeSinceEpochMs() const override { return static_cast( std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch() ) @@ -31,16 +31,65 @@ class ChronoClock : public Clock } std::string - timestampToString() const override + currentTimeToIsoString() const override { std::stringstream timeAsString; 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::localtime( &timeNowFormatted ), "%Y-%m-%d %I:%M:%S %p" ); + timeAsString << std::put_time( std::gmtime( &timeNowFormatted ), "%FT%T." ) << std::setfill( '0' ) + << std::setw( 3 ) << ms << "Z"; return timeAsString.str(); } + + Timestamp + monotonicTimeSinceEpochMs() const override + { + return static_cast( + std::chrono::duration_cast( std::chrono::steady_clock::now().time_since_epoch() ) + .count() ); + } + + TimePoint + timeSinceEpoch() const override + { + return TimePoint{ systemTimeSinceEpochMs(), monotonicTimeSinceEpochMs() }; + } }; +TimePoint +timePointFromSystemTime( const TimePoint &currTime, Timestamp systemTimeMs ) +{ + if ( systemTimeMs >= currTime.systemTimeMs ) + { + Timestamp differenceMs = systemTimeMs - currTime.systemTimeMs; + return TimePoint{ systemTimeMs, currTime.monotonicTimeMs + differenceMs }; + } + else + { + Timestamp differenceMs = currTime.systemTimeMs - systemTimeMs; + if ( differenceMs <= currTime.monotonicTimeMs ) + { + return TimePoint{ systemTimeMs, currTime.monotonicTimeMs - differenceMs }; + } + else + { + // Not much we can do here. The system time corresponds to a time in the past before the monotonic + // clock started ticking, so we would need to represent it as a negative number. This could happen in the + // case the obtained timestamp is completely out of sync with the system time, or when the system time + // changes between the moment the timestamp was extracted and the moment we are checking here. + // + // For example: + // 1. Timestamp is extracted from the message, corresponding to 08:00:00 + // 2. System time is changed to 2 hours into the future + // 3. We obtain the current system time (which is now 10:00:00) and monotonic time + // 4. If the monotonic time is small enough (e.g. less than 2 * 60 * 60 * 1000 = 7200000 ms), this situation + // will happen. + return TimePoint{ 0, 0 }; + } + } +} + std::shared_ptr ClockHandler::getClock() { diff --git a/src/platform/linux/timemanagement/test/ClockHandlerBenchmarkTest.cpp b/src/platform/linux/timemanagement/test/ClockHandlerBenchmarkTest.cpp index 651c468a..ebb3d0a1 100644 --- a/src/platform/linux/timemanagement/test/ClockHandlerBenchmarkTest.cpp +++ b/src/platform/linux/timemanagement/test/ClockHandlerBenchmarkTest.cpp @@ -10,18 +10,18 @@ BM_timestampToString( benchmark::State &state ) auto clock = ClockHandler::getClock(); for ( auto _ : state ) { - clock->timestampToString(); + clock->currentTimeToIsoString(); } } BENCHMARK( BM_timestampToString ); static void -BM_timeSinceEpochMs( benchmark::State &state ) +BM_systemTimeSinceEpochMs( benchmark::State &state ) { auto clock = ClockHandler::getClock(); for ( auto _ : state ) - clock->timeSinceEpochMs(); + clock->systemTimeSinceEpochMs(); } -BENCHMARK( BM_timeSinceEpochMs ); +BENCHMARK( BM_systemTimeSinceEpochMs ); BENCHMARK_MAIN(); \ No newline at end of file diff --git a/src/platform/linux/timemanagement/test/ClockHandlerTest.cpp b/src/platform/linux/timemanagement/test/ClockHandlerTest.cpp index 467c7708..8c054d4f 100644 --- a/src/platform/linux/timemanagement/test/ClockHandlerTest.cpp +++ b/src/platform/linux/timemanagement/test/ClockHandlerTest.cpp @@ -8,9 +8,9 @@ using namespace Aws::IoTFleetWise::Platform::Linux; -TEST( ClockHandlerTest, timeSinceEpochMs ) +TEST( ClockHandlerTest, systemTimeSinceEpochMs ) { auto clock = ClockHandler::getClock(); ASSERT_NE( clock.get(), nullptr ); - ASSERT_GT( clock->timeSinceEpochMs(), 0ull ); + ASSERT_GT( clock->systemTimeSinceEpochMs(), 0ull ); } diff --git a/src/platform/utility/CMakeLists.txt b/src/platform/utility/CMakeLists.txt index b3d760dd..bca7ef42 100644 --- a/src/platform/utility/CMakeLists.txt +++ b/src/platform/utility/CMakeLists.txt @@ -7,11 +7,10 @@ set(libraryAliasName IoTFleetWise::Platform::Utility) add_library( ${libraryTargetName} - # STATIC or SHARED left out to depend on BUILD_SHARED_LIBS - src/EnumUtility.cpp + INTERFACE ) -target_include_directories(${libraryTargetName} PUBLIC include) +target_include_directories(${libraryTargetName} INTERFACE include) add_library(${libraryAliasName} ALIAS ${libraryTargetName}) diff --git a/src/platform/utility/src/EnumUtility.cpp b/src/platform/utility/src/EnumUtility.cpp deleted file mode 100644 index f4d8c1e7..00000000 --- a/src/platform/utility/src/EnumUtility.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "EnumUtility.h" diff --git a/src/testingsupport/CMakeLists.txt b/src/testingsupport/CMakeLists.txt index 94370522..8bd3ef53 100644 --- a/src/testingsupport/CMakeLists.txt +++ b/src/testingsupport/CMakeLists.txt @@ -7,18 +7,21 @@ set(libraryAliasName IoTFleetWise::TestingSupport) add_library( ${libraryTargetName} - INTERFACE # Note: Header only library - remove this line if sources are added + # STATIC or SHARED left out to depend on BUILD_SHARED_LIBS + src/main.cpp ) +find_package(GTest REQUIRED) + target_include_directories(${libraryTargetName} - INTERFACE # Note: Header only library - remove this line if sources are added above + PUBLIC include ) target_link_libraries( ${libraryTargetName} - INTERFACE # Note: Header only library - remove this line if sources are added above IoTFleetWise::Platform::Linux + GTest::GTest ) add_library(${libraryAliasName} ALIAS ${libraryTargetName}) @@ -30,6 +33,7 @@ install(TARGETS ${libraryTargetName} DESTINATION lib) install( FILES include/Faketime.h + include/Testing.h DESTINATION include ) @@ -38,8 +42,6 @@ install( if(${BUILD_TESTING} AND FWE_TEST_FAKETIME) message(STATUS "Building tests for ${libraryTargetName}") - find_package(GTest REQUIRED) - set( testSources test/FakeSystemTimeTest.cpp @@ -51,12 +53,12 @@ if(${BUILD_TESTING} AND FWE_TEST_FAKETIME) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_unit_test_with_faketime(${testName}) diff --git a/src/testingsupport/include/Testing.h b/src/testingsupport/include/Testing.h new file mode 100644 index 00000000..d40162bc --- /dev/null +++ b/src/testingsupport/include/Testing.h @@ -0,0 +1,48 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +// Includes +#include "TimeTypes.h" + +namespace Aws +{ +namespace IoTFleetWise +{ +namespace TestingSupport +{ + +using TimePoint = Aws::IoTFleetWise::Platform::Linux::TimePoint; +using Timestamp = Aws::IoTFleetWise::Platform::Linux::Timestamp; + +TimePoint +operator+( const TimePoint &time, Timestamp increment ) +{ + return { time.systemTimeMs + increment, time.monotonicTimeMs + increment }; +} + +TimePoint & +operator+=( TimePoint &time, Timestamp increment ) +{ + time.systemTimeMs += increment; + time.monotonicTimeMs += increment; + return time; +} + +TimePoint +operator++( TimePoint &time, int ) +{ + time += 1; + return time; +} + +bool +operator==( const TimePoint &left, const TimePoint &right ) +{ + return left.systemTimeMs == right.systemTimeMs && left.monotonicTimeMs == right.monotonicTimeMs; +} + +} // namespace TestingSupport +} // namespace IoTFleetWise +} // namespace Aws diff --git a/src/testingsupport/src/main.cpp b/src/testingsupport/src/main.cpp new file mode 100644 index 00000000..04b2ba06 --- /dev/null +++ b/src/testingsupport/src/main.cpp @@ -0,0 +1,20 @@ +#include "ConsoleLogger.h" +#include "LogLevel.h" +#include + +using namespace Aws::IoTFleetWise::Platform::Linux; + +static void +configureLogging() +{ + gSystemWideLogLevel = LogLevel::Trace; + gLogColorOption = LogColorOption::Yes; +} + +int +main( int argc, char **argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + configureLogging(); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/src/vehiclenetwork/CMakeLists.txt b/src/vehiclenetwork/CMakeLists.txt index d1e3ae23..c7f41ffa 100644 --- a/src/vehiclenetwork/CMakeLists.txt +++ b/src/vehiclenetwork/CMakeLists.txt @@ -114,7 +114,6 @@ if(${BUILD_TESTING}) message(STATUS "Building tests for ${libraryTargetName}") file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test/CameraSubscriberTestPNG.png DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) - find_package(GTest REQUIRED) # Add the executable targets foreach(testSource ${testSources}) @@ -122,12 +121,12 @@ if(${BUILD_TESTING}) get_filename_component(testName ${testSource} NAME_WE) add_executable(${testName} ${testSource}) - # Link to the project library and GTest main + # Link to the project library and testing library main target_link_libraries( ${testName} PRIVATE ${libraryTargetName} - GTest::Main + IoTFleetWise::TestingSupport ) add_unit_test(${testName}) add_valgrind_test(${testName}) diff --git a/src/vehiclenetwork/include/businterfaces/AbstractVehicleDataSource.h b/src/vehiclenetwork/include/businterfaces/AbstractVehicleDataSource.h index fc5c7e31..af1cb45f 100644 --- a/src/vehiclenetwork/include/businterfaces/AbstractVehicleDataSource.h +++ b/src/vehiclenetwork/include/businterfaces/AbstractVehicleDataSource.h @@ -22,9 +22,6 @@ using namespace Aws::IoTFleetWise::Platform::Linux; // Single Producer/Consumer buffer. Used for data processing between the source and the consumer. using VehicleMessageCircularBuffer = boost::lockfree::spsc_queue; using VehicleMessageCircularBufferPtr = std::shared_ptr; -// Multi Producer/Single Consumer buffer. Used for raw data propagation. -using VehicleRawMessageCircularBuffer = boost::lockfree::queue; -using VehicleRawMessageCircularBufferPtr = std::shared_ptr; /** * @brief Abstract Interface for a Vehicle Data Source. A data source maps to exactly one Transport * Connector implementation. The Transport protocol details are abstracted away so that users of diff --git a/src/vehiclenetwork/include/businterfaces/CANDataSource.h b/src/vehiclenetwork/include/businterfaces/CANDataSource.h index a7e90109..fb7eabfc 100644 --- a/src/vehiclenetwork/include/businterfaces/CANDataSource.h +++ b/src/vehiclenetwork/include/businterfaces/CANDataSource.h @@ -102,8 +102,6 @@ class CANDataSource : public AbstractVehicleDataSource // Main work function. Listens on the socket for CAN Messages // and push data to the circular buffer. static void doWork( void *data ); - // Current non deterministic size of the circular buffer - size_t queueSize() const; Timestamp extractTimestamp( struct msghdr *msgHeader ); diff --git a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h index 42662041..b169c53b 100644 --- a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h +++ b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANReceiver.h @@ -68,6 +68,16 @@ class ISOTPOverCANReceiver */ bool receivePDU( std::vector &pduData ); + /** + * @brief Returns the socket + * @return Socket + */ + int + getSocket() const + { + return mSocket; + } + private: ISOTPOverCANReceiverOptions mReceiverOptions; Timer mTimer; diff --git a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h index f0c36c1f..0d96958b 100644 --- a/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h +++ b/src/vehiclenetwork/include/businterfaces/ISOTPOverCANSenderReceiver.h @@ -76,6 +76,23 @@ class ISOTPOverCANSenderReceiver */ bool sendPDU( const std::vector &pduData ); + /** + * @brief Flush socket to ignore the received data + * @param timeout poll timeout in ms + * @return Time in ms needed for poll + */ + uint32_t flush( uint32_t timeout ); + + /** + * @brief Returns the socket + * @return Socket + */ + int + getSocket() const + { + return mSocket; + } + private: ISOTPOverCANSenderReceiverOptions mSenderReceiverOptions; Timer mTimer; diff --git a/src/vehiclenetwork/include/datatypes/ISOTPOverCANOptions.h b/src/vehiclenetwork/include/datatypes/ISOTPOverCANOptions.h index 26e9e6eb..00632ab3 100644 --- a/src/vehiclenetwork/include/datatypes/ISOTPOverCANOptions.h +++ b/src/vehiclenetwork/include/datatypes/ISOTPOverCANOptions.h @@ -14,8 +14,8 @@ namespace IoTFleetWise namespace VehicleNetwork { // According to J1979 6.2.2.7, we should wait at least P2CAN Max ( 50 ms ) -// We relax that a bit e.g. up to 100 ms for network latency. -const uint32_t P2_TIMEOUT_DEFAULT_MS = 5000; // P2*CAN Max is 5 seconds. To be tuned +// We relax that a bit e.g. up to 1000 ms for network latency. +const uint32_t P2_TIMEOUT_DEFAULT_MS = 1000; // P2*CAN Max is 1 second const uint32_t P2_TIMEOUT_INFINITE = 0; /** * @brief Set of Options a Sender of a PDU must provide to the ISO-TP Stack diff --git a/src/vehiclenetwork/include/datatypes/OBDDataTypesUnitTestOnly.h b/src/vehiclenetwork/include/datatypes/OBDDataTypesUnitTestOnly.h index 80d5d419..94680617 100644 --- a/src/vehiclenetwork/include/datatypes/OBDDataTypesUnitTestOnly.h +++ b/src/vehiclenetwork/include/datatypes/OBDDataTypesUnitTestOnly.h @@ -16,6 +16,15 @@ using namespace Aws::IoTFleetWise::VehicleNetwork; using namespace Aws::IoTFleetWise::Platform::Linux; using namespace Aws::IoTFleetWise::Platform::Utility; +// Struct represent PID information: id, return length and formula for each signal +struct PIDInfo +{ + PID pid; // id for PID, used to query ECU + size_t retLen; // expected number of bytes in response + std::vector + formulas; // formula per signal. For multi-signal PID, this would contains multiple formulas. +}; + // This table is only used by unit test. // The actual Edge Agent will only use decoding manifest received from AWS const std::array mode1PIDs = { { @@ -382,6 +391,145 @@ const std::array mode1PIDs = { { { 0xC1, 1, { {} } } // HVESS Recommended Maximum State Of Charge } }; +// clang-format off +// Subset of Emission related PIDs that are supported by this SW +// Every new PID we support should be updated on those next +// structs +enum class EmissionPIDs +{ + PIDS_SUPPORTED_01_20 = 0X00, + FUEL_SYSTEM_STATUS = 0X03, + ENGINE_LOAD = 0X04, + ENGINE_COOLANT_TEMPERATURE = 0X05, + SHORT_TERM_FUEL_TRIM_BANK_1 = 0X06, + LONG_TERM_FUEL_TRIM_BANK_1 = 0X07, + SHORT_TERM_FUEL_TRIM_BANK_2 = 0X08, + LONG_TERM_FUEL_TRIM_BANK_2 = 0X09, + FUEL_PRESSURE = 0X0A, + INTAKE_MANIFOLD_ABSOLUTE_PRESSURE = 0X0B, + ENGINE_SPEED = 0X0C, + VEHICLE_SPEED = 0X0D, + TIMING_ADVANCE = 0X0E, + INTAKE_AIR_FLOW_TEMPERATURE = 0X0F, + MAF_RATE = 0X10, + THROTTLE_POSITION = 0X11, + OXYGEN_SENSORS_PRESENT = 0X13, + OXYGEN_SENSOR1_1 = 0X14, + OXYGEN_SENSOR2_1 = 0X15, + OXYGEN_SENSOR3_1 = 0X16, + OXYGEN_SENSOR4_1 = 0X17, + OXYGEN_SENSOR5_1 = 0X18, + OXYGEN_SENSOR6_1 = 0X19, + OXYGEN_SENSOR7_1 = 0X1A, + OXYGEN_SENSOR8_1 = 0X1B, + RUNTIME_SINCE_ENGINE_START = 0X1F, + PIDS_SUPPORTED_21_40 = 0X20, + DISTANCE_TRAVELED_WITH_MIL = 0X21, + FUEL_RAIL_PRESSURE = 0X22, + FUEL_RAIL_GAUGE_PRESSURE = 0X23, + OXYGEN_SENSOR1_2 = 0X24, + OXYGEN_SENSOR2_2 = 0X25, + OXYGEN_SENSOR3_2 = 0X26, + OXYGEN_SENSOR4_2 = 0X27, + OXYGEN_SENSOR5_2 = 0X28, + OXYGEN_SENSOR6_2 = 0X29, + OXYGEN_SENSOR7_2 = 0X2A, + OXYGEN_SENSOR8_2 = 0X2B, + EGR_ERROR = 0X2D, + FUEL_TANK_LEVEL = 0X2F, + WARM_UPS_SINCE_CODES_CLEARED = 0X30, + DISTANCE_TRAVELED_SINCE_CLEARED_DTC = 0X31, + EVAP_SYSTEM_VAPOR_PRESSURE = 0X32, + ABSOLUTE_BAROMETRIC_PRESSURE = 0X33, + OXYGEN_SENSOR1_3 = 0X34, + OXYGEN_SENSOR2_3 = 0X35, + OXYGEN_SENSOR3_3 = 0X36, + OXYGEN_SENSOR4_3 = 0X37, + OXYGEN_SENSOR5_3 = 0X38, + OXYGEN_SENSOR6_3 = 0X39, + OXYGEN_SENSOR7_3 = 0X3A, + OXYGEN_SENSOR8_3 = 0X3B, + CATALYST_TEMPERATURE_BANK1_SENSOR1 = 0X3C, + CATALYST_TEMPERATURE_BANK2_SENSOR1 = 0X3D, + CATALYST_TEMPERATURE_BANK1_SENSOR2 = 0X3E, + CATALYST_TEMPERATURE_BANK2_SENSOR2 = 0X3F, + PIDS_SUPPORTED_41_60 = 0X40, + CONTROL_MODULE_VOLTAGE = 0X42, + ABSOLUTE_LOAD_VALUE = 0X43, + COMMANDED_AIR_FUEL_EQUIVALENCE_RATIO = 0X44, + RELATIVE_THROTTLE_POSITION = 0X45, + AMBIENT_AIR_TEMPERATURE = 0X46, + ABSOLUTE_THROTTLE_POSITION_B = 0X47, + ABSOLUTE_THROTTLE_POSITION_C = 0X48, + ACCELERATOR_PEDAL_POSITION_D = 0X49, + ACCELERATOR_PEDAL_POSITION_E = 0X4A, + ACCELERATOR_PEDAL_POSITION_F = 0X4B, + TIME_RUN_WITH_MIL_ON = 0X4D, + TIME_SINCE_TROUBLE_CODES_CLEARED = 0X4E, + FUEL_TYPE = 0X51, + ALCOHOL_FUEL_PERCENTAGE = 0X52, + FUEL_RAIL_ABSOLUTE_PRESSURE = 0X59, + RELATIVE_ACCELERATOR_PEDAL_POSITION = 0X5A, + HYBRID_BATTERY_PACK_REMAINING_LIFE = 0X5B, + ENGINE_OIL_TEMPERATURE = 0X5C, + FUEL_INJECTION_TIMING = 0X5D, + ENGINE_FUEL_RATE = 0X5E, + PIDS_SUPPORTED_61_80 = 0X60, + DRIVER_DEMAND_PERCENT_TORQUE = 0X61, + ACTUAL_PERCENT_TORQUE = 0X62, + ENGINE_REFERENCE_PERCENT_TORQUE = 0X63, + ENGINE_PERCENT_TORQUE_DATA = 0X64, + MASS_AIR_FLOW_SENSOR = 0X66, + ENGINE_COOLANT_TEMPERATURE_1_2 = 0X67, + INTAKE_AIR_TEMPERATURE_SENSOR = 0X68, + COMMANDED_EGR_AND_EGR_ERROR = 0X69, + COMMANDED_DIESEL_INTAKE_AIR_FLOW_CONTROL_AND_RELATIVE_INTAKE_AIR_FLOW_POSITION = 0X6A, + EXHAUST_GAS_RECIRCULATION_TEMPERATURE = 0X6B, + COMMANDED_THROTTLE_ACTUATOR_CONTROL_AND_RELATIVE_THROTTLE_POSITION = 0X6C, + FUEL_PRESSURE_CONTROL_SYSTEM = 0X6D, + INJECTION_PRESSURE_CONTROL_SYSTEM = 0X6E, + TURBOCHARGER_COMPRESSOR_INLET_PRESSURE = 0X6F, + BOOST_PRESSURE_CONTROL = 0X70, + VARIABLE_GEOMETRY_TURBO_CONTROL = 0X71, + WASTEGATE_CONTROL = 0X72, + EXHAUST_PRESSURE = 0X73, + TURBOCHARGER_RPM = 0X74, + TURBOCHARGER_TEMPERATURE_A = 0X75, + TURBOCHARGER_TEMPERATURE_B = 0X76, + CHARGE_AIR_COOLER_TEMPERATURE = 0X77, + EXHAUST_GAS_TEMPERATURE_BANK1 = 0X78, + EXHAUST_GAS_TEMPERATURE_BANK2 = 0X79, + DIESEL_PARTICULATE_FILTER1 = 0X7A, + DIESEL_PARTICULATE_FILTER2 = 0X7B, + DIESEL_PARTICULATE_FILTER_TEMPERATURE = 0X7C, + ENGINE_RUN_TIME = 0X7F, + PIDS_SUPPORTED_81_A0 = 0X80, + NOX_SENSOR = 0X83, + MANIFOLD_SURFACE_TEMPERATURE = 0X84, + NOX_REAGENT_SYSTEM = 0X85, + PARTICULATE_MATTER_SENSOR = 0X86, + INTAKE_MANIFOLD_ABSOLUTE_PRESSURE_A_B = 0X87, + O2_SENSOR_WIDE_RANGE = 0X8C, + THROTTLE_POSITION_G = 0X8D, + ENGINE_FRICTION_PERCENT_TORQUE = 0X8E, + FUEL_SYSTEM_CONTROL = 0X92, + EXHAUST_GAS_TEMPERATURE_SENSORA = 0X98, + EXHAUST_GAS_TEMPERATURE_SENSORB = 0X99, + HYBRID_EV_VEHICLE_SYSTEM_DATA_BATTERY_VOLTAGE = 0X9A, + DIESEL_EXHAUST_FLUID_SENSOR_DATA = 0X9B, + O2_SENSOR_DATA = 0X9C, + FUEL_RATE = 0X9D, + ENGINE_EXHAUST_FLOW_RATE = 0X9E, + FUEL_SYSTEM_PERCENTAGE_USE = 0X9F, + PIDS_SUPPORTED_A1_C0 = 0XA0, + CYLINDER_FUEL_RATE = 0XA2, + TRANSMISSION_ACTUAL_GEAR = 0XA4, + ODOMETER = 0XA6, + PIDS_SUPPORTED_C1_E0 = 0XC0, + HVESS_RECOMMENDED_MAX_SOC = 0xC1 +}; +// clang-format on + } // namespace DataManagement } // namespace IoTFleetWise } // namespace Aws \ No newline at end of file diff --git a/src/vehiclenetwork/include/datatypes/VehicleDataMessage.h b/src/vehiclenetwork/include/datatypes/VehicleDataMessage.h index 98bcb877..d824804d 100644 --- a/src/vehiclenetwork/include/datatypes/VehicleDataMessage.h +++ b/src/vehiclenetwork/include/datatypes/VehicleDataMessage.h @@ -86,7 +86,7 @@ class VehicleDataMessage inline bool isValid() const { - return !mSyntheticData.empty() || !mRawData.empty(); + return ( !mSyntheticData.empty() ) || ( !mRawData.empty() ); } /** diff --git a/src/vehiclenetwork/include/dds/DDSDataTypes.h b/src/vehiclenetwork/include/dds/DDSDataTypes.h index dbc983b9..e0d5dfb9 100644 --- a/src/vehiclenetwork/include/dds/DDSDataTypes.h +++ b/src/vehiclenetwork/include/dds/DDSDataTypes.h @@ -21,7 +21,6 @@ namespace VehicleNetwork // on the DDS implementation we use e.g. fast dds. // For now, keeping them as basic C++ types. using DDSDomainID = uint32_t; -using DDSDomainParticipantQoS = std::string; using DDSTopicQoS = std::string; using DDSTopicName = std::string; using DDSReaderName = std::string; diff --git a/src/vehiclenetwork/src/CANDataSource.cpp b/src/vehiclenetwork/src/CANDataSource.cpp index f48f94f4..baceaa14 100644 --- a/src/vehiclenetwork/src/CANDataSource.cpp +++ b/src/vehiclenetwork/src/CANDataSource.cpp @@ -56,9 +56,9 @@ CANDataSource::init( const std::vector &sourceConfigs ) { // Only one source config is supported on the CAN stack i.e. we manage one socket with // one single thread. - if ( sourceConfigs.size() > 1 || sourceConfigs.empty() ) + if ( ( sourceConfigs.size() > 1 ) || sourceConfigs.empty() ) { - mLogger.error( "CANDataSource::init", " Only one source config is supported " ); + mLogger.error( "CANDataSource::init", "Only one source config is supported" ); return false; } auto settingsIterator = sourceConfigs[0].transportProperties.find( std::string( INTERFACE_NAME_KEY ) ); @@ -122,11 +122,11 @@ CANDataSource::start() mShouldSleep.store( true ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CANDataSource::start", " CAN Data Source Thread failed to start " ); + mLogger.trace( "CANDataSource::start", "Thread failed to start" ); } else { - mLogger.trace( "CANDataSource::start", " CAN Data Source Thread started " ); + mLogger.trace( "CANDataSource::start", "Thread started" ); mThread.setThreadName( "fwVNLinuxCAN" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -137,7 +137,7 @@ 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 ) ); + "Going to sleep until a the resume signal. CAN Data Source: " + std::to_string( mID ) ); mShouldSleep.store( true, std::memory_order_relaxed ); } @@ -146,9 +146,9 @@ CANDataSource::resumeDataAcquisition() { mLogger.trace( "CANDataSource::resumeDataAcquisition", - " Resuming Network data acquisition on Data Source :" + std::to_string( mID ) ); + "Resuming Network data acquisition on Data Source: " + std::to_string( mID ) ); // Make sure the thread does not sleep anymore - mResumeTime = mClock->timeSinceEpochMs(); + mResumeTime = mClock->systemTimeSinceEpochMs(); mShouldSleep.store( false ); // Wake up the worker thread. mWait.notify(); @@ -162,7 +162,7 @@ CANDataSource::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CANDataSource::stop", " CAN Data Source Thread stopped " ); + mLogger.trace( "CANDataSource::stop", "Thread stopped" ); return !mThread.isActive(); } @@ -211,13 +211,13 @@ CANDataSource::extractTimestamp( struct msghdr *msgHeader ) currentHeader = CMSG_NXTHDR( msgHeader, currentHeader ); } TraceModule::get().setVariable( TraceVariable::MAX_SYSTEMTIME_KERNELTIME_DIFF, - static_cast( mClock->timeSinceEpochMs() ) - + static_cast( mClock->systemTimeSinceEpochMs() ) - static_cast( timestamp ) ); } if ( timestamp == 0 ) // either other timestamp are invalid(=0) or mTimestampTypeToUse == POLLING_TIME { TraceModule::get().incrementVariable( TraceVariable::CAN_POLLING_TIMESTAMP_COUNTER ); - timestamp = mClock->timeSinceEpochMs(); + timestamp = mClock->systemTimeSinceEpochMs(); } return timestamp; } @@ -242,7 +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 " ); + "No valid decoding dictionary available, channel going to sleep" ); dataSource->mWait.wait( Platform::Linux::Signal::WaitWithPredicate ); wokeUpFromSleep = true; } @@ -281,7 +281,7 @@ 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 ) || ( timestamp >= dataSource->mResumeTime ) ) { lastFrameTime = timestamp; dataSource->receivedMessages++; @@ -304,7 +304,7 @@ CANDataSource::doWork( void *data ) dataSource->discardedMessages++; TraceModule::get().setVariable( TraceVariable::DISCARDED_FRAMES, dataSource->discardedMessages ); - dataSource->mLogger.warn( "CANDataSource::doWork", " Circular Buffer is full" ); + dataSource->mLogger.warn( "CANDataSource::doWork", "Circular Buffer is full" ); } } else @@ -332,12 +332,6 @@ CANDataSource::doWork( void *data ) } while ( !dataSource->shouldStop() ); } -size_t -CANDataSource::queueSize() const -{ - return mCircularBuffPtr->read_available(); -} - bool CANDataSource::connect() { @@ -377,19 +371,19 @@ CANDataSource::connect() if ( ioctl( mSocket, SIOCGIFINDEX, &interfaceRequest ) != 0 ) { - mLogger.error( "CANDataSource::connect", " CAN Interface with name " + mIfName + " is not accessible" ); + mLogger.error( "CANDataSource::connect", "CAN Interface with name " + mIfName + " is not accessible" ); close( mSocket ); return false; } - if ( mTimestampTypeToUse == CAN_TIMESTAMP_TYPE::KERNEL_SOFTWARE_TIMESTAMP || - mTimestampTypeToUse == CAN_TIMESTAMP_TYPE::KERNEL_HARDWARE_TIMESTAMP ) + if ( ( mTimestampTypeToUse == CAN_TIMESTAMP_TYPE::KERNEL_SOFTWARE_TIMESTAMP ) || + ( mTimestampTypeToUse == CAN_TIMESTAMP_TYPE::KERNEL_HARDWARE_TIMESTAMP ) ) { const int timestampFlags = ( SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_SOFTWARE | 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" ); + "Hardware timestamp not supported by socket but requested by config" ); close( mSocket ); return false; } @@ -415,7 +409,7 @@ CANDataSource::connect() bool CANDataSource::disconnect() { - if ( !stop() && close( mSocket ) < 0 ) + if ( ( !stop() ) && ( close( mSocket ) < 0 ) ) { return false; } @@ -431,7 +425,7 @@ CANDataSource::isAlive() socklen_t len = sizeof( error ); // Get the error status of the socket int retSockOpt = getsockopt( mSocket, SOL_SOCKET, SO_ERROR, &error, &len ); - if ( retSockOpt == -1 || !mThread.isValid() || !mThread.isActive() || error != 0 ) + if ( ( retSockOpt == -1 ) || ( !mThread.isValid() ) || ( !mThread.isActive() ) || ( error != 0 ) ) { return false; } diff --git a/src/vehiclenetwork/src/CameraDataPublisher.cpp b/src/vehiclenetwork/src/CameraDataPublisher.cpp index 3a6546e5..57d53370 100644 --- a/src/vehiclenetwork/src/CameraDataPublisher.cpp +++ b/src/vehiclenetwork/src/CameraDataPublisher.cpp @@ -75,7 +75,7 @@ CameraDataPublisher::init( const DDSDataSourceConfig &dataSourceConfig ) } else if ( dataSourceConfig.transportType == DDSTransportType::TCP ) { - mLogger.trace( "CameraDataPublisher::init", " TCP Transport is NOT yet supported " ); + mLogger.trace( "CameraDataPublisher::init", "TCP Transport is NOT yet supported" ); return false; } // Create the DDS participant @@ -121,11 +121,11 @@ CameraDataPublisher::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CameraDataPublisher::start", " Camera Publisher Thread failed to start " ); + mLogger.trace( "CameraDataPublisher::start", "Thread failed to start" ); } else { - mLogger.trace( "CameraDataPublisher::start", " Camera Publisher Thread started " ); + mLogger.trace( "CameraDataPublisher::start", "Thread started" ); mThread.setThreadName( "fwVNDDSCamPub" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -139,7 +139,7 @@ CameraDataPublisher::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CameraDataPublisher::stop", " Camera Publisher Thread stopped " ); + mLogger.trace( "CameraDataPublisher::stop", "Thread stopped" ); return !mThread.isActive(); } @@ -166,7 +166,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 " ); + publisher->mLogger.trace( "CameraDataPublisher::doWork", "Data request send to the remote node" ); } } } @@ -198,7 +198,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 " ); + mLogger.trace( "CameraDataPublisher::on_publication_matched", "A subscriber is available" ); } else if ( info.current_count_change == -1 ) { @@ -219,7 +219,7 @@ CameraDataPublisher::publishDataRequest( const DDSDataRequest &dataRequest ) mRequestCompleted.store( false ); } - mLogger.trace( "CameraDataPublisher::publishDataRequest", " Request queued for sending " ); + mLogger.trace( "CameraDataPublisher::publishDataRequest", "Request queued for sending" ); mWait.notify(); } diff --git a/src/vehiclenetwork/src/CameraDataSubscriber.cpp b/src/vehiclenetwork/src/CameraDataSubscriber.cpp index ee170a96..a0fc9ffc 100644 --- a/src/vehiclenetwork/src/CameraDataSubscriber.cpp +++ b/src/vehiclenetwork/src/CameraDataSubscriber.cpp @@ -75,7 +75,7 @@ CameraDataSubscriber::init( const DDSDataSourceConfig &dataSourceConfig ) } else if ( dataSourceConfig.transportType == DDSTransportType::TCP ) { - mLogger.trace( "CameraDataSubscriber::init", " TCP Transport is NOT yet supported " ); + mLogger.trace( "CameraDataSubscriber::init", "TCP Transport is NOT yet supported" ); return false; } // Create the DDS participant @@ -124,11 +124,11 @@ CameraDataSubscriber::start() mShouldStop.store( false ); if ( !mThread.create( doWork, this ) ) { - mLogger.trace( "CameraDataSubscriber::start", " Camera Subscriber Thread failed to start " ); + mLogger.trace( "CameraDataSubscriber::start", "Thread failed to start" ); } else { - mLogger.trace( "CameraDataSubscriber::start", " Camera Subscriber Thread started " ); + mLogger.trace( "CameraDataSubscriber::start", "Thread started" ); mThread.setThreadName( "fwVNDDSCamSub" + std::to_string( mID ) ); } return mThread.isActive() && mThread.isValid(); @@ -142,7 +142,7 @@ CameraDataSubscriber::stop() mWait.notify(); mThread.release(); mShouldStop.store( false, std::memory_order_relaxed ); - mLogger.trace( "CameraDataSubscriber::stop", " Camera Subscriber Thread stopped " ); + mLogger.trace( "CameraDataSubscriber::stop", "Thread stopped" ); return !mThread.isActive(); } @@ -178,12 +178,12 @@ CameraDataSubscriber::doWork( void *data ) subscriber->notifyListeners( &SensorDataListener::onSensorArtifactAvailable, cameraArtifact ); subscriber->mLogger.info( "CameraDataSubscriber::doWork", - " Data Collected from the Camera and made available " ); + "Data Collected from the Camera and made available" ); } else { subscriber->mLogger.error( "CameraDataSubscriber::doWork", - " Could not persist the data received into disk " ); + "Could not persist the data received into disk" ); } // Reset the response @@ -218,7 +218,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 " ); + mLogger.trace( "CameraDataSubscriber::on_subscription_matched", "A publisher is available" ); } else if ( info.current_count_change == -1 ) { @@ -235,7 +235,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 " ); + mLogger.trace( "CameraDataSubscriber::on_data_available", "Data received from the DDS Node" ); mWait.notify(); } } diff --git a/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp b/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp index cd408344..37b99821 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANReceiver.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -64,7 +63,7 @@ ISOTPOverCANReceiver::connect() if ( mSocket < 0 ) { mLogger.error( "ISOTPOverCANReceiver::connect", - " Failed to create the ISOTP Socket to IF:" + mReceiverOptions.mSocketCanIFName ); + "Failed to create the ISOTP Socket to IF: " + mReceiverOptions.mSocketCanIFName ); return false; } @@ -73,9 +72,9 @@ ISOTPOverCANReceiver::connect() int retFrameCtrFlag = setsockopt( mSocket, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &frameControlFlags, sizeof( frameControlFlags ) ); - if ( retOptFlag < 0 || retFrameCtrFlag < 0 ) + if ( ( retOptFlag < 0 ) || ( retFrameCtrFlag < 0 ) ) { - mLogger.error( "ISOTPOverCANReceiver::connect", " Failed to set ISO-TP socket option flags" ); + mLogger.error( "ISOTPOverCANReceiver::connect", "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -87,12 +86,12 @@ ISOTPOverCANReceiver::connect() if ( bind( mSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { mLogger.error( "ISOTPOverCANReceiver::connect", - " Failed to bind the ISOTP Socket to IF:" + mReceiverOptions.mSocketCanIFName ); + "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 ); + "ISOTP Socket connected to IF: " + mReceiverOptions.mSocketCanIFName ); return true; } @@ -102,11 +101,11 @@ ISOTPOverCANReceiver::disconnect() if ( close( mSocket ) < 0 ) { mLogger.error( "ISOTPOverCANReceiver::connect", - " Failed to disconnect the ISOTP Socket from IF:" + mReceiverOptions.mSocketCanIFName ); + "Failed to disconnect the ISOTP Socket from IF: " + mReceiverOptions.mSocketCanIFName ); return false; } mLogger.trace( "ISOTPOverCANReceiver::disconnect", - " ISOTP Socket disconnected from IF:" + mReceiverOptions.mSocketCanIFName ); + "ISOTP Socket disconnected from IF: " + mReceiverOptions.mSocketCanIFName ); return true; } @@ -117,7 +116,7 @@ ISOTPOverCANReceiver::isAlive() const socklen_t len = sizeof( error ); // Get the error status of the socket int retSockOpt = getsockopt( mSocket, SOL_SOCKET, SO_ERROR, &error, &len ); - return ( retSockOpt == 0 && error == 0 ); + return ( ( retSockOpt == 0 ) && ( error == 0 ) ); } bool @@ -137,7 +136,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 ) ); + mLogger.trace( "ISOTPOverCANReceiver::receivePDU", "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 6a5a350d..91c3649c 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANSender.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANSender.cpp @@ -5,14 +5,11 @@ // Includes #include "businterfaces/ISOTPOverCANSender.h" #include "ClockHandler.h" -#include #include #include #include #include -#include #include -#include #include namespace Aws @@ -54,7 +51,7 @@ ISOTPOverCANSender::connect() if ( mSocket < 0 ) { mLogger.error( "ISOTPOverCANSender::connect", - " Failed to create the ISOTP Socket to IF:" + mSenderOptions.mSocketCanIFName ); + "Failed to create the ISOTP Socket to IF: " + mSenderOptions.mSocketCanIFName ); return false; } @@ -62,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" ); + mLogger.error( "ISOTPOverCANSender::connect", "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -74,11 +71,11 @@ ISOTPOverCANSender::connect() if ( bind( mSocket, (struct sockaddr *)&interfaceAddress, sizeof( interfaceAddress ) ) < 0 ) { mLogger.error( "ISOTPOverCANSender::connect", - " Failed to bind the ISOTP Socket to IF:" + mSenderOptions.mSocketCanIFName ); + "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 ); + mLogger.trace( "ISOTPOverCANSender::connect", "ISOTP Socket connected to IF: " + mSenderOptions.mSocketCanIFName ); return true; } @@ -88,11 +85,11 @@ ISOTPOverCANSender::disconnect() if ( close( mSocket ) < 0 ) { mLogger.error( "ISOTPOverCANSender::connect", - " Failed to disconnect the ISOTP Socket from IF:" + mSenderOptions.mSocketCanIFName ); + "Failed to disconnect the ISOTP Socket from IF: " + mSenderOptions.mSocketCanIFName ); return false; } mLogger.trace( "ISOTPOverCANSender::disconnect", - " ISOTP Socket disconnected from IF:" + mSenderOptions.mSocketCanIFName ); + "ISOTP Socket disconnected from IF: " + mSenderOptions.mSocketCanIFName ); return true; } @@ -103,15 +100,15 @@ ISOTPOverCANSender::isAlive() const socklen_t len = sizeof( error ); // Get the error status of the socket int retSockOpt = getsockopt( mSocket, SOL_SOCKET, SO_ERROR, &error, &len ); - return ( retSockOpt == 0 && error == 0 ); + return ( ( retSockOpt == 0 ) && ( error == 0 ) ); } bool ISOTPOverCANSender::sendPDU( const std::vector &pduData ) { int bytesWritten = static_cast( write( mSocket, pduData.data(), pduData.size() ) ); - mLogger.trace( "ISOTPOverCANSender::sendPDU", " sent a PDU of size:" + std::to_string( bytesWritten ) ); - return ( bytesWritten > 0 && bytesWritten == static_cast( pduData.size() ) ); + mLogger.trace( "ISOTPOverCANSender::sendPDU", "Sent a PDU of size: " + std::to_string( bytesWritten ) ); + return ( ( bytesWritten > 0 ) && ( bytesWritten == static_cast( pduData.size() ) ) ); } } // namespace VehicleNetwork diff --git a/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp b/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp index 88cadf23..9fe1cbd0 100644 --- a/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp +++ b/src/vehiclenetwork/src/ISOTPOverCANSenderReceiver.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -69,8 +68,8 @@ ISOTPOverCANSenderReceiver::connect() if ( mSocket < 0 ) { mLogger.error( "ISOTPOverCANSenderReceiver::connect", - " Failed to create the ISOTP rx id " + mStreamRxID + - " to IF:" + mSenderReceiverOptions.mSocketCanIFName ); + "Failed to create the ISOTP rx id " + mStreamRxID + + " to IF: " + mSenderReceiverOptions.mSocketCanIFName ); return false; } @@ -80,9 +79,9 @@ ISOTPOverCANSenderReceiver::connect() int retFrameCtrFlag = setsockopt( mSocket, SOL_CAN_ISOTP, CAN_ISOTP_RECV_FC, &frameControlFlags, sizeof( frameControlFlags ) ); - if ( retOptFlag < 0 || retFrameCtrFlag < 0 ) + if ( ( retOptFlag < 0 ) || ( retFrameCtrFlag < 0 ) ) { - mLogger.error( "ISOTPOverCANSenderReceiver::connect", " Failed to set ISO-TP socket option flags" ); + mLogger.error( "ISOTPOverCANSenderReceiver::connect", "Failed to set ISO-TP socket option flags" ); return false; } // CAN PF and Interface Index @@ -95,13 +94,13 @@ ISOTPOverCANSenderReceiver::connect() 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 ); + "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 ); + "ISOTP rx id " + mStreamRxID + " connected to IF: " + mSenderReceiverOptions.mSocketCanIFName ); return true; } @@ -111,12 +110,12 @@ ISOTPOverCANSenderReceiver::disconnect() if ( close( mSocket ) < 0 ) { mLogger.error( "ISOTPOverCANSenderReceiver::connect", - " Failed to disconnect the ISOTP rx id " + mStreamRxID + - " from IF:" + mSenderReceiverOptions.mSocketCanIFName ); + "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 ); + "ISOTP rx id " + mStreamRxID + " disconnected from IF: " + mSenderReceiverOptions.mSocketCanIFName ); return true; } @@ -127,7 +126,33 @@ ISOTPOverCANSenderReceiver::isAlive() const socklen_t len = sizeof( error ); // Get the error status of the socket int retSockOpt = getsockopt( mSocket, SOL_SOCKET, SO_ERROR, &error, &len ); - return ( retSockOpt == 0 && error == 0 ); + return ( ( retSockOpt == 0 ) && ( error == 0 ) ); +} + +uint32_t +ISOTPOverCANSenderReceiver::flush( uint32_t timeout ) +{ + struct pollfd pfd = { mSocket, POLLIN, 0 }; + // start time measurement + Timer flushTimer; + flushTimer.reset(); + int res = poll( &pfd, 1U, static_cast( timeout ) ); + // end time measurement + uint32_t pollNeededTime = static_cast( flushTimer.getElapsedMs().count() ); + if ( res <= 0 ) + { + return timeout; + } + std::vector flushBuffer; + flushBuffer.resize( MAX_PDU_SIZE ); + 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 ) ); + } + return pollNeededTime; } bool @@ -137,10 +162,18 @@ ISOTPOverCANSenderReceiver::receivePDU( std::vector &pduData ) { struct pollfd pfd = { mSocket, POLLIN, 0 }; int res = poll( &pfd, 1U, static_cast( mSenderReceiverOptions.mP2TimeoutMs ) ); - if ( res <= 0 ) + if ( res == 0 ) + { + // 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 ); + return false; + } + if ( res < 0 ) { mLogger.warn( "ISOTPOverCANSenderReceiver::receivePDU", - " Failed to read PDU from socket:" + mStreamRxID + " with error code " + + "Failed to read PDU from socket: " + mStreamRxID + " with error code " + std::to_string( res ) ); // Error (<0) or timeout (==0): return false; @@ -160,7 +193,7 @@ ISOTPOverCANSenderReceiver::receivePDU( std::vector &pduData ) pduData.resize( 0 ); } mLogger.traceBytesInVector( "ISOTPOverCANSenderReceiver::receivePDU", - "Socket:" + mStreamRxID + " received a PDU of size " + std::to_string( bytesRead ), + "Socket: " + mStreamRxID + " received a PDU of size " + std::to_string( bytesRead ), pduData ); return bytesRead > 0; @@ -172,9 +205,9 @@ 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 ), + "Socket: " + mStreamRxID + " sent a PDU of size " + std::to_string( bytesWritten ), pduData ); - return ( bytesWritten > 0 && bytesWritten == static_cast( pduData.size() ) ); + return ( ( bytesWritten > 0 ) && ( bytesWritten == static_cast( pduData.size() ) ) ); } } // namespace VehicleNetwork diff --git a/tools/cansim/canigen.py b/tools/cansim/canigen.py index 08629249..7a29f214 100644 --- a/tools/cansim/canigen.py +++ b/tools/cansim/canigen.py @@ -123,6 +123,7 @@ def __sig_thread(self, msg_name, cycle_time): time.sleep(cycle_time / 1000.0) def __get_supported_pids(self, num_range, ecu): + supported = False out = [0, 0, 0, 0] for name, data in ecu['pids'].items(): pid_num = int(data['num'], 0) @@ -130,7 +131,8 @@ def __get_supported_pids(self, num_range, ecu): i = int((pid_num - num_range - 1) / 8) j = (pid_num - num_range - 1) % 8 out[i] |= 1 << (7 - j) - return out + supported = True + return supported, out def __encode_pid_data(self, num, ecu): for name, data in ecu['pids'].items(): @@ -180,14 +182,18 @@ def __obd_thread(self, ecu): #print(ecu['name']+' rx: '+str(rx)) sid = rx.pop(0) tx = [sid | 0x40] - if sid == 0x01: # PID + if ecu.get('require_broadcast_requests', False) and res[0][0] != isotp_socket_func: + tx = [0x7F, sid, 0x11] # NRC Service not supported + elif sid == 0x01: # PID while len(rx) > 0: pid_num = rx.pop(0) if (pid_num % 0x20) == 0: # Supported PIDs - tx += [pid_num] + self.__get_supported_pids(pid_num, ecu) + supported, data = self.__get_supported_pids(pid_num, ecu) + if pid_num == 0 or supported or not ecu.get('ignore_unsupported_pid_requests', False): + tx += [pid_num] + data else: data = self.__encode_pid_data(pid_num, ecu) - if not data is None: + if data is not None: tx += [pid_num] + data elif sid == 0x03: # DTCs num_dtcs = 0 @@ -202,7 +208,8 @@ def __obd_thread(self, ecu): else: tx = [0x7F, sid, 0x11] # NRC Service not supported #print(ecu['name']+' tx: '+str(tx)) - isotp_socket_phys.send(bytearray(tx)) + if len(tx) > 1: + isotp_socket_phys.send(bytearray(tx)) def get_sig_names(self): return self.__sig_names diff --git a/tools/cloud/dbc-to-json.py b/tools/cloud/dbc-to-json.py index 99e346ed..c8a2daf9 100644 --- a/tools/cloud/dbc-to-json.py +++ b/tools/cloud/dbc-to-json.py @@ -34,6 +34,9 @@ signal_to_add["offset"] = signal.offset signal_to_add["messageId"] = message.frame_id + # In a DBC file, the start bit indicates the LSB for little endian and MSB for big endian + # signals. AWS IoT Fleetwise considers start bit to always be the LSB regardless of + # endianess. That is why we need to convert the value obtained from DBC. if signal.byte_order == 'big_endian': pos = 7 - ( signal.start % 8 ) + ( signal.length - 1 ) if pos < 8: diff --git a/tools/cloud/iotfleetwise-2021-06-17.json b/tools/cloud/iotfleetwise-2021-06-17.json deleted file mode 100644 index 49d0ee2a..00000000 --- a/tools/cloud/iotfleetwise-2021-06-17.json +++ /dev/null @@ -1,4445 +0,0 @@ -{ - "version":"2.0", - "metadata":{ - "apiVersion":"2021-06-17", - "endpointPrefix":"iotfleetwise", - "jsonVersion":"1.0", - "protocol":"json", - "serviceFullName":"AWS IoT FleetWise", - "serviceId":"IoTFleetWise", - "signatureVersion":"v4", - "signingName":"iotfleetwise", - "targetPrefix":"IoTAutobahnControlPlane", - "uid":"iotfleetwise-2021-06-17" - }, - "operations":{ - "AssociateVehicleFleet":{ - "name":"AssociateVehicleFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"AssociateVehicleFleetRequest"}, - "output":{"shape":"AssociateVehicleFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Adds, or associates, a vehicle with a fleet.

" - }, - "BatchCreateVehicle":{ - "name":"BatchCreateVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"BatchCreateVehicleRequest"}, - "output":{"shape":"BatchCreateVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a group, or batch, of vehicles.

You must specify a decoder manifest and a vehicle model (model manifest) for each vehicle.

For more information, see Create multiple vehicles (AWS CLI) in the Amazon Web Services IoT FleetWise Developer Guide.

" - }, - "BatchUpdateVehicle":{ - "name":"BatchUpdateVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"BatchUpdateVehicleRequest"}, - "output":{"shape":"BatchUpdateVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a group, or batch, of vehicles.

You must specify a decoder manifest and a vehicle model (model manifest) for each vehicle.

For more information, see Update multiple vehicles (AWS CLI) in the Amazon Web Services IoT FleetWise Developer Guide.

" - }, - "CreateCampaign":{ - "name":"CreateCampaign", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateCampaignRequest"}, - "output":{"shape":"CreateCampaignResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates an orchestration of data collection rules. The Amazon Web Services IoT FleetWise Edge Agent software running in vehicles uses campaigns to decide how to collect and transfer data to the cloud. You create campaigns in the cloud. After you or your team approve campaigns, Amazon Web Services IoT FleetWise automatically deploys them to vehicles.

For more information, see Collect and transfer data with campaigns in the Amazon Web Services IoT FleetWise Developer Guide.

", - "idempotent":true - }, - "CreateDecoderManifest":{ - "name":"CreateDecoderManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateDecoderManifestRequest"}, - "output":{"shape":"CreateDecoderManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"DecoderManifestValidationException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates the decoder manifest associated with a model manifest. To create a decoder manifest, the following must be true:

  • Every signal decoder has a unique name.

  • Each signal decoder is associated with a network interface.

  • Each network interface has a unique ID.

  • The signal decoders are specified in the model manifest.

", - "idempotent":true - }, - "CreateFleet":{ - "name":"CreateFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateFleetRequest"}, - "output":{"shape":"CreateFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a fleet that represents a group of vehicles.

You must create both a signal catalog and vehicles before you can create a fleet.

For more information, see Fleets in the Amazon Web Services IoT FleetWise Developer Guide.

", - "idempotent":true - }, - "CreateModelManifest":{ - "name":"CreateModelManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateModelManifestRequest"}, - "output":{"shape":"CreateModelManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a vehicle model (model manifest) that specifies signals (attributes, branches, sensors, and actuators).

For more information, see Vehicle models in the Amazon Web Services IoT FleetWise Developer Guide.

", - "idempotent":true - }, - "CreateSignalCatalog":{ - "name":"CreateSignalCatalog", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateSignalCatalogRequest"}, - "output":{"shape":"CreateSignalCatalogResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"InvalidNodeException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a collection of standardized signals that can be reused to create vehicle models.

", - "idempotent":true - }, - "CreateVehicle":{ - "name":"CreateVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"CreateVehicleRequest"}, - "output":{"shape":"CreateVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a vehicle, which is an instance of a vehicle model (model manifest). Vehicles created from the same vehicle model consist of the same signals inherited from the vehicle model.

If you have an existing Amazon Web Services IoT Thing, you can use Amazon Web Services IoT FleetWise to create a vehicle and collect data from your thing.

For more information, see Create a vehicle (AWS CLI) in the Amazon Web Services IoT FleetWise Developer Guide.

", - "idempotent":true - }, - "DeleteCampaign":{ - "name":"DeleteCampaign", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteCampaignRequest"}, - "output":{"shape":"DeleteCampaignResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a data collection campaign. Deleting a campaign suspends all data collection and removes it from any vehicles.

", - "idempotent":true - }, - "DeleteDecoderManifest":{ - "name":"DeleteDecoderManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteDecoderManifestRequest"}, - "output":{"shape":"DeleteDecoderManifestResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a decoder manifest. You can't delete a decoder manifest if it has vehicles associated with it.

If the decoder manifest is successfully deleted, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

", - "idempotent":true - }, - "DeleteFleet":{ - "name":"DeleteFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteFleetRequest"}, - "output":{"shape":"DeleteFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a fleet. Before you delete a fleet, all vehicles must be dissociated from the fleet. For more information, see Delete a fleet (AWS CLI) in the Amazon Web Services IoT FleetWise Developer Guide.

If the fleet is successfully deleted, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

", - "idempotent":true - }, - "DeleteModelManifest":{ - "name":"DeleteModelManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteModelManifestRequest"}, - "output":{"shape":"DeleteModelManifestResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a vehicle model (model manifest).

If the vehicle model is successfully deleted, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

", - "idempotent":true - }, - "DeleteSignalCatalog":{ - "name":"DeleteSignalCatalog", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteSignalCatalogRequest"}, - "output":{"shape":"DeleteSignalCatalogResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a signal catalog.

If the signal catalog is successfully deleted, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

", - "idempotent":true - }, - "DeleteVehicle":{ - "name":"DeleteVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DeleteVehicleRequest"}, - "output":{"shape":"DeleteVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Deletes a vehicle and removes it from any campaigns.

If the vehicle is successfully deleted, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

", - "idempotent":true - }, - "DisassociateVehicleFleet":{ - "name":"DisassociateVehicleFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"DisassociateVehicleFleetRequest"}, - "output":{"shape":"DisassociateVehicleFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Removes, or disassociates, a vehicle from a fleet. Disassociating a vehicle from a fleet doesn't delete the vehicle.

If the vehicle is successfully dissociated from a fleet, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty body.

" - }, - "GetCampaign":{ - "name":"GetCampaign", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetCampaignRequest"}, - "output":{"shape":"GetCampaignResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a campaign.

" - }, - "GetDecoderManifest":{ - "name":"GetDecoderManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetDecoderManifestRequest"}, - "output":{"shape":"GetDecoderManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a created decoder manifest.

" - }, - "GetFleet":{ - "name":"GetFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetFleetRequest"}, - "output":{"shape":"GetFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a fleet.

" - }, - "GetLoggingOptions":{ - "name":"GetLoggingOptions", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetLoggingOptionsRequest"}, - "output":{"shape":"GetLoggingOptionsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves the logging options.

" - }, - "GetModelManifest":{ - "name":"GetModelManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetModelManifestRequest"}, - "output":{"shape":"GetModelManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a vehicle model (model manifest).

" - }, - "GetRegisterAccountStatus":{ - "name":"GetRegisterAccountStatus", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetRegisterAccountStatusRequest"}, - "output":{"shape":"GetRegisterAccountStatusResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about the status of registering your Amazon Web Services account, IAM, and Amazon Timestream resources so that Amazon Web Services IoT FleetWise can transfer your vehicle data to the Amazon Web Services Cloud.

For more information, including step-by-step procedures, see Setting up Amazon Web Services IoT FleetWise.

This API operation doesn't require input parameters.

" - }, - "GetSignalCatalog":{ - "name":"GetSignalCatalog", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetSignalCatalogRequest"}, - "output":{"shape":"GetSignalCatalogResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a signal catalog.

" - }, - "GetVehicle":{ - "name":"GetVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetVehicleRequest"}, - "output":{"shape":"GetVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about a vehicle.

" - }, - "GetVehicleStatus":{ - "name":"GetVehicleStatus", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"GetVehicleStatusRequest"}, - "output":{"shape":"GetVehicleStatusResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information about the status of a vehicle with any associated campaigns.

" - }, - "ImportDecoderManifest":{ - "name":"ImportDecoderManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ImportDecoderManifestRequest"}, - "output":{"shape":"ImportDecoderManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"DecoderManifestValidationException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a decoder manifest using your existing CAN DBC file from your local device.

" - }, - "ImportSignalCatalog":{ - "name":"ImportSignalCatalog", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ImportSignalCatalogRequest"}, - "output":{"shape":"ImportSignalCatalogResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates a signal catalog using your existing VSS formatted content from your local device.

", - "idempotent":true - }, - "ListCampaigns":{ - "name":"ListCampaigns", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListCampaignsRequest"}, - "output":{"shape":"ListCampaignsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists information about created campaigns.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListDecoderManifestNetworkInterfaces":{ - "name":"ListDecoderManifestNetworkInterfaces", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListDecoderManifestNetworkInterfacesRequest"}, - "output":{"shape":"ListDecoderManifestNetworkInterfacesResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists the network interfaces specified in a decoder manifest.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListDecoderManifestSignals":{ - "name":"ListDecoderManifestSignals", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListDecoderManifestSignalsRequest"}, - "output":{"shape":"ListDecoderManifestSignalsResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

A list of information about signal decoders specified in a decoder manifest.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListDecoderManifests":{ - "name":"ListDecoderManifests", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListDecoderManifestsRequest"}, - "output":{"shape":"ListDecoderManifestsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists decoder manifests.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListFleets":{ - "name":"ListFleets", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListFleetsRequest"}, - "output":{"shape":"ListFleetsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves information for each created fleet in an Amazon Web Services account.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListFleetsForVehicle":{ - "name":"ListFleetsForVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListFleetsForVehicleRequest"}, - "output":{"shape":"ListFleetsForVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves a list of IDs for all fleets that the vehicle is associated with.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListModelManifestNodes":{ - "name":"ListModelManifestNodes", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListModelManifestNodesRequest"}, - "output":{"shape":"ListModelManifestNodesResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists information about nodes specified in a vehicle model (model manifest).

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListModelManifests":{ - "name":"ListModelManifests", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListModelManifestsRequest"}, - "output":{"shape":"ListModelManifestsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves a list of vehicle models (model manifests).

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListSignalCatalogNodes":{ - "name":"ListSignalCatalogNodes", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListSignalCatalogNodesRequest"}, - "output":{"shape":"ListSignalCatalogNodesResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"LimitExceededException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists of information about the signals (nodes) specified in a signal catalog.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListSignalCatalogs":{ - "name":"ListSignalCatalogs", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListSignalCatalogsRequest"}, - "output":{"shape":"ListSignalCatalogsResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists all the created signal catalogs in an Amazon Web Services account.

You can use to list information about each signal (node) specified in a signal catalog.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListTagsForResource":{ - "name":"ListTagsForResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListTagsForResourceRequest"}, - "output":{"shape":"ListTagsForResourceResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Lists the tags (metadata) you have assigned to the resource.

" - }, - "ListVehicles":{ - "name":"ListVehicles", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListVehiclesRequest"}, - "output":{"shape":"ListVehiclesResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves a list of summaries of created vehicles.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "ListVehiclesInFleet":{ - "name":"ListVehiclesInFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"ListVehiclesInFleetRequest"}, - "output":{"shape":"ListVehiclesInFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Retrieves a list of summaries of all vehicles associated with a fleet.

This API operation uses pagination. Specify the nextToken parameter in the request to return more results.

" - }, - "PutLoggingOptions":{ - "name":"PutLoggingOptions", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"PutLoggingOptionsRequest"}, - "output":{"shape":"PutLoggingOptionsResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Creates or updates the logging option.

", - "idempotent":true - }, - "RegisterAccount":{ - "name":"RegisterAccount", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"RegisterAccountRequest"}, - "output":{"shape":"RegisterAccountResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Registers your Amazon Web Services account, IAM, and Amazon Timestream resources so Amazon Web Services IoT FleetWise can transfer your vehicle data to the Amazon Web Services Cloud. For more information, including step-by-step procedures, see Setting up Amazon Web Services IoT FleetWise.

An Amazon Web Services account is not the same thing as a \"user account\". An Amazon Web Services user is an identity that you create using Identity and Access Management (IAM) and takes the form of either an IAM user or an IAM role, both with credentials. A single Amazon Web Services account can, and typically does, contain many users and roles.

" - }, - "TagResource":{ - "name":"TagResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"TagResourceRequest"}, - "output":{"shape":"TagResourceResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Adds to or modifies the tags of the given resource. Tags are metadata which can be used to manage a resource.

", - "idempotent":true - }, - "UntagResource":{ - "name":"UntagResource", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UntagResourceRequest"}, - "output":{"shape":"UntagResourceResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Removes the given tags (metadata) from the resource.

", - "idempotent":true - }, - "UpdateCampaign":{ - "name":"UpdateCampaign", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateCampaignRequest"}, - "output":{"shape":"UpdateCampaignResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a campaign.

" - }, - "UpdateDecoderManifest":{ - "name":"UpdateDecoderManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateDecoderManifestRequest"}, - "output":{"shape":"UpdateDecoderManifestResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"DecoderManifestValidationException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a decoder manifest.

A decoder manifest can only be updated when the status is DRAFT. Only ACTIVE decoder manifests can be associated with vehicles.

", - "idempotent":true - }, - "UpdateFleet":{ - "name":"UpdateFleet", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateFleetRequest"}, - "output":{"shape":"UpdateFleetResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates the description of an existing fleet.

If the fleet is successfully updated, Amazon Web Services IoT FleetWise sends back an HTTP 200 response with an empty HTTP body.

" - }, - "UpdateModelManifest":{ - "name":"UpdateModelManifest", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateModelManifestRequest"}, - "output":{"shape":"UpdateModelManifestResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a vehicle model (model manifest). If created vehicles are associated with a vehicle model, it can't be updated.

", - "idempotent":true - }, - "UpdateSignalCatalog":{ - "name":"UpdateSignalCatalog", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateSignalCatalogRequest"}, - "output":{"shape":"UpdateSignalCatalogResponse"}, - "errors":[ - {"shape":"ResourceNotFoundException"}, - {"shape":"InternalServerException"}, - {"shape":"ConflictException"}, - {"shape":"LimitExceededException"}, - {"shape":"InvalidNodeException"}, - {"shape":"ThrottlingException"}, - {"shape":"InvalidSignalsException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a signal catalog.

", - "idempotent":true - }, - "UpdateVehicle":{ - "name":"UpdateVehicle", - "http":{ - "method":"POST", - "requestUri":"/" - }, - "input":{"shape":"UpdateVehicleRequest"}, - "output":{"shape":"UpdateVehicleResponse"}, - "errors":[ - {"shape":"InternalServerException"}, - {"shape":"ResourceNotFoundException"}, - {"shape":"ConflictException"}, - {"shape":"ThrottlingException"}, - {"shape":"ValidationException"}, - {"shape":"AccessDeniedException"} - ], - "documentation":"

Updates a vehicle.

" - } - }, - "shapes":{ - "AccessDeniedException":{ - "type":"structure", - "required":["message"], - "members":{ - "message":{"shape":"string"} - }, - "documentation":"

You don't have sufficient permission to perform this action.

", - "exception":true - }, - "Actuator":{ - "type":"structure", - "required":[ - "fullyQualifiedName", - "dataType" - ], - "members":{ - "fullyQualifiedName":{ - "shape":"string", - "documentation":"

The fully qualified name of the actuator. For example, the fully qualified name of an actuator might be Vehicle.Front.Left.Door.Lock.

" - }, - "dataType":{ - "shape":"NodeDataType", - "documentation":"

The specified data type of the actuator.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the actuator.

" - }, - "unit":{ - "shape":"string", - "documentation":"

The scientific unit for the actuator.

" - }, - "allowedValues":{ - "shape":"listOfStrings", - "documentation":"

A list of possible values an actuator can take.

" - }, - "min":{ - "shape":"double", - "documentation":"

The specified possible minimum value of an actuator.

" - }, - "max":{ - "shape":"double", - "documentation":"

The specified possible maximum value of an actuator.

" - }, - "assignedValue":{ - "shape":"string", - "documentation":"

A specified value for the actuator.

" - } - }, - "documentation":"

A signal that represents a vehicle device such as the engine, heater, and door locks. Data from an actuator reports the state of a certain vehicle device.

Updating actuator data can change the state of a device. For example, you can turn on or off the heater by updating its actuator data.

" - }, - "AmazonResourceName":{ - "type":"string", - "max":1011, - "min":1 - }, - "AssociateVehicleFleetRequest":{ - "type":"structure", - "required":[ - "vehicleName", - "fleetId" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to associate with the fleet.

" - }, - "fleetId":{ - "shape":"fleetId", - "documentation":"

The ID of a fleet.

" - } - } - }, - "AssociateVehicleFleetResponse":{ - "type":"structure", - "members":{ - } - }, - "Attribute":{ - "type":"structure", - "required":[ - "fullyQualifiedName", - "dataType" - ], - "members":{ - "fullyQualifiedName":{ - "shape":"string", - "documentation":"

The fully qualified name of the attribute. For example, the fully qualified name of an attribute might be Vehicle.Body.Engine.Type.

" - }, - "dataType":{ - "shape":"NodeDataType", - "documentation":"

The specified data type of the attribute.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the attribute.

" - }, - "unit":{ - "shape":"string", - "documentation":"

The scientific unit for the attribute.

" - }, - "allowedValues":{ - "shape":"listOfStrings", - "documentation":"

A list of possible values an attribute can be assigned.

" - }, - "min":{ - "shape":"double", - "documentation":"

The specified possible minimum value of the attribute.

" - }, - "max":{ - "shape":"double", - "documentation":"

The specified possible maximum value of the attribute.

" - }, - "assignedValue":{ - "shape":"string", - "documentation":"

A specified value for the attribute.

" - }, - "defaultValue":{ - "shape":"string", - "documentation":"

The default value of the attribute.

" - } - }, - "documentation":"

A signal that represents static information about the vehicle, such as engine type or manufacturing date.

" - }, - "BatchCreateVehicleRequest":{ - "type":"structure", - "required":["vehicles"], - "members":{ - "vehicles":{ - "shape":"createVehicleRequestItems", - "documentation":"

A list of information about each vehicle to create. For more information, see the API data type.

" - } - } - }, - "BatchCreateVehicleResponse":{ - "type":"structure", - "members":{ - "vehicles":{ - "shape":"createVehicleResponses", - "documentation":"

A list of information about a batch of created vehicles. For more information, see the API data type.

" - }, - "errors":{ - "shape":"createVehicleErrors", - "documentation":"

A list of information about creation errors, or an empty list if there aren't any errors.

" - } - } - }, - "BatchUpdateVehicleRequest":{ - "type":"structure", - "required":["vehicles"], - "members":{ - "vehicles":{ - "shape":"updateVehicleRequestItems", - "documentation":"

A list of information about the vehicles to update. For more information, see the API data type.

" - } - } - }, - "BatchUpdateVehicleResponse":{ - "type":"structure", - "members":{ - "vehicles":{ - "shape":"updateVehicleResponseItems", - "documentation":"

A list of information about the batch of updated vehicles.

This list contains only unique IDs for the vehicles that were updated.

" - }, - "errors":{ - "shape":"updateVehicleErrors", - "documentation":"

A list of information about errors returned while updating a batch of vehicles, or, if there aren't any errors, an empty list.

" - } - } - }, - "Branch":{ - "type":"structure", - "required":["fullyQualifiedName"], - "members":{ - "fullyQualifiedName":{ - "shape":"string", - "documentation":"

The fully qualified name of the branch. For example, the fully qualified name of a branch might be Vehicle.Body.Engine.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the branch.

" - } - }, - "documentation":"

A group of signals that are defined in a hierarchical structure.

" - }, - "CampaignStatus":{ - "type":"string", - "enum":[ - "CREATING", - "WAITING_FOR_APPROVAL", - "RUNNING", - "SUSPENDED" - ] - }, - "CampaignSummary":{ - "type":"structure", - "required":[ - "creationTime", - "lastModificationTime" - ], - "members":{ - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a campaign.

" - }, - "name":{ - "shape":"campaignName", - "documentation":"

The name of a campaign.

" - }, - "description":{ - "shape":"description", - "documentation":"

The description of the campaign.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of the signal catalog associated with the campaign.

" - }, - "targetArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle or fleet to which the campaign is deployed.

" - }, - "status":{ - "shape":"CampaignStatus", - "documentation":"

The state of a campaign. The status can be one of the following:

  • CREATING - Amazon Web Services IoT FleetWise is processing your request to create the campaign.

  • WAITING_FOR_APPROVAL - After a campaign is created, it enters the WAITING_FOR_APPROVAL state. To allow Amazon Web Services IoT FleetWise to deploy the campaign to the target vehicle or fleet, use the API operation to approve the campaign.

  • RUNNING - The campaign is active.

  • SUSPENDED - The campaign is suspended. To resume the campaign, use the API operation.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the campaign was created.

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The last time the campaign was modified.

" - } - }, - "documentation":"

Information about a campaign.

You can use the API operation to return this information about multiple created campaigns.

" - }, - "CanDbcDefinition":{ - "type":"structure", - "required":[ - "networkInterface", - "canDbcFiles" - ], - "members":{ - "networkInterface":{ - "shape":"InterfaceId", - "documentation":"

Contains information about a network interface.

" - }, - "canDbcFiles":{ - "shape":"NetworkFilesList", - "documentation":"

A list of DBC files. You can upload only one DBC file for each network interface and specify up to five (inclusive) files in the list.

" - }, - "signalsMap":{ - "shape":"ModelSignalsMap", - "documentation":"

Pairs every signal specified in your vehicle model with a signal decoder.

" - } - }, - "documentation":"

Configurations used to create a decoder manifest.

" - }, - "CanInterface":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"CanInterfaceName", - "documentation":"

The unique name of the interface.

" - }, - "protocolName":{ - "shape":"ProtocolName", - "documentation":"

The name of the communication protocol for the interface.

" - }, - "protocolVersion":{ - "shape":"ProtocolVersion", - "documentation":"

The version of the communication protocol for the interface.

" - } - }, - "documentation":"

A single controller area network (CAN) device interface.

" - }, - "CanInterfaceName":{ - "type":"string", - "max":100, - "min":1 - }, - "CanSignal":{ - "type":"structure", - "required":[ - "messageId", - "isBigEndian", - "isSigned", - "startBit", - "offset", - "factor", - "length" - ], - "members":{ - "messageId":{ - "shape":"nonNegativeInteger", - "documentation":"

The ID of the message.

" - }, - "isBigEndian":{ - "shape":"boolean", - "documentation":"

Whether the byte ordering of a CAN message is big-endian.

" - }, - "isSigned":{ - "shape":"boolean", - "documentation":"

Whether the message data is specified as a signed value.

" - }, - "startBit":{ - "shape":"nonNegativeInteger", - "documentation":"

Indicates the beginning of the CAN message.

" - }, - "offset":{ - "shape":"double", - "documentation":"

Indicates where data appears in the CAN message.

" - }, - "factor":{ - "shape":"double", - "documentation":"

A multiplier used to decode the CAN message.

" - }, - "length":{ - "shape":"nonNegativeInteger", - "documentation":"

How many bytes of data are in the message.

" - }, - "name":{ - "shape":"CanSignalName", - "documentation":"

The name of the signal.

" - } - }, - "documentation":"

Information about a single controller area network (CAN) signal and the messages it receives and transmits.

" - }, - "CanSignalName":{ - "type":"string", - "max":100, - "min":1 - }, - "CloudWatchLogDeliveryOptions":{ - "type":"structure", - "required":["logType"], - "members":{ - "logType":{ - "shape":"LogType", - "documentation":"

The type of log to send data to Amazon CloudWatch Logs.

" - }, - "logGroupName":{ - "shape":"CloudWatchLogGroupName", - "documentation":"

The Amazon CloudWatch Logs group the operation sends data to.

" - } - }, - "documentation":"

The log delivery option to send data to Amazon CloudWatch Logs.

" - }, - "CloudWatchLogGroupName":{ - "type":"string", - "max":512, - "min":1, - "pattern":"[\\.\\-_\\/#A-Za-z0-9]+" - }, - "CollectionScheme":{ - "type":"structure", - "members":{ - "timeBasedCollectionScheme":{ - "shape":"TimeBasedCollectionScheme", - "documentation":"

Information about a collection scheme that uses a time period to decide how often to collect data.

" - }, - "conditionBasedCollectionScheme":{ - "shape":"ConditionBasedCollectionScheme", - "documentation":"

Information about a collection scheme that uses a simple logical expression to recognize what data to collect.

" - } - }, - "documentation":"

Specifies what data to collect and how often or when to collect it.

", - "union":true - }, - "Compression":{ - "type":"string", - "enum":[ - "OFF", - "SNAPPY" - ] - }, - "ConditionBasedCollectionScheme":{ - "type":"structure", - "required":["expression"], - "members":{ - "expression":{ - "shape":"eventExpression", - "documentation":"

The logical expression used to recognize what data to collect. For example, $variable.Vehicle.OutsideAirTemperature >= 105.0.

" - }, - "minimumTriggerIntervalMs":{ - "shape":"uint32", - "documentation":"

The minimum duration of time between two triggering events to collect data, in milliseconds.

If a signal changes often, you might want to collect data at a slower rate.

" - }, - "triggerMode":{ - "shape":"TriggerMode", - "documentation":"

Whether to collect data for all triggering events (ALWAYS). Specify (RISING_EDGE), or specify only when the condition first evaluates to false. For example, triggering on \"AirbagDeployed\"; Users aren't interested on triggering when the airbag is already exploded; they only care about the change from not deployed => deployed.

" - }, - "conditionLanguageVersion":{ - "shape":"languageVersion", - "documentation":"

Specifies the version of the conditional expression language.

" - } - }, - "documentation":"

Information about a collection scheme that uses a simple logical expression to recognize what data to collect.

" - }, - "ConflictException":{ - "type":"structure", - "required":[ - "message", - "resource", - "resourceType" - ], - "members":{ - "message":{"shape":"string"}, - "resource":{ - "shape":"string", - "documentation":"

The resource on which there are conflicting operations.

" - }, - "resourceType":{ - "shape":"string", - "documentation":"

The type of resource on which there are conflicting operations..

" - } - }, - "documentation":"

The request has conflicting operations. This can occur if you're trying to perform more than one operation on the same resource at the same time.

", - "exception":true - }, - "CreateCampaignRequest":{ - "type":"structure", - "required":[ - "name", - "signalCatalogArn", - "targetArn", - "collectionScheme" - ], - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the campaign to create.

" - }, - "description":{ - "shape":"description", - "documentation":"

An optional description of the campaign to help identify its purpose.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

(Optional) The Amazon Resource Name (ARN) of the signal catalog to associate with the campaign.

" - }, - "targetArn":{ - "shape":"arn", - "documentation":"

The ARN of the vehicle or fleet to deploy a campaign to.

" - }, - "startTime":{ - "shape":"timestamp", - "documentation":"

(Optional) The time, in milliseconds, to deliver a campaign after it was approved. If it's not specified, 0 is used.

Default: 0

" - }, - "expiryTime":{ - "shape":"timestamp", - "documentation":"

(Optional) The time the campaign expires, in seconds since epoch (January 1, 1970 at midnight UTC time). Vehicle data won't be collected after the campaign expires.

Default: 253402243200 (December 31, 9999, 00:00:00 UTC)

" - }, - "postTriggerCollectionDuration":{ - "shape":"uint32", - "documentation":"

(Optional) How long (in milliseconds) to collect raw data after a triggering event initiates the collection. If it's not specified, 0 is used.

Default: 0

" - }, - "diagnosticsMode":{ - "shape":"DiagnosticsMode", - "documentation":"

(Optional) Option for a vehicle to send diagnostic trouble codes to Amazon Web Services IoT FleetWise. If you want to send diagnostic trouble codes, use SEND_ACTIVE_DTCS. If it's not specified, OFF is used.

Default: OFF

" - }, - "spoolingMode":{ - "shape":"SpoolingMode", - "documentation":"

(Optional) Whether to store collected data after a vehicle lost a connection with the cloud. After a connection is re-established, the data is automatically forwarded to Amazon Web Services IoT FleetWise. If you want to store collected data when a vehicle loses connection with the cloud, use TO_DISK. If it's not specified, OFF is used.

Default: OFF

" - }, - "compression":{ - "shape":"Compression", - "documentation":"

(Optional) Whether to compress signals before transmitting data to Amazon Web Services IoT FleetWise. If you don't want to compress the signals, use OFF. If it's not specified, SNAPPY is used.

Default: SNAPPY

" - }, - "priority":{ - "shape":"priority", - "documentation":"

(Optional) A number indicating the priority of one campaign over another campaign for a certain vehicle or fleet. A campaign with the lowest value is deployed to vehicles before any other campaigns. If it's not specified, 0 is used.

Default: 0

" - }, - "signalsToCollect":{ - "shape":"SignalInformationList", - "documentation":"

(Optional) A list of information about signals to collect.

" - }, - "collectionScheme":{ - "shape":"CollectionScheme", - "documentation":"

The data collection scheme associated with the campaign. You can specify a scheme that collects data based on time or an event.

" - }, - "dataExtraDimensions":{ - "shape":"DataExtraDimensionNodePathList", - "documentation":"

(Optional) A list of vehicle attributes to associate with a campaign.

Default: An empty array

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the campaign.

" - } - } - }, - "CreateCampaignResponse":{ - "type":"structure", - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the created campaign.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created campaign.

" - } - } - }, - "CreateDecoderManifestRequest":{ - "type":"structure", - "required":[ - "name", - "modelManifestArn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The unique name of the decoder manifest to create.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the decoder manifest.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the vehicle model (model manifest).

" - }, - "signalDecoders":{ - "shape":"SignalDecoders", - "documentation":"

A list of information about signal decoders.

" - }, - "networkInterfaces":{ - "shape":"NetworkInterfaces", - "documentation":"

A list of information about available network interfaces.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the decoder manifest.

" - } - } - }, - "CreateDecoderManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the created decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created decoder manifest.

" - } - } - }, - "CreateFleetRequest":{ - "type":"structure", - "required":[ - "fleetId", - "signalCatalogArn" - ], - "members":{ - "fleetId":{ - "shape":"fleetId", - "documentation":"

The unique ID of the fleet to create.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the fleet to create.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a signal catalog.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the fleet.

" - } - } - }, - "CreateFleetResponse":{ - "type":"structure", - "required":[ - "id", - "arn" - ], - "members":{ - "id":{ - "shape":"fleetId", - "documentation":"

The ID of the created fleet.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created fleet.

" - } - } - }, - "CreateModelManifestRequest":{ - "type":"structure", - "required":[ - "name", - "nodes", - "signalCatalogArn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the vehicle model to create.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the vehicle model.

" - }, - "nodes":{ - "shape":"listOfStrings", - "documentation":"

A list of nodes, which are a general abstraction of signals.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a signal catalog.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the vehicle model.

" - } - } - }, - "CreateModelManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the created vehicle model.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created vehicle model.

" - } - } - }, - "CreateSignalCatalogRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to create.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the signal catalog.

" - }, - "nodes":{ - "shape":"Nodes", - "documentation":"

A list of information about nodes, which are a general abstraction of signals. For more information, see the API data type.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the signal catalog.

" - } - } - }, - "CreateSignalCatalogResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the created signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created signal catalog.

" - } - } - }, - "CreateVehicleError":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle with the error.

" - }, - "code":{ - "shape":"string", - "documentation":"

An HTTP error code.

" - }, - "message":{ - "shape":"string", - "documentation":"

A description of the HTTP error.

" - } - }, - "documentation":"

An HTTP error resulting from creating a vehicle.

" - }, - "CreateVehicleRequest":{ - "type":"structure", - "required":[ - "vehicleName", - "modelManifestArn", - "decoderManifestArn" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to create.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name ARN of a vehicle model.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a decoder manifest.

" - }, - "attributes":{ - "shape":"attributesMap", - "documentation":"

Static information about a vehicle in a key-value pair. For example: \"engineType\" : \"1.3 L R2\"

" - }, - "associationBehavior":{ - "shape":"VehicleAssociationBehavior", - "documentation":"

An option to create a new Amazon Web Services IoT thing when creating a vehicle, or to validate an existing Amazon Web Services IoT thing as a vehicle.

Default:

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the vehicle.

" - } - } - }, - "CreateVehicleRequestItem":{ - "type":"structure", - "required":[ - "vehicleName", - "modelManifestArn", - "decoderManifestArn" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to create.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of the vehicle model (model manifest) to create the vehicle from.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a decoder manifest associated with the vehicle to create.

" - }, - "attributes":{ - "shape":"attributesMap", - "documentation":"

Static information about a vehicle in a key-value pair. For example: \"engine Type\" : \"v6\"

" - }, - "associationBehavior":{ - "shape":"VehicleAssociationBehavior", - "documentation":"

An option to create a new Amazon Web Services IoT thing when creating a vehicle, or to validate an existing thing as a vehicle.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata which can be used to manage the vehicle.

" - } - }, - "documentation":"

Information about the vehicle to create.

" - }, - "CreateVehicleResponse":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the created vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created vehicle.

" - }, - "thingArn":{ - "shape":"arn", - "documentation":"

The ARN of a created or validated Amazon Web Services IoT thing.

" - } - } - }, - "CreateVehicleResponseItem":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to create.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the created vehicle.

" - }, - "thingArn":{ - "shape":"arn", - "documentation":"

The ARN of a created or validated Amazon Web Services IoT thing.

" - } - }, - "documentation":"

Information about a created vehicle.

" - }, - "DataExtraDimensionNodePathList":{ - "type":"list", - "member":{"shape":"NodePath"}, - "max":5, - "min":0 - }, - "DecoderManifestSummary":{ - "type":"structure", - "required":[ - "creationTime", - "lastModificationTime" - ], - "members":{ - "name":{ - "shape":"string", - "documentation":"

The name of the decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the decoder manifest.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the decoder manifest.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the decoder manifest.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the decoder manifest. If the status is ACTIVE, the decoder manifest can't be edited. If the status is marked DRAFT, you can edit the decoder manifest.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the decoder manifest was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the decoder manifest was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - }, - "documentation":"

Information about a created decoder manifest. You can use the API operation to return this information about multiple decoder manifests.

" - }, - "DecoderManifestValidationException":{ - "type":"structure", - "members":{ - "invalidSignals":{ - "shape":"InvalidSignalDecoders", - "documentation":"

The request couldn't be completed because of invalid signals in the request.

" - }, - "invalidNetworkInterfaces":{ - "shape":"InvalidNetworkInterfaces", - "documentation":"

The request couldn't be completed because of invalid network interfaces in the request.

" - } - }, - "documentation":"

The request couldn't be completed because it contains signal decoders with one or more validation errors.

", - "exception":true - }, - "DeleteCampaignRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the campaign to delete.

" - } - } - }, - "DeleteCampaignResponse":{ - "type":"structure", - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the deleted campaign.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted campaign.

The ARN isn’t returned if a campaign doesn’t exist.

" - } - } - }, - "DeleteDecoderManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to delete.

" - } - } - }, - "DeleteDecoderManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the deleted decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted decoder manifest.

" - } - } - }, - "DeleteFleetRequest":{ - "type":"structure", - "required":["fleetId"], - "members":{ - "fleetId":{ - "shape":"fleetId", - "documentation":"

The ID of the fleet to delete.

" - } - } - }, - "DeleteFleetResponse":{ - "type":"structure", - "members":{ - "id":{ - "shape":"fleetId", - "documentation":"

The ID of the deleted fleet.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted fleet.

" - } - } - }, - "DeleteModelManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the model manifest to delete.

" - } - } - }, - "DeleteModelManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the deleted model manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted model manifest.

" - } - } - }, - "DeleteSignalCatalogRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to delete.

" - } - } - }, - "DeleteSignalCatalogResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the deleted signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted signal catalog.

" - } - } - }, - "DeleteVehicleRequest":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle to delete.

" - } - } - }, - "DeleteVehicleResponse":{ - "type":"structure", - "required":[ - "vehicleName", - "arn" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the deleted vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the deleted vehicle.

" - } - } - }, - "DiagnosticsMode":{ - "type":"string", - "enum":[ - "OFF", - "SEND_ACTIVE_DTCS" - ] - }, - "DisassociateVehicleFleetRequest":{ - "type":"structure", - "required":[ - "vehicleName", - "fleetId" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to disassociate from the fleet.

" - }, - "fleetId":{ - "shape":"fleetId", - "documentation":"

The unique ID of a fleet.

" - } - } - }, - "DisassociateVehicleFleetResponse":{ - "type":"structure", - "members":{ - } - }, - "FleetSummary":{ - "type":"structure", - "required":[ - "id", - "arn", - "signalCatalogArn", - "creationTime" - ], - "members":{ - "id":{ - "shape":"fleetId", - "documentation":"

The unique ID of the fleet.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the fleet.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the fleet.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of the signal catalog associated with the fleet.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the fleet was created, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the fleet was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - }, - "documentation":"

Information about a fleet.

You can use the API operation to return this information about multiple fleets.

" - }, - "FormattedVss":{ - "type":"structure", - "members":{ - "vssJson":{ - "shape":"String", - "documentation":"

Provides the VSS in JSON format.

" - } - }, - "documentation":"

Vehicle Signal Specification (VSS) is a precise language used to describe and model signals in vehicle networks. The JSON file collects signal specificiations in a VSS format.

", - "union":true - }, - "Fqns":{ - "type":"list", - "member":{"shape":"FullyQualifiedName"}, - "max":500, - "min":1 - }, - "FullyQualifiedName":{ - "type":"string", - "max":150, - "min":1 - }, - "GetCampaignRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the campaign to retrieve information about.

" - } - } - }, - "GetCampaignResponse":{ - "type":"structure", - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the campaign.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the campaign.

" - }, - "description":{ - "shape":"description", - "documentation":"

The description of the campaign.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of a signal catalog.

" - }, - "targetArn":{ - "shape":"arn", - "documentation":"

The ARN of the vehicle or the fleet targeted by the campaign.

" - }, - "status":{ - "shape":"CampaignStatus", - "documentation":"

The state of the campaign. The status can be one of: CREATING, WAITING_FOR_APPROVAL, RUNNING, and SUSPENDED.

" - }, - "startTime":{ - "shape":"timestamp", - "documentation":"

The time, in milliseconds, to deliver a campaign after it was approved.

" - }, - "expiryTime":{ - "shape":"timestamp", - "documentation":"

The time the campaign expires, in seconds since epoch (January 1, 1970 at midnight UTC time). Vehicle data won't be collected after the campaign expires.

" - }, - "postTriggerCollectionDuration":{ - "shape":"uint32", - "documentation":"

How long (in seconds) to collect raw data after a triggering event initiates the collection.

" - }, - "diagnosticsMode":{ - "shape":"DiagnosticsMode", - "documentation":"

Option for a vehicle to send diagnostic trouble codes to Amazon Web Services IoT FleetWise.

" - }, - "spoolingMode":{ - "shape":"SpoolingMode", - "documentation":"

Whether to store collected data after a vehicle lost a connection with the cloud. After a connection is re-established, the data is automatically forwarded to Amazon Web Services IoT FleetWise.

" - }, - "compression":{ - "shape":"Compression", - "documentation":"

Whether to compress signals before transmitting data to Amazon Web Services IoT FleetWise. If OFF is specified, the signals aren't compressed. If it's not specified, SNAPPY is used.

" - }, - "priority":{ - "shape":"priority", - "documentation":"

A number indicating the priority of one campaign over another campaign for a certain vehicle or fleet. A campaign with the lowest value is deployed to vehicles before any other campaigns.

" - }, - "signalsToCollect":{ - "shape":"SignalInformationList", - "documentation":"

Information about a list of signals to collect data on.

" - }, - "collectionScheme":{ - "shape":"CollectionScheme", - "documentation":"

Information about the data collection scheme associated with the campaign.

" - }, - "dataExtraDimensions":{ - "shape":"DataExtraDimensionNodePathList", - "documentation":"

A list of vehicle attributes associated with the campaign.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the campaign was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The last time the campaign was modified.

" - } - } - }, - "GetDecoderManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to retrieve information about.

" - } - } - }, - "GetDecoderManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn", - "creationTime", - "lastModificationTime" - ], - "members":{ - "name":{ - "shape":"string", - "documentation":"

The name of the decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the decoder manifest.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the decoder manifest.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the decoder manifest.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the decoder manifest. If the status is ACTIVE, the decoder manifest can't be edited. If the status is marked DRAFT, you can edit the decoder manifest.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the decoder manifest was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the decoder manifest was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - } - }, - "GetFleetRequest":{ - "type":"structure", - "required":["fleetId"], - "members":{ - "fleetId":{ - "shape":"fleetId", - "documentation":"

The ID of the fleet to retrieve information about.

" - } - } - }, - "GetFleetResponse":{ - "type":"structure", - "required":[ - "id", - "arn", - "signalCatalogArn", - "creationTime", - "lastModificationTime" - ], - "members":{ - "id":{ - "shape":"fleetId", - "documentation":"

The ID of the fleet.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the fleet.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the fleet.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of a signal catalog associated with the fleet.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the fleet was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the fleet was last updated, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - } - }, - "GetLoggingOptionsRequest":{ - "type":"structure", - "members":{ - } - }, - "GetLoggingOptionsResponse":{ - "type":"structure", - "required":["cloudWatchLogDelivery"], - "members":{ - "cloudWatchLogDelivery":{ - "shape":"CloudWatchLogDeliveryOptions", - "documentation":"

Returns information about log delivery to Amazon CloudWatch Logs.

" - } - } - }, - "GetModelManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the vehicle model to retrieve information about.

" - } - } - }, - "GetModelManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn", - "creationTime", - "lastModificationTime" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the vehicle model.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the vehicle model.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the vehicle model.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of the signal catalog associated with the vehicle model.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the vehicle model. If the status is ACTIVE, the vehicle model can't be edited. You can edit the vehicle model if the status is marked DRAFT.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle model was created, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The last time the vehicle model was modified.

" - } - } - }, - "GetRegisterAccountStatusRequest":{ - "type":"structure", - "members":{ - } - }, - "GetRegisterAccountStatusResponse":{ - "type":"structure", - "required":[ - "customerAccountId", - "accountStatus", - "timestreamRegistrationResponse", - "iamRegistrationResponse", - "creationTime", - "lastModificationTime" - ], - "members":{ - "customerAccountId":{ - "shape":"customerAccountId", - "documentation":"

The unique ID of the Amazon Web Services account, provided at account creation.

" - }, - "accountStatus":{ - "shape":"RegistrationStatus", - "documentation":"

The status of registering your account and resources. The status can be one of:

  • REGISTRATION_SUCCESS - The Amazon Web Services resource is successfully registered.

  • REGISTRATION_PENDING - Amazon Web Services IoT FleetWise is processing the registration request. This process takes approximately five minutes to complete.

  • REGISTRATION_FAILURE - Amazon Web Services IoT FleetWise can't register the AWS resource. Try again later.

" - }, - "timestreamRegistrationResponse":{ - "shape":"TimestreamRegistrationResponse", - "documentation":"

Information about the registered Amazon Timestream resources or errors, if any.

" - }, - "iamRegistrationResponse":{ - "shape":"IamRegistrationResponse", - "documentation":"

Information about the registered IAM resources or errors, if any.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the account was registered, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time this registration was last updated, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - } - }, - "GetSignalCatalogRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to retrieve information about.

" - } - } - }, - "GetSignalCatalogResponse":{ - "type":"structure", - "required":[ - "name", - "arn", - "creationTime", - "lastModificationTime" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the signal catalog.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the signal catalog.

" - }, - "nodeCounts":{ - "shape":"NodeCounts", - "documentation":"

The total number of network nodes specified in a signal catalog.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the signal catalog was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The last time the signal catalog was modified.

" - } - } - }, - "GetVehicleRequest":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle to retrieve information about.

" - } - } - }, - "GetVehicleResponse":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the vehicle to retrieve information about.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the vehicle.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a decoder manifest associated with the vehicle.

" - }, - "attributes":{ - "shape":"attributesMap", - "documentation":"

Static information about a vehicle in a key-value pair. For example:

\"engineType\" : \"1.3 L R2\"

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - } - }, - "GetVehicleStatusRequest":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - }, - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle to retrieve information about.

" - } - } - }, - "GetVehicleStatusResponse":{ - "type":"structure", - "members":{ - "campaigns":{ - "shape":"VehicleStatusList", - "documentation":"

Lists information about the state of the vehicle with deployed campaigns.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "IAMRoleArn":{ - "type":"string", - "max":2048, - "min":20, - "pattern":"arn:(aws[a-zA-Z0-9-]*):iam::(\\d{12})?:(role((\\u002F)|(\\u002F[\\u0021-\\u007F]+\\u002F))[\\w+=,.@-]+)" - }, - "IamRegistrationResponse":{ - "type":"structure", - "required":[ - "roleArn", - "registrationStatus" - ], - "members":{ - "roleArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM role to register.

" - }, - "registrationStatus":{ - "shape":"RegistrationStatus", - "documentation":"

The status of registering your IAM resource. The status can be one of REGISTRATION_SUCCESS, REGISTRATION_PENDING, REGISTRATION_FAILURE.

" - }, - "errorMessage":{ - "shape":"errorMessage", - "documentation":"

A message associated with a registration error.

" - } - }, - "documentation":"

Information about registering an Identity and Access Management (IAM) resource so Amazon Web Services IoT FleetWise edge agent software can transfer your vehicle data to Amazon Timestream.

" - }, - "IamResources":{ - "type":"structure", - "required":["roleArn"], - "members":{ - "roleArn":{ - "shape":"IAMRoleArn", - "documentation":"

The Amazon Resource Name (ARN) of the IAM resource that allows Amazon Web Services IoT FleetWise to send data to Amazon Timestream. For example, arn:aws:iam::123456789012:role/SERVICE-ROLE-ARN.

" - } - }, - "documentation":"

The IAM resource that enables Amazon Web Services IoT FleetWise edge agent software to send data to Amazon Timestream.

For more information, see IAM roles in the Identity and Access Management User Guide.

" - }, - "ImportDecoderManifestRequest":{ - "type":"structure", - "required":[ - "name", - "networkFileDefinitions" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to import.

" - }, - "networkFileDefinitions":{ - "shape":"NetworkFileDefinitions", - "documentation":"

The file to load into an Amazon Web Services account.

" - } - } - }, - "ImportDecoderManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the imported decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the decoder manifest that was imported.

" - } - } - }, - "ImportSignalCatalogRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to import.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the signal catalog.

" - }, - "vss":{ - "shape":"FormattedVss", - "documentation":"

The contents of the Vehicle Signal Specification (VSS) configuration. VSS is a precise language used to describe and model signals in vehicle networks.

" - }, - "tags":{ - "shape":"TagList", - "documentation":"

Metadata that can be used to manage the signal catalog.

" - } - } - }, - "ImportSignalCatalogResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the imported signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the imported signal catalog.

" - } - } - }, - "InterfaceId":{ - "type":"string", - "max":50, - "min":1 - }, - "InterfaceIds":{ - "type":"list", - "member":{"shape":"InterfaceId"}, - "max":500, - "min":1 - }, - "InternalServerException":{ - "type":"structure", - "required":["message"], - "members":{ - "message":{"shape":"string"}, - "retryAfterSeconds":{ - "shape":"RetryAfterSeconds", - "documentation":"

The number of seconds to wait before retrying the command.

" - } - }, - "documentation":"

The request couldn't be completed because the server temporarily failed.

", - "exception":true, - "fault":true - }, - "InvalidNetworkInterface":{ - "type":"structure", - "members":{ - "interfaceId":{ - "shape":"InterfaceId", - "documentation":"

The ID of the interface that isn't valid.

" - }, - "reason":{ - "shape":"NetworkInterfaceFailureReason", - "documentation":"

A message about why the interface isn't valid.

" - } - }, - "documentation":"

A reason a vehicle network interface isn't valid.

" - }, - "InvalidNetworkInterfaces":{ - "type":"list", - "member":{"shape":"InvalidNetworkInterface"} - }, - "InvalidNodeException":{ - "type":"structure", - "members":{ - "invalidNodes":{ - "shape":"Nodes", - "documentation":"

The specified node type isn't valid.

" - }, - "reason":{ - "shape":"string", - "documentation":"

The reason the node validation failed.

" - } - }, - "documentation":"

The specified node type doesn't match the expected node type for a node. You can specify the node type as branch, sensor, actuator, or attribute.

", - "exception":true - }, - "InvalidSignal":{ - "type":"structure", - "members":{ - "name":{ - "shape":"FullyQualifiedName", - "documentation":"

The name of the signal that isn't valid.

" - }, - "reason":{ - "shape":"string", - "documentation":"

A message about why the signal isn't valid.

" - } - }, - "documentation":"

A reason that a signal isn't valid.

" - }, - "InvalidSignalDecoder":{ - "type":"structure", - "members":{ - "name":{ - "shape":"FullyQualifiedName", - "documentation":"

The name of a signal decoder that isn't valid.

" - }, - "reason":{ - "shape":"SignalDecoderFailureReason", - "documentation":"

A message about why the signal decoder isn't valid.

" - } - }, - "documentation":"

A reason that a signal decoder isn't valid.

" - }, - "InvalidSignalDecoders":{ - "type":"list", - "member":{"shape":"InvalidSignalDecoder"} - }, - "InvalidSignals":{ - "type":"list", - "member":{"shape":"InvalidSignal"} - }, - "InvalidSignalsException":{ - "type":"structure", - "members":{ - "message":{"shape":"string"}, - "invalidSignals":{ - "shape":"InvalidSignals", - "documentation":"

The signals which caused the exception.

" - } - }, - "documentation":"

The request couldn't be completed because it contains signals that aren't valid.

", - "exception":true - }, - "LimitExceededException":{ - "type":"structure", - "required":[ - "message", - "resourceId", - "resourceType" - ], - "members":{ - "message":{"shape":"string"}, - "resourceId":{ - "shape":"string", - "documentation":"

The identifier of the resource that was exceeded.

" - }, - "resourceType":{ - "shape":"string", - "documentation":"

The type of resource that was exceeded.

" - } - }, - "documentation":"

A service quota was exceeded.

", - "exception":true - }, - "ListCampaignsRequest":{ - "type":"structure", - "members":{ - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - }, - "status":{ - "shape":"status", - "documentation":"

Optional parameter to filter the results by the status of each created campaign in your account. The status can be one of: CREATING, WAITING_FOR_APPROVAL, RUNNING, or SUSPENDED.

" - } - } - }, - "ListCampaignsResponse":{ - "type":"structure", - "members":{ - "campaignSummaries":{ - "shape":"campaignSummaries", - "documentation":"

A summary of information about each campaign.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListDecoderManifestNetworkInterfacesRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to list information about.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListDecoderManifestNetworkInterfacesResponse":{ - "type":"structure", - "members":{ - "networkInterfaces":{ - "shape":"NetworkInterfaces", - "documentation":"

A list of information about network interfaces.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListDecoderManifestSignalsRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to list information about.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListDecoderManifestSignalsResponse":{ - "type":"structure", - "members":{ - "signalDecoders":{ - "shape":"SignalDecoders", - "documentation":"

Information about a list of signals to decode.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListDecoderManifestsRequest":{ - "type":"structure", - "members":{ - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a vehicle model (model manifest) associated with the decoder manifest.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListDecoderManifestsResponse":{ - "type":"structure", - "members":{ - "summaries":{ - "shape":"decoderManifestSummaries", - "documentation":"

A list of information about each decoder manifest.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListFleetsForVehicleRequest":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle to retrieve information about.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListFleetsForVehicleResponse":{ - "type":"structure", - "members":{ - "fleets":{ - "shape":"fleets", - "documentation":"

A list of fleet IDs that the vehicle is associated with.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListFleetsRequest":{ - "type":"structure", - "members":{ - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListFleetsResponse":{ - "type":"structure", - "members":{ - "fleetSummaries":{ - "shape":"fleetSummaries", - "documentation":"

A list of information for each fleet.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListModelManifestNodesRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the vehicle model to list information about.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListModelManifestNodesResponse":{ - "type":"structure", - "members":{ - "nodes":{ - "shape":"Nodes", - "documentation":"

A list of information about nodes.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListModelManifestsRequest":{ - "type":"structure", - "members":{ - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of a signal catalog. If you specify a signal catalog, only the vehicle models associated with it are returned.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListModelManifestsResponse":{ - "type":"structure", - "members":{ - "summaries":{ - "shape":"modelManifestSummaries", - "documentation":"

A list of information about vehicle models.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListSignalCatalogNodesRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to list information about.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListSignalCatalogNodesResponse":{ - "type":"structure", - "members":{ - "nodes":{ - "shape":"Nodes", - "documentation":"

A list of information about nodes.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListSignalCatalogsRequest":{ - "type":"structure", - "members":{ - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListSignalCatalogsResponse":{ - "type":"structure", - "members":{ - "summaries":{ - "shape":"signalCatalogSummaries", - "documentation":"

A list of information about each signal catalog.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListTagsForResourceRequest":{ - "type":"structure", - "required":["ResourceARN"], - "members":{ - "ResourceARN":{ - "shape":"AmazonResourceName", - "documentation":"

The ARN of the resource.

" - } - } - }, - "ListTagsForResourceResponse":{ - "type":"structure", - "members":{ - "Tags":{ - "shape":"TagList", - "documentation":"

The list of tags assigned to the resource.

" - } - } - }, - "ListVehiclesInFleetRequest":{ - "type":"structure", - "required":["fleetId"], - "members":{ - "fleetId":{ - "shape":"fleetId", - "documentation":"

The ID of a fleet.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"maxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListVehiclesInFleetResponse":{ - "type":"structure", - "members":{ - "vehicles":{ - "shape":"vehicles", - "documentation":"

A list of vehicles associated with the fleet.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "ListVehiclesRequest":{ - "type":"structure", - "members":{ - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of a vehicle model (model manifest). You can use this optional parameter to list only the vehicles created from a certain vehicle model.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

A pagination token for the next set of results.

If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next set of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

" - }, - "maxResults":{ - "shape":"listVehiclesMaxResults", - "documentation":"

The maximum number of items to return, between 1 and 100, inclusive.

" - } - } - }, - "ListVehiclesResponse":{ - "type":"structure", - "members":{ - "vehicleSummaries":{ - "shape":"vehicleSummaries", - "documentation":"

A list of vehicles and information about them.

" - }, - "nextToken":{ - "shape":"nextToken", - "documentation":"

The token to retrieve the next set of results, or null if there are no more results.

" - } - } - }, - "LogType":{ - "type":"string", - "enum":[ - "OFF", - "ERROR" - ] - }, - "ManifestStatus":{ - "type":"string", - "enum":[ - "ACTIVE", - "DRAFT" - ] - }, - "ModelManifestSummary":{ - "type":"structure", - "required":[ - "creationTime", - "lastModificationTime" - ], - "members":{ - "name":{ - "shape":"string", - "documentation":"

The name of the vehicle model.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the vehicle model.

" - }, - "signalCatalogArn":{ - "shape":"arn", - "documentation":"

The ARN of the signal catalog associated with the vehicle model.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the vehicle model.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the vehicle model. If the status is ACTIVE, the vehicle model can't be edited. If the status is DRAFT, you can edit the vehicle model.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle model was created, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle model was last updated, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - }, - "documentation":"

Information about a vehicle model (model manifest). You can use the API operation to return this information about multiple vehicle models.

" - }, - "ModelSignalsMap":{ - "type":"map", - "key":{"shape":"string"}, - "value":{"shape":"string"} - }, - "NetworkFileBlob":{"type":"blob"}, - "NetworkFileDefinition":{ - "type":"structure", - "members":{ - "canDbc":{ - "shape":"CanDbcDefinition", - "documentation":"

Information, including CAN DBC files, about the configurations used to create a decoder manifest.

" - } - }, - "documentation":"

Specifications for defining a vehicle network.

", - "union":true - }, - "NetworkFileDefinitions":{ - "type":"list", - "member":{"shape":"NetworkFileDefinition"} - }, - "NetworkFilesList":{ - "type":"list", - "member":{"shape":"NetworkFileBlob"}, - "max":5, - "min":1 - }, - "NetworkInterface":{ - "type":"structure", - "required":[ - "interfaceId", - "type" - ], - "members":{ - "interfaceId":{ - "shape":"InterfaceId", - "documentation":"

The ID of the network interface.

" - }, - "type":{ - "shape":"NetworkInterfaceType", - "documentation":"

The network protocol for the vehicle. For example, CAN_SIGNAL specifies a protocol that defines how data is communicated between electronic control units (ECUs). OBD_SIGNAL specifies a protocol that defines how self-diagnostic data is communicated between ECUs.

" - }, - "canInterface":{ - "shape":"CanInterface", - "documentation":"

Information about a network interface specified by the Controller Area Network (CAN) protocol.

" - }, - "obdInterface":{ - "shape":"ObdInterface", - "documentation":"

Information about a network interface specified by the On-board diagnostic (OBD) II protocol.

" - } - }, - "documentation":"

Represents a node and its specifications in an in-vehicle communication network. All signal decoders must be associated with a network node.

To return this information about all the network interfaces specified in a decoder manifest, use the API operation.

" - }, - "NetworkInterfaceFailureReason":{ - "type":"string", - "enum":[ - "DUPLICATE_NETWORK_INTERFACE", - "CONFLICTING_NETWORK_INTERFACE", - "NETWORK_INTERFACE_TO_ADD_ALREADY_EXISTS", - "CAN_NETWORK_INTERFACE_INFO_IS_NULL", - "OBD_NETWORK_INTERFACE_INFO_IS_NULL", - "NETWORK_INTERFACE_TO_REMOVE_ASSOCIATED_WITH_SIGNALS" - ] - }, - "NetworkInterfaceType":{ - "type":"string", - "enum":[ - "CAN_INTERFACE", - "OBD_INTERFACE" - ] - }, - "NetworkInterfaces":{ - "type":"list", - "member":{"shape":"NetworkInterface"}, - "max":500, - "min":1 - }, - "Node":{ - "type":"structure", - "members":{ - "branch":{ - "shape":"Branch", - "documentation":"

Information about a node specified as a branch.

A group of signals that are defined in a hierarchical structure.

" - }, - "sensor":{"shape":"Sensor"}, - "actuator":{ - "shape":"Actuator", - "documentation":"

Information about a node specified as an actuator.

An actuator is a digital representation of a vehicle device.

" - }, - "attribute":{ - "shape":"Attribute", - "documentation":"

Information about a node specified as an attribute.

An attribute represents static information about a vehicle.

" - } - }, - "documentation":"

A general abstraction of a signal. A node can be specified as an actuator, attribute, branch, or sensor.

", - "union":true - }, - "NodeCounts":{ - "type":"structure", - "members":{ - "totalNodes":{ - "shape":"number", - "documentation":"

The total number of nodes in a vehicle network.

" - }, - "totalBranches":{ - "shape":"number", - "documentation":"

The total number of nodes in a vehicle network that represent branches.

" - }, - "totalSensors":{ - "shape":"number", - "documentation":"

The total number of nodes in a vehicle network that represent sensors.

" - }, - "totalAttributes":{ - "shape":"number", - "documentation":"

The total number of nodes in a vehicle network that represent attributes.

" - }, - "totalActuators":{ - "shape":"number", - "documentation":"

The total number of nodes in a vehicle network that represent actuators.

" - } - }, - "documentation":"

Information about the number of nodes and node types in a vehicle network.

" - }, - "NodeDataType":{ - "type":"string", - "enum":[ - "INT8", - "UINT8", - "INT16", - "UINT16", - "INT32", - "UINT32", - "INT64", - "UINT64", - "BOOLEAN", - "FLOAT", - "DOUBLE", - "STRING", - "UNIX_TIMESTAMP", - "INT8_ARRAY", - "UINT8_ARRAY", - "INT16_ARRAY", - "UINT16_ARRAY", - "INT32_ARRAY", - "UINT32_ARRAY", - "INT64_ARRAY", - "UINT64_ARRAY", - "BOOLEAN_ARRAY", - "FLOAT_ARRAY", - "DOUBLE_ARRAY", - "STRING_ARRAY", - "UNIX_TIMESTAMP_ARRAY", - "UNKNOWN" - ] - }, - "NodePath":{ - "type":"string", - "max":150, - "min":1, - "pattern":"[a-zA-Z0-9_.]+" - }, - "NodePaths":{ - "type":"list", - "member":{"shape":"NodePath"}, - "max":500, - "min":1 - }, - "Nodes":{ - "type":"list", - "member":{"shape":"Node"}, - "max":500, - "min":0 - }, - "ObdBitmaskLength":{ - "type":"integer", - "box":true, - "max":8, - "min":1 - }, - "ObdByteLength":{ - "type":"integer", - "box":true, - "max":8, - "min":1 - }, - "ObdInterface":{ - "type":"structure", - "required":[ - "name", - "requestMessageId" - ], - "members":{ - "name":{ - "shape":"ObdInterfaceName", - "documentation":"

The name of the interface.

" - }, - "requestMessageId":{ - "shape":"nonNegativeInteger", - "documentation":"

The ID of the message requesting vehicle data.

" - }, - "obdStandard":{ - "shape":"ObdStandard", - "documentation":"

The standard OBD II PID.

" - }, - "pidRequestIntervalSeconds":{ - "shape":"nonNegativeInteger", - "documentation":"

The maximum number message requests per second.

" - }, - "dtcRequestIntervalSeconds":{ - "shape":"nonNegativeInteger", - "documentation":"

The maximum number message requests per diagnostic trouble code per second.

" - }, - "useExtendedIds":{ - "shape":"boolean", - "documentation":"

Whether to use extended IDs in the message.

" - }, - "hasTransmissionEcu":{ - "shape":"boolean", - "documentation":"

Whether the vehicle has a transmission control module (TCM).

" - } - }, - "documentation":"

A network interface that specifies the On-board diagnostic (OBD) II network protocol.

" - }, - "ObdInterfaceName":{ - "type":"string", - "max":100, - "min":1 - }, - "ObdSignal":{ - "type":"structure", - "required":[ - "pidResponseLength", - "serviceMode", - "pid", - "scaling", - "offset", - "startByte", - "byteLength" - ], - "members":{ - "pidResponseLength":{ - "shape":"positiveInteger", - "documentation":"

The length of the requested data.

" - }, - "serviceMode":{ - "shape":"nonNegativeInteger", - "documentation":"

The mode of operation (diagnostic service) in a message.

" - }, - "pid":{ - "shape":"nonNegativeInteger", - "documentation":"

The diagnostic code used to request data from a vehicle for this signal.

" - }, - "scaling":{ - "shape":"double", - "documentation":"

A multiplier used to decode the message.

" - }, - "offset":{ - "shape":"double", - "documentation":"

Indicates where data appears in the message.

" - }, - "startByte":{ - "shape":"nonNegativeInteger", - "documentation":"

Indicates the beginning of the message.

" - }, - "byteLength":{ - "shape":"ObdByteLength", - "documentation":"

The length of a message.

" - }, - "bitRightShift":{ - "shape":"nonNegativeInteger", - "documentation":"

The number of positions to shift bits in the message.

" - }, - "bitMaskLength":{ - "shape":"ObdBitmaskLength", - "documentation":"

The number of bits to mask in a message.

" - } - }, - "documentation":"

Information about signal messages using the on-board diagnostics (OBD) II protocol in a vehicle.

" - }, - "ObdStandard":{ - "type":"string", - "max":50, - "min":1 - }, - "ProtocolName":{ - "type":"string", - "max":50, - "min":1 - }, - "ProtocolVersion":{ - "type":"string", - "max":50, - "min":1 - }, - "PutLoggingOptionsRequest":{ - "type":"structure", - "required":["cloudWatchLogDelivery"], - "members":{ - "cloudWatchLogDelivery":{ - "shape":"CloudWatchLogDeliveryOptions", - "documentation":"

Creates or updates the log delivery option to Amazon CloudWatch Logs.

" - } - } - }, - "PutLoggingOptionsResponse":{ - "type":"structure", - "members":{ - } - }, - "RegisterAccountRequest":{ - "type":"structure", - "required":["timestreamResources"], - "members":{ - "timestreamResources":{"shape":"TimestreamResources"}, - "iamResources":{ - "shape":"IamResources", - "documentation":"

The IAM resource that allows Amazon Web Services IoT FleetWise to send data to Amazon Timestream.

", - "deprecated":true, - "deprecatedMessage":"iamResources is no longer used or needed as input" - } - } - }, - "RegisterAccountResponse":{ - "type":"structure", - "required":[ - "registerAccountStatus", - "timestreamResources", - "iamResources", - "creationTime", - "lastModificationTime" - ], - "members":{ - "registerAccountStatus":{ - "shape":"RegistrationStatus", - "documentation":"

The status of registering your Amazon Web Services account, IAM role, and Timestream resources.

" - }, - "timestreamResources":{"shape":"TimestreamResources"}, - "iamResources":{ - "shape":"IamResources", - "documentation":"

The registered IAM resource that allows Amazon Web Services IoT FleetWise to send data to Amazon Timestream.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the account was registered, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time this registration was last updated, in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - } - }, - "RegistrationStatus":{ - "type":"string", - "enum":[ - "REGISTRATION_PENDING", - "REGISTRATION_SUCCESS", - "REGISTRATION_FAILURE" - ] - }, - "ResourceNotFoundException":{ - "type":"structure", - "required":[ - "message", - "resourceId", - "resourceType" - ], - "members":{ - "message":{"shape":"string"}, - "resourceId":{ - "shape":"string", - "documentation":"

The identifier of the resource that wasn't found.

" - }, - "resourceType":{ - "shape":"string", - "documentation":"

The type of resource that wasn't found.

" - } - }, - "documentation":"

The resource wasn't found.

", - "exception":true - }, - "RetryAfterSeconds":{"type":"integer"}, - "Sensor":{ - "type":"structure", - "required":[ - "fullyQualifiedName", - "dataType" - ], - "members":{ - "fullyQualifiedName":{ - "shape":"string", - "documentation":"

The fully qualified name of the sensor. For example, the fully qualified name of a sensor might be Vehicle.Body.Engine.Battery.

" - }, - "dataType":{ - "shape":"NodeDataType", - "documentation":"

The specified data type of the sensor.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of a sensor.

" - }, - "unit":{ - "shape":"string", - "documentation":"

The scientific unit of measurement for data collected by the sensor.

" - }, - "allowedValues":{ - "shape":"listOfStrings", - "documentation":"

A list of possible values a sensor can take.

" - }, - "min":{ - "shape":"double", - "documentation":"

The specified possible minimum value of the sensor.

" - }, - "max":{ - "shape":"double", - "documentation":"

The specified possible maximum value of the sensor.

" - } - }, - "documentation":"

An input component that reports the environmental condition of a vehicle.

You can collect data about fluid levels, temperatures, vibrations, or battery voltage from sensors.

" - }, - "SignalCatalogSummary":{ - "type":"structure", - "members":{ - "name":{ - "shape":"string", - "documentation":"

The name of the signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the signal catalog.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the signal catalog was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the signal catalog was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - }, - "documentation":"

Information about a collection of standardized signals, which can be attributes, branches, sensors, or actuators.

" - }, - "SignalDecoder":{ - "type":"structure", - "required":[ - "fullyQualifiedName", - "type", - "interfaceId" - ], - "members":{ - "fullyQualifiedName":{ - "shape":"FullyQualifiedName", - "documentation":"

The fully qualified name of a signal decoder as defined in a vehicle model.

" - }, - "type":{ - "shape":"SignalDecoderType", - "documentation":"

The network protocol for the vehicle. For example, CAN_SIGNAL specifies a protocol that defines how data is communicated between electronic control units (ECUs). OBD_SIGNAL specifies a protocol that defines how self-diagnostic data is communicated between ECUs.

" - }, - "interfaceId":{ - "shape":"InterfaceId", - "documentation":"

The ID of a network interface that specifies what network protocol a vehicle follows.

" - }, - "canSignal":{ - "shape":"CanSignal", - "documentation":"

Information about signal decoder using the Controller Area Network (CAN) protocol.

" - }, - "obdSignal":{ - "shape":"ObdSignal", - "documentation":"

Information about signal decoder using the On-board diagnostic (OBD) II protocol.

" - } - }, - "documentation":"

Information about a signal decoder.

" - }, - "SignalDecoderFailureReason":{ - "type":"string", - "enum":[ - "DUPLICATE_SIGNAL", - "CONFLICTING_SIGNAL", - "SIGNAL_TO_ADD_ALREADY_EXISTS", - "SIGNAL_NOT_ASSOCIATED_WITH_NETWORK_INTERFACE", - "NETWORK_INTERFACE_TYPE_INCOMPATIBLE_WITH_SIGNAL_DECODER_TYPE", - "SIGNAL_NOT_IN_MODEL", - "CAN_SIGNAL_INFO_IS_NULL", - "OBD_SIGNAL_INFO_IS_NULL", - "NO_DECODER_INFO_FOR_SIGNAL_IN_MODEL" - ] - }, - "SignalDecoderType":{ - "type":"string", - "enum":[ - "CAN_SIGNAL", - "OBD_SIGNAL" - ] - }, - "SignalDecoders":{ - "type":"list", - "member":{"shape":"SignalDecoder"}, - "max":500, - "min":1 - }, - "SignalInformation":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"wildcardSignalName", - "documentation":"

The name of the signal.

" - }, - "maxSampleCount":{ - "shape":"maxSampleCount", - "documentation":"

The maximum number of samples to collect.

" - }, - "minimumSamplingIntervalMs":{ - "shape":"uint32", - "documentation":"

The minimum duration of time (in milliseconds) between two triggering events to collect data.

If a signal changes often, you might want to collect data at a slower rate.

" - } - }, - "documentation":"

Information about a signal.

" - }, - "SignalInformationList":{ - "type":"list", - "member":{"shape":"SignalInformation"}, - "max":1000, - "min":0 - }, - "SpoolingMode":{ - "type":"string", - "enum":[ - "OFF", - "TO_DISK" - ] - }, - "String":{"type":"string"}, - "Tag":{ - "type":"structure", - "required":[ - "Key", - "Value" - ], - "members":{ - "Key":{ - "shape":"TagKey", - "documentation":"

The tag's key.

" - }, - "Value":{ - "shape":"TagValue", - "documentation":"

The tag's value.

" - } - }, - "documentation":"

A set of key/value pairs that are used to manage the resource.

" - }, - "TagKey":{ - "type":"string", - "max":128, - "min":1 - }, - "TagKeyList":{ - "type":"list", - "member":{"shape":"TagKey"}, - "max":200, - "min":0 - }, - "TagList":{ - "type":"list", - "member":{"shape":"Tag"}, - "max":50, - "min":0 - }, - "TagResourceRequest":{ - "type":"structure", - "required":[ - "ResourceARN", - "Tags" - ], - "members":{ - "ResourceARN":{ - "shape":"AmazonResourceName", - "documentation":"

The ARN of the resource.

" - }, - "Tags":{ - "shape":"TagList", - "documentation":"

The new or modified tags for the resource.

" - } - } - }, - "TagResourceResponse":{ - "type":"structure", - "members":{ - } - }, - "TagValue":{ - "type":"string", - "max":256, - "min":0 - }, - "ThrottlingException":{ - "type":"structure", - "required":["message"], - "members":{ - "message":{"shape":"string"}, - "quotaCode":{ - "shape":"string", - "documentation":"

The quota identifier of the applied throttling rules for this request.

" - }, - "serviceCode":{ - "shape":"string", - "documentation":"

The code for the service that couldn't be completed due to throttling.

" - }, - "retryAfterSeconds":{ - "shape":"RetryAfterSeconds", - "documentation":"

The number of seconds to wait before retrying the command.

" - } - }, - "documentation":"

The request couldn't be completed due to throttling.

", - "exception":true - }, - "TimeBasedCollectionScheme":{ - "type":"structure", - "required":["periodMs"], - "members":{ - "periodMs":{ - "shape":"collectionPeriodMs", - "documentation":"

The time period (in milliseconds) to decide how often to collect data. For example, if the time period is 60000, the Edge Agent software collects data once every minute.

" - } - }, - "documentation":"

Information about a collection scheme that uses a time period to decide how often to collect data.

" - }, - "TimestreamDatabaseName":{ - "type":"string", - "max":255, - "min":3, - "pattern":"[a-zA-Z0-9_.-]+" - }, - "TimestreamRegistrationResponse":{ - "type":"structure", - "required":[ - "timestreamDatabaseName", - "timestreamTableName", - "registrationStatus" - ], - "members":{ - "timestreamDatabaseName":{ - "shape":"TimestreamDatabaseName", - "documentation":"

The name of the Timestream database.

" - }, - "timestreamTableName":{ - "shape":"TimestreamTableName", - "documentation":"

The name of the Timestream database table.

" - }, - "timestreamDatabaseArn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the Timestream database.

" - }, - "timestreamTableArn":{ - "shape":"arn", - "documentation":"

The ARN of the Timestream database table.

" - }, - "registrationStatus":{ - "shape":"RegistrationStatus", - "documentation":"

The status of registering your Amazon Timestream resources. The status can be one of REGISTRATION_SUCCESS, REGISTRATION_PENDING, REGISTRATION_FAILURE.

" - }, - "errorMessage":{ - "shape":"errorMessage", - "documentation":"

A message associated with a registration error.

" - } - }, - "documentation":"

Information about the registered Amazon Timestream resources or errors, if any.

" - }, - "TimestreamResources":{ - "type":"structure", - "required":[ - "timestreamDatabaseName", - "timestreamTableName" - ], - "members":{ - "timestreamDatabaseName":{ - "shape":"TimestreamDatabaseName", - "documentation":"

The name of the registered Amazon Timestream database.

" - }, - "timestreamTableName":{ - "shape":"TimestreamTableName", - "documentation":"

The name of the registered Amazon Timestream database table.

" - } - }, - "documentation":"

The registered Amazon Timestream resources that Amazon Web Services IoT FleetWise edge agent software can transfer your vehicle data to.

" - }, - "TimestreamTableName":{ - "type":"string", - "max":255, - "min":3, - "pattern":"[a-zA-Z0-9_.-]+" - }, - "TriggerMode":{ - "type":"string", - "enum":[ - "ALWAYS", - "RISING_EDGE" - ] - }, - "UntagResourceRequest":{ - "type":"structure", - "required":[ - "ResourceARN", - "TagKeys" - ], - "members":{ - "ResourceARN":{ - "shape":"AmazonResourceName", - "documentation":"

The ARN of the resource.

" - }, - "TagKeys":{ - "shape":"TagKeyList", - "documentation":"

A list of the keys of the tags to be removed from the resource.

" - } - } - }, - "UntagResourceResponse":{ - "type":"structure", - "members":{ - } - }, - "UpdateCampaignAction":{ - "type":"string", - "enum":[ - "APPROVE", - "SUSPEND", - "RESUME", - "UPDATE" - ] - }, - "UpdateCampaignRequest":{ - "type":"structure", - "required":[ - "name", - "action" - ], - "members":{ - "name":{ - "shape":"campaignName", - "documentation":"

The name of the campaign to update.

" - }, - "description":{ - "shape":"description", - "documentation":"

The description of the campaign.

" - }, - "dataExtraDimensions":{ - "shape":"DataExtraDimensionNodePathList", - "documentation":"

A list of vehicle attributes to associate with a signal.

Default: An empty array

" - }, - "action":{ - "shape":"UpdateCampaignAction", - "documentation":"

Specifies how to update a campaign. The action can be one of the following:

  • APPROVE - To approve delivering a data collection scheme to vehicles.

  • SUSPEND - To suspend collecting signal data.

  • RESUME - To resume collecting signal data.

  • UPDATE - To update a campaign.

" - } - } - }, - "UpdateCampaignResponse":{ - "type":"structure", - "members":{ - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the campaign.

" - }, - "name":{ - "shape":"campaignName", - "documentation":"

The name of the updated campaign.

" - }, - "status":{ - "shape":"CampaignStatus", - "documentation":"

The state of a campaign. The status can be one of:

  • CREATING - Amazon Web Services IoT FleetWise is processing your request to create the campaign.

  • WAITING_FOR_APPROVAL - After a campaign is created, it enters the WAITING_FOR_APPROVAL state. To allow Amazon Web Services IoT FleetWise to deploy the campaign to the target vehicle or fleet, use the API operation to approve the campaign.

  • RUNNING - The campaign is active.

  • SUSPENDED - The campaign is suspended. To resume the campaign, use the API operation.

" - } - } - }, - "UpdateDecoderManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the decoder manifest to update.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the decoder manifest to update.

" - }, - "signalDecodersToAdd":{ - "shape":"SignalDecoders", - "documentation":"

A list of information about decoding additional signals to add to the decoder manifest.

" - }, - "signalDecodersToUpdate":{ - "shape":"SignalDecoders", - "documentation":"

A list of updated information about decoding signals to update in the decoder manifest.

" - }, - "signalDecodersToRemove":{ - "shape":"Fqns", - "documentation":"

A list of signal decoders to remove from the decoder manifest.

" - }, - "networkInterfacesToAdd":{ - "shape":"NetworkInterfaces", - "documentation":"

A list of information about the network interfaces to add to the decoder manifest.

" - }, - "networkInterfacesToUpdate":{ - "shape":"NetworkInterfaces", - "documentation":"

A list of information about the network interfaces to update in the decoder manifest.

" - }, - "networkInterfacesToRemove":{ - "shape":"InterfaceIds", - "documentation":"

A list of network interfaces to remove from the decoder manifest.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the decoder manifest. If the status is ACTIVE, the decoder manifest can't be edited. If the status is DRAFT, you can edit the decoder manifest.

" - } - } - }, - "UpdateDecoderManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the updated decoder manifest.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the updated decoder manifest.

" - } - } - }, - "UpdateFleetRequest":{ - "type":"structure", - "required":["fleetId"], - "members":{ - "fleetId":{ - "shape":"fleetId", - "documentation":"

The ID of the fleet to update.

" - }, - "description":{ - "shape":"description", - "documentation":"

An updated description of the fleet.

" - } - } - }, - "UpdateFleetResponse":{ - "type":"structure", - "members":{ - "id":{ - "shape":"fleetId", - "documentation":"

The ID of the updated fleet.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the updated fleet.

" - } - } - }, - "UpdateMode":{ - "type":"string", - "enum":[ - "Overwrite", - "Merge" - ] - }, - "UpdateModelManifestRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the vehicle model to update.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the vehicle model.

" - }, - "nodesToAdd":{ - "shape":"NodePaths", - "documentation":"

A list of fullyQualifiedName of nodes, which are a general abstraction of signals, to add to the vehicle model.

" - }, - "nodesToRemove":{ - "shape":"NodePaths", - "documentation":"

A list of fullyQualifiedName of nodes, which are a general abstraction of signals, to remove from the vehicle model.

" - }, - "status":{ - "shape":"ManifestStatus", - "documentation":"

The state of the vehicle model. If the status is ACTIVE, the vehicle model can't be edited. If the status is DRAFT, you can edit the vehicle model.

" - } - } - }, - "UpdateModelManifestResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the updated vehicle model.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the updated vehicle model.

" - } - } - }, - "UpdateSignalCatalogRequest":{ - "type":"structure", - "required":["name"], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the signal catalog to update.

" - }, - "description":{ - "shape":"description", - "documentation":"

A brief description of the signal catalog to update.

" - }, - "nodesToAdd":{ - "shape":"Nodes", - "documentation":"

A list of information about nodes to add to the signal catalog.

" - }, - "nodesToUpdate":{ - "shape":"Nodes", - "documentation":"

A list of information about nodes to update in the signal catalog.

" - }, - "nodesToRemove":{ - "shape":"NodePaths", - "documentation":"

A list of fullyQualifiedName of nodes to remove from the signal catalog.

" - } - } - }, - "UpdateSignalCatalogResponse":{ - "type":"structure", - "required":[ - "name", - "arn" - ], - "members":{ - "name":{ - "shape":"resourceName", - "documentation":"

The name of the updated signal catalog.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the updated signal catalog.

" - } - } - }, - "UpdateVehicleError":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the vehicle with the error.

" - }, - "code":{ - "shape":"number", - "documentation":"

The relevant HTTP error code (400+).

" - }, - "message":{ - "shape":"string", - "documentation":"

A message associated with the error.

" - } - }, - "documentation":"

An HTTP error resulting from updating the description for a vehicle.

" - }, - "UpdateVehicleRequest":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to update.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the vehicle.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of the decoder manifest associated with this vehicle.

" - }, - "attributes":{ - "shape":"attributesMap", - "documentation":"

Static information about a vehicle in a key-value pair. For example:

\"engineType\" : \"1.3 L R2\"

" - }, - "attributeUpdateMode":{ - "shape":"UpdateMode", - "documentation":"

The method the specified attributes will update the existing attributes on the vehicle. UseOverwite to replace the vehicle attributes with the specified attributes. Or use Merge to combine all attributes.

This is required if attributes are present in the input.

" - } - } - }, - "UpdateVehicleRequestItem":{ - "type":"structure", - "required":["vehicleName"], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle to update.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of the vehicle model (model manifest) associated with the vehicle to update.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of the signal decoder manifest associated with the vehicle to update.

" - }, - "attributes":{ - "shape":"attributesMap", - "documentation":"

Static information about a vehicle in a key-value pair. For example:

\"engineType\" : \"1.3 L R2\"

" - }, - "attributeUpdateMode":{ - "shape":"UpdateMode", - "documentation":"

The method the specified attributes will update the existing attributes on the vehicle. UseOverwite to replace the vehicle attributes with the specified attributes. Or use Merge to combine all attributes.

This is required if attributes are present in the input.

" - } - }, - "documentation":"

Information about the vehicle to update.

" - }, - "UpdateVehicleResponse":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The ID of the updated vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The ARN of the updated vehicle.

" - } - } - }, - "UpdateVehicleResponseItem":{ - "type":"structure", - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the updated vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the updated vehicle.

" - } - }, - "documentation":"

Information about the updated vehicle.

" - }, - "ValidationException":{ - "type":"structure", - "required":["message"], - "members":{ - "message":{"shape":"string"}, - "reason":{ - "shape":"ValidationExceptionReason", - "documentation":"

The reason the input failed to satisfy the constraints specified by an Amazon Web Services service.

" - }, - "fieldList":{ - "shape":"ValidationExceptionFieldList", - "documentation":"

The list of fields that fail to satisfy the constraints specified by an Amazon Web Services service.

" - } - }, - "documentation":"

The input fails to satisfy the constraints specified by an Amazon Web Services service.

", - "exception":true - }, - "ValidationExceptionField":{ - "type":"structure", - "required":[ - "name", - "message" - ], - "members":{ - "name":{ - "shape":"String", - "documentation":"

The name of the parameter field with the validation error.

" - }, - "message":{ - "shape":"String", - "documentation":"

A message about the validation error.

" - } - }, - "documentation":"

A validation error due to mismatch between the expected data type, length, or pattern of the parameter and the input.

" - }, - "ValidationExceptionFieldList":{ - "type":"list", - "member":{"shape":"ValidationExceptionField"} - }, - "ValidationExceptionReason":{ - "type":"string", - "enum":[ - "unknownOperation", - "cannotParse", - "fieldValidationFailed", - "other" - ] - }, - "VehicleAssociationBehavior":{ - "type":"string", - "enum":[ - "CreateIotThing", - "ValidateIotThingExists" - ] - }, - "VehicleState":{ - "type":"string", - "enum":[ - "CREATED", - "READY", - "HEALTHY", - "SUSPENDED", - "DELETING" - ] - }, - "VehicleStatus":{ - "type":"structure", - "members":{ - "campaignName":{ - "shape":"string", - "documentation":"

The name of a campaign.

" - }, - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle.

" - }, - "status":{ - "shape":"VehicleState", - "documentation":"

The state of a vehicle, which can be one of the following:

  • CREATED - Amazon Web Services IoT FleetWise sucessfully created the vehicle.

  • READY - The vehicle is ready to receive a campaign deployment.

  • HEALTHY - A campaign deployment was delivered to the vehicle.

  • SUSPENDED - A campaign associated with the vehicle was suspended and data collection was paused.

  • DELETING - Amazon Web Services IoT FleetWise is removing a campaign from the vehicle.

" - } - }, - "documentation":"

Information about the state of a vehicle and how it relates to the status of a campaign.

" - }, - "VehicleStatusList":{ - "type":"list", - "member":{"shape":"VehicleStatus"} - }, - "VehicleSummary":{ - "type":"structure", - "required":[ - "vehicleName", - "arn", - "modelManifestArn", - "decoderManifestArn", - "creationTime", - "lastModificationTime" - ], - "members":{ - "vehicleName":{ - "shape":"vehicleName", - "documentation":"

The unique ID of the vehicle.

" - }, - "arn":{ - "shape":"arn", - "documentation":"

The Amazon Resource Name (ARN) of the vehicle.

" - }, - "modelManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a vehicle model (model manifest) associated with the vehicle.

" - }, - "decoderManifestArn":{ - "shape":"arn", - "documentation":"

The ARN of a decoder manifest associated with the vehicle.

" - }, - "creationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle was created in seconds since epoch (January 1, 1970 at midnight UTC time).

" - }, - "lastModificationTime":{ - "shape":"timestamp", - "documentation":"

The time the vehicle was last updated in seconds since epoch (January 1, 1970 at midnight UTC time).

" - } - }, - "documentation":"

Information about a vehicle.

To return this information about vehicles in your account, you can use the API operation.

" - }, - "arn":{"type":"string"}, - "attributeName":{ - "type":"string", - "max":150, - "min":1, - "pattern":"[a-zA-Z0-9_.-]+" - }, - "attributeValue":{"type":"string"}, - "attributesMap":{ - "type":"map", - "key":{"shape":"attributeName"}, - "value":{"shape":"attributeValue"} - }, - "boolean":{"type":"boolean"}, - "campaignName":{ - "type":"string", - "max":100, - "min":1, - "pattern":"[a-zA-Z\\d\\-_:]+" - }, - "campaignSummaries":{ - "type":"list", - "member":{"shape":"CampaignSummary"} - }, - "collectionPeriodMs":{ - "type":"long", - "box":true, - "max":60000, - "min":10000 - }, - "createVehicleErrors":{ - "type":"list", - "member":{"shape":"CreateVehicleError"} - }, - "createVehicleRequestItems":{ - "type":"list", - "member":{"shape":"CreateVehicleRequestItem"} - }, - "createVehicleResponses":{ - "type":"list", - "member":{"shape":"CreateVehicleResponseItem"} - }, - "customerAccountId":{"type":"string"}, - "decoderManifestSummaries":{ - "type":"list", - "member":{"shape":"DecoderManifestSummary"} - }, - "description":{ - "type":"string", - "max":2048, - "min":1, - "pattern":"[^\\u0000-\\u001F\\u007F]+" - }, - "double":{ - "type":"double", - "box":true - }, - "errorMessage":{"type":"string"}, - "eventExpression":{ - "type":"string", - "max":2048, - "min":1 - }, - "fleetId":{ - "type":"string", - "max":100, - "min":1, - "pattern":"[a-zA-Z0-9:_-]+" - }, - "fleetSummaries":{ - "type":"list", - "member":{"shape":"FleetSummary"} - }, - "fleets":{ - "type":"list", - "member":{"shape":"fleetId"} - }, - "languageVersion":{ - "type":"integer", - "box":true, - "min":1 - }, - "listOfStrings":{ - "type":"list", - "member":{"shape":"string"} - }, - "listVehiclesMaxResults":{ - "type":"integer", - "box":true, - "max":100, - "min":1 - }, - "maxResults":{ - "type":"integer", - "box":true, - "max":100, - "min":1 - }, - "maxSampleCount":{ - "type":"long", - "box":true, - "max":4294967295, - "min":1 - }, - "modelManifestSummaries":{ - "type":"list", - "member":{"shape":"ModelManifestSummary"} - }, - "nextToken":{ - "type":"string", - "max":4096, - "min":1 - }, - "nonNegativeInteger":{ - "type":"integer", - "min":0 - }, - "number":{"type":"integer"}, - "positiveInteger":{ - "type":"integer", - "min":1 - }, - "priority":{ - "type":"integer", - "box":true, - "min":0 - }, - "resourceName":{ - "type":"string", - "max":100, - "min":1, - "pattern":"[a-zA-Z\\d\\-_:]+" - }, - "signalCatalogSummaries":{ - "type":"list", - "member":{"shape":"SignalCatalogSummary"} - }, - "status":{"type":"string"}, - "string":{"type":"string"}, - "timestamp":{"type":"timestamp"}, - "uint32":{ - "type":"long", - "box":true, - "max":4294967295, - "min":0 - }, - "updateVehicleErrors":{ - "type":"list", - "member":{"shape":"UpdateVehicleError"} - }, - "updateVehicleRequestItems":{ - "type":"list", - "member":{"shape":"UpdateVehicleRequestItem"} - }, - "updateVehicleResponseItems":{ - "type":"list", - "member":{"shape":"UpdateVehicleResponseItem"} - }, - "vehicleName":{ - "type":"string", - "max":100, - "min":1, - "pattern":"[a-zA-Z\\d\\-_:]+" - }, - "vehicleSummaries":{ - "type":"list", - "member":{"shape":"VehicleSummary"} - }, - "vehicles":{ - "type":"list", - "member":{"shape":"vehicleName"} - }, - "wildcardSignalName":{ - "type":"string", - "max":150, - "min":1, - "pattern":"[\\w|*|-]+(\\.[\\w|*|-]+)*" - } - }, - "documentation":"

Amazon Web Services IoT FleetWise is in preview release and is subject to change. We recommend that you use the service only with test data, and not in production environments.

While Amazon Web Services IoT FleetWise is in preview, you must download the preview Amazon Web Services SDK and CLI to use the API operations for this service. These API operations aren't available in the public Amazon Web Services SDK or CLI. For more information, see Preview Amazon Web Services SDK and CLI in the Amazon Web Services IoT FleetWise Developer Guide.

Amazon Web Services IoT FleetWise is a fully managed service that you can use to collect, model, and transfer vehicle data to the Amazon Web Services cloud at scale. With Amazon Web Services IoT FleetWise, you can standardize all of your vehicle data models, independent of the in-vehicle communication architecture, and define data collection rules to transfer only high-value data to the cloud.

For more information, see What is Amazon Web Services IoT FleetWise? in the Amazon Web Services IoT FleetWise Developer Guide.

" -} diff --git a/tools/configure-fwe.sh b/tools/configure-fwe.sh index 78f4b86c..2c872312 100755 --- a/tools/configure-fwe.sh +++ b/tools/configure-fwe.sh @@ -28,6 +28,9 @@ fi if [ -z "${LOG_LEVEL+x}" ]; then LOG_LEVEL="Info" fi +if [ -z "${LOG_COLOR+x}" ]; then + LOG_COLOR="Auto" +fi if [ -z "${PERSISTENCY_PATH+x}" ]; then PERSISTENCY_PATH="/var/aws-iot-fleetwise/" fi @@ -80,6 +83,7 @@ parse_args() { echo " --persistency-path Persistency path, default: ${PERSISTENCY_PATH}" echo " --topic-prefix IoT MQTT topic prefix, default: ${TOPIC_PREFIX}" echo " --log-level Log level. Either: Off, Error, Warning, Info, Trace. Default: ${LOG_LEVEL}" + echo " --log-color Whether logs should be colored. Either: Auto, Yes, No. Default: ${LOG_COLOR}" exit 0 ;; esac @@ -122,6 +126,7 @@ jq ".staticConfig.mqttConnection.endpointUrl=\"${ENDPOINT_URL}\"" ${INPUT_CONFIG | jq ".staticConfig.mqttConnection.certificateFilename=\"${CERTIFICATE_FILE}\"" \ | jq ".staticConfig.mqttConnection.privateKeyFilename=\"${PRIVATE_KEY_FILE}\"" \ | jq ".staticConfig.internalParameters.systemWideLogLevel=\"${LOG_LEVEL}\"" \ + | jq ".staticConfig.internalParameters.logColor=\"${LOG_COLOR}\"" \ | jq ".staticConfig.persistency.persistencyPath=\"${PERSISTENCY_PATH}\"" \ | jq ".networkInterfaces[0].canInterface.interfaceName=\"${CAN_BUS0}\"" \ | jq ".networkInterfaces[1].obdInterface.interfaceName=\"${CAN_BUS0}\"" \ diff --git a/tools/container/README.md b/tools/container/README.md index ed0f0a3e..8137077f 100644 --- a/tools/container/README.md +++ b/tools/container/README.md @@ -1,6 +1,7 @@ # Containerized Edge Agent -A containerized version of the edge agent is built using Github Actions, for amd64, arm64 and armv7. +A containerized version of the edge agent is built using Github Actions, and is available from +AWS ECR Public Gallery: https://gallery.ecr.aws/aws-iot-fleetwise-edge/aws-iot-fleetwise-edge ## Running the Container @@ -22,5 +23,5 @@ docker run \ --env VEHICLE_NAME= \ --env ENDPOINT_URL= \ --env CAN_BUS0= \ - ghcr.io/aws/aws-iot-fleetwise-edge + public.ecr.aws/aws-iot-fleetwise-edge/aws-iot-fleetwise-edge ``` diff --git a/tools/install-deps-cross-arm64.sh b/tools/install-deps-cross-arm64.sh index 7e6e1228..b9cc3365 100755 --- a/tools/install-deps-cross-arm64.sh +++ b/tools/install-deps-cross-arm64.sh @@ -45,7 +45,6 @@ apt install -y \ build-essential \ crossbuild-essential-arm64 \ cmake \ - faketime:arm64 \ unzip \ git \ wget \ @@ -60,6 +59,7 @@ if [ ! -d jsoncpp ]; then cd jsoncpp mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DJSONCPP_WITH_TESTS=Off \ @@ -71,10 +71,10 @@ if [ ! -d jsoncpp ]; then fi make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.tar.gz - tar -zxf protobuf-all-21.7.tar.gz - cd protobuf-21.7 +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 mkdir build && cd build ../configure cd .. @@ -83,8 +83,8 @@ if [ ! -d protobuf-21.7 ]; then ../configure --host=aarch64-linux --prefix=/usr/local/aarch64-linux-gnu cd ../.. fi -make install -j`nproc` -C protobuf-21.7/build -make install -j`nproc` -C protobuf-21.7/build_arm64 +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 @@ -125,32 +125,6 @@ if [ ! -d aws-sdk-cpp ]; then 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 - cd googletest - mkdir build && cd build - cmake \ - -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ - .. - 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 - cd benchmark - mkdir build && cd build - cmake \ - -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on \ - -DCMAKE_BUILD_TYPE=Release \ - .. - 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 \ @@ -163,6 +137,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd tinyxml2 mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_STATIC_LIBS=ON \ -DBUILD_TESTING=OFF \ @@ -179,6 +154,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd foonathan_memory_vendor mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -Dextra_cmake_args="-DCMAKE_CROSSCOMPILING_EMULATOR=qemu-aarch64" \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ @@ -193,6 +169,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-CDR mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/aarch64-linux-gnu/lib/cmake/arm64-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/aarch64-linux-gnu \ @@ -206,6 +183,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-DDS mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \ diff --git a/tools/install-deps-cross-armhf.sh b/tools/install-deps-cross-armhf.sh index 92eab645..f538e0ed 100755 --- a/tools/install-deps-cross-armhf.sh +++ b/tools/install-deps-cross-armhf.sh @@ -45,7 +45,6 @@ apt install -y \ build-essential \ crossbuild-essential-armhf \ cmake \ - faketime:armhf \ unzip \ git \ wget \ @@ -60,6 +59,7 @@ if [ ! -d jsoncpp ]; then cd jsoncpp mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DJSONCPP_WITH_TESTS=Off \ @@ -71,10 +71,10 @@ if [ ! -d jsoncpp ]; then fi make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.tar.gz - tar -zxf protobuf-all-21.7.tar.gz - cd protobuf-21.7 +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 mkdir build && cd build ../configure cd .. @@ -83,8 +83,8 @@ if [ ! -d protobuf-21.7 ]; then ../configure --host=arm-linux --prefix=/usr/local/arm-linux-gnueabihf cd ../.. fi -make install -j`nproc` -C protobuf-21.7/build -make install -j`nproc` -C protobuf-21.7/build_armhf +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 @@ -125,32 +125,6 @@ if [ ! -d aws-sdk-cpp ]; then 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 - cd googletest - mkdir build && cd build - cmake \ - -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ - .. - 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 - cd benchmark - mkdir build && cd build - cmake \ - -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ - -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ - -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on \ - -DCMAKE_BUILD_TYPE=Release \ - .. - 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 \ @@ -163,6 +137,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd tinyxml2 mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_STATIC_LIBS=ON \ -DBUILD_TESTS=OFF \ @@ -179,6 +154,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd foonathan_memory_vendor mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -Dextra_cmake_args="-DCMAKE_CROSSCOMPILING_EMULATOR=qemu-arm" \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ @@ -193,6 +169,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-CDR mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_TOOLCHAIN_FILE=/usr/local/arm-linux-gnueabihf/lib/cmake/armhf-toolchain.cmake \ -DCMAKE_INSTALL_PREFIX=/usr/local/arm-linux-gnueabihf \ @@ -206,6 +183,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-DDS mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \ diff --git a/tools/install-deps-native.sh b/tools/install-deps-native.sh index 09ee8f7d..bc74c03f 100755 --- a/tools/install-deps-native.sh +++ b/tools/install-deps-native.sh @@ -52,6 +52,7 @@ if [ ! -d jsoncpp ]; then cd jsoncpp mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_POSITION_INDEPENDENT_CODE=On \ -DJSONCPP_WITH_TESTS=Off \ @@ -61,15 +62,15 @@ if [ ! -d jsoncpp ]; then fi make install -j`nproc` -C jsoncpp/build -if [ ! -d protobuf-21.7 ]; then - wget -q https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.tar.gz - tar -zxf protobuf-all-21.7.tar.gz - cd protobuf-21.7 +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 mkdir build && cd build ../configure cd ../.. fi -make install -j`nproc` -C protobuf-21.7/build +make install -j`nproc` -C protobuf-3.21.7/build if [ ! -d can-isotp ]; then git clone https://github.com/hartkopp/can-isotp.git @@ -111,7 +112,9 @@ if [ ! -d googletest ]; then git clone -b release-1.10.0 https://github.com/google/googletest.git cd googletest mkdir build && cd build - cmake .. + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + .. cd ../.. fi make install -j`nproc` -C googletest/build @@ -120,7 +123,10 @@ if [ ! -d benchmark ]; then git clone -b v1.6.1 https://github.com/google/benchmark.git cd benchmark mkdir build && cd build - cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release .. + cmake \ + -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on \ + -DCMAKE_BUILD_TYPE=Release \ + .. cd ../.. fi make install -j`nproc` -C benchmark/build @@ -136,6 +142,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd tinyxml2 mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_STATIC_LIBS=ON \ -DBUILD_TESTING=OFF \ @@ -150,6 +157,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd foonathan_memory_vendor mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ .. cd ../.. @@ -161,6 +169,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-CDR mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ .. cd ../.. @@ -172,6 +181,7 @@ if [ "${WITH_CAMERA_SUPPORT}" == "true" ]; then cd Fast-DDS mkdir build && cd build cmake \ + -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCOMPILE_TOOLS=OFF \ -DCMAKE_CXX_FLAGS="-DUSE_FOONATHAN_NODE_SIZES=1" \