diff --git a/CHANGELOG.md b/CHANGELOG.md index 218bb1f8..c18df677 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Change Log +## v1.1.1 (2024-02-12) + +Bug fixes: + +- Fixed possible segfaults at startup triggered by bad configuration. +- Fixed periodic upload trigger for heartbeat campaigns, that previously was only triggered by + further data reception. + +Improvements: + +- Improve error output for bad configuration, to indicate where an option is missing or incorrect. +- Upgraded GitHub actions to support Node v20, as Node v16 is now EOL. +- Fixed some Coverity check regressions. +- Removed unsupported 'Geohash' feature. +- Corrected cleanup instructions in guides. +- Build Boost from source with `-fPIC` to enable linkage in a shared library. + ## v1.1.0 (2023-11-26) Features: diff --git a/CMakeLists.txt b/CMakeLists.txt index 02702190..1f6c041f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10.2) -project(iotfleetwise VERSION 1.1.0) +project(iotfleetwise VERSION 1.1.1) # FWE uses C++14 for compatibility reasons with Automotive middlewares (Adaptive AUTOSAR, ROS2) # Note: When built with FWE_FEATURE_ROS2, colcon will override these settings @@ -25,10 +25,10 @@ option(FWE_SECURITY_COMPILE_FLAGS "Add security related compile options" OFF) option(FWE_AWS_SDK_SHARED_LIBS "Use AWS SDK shared libs. Needs to be set to the same value of BUILD_SHARED_LIBS that the SDK was compiled with." OFF) option(FWE_AWS_SDK_EXTRA_LIBS "Extra libs required to link with the AWS SDK. When FWE_STATIC_LINK is ON, setting this to ON will automatically find the standard libs. Can be a space-separated list of libs." ON) option(FWE_FEATURE_GREENGRASSV2 "Enable Greengrass connection module" OFF) -option(FWE_FEATURE_CUSTOM_DATA_SOURCE "Include the custom data source interface" OFF) -option(FWE_FEATURE_IWAVE_GPS "Include the IWave GPS example for a custom data source" OFF) -option(FWE_FEATURE_EXTERNAL_GPS "Include the external GPS example for a custom data source" OFF) -option(FWE_FEATURE_AAOS_VHAL "Include the Android Automotive VHAL example for a custom data source" OFF) +option(FWE_FEATURE_CUSTOM_DATA_SOURCE "Include the custom data source interface, which uses CAN signals to model arbitary signal sources" OFF) +option(FWE_FEATURE_IWAVE_GPS "Include the IWave GPS example for a custom data source (implies FWE_FEATURE_CUSTOM_DATA_SOURCE)" OFF) +option(FWE_FEATURE_EXTERNAL_GPS "Include the external GPS example for a custom data source (implies FWE_FEATURE_CUSTOM_DATA_SOURCE)" OFF) +option(FWE_FEATURE_AAOS_VHAL "Include the Android Automotive VHAL example for a custom data source (implies FWE_FEATURE_CUSTOM_DATA_SOURCE)" OFF) option(FWE_FEATURE_VISION_SYSTEM_DATA "Include support for vision-system-data sources" OFF) option(FWE_FEATURE_ROS2 "Include support for ROS2 as a vision-system-data source. Implies FWE_FEATURE_VISION_SYSTEM_DATA." OFF) option(FWE_BUILD_EXECUTABLE "Build the executable, otherwise build a library" ON) @@ -95,13 +95,14 @@ configure_file(src/IoTFleetWiseVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/IoTFle # Protobuf find_package(Protobuf REQUIRED) -protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS +set(PROTO_FILES interfaces/protobuf/schemas/cloudToEdge/common_types.proto interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto interfaces/protobuf/schemas/cloudToEdge/decoder_manifest.proto interfaces/protobuf/schemas/edgeToCloud/checkin.proto interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto ) +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) add_library(fwe-proto OBJECT ${PROTO_SRCS} ${PROTO_HDRS} @@ -131,11 +132,9 @@ set(HEADER_FILES src/CollectionInspectionWorkerThread.h src/CollectionSchemeIngestion.h src/CollectionSchemeIngestionList.h - src/CollectionSchemeManagementListener.h src/CollectionSchemeManager.h src/ConsoleLogger.h src/CPUUsageInfo.h - src/DataReduction.h src/DataSenderManager.h src/DataSenderManagerWorkerThread.h src/DataSenderProtoWriter.h @@ -143,23 +142,15 @@ set(HEADER_FILES src/EnumUtility.h src/EventTypes.h src/ExternalCANDataSource.h - src/GeohashFunctionNode.h - src/Geohash.h - src/GeohashInfo.h - src/IActiveCollectionSchemesListener.h - src/IActiveConditionProcessor.h - src/IActiveDecoderDictionaryListener.h src/ICollectionScheme.h src/ICollectionSchemeList.h src/ICollectionSchemeManager.h src/IConnectionTypes.h src/IConnectivityChannel.h src/IConnectivityModule.h - src/IDataReadyToPublishListener.h src/IDecoderDictionary.h src/IDecoderManifest.h src/ILogger.h - src/InspectionEventListener.h src/IoTFleetWiseConfig.h src/IoTFleetWiseEngine.h src/IoTFleetWiseVersion.h @@ -219,8 +210,6 @@ set(SRC_FILES src/DecoderDictionaryExtractor.cpp src/DecoderManifestIngestion.cpp src/ExternalCANDataSource.cpp - src/Geohash.cpp - src/GeohashFunctionNode.cpp src/InspectionMatrixExtractor.cpp src/IoTFleetWiseConfig.cpp src/IoTFleetWiseEngine.cpp @@ -260,8 +249,6 @@ set(TEST_FILES test/unit/DataSenderProtoWriterTest.cpp test/unit/DecoderDictionaryExtractorTest.cpp test/unit/ExternalCANDataSourceTest.cpp - test/unit/GeohashFunctionNodeTest.cpp - test/unit/GeohashTest.cpp test/unit/InspectionMatrixExtractorTest.cpp test/unit/IoTFleetWiseConfigTest.cpp test/unit/IoTFleetWiseEngineTest.cpp @@ -564,6 +551,7 @@ if(${BUILD_TESTING}) src/ClockHandler.cpp src/RawDataManager.cpp src/ConsoleLogger.cpp + src/IoTFleetWiseConfig.cpp test/unit/support/main.cpp ) target_include_directories(ROS2DataSourceTest PUBLIC diff --git a/README.md b/README.md index 7158ed4a..93893d7a 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ information. - [GoogleTest: v1.10.0](https://github.com/google/googletest) - [Google Benchmark: v1.6.1](https://github.com/google/benchmark) - [Protobuf: v3.21.12](https://github.com/protocolbuffers/protobuf) -- [Boost: v1.71.1](https://github.com/boostorg/boost) +- [Boost: v1.78.0](https://github.com/boostorg/boost) - [JsonCpp: v1.9.5](https://github.com/open-source-parsers/jsoncpp) - [Snappy: v1.1.8](https://github.com/google/snappy) diff --git a/THIRD-PARTY-LICENSES b/THIRD-PARTY-LICENSES index 4586e79f..fbcd16e9 100644 --- a/THIRD-PARTY-LICENSES +++ b/THIRD-PARTY-LICENSES @@ -248,7 +248,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------- -** Boost: v1.71.1 - https://github.com/boostorg/boost +** Boost: v1.78.0 - https://github.com/boostorg/boost Boost Software License - Version 1.0 - August 17th, 2003 diff --git a/cmake/doxygen.cmake b/cmake/doxygen.cmake index dcf10ebe..c041bb71 100644 --- a/cmake/doxygen.cmake +++ b/cmake/doxygen.cmake @@ -29,6 +29,7 @@ if(DOXYGEN_FOUND) set(DOXYGEN_TOC_INCLUDE_HEADINGS 5) set(DOXYGEN_UML_LOOK YES) set(DOXYGEN_EXCLUDE_PATTERNS "*.md") + set(DOXYGEN_DOT_GRAPH_MAX_NODES 100) foreach(directive FWE_FEATURE_VISION_SYSTEM_DATA FWE_FEATURE_ROS2) if(${directive}) diff --git a/configuration/static-config.json b/configuration/static-config.json index 6fe6c28f..cf8eaf87 100644 --- a/configuration/static-config.json +++ b/configuration/static-config.json @@ -41,7 +41,6 @@ "internalParameters": { "readyToPublishDataBufferSize": 10000, "systemWideLogLevel": "Trace", - "dataReductionProbabilityDisabled": false, "maximumAwsSdkHeapMemoryBytes": 10000000 }, "publishToCloudParameters": { diff --git a/docs/custom-data-source.md b/docs/custom-data-source.md index 4947f9b8..90708ad5 100644 --- a/docs/custom-data-source.md +++ b/docs/custom-data-source.md @@ -84,12 +84,11 @@ if(mIWaveGpsSource->init( mIWaveGpsSource->connect() ) { - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mIWaveGpsSource.get() ) ) ) - { - FWE_LOG_ERROR(" Failed to register the IWaveGps to the CollectionScheme Manager"); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &IWaveGpsSource::onChangeOfActiveDictionary, + mIWaveGpsSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); mIWaveGpsSource->start(); } ``` 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 bd581533..0c16b18c 100644 --- a/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md +++ b/docs/dev-guide/edge-agent-dev-guide-nxp-s32g.md @@ -167,14 +167,17 @@ mkdir -p ~/aws-iot-fleetwise-deploy \ ## Clean up -Run the following _on the development machine_ to clean up resources created by the `provision.sh` -and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. +1. Run the following _on the development machine_ to clean up resources created by the + `provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo-s32g \ - --region us-east-1 \ - --only-clean-up -``` + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh \ + && ../provision.sh \ + --vehicle-name fwdemo-s32g \ + --region us-east-1 \ + --only-clean-up + ``` + +1. Delete the CloudFormation stack for your development machine, which by default is called `fwdev`: + https://us-east-1.console.aws.amazon.com/cloudformation/home 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 f466fc5d..b66a3add 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 @@ -183,14 +183,17 @@ mkdir -p ~/aws-iot-fleetwise-deploy \ ## Clean up -Run the following _on the development machine_ to clean up resources created by the `provision.sh` -and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. +1. Run the following _on the development machine_ to clean up resources created by the + `provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo-rcars4 \ - --region us-east-1 \ - --only-clean-up -``` + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh \ + && ../provision.sh \ + --vehicle-name fwdemo-rcars4 \ + --region us-east-1 \ + --only-clean-up + ``` + +1. Delete the CloudFormation stack for your development machine, which by default is called `fwdev`: + https://us-east-1.console.aws.amazon.com/cloudformation/home diff --git a/docs/dev-guide/edge-agent-dev-guide.md b/docs/dev-guide/edge-agent-dev-guide.md index 9f18deb8..877aa75a 100644 --- a/docs/dev-guide/edge-agent-dev-guide.md +++ b/docs/dev-guide/edge-agent-dev-guide.md @@ -228,18 +228,16 @@ collect data from it. ## Clean up resources -Copy and paste the following commands to AWS CloudShell to clean up resources created by the -`provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream and S3 resources are not -deleted. - -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo \ - --region us-east-1 \ - --only-clean-up -``` +1. Copy and paste the following commands to AWS CloudShell to clean up resources created by the + `demo.sh` script. **Note:** The Amazon Timestream and S3 resources are not deleted. + + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh + ``` + +1. Delete the CloudFormation stack created earlier, which by default is called `fwdemo`: + https://us-east-1.console.aws.amazon.com/cloudformation/home # Getting started guide @@ -541,17 +539,21 @@ collect data from it. ### Clean up -Run the following _on the development machine_ to clean up resources created by the `provision.sh` -and `demo.sh` scripts. **Note:** The Amazon Timestream and S3 resources are not deleted. +1. Run the following _on the development machine_ to clean up resources created by the + `provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream and S3 resources are not + deleted. -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo-ec2 \ - --region us-east-1 \ - --only-clean-up -``` + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh \ + && ../provision.sh \ + --vehicle-name fwdemo-ec2 \ + --region us-east-1 \ + --only-clean-up + ``` + +1. Delete the CloudFormation stack for your development machine, which by default is called `fwdev`: + https://us-east-1.console.aws.amazon.com/cloudformation/home ## Getting started on a NXP S32G board @@ -777,7 +779,6 @@ DataSenderManagerWorkerThread DataSenderProtoWriter DecoderDictionaryExtractor DecoderManifestIngestion -Geohash InspectionMatrixExtractor OBDDataDecoder RawDataManager @@ -815,7 +816,6 @@ CANDataSource CollectionInspectionEngine CollectionInspectionWorkerThread ExternalCANDataSource -GeohashFunctionNode OBDOverCANECU OBDOverCANModule ROS2DataSource @@ -929,46 +929,43 @@ FWE implements a concurrent and event-based multithreading system. ## Data Models -FWE defines four schemas that describe the communication with the Cloud Control and Data Plane -services. +FWE defines schemas that describe the communication with the Cloud Control and Data Plane services. -All the payloads exchanged between FWE and the cloud services are serialized in a Protobuff format. +All the payloads exchanged between FWE and the cloud services are serialized in a Protobuf format. ### Device to Cloud communication -FWE sends two artifacts with the Cloud services: - -**Check-in Information** +FWE sends the following artifacts to the Cloud services: -This check-in information consists of data collection schemes and decoder manifest Amazon Resource -Name (ARN) that are active in FWE at a given time point. This check-in message is send regularly at -a configurable frequency to the cloud services. Refer to -[checkin.proto](../../interfaces/protobuf/schemas/edgeToCloud/checkin.proto). +- **Check-in Information:** This check-in information consists of data collection schemes and + decoder manifest Amazon Resource Name (ARN) that are active in FWE at a given time point. This + check-in message is send regularly at a configurable frequency to the cloud services. Refer to + [checkin.proto](../../interfaces/protobuf/schemas/edgeToCloud/checkin.proto). -**Data Snapshot Information** +- **Data Snapshot Information** -**_Telemetry Data_** This message is sent conditionally to the cloud data plane services once one or -more inspection rule is met. For telemetry data such as CAN data, FWE sends it in an MQTT packet to -the cloud. Refer to -[vehicle_data.proto](../../interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto). + - **Telemetry Data:** This message is sent conditionally to the cloud data plane services once one + or more inspection rule is met. For telemetry data such as CAN data, FWE sends it in an MQTT + packet to the cloud. Refer to + [vehicle_data.proto](../../interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto). -**_Vision System Data_** In Vision System data use case, FWE serializes each ROS2 message into CDR -format and packed them in Amazon ION file format and directly upload to S3. Refer to -[vision_system_data.isl](../../interfaces/protobuf/schemas/edgeToCloud/vision_system_data.isl). + - **Vision System Data:** In Vision System data use case, FWE serializes each ROS2 message into + CDR format and packed them in Amazon ION file format and directly upload to S3. Refer to + [vision_system_data.isl](../../interfaces/protobuf/schemas/edgeToCloud/vision_system_data.isl). ### Cloud to Device communication -The Cloud Control plane services publish to FWE dedicated MQTT Topic the following two artifacts: +The Cloud Control plane services publish to FWE dedicated MQTT Topic the following artifacts: -**Decoder Manifest:** This artifact describes the Vehicle Network Interfaces that the user defined. -The description includes the semantics of each of the Network interface traffic to be inspected -including the signal decoding rules. Refer to -[decoder_manifest.proto](../../interfaces/protobuf/schemas/cloudToEdge/decoder_manifest.proto). +- **Decoder Manifest:** This artifact describes the Vehicle Network Interfaces that the user + defined. The description includes the semantics of each of the Network interface traffic to be + inspected including the signal decoding rules. Refer to + [decoder_manifest.proto](../../interfaces/protobuf/schemas/cloudToEdge/decoder_manifest.proto). -**Collection Scheme:** This artifact describes effectively the inspection rules, that FWE will apply -on the network traffic it receives. Using the decoder manifest, the Inspection module will apply the -rules defined in the collection schemes to generate data snapshots. Refer to -[collection_schemes.proto](../../interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto). +- **Collection Scheme:** This artifact describes effectively the inspection rules, that FWE will + apply on the network traffic it receives. Using the decoder manifest, the Inspection module will + apply the rules defined in the collection schemes to generate data snapshots. Refer to + [collection_schemes.proto](../../interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto). ## Data Persistency @@ -1063,7 +1060,6 @@ described below in the configuration section. Each log entry includes the follow | | systemWideLogLevel | Sets logging level severity: `Trace`, `Info`, `Warning`, `Error` | string | | | logColor | Whether logs should be colored: `Auto`, `Yes`, `No`. Default to `Auto`, meaning FWE will try to detect whether colored output is supported (for example when connected to a tty) | string | | | maximumAwsSdkHeapMemoryBytes | The maximum size of AWS SDK heap memory | integer | -| | 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 | | | collectionSchemeManagementCheckinIntervalMs | Time interval between collection schemes checkins(in milliseconds) | integer | diff --git a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md index 5c7a411a..6c26d9e0 100644 --- a/docs/iwave-g26-tutorial/iwave-g26-tutorial.md +++ b/docs/iwave-g26-tutorial/iwave-g26-tutorial.md @@ -547,14 +547,17 @@ mkdir -p ~/aws-iot-fleetwise-deploy \ ## Step 8: Clean up -Run the following to clean up resources created by the `provision.sh` and `demo.sh` scripts. -**Note:** The Amazon Timestream resources are not deleted. +1. Run the following _on the development machine_ to clean up resources created by the + `provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo-g26 \ - --region us-east-1 \ - --only-clean-up -``` + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh \ + && ../provision.sh \ + --vehicle-name fwdemo-g26 \ + --region us-east-1 \ + --only-clean-up + ``` + +1. Delete the CloudFormation stack for your development machine, which by default is called `fwdev`: + https://us-east-1.console.aws.amazon.com/cloudformation/home diff --git a/docs/iwave-g26-tutorial/iwave-gps-setup.md b/docs/iwave-g26-tutorial/iwave-gps-setup.md index ee801ade..dc74e5f9 100644 --- a/docs/iwave-g26-tutorial/iwave-gps-setup.md +++ b/docs/iwave-g26-tutorial/iwave-gps-setup.md @@ -31,7 +31,7 @@ compile using `make` as usual. Like CAN if data is sent to cloud you should see this: ``` -[INFO ] [IoTFleetWiseEngine.cpp:914] [doWork()]: [FWE data ready to send with eventID 1644139266 from arn:aws:iotfleetwise:us-east-1:xxxxxxxxxxxx:campaign/IWaveGpsCampaign Signals:70 [2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196, ...] first signal timestamp: 1666881551998 raw CAN frames:0 DTCs:0 Geohash:] +[INFO ] [IoTFleetWiseEngine.cpp:914] [doWork()]: [FWE data ready to send with eventID 1644139266 from arn:aws:iotfleetwise:us-east-1:xxxxxxxxxxxx:campaign/IWaveGpsCampaign Signals:70 [2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196,2514:13.393196, ...] first signal timestamp: 1666881551998 raw CAN frames:0 DTCs:0] ``` If the GPS NMEA output it working but gps fix is available you should move to an area with a open diff --git a/docs/rpi-tutorial/raspberry-pi-tutorial.md b/docs/rpi-tutorial/raspberry-pi-tutorial.md index 4a5bf357..a3b7fa39 100644 --- a/docs/rpi-tutorial/raspberry-pi-tutorial.md +++ b/docs/rpi-tutorial/raspberry-pi-tutorial.md @@ -333,14 +333,17 @@ mkdir -p ~/aws-iot-fleetwise-deploy \ ## Step 7: Clean up -Run the following to clean up resources created by the `provision.sh` and `demo.sh` scripts. -**Note:** The Amazon Timestream resources are not deleted. +1. Run the following _on the development machine_ to clean up resources created by the + `provision.sh` and `demo.sh` scripts. **Note:** The Amazon Timestream resources are not deleted. -```bash -cd ~/aws-iot-fleetwise-edge/tools/cloud \ -&& clean-up.sh \ -&& ../provision.sh \ - --vehicle-name fwdemo-rpi \ - --region us-east-1 \ - --only-clean-up -``` + ```bash + cd ~/aws-iot-fleetwise-edge/tools/cloud \ + && ./clean-up.sh \ + && ../provision.sh \ + --vehicle-name fwdemo-rpi \ + --region us-east-1 \ + --only-clean-up + ``` + +1. Delete the CloudFormation stack for your development machine, which by default is called `fwdev`: + https://us-east-1.console.aws.amazon.com/cloudformation/home diff --git a/interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto b/interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto index fbd7a786..4b4fe469 100644 --- a/interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto +++ b/interfaces/protobuf/schemas/cloudToEdge/collection_schemes.proto @@ -103,9 +103,10 @@ message CollectionScheme { uint32 priority = 13; /* - * An optional probabilities message indicating the probability that a CollectionScheme be enacted. + * This field was never supported, so it should not be used any more. */ - Probabilities probabilities = 14; + reserved 14; + reserved "probabilities"; /* * This field was never supported, so it should not be used any more. @@ -142,14 +143,6 @@ message S3UploadMetadata { string bucket_owner_account_id = 4; } -message Probabilities { - /* - * Double between 0 and 1 giving the probability after a condition is met. - * 0: never send, 1: send always. It is usable for both condition and time based collectionSchemes. - */ - double probability_to_send = 1; -} - /* * Contains time based specific attributes necessary for time based collectionSchemes such as a heartbeat. */ diff --git a/interfaces/protobuf/schemas/cloudToEdge/common_types.proto b/interfaces/protobuf/schemas/cloudToEdge/common_types.proto index 3d4f505f..7bab1927 100644 --- a/interfaces/protobuf/schemas/cloudToEdge/common_types.proto +++ b/interfaces/protobuf/schemas/cloudToEdge/common_types.proto @@ -134,6 +134,11 @@ message ConditionNode { * output based on specific logic */ message NodeFunction{ + /* + * This field was never supported, so it should not be used any more. + */ + reserved 2; + reserved "geohash_function"; /* * The function node could be one of the following function types. @@ -145,54 +150,6 @@ message ConditionNode { * run an aggregation function over the samples and evaluate to a double. */ WindowFunction window_function = 1; - - /* - * Geohash function Node that evaluates whether Edge has changed Geohash. It returns true if the Geohash - * has changed at given precision and otherwise return false - */ - GeohashFunction geohash_function = 2; - } - - /* - * Geohash function evaluates whether Edge has changed Geohash at given precision - * It will firstly calculate Geohash with latitude and longitude - * It returns true if the Geohash has changed at given precision. Otherwise return false - */ - message GeohashFunction{ - - /* - * signal id for latitude - */ - uint32 latitude_signal_id = 1; - - /* - * signal id for longitude - */ - uint32 longitude_signal_id = 2; - - /* - * The geohash precision for dynamic data collection Note geohash precision is defined as the length of hash - * characters (base 32 encoding). Longer hash will have higher precision than shorter hash. - * see more details: https://en.wikipedia.org/wiki/Geohash - */ - uint32 geohash_precision = 3; - - /* - * The unit for decoded latitude / longitude signal. GPS Signal might be decoded into different unit - * according to the DBC file. - */ - GPSUnitType gps_unit = 4; - - /* - * The unit type for decoded latitude / longitude signal. This list might be extended in future to - * accommodate different vehicle models. - */ - enum GPSUnitType { - DECIMAL_DEGREE = 0; - MICROARCSECOND = 1; - MILLIARCSECOND = 2; - ARCSECOND = 3; - } } /* diff --git a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json index c618b126..27474608 100644 --- a/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json +++ b/interfaces/protobuf/schemas/edgeConfiguration/staticConfiguration.json @@ -45,7 +45,7 @@ }, "interfaceId": { "type": "string", - "description": "Every CAN/OBD signal decoder is associated with a signal/OBD network interface using a unique Id" + "description": "Every network interface is associated with a unique ID that must match the interface ID sent by the cloud in the decoder manifest" }, "type": { "type": "string", @@ -93,7 +93,7 @@ }, "interfaceId": { "type": "string", - "description": "Every CAN/OBD signal decoder is associated with a signal/OBD network interface using a unique Id" + "description": "Every network interface is associated with a unique ID that must match the interface ID sent by the cloud in the decoder manifest" }, "type": { "type": "string", @@ -132,7 +132,7 @@ }, "interfaceId": { "type": "string", - "description": "Every CAN/OBD/ROS signal decoder is associated with a network interface using a unique Id. This must match the interface Id configured in the cloud" + "description": "Every network interface is associated with a unique ID that must match the interface ID sent by the cloud in the decoder manifest" }, "type": { "type": "string", @@ -227,10 +227,6 @@ "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" - }, "metricsCyclicPrintIntervalMs": { "type": "string", "description": "Sets the interval in milliseconds how often the application metrics should be printed to stdout. Default 0 means never" @@ -240,11 +236,7 @@ "description": "Set the maximum AWS SDK heap memory bytes. Default to 10000000" } }, - "required": [ - "readyToPublishDataBufferSize", - "systemWideLogLevel", - "dataReductionProbabilityDisabled" - ] + "required": ["readyToPublishDataBufferSize", "systemWideLogLevel"] }, "publishToCloudParameters": { "type": "object", diff --git a/interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto b/interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto index d2933a5c..4facc90e 100644 --- a/interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto +++ b/interfaces/protobuf/schemas/edgeToCloud/vehicle_data.proto @@ -48,9 +48,10 @@ message VehicleData { repeated CanFrame can_frames = 7; /* - * Captured Geohash which reflect which geohash tile the vehicle is currently located. + * This field was never supported, so it should not be used any more. */ - Geohash geohash = 8; + reserved 8; + reserved "geohash"; /* * Files that were uploaded to S3. @@ -147,20 +148,6 @@ message DtcData { repeated string active_dtc_codes = 2; } -message Geohash { - - /* - * Geohash in string format. It's encoded in base 32 format. The maximum resolution of geohash is used and the string is always 9 characters long. - */ - string geohash_string = 1; - - /* - * Previous Geohash in string format encoded in base 32 format. The maximum resolution of geohash is used and the - * string is always 9 characters long. - */ - string prev_reported_geohash_string = 2; -} - message S3Object { /* diff --git a/src/Assert.h b/src/Assert.h index ca4eeba7..d41ce02e 100644 --- a/src/Assert.h +++ b/src/Assert.h @@ -8,12 +8,6 @@ #include #include -namespace Aws -{ - -namespace IoTFleetWise -{ - #define FWE_FATAL_ASSERT( cond, msg ) \ do \ { \ @@ -38,6 +32,3 @@ namespace IoTFleetWise return returnValue; \ } \ } while ( 0 ) - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/AwsGGChannel.cpp b/src/AwsGGChannel.cpp index 00900d40..6cef70f2 100644 --- a/src/AwsGGChannel.cpp +++ b/src/AwsGGChannel.cpp @@ -7,14 +7,70 @@ #include "IConnectivityModule.h" #include "IReceiver.h" #include "LoggingModule.h" +#include "TimeTypes.h" +#include +#include #include #include +#include +#include namespace Aws { namespace IoTFleetWise { +// coverity[autosar_cpp14_a0_1_3_violation] false positive - function overrides sdk's virtual function. +void +SubscribeStreamHandler::OnStreamEvent( Aws::Greengrass::IoTCoreMessage *response ) +{ + auto message = response->GetMessage(); + + if ( message.has_value() && message.value().GetPayload().has_value() ) + { + Timestamp currentTime = mClock->monotonicTimeSinceEpochMs(); + + auto payloadBytes = message.value().GetPayload().value(); + std::string payloadString( payloadBytes.begin(), payloadBytes.end() ); + std::unordered_map properties; + auto messageUserProperties = message.value().GetUserProperties(); + if ( messageUserProperties.has_value() ) + { + for ( auto &property : messageUserProperties.value() ) + { + std::string name; + std::string value; + if ( property.GetKey().has_value() ) + { + auto propertyKey = property.GetKey().value(); + name = std::string( propertyKey.begin(), propertyKey.end() ); + } + if ( property.GetValue().has_value() ) + { + auto propertyValue = property.GetValue().value(); + value = std::string( propertyValue.begin(), propertyValue.end() ); + } + + if ( !properties.emplace( name, value ).second ) + { + FWE_LOG_WARN( "Duplicate property name '" + name + "', first value will be kept" ); + } + } + } + + auto messageExpiryIntervalSec = message.value().GetMessageExpiryIntervalSeconds(); + Timestamp messageExpiryMonotonicTimeSinceEpochMs = 0; + if ( messageExpiryIntervalSec.has_value() ) + { + // convert seconds to milliseconds and calculate absolute message expiry time + messageExpiryMonotonicTimeSinceEpochMs = + currentTime + static_cast( messageExpiryIntervalSec.value() ) * 1000; + } + mCallback( ReceivedChannelMessage{ + payloadBytes.data(), payloadBytes.size(), properties, messageExpiryMonotonicTimeSinceEpochMs } ); + } +} + AwsGGChannel::AwsGGChannel( IConnectivityModule *connectivityModule, std::shared_ptr payloadManager, std::shared_ptr &ggConnection, @@ -61,9 +117,10 @@ AwsGGChannel::subscribe() return ConnectivityError::NoConnection; } - mSubscribeStreamHandler = std::make_shared( [&]( uint8_t *data, size_t size ) { - notifyListeners( &IReceiverCallback::onDataReceived, data, size ); - } ); + mSubscribeStreamHandler = + std::make_shared( [&]( const ReceivedChannelMessage &receivedChannelMessage ) { + mListeners.notify( receivedChannelMessage ); + } ); if ( mConnection == nullptr ) { @@ -383,6 +440,12 @@ AwsGGChannel::sendFile( const std::string &filePath, size_t size, CollectionSche return ConnectivityError::Success; } +void +AwsGGChannel::subscribeToDataReceived( OnDataReceivedCallback callback ) +{ + mListeners.subscribe( callback ); +} + bool AwsGGChannel::unsubscribe() { diff --git a/src/AwsGGChannel.h b/src/AwsGGChannel.h index bb40d35a..a55c5315 100644 --- a/src/AwsGGChannel.h +++ b/src/AwsGGChannel.h @@ -3,14 +3,16 @@ #pragma once +#include "Clock.h" +#include "ClockHandler.h" #include "IConnectionTypes.h" #include "IConnectivityChannel.h" #include "IConnectivityModule.h" +#include "IReceiver.h" #include "ISender.h" +#include "Listener.h" #include "PayloadManager.h" #include -#include -#include #include #include #include @@ -19,14 +21,13 @@ #include #include #include -#include namespace Aws { namespace IoTFleetWise { -using SubscribeCallback = std::function; +using SubscribeCallback = std::function; class SubscribeStreamHandler : public Aws::Greengrass::SubscribeToIoTCoreStreamHandler { @@ -39,19 +40,14 @@ class SubscribeStreamHandler : public Aws::Greengrass::SubscribeToIoTCoreStreamH private: // coverity[autosar_cpp14_a0_1_3_violation] false positive - function overrides sdk's virtual function. - void - OnStreamEvent( Aws::Greengrass::IoTCoreMessage *response ) override - { - auto message = response->GetMessage(); - - if ( message.has_value() && message.value().GetPayload().has_value() ) - { - auto payloadBytes = message.value().GetPayload().value(); - std::string payloadString( payloadBytes.begin(), payloadBytes.end() ); - mCallback( payloadBytes.data(), payloadBytes.size() ); - } - }; + void OnStreamEvent( Aws::Greengrass::IoTCoreMessage *response ) override; + SubscribeCallback mCallback; + + /** + * @brief Clock member variable used to generate the time an MQTT message was received + */ + std::shared_ptr mClock = ClockHandler::getClock(); }; /** @@ -107,6 +103,8 @@ class AwsGGChannel : public IConnectivityChannel size_t size, CollectionSchemeParams collectionSchemeParams = CollectionSchemeParams() ) override; + void subscribeToDataReceived( OnDataReceivedCallback callback ) override; + void invalidateConnection() { @@ -144,6 +142,7 @@ class AwsGGChannel : public IConnectivityChannel */ static const size_t AWS_IOT_MAX_MESSAGE_SIZE = 131072; // = 128 KiB IConnectivityModule *mConnectivityModule; + ThreadSafeListeners mListeners; std::mutex mConnectivityMutex; std::mutex mConnectivityLambdaMutex; diff --git a/src/AwsIotChannel.cpp b/src/AwsIotChannel.cpp index 43ae8b5b..70398351 100644 --- a/src/AwsIotChannel.cpp +++ b/src/AwsIotChannel.cpp @@ -6,6 +6,7 @@ #include "CacheAndPersist.h" #include "IConnectivityModule.h" #include "LoggingModule.h" +#include "TimeTypes.h" #include "TraceModule.h" #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -274,6 +276,51 @@ AwsIotChannel::sendFile( const std::string &filePath, size_t size, CollectionSch return ConnectivityError::Success; } +void +AwsIotChannel::subscribeToDataReceived( OnDataReceivedCallback callback ) +{ + mListeners.subscribe( callback ); +} + +void +AwsIotChannel::onDataReceived( const Aws::Crt::Mqtt5::PublishReceivedEventData &eventData ) +{ + Timestamp currentTime = mClock->monotonicTimeSinceEpochMs(); + + std::unordered_map properties; + + auto correlationData = eventData.publishPacket->getCorrelationData(); + if ( correlationData.has_value() ) + { + // coverity[cert_str51_cpp_violation] correlationData->ptr is not null, checked before + properties[PROPERTY_NAME_CORRELATION_DATA] = + std::string( correlationData->ptr, correlationData->ptr + correlationData->len ); + } + + auto messageExpiryIntervalSec = eventData.publishPacket->getMessageExpiryIntervalSec(); + Timestamp messageExpiryMonotonicTimeSinceEpochMs = 0; + if ( messageExpiryIntervalSec.has_value() ) + { + // convert seconds to milliseconds and calculate absolute message expiry time + messageExpiryMonotonicTimeSinceEpochMs = currentTime + messageExpiryIntervalSec.value() * 1000; + } + + for ( auto property : eventData.publishPacket->getUserProperties() ) + { + auto name = std::string( property.getName().begin(), property.getName().end() ); + auto value = std::string( property.getValue().begin(), property.getValue().end() ); + if ( !properties.emplace( name, value ).second ) + { + FWE_LOG_WARN( "Duplicate property name '" + name + "', first value will be kept" ); + } + properties[name] = value; + } + mListeners.notify( ReceivedChannelMessage{ eventData.publishPacket->getPayload().ptr, + eventData.publishPacket->getPayload().len, + properties, + messageExpiryMonotonicTimeSinceEpochMs } ); +} + void AwsIotChannel::publishMessage( const uint8_t *buf, size_t size ) { @@ -307,23 +354,50 @@ AwsIotChannel::publishMessage( const uint8_t *buf, size_t size ) bool AwsIotChannel::unsubscribe() +{ + auto result = unsubscribeAsync(); + result.wait(); + return result.get(); +} + +std::future +AwsIotChannel::unsubscribeAsync() { std::lock_guard connectivityLock( mConnectivityMutex ); - if ( isAliveNotThreadSafe() ) + + // We can't move the promise into the lambda, because the lambda needs to be copyable. So we + // don't have much choice but use a shared pointer. + auto unsubscribeFinishedPromise = std::make_shared>(); + auto unsubscribeFuture = unsubscribeFinishedPromise->get_future(); + + if ( !isAliveNotThreadSafe() ) { - std::promise unsubscribeFinishedPromise; - FWE_LOG_TRACE( "Unsubscribing..." ); - auto unsubPacket = std::make_shared(); - // coverity[cert_str51_cpp_violation] - pointer comes from std::string, which can't be null - unsubPacket->WithTopicFilter( mTopicName.c_str() ); - mMqttClient->Unsubscribe( unsubPacket, [&]( int errorCode, std::shared_ptr unsubAckPacket ) { + unsubscribeFinishedPromise->set_value( false ); + return unsubscribeFuture; + } + + FWE_LOG_TRACE( "Unsubscribing..." ); + auto unsubPacket = std::make_shared(); + // coverity[cert_str51_cpp_violation] - pointer comes from std::string, which can't be null + unsubPacket->WithTopicFilter( mTopicName.c_str() ); + mMqttClient->Unsubscribe( + unsubPacket, + [this, unsubscribeFinishedPromise]( int errorCode, std::shared_ptr unsubAckPacket ) { if ( errorCode != 0 ) { - TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::SUBSCRIBE_ERROR ); auto errorString = Aws::Crt::ErrorDebugString( errorCode ); - FWE_LOG_ERROR( "Unsubscribe failed with error code " + std::to_string( errorCode ) + ": " + - std::string( errorString != nullptr ? errorString : "Unknown error" ) ); - unsubscribeFinishedPromise.set_value( false ); + std::string logMessage = "Unsubscribe failed with error code " + std::to_string( errorCode ) + ": " + + std::string( errorString != nullptr ? errorString : "Unknown error" ); + if ( errorCode == AWS_ERROR_MQTT5_USER_REQUESTED_STOP ) + { + FWE_LOG_TRACE( logMessage ); + } + else + { + TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::SUBSCRIBE_ERROR ); + FWE_LOG_ERROR( logMessage ); + } + unsubscribeFinishedPromise->set_value( false ); return; } @@ -340,23 +414,19 @@ AwsIotChannel::unsubscribe() TraceModule::get().incrementAtomicVariable( TraceAtomicVariable::SUBSCRIBE_ERROR ); FWE_LOG_ERROR( "Server rejected unsubscribe from topic " + mTopicName + ". Reason code " + std::to_string( reasonCode ) + ": " + reasonString ); - unsubscribeFinishedPromise.set_value( false ); - // Just return on the first error found. There could be multiple reason codes if we unsubscribe - // from multiple subscriptions at once, but we always request a single one. + unsubscribeFinishedPromise->set_value( false ); + // Just return on the first error found. There could be multiple reason codes if we + // unsubscribe from multiple subscriptions at once, but we always request a single one. return; } } } FWE_LOG_TRACE( "Unsubscribed from topic " + mTopicName ); mSubscribed = false; - unsubscribeFinishedPromise.set_value( true ); + unsubscribeFinishedPromise->set_value( true ); } ); - // Blocked call until subscribe finished this call should quickly either fail or succeed but - // depends on the network quality the Bootstrap needs to retry subscribing if failed. - unsubscribeFinishedPromise.get_future().wait(); - return true; - } - return false; + + return unsubscribeFuture; } AwsIotChannel::~AwsIotChannel() diff --git a/src/AwsIotChannel.h b/src/AwsIotChannel.h index 25014619..fcd0322e 100644 --- a/src/AwsIotChannel.h +++ b/src/AwsIotChannel.h @@ -3,15 +3,21 @@ #pragma once +#include "Clock.h" +#include "ClockHandler.h" #include "IConnectionTypes.h" #include "IConnectivityChannel.h" #include "IConnectivityModule.h" +#include "IReceiver.h" #include "ISender.h" +#include "Listener.h" #include "MqttClientWrapper.h" #include "PayloadManager.h" #include +#include #include #include +#include #include #include #include @@ -65,6 +71,12 @@ class AwsIotChannel : public IConnectivityChannel */ bool unsubscribe(); + /** + * @brief Unsubscribe from the MQTT topic asynchronously + * @return A future that can be used to wait for the unsubscribe to finish. It will return True on success. + */ + std::future unsubscribeAsync(); + bool isAlive() override; size_t getMaxSendSize() const override; @@ -77,6 +89,10 @@ class AwsIotChannel : public IConnectivityChannel size_t size, CollectionSchemeParams collectionSchemeParams = CollectionSchemeParams() ) override; + void subscribeToDataReceived( OnDataReceivedCallback callback ) override; + + void onDataReceived( const Aws::Crt::Mqtt5::PublishReceivedEventData &eventData ); + void invalidateConnection() { @@ -103,6 +119,8 @@ class AwsIotChannel : public IConnectivityChannel private: bool isAliveNotThreadSafe(); + + // coverity[autosar_cpp14_a0_1_3_violation] false positive - function is used bool isTopicValid() { @@ -117,6 +135,7 @@ class AwsIotChannel : public IConnectivityChannel */ static const size_t AWS_IOT_MAX_MESSAGE_SIZE = 131072; // = 128 KiB IConnectivityModule *mConnectivityModule; + ThreadSafeListeners mListeners; std::shared_ptr mPayloadManager; std::shared_ptr &mMqttClient; std::mutex mConnectivityMutex; @@ -125,6 +144,11 @@ class AwsIotChannel : public IConnectivityChannel std::atomic mSubscribed; std::atomic mPayloadCountSent{}; + /** + * @brief Clock member variable used to generate the time an MQTT message was received + */ + std::shared_ptr mClock = ClockHandler::getClock(); + bool mSubscription; }; diff --git a/src/AwsIotConnectivityModule.cpp b/src/AwsIotConnectivityModule.cpp index 2a5f7ce1..bd644063 100644 --- a/src/AwsIotConnectivityModule.cpp +++ b/src/AwsIotConnectivityModule.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #include "AwsIotConnectivityModule.h" -#include "IReceiver.h" #include "LoggingModule.h" #include "Thread.h" #include "TraceModule.h" @@ -13,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -37,6 +36,9 @@ constexpr uint16_t MQTT_CONNECT_KEEP_ALIVE_SECONDS = 60; constexpr uint32_t MQTT_PING_TIMEOUT_MS = 3000; constexpr uint32_t MQTT_SESSION_EXPIRY_INTERVAL_SEC = 3600; +// How much time to wait for a response to an unsubscribe operation when shutting the module down. +constexpr uint32_t MQTT_UNSUBSCRIBE_TIMEOUT_ON_SHUTDOWN_SEC = 5; + AwsIotConnectivityModule::AwsIotConnectivityModule( std::string rootCA, std::string clientId, std::shared_ptr mqttClientBuilder ) @@ -108,12 +110,32 @@ AwsIotConnectivityModule::resetConnection() bool AwsIotConnectivityModule::disconnect() { + // In case there is no connection or the connection is bad, we don't want to be waiting here for + // a long time. So we tell all channels to unsubscribe asynchronously, and then wait for them + // in a separate step. + std::vector>> unsubscribeResults; + { + std::lock_guard lock( mTopicToChannelMutex ); + for ( auto &topicAndChannel : mTopicToChannel ) + { + unsubscribeResults.emplace_back( topicAndChannel.first, topicAndChannel.second->unsubscribeAsync() ); + } + } + + auto timeout = std::chrono::steady_clock::now() + std::chrono::seconds( MQTT_UNSUBSCRIBE_TIMEOUT_ON_SHUTDOWN_SEC ); + for ( auto &topicAndResult : unsubscribeResults ) + { + if ( topicAndResult.second.wait_until( timeout ) == std::future_status::timeout ) + { + FWE_LOG_WARN( "Unsubscribe operation timed out for topic " + topicAndResult.first ); + } + } + + mRetryThread.stop(); for ( auto channel : mChannels ) { - channel->unsubscribe(); channel->invalidateConnection(); } - mRetryThread.stop(); return resetConnection(); } @@ -258,7 +280,11 @@ AwsIotConnectivityModule::createMqttConnection() std::shared_ptr channel; { std::lock_guard lock( mTopicToChannelMutex ); - channel = mTopicToChannel[topic]; + auto it = mTopicToChannel.find( topic ); + if ( it != mTopicToChannel.end() ) + { + channel = it->second; + } } if ( channel == nullptr ) @@ -267,14 +293,20 @@ AwsIotConnectivityModule::createMqttConnection() return; } - channel->notifyListeners( &IReceiverCallback::onDataReceived, - eventData.publishPacket->getPayload().ptr, - eventData.publishPacket->getPayload().len ); + channel->onDataReceived( eventData ); } ); TraceModule::get().sectionBegin( TraceSection::BUILD_MQTT ); mMqttClient = mMqttClientBuilder->Build(); TraceModule::get().sectionEnd( TraceSection::BUILD_MQTT ); + if ( !mMqttClient ) + { + int lastError = mMqttClientBuilder->LastError(); + auto errorString = Aws::Crt::ErrorDebugString( lastError ); + FWE_LOG_ERROR( "MQTT Client building failed with error code " + std::to_string( lastError ) + ": " + + std::string( errorString != nullptr ? errorString : "Unknown error" ) ); + return false; + } if ( !*mMqttClient ) { int lastError = mMqttClient->LastError(); diff --git a/src/CANDataSource.cpp b/src/CANDataSource.cpp index 1baa5de4..79e9ffdf 100644 --- a/src/CANDataSource.cpp +++ b/src/CANDataSource.cpp @@ -141,7 +141,7 @@ CANDataSource::extractTimestamp( struct msghdr *msgHeader ) } if ( timestamp == 0 ) // either other timestamp are invalid(=0) or mTimestampTypeToUse == POLLING_TIME { - TraceModule::get().incrementVariable( TraceVariable::CAN_POLLING_TIMESTAMP_COUNTER ); + TraceModule::get().incrementVariable( TraceVariable::POLLING_TIMESTAMP_COUNTER ); timestamp = mClock->systemTimeSinceEpochMs(); } return timestamp; diff --git a/src/CANDataSource.h b/src/CANDataSource.h index 1a80ca08..552406b4 100644 --- a/src/CANDataSource.h +++ b/src/CANDataSource.h @@ -6,7 +6,6 @@ #include "CANDataConsumer.h" #include "Clock.h" #include "ClockHandler.h" -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" #include "Signal.h" #include "SignalTypes.h" @@ -62,7 +61,7 @@ stringToCanTimestampType( std::string const ×tampType, CanTimestampType &ou * @brief Linux CAN Bus implementation. Uses Raw Sockets to listen to CAN * data on 1 single CAN IF. */ -class CANDataSource : public IActiveDecoderDictionaryListener +class CANDataSource { public: static constexpr int PARALLEL_RECEIVED_FRAMES_FROM_KERNEL = 10; @@ -85,7 +84,7 @@ class CANDataSource : public IActiveDecoderDictionaryListener bool forceCanFD, uint32_t threadIdleTimeMs, CANDataConsumer &consumer ); - ~CANDataSource() override; + ~CANDataSource(); CANDataSource( const CANDataSource & ) = delete; CANDataSource &operator=( const CANDataSource & ) = delete; @@ -100,7 +99,7 @@ class CANDataSource : public IActiveDecoderDictionaryListener bool isAlive(); void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); private: // Start the bus thread diff --git a/src/CANInterfaceIDTranslator.h b/src/CANInterfaceIDTranslator.h index 37c3527e..60608a8a 100644 --- a/src/CANInterfaceIDTranslator.h +++ b/src/CANInterfaceIDTranslator.h @@ -19,14 +19,14 @@ class CANInterfaceIDTranslator public: void - add( CANInterfaceID iid ) + add( InterfaceID iid ) { mLookup.emplace_back( mCounter, iid ); mCounter++; } CANChannelNumericID - getChannelNumericID( const CANInterfaceID &iid ) + getChannelNumericID( const InterfaceID &iid ) { for ( auto l : mLookup ) { @@ -38,7 +38,7 @@ class CANInterfaceIDTranslator return INVALID_CAN_SOURCE_NUMERIC_ID; }; - CANInterfaceID + InterfaceID getInterfaceID( CANChannelNumericID cid ) { for ( auto l : mLookup ) @@ -48,11 +48,11 @@ class CANInterfaceIDTranslator return l.second; } } - return INVALID_CAN_INTERFACE_ID; + return INVALID_INTERFACE_ID; }; private: - std::vector> mLookup; + std::vector> mLookup; CANChannelNumericID mCounter{ 0 }; }; diff --git a/src/CacheAndPersist.cpp b/src/CacheAndPersist.cpp index 08336130..a51320aa 100644 --- a/src/CacheAndPersist.cpp +++ b/src/CacheAndPersist.cpp @@ -148,6 +148,8 @@ CacheAndPersist::write( const uint8_t *bufPtr, size_t size, std::string &path ) } #ifdef FWE_FEATURE_VISION_SYSTEM_DATA +/// @cond Ignore due to Doxygen bug. Even though ENABLE_PREPROCESSING is enabled, Doxygen warns +// about this overload not being declared when FWE_FEATURE_VISION_SYSTEM_DATA is disabled. ErrorCode CacheAndPersist::write( std::unique_ptr streambuf, DataType dataType, const std::string &filename ) { @@ -200,6 +202,7 @@ CacheAndPersist::write( std::unique_ptr streambuf, DataType data return ErrorCode::SUCCESS; } +/// @endcond #endif void diff --git a/src/CollectionInspectionAPITypes.h b/src/CollectionInspectionAPITypes.h index e9b2cbb0..bf0dae99 100644 --- a/src/CollectionInspectionAPITypes.h +++ b/src/CollectionInspectionAPITypes.h @@ -5,7 +5,6 @@ #include "CANDataTypes.h" #include "EventTypes.h" -#include "GeohashInfo.h" #include "MessageTypes.h" #include "OBDDataTypes.h" #include "SignalTypes.h" @@ -27,8 +26,6 @@ static constexpr uint32_t MAX_EQUATION_DEPTH = static constexpr uint32_t MAX_DIFFERENT_SIGNAL_IDS = 50000; /**< Signal IDs can be distributed over the whole range but never more than 50.000 signals in parallel */ -static constexpr double MIN_PROBABILITY = 0.0; -static constexpr double MAX_PROBABILITY = 1.0; // INPUT to collection and inspection engine: // This values will be provided by CollectionSchemeManagement: @@ -76,7 +73,6 @@ struct ConditionWithCollectedData std::vector canFrames; bool includeActiveDtcs; bool triggerOnlyOnRisingEdge; - double probabilityToSend; PassThroughMetadata metadata; }; @@ -399,6 +395,7 @@ struct LockedQueue } return consumed; } + // coverity[misra_cpp_2008_rule_14_7_1_violation] Required in unit tests bool isEmpty() { @@ -428,8 +425,6 @@ struct TriggeredCollectionSchemeData std::vector uploadedS3Objects; #endif DTCInfo mDTCInfo; - GeohashInfo mGeohashInfo; // Because Geohash is not a physical signal from VSS, we decided to not using SignalID for - // geohash. In future we might introduce virtual signal concept which will include geohash. EventID eventID; }; diff --git a/src/CollectionInspectionEngine.cpp b/src/CollectionInspectionEngine.cpp index 2ad4dac1..0986fe39 100644 --- a/src/CollectionInspectionEngine.cpp +++ b/src/CollectionInspectionEngine.cpp @@ -31,11 +31,6 @@ CollectionInspectionEngine::isSignalPartOfEval( const ExpressionNode *expression { return expression->signalID == signalID; } - else if ( expression->nodeType == ExpressionNodeType::GEOHASHFUNCTION ) - { - 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 ); bool rightRet = isSignalPartOfEval( expression->right, signalID, remainingStackDepth - 1 ); @@ -109,7 +104,7 @@ CollectionInspectionEngine::onChangeInspectionMatrix( const std::shared_ptrmDTCInfo = mActiveDTCs; setActiveDTCsConsumed( conditionId, true ); } - // Pack geohash into data sender buffer if there's new geohash. - // A new geohash is generated during geohash function node evaluation - if ( mGeohashFunctionNode.hasNewGeohash() ) - { - mGeohashFunctionNode.consumeGeohash( collectedData->mGeohashInfo ); - } // Propagate the event ID collectedData->eventID = condition.mEventID; return std::const_pointer_cast( collectedData ); @@ -877,23 +866,17 @@ CollectionInspectionEngine::collectNextDataToSend( const TimePoint ¤tTime, condition.mLastTrigger.monotonicTimeMs + condition.mCondition.afterDuration ) ) { mConditionsNotTriggeredWaitingPublished.set( mNextConditionToCollectedIndex ); - // Send message out only with a certain probability. If probabilityToSend==0 - // no data is sent out - if ( mDataReduction.shallSendData( condition.mCondition.probabilityToSend ) ) - { - // Generate the Event ID and pack it into the active Condition - condition.mEventID = generateEventID( currentTime.systemTimeMs ); - // Return the collected data - InspectionTimestamp newestSignalTimeStamp = 0; - 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.monotonicTimeMs ); - // Increase index before returning from the function - mNextConditionToCollectedIndex++; - return cd; - } + // Generate the Event ID and pack it into the active Condition + condition.mEventID = generateEventID( currentTime.systemTimeMs ); + // Return the collected data + InspectionTimestamp newestSignalTimeStamp = 0; + 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.monotonicTimeMs ); + // Increase index before returning from the function + mNextConditionToCollectedIndex++; + return cd; } else { @@ -1126,34 +1109,6 @@ CollectionInspectionEngine::getSampleWindowFunction( WindowFunction function, } } -CollectionInspectionEngine::ExpressionErrorCode -CollectionInspectionEngine::getGeohashFunctionNode( const ExpressionNode *expression, - ActiveCondition &condition, - bool &resultValueBool ) -{ - resultValueBool = false; - // First we need to grab Latitude / longitude signal from collected signal buffer - InspectionValue latitude = 0; - auto status = getLatestSignalValue( expression->function.geohashFunction.latitudeSignalID, condition, latitude ); - if ( status != ExpressionErrorCode::SUCCESSFUL ) - { - FWE_LOG_WARN( "Unable to evaluate Geohash due to missing latitude signal" ); - return status; - } - InspectionValue longitude = 0; - status = getLatestSignalValue( expression->function.geohashFunction.longitudeSignalID, condition, longitude ); - if ( status != ExpressionErrorCode::SUCCESSFUL ) - { - FWE_LOG_WARN( "Unable to evaluate Geohash due to missing longitude signal" ); - return status; - } - resultValueBool = mGeohashFunctionNode.evaluateGeohash( latitude, - longitude, - expression->function.geohashFunction.precision, - expression->function.geohashFunction.gpsUnitType ); - return ExpressionErrorCode::SUCCESSFUL; -} - CollectionInspectionEngine::ExpressionErrorCode CollectionInspectionEngine::eval( const ExpressionNode *expression, ActiveCondition &condition, @@ -1185,10 +1140,6 @@ CollectionInspectionEngine::eval( const ExpressionNode *expression, return getSampleWindowFunction( expression->function.windowFunction, expression->signalID, condition, resultValueDouble ); } - if ( expression->nodeType == ExpressionNodeType::GEOHASHFUNCTION ) - { - return getGeohashFunctionNode( expression, condition, resultValueBool ); - } InspectionValue leftDouble = 0; InspectionValue rightDouble = 0; diff --git a/src/CollectionInspectionEngine.h b/src/CollectionInspectionEngine.h index 4cde3290..7fefd69a 100644 --- a/src/CollectionInspectionEngine.h +++ b/src/CollectionInspectionEngine.h @@ -5,12 +5,8 @@ #include "CANDataTypes.h" #include "CollectionInspectionAPITypes.h" -#include "DataReduction.h" #include "EventTypes.h" -#include "GeohashFunctionNode.h" #include "ICollectionScheme.h" -#include "InspectionEventListener.h" -#include "Listener.h" #include "LoggingModule.h" #include "MessageTypes.h" #include "OBDDataTypes.h" @@ -116,7 +112,7 @@ class NotifyRawBufferManager * are called only from one thread. This class will be instantiated and used from the Collection * Inspection Engine thread */ -class CollectionInspectionEngine : public ThreadListeners +class CollectionInspectionEngine { public: @@ -199,18 +195,6 @@ class CollectionInspectionEngine : public ThreadListeners &buffer, uint8_t size ); - /** - * @brief Copies the data reduction object over and applies it before handing out data - * - * After setting this depending on the parameters the number of data packages collected over - * collectNextDataToSend will go or down - */ - void - setDataReductionParameters( bool disableProbability ) - { - mDataReduction.setDisableProbability( disableProbability ); - }; - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA void setRawDataBufferManager( std::shared_ptr rawBufferManager ) @@ -584,9 +568,6 @@ class CollectionInspectionEngine : public ThreadListeners void collectLastSignals( InspectionSignalID id, uint32_t minimumSamplingInterval, @@ -716,7 +697,6 @@ class CollectionInspectionEngine : public ThreadListeners mConditionsWithInputSignalChanged; // bit is set if any signal or fixed window that this condition uses in its @@ -736,7 +716,6 @@ class CollectionInspectionEngine : public ThreadListeners mRawBufferManager{ nullptr }; diff --git a/src/CollectionInspectionWorkerThread.cpp b/src/CollectionInspectionWorkerThread.cpp index 2e9393ee..e2dbd00e 100644 --- a/src/CollectionInspectionWorkerThread.cpp +++ b/src/CollectionInspectionWorkerThread.cpp @@ -20,11 +20,12 @@ namespace IoTFleetWise bool CollectionInspectionWorkerThread::init( const std::shared_ptr &inputSignalBuffer, const std::shared_ptr &outputCollectedData, - uint32_t idleTimeMs, + uint32_t idleTimeMs #ifdef FWE_FEATURE_VISION_SYSTEM_DATA - std::shared_ptr rawBufferManager, + , + std::shared_ptr rawBufferManager #endif - bool dataReductionProbabilityDisabled ) +) { fInputSignalBuffer = inputSignalBuffer; fOutputCollectedData = outputCollectedData; @@ -32,7 +33,6 @@ CollectionInspectionWorkerThread::init( const std::shared_ptr &inp { fIdleTimeMs = idleTimeMs; } - fCollectionInspectionEngine.setDataReductionParameters( dataReductionProbabilityDisabled ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA fCollectionInspectionEngine.setRawDataBufferManager( rawBufferManager ); @@ -117,7 +117,6 @@ CollectionInspectionWorkerThread::doWork( void *data ) CollectionInspectionWorkerThread *consumer = static_cast( data ); TimePoint lastTimeEvaluated = { 0, 0 }; Timestamp lastTraceOutput = 0; - uint64_t inputCounterSinceLastEvaluate = 0; uint32_t statisticInputMessagesProcessed = 0; uint32_t statisticDataSentOut = 0; uint32_t activations = 0; @@ -139,7 +138,6 @@ CollectionInspectionWorkerThread::doWork( void *data ) // Otherwise, go to sleep. if ( consumer->fUpdatedInspectionMatrix ) { - CollectedSignal inputSignal( 0, 0, 0.0 ); std::array buf = {}; CollectedCanRawFrame inputCANFrame( 0, 0, 0, buf, 0 ); TimePoint currentTime = consumer->fClock->timeSinceEpoch(); @@ -257,7 +255,6 @@ CollectionInspectionWorkerThread::doWork( void *data ) calculateMonotonicTime( currentTime, dataFrame.mCollectedCanRawFrame->receiveTime ), dataFrame.mCollectedCanRawFrame->data, dataFrame.mCollectedCanRawFrame->size ); - inputCounterSinceLastEvaluate++; statisticInputMessagesProcessed++; } @@ -283,32 +280,36 @@ CollectionInspectionWorkerThread::doWork( void *data ) // Initiate data collection and upload after every condition evaluation statisticDataSentOut += consumer->collectDataAndUpload(); }; - consumer->fInputSignalBuffer->consumeAll( consumeSignalGroups ); + auto consumed = consumer->fInputSignalBuffer->consumeAll( consumeSignalGroups ); - // Repeat data collection and upload after queue was emptied - statisticDataSentOut += consumer->collectDataAndUpload(); + // If nothing was consumed and at least the evaluate interval has elapsed, evaluate the + // conditions to check heartbeat campaigns: + if ( ( consumed == 0 ) && ( ( consumer->fClock->monotonicTimeSinceEpochMs() - + lastTimeEvaluated.monotonicTimeMs ) >= EVALUATE_INTERVAL_MS ) ) + { + lastTimeEvaluated = consumer->fClock->timeSinceEpoch(); + consumer->fCollectionInspectionEngine.evaluateConditions( lastTimeEvaluated ); + statisticDataSentOut += consumer->collectDataAndUpload(); + } - if ( consumer->fInputSignalBuffer->isEmpty() ) + // 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->monotonicTimeSinceEpochMs() > + ( lastTraceOutput + LoggingModule::LOG_AGGREGATION_TIME_MS ) ) { - // 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->monotonicTimeSinceEpochMs() > - ( lastTraceOutput + LoggingModule::LOG_AGGREGATION_TIME_MS ) ) - { - FWE_LOG_TRACE( "Activations: " + std::to_string( activations ) + - ". Waiting for some data to come. Idling for: " + std::to_string( timeToWait ) + - " ms or until notify. Since last idling processed " + - std::to_string( statisticInputMessagesProcessed ) + - " incoming data packages and sent out " + std::to_string( statisticDataSentOut ) + - " packages out" ); - activations = 0; - statisticInputMessagesProcessed = 0; - statisticDataSentOut = 0; - lastTraceOutput = consumer->fClock->monotonicTimeSinceEpochMs(); - } - consumer->fWait.wait( timeToWait ); + FWE_LOG_TRACE( "Activations: " + std::to_string( activations ) + + ". Waiting for some data to come. Idling for: " + std::to_string( timeToWait ) + + " ms or until notify. Since last idling processed " + + std::to_string( statisticInputMessagesProcessed ) + + " incoming data packages and sent out " + std::to_string( statisticDataSentOut ) + + " packages out" ); + activations = 0; + statisticInputMessagesProcessed = 0; + statisticDataSentOut = 0; + lastTraceOutput = consumer->fClock->monotonicTimeSinceEpochMs(); } + consumer->fWait.wait( timeToWait ); } else { @@ -339,7 +340,7 @@ CollectionInspectionWorkerThread::collectDataAndUpload() else { collectedDataPackages++; - this->notifyListeners<>( &IDataReadyToPublishListener::onDataReadyToPublish ); + this->mDataReadyListeners.notify(); } collectedData = this->fCollectionInspectionEngine.collectNextDataToSend( this->fClock->timeSinceEpoch(), waitTimeMs ); diff --git a/src/CollectionInspectionWorkerThread.h b/src/CollectionInspectionWorkerThread.h index 626ff149..82101fd3 100644 --- a/src/CollectionInspectionWorkerThread.h +++ b/src/CollectionInspectionWorkerThread.h @@ -7,15 +7,13 @@ #include "ClockHandler.h" #include "CollectionInspectionAPITypes.h" #include "CollectionInspectionEngine.h" -#include "IActiveConditionProcessor.h" -#include "IDataReadyToPublishListener.h" -#include "InspectionEventListener.h" #include "Listener.h" #include "Signal.h" #include "Thread.h" #include "TimeTypes.h" #include #include +#include #include #include @@ -28,20 +26,29 @@ namespace Aws namespace IoTFleetWise { -class CollectionInspectionWorkerThread : public IActiveConditionProcessor, - public ThreadListeners +class CollectionInspectionWorkerThread { public: + using OnDataReadyToPublishCallback = std::function; + CollectionInspectionWorkerThread() = default; - ~CollectionInspectionWorkerThread() override; + ~CollectionInspectionWorkerThread(); CollectionInspectionWorkerThread( const CollectionInspectionWorkerThread & ) = delete; CollectionInspectionWorkerThread &operator=( const CollectionInspectionWorkerThread & ) = delete; CollectionInspectionWorkerThread( CollectionInspectionWorkerThread && ) = delete; CollectionInspectionWorkerThread &operator=( CollectionInspectionWorkerThread && ) = delete; - // Inherited from IActiveConditionProcessor - void onChangeInspectionMatrix( const std::shared_ptr &inspectionMatrix ) override; + void onChangeInspectionMatrix( const std::shared_ptr &inspectionMatrix ); + + /** + * @brief Register a callback to be called when data is ready to be published to the cloud + * */ + void + subscribeToDataReadyToPublish( OnDataReadyToPublishCallback callback ) + { + mDataReadyListeners.subscribe( callback ); + } /** * @brief As soon as new data is available in any input queue call this to wakeup the thread @@ -53,17 +60,17 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, * * @return true if initialization was successful * */ - bool init( - const std::shared_ptr &inputSignalBuffer, /**< IVehicleDataSourceConsumer instances will - put relevant signals in this queue */ - const std::shared_ptr - &outputCollectedData, /**< this thread will put data that should be sent to cloud into this queue */ - uint32_t idleTimeMs, /**< if no new data is available sleep for this amount of milliseconds */ + bool init( const std::shared_ptr &inputSignalBuffer, /**< IVehicleDataSourceConsumer instances will + put relevant signals in this queue */ + const std::shared_ptr + &outputCollectedData, /**< this thread will put data that should be sent to cloud into this queue */ + uint32_t idleTimeMs /**< if no new data is available sleep for this amount of milliseconds */ #ifdef FWE_FEATURE_VISION_SYSTEM_DATA - std::shared_ptr rawBufferManager = - nullptr, /**< the raw buffer manager which is informed what data is used */ + , + std::shared_ptr rawBufferManager = + nullptr /**< the raw buffer manager which is informed what data is used */ #endif - bool dataReductionProbabilityDisabled = false /**< set to true to disable data reduction using probability*/ ); + ); /** * @brief stops the internal thread if started and wait until it finishes @@ -84,30 +91,6 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, */ bool isAlive(); - /** - * @brief Register a thread as a listener to the Inspection Engine events. - * Thread safety is guaranteed by the underlying ThreadListener instance - * @param listener an InspectionEventListener instance - * @return the outcome of the Listener interface subscribeListener() - */ - inline bool - subscribeToEvents( InspectionEventListener *listener ) - { - return fCollectionInspectionEngine.subscribeListener( listener ); - } - - /** - * @brief unRegister a thread as a listener from the Inspection Engine events. - * Thread safety is guaranteed by the underlying ThreadListener instance - * @param listener an InspectionEventListener instance - * @return the outcome of the Listener interface unSubscribeListener() - */ - inline bool - unSubscribeFromEvents( InspectionEventListener *listener ) - { - return fCollectionInspectionEngine.unSubscribeListener( listener ); - } - private: static constexpr Timestamp EVALUATE_INTERVAL_MS = 1; // Evaluate every millisecond static constexpr uint32_t DEFAULT_THREAD_IDLE_TIME_MS = 1000; @@ -139,6 +122,7 @@ class CollectionInspectionWorkerThread : public IActiveConditionProcessor, Signal fWait; uint32_t fIdleTimeMs{ DEFAULT_THREAD_IDLE_TIME_MS }; std::shared_ptr fClock = ClockHandler::getClock(); + ThreadSafeListeners mDataReadyListeners; #ifdef FWE_FEATURE_VISION_SYSTEM_DATA std::shared_ptr mRawBufferManager{ nullptr }; #endif diff --git a/src/CollectionSchemeIngestion.cpp b/src/CollectionSchemeIngestion.cpp index 20318596..9ef7568a 100644 --- a/src/CollectionSchemeIngestion.cpp +++ b/src/CollectionSchemeIngestion.cpp @@ -3,7 +3,6 @@ #include "CollectionSchemeIngestion.h" #include "CollectionInspectionAPITypes.h" -#include "EnumUtility.h" #include "LoggingModule.h" #include @@ -435,37 +434,6 @@ CollectionSchemeIngestion::serializeNode( const Schemas::CommonTypesMsg::Conditi FWE_LOG_TRACE( "Creating Window FUNCTION node for Signal ID:" + std::to_string( currentNode->signalID ) ); return currentNode; } - else if ( node.node_function().functionType_case() == - Schemas::CommonTypesMsg::ConditionNode_NodeFunction::kGeohashFunction ) - { - if ( ( node.node_function().geohash_function().geohash_precision() > UINT8_MAX ) || - ( node.node_function().geohash_function().gps_unit() >= - toUType( GeohashFunction::GPSUnitType::MAX ) ) ) - { - FWE_LOG_WARN( "Invalid Geohash function arguments" ); - } - else - { - currentNode->nodeType = ExpressionNodeType::GEOHASHFUNCTION; // geohash - currentNode->function.geohashFunction.latitudeSignalID = - node.node_function().geohash_function().latitude_signal_id(); - currentNode->function.geohashFunction.longitudeSignalID = - node.node_function().geohash_function().longitude_signal_id(); - currentNode->function.geohashFunction.precision = - static_cast( node.node_function().geohash_function().geohash_precision() ); - // coverity[autosar_cpp14_a7_2_1_violation] Range is checked by the if-statement above - currentNode->function.geohashFunction.gpsUnitType = - static_cast( node.node_function().geohash_function().gps_unit() ); - FWE_LOG_TRACE( - "Creating Geohash FUNCTION node: Lat SignalID: " + - std::to_string( currentNode->function.geohashFunction.latitudeSignalID ) + - "; Lon SignalID: " + std::to_string( currentNode->function.geohashFunction.longitudeSignalID ) + - "; precision: " + std::to_string( currentNode->function.geohashFunction.precision ) + - "; GPS Unit Type: " + - std::to_string( static_cast( currentNode->function.geohashFunction.gpsUnitType ) ) ); - return currentNode; - } - } else { FWE_LOG_WARN( "Unsupported Function Node Type" ); @@ -711,20 +679,6 @@ CollectionSchemeIngestion::isTriggerOnlyOnRisingEdge() const return false; } -double -CollectionSchemeIngestion::getProbabilityToSend() const -{ - if ( !mReady ) - { - return INVALID_PROBABILITY_TO_SEND; - } - if ( !mProtoCollectionSchemeMessagePtr->has_probabilities() ) - { - return DEFAULT_PROBABILITY_TO_SEND; - } - return mProtoCollectionSchemeMessagePtr->probabilities().probability_to_send(); -} - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA S3UploadMetadata CollectionSchemeIngestion::getS3UploadMetadata() const diff --git a/src/CollectionSchemeIngestion.h b/src/CollectionSchemeIngestion.h index 2aa6844a..0967a184 100644 --- a/src/CollectionSchemeIngestion.h +++ b/src/CollectionSchemeIngestion.h @@ -5,6 +5,7 @@ #include "ICollectionScheme.h" #include "collection_schemes.pb.h" +#include "common_types.pb.h" #include #include #include @@ -55,8 +56,6 @@ class CollectionSchemeIngestion : public ICollectionScheme bool isTriggerOnlyOnRisingEdge() const override; - double getProbabilityToSend() const override; - const Signals_t &getCollectSignals() const override; const RawCanFrames_t &getCollectRawCanFrames() const override; diff --git a/src/CollectionSchemeManagementListener.h b/src/CollectionSchemeManagementListener.h deleted file mode 100644 index a0dff095..00000000 --- a/src/CollectionSchemeManagementListener.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "ICollectionSchemeList.h" -#include "IDecoderManifest.h" - -namespace Aws -{ -namespace IoTFleetWise -{ - -using IDecoderManifestPtr = std::shared_ptr; -using ICollectionSchemeListPtr = std::shared_ptr; - -struct CollectionSchemeManagementListener -{ - virtual ~CollectionSchemeManagementListener() = default; - - /** - * @brief Callback function that Schema uses to notify CollectionSchemeManagement when a new CollectionScheme List - * arrives from the Cloud. - * - * @param collectionSchemeList ICollectionSchemeList from CollectionScheme Ingestion - */ - virtual void onCollectionSchemeUpdate( const ICollectionSchemeListPtr &collectionSchemeList ) = 0; - - /** - * @brief Callback function that Schema uses to notify CollectionSchemeManagement when a new Decoder - * Manifest arrives from the Cloud. - * - * @param decoderManifest IDecoderManifest from CollectionScheme Ingestion - */ - virtual void onDecoderManifestUpdate( const IDecoderManifestPtr &decoderManifest ) = 0; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/CollectionSchemeManager.cpp b/src/CollectionSchemeManager.cpp index e908fbaa..002cab4e 100644 --- a/src/CollectionSchemeManager.cpp +++ b/src/CollectionSchemeManager.cpp @@ -940,8 +940,7 @@ CollectionSchemeManager::updateActiveSchemesListeners() activeCollectionSchemesOutput->activeCollectionSchemes.push_back( enabledCollectionScheme.second ); } - notifyListeners &>( - &IActiveCollectionSchemesListener::onChangeCollectionSchemeList, activeCollectionSchemesOutput ); + mCollectionSchemeListChangeListeners.notify( activeCollectionSchemesOutput ); } } // namespace IoTFleetWise diff --git a/src/CollectionSchemeManager.h b/src/CollectionSchemeManager.h index 9edc0312..75810c09 100644 --- a/src/CollectionSchemeManager.h +++ b/src/CollectionSchemeManager.h @@ -8,10 +8,6 @@ #include "Clock.h" #include "ClockHandler.h" #include "CollectionInspectionAPITypes.h" -#include "CollectionSchemeManagementListener.h" -#include "IActiveCollectionSchemesListener.h" -#include "IActiveConditionProcessor.h" -#include "IActiveDecoderDictionaryListener.h" #include "ICollectionSchemeList.h" #include "ICollectionSchemeManager.h" #include "IDecoderDictionary.h" @@ -72,16 +68,36 @@ struct TimeData * 7. Notify other components about currently Enabled CollectionSchemes. */ -class CollectionSchemeManager : public ICollectionSchemeManager, - public CollectionSchemeManagementListener, - public ThreadListeners, - public ThreadListeners, - public ThreadListeners +class CollectionSchemeManager : public ICollectionSchemeManager { public: - using ThreadListeners::subscribeListener; - using ThreadListeners::subscribeListener; - using ThreadListeners::subscribeListener; + /** + * @brief The callback function used to notify any listeners on change of Decoder Dictionary + * + * @param dictionary const shared pointer pointing to a constant decoder dictionary + * @param networkProtocol network protocol type indicating which type of decoder dictionary it's updating + */ + using OnActiveDecoderDictionaryChangeCallback = + std::function; + + /** + * @brief Callback to notify the change of active conditions for example by rebuilding buffers + * + * This function should be called as rarely as possible. + * All condition should fulfill the restriction like max signal id or equation depth. + * After this call all cached signal values that were not published are deleted + * @param inspectionMatrix all currently active Conditions + * @return true if valid conditions were handed over + * */ + using OnInspectionMatrixChangeCallback = + std::function &inspectionMatrix )>; + + /** + * @brief Callback to notify the change of active collection schemes + * + * */ + using OnCollectionSchemeListChangeCallback = + std::function &activeCollectionSchemes )>; CollectionSchemeManager() = default; @@ -174,11 +190,37 @@ class CollectionSchemeManager : public ICollectionSchemeManager, */ std::vector getCollectionSchemeArns(); -private: - using ThreadListeners::notifyListeners; - using ThreadListeners::notifyListeners; - using ThreadListeners::notifyListeners; + /** + * @brief Subscribe to changes in the active decoder dictionary + * @param callback A function that will be called when the active dictionary changes + */ + void + subscribeToActiveDecoderDictionaryChange( OnActiveDecoderDictionaryChangeCallback callback ) + { + mActiveDecoderDictionaryChangeListeners.subscribe( callback ); + } + /** + * @brief Subscribe to changes in the inspection matrix + * @param callback A function that will be called when the inspection matrix changes + */ + void + subscribeToInspectionMatrixChange( OnInspectionMatrixChangeCallback callback ) + { + mInspectionMatrixChangeListeners.subscribe( callback ); + } + + /** + * @brief Subscribe to changes in the collection scheme list + * @param callback A function that will be called when the collection scheme list changes + */ + void + subscribeToCollectionSchemeListChange( OnCollectionSchemeListChangeCallback callback ) + { + mCollectionSchemeListChangeListeners.subscribe( callback ); + } + +private: /** * @brief Starts main thread * @return True if successful. False otherwise. @@ -389,6 +431,10 @@ class CollectionSchemeManager : public ICollectionSchemeManager, /* lock used in callback functions onCollectionSchemeAvailable and onDecoderManifest */ std::mutex mSchemaUpdateMutex; + ThreadSafeListeners mActiveDecoderDictionaryChangeListeners; + ThreadSafeListeners mInspectionMatrixChangeListeners; + ThreadSafeListeners mCollectionSchemeListChangeListeners; + /* * parameters used in onCollectionSchemeAvailable() * mCollectionSchemeAvailable: flag notifying collectionScheme update is available diff --git a/src/CustomDataSource.h b/src/CustomDataSource.h index 0194e0ad..cb70ba69 100644 --- a/src/CustomDataSource.h +++ b/src/CustomDataSource.h @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" #include "MessageTypes.h" #include "Signal.h" @@ -24,13 +23,13 @@ namespace IoTFleetWise * To implement a custom data source create a new class and inherit from CustomDataSource * then call setFilter() then start() and provide an implementation for pollData */ -class CustomDataSource : public IActiveDecoderDictionaryListener +class CustomDataSource { public: CustomDataSource() = default; - // from IActiveDecoderDictionaryListener + void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); bool start(); bool stop(); @@ -61,7 +60,7 @@ class CustomDataSource : public IActiveDecoderDictionaryListener */ std::vector getSignalInfo(); - ~CustomDataSource() override; + virtual ~CustomDataSource(); CustomDataSource( const CustomDataSource & ) = delete; CustomDataSource &operator=( const CustomDataSource & ) = delete; CustomDataSource( CustomDataSource && ) = delete; diff --git a/src/DataReduction.h b/src/DataReduction.h deleted file mode 100644 index cb4c384b..00000000 --- a/src/DataReduction.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -#pragma once - -#include "CollectionInspectionAPITypes.h" -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief Utility class used by CollectionInspectionEngine for reducing data sent from FWE to cloud - * - * One way to reduce data is to randomly not send out data. Other mechanisms to - * reduce the data sent out are planned in the future. - */ -class DataReduction -{ - -public: - /** - * @brief probability data reduction can be disabled for example for debugging - * - * @param disableProbability if true all data will be sent out independent of the reduction defined - */ - void - setDisableProbability( bool disableProbability ) - { - mDisableProbability = disableProbability; - } - - /** - * @brief decides if the data should be sent out or not partially based on randomness - * - * As random number generation is part of the function the result is not deterministic. - * Depending on the input parameters the probability of this function returning true changes. - * - * @return non deterministic decision to send the data out or not - * - */ - bool - shallSendData( double collectionSchemeProbability ) - { - return ( mDisableProbability || ( ( collectionSchemeProbability > 0.0 ) && - ( generateNewRandomNumber() <= collectionSchemeProbability ) ) ); - } - -private: - bool mDisableProbability{ false }; - /* Pseudo random number generation*/ - std::mt19937 mRandomGenerator{ std::random_device{}() }; // Standard mersenne_twister_engine seeded with rd() - std::uniform_real_distribution<> mRandomUniformDistribution{ MIN_PROBABILITY, MAX_PROBABILITY }; - - double - generateNewRandomNumber() - { - return this->mRandomUniformDistribution( this->mRandomGenerator ); - }; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/DataSenderIonWriter.cpp b/src/DataSenderIonWriter.cpp index 1fea699c..c0ee7202 100644 --- a/src/DataSenderIonWriter.cpp +++ b/src/DataSenderIonWriter.cpp @@ -298,11 +298,12 @@ class IonFileGenerator : public std::streambuf ionWriteFieldStr( hWRITER writer, const char *str, size_t len ) { ION_STRING fieldNameString; - // coverity[cert_exp55_cpp_violation] ion-c needs non-const input + // clang-format off // coverity[autosar_cpp14_a5_2_3_violation] ion-c needs non-const input // coverity[misra_cpp_2008_rule_5_2_5_violation] ion-c needs non-const input - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input - ion_string_assign_cstr( &fieldNameString, const_cast( str ), static_cast( len ) ); + // coverity[cert_exp55_cpp_violation] ion-c needs non-const input + ion_string_assign_cstr( &fieldNameString, const_cast( str ), static_cast( len ) ); // NOLINT(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input + // clang-format on return ion_writer_write_field_name( ( writer ), &fieldNameString ); } @@ -310,11 +311,12 @@ class IonFileGenerator : public std::streambuf ionWriteValueStr( hWRITER writer, const char *str, size_t len ) { ION_STRING valueString; - // coverity[cert_exp55_cpp_violation] ion-c needs non-const input + // clang-format off // coverity[autosar_cpp14_a5_2_3_violation] ion-c needs non-const input // coverity[misra_cpp_2008_rule_5_2_5_violation] ion-c needs non-const input - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input - ion_string_assign_cstr( &valueString, const_cast( str ), static_cast( len ) ); + // coverity[cert_exp55_cpp_violation] ion-c needs non-const input + ion_string_assign_cstr( &valueString, const_cast( str ), static_cast( len ) ); // NOLINT(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input + // clang-format on return ion_writer_write_string( ( writer ), &valueString ); } @@ -342,34 +344,24 @@ class IonFileGenerator : public std::streambuf // The callbacks will come only directly form inside a ion_ call and not from a different thread mIonWriteCallback = [this]( _ion_user_stream *stream ) -> iERR { // Check limit to skip first call where stream->limit is not initialized - - // coverity[autosar_cpp14_m5_0_18_violation] stream-> limit is assigned to mIonWriteBuffer.end() - // coverity[cert_ctr54_cpp_violation] stream-> limit is assigned to mIonWriteBuffer.end() - // coverity[misra_cpp_2008_rule_5_0_18_violation] stream-> limit is assigned to mIonWriteBuffer.end() if ( stream->limit == static_cast( mIonWriteBuffer.data() + mIonWriteBuffer.size() ) ) { - // coverity[cert_ctr54_cpp_violation] this explicitly checks if stream->curr is inside the array - // coverity[autosar_cpp14_m5_0_18_violation] this explicitly checks if stream->curr is inside the array - // coverity[misra_cpp_2008_rule_5_0_18_violation] this explicitly checks if stream->curr is inside the - // array + // coverity[misra_cpp_2008_rule_5_0_18_violation] it was checked that stream->curr is inside the array + // coverity[autosar_cpp14_m5_0_18_violation] same + // coverity[cert_ctr54_cpp_violation] same if ( ( stream->curr >= static_cast( &( *mIonWriteBuffer.begin() ) ) ) && - // coverity[autosar_cpp14_m5_0_18_violation] this explicitly checks if stream->curr is inside the - // array - // coverity[cert_ctr54_cpp_violation] this explicitly checks if stream->curr is inside the array - // coverity[misra_cpp_2008_rule_5_0_18_violation] this explicitly checks if stream->curr is inside - // the array + // clang-format off + // coverity[misra_cpp_2008_rule_5_0_18_violation] it was checked that stream->curr is inside the array + // coverity[autosar_cpp14_m5_0_18_violation] same ( stream->curr <= static_cast( mIonWriteBuffer.data() + mIonWriteBuffer.size() ) ) ) + // clang-format on { - // coverity[autosar_cpp14_m5_0_18_violation] it was checked that stream->curr is inside the array - // coverity[autosar_cpp14_m5_0_17_violation] same - // coverity[cert_ctr54_cpp_violation] same - // coverity[misra_cpp_2008_rule_5_0_18_violation] same + // coverity[autosar_cpp14_m5_0_17_violation] it was checked that stream->curr is inside the array + // coverity[autosar_cpp14_m5_0_9_violation] same // coverity[misra_cpp_2008_rule_5_0_17_violation] same + // coverity[misra_cpp_2008_rule_5_0_9_violation] same + // coverity[cert_ctr54_cpp_violation] same mWrittenBytesInIonWriteBuffer = - // coverity[autosar_cpp14_m5_0_9_violation] it is checked that stream->curr >= - // mIonWriteBuffer.begin() so not negative - // coverity[misra_cpp_2008_rule_5_0_9_violation] it is checked that stream->curr >= - // mIonWriteBuffer.begin() so not negative static_cast( stream->curr - static_cast( &( *mIonWriteBuffer.begin() ) ) ); } if ( stream->curr == stream->limit ) @@ -415,12 +407,12 @@ class IonFileGenerator : public std::streambuf FWE_LOG_ERROR( "Abort serializeMetadata as Ion Writer could not be created" ); return; } + // clang-format off // coverity[autosar_cpp14_m5_2_9_violation] tid_STRUCT comes from library so cast is done in library header - // coverity[cert_exp57_cpp_violation] tid_STRUCT comes from library so cast is done in library header // coverity[misra_cpp_2008_rule_5_2_9_violation] tid_STRUCT comes from library so cast is done in library header - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) cast is for tid_STRUCT in Ion header - ION_CHECK( ion_writer_start_container( mIonWriter, tid_STRUCT ) ); + // coverity[cert_exp57_cpp_violation] tid_STRUCT comes from library so cast is done in library header + ION_CHECK( ion_writer_start_container( mIonWriter, tid_STRUCT ) ); // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-cstyle-cast) + // clang-format on ION_CHECK( ionWriteFieldStr( mIonWriter, &FIELD_NAME_SCHEMA[0], static_cast( sizeof( FIELD_NAME_SCHEMA ) - 1 ) ) ); @@ -463,12 +455,12 @@ class IonFileGenerator : public std::streambuf FWE_LOG_ERROR( "Abort serializeMetadata as Ion Writer could not be created" ); return; } - // coverity[cert_exp57_cpp_violation] tid_STRUCT comes from library so cast is done in library header + // clang-format off // coverity[autosar_cpp14_m5_2_9_violation] tid_STRUCT comes from library so cast is done in library header // coverity[misra_cpp_2008_rule_5_2_9_violation] tid_STRUCT comes from library so cast is done in library header - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) cast is for tid_STRUCT in Ion header - ION_CHECK( ion_writer_start_container( mIonWriter, tid_STRUCT ) ); + // coverity[cert_exp57_cpp_violation] tid_STRUCT comes from library so cast is done in library header + ION_CHECK( ion_writer_start_container( mIonWriter, tid_STRUCT ) ); // NOLINT(cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-cstyle-cast) + // clang-format on ION_CHECK( ionWriteFieldStr( mIonWriter, &FIELD_NAME_SIGNAL_ID[0], static_cast( sizeof( FIELD_NAME_SIGNAL_ID ) - 1 ) ) ); ION_CHECK( ion_writer_write_int32( mIonWriter, static_cast( frameInfo.mId ) ) ); @@ -503,12 +495,13 @@ class IonFileGenerator : public std::streambuf { ION_CHECK( ionWriteFieldStr( mIonWriter, &FIELD_NAME_SIGNAL_BLOB[0], static_cast( sizeof( FIELD_NAME_SIGNAL_BLOB ) - 1 ) ) ); + // clang-format off // coverity[autosar_cpp14_a5_2_3_violation] ion-c needs non-const input - // coverity[cert_exp55_cpp_violation] ion-c needs non-const input // coverity[misra_cpp_2008_rule_5_2_5_violation] ion-c needs non-const input - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input + // coverity[cert_exp55_cpp_violation] ion-c needs non-const input ION_CHECK( ion_writer_write_blob( - mIonWriter, reinterpret_cast( const_cast( buffer ) ), static_cast( size ) ) ); + mIonWriter, reinterpret_cast( const_cast( buffer ) ), static_cast( size ) ) ); // NOLINT(cppcoreguidelines-pro-type-const-cast) ion-c needs non-const input + // clang-format on } ION_CHECK( ion_writer_finish_container( mIonWriter ) ); diff --git a/src/DataSenderIonWriter.h b/src/DataSenderIonWriter.h index 7b19d8c7..5f8cd1d6 100644 --- a/src/DataSenderIonWriter.h +++ b/src/DataSenderIonWriter.h @@ -4,7 +4,6 @@ #pragma once #include "CollectionInspectionAPITypes.h" -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" #include "RawDataManager.h" #include "SignalTypes.h" @@ -39,7 +38,7 @@ struct FrameInfoForIon // coverity[cert_dcl60_cpp_violation] false positive - class only defined once // coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once // coverity[misra_cpp_2008_rule_3_2_2_violation] false positive - class only defined once -class DataSenderIonWriter : public IActiveDecoderDictionaryListener +class DataSenderIonWriter { public: /** @@ -50,7 +49,7 @@ class DataSenderIonWriter : public IActiveDecoderDictionaryListener /** * @brief Destructor. */ - ~DataSenderIonWriter() override; + virtual ~DataSenderIonWriter(); DataSenderIonWriter( const DataSenderIonWriter & ) = delete; DataSenderIonWriter &operator=( const DataSenderIonWriter & ) = delete; @@ -97,12 +96,12 @@ class DataSenderIonWriter : public IActiveDecoderDictionaryListener }; /** - * @brief From IActiveDecoderDictionaryListener get called on dictionary updates + * @brief To be called on dictionary updates * @param dictionary new dictionary with the topics to subscribe to and information how to decode * @param networkProtocol only COMPLEX_DATA will be accepted */ void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); private: bool fillFrameInfo( FrameInfoForIon &frame ); diff --git a/src/DataSenderManager.cpp b/src/DataSenderManager.cpp index 90b31c2e..477fd622 100644 --- a/src/DataSenderManager.cpp +++ b/src/DataSenderManager.cpp @@ -3,7 +3,6 @@ #include "DataSenderManager.h" #include "CacheAndPersist.h" -#include "GeohashInfo.h" #include "LoggingModule.h" #include "OBDDataTypes.h" #include "TraceModule.h" @@ -127,12 +126,6 @@ DataSenderManager::transformTelemetryDataToProto( } } - // Add Geohash to the payload - if ( triggeredCollectionSchemeDataPtr->mGeohashInfo.hasItems() ) - { - appendMessageToProto( triggeredCollectionSchemeDataPtr, triggeredCollectionSchemeDataPtr->mGeohashInfo ); - } - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA for ( const auto &object : triggeredCollectionSchemeDataPtr->uploadedS3Objects ) { diff --git a/src/DataSenderManager.h b/src/DataSenderManager.h index 65925dc8..49b667f2 100644 --- a/src/DataSenderManager.h +++ b/src/DataSenderManager.h @@ -16,8 +16,8 @@ #ifdef FWE_FEATURE_VISION_SYSTEM_DATA #include "DataSenderIonWriter.h" -#include "IActiveCollectionSchemesListener.h" #include "ICollectionScheme.h" +#include "ICollectionSchemeList.h" #include "S3Sender.h" #include #endif diff --git a/src/DataSenderManagerWorkerThread.cpp b/src/DataSenderManagerWorkerThread.cpp index c1414c0d..26c6765d 100644 --- a/src/DataSenderManagerWorkerThread.cpp +++ b/src/DataSenderManagerWorkerThread.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 #include "DataSenderManagerWorkerThread.h" -#include "GeohashInfo.h" #include "LoggingModule.h" #include "OBDDataTypes.h" #include "SignalTypes.h" @@ -187,8 +186,7 @@ DataSenderManagerWorkerThread::doWork( void *data ) // Avoid invoking Data Collection Sender if there is nothing to send. if ( triggeredCollectionSchemeDataPtr->signals.empty() && triggeredCollectionSchemeDataPtr->canFrames.empty() && - triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.empty() && - ( !triggeredCollectionSchemeDataPtr->mGeohashInfo.hasItems() ) + triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.empty() #ifdef FWE_FEATURE_VISION_SYSTEM_DATA && triggeredCollectionSchemeDataPtr->uploadedS3Objects.empty() #endif @@ -209,8 +207,7 @@ DataSenderManagerWorkerThread::doWork( void *data ) firstSignalValues + firstSignalTimestamp + " trigger timestamp: " + std::to_string( triggeredCollectionSchemeDataPtr->triggerTime ) + " raw CAN frames:" + std::to_string( triggeredCollectionSchemeDataPtr->canFrames.size() ) + - " DTCs:" + std::to_string( triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.size() ) + - " Geohash:" + triggeredCollectionSchemeDataPtr->mGeohashInfo.mGeohashString + " DTCs:" + std::to_string( triggeredCollectionSchemeDataPtr->mDTCInfo.mDTCCodes.size() ) #ifdef FWE_FEATURE_VISION_SYSTEM_DATA + " Uploaded S3 Objects: " + std::to_string( triggeredCollectionSchemeDataPtr->uploadedS3Objects.size() ) diff --git a/src/DataSenderManagerWorkerThread.h b/src/DataSenderManagerWorkerThread.h index e2eec287..951ed68b 100644 --- a/src/DataSenderManagerWorkerThread.h +++ b/src/DataSenderManagerWorkerThread.h @@ -6,7 +6,6 @@ #include "CollectionInspectionAPITypes.h" #include "DataSenderManager.h" #include "IConnectivityModule.h" -#include "IDataReadyToPublishListener.h" #include "Signal.h" #include "Thread.h" #include "Timer.h" @@ -16,7 +15,7 @@ #include #ifdef FWE_FEATURE_VISION_SYSTEM_DATA -#include "IActiveCollectionSchemesListener.h" +#include "ICollectionSchemeList.h" #endif namespace Aws @@ -24,18 +23,14 @@ namespace Aws namespace IoTFleetWise { -class DataSenderManagerWorkerThread : public IDataReadyToPublishListener -#ifdef FWE_FEATURE_VISION_SYSTEM_DATA - , - public IActiveCollectionSchemesListener -#endif +class DataSenderManagerWorkerThread { public: DataSenderManagerWorkerThread( std::shared_ptr connectivityModule, std::shared_ptr dataSenderManager, uint64_t persistencyUploadRetryIntervalMs, std::shared_ptr &collectedDataQueue ); - ~DataSenderManagerWorkerThread() override; + ~DataSenderManagerWorkerThread(); DataSenderManagerWorkerThread( const DataSenderManagerWorkerThread & ) = delete; DataSenderManagerWorkerThread &operator=( const DataSenderManagerWorkerThread & ) = delete; @@ -48,11 +43,10 @@ class DataSenderManagerWorkerThread : public IDataReadyToPublishListener * @brief Callback from the Inspection Engine to wake up this thread and * publish the data to the cloud. */ - void onDataReadyToPublish() override; + void onDataReadyToPublish(); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA - void onChangeCollectionSchemeList( - const std::shared_ptr &activeCollectionSchemes ) override; + void onChangeCollectionSchemeList( const std::shared_ptr &activeCollectionSchemes ); #endif /** diff --git a/src/DataSenderProtoWriter.cpp b/src/DataSenderProtoWriter.cpp index 7bd4e36e..c41ac2b8 100644 --- a/src/DataSenderProtoWriter.cpp +++ b/src/DataSenderProtoWriter.cpp @@ -117,15 +117,6 @@ DataSenderProtoWriter::append( const std::string &dtc ) dtcData->add_active_dtc_codes( dtc ); } -void -DataSenderProtoWriter::append( const GeohashInfo &geohashInfo ) -{ - auto geohashProto = mVehicleData.mutable_geohash(); - mVehicleDataMsgCount++; - geohashProto->set_geohash_string( geohashInfo.mGeohashString ); - geohashProto->set_prev_reported_geohash_string( geohashInfo.mPrevReportedGeohashString ); -} - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA void DataSenderProtoWriter::append( const UploadedS3Object &uploadedS3Object ) diff --git a/src/DataSenderProtoWriter.h b/src/DataSenderProtoWriter.h index 89fc59f5..853fabd2 100644 --- a/src/DataSenderProtoWriter.h +++ b/src/DataSenderProtoWriter.h @@ -5,7 +5,6 @@ #include "CANInterfaceIDTranslator.h" #include "CollectionInspectionAPITypes.h" -#include "GeohashInfo.h" #include "OBDDataTypes.h" #include "TimeTypes.h" #include "vehicle_data.pb.h" @@ -70,13 +69,6 @@ class DataSenderProtoWriter */ void append( const std::string &dtc ); - /** - * @brief Appends the Geohash String to the output protobuf - * - * @param geohashInfo Geohash information - */ - void append( const GeohashInfo &geohashInfo ); - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA /** * @brief Appends uploaded S3 object info to the output protobuf diff --git a/src/DecoderDictionaryExtractor.cpp b/src/DecoderDictionaryExtractor.cpp index 3be99547..aa5fecde 100644 --- a/src/DecoderDictionaryExtractor.cpp +++ b/src/DecoderDictionaryExtractor.cpp @@ -381,8 +381,7 @@ CollectionSchemeManager::decoderDictionaryUpdater( // Down cast the CAN Decoder Dictionary to base Decoder Dictionary. We will support more // types of Decoder Dictionary in later releases auto dictPtr = std::static_pointer_cast( dict.second ); - notifyListeners &>( - &IActiveDecoderDictionaryListener::onChangeOfActiveDictionary, dictPtr, dict.first ); + mActiveDecoderDictionaryChangeListeners.notify( dictPtr, dict.first ); } } diff --git a/src/DecoderManifestIngestion.cpp b/src/DecoderManifestIngestion.cpp index ff4a8899..02be347a 100644 --- a/src/DecoderManifestIngestion.cpp +++ b/src/DecoderManifestIngestion.cpp @@ -42,7 +42,7 @@ DecoderManifestIngestion::isReady() const } const CANMessageFormat & -DecoderManifestIngestion::getCANMessageFormat( CANRawFrameID canID, CANInterfaceID interfaceID ) const +DecoderManifestIngestion::getCANMessageFormat( CANRawFrameID canID, InterfaceID interfaceID ) const { if ( !mReady ) { @@ -61,12 +61,12 @@ DecoderManifestIngestion::getCANMessageFormat( CANRawFrameID canID, CANInterface return INVALID_CAN_MESSAGE_FORMAT; } -std::pair +std::pair DecoderManifestIngestion::getCANFrameAndInterfaceID( SignalID signalID ) const { if ( !mReady ) { - return std::make_pair( INVALID_CAN_FRAME_ID, INVALID_CAN_INTERFACE_ID ); + return std::make_pair( INVALID_CAN_FRAME_ID, INVALID_INTERFACE_ID ); } // Check to see if entry exists @@ -77,7 +77,7 @@ DecoderManifestIngestion::getCANFrameAndInterfaceID( SignalID signalID ) const } // Information for signal does not exist. - return std::make_pair( INVALID_CAN_FRAME_ID, INVALID_CAN_INTERFACE_ID ); + return std::make_pair( INVALID_CAN_FRAME_ID, INVALID_INTERFACE_ID ); } VehicleDataSourceProtocol @@ -407,7 +407,7 @@ DecoderManifestIngestion::build() { const Schemas::DecoderManifestMsg::ComplexSignal &complexSignal = mProtoDecoderManifest.complex_signals( i ); mSignalToVehicleDataSourceProtocol[complexSignal.signal_id()] = VehicleDataSourceProtocol::COMPLEX_DATA; - if ( complexSignal.interface_id() == INVALID_COMPLEX_DATA_INTERFACE ) + if ( complexSignal.interface_id() == INVALID_INTERFACE_ID ) { FWE_LOG_WARN( "Complex Signal with empty interface_id and signal id:" + std::to_string( complexSignal.signal_id() ) ); diff --git a/src/DecoderManifestIngestion.h b/src/DecoderManifestIngestion.h index b69144a7..2d2bc74e 100644 --- a/src/DecoderManifestIngestion.h +++ b/src/DecoderManifestIngestion.h @@ -54,9 +54,9 @@ class DecoderManifestIngestion : public IDecoderManifest std::string getID() const override; - const CANMessageFormat &getCANMessageFormat( CANRawFrameID canID, CANInterfaceID interfaceID ) const override; + const CANMessageFormat &getCANMessageFormat( CANRawFrameID canID, InterfaceID interfaceID ) const override; - std::pair getCANFrameAndInterfaceID( SignalID signalID ) const override; + std::pair getCANFrameAndInterfaceID( SignalID signalID ) const override; VehicleDataSourceProtocol getNetworkProtocol( SignalID signalID ) const override; @@ -108,14 +108,13 @@ class DecoderManifestIngestion : public IDecoderManifest * @brief A dictionary used internally that allows the retrieval of a CANMessageFormat per CanChannelId and * CANRawFrameID Key: CANRawFrameID Value: CANMessageFormat */ - std::unordered_map mCANMessageFormatDictionary; + std::unordered_map mCANMessageFormatDictionary; /** * @brief A dictionary used internally that allows lookup of what CANRawFrameID and NodeID a Signal is found on * Key: Signal ID Value:pair of CANRawFrameID and NodeID */ - std::unordered_map> - mSignalToCANRawFrameIDAndInterfaceIDDictionary; + std::unordered_map> mSignalToCANRawFrameIDAndInterfaceIDDictionary; /** * @brief A dictionary used internally that allows lookup of what type of network protocol is this signal diff --git a/src/ExternalCANDataSource.cpp b/src/ExternalCANDataSource.cpp index 8aa53699..c7d7e2a5 100644 --- a/src/ExternalCANDataSource.cpp +++ b/src/ExternalCANDataSource.cpp @@ -29,7 +29,7 @@ ExternalCANDataSource::ingestMessage( CANChannelNumericID channelId, } if ( timestamp == 0 ) { - TraceModule::get().incrementVariable( TraceVariable::CAN_POLLING_TIMESTAMP_COUNTER ); + TraceModule::get().incrementVariable( TraceVariable::POLLING_TIMESTAMP_COUNTER ); timestamp = mClock->systemTimeSinceEpochMs(); } if ( timestamp < mLastFrameTime ) diff --git a/src/ExternalCANDataSource.h b/src/ExternalCANDataSource.h index af03b5ee..91651776 100644 --- a/src/ExternalCANDataSource.h +++ b/src/ExternalCANDataSource.h @@ -6,7 +6,6 @@ #include "CANDataConsumer.h" #include "Clock.h" #include "ClockHandler.h" -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" #include "SignalTypes.h" #include "TimeTypes.h" @@ -27,7 +26,7 @@ namespace IoTFleetWise */ // coverity[cert_dcl60_cpp_violation] false positive - class only defined once // coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once -class ExternalCANDataSource : public IActiveDecoderDictionaryListener +class ExternalCANDataSource { public: /** @@ -35,7 +34,7 @@ class ExternalCANDataSource : public IActiveDecoderDictionaryListener * @param consumer CAN data consumer */ ExternalCANDataSource( CANDataConsumer &consumer ); - ~ExternalCANDataSource() override = default; + ~ExternalCANDataSource() = default; ExternalCANDataSource( const ExternalCANDataSource & ) = delete; ExternalCANDataSource &operator=( const ExternalCANDataSource & ) = delete; @@ -53,7 +52,7 @@ class ExternalCANDataSource : public IActiveDecoderDictionaryListener const std::vector &data ); void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); private: std::shared_ptr mClock = ClockHandler::getClock(); diff --git a/src/Geohash.cpp b/src/Geohash.cpp deleted file mode 100644 index bf814ebc..00000000 --- a/src/Geohash.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include "Geohash.h" -namespace Aws -{ -namespace IoTFleetWise -{ - -// This is a Base 32 character map. The map index is the number. -// For instance, 8 correspond to '8', 31 correspond to 'z' -static constexpr char base32Map[32] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; - -bool -Geohash::encode( double lat, double lon, uint8_t precision, uint64_t &hashBits ) -{ - // check MAX_PRECISION and BASE32_BITS validity at compile time. - 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 ) ) - { - // INVALID INPUT, need to return as we cannot proceed for calculation - return false; - } - auto latLow = LAT_MIN; - auto latHigh = LAT_MAX; - auto lonLow = LON_MIN; - auto lonHigh = LON_MAX; - // This is the Geohash in bits format. It's an uint64_t. - hashBits = 0; - // This is a flag indicating whether current bit represent longitude or latitude. - // In Geohash, bits in odd position represent longitude, bits in even position represent latitude. - // Note first bit is odd position, hence we set the initial flag to true. - bool isLonBit = true; - // Each hash character is in base 32 format, hence 5-bit. The total number bits in hash is - // precision * 5 - int numOfHashBits = precision * BASE32_BITS; - // Iterate through the bits - for ( int i = 0; i < numOfHashBits; ++i ) - { - if ( isLonBit ) - { - // Binary Search on longitude - auto lonMid = lonLow + ( lonHigh - lonLow ) / 2; - if ( lon >= lonMid ) - { - // Set the new bit to 1 - hashBits = ( hashBits << 1 ) | 1; - lonLow = lonMid; - } - else - { - // Set the new bit to 0 - hashBits = ( hashBits << 1 ) | 0; - lonHigh = lonMid; - } - } - else - { - // Binary Search on latitude - auto latMid = latLow + ( latHigh - latLow ) / 2; - if ( lat >= latMid ) - { - // Set the new bit to 1 - hashBits = ( hashBits << 1 ) | 1; - latLow = latMid; - } - else - { - // Set the new bit to 0 - hashBits = ( hashBits << 1 ) | 0; - latHigh = latMid; - } - } - // Toggle the flag - isLonBit = !isLonBit; - } - return true; -} - -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 ) ) - { - // INVALID INPUT, need to return as we cannot proceed for calculation - return false; - } - hashString = ""; - uint64_t hashBits = 0; - // First we get the Geohash in raw bits format. - encode( lat, lon, precision, hashBits ); - for ( uint8_t i = 0; i < precision; ++i ) - { - // we iterate the hash bits from left to right - // Each time we grab the 5-bit - uint32_t base32Num = ( hashBits >> ( precision - 1 - i ) * BASE32_BITS ) & 0x1F; - // Convert 5-bit to base 32 format - hashString.append( 1, base32Map[base32Num] ); - } - return true; -} - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/Geohash.h b/src/Geohash.h deleted file mode 100644 index 12a5bde1..00000000 --- a/src/Geohash.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief This is the Geohash module that can convert GPS latitude and longitude to GeoHash - * - * See more details about Geohash at wikipedia: https://en.wikipedia.org/wiki/Geohash - * - */ -// coverity[cert_dcl60_cpp_violation] false positive - class only defined once -// coverity[autosar_cpp14_m3_2_2_violation] false positive - class only defined once -// coverity[misra_cpp_2008_rule_3_2_2_violation] false positive - class only defined once -class Geohash -{ -public: - /** - * @brief Encoding function that takes latitude and longitude and precision and output Geohash - * in bits format. - * Note the LSb is the last bit of Geohash. The unused bits are filled with 0. - * @param lat: latitude in Decimal Degree - * @param lon: longitude in Decimal Degree - * @param precision: In Geohash, precision is the length of hash character. - * @param hashBits: pass by reference. Function will set its value with the calculated Geohash - * @return True if encode is successful, false is encode failed due to input - */ - static bool encode( double lat, double lon, uint8_t precision, uint64_t &hashBits ); - /** - * @brief Encoding function that takes latitude and longitude and precision and output Geohash - * in String (base 32) format. - * @param lat: latitude in Decimal Degree - * @param lon: longitude in Decimal Degree - * @param precision: In Geohash, precision is the length of hash character. - * @param hashString: pass by reference. Function will set its value with the calculated Geohash - * @return True if encode is successful, false is encode failed due to input - */ - static bool encode( double lat, double lon, uint8_t precision, std::string &hashString ); - - // In GeoHash, precision is specified by the length of hash. 9 characters hash can specify a - // rectangle area of 4.77m X 4.77m. Here we defined the maximum precision as 9 characters. - static constexpr uint8_t MAX_PRECISION = 9; - -private: - // number of bits in Base32 character - static constexpr uint8_t BASE32_BITS = 5; - // minimum Latitude - static constexpr double LAT_MIN = -90.0; - // maximum Latitude - static constexpr double LAT_MAX = 90.0; - // minimum Longitude - static constexpr double LON_MIN = -180.0; - // maximum Longitude - static constexpr double LON_MAX = 180.0; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/GeohashFunctionNode.cpp b/src/GeohashFunctionNode.cpp deleted file mode 100644 index 2c378fb3..00000000 --- a/src/GeohashFunctionNode.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include "GeohashFunctionNode.h" -#include "Geohash.h" -#include "LoggingModule.h" -#include "TraceModule.h" -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -bool -GeohashFunctionNode::evaluateGeohash( double latitude, - double longitude, - uint8_t precision, - GeohashFunction::GPSUnitType gpsUnitType ) -{ - // set flag to false. It will turn true only if Geohash has been evaluated as changed at given precision. - this->mIsGeohashNew = false; - // Perform unit conversion to Decimal Degree which is the only format supported by Geohash library - latitude = convertToDecimalDegree( latitude, gpsUnitType ); - longitude = convertToDecimalDegree( longitude, gpsUnitType ); - // If precision is out of bound, we limit it to max precision supported by Geohash library - if ( precision > Geohash::MAX_PRECISION ) - { - precision = Geohash::MAX_PRECISION; - } - std::string currentGeohashString{}; - if ( Geohash::encode( latitude, longitude, Geohash::MAX_PRECISION, currentGeohashString ) ) - { - // FWE_LOG_INFO( "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 ) ) - { - // We compare the front part of string at given precision - if ( currentGeohashString.substr( 0, precision ) != - this->mGeohashInfo.mGeohashString.substr( 0, precision ) ) - { - FWE_LOG_TRACE( "Geohash has changed from " + this->mGeohashInfo.mGeohashString + " to " + - currentGeohashString + " at given precision " + std::to_string( precision ) ); - this->mIsGeohashNew = true; - } - } - else if ( !this->mGeohashInfo.hasItems() ) - { - // There's no existing Geohash, set the flag to true. One use case is first time Geohash evaluation. - this->mIsGeohashNew = true; - FWE_LOG_TRACE( "Geohash start at: " + currentGeohashString ); - } - else - { - TraceModule::get().incrementVariable( TraceVariable::GE_COMPARE_PRECISION_ERROR ); - FWE_LOG_ERROR( "Cannot compare two Geohashes as they have less precision than required" ); - } - this->mGeohashInfo.mGeohashString = currentGeohashString; - } - else - { - TraceModule::get().incrementVariable( TraceVariable::GE_EVALUATE_ERROR_LAT_LON ); - FWE_LOG_ERROR( "Unable to calculate Geohash with lat/lon: " + std::to_string( latitude ) + ", " + - std::to_string( longitude ) ); - } - return this->mIsGeohashNew; -} - -void -GeohashFunctionNode::consumeGeohash( GeohashInfo &geohashInfo ) -{ - // set the flag to be false as the geohash has been read out. - this->mIsGeohashNew = false; - geohashInfo = this->mGeohashInfo; - this->mGeohashInfo.mPrevReportedGeohashString = this->mGeohashInfo.mGeohashString; - FWE_LOG_TRACE( "Previous Geohash is updated to " + this->mGeohashInfo.mPrevReportedGeohashString ); -} - -bool -GeohashFunctionNode::hasNewGeohash() const -{ - return this->mIsGeohashNew; -} - -double -GeohashFunctionNode::convertToDecimalDegree( double value, GeohashFunction::GPSUnitType gpsUnitType ) -{ - double convertedValue = 0; - switch ( gpsUnitType ) - { - case GeohashFunction::GPSUnitType::DECIMAL_DEGREE: - convertedValue = value; - break; - case GeohashFunction::GPSUnitType::MICROARCSECOND: - convertedValue = value / 3600000000.0F; - break; - case GeohashFunction::GPSUnitType::MILLIARCSECOND: - convertedValue = value / 3600000.0F; - break; - case GeohashFunction::GPSUnitType::ARCSECOND: - convertedValue = value / 3600.0F; - break; - default: - break; - } - return convertedValue; -} - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/GeohashFunctionNode.h b/src/GeohashFunctionNode.h deleted file mode 100644 index c0f44c54..00000000 --- a/src/GeohashFunctionNode.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "GeohashInfo.h" -#include "ICollectionScheme.h" -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief This is the Geohash Function Node module that can be used as part of the AST tree to - * evaluate whether the Geohash has changed at given precision. - * - */ -class GeohashFunctionNode -{ -public: - /** - * @brief Default Destructor. - */ - ~GeohashFunctionNode() = default; - - /** - * @brief This function calculates current Geohash for the vehicle and compare it against - * the previous Geohash. - * The Geohash will always be calculated at the maximum precision defined in Geohash module. - * However, the comparison between current and previous Geohash is at the precision specified at the input. - * - * For Instance: Geohash calculated previously at 9q9hwg28j and currently at 9q9hwheb9. If the precision is - * specified as 5, the comparison would return EQUAL. If the precision is specified as 6, the comparison - * would return NOT EQUAL. - * - * @param latitude latitude from GPS - * @param longitude longitude from GPS - * @param precision In Geohash, precision is the length of hash character. - * @param gpsUnitType The GPS signal latitude / longitude unit type. The following unit type is supported: - * 1) DECIMAL DEGREE 2) MICROARCSECOND 3) MILLIARCSECOND 4) ARCSECOND - * @return True if geohash has changed at given precision. False if geohash has not changed. - */ - bool evaluateGeohash( double latitude, - double longitude, - uint8_t precision, - GeohashFunction::GPSUnitType gpsUnitType ); - - /** - * @brief Consume the latest evaluated geohash info. This function will set the mIsGeohashNew - * flag to false to avoid re-consuming the same geohash. - */ - void consumeGeohash( GeohashInfo &geohashInfo ); - - /** - * @brief return whether a new Geohash has been generated but not read (consumed) yet. - * - * @return true if a new Geohash has been evaluated but not read yet. false if no new geohash. - */ - bool hasNewGeohash() const; - -private: - /** - * @brief Utility function to convert different GPS unit to Decimal Degree - * - * @return converted GPS signal in Decimal Degree - */ - static double convertToDecimalDegree( double value, GeohashFunction::GPSUnitType gpsUnitType ); - - /** - * @brief This is the Geohash in String format holding the latest calculated geohash - */ - GeohashInfo mGeohashInfo; - - /** - * @brief If this flag is true, it indicates a Geohash has been generated but not read yet. - */ - bool mIsGeohashNew{ false }; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/GeohashInfo.h b/src/GeohashInfo.h deleted file mode 100644 index d5a3c249..00000000 --- a/src/GeohashInfo.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief This struct encapsulates the Geohash information. - * In current implementation, the Geohash is represented in String Format. - * API hasItems() indicates whether this structure contains valid Geohash - * - */ -struct GeohashInfo -{ - // Geohash in String Format - std::string mGeohashString; - - // Geohash in string format which was reported to Cloud in last update - std::string mPrevReportedGeohashString; - - // Return whether Geohash is valid to use. In string format, we consider non-zero length string - // as valid geohash - bool - hasItems() const - { - return mGeohashString.length() > 0; - } -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/IActiveCollectionSchemesListener.h b/src/IActiveCollectionSchemesListener.h deleted file mode 100644 index 80b4541e..00000000 --- a/src/IActiveCollectionSchemesListener.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once -#include "ICollectionSchemeList.h" - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief Interface for components interested in the currently active collection schemes. Used to prepare senders based - * on campaign data before the data is collected and selected for the upload. - * - */ - -struct ActiveCollectionSchemes -{ - std::vector activeCollectionSchemes; -}; - -class IActiveCollectionSchemesListener -{ -public: - /** - * @brief process the change of active collection schemes - * - * */ - virtual void onChangeCollectionSchemeList( - const std::shared_ptr &activeCollectionSchemes ) = 0; - - virtual ~IActiveCollectionSchemesListener() = default; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/IActiveConditionProcessor.h b/src/IActiveConditionProcessor.h deleted file mode 100644 index 76912a63..00000000 --- a/src/IActiveConditionProcessor.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "CollectionInspectionAPITypes.h" -#include "ICollectionScheme.h" -#include "IDecoderManifest.h" - -#include -#include -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief Interface for components interested in the currently active conditions - * - */ -class IActiveConditionProcessor -{ -public: - /** - * @brief process the change of active conditions for example by rebuilding buffers - * - * This function should be called as rarely as possible. - * All condition should fulfill the restriction like max signal id or equation depth. - * After this call all cached signal values that were not published are deleted - * @param inspectionMatrix all currently active Conditions - * @return true if valid conditions were handed over - * */ - virtual void onChangeInspectionMatrix( const std::shared_ptr &inspectionMatrix ) = 0; - - virtual ~IActiveConditionProcessor() = default; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/IActiveDecoderDictionaryListener.h b/src/IActiveDecoderDictionaryListener.h deleted file mode 100644 index 677d9f2f..00000000 --- a/src/IActiveDecoderDictionaryListener.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "IDecoderDictionary.h" - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief This is the listener interface to notify any listeners on change of Decoder Dictionary. - * - */ -class IActiveDecoderDictionaryListener -{ -public: - /** - * @brief default destructor - */ - virtual ~IActiveDecoderDictionaryListener() = default; - - /** - * @brief The callback function used to notify any listeners on change of Decoder Dictionary - * - * @param dictionary const shared pointer pointing to a constant decoder dictionary - * @param networkProtocol network protocol type indicating which type of decoder dictionary it's updating - * @return None - */ - virtual void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) = 0; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/ICollectionScheme.h b/src/ICollectionScheme.h index b7b31804..dff9d0e2 100644 --- a/src/ICollectionScheme.h +++ b/src/ICollectionScheme.h @@ -63,7 +63,7 @@ struct CanFrameCollectionInfo * @brief The Interface Id specified by the Decoder Manifest. This will contain the physical channel * id of the hardware CAN Bus the frame is present on. */ - CANInterfaceID interfaceID{ INVALID_CAN_INTERFACE_ID }; + InterfaceID interfaceID{ INVALID_INTERFACE_ID }; /** * @brief Ring buffer size used to store these sampled CAN frames. One CAN Frame is a sample. @@ -81,9 +81,8 @@ struct CanFrameCollectionInfo enum class ExpressionNodeType { FLOAT = 0, - SIGNAL, // Node_Signal_ID - WINDOWFUNCTION, // NodeFunction - GEOHASHFUNCTION, // GEOHASH + SIGNAL, // Node_Signal_ID + WINDOWFUNCTION, // NodeFunction BOOLEAN, OPERATOR_SMALLER, // NodeOperator OPERATOR_BIGGER, @@ -111,25 +110,8 @@ enum class WindowFunction NONE }; -struct GeohashFunction -{ - enum class GPSUnitType - { - DECIMAL_DEGREE = 0, - MICROARCSECOND, - MILLIARCSECOND, - ARCSECOND, - MAX - }; - SignalID latitudeSignalID{ 0 }; - SignalID longitudeSignalID{ 0 }; - uint8_t precision{ 0 }; - GPSUnitType gpsUnitType{ GPSUnitType::DECIMAL_DEGREE }; -}; - struct ExpressionFunction { - GeohashFunction geohashFunction; WindowFunction windowFunction{ WindowFunction::NONE }; }; @@ -273,12 +255,9 @@ class ICollectionScheme const uint32_t INVALID_MINIMUM_PUBLISH_TIME = std::numeric_limits::max(); const uint32_t INVALID_AFTER_TRIGGER_DURATION = std::numeric_limits::max(); const uint32_t INVALID_PRIORITY_LEVEL = std::numeric_limits::max(); - const double INVALID_PROBABILITY_TO_SEND = 0.0; const std::string INVALID_COLLECTION_SCHEME_ID = std::string(); const std::string INVALID_DECODER_MANIFEST_ID = std::string(); - const double DEFAULT_PROBABILITY_TO_SEND = 1.0; - /** * @brief indicates if the decoder manifest is prepared to be used for example by calling getters * @@ -354,13 +333,6 @@ class ICollectionScheme */ virtual bool isTriggerOnlyOnRisingEdge() const = 0; - /** - * @brief At which probability should the triggered and collected data be sent out - * - * @return double 0: send never, send always - */ - virtual double getProbabilityToSend() const = 0; - /** * @brief get priority which is used by the offboard offboardconnectivity module * A smaller value collectionScheme has more priority (takes precedence) over larger values diff --git a/src/ICollectionSchemeList.h b/src/ICollectionSchemeList.h index ce63b324..2275dc1e 100644 --- a/src/ICollectionSchemeList.h +++ b/src/ICollectionSchemeList.h @@ -76,5 +76,18 @@ class ICollectionSchemeList virtual ~ICollectionSchemeList() = default; }; +using ICollectionSchemeListPtr = std::shared_ptr; + +/** + * @brief Interface for components interested in the currently active collection schemes. Used to prepare senders based + * on campaign data before the data is collected and selected for the upload. + * + */ + +struct ActiveCollectionSchemes +{ + std::vector activeCollectionSchemes; +}; + } // namespace IoTFleetWise } // namespace Aws diff --git a/src/ICollectionSchemeManager.h b/src/ICollectionSchemeManager.h index f98e06f5..4780d3a1 100644 --- a/src/ICollectionSchemeManager.h +++ b/src/ICollectionSchemeManager.h @@ -5,8 +5,9 @@ #include "CacheAndPersist.h" #include "CollectionInspectionAPITypes.h" -#include "CollectionSchemeManagementListener.h" #include "ICollectionScheme.h" +#include "IDecoderManifest.h" + namespace Aws { namespace IoTFleetWise diff --git a/src/IDataReadyToPublishListener.h b/src/IDataReadyToPublishListener.h deleted file mode 100644 index 87863b09..00000000 --- a/src/IDataReadyToPublishListener.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -namespace Aws -{ -namespace IoTFleetWise -{ - -class IDataReadyToPublishListener -{ -public: - virtual ~IDataReadyToPublishListener() = default; - - /** - * @brief New data in CollectedDataReadyToPublish queue that can be published to cloud - */ - virtual void onDataReadyToPublish() = 0; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/IDecoderDictionary.h b/src/IDecoderDictionary.h index 01865c81..1f4293f3 100644 --- a/src/IDecoderDictionary.h +++ b/src/IDecoderDictionary.h @@ -99,7 +99,7 @@ const uint32_t MAX_COMPLEX_TYPES = 5000; struct ComplexDataDecoderDictionary : DecoderDictionary { using ComplexDataDecoderMethodType = - std::unordered_map>; + std::unordered_map>; ComplexDataDecoderDictionary() = default; ComplexDataDecoderDictionary( ComplexDataDecoderMethodType complexMsgDecoderMethod, diff --git a/src/IDecoderManifest.h b/src/IDecoderManifest.h index e9c9f86a..4feef586 100644 --- a/src/IDecoderManifest.h +++ b/src/IDecoderManifest.h @@ -140,7 +140,7 @@ struct PIDSignalDecoderFormat struct ComplexSignalDecoderFormat { - ComplexDataInterfaceId mInterfaceId; + InterfaceID mInterfaceId; /* * Interface-specific message information. The pair interface_id and message_id should be unique across all @@ -203,7 +203,7 @@ class IDecoderManifest * @return if can frame id can't be found a CANMessageFormat equal to INVALID_CAN_MESSAGE_FORMAT * is returned */ - virtual const CANMessageFormat &getCANMessageFormat( CANRawFrameID canID, CANInterfaceID interfaceID ) const = 0; + virtual const CANMessageFormat &getCANMessageFormat( CANRawFrameID canID, InterfaceID interfaceID ) const = 0; /** * @brief get the can frame that contains the signal @@ -211,7 +211,7 @@ class IDecoderManifest * * @return if no can and can interface ids can be found invalid ids are returned */ - virtual std::pair getCANFrameAndInterfaceID( SignalID signalID ) const = 0; + virtual std::pair getCANFrameAndInterfaceID( SignalID signalID ) const = 0; /** * @brief Get the Vehicle Data Source Protocol for this Signal @@ -276,5 +276,7 @@ class IDecoderManifest virtual ~IDecoderManifest() = default; }; +using IDecoderManifestPtr = std::shared_ptr; + } // namespace IoTFleetWise } // namespace Aws diff --git a/src/IReceiver.h b/src/IReceiver.h index c9438a60..177eff9f 100644 --- a/src/IReceiver.h +++ b/src/IReceiver.h @@ -5,45 +5,65 @@ #include "IConnectionTypes.h" #include "Listener.h" +#include "TimeTypes.h" +#include +#include namespace Aws { namespace IoTFleetWise { -/** - * @brief Receiver must inherit from IReceiverCallback - * @see IReceiver - */ -struct IReceiverCallback +struct ReceivedChannelMessage { - virtual ~IReceiverCallback() = default; + /* + * Pointer to raw received data that will be at least size long. + * The function does not care if the data is a c string, a json or a binary + * data stream like proto buf. The pointer is invalid after the function returned + */ + const std::uint8_t *buf; - /** - * @brief called after new data received - * - * Be cautious the callback onDataReceived will happen from a different thread and the callee - * needs to ensure that the data is treated in a thread safe manner when copying it. - * The function behind onDataReceived must be fast (<1ms) and the pointer buf will get - * invalid after returning from onDataReceived. - * - * @param buf pointer to raw received data that will be at least size long. - * The function does not care if the data is a c string, a json or a binary - * data stream like proto buf. The pointer is invalid after the function returned - * @param size number of accessible bytes in buf + /* + * Number of accessible bytes in buf + */ + size_t size{ 0 }; + + /* + * Key/value pairs that were received together with the data. It might be empty. + */ + const std::unordered_map &properties; + + /* + * Absolute MQTT message expiry time since epoch from a monotonic clock. */ - virtual void onDataReceived( const std::uint8_t *buf, size_t size ) = 0; + Timestamp messageExpiryMonotonicTimeSinceEpochMs{ 0 }; }; +/** + * @brief called after new data received + * + * Be cautious the callback onDataReceived will happen from a different thread and the callee + * needs to ensure that the data is treated in a thread safe manner when copying it. + * The function behind onDataReceived must be fast (<1ms) and the pointer buf will get + * invalid after returning from the callback. + * + * @param receivedChannelMessage struct containing message data and metadata + */ +using OnDataReceivedCallback = std::function; + +// Define some common property names to make it easier for subscribers to extract the properties they +// are interested in when the callback is called. +constexpr auto PROPERTY_NAME_CORRELATION_DATA = "correlation-data"; + /** * @brief This interface will be used by all objects receiving data from the cloud * * The configuration will done by the bootstrap with the implementing class. - * To register an IReceiverCallback use the subscribeListener inherited from ThreadListeners. + * To register an IReceiverCallback use the subscribeToDataReceived method. * \code{.cpp} * class ExampleReceiver:IReceiverCallback { * startReceiving(IReceiver &r) { - * r.subscribeListener(this); + * r.subscribeToDataReceived(this); * } * onDataReceived( std::uint8_t *buf, size_t size ) { * // copy buf if needed @@ -52,11 +72,11 @@ struct IReceiverCallback * \endcode * @see IReceiverCallback */ -class IReceiver : public ThreadListeners +class IReceiver { public: - ~IReceiver() override = default; + ~IReceiver() = default; /** * @brief indicates if the connection is established and authenticated * @@ -64,6 +84,12 @@ class IReceiver : public ThreadListeners * of this interface do not need to call it * */ virtual bool isAlive() = 0; + + /** + * @brief Register a callback to be called after new data received + * @param callback The function that will be called each time new data is received + */ + virtual void subscribeToDataReceived( OnDataReceivedCallback callback ) = 0; }; } // namespace IoTFleetWise diff --git a/src/IWaveGpsSource.cpp b/src/IWaveGpsSource.cpp index d1f0ec25..21e80031 100644 --- a/src/IWaveGpsSource.cpp +++ b/src/IWaveGpsSource.cpp @@ -58,8 +58,9 @@ detectQuectelDevice() it != boost::filesystem::directory_iterator(); ++it ) { - if ( !boost::filesystem::is_directory( *it ) || !boost::filesystem::exists( it->path().string() + "/uevent" ) || - !boost::filesystem::exists( it->path().string() + "/" + DEFAULT_NMEA_SOURCE ) ) + if ( ( !boost::filesystem::is_directory( *it ) ) || + ( !boost::filesystem::exists( it->path().string() + "/uevent" ) ) || + ( !boost::filesystem::exists( it->path().string() + "/" + DEFAULT_NMEA_SOURCE ) ) ) { continue; } diff --git a/src/InspectionEventListener.h b/src/InspectionEventListener.h deleted file mode 100644 index bbfccfcc..00000000 --- a/src/InspectionEventListener.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** - * @brief Metadata representing an event of interest. - * An event is an entity that represents a point in time when something has happened and - * requires AWS IoT FleetWise to collect data for the period of time before and after its - * occurrence. The Metadata consists of ( but not limited, and thus can be extended ) : - * - * @param eventID Unique identifier of the event as a string, unique across the system and - * unique also after resets. The timestamp of this event itself is implicit and is equal to the - * time of reception of this notification. - * @param sourceID Unique identifier of the source from which the data should be collected. - * This can be for example the source name ( e.g. CAN0 ), an IP address of a camera or - * any other unique identifier that is known as a source of vehicle data across the system. - * @param negativeOffsetMs amount of time in milliseconds before the event happened. - * @param positiveOffsetMs amount of time in milliseconds after the event happened. - */ -struct EventMetadata - -{ - EventMetadata() = default; - EventMetadata( const uint32_t &evID, const uint32_t &srcID, const uint32_t &negOff, const uint32_t &posOff ) - : eventID( evID ) - , sourceID( srcID ) - , negativeOffsetMs( negOff ) - , positiveOffsetMs( posOff ) - { - } - uint32_t eventID{ 0 }; - uint32_t sourceID{ 0 }; - uint32_t negativeOffsetMs{ 0 }; - uint32_t positiveOffsetMs{ 0 }; -}; - -class InspectionEventListener -{ - -public: - virtual ~InspectionEventListener() = default; - - /** - * @brief Notification raised when an event of interest is detected by the Inspection - * Engine during the incoming data evaluation. During evaluation, the inspection engine uses - * the inspection matrix metadata to extract the time span to be applied by this type of events - * Listeners to this notification are free to utilise this notification in the way - * it's appropriate i.e. this is a fire and forget. The timestamp of the event occurrence is implicit - * and is the time of this notification. - * @param eventMetadata vector of EventMetadata consisting of: - * - eventID unique identifier of the event ( persist across reboots ) - * - negativeOffsetMs amount of time in milliseconds before the event occurrence. - * - positiveOffsetMs amount of time in milliseconds after the event occurrence. - * - sourceID this is the identifier of the device to which this event should be forwarded. - */ - virtual void onEventOfInterestDetected( const std::vector &eventMetadata ) = 0; -}; - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/src/InspectionMatrixExtractor.cpp b/src/InspectionMatrixExtractor.cpp index 540846f7..f7f66170 100644 --- a/src/InspectionMatrixExtractor.cpp +++ b/src/InspectionMatrixExtractor.cpp @@ -54,7 +54,7 @@ CollectionSchemeManager::updateRawDataBufferConfig( if ( interface != complexDataDecoderDictionary->complexMessageDecoderMethod.end() ) { auto complexDataMessage = std::find_if( - interface->second.begin(), interface->second.end(), [signalId]( const auto &pair ) { + interface->second.begin(), interface->second.end(), [signalId]( const auto &pair ) -> bool { return pair.second.mSignalId == signalId; } ); if ( complexDataMessage != interface->second.end() ) @@ -78,7 +78,6 @@ CollectionSchemeManager::addConditionData( const ICollectionSchemePtr &collectio conditionData.afterDuration = collectionScheme->getAfterDurationMs(); conditionData.includeActiveDtcs = collectionScheme->isActiveDTCsIncluded(); conditionData.triggerOnlyOnRisingEdge = collectionScheme->isTriggerOnlyOnRisingEdge(); - conditionData.probabilityToSend = collectionScheme->getProbabilityToSend(); /* * use for loop to copy signalInfo and CANframe over to avoid error or memory issue @@ -215,8 +214,7 @@ CollectionSchemeManager::inspectionMatrixExtractor( const std::shared_ptr &inspectionMatrix ) { - notifyListeners &>( - &IActiveConditionProcessor::onChangeInspectionMatrix, inspectionMatrix ); + mInspectionMatrixChangeListeners.notify( inspectionMatrix ); } } // namespace IoTFleetWise diff --git a/src/IoTFleetWiseConfig.cpp b/src/IoTFleetWiseConfig.cpp index 66c84789..c6570f8b 100644 --- a/src/IoTFleetWiseConfig.cpp +++ b/src/IoTFleetWiseConfig.cpp @@ -2,13 +2,252 @@ // SPDX-License-Identifier: Apache-2.0 #include "IoTFleetWiseConfig.h" +#include #include +#include +#include namespace Aws { namespace IoTFleetWise { +IoTFleetWiseConfig::IoTFleetWiseConfig( const Json::Value &config ) + : mConfig( config ) +{ +} + +IoTFleetWiseConfig::IoTFleetWiseConfig( const Json::Value &config, std::string path ) + : mConfig( config ) + , mPath( std::move( path ) ) +{ +} + +IoTFleetWiseConfig +IoTFleetWiseConfig::operator[]( unsigned index ) const +{ + return IoTFleetWiseConfig( mConfig[index], mPath + "[" + std::to_string( index ) + "]" ); +} + +IoTFleetWiseConfig +IoTFleetWiseConfig::operator[]( const std::string &key ) const +{ + return IoTFleetWiseConfig( mConfig[key], mPath + "." + key ); +} + +std::string +IoTFleetWiseConfig::getValueString() const +{ + return ( mConfig.isObject() || mConfig.isArray() ) ? "" : "'" + mConfig.asString() + "' "; +} + +std::string +IoTFleetWiseConfig::asStringRequired() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( !mConfig.isString() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a string at " + mPath ); + } + return mConfig.asString(); +} + +boost::optional +IoTFleetWiseConfig::asStringOptional() const +{ + if ( mConfig.isNull() ) + { + return boost::none; + } + if ( !mConfig.isString() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a string at " + mPath ); + } + return boost::make_optional( mConfig.asString() ); +} + +uint32_t +IoTFleetWiseConfig::asU32Required() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( !mConfig.isUInt() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid uint32 at " + mPath ); + } + return mConfig.asUInt(); +} + +boost::optional +IoTFleetWiseConfig::asU32Optional() const +{ + if ( mConfig.isNull() ) + { + return boost::none; + } + if ( !mConfig.isUInt() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid uint32 at " + mPath ); + } + return boost::make_optional( mConfig.asUInt() ); +} + +uint64_t +IoTFleetWiseConfig::asU64Required() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( !mConfig.isUInt64() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid uint64 at " + mPath ); + } + return mConfig.asUInt64(); +} + +boost::optional +IoTFleetWiseConfig::asU64Optional() const +{ + if ( mConfig.isNull() ) + { + return boost::none; + } + if ( !mConfig.isUInt64() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid uint64 at " + mPath ); + } + return boost::make_optional( mConfig.asUInt64() ); +} + +uint32_t +IoTFleetWiseConfig::asU32FromStringRequired() const +{ + auto value = asStringRequired(); + try + { + return static_cast( std::stoul( value, nullptr, 0 ) ); + } + catch ( ... ) + { + throw std::runtime_error( "Could not convert '" + value + "' to uint32 for config value at " + mPath ); + } +} + +boost::optional +IoTFleetWiseConfig::asU32FromStringOptional() const +{ + auto value = asStringOptional(); + if ( !value.has_value() ) + { + return boost::none; + } + try + { + return boost::make_optional( static_cast( std::stoul( value.get(), nullptr, 0 ) ) ); + } + catch ( ... ) + { + throw std::runtime_error( "Could not convert '" + value.get() + "' to uint32 for config value at " + mPath ); + } +} + +size_t +IoTFleetWiseConfig::asSizeRequired() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( sizeof( size_t ) >= sizeof( uint64_t ) ? !mConfig.isUInt64() : !mConfig.isUInt() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid size at " + mPath ); + } + return sizeof( size_t ) >= sizeof( uint64_t ) ? mConfig.asUInt64() : mConfig.asUInt(); +} + +boost::optional +IoTFleetWiseConfig::asSizeOptional() const +{ + if ( mConfig.isNull() ) + { + return boost::none; + } + if ( sizeof( size_t ) >= sizeof( uint64_t ) ? !mConfig.isUInt64() : !mConfig.isUInt() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a valid size at " + mPath ); + } + return boost::make_optional( + static_cast( sizeof( size_t ) >= sizeof( uint64_t ) ? mConfig.asUInt64() : mConfig.asUInt() ) ); +} + +bool +IoTFleetWiseConfig::asBoolRequired() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( !mConfig.isBool() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a bool at " + mPath ); + } + return mConfig.asBool(); +} + +boost::optional +IoTFleetWiseConfig::asBoolOptional() const +{ + if ( mConfig.isNull() ) + { + return boost::none; + } + if ( !mConfig.isBool() ) + { + throw std::runtime_error( "Config value " + getValueString() + "is not a bool at " + mPath ); + } + return boost::make_optional( mConfig.asBool() ); +} + +bool +IoTFleetWiseConfig::isMember( const std::string &key ) const +{ + return mConfig.isMember( key ); +} + +unsigned int +IoTFleetWiseConfig::getArraySizeRequired() const +{ + if ( mConfig.isNull() ) + { + throw std::runtime_error( "Config value missing at " + mPath ); + } + if ( !mConfig.isArray() ) + { + throw std::runtime_error( "Config value is not an array at " + mPath ); + } + return mConfig.size(); +} + +unsigned int +IoTFleetWiseConfig::getArraySizeOptional() const +{ + if ( mConfig.isNull() ) + { + return 0; + } + if ( !mConfig.isArray() ) + { + throw std::runtime_error( "Config value is not an array at " + mPath ); + } + return mConfig.size(); +} + bool IoTFleetWiseConfig::read( const std::string &filename, Json::Value &config ) { diff --git a/src/IoTFleetWiseConfig.h b/src/IoTFleetWiseConfig.h index ffebd0b1..932cea7d 100644 --- a/src/IoTFleetWiseConfig.h +++ b/src/IoTFleetWiseConfig.h @@ -3,6 +3,9 @@ #pragma once +#include +#include +#include #include #include @@ -16,10 +19,41 @@ namespace IoTFleetWise class IoTFleetWiseConfig { public: - IoTFleetWiseConfig() = delete; + IoTFleetWiseConfig( const Json::Value &config ); + ~IoTFleetWiseConfig() = default; static bool read( const std::string &filename, Json::Value &config ); + IoTFleetWiseConfig operator[]( unsigned index ) const; + IoTFleetWiseConfig operator[]( const std::string &key ) const; + + std::string asStringRequired() const; + boost::optional asStringOptional() const; + + uint32_t asU32Required() const; + boost::optional asU32Optional() const; + + uint64_t asU64Required() const; + boost::optional asU64Optional() const; + + uint32_t asU32FromStringRequired() const; + boost::optional asU32FromStringOptional() const; + + size_t asSizeRequired() const; + boost::optional asSizeOptional() const; + + bool asBoolRequired() const; + boost::optional asBoolOptional() const; + + bool isMember( const std::string &key ) const; + + unsigned int getArraySizeRequired() const; + unsigned int getArraySizeOptional() const; + private: + IoTFleetWiseConfig( const Json::Value &config, std::string path ); + const Json::Value &mConfig; + std::string mPath; + std::string getValueString() const; }; } // namespace IoTFleetWise diff --git a/src/IoTFleetWiseEngine.cpp b/src/IoTFleetWiseEngine.cpp index 4e4e02b6..cae09fbb 100644 --- a/src/IoTFleetWiseEngine.cpp +++ b/src/IoTFleetWiseEngine.cpp @@ -6,11 +6,9 @@ #include "AwsIotConnectivityModule.h" #include "AwsSDKMemoryManager.h" #include "CollectionInspectionAPITypes.h" -#include "CollectionSchemeManagementListener.h" #include "DataSenderManager.h" -#include "IActiveConditionProcessor.h" -#include "IActiveDecoderDictionaryListener.h" #include "ILogger.h" +#include "IoTFleetWiseConfig.h" #include "LogLevel.h" #include "LoggingModule.h" #include "MqttClientWrapper.h" @@ -20,14 +18,13 @@ #include #include #include +#include #include #include #include +#include #include -#if defined( FWE_FEATURE_IWAVE_GPS ) || defined( FWE_FEATURE_EXTERNAL_GPS ) -#include -#endif #ifdef FWE_FEATURE_GREENGRASSV2 #include "AwsGGConnectivityModule.h" #ifdef FWE_FEATURE_VISION_SYSTEM_DATA @@ -37,16 +34,12 @@ #ifdef FWE_FEATURE_VISION_SYSTEM_DATA #include "Credentials.h" #include "DataSenderIonWriter.h" -#include "IActiveCollectionSchemesListener.h" #include "RawDataManager.h" #include "TransferManagerWrapper.h" #include #include #include #include -#include -#include -#include #endif namespace Aws @@ -54,12 +47,22 @@ namespace Aws namespace IoTFleetWise { +static constexpr uint64_t DEFAULT_RETRY_UPLOAD_PERSISTED_INTERVAL_MS = 10000; static const std::string CAN_INTERFACE_TYPE = "canInterface"; static const std::string EXTERNAL_CAN_INTERFACE_TYPE = "externalCanInterface"; static const std::string OBD_INTERFACE_TYPE = "obdInterface"; #ifdef FWE_FEATURE_ROS2 static const std::string ROS2_INTERFACE_TYPE = "ros2Interface"; #endif +#ifdef FWE_FEATURE_IWAVE_GPS +static const std::string CONFIG_SECTION_IWAVE_GPS = "iWaveGpsExample"; +#endif +#ifdef FWE_FEATURE_EXTERNAL_GPS +static const std::string CONFIG_SECTION_EXTERNAL_GPS = "externalGpsExample"; +#endif +#ifdef FWE_FEATURE_AAOS_VHAL +static const std::string CONFIG_SECTION_AAOS_VHAL = "aaosVhalExample"; +#endif namespace { @@ -87,30 +90,6 @@ getFileContents( const std::string &p ) return ret; } -#if defined( FWE_FEATURE_IWAVE_GPS ) || defined( FWE_FEATURE_EXTERNAL_GPS ) -uint32_t -stringToU32( const std::string &value ) -{ - try - { - return static_cast( std::stoul( value ) ); - } - catch ( const std::exception &e ) - { - throw std::runtime_error( "Could not cast " + value + - " to integer, invalid input: " + std::string( e.what() ) ); - } -} -#endif - -#ifdef FWE_FEATURE_VISION_SYSTEM_DATA -size_t -getJsonValueAsSize( const Json::Value &jsonValue ) -{ - return sizeof( size_t ) >= sizeof( uint64_t ) ? jsonValue.asUInt64() : jsonValue.asUInt(); -} -#endif - } // namespace IoTFleetWiseEngine::IoTFleetWiseEngine() @@ -129,46 +108,45 @@ IoTFleetWiseEngine::~IoTFleetWiseEngine() } bool -IoTFleetWiseEngine::connect( const Json::Value &config ) +IoTFleetWiseEngine::connect( const Json::Value &jsonConfig ) { // Main bootstrap sequence. try { - const auto persistencyPath = config["staticConfig"]["persistency"]["persistencyPath"].asString(); + IoTFleetWiseConfig config( jsonConfig ); + const auto persistencyPath = config["staticConfig"]["persistency"]["persistencyPath"].asStringRequired(); /*************************Payload Manager and Persistency library bootstrap begin*********/ - // Create an object for Persistency mPersistDecoderManifestCollectionSchemesAndData = std::make_shared( - persistencyPath, config["staticConfig"]["persistency"]["persistencyPartitionMaxSize"].asInt() ); + persistencyPath, config["staticConfig"]["persistency"]["persistencyPartitionMaxSize"].asSizeRequired() ); if ( !mPersistDecoderManifestCollectionSchemesAndData->init() ) { FWE_LOG_ERROR( "Failed to init persistency library" ); } - uint64_t persistencyUploadRetryIntervalMs = DEFAULT_RETRY_UPLOAD_PERSISTED_INTERVAL_MS; - if ( config["staticConfig"]["persistency"].isMember( "persistencyUploadRetryIntervalMs" ) ) - { - persistencyUploadRetryIntervalMs = static_cast( - config["staticConfig"]["persistency"]["persistencyUploadRetryIntervalMs"].asInt() ); - } + uint64_t persistencyUploadRetryIntervalMs = + config["staticConfig"]["persistency"]["persistencyUploadRetryIntervalMs"].asU64Optional().get_value_or( + DEFAULT_RETRY_UPLOAD_PERSISTED_INTERVAL_MS ); // Payload Manager for offline data management mPayloadManager = std::make_shared( mPersistDecoderManifestCollectionSchemesAndData ); /*************************Payload Manager and Persistency library bootstrap end************/ /*************************CAN InterfaceID to InternalID Translator begin*********/ - for ( const auto &interfaceName : config["networkInterfaces"] ) + for ( unsigned i = 0; i < config["networkInterfaces"].getArraySizeRequired(); i++ ) { - if ( ( interfaceName["type"].asString() == CAN_INTERFACE_TYPE ) || - ( interfaceName["type"].asString() == EXTERNAL_CAN_INTERFACE_TYPE ) ) + auto networkInterface = config["networkInterfaces"][i]; + auto networkInterfaceType = networkInterface["type"].asStringRequired(); + if ( ( networkInterfaceType == CAN_INTERFACE_TYPE ) || + ( networkInterfaceType == EXTERNAL_CAN_INTERFACE_TYPE ) ) { - mCANIDTranslator.add( interfaceName["interfaceId"].asString() ); + mCANIDTranslator.add( networkInterface["interfaceId"].asStringRequired() ); } } #ifdef FWE_FEATURE_IWAVE_GPS - if ( config["staticConfig"].isMember( "iWaveGpsExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_IWAVE_GPS ) ) { - mCANIDTranslator.add( - config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::CAN_CHANNEL_NUMBER].asString() ); + mCANIDTranslator.add( config["staticConfig"][CONFIG_SECTION_IWAVE_GPS][IWaveGpsSource::CAN_CHANNEL_NUMBER] + .asStringRequired() ); } else { @@ -176,10 +154,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } #endif #ifdef FWE_FEATURE_EXTERNAL_GPS - if ( config["staticConfig"].isMember( "externalGpsExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_EXTERNAL_GPS ) ) { mCANIDTranslator.add( - config["staticConfig"]["externalGpsExample"][ExternalGpsSource::CAN_CHANNEL_NUMBER].asString() ); + config["staticConfig"][CONFIG_SECTION_EXTERNAL_GPS][ExternalGpsSource::CAN_CHANNEL_NUMBER] + .asStringRequired() ); } else { @@ -187,10 +166,10 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } #endif #ifdef FWE_FEATURE_AAOS_VHAL - if ( config["staticConfig"].isMember( "aaosVhalExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_AAOS_VHAL ) ) { - mCANIDTranslator.add( - config["staticConfig"]["aaosVhalExample"][AaosVhalSource::CAN_CHANNEL_NUMBER].asString() ); + mCANIDTranslator.add( config["staticConfig"][CONFIG_SECTION_AAOS_VHAL][AaosVhalSource::CAN_CHANNEL_NUMBER] + .asStringRequired() ); } else { @@ -206,7 +185,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( config["staticConfig"]["internalParameters"].isMember( "maximumAwsSdkHeapMemoryBytes" ) ) { maxAwsSdkHeapMemoryBytes = - config["staticConfig"]["internalParameters"]["maximumAwsSdkHeapMemoryBytes"].asUInt(); + config["staticConfig"]["internalParameters"]["maximumAwsSdkHeapMemoryBytes"].asSizeRequired(); if ( ( maxAwsSdkHeapMemoryBytes != 0U ) && AwsSDKMemoryManager::getInstance().setLimit( maxAwsSdkHeapMemoryBytes ) ) { @@ -223,54 +202,45 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) FWE_LOG_TRACE( "Maximum AWS SDK Heap Memory Bytes will use default value" ); } -#ifdef FWE_FEATURE_GREENGRASSV2 - if ( config["staticConfig"]["mqttConnection"]["connectionType"].asString() == "iotGreengrassV2" ) - { - FWE_LOG_INFO( "ConnectionType is iotGreengrassV2" ) - mConnectivityModule = std::make_shared( bootstrapPtr ); -#ifdef FWE_FEATURE_VISION_SYSTEM_DATA - mAwsCredentialsProvider = std::make_shared(); -#endif - } - else -#endif + auto mqttConfig = config["staticConfig"]["mqttConnection"]; + auto clientId = mqttConfig["clientId"].asStringRequired(); + std::string connectionType = mqttConfig["connectionType"].asStringOptional().get_value_or( "iotCore" ); + + if ( connectionType == "iotCore" ) { std::string privateKey; std::string certificate; std::string rootCA; - FWE_LOG_INFO( "ConnectionType is iotCore " + - config["staticConfig"]["mqttConnection"]["connectionType"].asString() ) + FWE_LOG_INFO( "ConnectionType is iotCore" ); // fetch connection parameters from config - if ( config["staticConfig"]["mqttConnection"].isMember( "privateKey" ) ) + if ( mqttConfig.isMember( "privateKey" ) ) { - privateKey = config["staticConfig"]["mqttConnection"]["privateKey"].asString(); + privateKey = mqttConfig["privateKey"].asStringRequired(); } - else if ( config["staticConfig"]["mqttConnection"].isMember( "privateKeyFilename" ) ) + else if ( mqttConfig.isMember( "privateKeyFilename" ) ) { - privateKey = - getFileContents( config["staticConfig"]["mqttConnection"]["privateKeyFilename"].asString() ); + privateKey = getFileContents( mqttConfig["privateKeyFilename"].asStringRequired() ); } - if ( config["staticConfig"]["mqttConnection"].isMember( "certificate" ) ) + if ( mqttConfig.isMember( "certificate" ) ) { - certificate = config["staticConfig"]["mqttConnection"]["certificate"].asString(); + certificate = mqttConfig["certificate"].asStringRequired(); } - else if ( config["staticConfig"]["mqttConnection"].isMember( "certificateFilename" ) ) + else if ( mqttConfig.isMember( "certificateFilename" ) ) { - certificate = - getFileContents( config["staticConfig"]["mqttConnection"]["certificateFilename"].asString() ); + certificate = getFileContents( mqttConfig["certificateFilename"].asStringRequired() ); } - if ( config["staticConfig"]["mqttConnection"].isMember( "rootCA" ) ) + if ( mqttConfig.isMember( "rootCA" ) ) { - rootCA = config["staticConfig"]["mqttConnection"]["rootCA"].asString(); + rootCA = mqttConfig["rootCA"].asStringRequired(); } - else if ( config["staticConfig"]["mqttConnection"].isMember( "rootCAFilename" ) ) + else if ( mqttConfig.isMember( "rootCAFilename" ) ) { - rootCA = getFileContents( config["staticConfig"]["mqttConnection"]["rootCAFilename"].asString() ); + rootCA = getFileContents( mqttConfig["rootCAFilename"].asStringRequired() ); } // coverity[autosar_cpp14_a20_8_5_violation] - can't use make_unique as the constructor is private auto builder = std::unique_ptr( Aws::Iot::Mqtt5ClientBuilder::NewMqtt5ClientBuilderWithMtlsFromMemory( - config["staticConfig"]["mqttConnection"]["endpointUrl"].asString().c_str(), + mqttConfig["endpointUrl"].asStringRequired().c_str(), Crt::ByteCursorFromCString( certificate.c_str() ), Crt::ByteCursorFromCString( privateKey.c_str() ) ) ); @@ -280,6 +250,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) FWE_LOG_ERROR( "Failed to setup mqtt5 client builder with error code " + std::to_string( Aws::Crt::LastError() ) + ": " + Aws::Crt::ErrorDebugString( Aws::Crt::LastError() ) ); + return false; } else { @@ -287,112 +258,103 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) builderWrapper = std::make_unique( std::move( builder ) ); } - mConnectivityModule = std::make_shared( - rootCA, config["staticConfig"]["mqttConnection"]["clientId"].asString(), std::move( builderWrapper ) ); + mConnectivityModule = + std::make_shared( rootCA, clientId, std::move( builderWrapper ) ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA if ( config["staticConfig"].isMember( "credentialsProvider" ) ) { auto crtCredentialsProvider = createX509CredentialsProvider( bootstrapPtr, - config["staticConfig"]["mqttConnection"]["clientId"].asString(), + clientId, privateKey, certificate, - config["staticConfig"]["credentialsProvider"]["endpointUrl"].asString(), - config["staticConfig"]["credentialsProvider"]["roleAlias"].asString() ); + config["staticConfig"]["credentialsProvider"]["endpointUrl"].asStringRequired(), + config["staticConfig"]["credentialsProvider"]["roleAlias"].asStringRequired() ); mAwsCredentialsProvider = std::make_shared( crtCredentialsProvider ); } #endif } +#ifdef FWE_FEATURE_GREENGRASSV2 + else if ( connectionType == "iotGreengrassV2" ) + { + FWE_LOG_INFO( "ConnectionType is iotGreengrassV2" ); + mConnectivityModule = std::make_shared( bootstrapPtr ); +#ifdef FWE_FEATURE_VISION_SYSTEM_DATA + mAwsCredentialsProvider = std::make_shared(); +#endif + } +#endif + else + { + FWE_LOG_ERROR( "Unknown connection type: " + connectionType ); + return false; + } // Only CAN data channel needs a payloadManager object for persistency and compression support, // for other components this will be nullptr - mConnectivityChannelSendVehicleData = mConnectivityModule->createNewChannel( - mPayloadManager, config["staticConfig"]["mqttConnection"]["canDataTopic"].asString() ); + mConnectivityChannelSendVehicleData = + mConnectivityModule->createNewChannel( mPayloadManager, mqttConfig["canDataTopic"].asStringRequired() ); mConnectivityChannelReceiveCollectionSchemeList = mConnectivityModule->createNewChannel( - nullptr, config["staticConfig"]["mqttConnection"]["collectionSchemeListTopic"].asString(), true ); + nullptr, mqttConfig["collectionSchemeListTopic"].asStringRequired(), true ); mConnectivityChannelReceiveDecoderManifest = mConnectivityModule->createNewChannel( - nullptr, config["staticConfig"]["mqttConnection"]["decoderManifestTopic"].asString(), true ); + nullptr, mqttConfig["decoderManifestTopic"].asStringRequired(), true ); /* * Over this channel metrics like performance (resident ram pages, cpu time spent in threads) * and tracing metrics like internal variables and time spent in specially instrumented functions * spent are uploaded in json format over mqtt. */ - if ( config["staticConfig"]["mqttConnection"]["metricsUploadTopic"].asString().length() > 0 ) + auto metricsUploadTopic = mqttConfig["metricsUploadTopic"].asStringOptional().get_value_or( "" ); + if ( !metricsUploadTopic.empty() ) { - mConnectivityChannelMetricsUpload = mConnectivityModule->createNewChannel( - nullptr, config["staticConfig"]["mqttConnection"]["metricsUploadTopic"].asString() ); + mConnectivityChannelMetricsUpload = mConnectivityModule->createNewChannel( nullptr, metricsUploadTopic ); } /* * Over this channel log messages that are currently logged to STDOUT are uploaded in json * format over MQTT. */ - if ( config["staticConfig"]["mqttConnection"]["loggingUploadTopic"].asString().length() > 0 ) + auto loggingUploadTopic = mqttConfig["loggingUploadTopic"].asStringOptional().get_value_or( "" ); + if ( !loggingUploadTopic.empty() ) { - mConnectivityChannelLogsUpload = mConnectivityModule->createNewChannel( - nullptr, config["staticConfig"]["mqttConnection"]["loggingUploadTopic"].asString() ); + mConnectivityChannelLogsUpload = mConnectivityModule->createNewChannel( nullptr, loggingUploadTopic ); } // Create an ISender for sending Checkins - mConnectivityChannelSendCheckin = mConnectivityModule->createNewChannel( - nullptr, config["staticConfig"]["mqttConnection"]["checkinTopic"].asString() ); + mConnectivityChannelSendCheckin = + mConnectivityModule->createNewChannel( nullptr, mqttConfig["checkinTopic"].asStringRequired() ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA std::shared_ptr rawDataBufferManager; boost::optional rawDataBufferManagerConfig; auto rawDataBufferJsonConfig = config["staticConfig"]["visionSystemDataCollection"]["rawDataBuffer"]; - auto rawBufferSize = rawDataBufferJsonConfig.isMember( "maxSize" ) - ? boost::make_optional( getJsonValueAsSize( rawDataBufferJsonConfig["maxSize"] ) ) - : boost::none; + auto rawBufferSize = rawDataBufferJsonConfig["maxSize"].asSizeOptional(); if ( rawBufferSize.get_value_or( SIZE_MAX ) > 0 ) { // Create a Raw Data Buffer Manager std::vector rawDataBufferOverridesPerSignal; - if ( rawDataBufferJsonConfig.isMember( "overridesPerSignal" ) ) + for ( auto i = 0U; i < rawDataBufferJsonConfig["overridesPerSignal"].getArraySizeOptional(); i++ ) { - for ( const auto &signalOverridesJson : rawDataBufferJsonConfig["overridesPerSignal"] ) - { - RawData::SignalBufferOverrides signalOverrides; - signalOverrides.interfaceId = signalOverridesJson["interfaceId"].asString(); - signalOverrides.messageId = signalOverridesJson["messageId"].asString(); - signalOverrides.reservedBytes = - signalOverridesJson.isMember( "reservedSize" ) - ? boost::make_optional( getJsonValueAsSize( signalOverridesJson["reservedSize"] ) ) - : boost::none; - signalOverrides.maxNumOfSamples = - signalOverridesJson.isMember( "maxSamples" ) - ? boost::make_optional( getJsonValueAsSize( signalOverridesJson["maxSamples"] ) ) - : boost::none; - signalOverrides.maxBytesPerSample = - signalOverridesJson.isMember( "maxSizePerSample" ) - ? boost::make_optional( getJsonValueAsSize( signalOverridesJson["maxSizePerSample"] ) ) - : boost::none; - signalOverrides.maxBytes = - signalOverridesJson.isMember( "maxSize" ) - ? boost::make_optional( getJsonValueAsSize( signalOverridesJson["maxSize"] ) ) - : boost::none; - rawDataBufferOverridesPerSignal.emplace_back( signalOverrides ); - } + auto signalOverridesJson = rawDataBufferJsonConfig["overridesPerSignal"][i]; + RawData::SignalBufferOverrides signalOverrides; + signalOverrides.interfaceId = signalOverridesJson["interfaceId"].asStringRequired(); + signalOverrides.messageId = signalOverridesJson["messageId"].asStringRequired(); + signalOverrides.reservedBytes = signalOverridesJson["reservedSize"].asSizeOptional(); + signalOverrides.maxNumOfSamples = signalOverridesJson["maxSamples"].asSizeOptional(); + signalOverrides.maxBytesPerSample = signalOverridesJson["maxSizePerSample"].asSizeOptional(); + signalOverrides.maxBytes = signalOverridesJson["maxSize"].asSizeOptional(); + rawDataBufferOverridesPerSignal.emplace_back( signalOverrides ); } - rawDataBufferManagerConfig = RawData::BufferManagerConfig::create( - rawBufferSize, - rawDataBufferJsonConfig.isMember( "reservedSizePerSignal" ) - ? boost::make_optional( getJsonValueAsSize( rawDataBufferJsonConfig["reservedSizePerSignal"] ) ) - : boost::none, - rawDataBufferJsonConfig.isMember( "maxSamplesPerSignal" ) - ? boost::make_optional( getJsonValueAsSize( rawDataBufferJsonConfig["maxSamplesPerSignal"] ) ) - : boost::none, - rawDataBufferJsonConfig.isMember( "maxSizePerSample" ) - ? boost::make_optional( getJsonValueAsSize( rawDataBufferJsonConfig["maxSizePerSample"] ) ) - : boost::none, - rawDataBufferJsonConfig.isMember( "maxSizePerSignal" ) - ? boost::make_optional( getJsonValueAsSize( rawDataBufferJsonConfig["maxSizePerSignal"] ) ) - : boost::none, - rawDataBufferOverridesPerSignal ); + rawDataBufferManagerConfig = + RawData::BufferManagerConfig::create( rawBufferSize, + rawDataBufferJsonConfig["reservedSizePerSignal"].asSizeOptional(), + rawDataBufferJsonConfig["maxSamplesPerSignal"].asSizeOptional(), + rawDataBufferJsonConfig["maxSizePerSample"].asSizeOptional(), + rawDataBufferJsonConfig["maxSizePerSignal"].asSizeOptional(), + rawDataBufferOverridesPerSignal ); if ( !rawDataBufferManagerConfig ) { FWE_LOG_ERROR( "Failed to create raw data buffer manager config" ); @@ -403,7 +365,10 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) #endif // For asynchronous connect the call needs to be done after all channels created and setTopic calls - mConnectivityModule->connect(); + if ( !mConnectivityModule->connect() ) + { + return false; + } /*************************Connectivity bootstrap end***************************************/ /*************************Remote Profiling bootstrap begin**********************************/ @@ -416,7 +381,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) * "Warning" all log messages with this or a higher log level are mirrored over MQTT */ stringToLogLevel( - config["staticConfig"]["remoteProfilerDefaultValues"]["loggingUploadLevelThreshold"].asString(), + config["staticConfig"]["remoteProfilerDefaultValues"]["loggingUploadLevelThreshold"].asStringRequired(), logThreshold ); /* @@ -438,10 +403,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) mRemoteProfiler = std::make_unique( mConnectivityChannelMetricsUpload, mConnectivityChannelLogsUpload, - config["staticConfig"]["remoteProfilerDefaultValues"]["metricsUploadIntervalMs"].asUInt(), - config["staticConfig"]["remoteProfilerDefaultValues"]["loggingUploadMaxWaitBeforeUploadMs"].asUInt(), + config["staticConfig"]["remoteProfilerDefaultValues"]["metricsUploadIntervalMs"].asU32Required(), + config["staticConfig"]["remoteProfilerDefaultValues"]["loggingUploadMaxWaitBeforeUploadMs"] + .asU32Required(), logThreshold, - config["staticConfig"]["remoteProfilerDefaultValues"]["profilerPrefix"].asString() ); + config["staticConfig"]["remoteProfilerDefaultValues"]["profilerPrefix"].asStringRequired() ); if ( !mRemoteProfiler->start() ) { FWE_LOG_WARN( @@ -456,22 +422,23 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // Below are three buffers to be shared between Vehicle Data Consumer and Collection Engine // Signal Buffer are a lock-free multi-producer single consumer buffer - auto signalBufferPtr = - std::make_shared( config["staticConfig"]["bufferSizes"]["decodedSignalsBufferSize"].asInt() ); + auto signalBufferPtr = std::make_shared( + config["staticConfig"]["bufferSizes"]["decodedSignalsBufferSize"].asSizeRequired() ); // Create the Data Inspection Queue mCollectedDataReadyToPublish = std::make_shared( - config["staticConfig"]["internalParameters"]["readyToPublishDataBufferSize"].asInt() ); + config["staticConfig"]["internalParameters"]["readyToPublishDataBufferSize"].asSizeRequired() ); // Init and start the Inspection Engine mCollectionInspectionWorkerThread = std::make_shared(); if ( ( !mCollectionInspectionWorkerThread->init( signalBufferPtr, mCollectedDataReadyToPublish, - config["staticConfig"]["threadIdleTimes"]["inspectionThreadIdleTimeMs"].asUInt(), + config["staticConfig"]["threadIdleTimes"]["inspectionThreadIdleTimeMs"].asU32Required() #ifdef FWE_FEATURE_VISION_SYSTEM_DATA - rawDataBufferManager, + , + rawDataBufferManager #endif - config["staticConfig"]["internalParameters"]["dataReductionProbabilityDisabled"].asBool() ) ) || + ) ) || ( !mCollectionInspectionWorkerThread->start() ) ) { FWE_LOG_ERROR( "Failed to init and start the Inspection Engine" ); @@ -488,7 +455,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } else { - auto s3MaxConnections = config["staticConfig"]["s3Upload"]["maxConnections"].asUInt(); + auto s3MaxConnections = config["staticConfig"]["s3Upload"]["maxConnections"].asU32Required(); s3MaxConnections = s3MaxConnections > 0U ? s3MaxConnections : 1U; auto createTransferManagerWrapper = [this, s3MaxConnections]( Aws::Client::ClientConfiguration &clientConfiguration, @@ -506,23 +473,23 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) return std::make_shared( Aws::Transfer::TransferManager::Create( transferManagerConfiguration ) ); }; - mS3Sender = std::make_shared( mPayloadManager, - createTransferManagerWrapper, - config["staticConfig"]["s3Upload"]["multipartSize"].asUInt() ); + mS3Sender = + std::make_shared( mPayloadManager, + createTransferManagerWrapper, + config["staticConfig"]["s3Upload"]["multipartSize"].asSizeRequired() ); } - auto ionWriter = std::make_shared( - rawDataBufferManager, config["staticConfig"]["mqttConnection"]["clientId"].asString() ); + auto ionWriter = std::make_shared( rawDataBufferManager, clientId ); #endif mDataSenderManager = std::make_shared( mConnectivityChannelSendVehicleData, mPayloadManager, mCANIDTranslator, - config["staticConfig"]["publishToCloudParameters"]["maxPublishMessageCount"].asUInt() + config["staticConfig"]["publishToCloudParameters"]["maxPublishMessageCount"].asU32Required() #ifdef FWE_FEATURE_VISION_SYSTEM_DATA , mS3Sender, ionWriter, - config["staticConfig"]["mqttConnection"]["clientId"].asString() + clientId #endif ); mDataSenderManagerWorkerThread = std::make_shared( @@ -533,11 +500,8 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) return false; } - if ( !mCollectionInspectionWorkerThread->subscribeListener( mDataSenderManagerWorkerThread.get() ) ) - { - FWE_LOG_ERROR( "Failed register the Data Sender Thread to the Inspection Module" ); - return false; - } + mCollectionInspectionWorkerThread->subscribeToDataReadyToPublish( + std::bind( &DataSenderManagerWorkerThread::onDataReadyToPublish, mDataSenderManagerWorkerThread.get() ) ); /*************************DataSender bootstrap end*********************************/ /*************************CollectionScheme Ingestion bootstrap begin*********************************/ @@ -556,7 +520,7 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( !mCollectionSchemeManagerPtr->init( config["staticConfig"]["publishToCloudParameters"]["collectionSchemeManagementCheckinIntervalMs"] - .asUInt(), + .asU32Required(), mPersistDecoderManifestCollectionSchemesAndData, mCANIDTranslator #ifdef FWE_FEATURE_VISION_SYSTEM_DATA @@ -571,37 +535,32 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) // Make sure the CollectionScheme Ingestion can notify the CollectionScheme Manager about the arrival // of new artifacts over the offboardconnectivity channel. - if ( !mSchemaPtr->subscribeListener( - static_cast( mCollectionSchemeManagerPtr.get() ) ) ) - { - FWE_LOG_ERROR( "Failed register the CollectionScheme Manager to the CollectionScheme Ingestion Module" ); - return false; - } + mSchemaPtr->subscribeToCollectionSchemeUpdate( std::bind( &CollectionSchemeManager::onCollectionSchemeUpdate, + mCollectionSchemeManagerPtr.get(), + std::placeholders::_1 ) ); + mSchemaPtr->subscribeToDecoderManifestUpdate( std::bind( &CollectionSchemeManager::onDecoderManifestUpdate, + mCollectionSchemeManagerPtr.get(), + std::placeholders::_1 ) ); // Make sure the CollectionScheme Manager can notify the Inspection Engine about the availability of // a new set of collection CollectionSchemes. - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mCollectionInspectionWorkerThread.get() ) ) ) - { - FWE_LOG_ERROR( "Failed register the Inspection Engine to the CollectionScheme Manager Module" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToInspectionMatrixChange( + std::bind( &CollectionInspectionWorkerThread::onChangeInspectionMatrix, + mCollectionInspectionWorkerThread.get(), + std::placeholders::_1 ) ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA // Make sure the CollectionScheme Manager can notify the Data Sender about the availability of // a new set of collection CollectionSchemes. - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mDataSenderManagerWorkerThread.get() ) ) ) - { - FWE_LOG_ERROR( "Failed register the Data Sender to the CollectionScheme Manager Module" ); - return false; - } - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( ionWriter.get() ) ) ) - { - FWE_LOG_ERROR( "Failed register the IonWriter to the CollectionScheme Manager Module" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToCollectionSchemeListChange( + std::bind( &DataSenderManagerWorkerThread::onChangeCollectionSchemeList, + mDataSenderManagerWorkerThread.get(), + std::placeholders::_1 ) ); + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &DataSenderIonWriter::onChangeOfActiveDictionary, + ionWriter.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); #endif // Allow CollectionSchemeManagement to send checkins through the Schema Object Callback @@ -611,16 +570,19 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) auto obdOverCANModuleInit = false; mCANDataConsumer = std::make_unique( signalBufferPtr ); - for ( const auto &interfaceName : config["networkInterfaces"] ) + for ( unsigned i = 0; i < config["networkInterfaces"].getArraySizeRequired(); i++ ) { - const auto &interfaceType = interfaceName["type"].asString(); + const auto networkInterfaceConfig = config["networkInterfaces"][i]; + const auto interfaceType = networkInterfaceConfig["type"].asStringRequired(); + const auto interfaceId = networkInterfaceConfig["interfaceId"].asStringRequired(); if ( interfaceType == CAN_INTERFACE_TYPE ) { CanTimestampType canTimestampType = CanTimestampType::KERNEL_SOFTWARE_TIMESTAMP; // default - if ( interfaceName[CAN_INTERFACE_TYPE].isMember( "timestampType" ) ) + auto canConfig = networkInterfaceConfig[CAN_INTERFACE_TYPE]; + if ( canConfig.isMember( "timestampType" ) ) { - auto timestampTypeInput = interfaceName[CAN_INTERFACE_TYPE]["timestampType"].asString(); + auto timestampTypeInput = canConfig["timestampType"].asStringRequired(); bool success = stringToCanTimestampType( timestampTypeInput, canTimestampType ); if ( !success ) { @@ -628,25 +590,24 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) " so default to Software" ); } } - auto canChannelId = mCANIDTranslator.getChannelNumericID( interfaceName["interfaceId"].asString() ); + auto canChannelId = mCANIDTranslator.getChannelNumericID( interfaceId ); auto canSourcePtr = std::make_unique( canChannelId, canTimestampType, - interfaceName[CAN_INTERFACE_TYPE]["interfaceName"].asString(), - interfaceName[CAN_INTERFACE_TYPE]["protocolName"].asString() == "CAN-FD", - config["staticConfig"]["threadIdleTimes"]["socketCANThreadIdleTimeMs"].asUInt(), + canConfig["interfaceName"].asStringRequired(), + canConfig["protocolName"].asStringRequired() == "CAN-FD", + config["staticConfig"]["threadIdleTimes"]["socketCANThreadIdleTimeMs"].asU32Required(), *mCANDataConsumer ); if ( !canSourcePtr->init() ) { FWE_LOG_ERROR( "Failed to initialize CANDataSource" ); return false; } - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( canSourcePtr.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the CANDataSource to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &CANDataSource::onChangeOfActiveDictionary, + canSourcePtr.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); mCANDataSources.push_back( std::move( canSourcePtr ) ); } else if ( interfaceType == OBD_INTERFACE_TYPE ) @@ -655,14 +616,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) { auto obdOverCANModule = std::make_shared(); obdOverCANModuleInit = true; - const auto &broadcastRequests = interfaceName[OBD_INTERFACE_TYPE]["broadcastRequests"]; + auto obdConfig = networkInterfaceConfig[OBD_INTERFACE_TYPE]; if ( obdOverCANModule->init( signalBufferPtr, - interfaceName[OBD_INTERFACE_TYPE]["interfaceName"].asString(), - interfaceName[OBD_INTERFACE_TYPE]["pidRequestIntervalSeconds"].asUInt(), - interfaceName[OBD_INTERFACE_TYPE]["dtcRequestIntervalSeconds"].asUInt(), + obdConfig["interfaceName"].asStringRequired(), + obdConfig["pidRequestIntervalSeconds"].asU32Required(), + obdConfig["dtcRequestIntervalSeconds"].asU32Required(), // Broadcast mode is enabled by default if not defined in config: - broadcastRequests.isNull() || broadcastRequests.asBool() ) ) + obdConfig["broadcastRequests"].asBoolOptional().get_value_or( true ) ) ) { // Connect the OBD Module mOBDOverCANModule = obdOverCANModule; @@ -672,18 +633,15 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) return false; } - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mOBDOverCANModule.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the OBD Module to the CollectionScheme Manager" ); - return false; - } - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mOBDOverCANModule.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the OBD Module to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &OBDOverCANModule::onChangeOfActiveDictionary, + mOBDOverCANModule.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); + mCollectionSchemeManagerPtr->subscribeToInspectionMatrixChange( + std::bind( &OBDOverCANModule::onChangeInspectionMatrix, + mOBDOverCANModule.get(), + std::placeholders::_1 ) ); } } else @@ -696,36 +654,33 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) if ( mExternalCANDataSource == nullptr ) { mExternalCANDataSource = std::make_unique( *mCANDataConsumer ); - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mExternalCANDataSource.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the ExternalCANDataSource to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &ExternalCANDataSource::onChangeOfActiveDictionary, + mExternalCANDataSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); } } #ifdef FWE_FEATURE_ROS2 else if ( interfaceType == ROS2_INTERFACE_TYPE ) { ROS2DataSourceConfig ros2Config; - if ( !ROS2DataSourceConfig::parseFromJson( interfaceName, ros2Config ) ) + if ( !ROS2DataSourceConfig::parseFromJson( networkInterfaceConfig, ros2Config ) ) { - FWE_LOG_ERROR( "Could not parse ros2Interface configuration" ); return false; } mROS2DataSource = std::make_shared( ros2Config, signalBufferPtr, rawDataBufferManager ); mROS2DataSource->connect(); - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mROS2DataSource.get() ) ) ) - { - FWE_LOG_ERROR( "Failed register the ROS2 Data Source to the CollectionScheme Manager Module" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &ROS2DataSource::onChangeOfActiveDictionary, + mROS2DataSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); } #endif else { - FWE_LOG_ERROR( interfaceName["type"].asString() + " is not supported" ); + FWE_LOG_ERROR( interfaceType + " is not supported" ); } } @@ -749,18 +704,18 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) CANRawFrameID canRawFrameId{}; uint16_t latitudeStartBit{}; uint16_t longitudeStartBit{}; - if ( config["staticConfig"].isMember( "iWaveGpsExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_IWAVE_GPS ) ) { - FWE_LOG_TRACE( "Found 'iWaveGpsExample' section in config file" ); - pathToNmeaSource = config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::PATH_TO_NMEA].asString(); + FWE_LOG_TRACE( "Found '" + CONFIG_SECTION_IWAVE_GPS + "' section in config file" ); + const auto iwaveConfig = config["staticConfig"][CONFIG_SECTION_IWAVE_GPS]; + pathToNmeaSource = iwaveConfig[IWaveGpsSource::PATH_TO_NMEA].asStringRequired(); canChannel = mCANIDTranslator.getChannelNumericID( - config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::CAN_CHANNEL_NUMBER].asString() ); - canRawFrameId = - stringToU32( config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::CAN_RAW_FRAME_ID].asString() ); - latitudeStartBit = static_cast( stringToU32( - config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::LATITUDE_START_BIT].asString() ) ); - longitudeStartBit = static_cast( stringToU32( - config["staticConfig"]["iWaveGpsExample"][IWaveGpsSource::LONGITUDE_START_BIT].asString() ) ); + iwaveConfig[IWaveGpsSource::CAN_CHANNEL_NUMBER].asStringRequired() ); + canRawFrameId = iwaveConfig[IWaveGpsSource::CAN_RAW_FRAME_ID].asU32FromStringRequired(); + latitudeStartBit = + static_cast( iwaveConfig[IWaveGpsSource::LATITUDE_START_BIT].asU32FromStringRequired() ); + longitudeStartBit = + static_cast( iwaveConfig[IWaveGpsSource::LONGITUDE_START_BIT].asU32FromStringRequired() ); } else { @@ -779,12 +734,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) FWE_LOG_ERROR( "IWaveGps initialization failed" ); return false; } - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mIWaveGpsSource.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the IWaveGps to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &IWaveGpsSource::onChangeOfActiveDictionary, + mIWaveGpsSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); mIWaveGpsSource->start(); } /********************************IWave GPS Example NMEA reader end******************************/ @@ -794,19 +748,18 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) /********************************External GPS Example NMEA reader *********************************/ mExternalGpsSource = std::make_shared( signalBufferPtr ); bool externalGpsInitSuccessful = false; - if ( config["staticConfig"].isMember( "externalGpsExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_EXTERNAL_GPS ) ) { - FWE_LOG_TRACE( "Found 'externalGpsExample' section in config file" ); + FWE_LOG_TRACE( "Found '" + CONFIG_SECTION_EXTERNAL_GPS + "' section in config file" ); + auto externalGpsConfig = config["staticConfig"][CONFIG_SECTION_EXTERNAL_GPS]; externalGpsInitSuccessful = mExternalGpsSource->init( mCANIDTranslator.getChannelNumericID( - config["staticConfig"]["externalGpsExample"][ExternalGpsSource::CAN_CHANNEL_NUMBER].asString() ), - stringToU32( - config["staticConfig"]["externalGpsExample"][ExternalGpsSource::CAN_RAW_FRAME_ID].asString() ), - static_cast( stringToU32( - config["staticConfig"]["externalGpsExample"][ExternalGpsSource::LATITUDE_START_BIT].asString() ) ), + externalGpsConfig[ExternalGpsSource::CAN_CHANNEL_NUMBER].asStringRequired() ), + externalGpsConfig[ExternalGpsSource::CAN_RAW_FRAME_ID].asU32FromStringRequired(), static_cast( - stringToU32( config["staticConfig"]["externalGpsExample"][ExternalGpsSource::LONGITUDE_START_BIT] - .asString() ) ) ); + externalGpsConfig[ExternalGpsSource::LATITUDE_START_BIT].asU32FromStringRequired() ), + static_cast( + externalGpsConfig[ExternalGpsSource::LONGITUDE_START_BIT].asU32FromStringRequired() ) ); } else { @@ -816,12 +769,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } if ( externalGpsInitSuccessful ) { - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mExternalGpsSource.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the ExternalGpsSource to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &ExternalGpsSource::onChangeOfActiveDictionary, + mExternalGpsSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); mExternalGpsSource->start(); } else @@ -836,13 +788,14 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) /********************************AAOS VHAL Example reader *********************************/ mAaosVhalSource = std::make_shared( signalBufferPtr ); bool aaosVhalInitSuccessful = false; - if ( config["staticConfig"].isMember( "aaosVhalExample" ) ) + if ( config["staticConfig"].isMember( CONFIG_SECTION_AAOS_VHAL ) ) { - FWE_LOG_TRACE( "Found 'aaosVhalExample' section in config file" ); - aaosVhalInitSuccessful = mAaosVhalSource->init( - mCANIDTranslator.getChannelNumericID( - config["staticConfig"]["aaosVhalExample"][AaosVhalSource::CAN_CHANNEL_NUMBER].asString() ), - stringToU32( config["staticConfig"]["aaosVhalExample"][AaosVhalSource::CAN_RAW_FRAME_ID].asString() ) ); + FWE_LOG_TRACE( "Found '" + CONFIG_SECTION_AAOS_VHAL + "' section in config file" ); + auto aaosConfig = config["staticConfig"][CONFIG_SECTION_AAOS_VHAL]; + aaosVhalInitSuccessful = + mAaosVhalSource->init( mCANIDTranslator.getChannelNumericID( + aaosConfig[AaosVhalSource::CAN_CHANNEL_NUMBER].asStringRequired() ), + aaosConfig[AaosVhalSource::CAN_RAW_FRAME_ID].asU32FromStringRequired() ); } else { @@ -852,12 +805,11 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) } if ( aaosVhalInitSuccessful ) { - if ( !mCollectionSchemeManagerPtr->subscribeListener( - static_cast( mAaosVhalSource.get() ) ) ) - { - FWE_LOG_ERROR( "Failed to register the AaosVhalExample to the CollectionScheme Manager" ); - return false; - } + mCollectionSchemeManagerPtr->subscribeToActiveDecoderDictionaryChange( + std::bind( &AaosVhalSource::onChangeOfActiveDictionary, + mAaosVhalSource.get(), + std::placeholders::_1, + std::placeholders::_2 ) ); mAaosVhalSource->start(); } else @@ -869,7 +821,8 @@ IoTFleetWiseEngine::connect( const Json::Value &config ) #endif mPrintMetricsCyclicPeriodMs = - config["staticConfig"]["internalParameters"]["metricsCyclicPrintIntervalMs"].asUInt(); // default to 0 + config["staticConfig"]["internalParameters"]["metricsCyclicPrintIntervalMs"].asU32Optional().get_value_or( + 0 ); } catch ( const std::exception &e ) { @@ -1087,7 +1040,7 @@ IoTFleetWiseEngine::setExternalOBDPIDResponse( PID pid, const std::vector &data ) diff --git a/src/IoTFleetWiseEngine.h b/src/IoTFleetWiseEngine.h index 4e8439ff..13c0b08e 100644 --- a/src/IoTFleetWiseEngine.h +++ b/src/IoTFleetWiseEngine.h @@ -23,6 +23,7 @@ #include "RemoteProfiler.h" #include "Schema.h" #include "Signal.h" +#include "SignalTypes.h" #include "Thread.h" #include "TimeTypes.h" #include "Timer.h" @@ -77,7 +78,7 @@ class IoTFleetWiseEngine IoTFleetWiseEngine( IoTFleetWiseEngine && ) = delete; IoTFleetWiseEngine &operator=( IoTFleetWiseEngine && ) = delete; - bool connect( const Json::Value &config ); + bool connect( const Json::Value &jsonConfig ); bool start(); bool stop(); bool disconnect(); @@ -100,7 +101,7 @@ class IoTFleetWiseEngine * @param timestamp Timestamp of CAN message in milliseconds since epoch, or zero if unknown. * @param messageId CAN message ID in Linux SocketCAN format * @param data CAN message data */ - void ingestExternalCANMessage( const std::string &interfaceId, + void ingestExternalCANMessage( const InterfaceID &interfaceId, Timestamp timestamp, uint32_t messageId, const std::vector &data ); @@ -153,8 +154,6 @@ class IoTFleetWiseEngine std::shared_ptr mPersistDecoderManifestCollectionSchemesAndData; private: - static constexpr uint64_t DEFAULT_RETRY_UPLOAD_PERSISTED_INTERVAL_MS = 10000; - Thread mThread; std::atomic mShouldStop{ false }; mutable std::mutex mThreadMutex; diff --git a/src/Listener.h b/src/Listener.h index 42753d92..a00df10d 100644 --- a/src/Listener.h +++ b/src/Listener.h @@ -14,75 +14,37 @@ namespace IoTFleetWise /** * @brief Template utility implementing a thread safe Subject/Observer design pattern. + * + * It is intended to be used with callbacks defined as std::function. */ -template -class ThreadListeners +template +class ThreadSafeListeners { -private: - template - using CallBackFunction = void ( ThreadListener::* )( Args... ); - public: - ThreadListeners() = default; - virtual ~ThreadListeners() + ThreadSafeListeners() = default; + virtual ~ThreadSafeListeners() { MutexLock lock( mMutex ); mContainer.clear(); } - ThreadListeners( const ThreadListeners & ) = delete; - ThreadListeners &operator=( const ThreadListeners & ) = delete; - ThreadListeners( ThreadListeners && ) = delete; - ThreadListeners &operator=( ThreadListeners && ) = delete; + ThreadSafeListeners( const ThreadSafeListeners & ) = delete; + ThreadSafeListeners &operator=( const ThreadSafeListeners & ) = delete; + ThreadSafeListeners( ThreadSafeListeners && ) = delete; + ThreadSafeListeners &operator=( ThreadSafeListeners && ) = delete; /** * @brief Subscribe the listener instance to notifications from this thread. - * @param listener Listener instance that will invoked when notifyListeners is called. - * @return True if the listener instance has been subscribed, False if - * it's already subscribed. + * @param callback Callback that will invoked when notify is called. */ - bool - subscribeListener( ThreadListener *listener ) - { - MutexLock lock( mMutex ); - - ListenerContainer &container = getContainer(); - const auto &containerIterator = std::find( container.begin(), container.end(), listener ); - if ( containerIterator == container.end() ) - { - container.emplace_back( listener ); - mModified = mCopied; - return true; - } - else - { - return false; - } - } - - /** - * @brief unSubscribe a Listener the listener instance from notifications to this thread. - * @param listener Listener instance that will stop receiving notifications. - * @return True if the listener instance has been removed, False if - * it was not subscribed in the first place. - */ - bool - unSubscribeListener( ThreadListener *listener ) + void + subscribe( T callback ) { MutexLock lock( mMutex ); - ListenerContainer &container = getContainer(); - const auto &containerIterator = std::find( container.begin(), container.end(), listener ); - if ( containerIterator != container.end() ) - { - container.erase( containerIterator ); - mModified = mCopied; - return true; - } - else - { - return false; - } + CallbackContainer &container = getContainer(); + container.emplace_back( callback ); + mModified = mCopied; } /** @@ -90,27 +52,27 @@ class ThreadListeners */ template void - notifyListeners( CallBackFunction callBackFunction, Args... args ) const + notify( Args... args ) const { MutexLock lock( mMutex ); ContainerInvocationState state( this ); - for ( const auto &listener : mContainer ) + for ( const auto &callback : mContainer ) { - ( ( listener )->*callBackFunction )( args... ); + callback( args... ); } } private: // Container to store the list of listeners to this thread - using ListenerContainer = std::vector; + using CallbackContainer = std::vector; // Mutex to protect the storage from concurrent reads and writes using MutexLock = std::lock_guard; // Container for all listeners registered. - mutable ListenerContainer mContainer; + mutable CallbackContainer mContainer; // Temporary container used during modification via subscribe/unsubscribe - mutable ListenerContainer mTemporaryContainer; + mutable CallbackContainer mTemporaryContainer; // Container state coordinating local swaps of the listener container // Active flag is set when Listener callbacks are being executed mutable bool mActive{ false }; @@ -121,11 +83,11 @@ class ThreadListeners mutable bool mModified{ false }; mutable typename std::mutex mMutex; - // Manages the container storing the listeners in a way that + // Manages the container storing the callbacks in a way that // callback invocations is eventually consistent. struct ContainerInvocationState { - ContainerInvocationState( ThreadListeners const *currentState ) + ContainerInvocationState( ThreadSafeListeners const *currentState ) : mPreviousState( currentState->mActive ) , mOriginalContainer( currentState ) { @@ -149,10 +111,10 @@ class ThreadListeners private: bool mPreviousState; - ThreadListeners const *mOriginalContainer; + ThreadSafeListeners const *mOriginalContainer; }; - ListenerContainer & + CallbackContainer & getContainer() { if ( mModified ) diff --git a/src/MessageTypes.h b/src/MessageTypes.h index 22a26ece..722b0fe4 100644 --- a/src/MessageTypes.h +++ b/src/MessageTypes.h @@ -117,10 +117,6 @@ struct InvalidComplexVariant using ComplexDataElement = boost::variant; -using ComplexDataInterfaceId = std::string; - -const std::string INVALID_COMPLEX_DATA_INTERFACE = std::string(); // empty string is not valid - using ComplexDataMessageId = std::string; static constexpr char COMPLEX_DATA_MESSAGE_ID_SEPARATOR = ':'; diff --git a/src/OBDOverCANModule.h b/src/OBDOverCANModule.h index 3c5a46a2..9d4fa0fe 100644 --- a/src/OBDOverCANModule.h +++ b/src/OBDOverCANModule.h @@ -6,8 +6,6 @@ #include "Clock.h" #include "ClockHandler.h" #include "CollectionInspectionAPITypes.h" -#include "IActiveConditionProcessor.h" -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" #include "OBDDataDecoder.h" #include "OBDDataTypes.h" @@ -47,11 +45,11 @@ enum class ECUID * @brief This class is responsible for coordinating OBD requests on all ECUs */ -class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActiveConditionProcessor +class OBDOverCANModule { public: OBDOverCANModule() = default; - ~OBDOverCANModule() override; + ~OBDOverCANModule(); OBDOverCANModule( const OBDOverCANModule & ) = delete; OBDOverCANModule &operator=( const OBDOverCANModule & ) = delete; @@ -94,14 +92,12 @@ class OBDOverCANModule : public IActiveDecoderDictionaryListener, public IActive */ bool isAlive(); - // From IActiveDecoderDictionaryListener // We need this to know whether PIDs should be requested or not void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); - // From IActiveConditionProcessor // We need this to know whether DTCs should be requested or not - void onChangeInspectionMatrix( const std::shared_ptr &inspectionMatrix ) override; + void onChangeInspectionMatrix( const std::shared_ptr &inspectionMatrix ); /** * @brief Handle of the Signal Output Buffer. This buffer shared between Collection Engine diff --git a/src/ROS2DataSource.cpp b/src/ROS2DataSource.cpp index d364ae27..a508a945 100644 --- a/src/ROS2DataSource.cpp +++ b/src/ROS2DataSource.cpp @@ -29,47 +29,44 @@ static constexpr int MAX_TYPE_TREE_DEPTH = 100; constexpr uint32_t DEFAULT_STARTING_OFFSET = 0; bool -ROS2DataSourceConfig::parseFromJson( const Json::Value &node, ROS2DataSourceConfig &outputConfig ) +ROS2DataSourceConfig::parseFromJson( const IoTFleetWiseConfig &node, ROS2DataSourceConfig &outputConfig ) { - outputConfig.mExecutorThreads = static_cast( node["ros2Interface"]["executorThreads"].asUInt() ); - if ( outputConfig.mExecutorThreads <= 0 ) - { - FWE_LOG_ERROR( "executorThreads must be set to a value > 0" ); - outputConfig.mExecutorThreads = 0; - return false; - } - outputConfig.mSubscribeQueueLength = static_cast( node["ros2Interface"]["subscribeQueueLength"].asUInt() ); - if ( outputConfig.mSubscribeQueueLength <= 0 ) + try { - FWE_LOG_ERROR( "subscribeQueueLength must be set to a value > 0" ); - outputConfig.mSubscribeQueueLength = 0; - return false; - } + outputConfig.mExecutorThreads = + static_cast( node["ros2Interface"]["executorThreads"].asU32Required() ); + outputConfig.mSubscribeQueueLength = + static_cast( node["ros2Interface"]["subscribeQueueLength"].asU32Required() ); + auto introspectionLibraryCompareString = + node["ros2Interface"]["introspectionLibraryCompare"].asStringRequired(); + if ( introspectionLibraryCompareString == "ErrorAndFail" ) + { + outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::ERROR_AND_FAIL_ON_DIFFERENCE; + } + else if ( introspectionLibraryCompareString == "Warn" ) + { + outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::WARN_ON_DIFFERENCE; + } + else if ( introspectionLibraryCompareString == "Ignore" ) + { + outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::NO_CHECK; + } + else + { + FWE_LOG_ERROR( "introspectionLibraryCompare must be set to either ErrorAndFail, Warn or Ignore" ); + return false; + } - auto introspectionLibraryCompareString = node["ros2Interface"]["introspectionLibraryCompare"].asString(); - if ( introspectionLibraryCompareString == "ErrorAndFail" ) - { - outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::ERROR_AND_FAIL_ON_DIFFERENCE; - } - else if ( introspectionLibraryCompareString == "Warn" ) - { - outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::WARN_ON_DIFFERENCE; - } - else if ( introspectionLibraryCompareString == "Ignore" ) - { - outputConfig.mIntrospectionLibraryCompare = CompareToIntrospection::NO_CHECK; - } - else - { - FWE_LOG_ERROR( "introspectionLibraryCompare must be set to either ErrorAndFail, Warn or Ignore" ); - return false; + outputConfig.mInterfaceId = node["interfaceId"].asStringRequired(); + if ( outputConfig.mInterfaceId.empty() ) + { + FWE_LOG_ERROR( "interfaceId must be set" ); + return false; + } } - - outputConfig.mInterfaceId = node["interfaceId"].asString(); - if ( outputConfig.mInterfaceId.empty() ) + catch ( const std::exception &e ) { - FWE_LOG_ERROR( "interfaceId must be set" ); - outputConfig.mInterfaceId = ""; + FWE_LOG_ERROR( std::string( ( e.what() == nullptr ? "" : e.what() ) ) ); return false; } return true; diff --git a/src/ROS2DataSource.h b/src/ROS2DataSource.h index 15268b23..e5b9f36b 100644 --- a/src/ROS2DataSource.h +++ b/src/ROS2DataSource.h @@ -6,8 +6,8 @@ #include "Clock.h" #include "ClockHandler.h" #include "CollectionInspectionAPITypes.h" -#include "IActiveDecoderDictionaryListener.h" #include "IDecoderDictionary.h" +#include "IoTFleetWiseConfig.h" #include "MessageTypes.h" #include "RawDataManager.h" #include "Signal.h" @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -45,7 +44,7 @@ enum class CompareToIntrospection class ROS2DataSourceConfig { public: - std::string mInterfaceId; + InterfaceID mInterfaceId; uint8_t mExecutorThreads; CompareToIntrospection mIntrospectionLibraryCompare; size_t mSubscribeQueueLength; @@ -56,7 +55,7 @@ class ROS2DataSourceConfig * @param outputConfig ouput only valid when true is returned * @return true if successfully parsed, false otherwise */ - static bool parseFromJson( const Json::Value &node, ROS2DataSourceConfig &outputConfig ); + static bool parseFromJson( const IoTFleetWiseConfig &node, ROS2DataSourceConfig &outputConfig ); }; class ROS2DataSourceNode : public rclcpp::Node @@ -97,13 +96,13 @@ class ROS2DataSourceNode : public rclcpp::Node rclcpp::CallbackGroup::SharedPtr mCallbackGroup; }; -class ROS2DataSource : public IActiveDecoderDictionaryListener +class ROS2DataSource { public: ROS2DataSource( ROS2DataSourceConfig config, SignalBufferPtr signalBufferPtr, std::shared_ptr rawDataBufferManager = nullptr ); - ~ROS2DataSource() override; + ~ROS2DataSource(); ROS2DataSource( const ROS2DataSource & ) = delete; ROS2DataSource &operator=( const ROS2DataSource & ) = delete; @@ -133,12 +132,12 @@ class ROS2DataSource : public IActiveDecoderDictionaryListener } /** - * @brief From IActiveDecoderDictionaryListener get called on dictionary updates + * @brief To be called on dictionary updates * @param dictionary new dictionary with the topics to subscribe to and information how to decode * @param networkProtocol only COMPLEX_DATA will be accepted */ void onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override; + VehicleDataSourceProtocol networkProtocol ); private: /** diff --git a/src/RawDataManager.cpp b/src/RawDataManager.cpp index 33ec5106..ea9b01fa 100644 --- a/src/RawDataManager.cpp +++ b/src/RawDataManager.cpp @@ -430,11 +430,11 @@ BufferManager::deleteBufferFromStats( Buffer &buffer ) { auto bytesInUseAndReserved = std::max( buffer.mBytesInUse, buffer.mReservedBytes ); - FWE_FATAL_ASSERT( mBytesInUse <= mMaxOverallMemory, "" ); - FWE_FATAL_ASSERT( mBytesInUseAndReserved <= mMaxOverallMemory, "" ); - FWE_FATAL_ASSERT( mBytesReserved <= mMaxOverallMemory, "" ); - FWE_FATAL_ASSERT( mBytesInUse <= mBytesInUseAndReserved, "" ); - FWE_FATAL_ASSERT( mBytesReserved <= mBytesInUseAndReserved, "" ); + FWE_FATAL_ASSERT( ( mBytesInUse <= mMaxOverallMemory ), "" ); + FWE_FATAL_ASSERT( ( mBytesInUseAndReserved <= mMaxOverallMemory ), "" ); + FWE_FATAL_ASSERT( ( mBytesReserved <= mMaxOverallMemory ), "" ); + FWE_FATAL_ASSERT( ( mBytesInUse <= mBytesInUseAndReserved ), "" ); + FWE_FATAL_ASSERT( ( mBytesReserved <= mBytesInUseAndReserved ), "" ); FWE_FATAL_ASSERT( mBytesInUse >= buffer.mBytesInUse, "" ); FWE_FATAL_ASSERT( mBytesInUseAndReserved >= bytesInUseAndReserved, "" ); @@ -651,8 +651,8 @@ BufferManager::Buffer::deleteUnusedData() // to release unused data whose handle is in use. This will cause the user to get // a null when calling borrowFrame() to request the data. unusedDataFrame = std::find_if( mBuffer.cbegin(), mBuffer.cend(), [&]( const Frame &rawDataFrame ) -> bool { - return rawDataFrame.mDataInUseCounter == 0 && - rawDataFrame.getUsageHint( BufferHandleUsageStage::UPLOADING ) == 0; + return ( rawDataFrame.mDataInUseCounter == 0 ) && + ( rawDataFrame.getUsageHint( BufferHandleUsageStage::UPLOADING ) == 0 ); } ); if ( unusedDataFrame == mBuffer.cend() ) { @@ -816,22 +816,22 @@ BufferManagerConfig::create( boost::optional maxBytes, return {}; } - auto maxBytes = config.mMaxBytes; + auto maxBytesCur = config.mMaxBytes; if ( signalOverride.maxBytes.has_value() ) { - maxBytes = signalOverride.maxBytes.get(); - if ( maxBytes > config.mMaxBytes ) + maxBytesCur = signalOverride.maxBytes.get(); + if ( maxBytesCur > config.mMaxBytes ) { FWE_LOG_ERROR( "Invalid buffer config override for interfaceId '" + signalOverride.interfaceId + "' and messageId '" + signalOverride.messageId + "'. Max bytes for this signal " + - std::to_string( maxBytes ) + " can't be larger than max overall buffer size " + + std::to_string( maxBytesCur ) + " can't be larger than max overall buffer size " + std::to_string( config.mMaxBytes ) ); return {}; } // In case the size per sample is not set, it should be capped to the max size allowed for this signal. if ( !signalOverride.maxBytesPerSample.has_value() ) { - signalOverride.maxBytesPerSample = maxBytes; + signalOverride.maxBytesPerSample = maxBytesCur; } } @@ -843,30 +843,30 @@ BufferManagerConfig::create( boost::optional maxBytes, return {}; } - auto maxBytesPerSample = signalOverride.maxBytesPerSample.get_value_or( config.mMaxBytesPerSample ); - if ( maxBytesPerSample == 0 ) + auto maxBytesPerSampleCur = signalOverride.maxBytesPerSample.get_value_or( config.mMaxBytesPerSample ); + if ( maxBytesPerSampleCur == 0 ) { FWE_LOG_ERROR( "Invalid buffer config override for interfaceId '" + signalOverride.interfaceId + "' and messageId '" + signalOverride.messageId + "'. Max bytes per sample for this signal can't be zero" ); return {}; } - if ( maxBytesPerSample > maxBytes ) + if ( maxBytesPerSampleCur > maxBytesCur ) { FWE_LOG_ERROR( "Invalid buffer config override for interfaceId '" + signalOverride.interfaceId + "' and messageId '" + signalOverride.messageId + "'. Max bytes per sample for this signal " + - std::to_string( maxBytesPerSample ) + " can't be larger than max bytes for this signal " + - std::to_string( maxBytes ) ); + std::to_string( maxBytesPerSampleCur ) + " can't be larger than max bytes for this signal " + + std::to_string( maxBytesCur ) ); return {}; } auto reservedBytes = signalOverride.reservedBytes.get_value_or( config.mReservedBytesPerSignal ); - if ( reservedBytes > maxBytes ) + if ( reservedBytes > maxBytesCur ) { FWE_LOG_ERROR( "Invalid buffer config override for interfaceId '" + signalOverride.interfaceId + "' and messageId '" + signalOverride.messageId + "'. Reserved bytes for this signal " + std::to_string( reservedBytes ) + " can't be larger than max bytes for this signal " + - std::to_string( maxBytes ) ); + std::to_string( maxBytesCur ) ); return {}; } @@ -881,7 +881,7 @@ BufferManagerConfig::create( boost::optional maxBytes, SignalConfig BufferManagerConfig::getSignalConfig( BufferTypeId typeId, - const std::string &interfaceId, + const InterfaceID &interfaceId, const std::string &messageId ) const { SignalConfig signalConfig; diff --git a/src/RawDataManager.h b/src/RawDataManager.h index b0c62e7d..9c4f8c1b 100644 --- a/src/RawDataManager.h +++ b/src/RawDataManager.h @@ -152,6 +152,7 @@ class LoanedFrame // owns the actual data and it needs to track what is in use to ensure the data is kept valid. LoanedFrame() = default; + // coverity[autosar_cpp14_a0_1_3_violation] false-positive, this constructor is used LoanedFrame( BufferManager *rawBufferManager, BufferTypeId typeId, BufferHandle handle, const uint8_t *data, size_t size ) : mRawBufferManager( rawBufferManager ) @@ -241,7 +242,7 @@ static const TypeStatistics INVALID_TYPE_STATISTICS = TypeStatistics{ 0, 0, 0 }; struct SignalBufferOverrides { - std::string interfaceId; + InterfaceID interfaceId; std::string messageId; boost::optional reservedBytes; boost::optional maxNumOfSamples; @@ -249,6 +250,7 @@ struct SignalBufferOverrides boost::optional maxBytes; }; +// coverity[cert_dcl60_cpp_violation] false positive - class only defined once class BufferManagerConfig { public: @@ -297,7 +299,7 @@ class BufferManagerConfig * @return the config for the signal buffer with any overrides already resolved */ SignalConfig getSignalConfig( BufferTypeId typeId, - const std::string &interfaceId, + const InterfaceID &interfaceId, const std::string &messageId ) const; size_t @@ -325,7 +327,7 @@ class BufferManagerConfig struct SignalUpdateConfig { BufferTypeId typeId; - std::string interfaceId; + InterfaceID interfaceId; std::string messageId; }; @@ -523,6 +525,7 @@ class BufferManager * @brief Get an raw message counter since the last reset of the software. * @return The incremented counter value */ + // coverity[autosar_cpp14_a0_1_3_violation] false-positive, this function is used static uint8_t generateRawMsgCounter() { @@ -538,6 +541,7 @@ class BufferManager */ bool checkMemoryLimit( size_t memoryReq ) const; + // coverity[autosar_cpp14_a0_1_3_violation] false-positive, this function is used static bool isValidStageIndex( uint32_t stageIndex ) { diff --git a/src/S3Sender.cpp b/src/S3Sender.cpp index fe58b05a..9f7f804e 100644 --- a/src/S3Sender.cpp +++ b/src/S3Sender.cpp @@ -117,7 +117,7 @@ S3Sender::submitQueuedUploads() { std::lock_guard lock( mQueuedAndOngoingUploadsLookupMutex ); - while ( mOngoingUploads.size() < MAX_SIMULTANEOUS_FILES && !mQueuedUploads.empty() ) + while ( ( mOngoingUploads.size() < MAX_SIMULTANEOUS_FILES ) && ( !mQueuedUploads.empty() ) ) { QueuedUploadMetadata &queuedUploadMetadata = mQueuedUploads.front(); auto streambuf = queuedUploadMetadata.streambufBuilder->build(); @@ -208,16 +208,16 @@ S3Sender::transferStatusUpdatedCallback( const std::shared_ptrGetQueuedParts().size() ) + "; FailedParts: " + std::to_string( transferHandle->GetFailedParts().size() ) ); - if ( transferStatus == Aws::Transfer::TransferStatus::NOT_STARTED || - transferStatus == Aws::Transfer::TransferStatus::IN_PROGRESS ) + if ( ( transferStatus == Aws::Transfer::TransferStatus::NOT_STARTED ) || + ( transferStatus == Aws::Transfer::TransferStatus::IN_PROGRESS ) ) { return; } - if ( transferStatus != Aws::Transfer::TransferStatus::CANCELED && - transferStatus != Aws::Transfer::TransferStatus::FAILED && - transferStatus != Aws::Transfer::TransferStatus::COMPLETED && - transferStatus != Aws::Transfer::TransferStatus::ABORTED ) + if ( ( transferStatus != Aws::Transfer::TransferStatus::CANCELED ) && + ( transferStatus != Aws::Transfer::TransferStatus::FAILED ) && + ( transferStatus != Aws::Transfer::TransferStatus::COMPLETED ) && + ( transferStatus != Aws::Transfer::TransferStatus::ABORTED ) ) { FWE_LOG_ERROR( "Unexpected transfer status '" + transferStatusToString( transferStatus ) + "' for object " + transferHandle->GetKey() ); @@ -252,7 +252,7 @@ S3Sender::transferStatusUpdatedCallback( const std::shared_ptrRetryUpload( data, metadata.transferHandle ); return; } - }; + } } } diff --git a/src/Schema.cpp b/src/Schema.cpp index 9596929c..c3aabcef 100644 --- a/src/Schema.cpp +++ b/src/Schema.cpp @@ -3,6 +3,7 @@ #include "Schema.h" #include "IConnectionTypes.h" +#include "LoggingModule.h" #include namespace Aws @@ -13,27 +14,65 @@ namespace IoTFleetWise Schema::Schema( std::shared_ptr receiverDecoderManifest, std::shared_ptr receiverCollectionSchemeList, std::shared_ptr sender ) - : mDecoderManifestCb( *this ) - , mCollectionSchemeListCb( *this ) - , mSender( std::move( sender ) ) + : mSender( std::move( sender ) ) { // Register the listeners - receiverCollectionSchemeList->subscribeListener( &mCollectionSchemeListCb ); - receiverDecoderManifest->subscribeListener( &mDecoderManifestCb ); + receiverDecoderManifest->subscribeToDataReceived( [this]( const ReceivedChannelMessage &receivedChannelMessage ) { + onDecoderManifestReceived( receivedChannelMessage.buf, receivedChannelMessage.size ); + } ); + receiverCollectionSchemeList->subscribeToDataReceived( + [this]( const ReceivedChannelMessage &receivedChannelMessage ) { + onCollectionSchemeReceived( receivedChannelMessage.buf, receivedChannelMessage.size ); + } ); } void -Schema::setCollectionSchemeList( const CollectionSchemeListPtr collectionSchemeListPtr ) +Schema::onDecoderManifestReceived( const uint8_t *buf, size_t size ) { - notifyListeners( &CollectionSchemeManagementListener::onCollectionSchemeUpdate, - collectionSchemeListPtr ); + // Check for a empty input data + if ( ( buf == nullptr ) || ( size == 0 ) ) + { + FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); + return; + } + + // Create an empty shared pointer which we'll copy the data to + DecoderManifestPtr decoderManifestPtr = std::make_shared(); + + // Try to copy the binary data into the decoderManifest object + if ( !decoderManifestPtr->copyData( buf, size ) ) + { + FWE_LOG_ERROR( "DecoderManifest copyData from IoT core failed" ); + return; + } + + // Successful copy, so we cache the decoderManifest in the Schema object + mDecoderManifestListeners.notify( decoderManifestPtr ); + FWE_LOG_TRACE( "Received Decoder Manifest in PI DecoderManifestCb" ); } void -Schema::setDecoderManifest( const DecoderManifestPtr decoderManifestPtr ) +Schema::onCollectionSchemeReceived( const uint8_t *buf, size_t size ) { - notifyListeners( &CollectionSchemeManagementListener::onDecoderManifestUpdate, - decoderManifestPtr ); + // Check for a empty input data + if ( ( buf == nullptr ) || ( size == 0 ) ) + { + FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); + return; + } + + // Create an empty shared pointer which we'll copy the data to + CollectionSchemeListPtr collectionSchemeListPtr = std::make_shared(); + + // Try to copy the binary data into the collectionSchemeList object + if ( !collectionSchemeListPtr->copyData( buf, size ) ) + { + FWE_LOG_ERROR( "CollectionSchemeList copyData from IoT core failed" ); + return; + } + + mCollectionSchemeListeners.notify( collectionSchemeListPtr ); + FWE_LOG_TRACE( "Received CollectionSchemeList" ); } bool diff --git a/src/Schema.h b/src/Schema.h index 254462cb..fe309ebf 100644 --- a/src/Schema.h +++ b/src/Schema.h @@ -6,16 +6,17 @@ #include "Clock.h" #include "ClockHandler.h" #include "CollectionSchemeIngestionList.h" -#include "CollectionSchemeManagementListener.h" #include "DecoderManifestIngestion.h" +#include "ICollectionSchemeList.h" +#include "IDecoderManifest.h" #include "IReceiver.h" #include "ISender.h" #include "Listener.h" -#include "LoggingModule.h" #include "SchemaListener.h" #include "checkin.pb.h" #include #include +#include #include #include #include @@ -32,9 +33,26 @@ using DecoderManifestPtr = std::shared_ptr; /** * @brief This class handles the receipt of Decoder Manifests and CollectionScheme Lists from the Cloud. */ -class Schema : public ThreadListeners, public SchemaListener +class Schema : public SchemaListener { public: + /** + * @brief Callback function that Schema uses to notify CollectionSchemeManagement when a new CollectionScheme List + * arrives from the Cloud. + * + * @param collectionSchemeList ICollectionSchemeList from CollectionScheme Ingestion + */ + using OnCollectionSchemeUpdateCallback = + std::function; + + /** + * @brief Callback function that Schema uses to notify CollectionSchemeManagement when a new Decoder + * Manifest arrives from the Cloud. + * + * @param decoderManifest IDecoderManifest from CollectionScheme Ingestion + */ + using OnDecoderManifestUpdateCallback = std::function; + /** * @brief Constructor for the Schema class that handles receiving CollectionSchemes and DecoderManifest protobuffers * from Cloud and sending them to CollectionSchemeManagement. @@ -54,21 +72,17 @@ class Schema : public ThreadListeners, publi Schema( Schema && ) = delete; Schema &operator=( Schema && ) = delete; - /** - * @brief Sends CollectionScheme List to CollectionScheme Management - * - * @param collectionSchemeListPtr A shared pointer of a collectionScheme list object received from Cloud containing - * the binary data packed inside it. - */ - void setCollectionSchemeList( const CollectionSchemeListPtr collectionSchemeListPtr ); + void + subscribeToCollectionSchemeUpdate( OnCollectionSchemeUpdateCallback callback ) + { + mCollectionSchemeListeners.subscribe( callback ); + } - /** - * @brief Sends DecoderManifest to CollectionScheme Management - * - * @param decoderManifestPtr A shared pointer of a Decoder Manifest object received from Cloud containing the binary - * data packed inside it. - */ - void setDecoderManifest( const DecoderManifestPtr decoderManifestPtr ); + void + subscribeToDecoderManifestUpdate( OnDecoderManifestUpdateCallback callback ) + { + mDecoderManifestListeners.subscribe( callback ); + } /** * @brief Send a Checkin message to the cloud that includes the active decoder manifest and schemes currently in the @@ -81,96 +95,18 @@ class Schema : public ThreadListeners, publi private: /** - * @brief This struct is used to receive the callback from MQTT IoT Core on receipt of data on the DecoderManifest - * topic + * @brief Callback that should be called whenever a new message with DecoderManifest is received from the Cloud. + * @param buf Pointer to the data. It will be valid only until the callback returns. + * @param size Size of the data */ - struct DecoderManifestCb : IReceiverCallback - { - Schema &mSchema; //< Member variable to the Schema object which will receive the data - - /** - * @brief Constructor that will initialize the member variables - * - * @param collectionSchemeIngestion Reference to a Schema object which allow this struct to pass data to - */ - DecoderManifestCb( Schema &collectionSchemeIngestion ) - : mSchema( collectionSchemeIngestion ) - { - } - - void - onDataReceived( const uint8_t *buf, size_t size ) override - { - // Check for a empty input data - if ( ( buf == nullptr ) || ( size == 0 ) ) - { - FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); - return; - } - - // Create an empty shared pointer which we'll copy the data to - DecoderManifestPtr decoderManifestPtr = std::make_shared(); - - // Try to copy the binary data into the decoderManifest object - if ( !decoderManifestPtr->copyData( buf, size ) ) - { - FWE_LOG_ERROR( "DecoderManifest copyData from IoT core failed" ); - return; - } - - // Successful copy, so we cache the decoderManifest in the Schema object - mSchema.setDecoderManifest( decoderManifestPtr ); - FWE_LOG_TRACE( "Received Decoder Manifest in PI DecoderManifestCb" ); - } - }; - - DecoderManifestCb mDecoderManifestCb; + void onDecoderManifestReceived( const uint8_t *buf, size_t size ); /** - * @brief This struct is used to receive the callback from MQTT IoT Core on receipt of data on the - * CollectionSchemeList topic + * @brief Callback that should be called whenever a new message with CollectionScheme is received from the Cloud. + * @param buf Pointer to the data. It will be valid only until the callback returns. + * @param size Size of the data */ - struct CollectionSchemeListCb : IReceiverCallback - { - Schema &mSchema; //< Member variable to the Schema object which will receive the data - - /** - * @brief Constructor that will initialize the member variables - * - * @param collectionSchemeIngestion Reference to a Schema object which allow this struct to pass data to - */ - CollectionSchemeListCb( Schema &collectionSchemeIngestion ) - : mSchema( collectionSchemeIngestion ) - { - } - - void - onDataReceived( const uint8_t *buf, size_t size ) override - { - // Check for a empty input data - if ( ( buf == nullptr ) || ( size == 0 ) ) - { - FWE_LOG_ERROR( "Received empty CollectionScheme List data from Cloud" ); - return; - } - - // Create an empty shared pointer which we'll copy the data to - CollectionSchemeListPtr collectionSchemeListPtr = std::make_shared(); - - // Try to copy the binary data into the collectionSchemeList object - if ( !collectionSchemeListPtr->copyData( buf, size ) ) - { - FWE_LOG_ERROR( "CollectionSchemeList copyData from IoT core failed" ); - return; - } - - // Successful copy, so we cache the collectionSchemeList in the Schema object - mSchema.setCollectionSchemeList( collectionSchemeListPtr ); - FWE_LOG_TRACE( "Received CollectionSchemeList" ); - } - }; - - CollectionSchemeListCb mCollectionSchemeListCb; + void onCollectionSchemeReceived( const uint8_t *buf, size_t size ); /** * @brief ISender object used to interface with cloud to send Checkins @@ -192,6 +128,9 @@ class Schema : public ThreadListeners, publi */ std::shared_ptr mClock = ClockHandler::getClock(); + ThreadSafeListeners mCollectionSchemeListeners; + ThreadSafeListeners mDecoderManifestListeners; + /** * @brief Sends an mProtoCheckinMsgOutput string on the checkin topic * @return True if the Connectivity Module packed and send the data out of the process space. diff --git a/src/SignalTypes.h b/src/SignalTypes.h index 688ca34e..b4ec7d8f 100644 --- a/src/SignalTypes.h +++ b/src/SignalTypes.h @@ -22,14 +22,18 @@ using CANRawFrameID = uint32_t; /** * @brief CAN Channel Numeric ID specifies which physical CAN channel a signal is found on. Its is only used internally * and not by any input or output artifact. Every vehicle has an array of available CAN channels, and the - * CANChannelNumericID is the index to that array. CANChannelNumericID has a 1:1 mapping with CANInterfaceID. The array + * CANChannelNumericID is the index to that array. CANChannelNumericID has a 1:1 mapping with InterfaceID. The array * of available channels is constructed during the FWE Binary launch by a config file passed to the FWE Binary. */ using CANChannelNumericID = uint32_t; static constexpr CANChannelNumericID INVALID_CAN_SOURCE_NUMERIC_ID = 0xFFFFFFFF; -using CANInterfaceID = std::string; -static const CANInterfaceID INVALID_CAN_INTERFACE_ID{}; +/** + * @brief Interface ID is a string identifier for a logical network interface that is defined in the static + * configuration file, and must match the value sent by cloud in the decoder manifest. + */ +using InterfaceID = std::string; +static const InterfaceID INVALID_INTERFACE_ID{}; /** * @brief Signal ID is either an ID provided by Cloud that is unique across all signals found in the vehicle regardless diff --git a/src/TraceModule.cpp b/src/TraceModule.cpp index f56773d0..7500fb43 100644 --- a/src/TraceModule.cpp +++ b/src/TraceModule.cpp @@ -54,7 +54,9 @@ TraceModule::getVariableName( TraceVariable variable ) switch ( variable ) { // The _idX suffix is to match the legacy naming, which should not be changed as they are used - // in dashbaords. + // in dashboards. + case TraceVariable::TRACE_VARIABLE_SIZE: + return nullptr; case TraceVariable::READ_SOCKET_FRAMES_0: return "RFrames0_id0"; case TraceVariable::READ_SOCKET_FRAMES_1: @@ -127,7 +129,7 @@ TraceModule::getVariableName( TraceVariable variable ) return "ObdE3_id54"; case TraceVariable::DISCARDED_FRAMES: return "FrmE0_id55"; - case TraceVariable::CAN_POLLING_TIMESTAMP_COUNTER: + case TraceVariable::POLLING_TIMESTAMP_COUNTER: return "CanPollTCnt_id56"; case TraceVariable::CE_PROCESSED_SIGNALS: return "CeSCnt_id57"; @@ -155,9 +157,9 @@ TraceModule::getVariableName( TraceVariable variable ) return "CEProcessedDataFrames"; case TraceVariable::CE_PROCESSED_DTCS: return "CEProcessedDTCs"; - default: - return nullptr; + // Intentionally omit default so that we can use compiler warnings to remind us about missing values } + return nullptr; } const char * @@ -166,7 +168,9 @@ TraceModule::getAtomicVariableName( TraceAtomicVariable variable ) switch ( variable ) { // The _idX suffix is to match the legacy naming, which should not be changed as they are used - // in dashbaords. + // in dashboards. + case TraceAtomicVariable::TRACE_ATOMIC_VARIABLE_SIZE: + return nullptr; case TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_SIGNALS: return "QUEUE_CONSUMER_TO_INSPECTION_SIGNALS_id0"; case TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_CAN: @@ -174,7 +178,7 @@ TraceModule::getAtomicVariableName( TraceAtomicVariable variable ) case TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_DATA_FRAMES: return "QueueConsumerToInspectionDataFrames"; case TraceAtomicVariable::QUEUE_CONSUMER_TO_INSPECTION_DTCS: - return "QueueConsumerToInspectionDataFrames"; + return "QueueConsumerToInspectionDtcs"; case TraceAtomicVariable::NOT_TIME_MONOTONIC_FRAMES: return "nTime_id2"; case TraceAtomicVariable::SUBSCRIBE_ERROR: @@ -191,9 +195,9 @@ TraceModule::getAtomicVariableName( TraceAtomicVariable variable ) return "ConRes_id8"; case TraceAtomicVariable::COLLECTION_SCHEME_ERROR: return "CampaignFailures"; - default: - return nullptr; + // Intentionally omit default so that we can use compiler warnings to remind us about missing values } + return nullptr; } const char * @@ -202,7 +206,9 @@ TraceModule::getSectionName( TraceSection section ) switch ( section ) { // The _idX suffix is to match the legacy naming, which should not be changed as they are used - // in dashbaords. + // in dashboards. + case TraceSection::TRACE_SECTION_SIZE: + return nullptr; case TraceSection::BUILD_MQTT: return "BUILD_MQTT_id0"; case TraceSection::FWE_STARTUP: @@ -257,9 +263,9 @@ TraceModule::getSectionName( TraceSection section ) return "CD_19_id25"; case TraceSection::COLLECTION_SCHEME_CHANGE_TO_FIRST_DATA: return "CampaignRxToDataTx"; - default: - return nullptr; + // Intentionally omit default so that we can use compiler warnings to remind us about missing values } + return nullptr; } void diff --git a/src/TraceModule.h b/src/TraceModule.h index a83a607c..01a8a5c5 100644 --- a/src/TraceModule.h +++ b/src/TraceModule.h @@ -58,7 +58,7 @@ enum class TraceVariable OBD_TRA_PID_REQ_ERROR, OBD_KEEP_ALIVE_ERROR, DISCARDED_FRAMES, - CAN_POLLING_TIMESTAMP_COUNTER, + POLLING_TIMESTAMP_COUNTER, CE_PROCESSED_SIGNALS, CE_PROCESSED_CAN_FRAMES, CE_PROCESSED_DATA_FRAMES, diff --git a/src/VehicleDataSourceTypes.h b/src/VehicleDataSourceTypes.h index 0dfa00e0..7e1ef079 100644 --- a/src/VehicleDataSourceTypes.h +++ b/src/VehicleDataSourceTypes.h @@ -16,7 +16,9 @@ enum class VehicleDataSourceProtocol INVALID_PROTOCOL, OBD, RAW_SOCKET, +#ifdef FWE_FEATURE_VISION_SYSTEM_DATA COMPLEX_DATA +#endif // Add any new protocols to the list of supported protocols below }; diff --git a/src/android_shared_library.cpp b/src/android_shared_library.cpp index 24ccbb91..82bb7df6 100644 --- a/src/android_shared_library.cpp +++ b/src/android_shared_library.cpp @@ -287,7 +287,7 @@ Java_com_aws_iotfleetwise_Fwe_ingestCanMessage( return; } auto interfaceIdCString = env->GetStringUTFChars( interfaceIdJString, 0 ); - std::string interfaceId( interfaceIdCString ); + Aws::IoTFleetWise::InterfaceID interfaceId( interfaceIdCString ); env->ReleaseStringUTFChars( interfaceIdJString, interfaceIdCString ); auto len = env->GetArrayLength( dataJArray ); std::vector data( static_cast( len ) ); diff --git a/test/unit/AwsIotConnectivityModuleTest.cpp b/test/unit/AwsIotConnectivityModuleTest.cpp index e55feb69..e40ac5cf 100644 --- a/test/unit/AwsIotConnectivityModuleTest.cpp +++ b/test/unit/AwsIotConnectivityModuleTest.cpp @@ -6,6 +6,8 @@ #include "AwsIotChannel.h" #include "AwsSDKMemoryManager.h" #include "CacheAndPersist.h" +#include "Clock.h" +#include "ClockHandler.h" #include "IConnectionTypes.h" #include "IConnectivityChannel.h" #include "IReceiver.h" @@ -13,7 +15,6 @@ #include "MqttClientWrapper.h" #include "MqttClientWrapperMock.h" #include "PayloadManager.h" -#include "ReceiverListenerFake.h" #include "WaitUntil.h" #include #include @@ -351,13 +352,18 @@ TEST_F( AwsIotConnectivityModuleTest, subscribeWithoutBeingConnected ) TEST_F( AwsIotConnectivityModuleTest, receiveMessage ) { - Testing::ReceiverListenerFake listener1; - Testing::ReceiverListenerFake listener2; + std::vector> receivedDataChannel1; + std::vector> receivedDataChannel2; + auto channel1 = mConnectivityModule->createNewChannel( nullptr, "topic1", true ); auto channel2 = mConnectivityModule->createNewChannel( nullptr, "topic2", true ); - channel1->subscribeListener( &listener1 ); - channel2->subscribeListener( &listener2 ); + channel1->subscribeToDataReceived( [&]( const ReceivedChannelMessage &message ) { + receivedDataChannel1.emplace_back( std::string( message.buf, message.buf + message.size ), message ); + } ); + channel2->subscribeToDataReceived( [&]( const ReceivedChannelMessage &message ) { + receivedDataChannel2.emplace_back( std::string( message.buf, message.buf + message.size ), message ); + } ); EXPECT_CALL( *mMqttClientBuilderWrapperMock, WithClientExtendedValidationAndFlowControl( _ ) ).Times( 1 ); EXPECT_CALL( *mMqttClientBuilderWrapperMock, WithConnectOptions( _ ) ).Times( 1 ); @@ -382,13 +388,19 @@ TEST_F( AwsIotConnectivityModuleTest, receiveMessage ) // Simulate messages coming from MQTT client std::string data1 = "data1"; + uint64_t expectedMessageExpiryMonotonicTimeSinceEpochMs = UINT64_MAX; { Aws::Crt::Mqtt5::PublishReceivedEventData eventData; + auto publishPacket = std::make_shared( "topic1", Aws::Crt::ByteCursorFromCString( data1.c_str() ), Aws::Crt::Mqtt5::QOS::AWS_MQTT5_QOS_AT_MOST_ONCE ); + auto messageExpiryIntervalSec = 5; + publishPacket->WithMessageExpiryIntervalSec( messageExpiryIntervalSec ); eventData.publishPacket = publishPacket; + expectedMessageExpiryMonotonicTimeSinceEpochMs = + ClockHandler::getClock()->monotonicTimeSinceEpochMs() + ( messageExpiryIntervalSec * 1000 ); mMqttClientBuilderWrapperMock->mOnPublishReceivedHandlerCallback( eventData ); } std::string data2 = "data2"; @@ -402,10 +414,18 @@ TEST_F( AwsIotConnectivityModuleTest, receiveMessage ) mMqttClientBuilderWrapperMock->mOnPublishReceivedHandlerCallback( eventData ); } - ASSERT_EQ( listener1.mReceivedData.size(), 1 ); - ASSERT_EQ( listener1.mReceivedData[0], "data1" ); - ASSERT_EQ( listener2.mReceivedData.size(), 1 ); - ASSERT_EQ( listener2.mReceivedData[0], "data2" ); + ASSERT_EQ( receivedDataChannel1.size(), 1 ); + ASSERT_EQ( receivedDataChannel1[0].first, "data1" ); + ASSERT_GE( receivedDataChannel1[0].second.messageExpiryMonotonicTimeSinceEpochMs, + expectedMessageExpiryMonotonicTimeSinceEpochMs ); + // Give some margin for error due to test being slow, but make sure that timeout is not much more + // than expected. + ASSERT_LE( receivedDataChannel1[0].second.messageExpiryMonotonicTimeSinceEpochMs, + expectedMessageExpiryMonotonicTimeSinceEpochMs + 500 ); + + ASSERT_EQ( receivedDataChannel2.size(), 1 ); + ASSERT_EQ( receivedDataChannel2[0].first, "data2" ); + ASSERT_EQ( receivedDataChannel2[0].second.messageExpiryMonotonicTimeSinceEpochMs, 0 ); // Should be called on destruction EXPECT_CALL( *mMqttClientWrapperMock, Unsubscribe( _, _ ) ) diff --git a/test/unit/CollectionInspectionEngineTest.cpp b/test/unit/CollectionInspectionEngineTest.cpp index 039461ad..dadea430 100644 --- a/test/unit/CollectionInspectionEngineTest.cpp +++ b/test/unit/CollectionInspectionEngineTest.cpp @@ -4,7 +4,6 @@ #include "CollectionInspectionEngine.h" #include "CANDataTypes.h" #include "CollectionInspectionAPITypes.h" -#include "GeohashInfo.h" #include "ICollectionScheme.h" #include "OBDDataTypes.h" #include "SignalTypes.h" @@ -170,18 +169,6 @@ class CollectionInspectionEngineTest : public ::testing::Test return boolAnd; } - std::shared_ptr - getGeohashFunctionCondition( SignalID latID, SignalID lonID, uint8_t precision ) - { - expressionNodes.push_back( std::make_shared() ); - auto function = expressionNodes.back(); - function->nodeType = ExpressionNodeType::GEOHASHFUNCTION; - function->function.geohashFunction.latitudeSignalID = latID; - function->function.geohashFunction.longitudeSignalID = lonID; - function->function.geohashFunction.precision = precision; - return function; - } - std::shared_ptr getMultiFixedWindowCondition( SignalID id1 ) { @@ -395,9 +382,7 @@ class CollectionInspectionEngineTest : public ::testing::Test collectionSchemes->conditions.resize( 2 ); collectionSchemes->conditions[0].condition = getAlwaysFalseCondition().get(); - collectionSchemes->conditions[0].probabilityToSend = 1.0; collectionSchemes->conditions[1].condition = getAlwaysFalseCondition().get(); - collectionSchemes->conditions[1].probabilityToSend = 1.0; } void @@ -1364,7 +1349,6 @@ TEST_F( CollectionInspectionEngineDoubleTest, MoreCollectionSchemesThanSupported for ( uint32_t i = 0; i < MAX_NUMBER_OF_ACTIVE_CONDITION; i++ ) { collectionSchemes->conditions[i].condition = getAlwaysTrueCondition().get(); - collectionSchemes->conditions[i].probabilityToSend = 1.0; addSignalToCollect( collectionSchemes->conditions[i], s1 ); } @@ -1383,95 +1367,6 @@ TEST_F( CollectionInspectionEngineDoubleTest, MoreCollectionSchemesThanSupported engine.collectNextDataToSend( timestamp, waitTimeMs ); } -/** - * @brief This test aims to test Inspection Engine to evaluate Geohash Function Node. - * Here's the test procedure: - * 1. Generate AST Tree with Root setting to Geohash Function Node - * 2. Before Signal become ready, we ask Inspection Engine to evaluate Geohash. This Step verify - * Inspection Engine's ability to handle corner case if GPS signal is not there - * 3. Then we add valid lat/lon signal and expect inspection engine to evaluate true - * 4. Next we change GPS signal slightly. Since Geohash didn't change at given precision. - * Evaluation return false. - * 5. We change GPS signal more so that Geohash changed at given precision. Evaluation return true. - * 6. As final step, we supply invalid lat/lon to test Inspection Engine can gracefully handle - * invalid signal - */ -TEST_F( CollectionInspectionEngineDoubleTest, GeohashFunctionNodeTrigger ) -{ - CollectionInspectionEngine engine; - InspectionMatrixSignalCollectionInfo lat{}; - lat.signalID = 1; - lat.sampleBufferSize = 50; - lat.minimumSampleIntervalMs = 0; - lat.fixedWindowPeriod = 77777; - lat.isConditionOnlySignal = true; - InspectionMatrixSignalCollectionInfo lon{}; - lon.signalID = 2; - lon.sampleBufferSize = 50; - lon.minimumSampleIntervalMs = 0; - lon.fixedWindowPeriod = 77777; - lon.isConditionOnlySignal = true; - addSignalToCollect( collectionSchemes->conditions[0], lat ); - addSignalToCollect( collectionSchemes->conditions[0], lon ); - - collectionSchemes->conditions[0].condition = getGeohashFunctionCondition( lat.signalID, lon.signalID, 5 ).get(); - - TimePoint timestamp = { 160000000, 100 }; - engine.onChangeInspectionMatrix( consCollectionSchemes, timestamp ); - - // Before GPS signal is ready, we ask Inspection Engine to evaluate Geohash - ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); - uint32_t waitTimeMs = 0; - auto collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_EQ( collectedData, nullptr ); - - timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.371392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.046208 ); - - ASSERT_TRUE( engine.evaluateConditions( timestamp ) ); - collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_NE( collectedData, nullptr ); - ASSERT_TRUE( collectedData->mGeohashInfo.hasItems() ); - ASSERT_EQ( collectedData->mGeohashInfo.mGeohashString, "9q9hwg28j" ); - ASSERT_EQ( collectedData->mGeohashInfo.mPrevReportedGeohashString.length(), 0 ); - - // 37.361392, -122.056208 -> 9q9hw93mu. still within the same geohash tile at precision 5. - timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.361392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.056208 ); - ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); - collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_EQ( collectedData, nullptr ); - - // 37.351392, -122.066208 -> 9q9hqkpbp. Geohash changed at precision 5. - timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); - ASSERT_TRUE( engine.evaluateConditions( timestamp ) ); - collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_NE( collectedData, nullptr ); - ASSERT_TRUE( collectedData->mGeohashInfo.hasItems() ); - ASSERT_EQ( collectedData->mGeohashInfo.mGeohashString, "9q9hqrd5e" ); - ASSERT_EQ( collectedData->mGeohashInfo.mPrevReportedGeohashString, "9q9hwg28j" ); - - // We supply an invalid latitude - timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 137.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -122.066208 ); - ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); - collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_EQ( collectedData, nullptr ); - - // We supply an invalid longitude - timestamp += 1000; - engine.addNewSignal( lat.signalID, timestamp, 37.351392 ); - engine.addNewSignal( lon.signalID, timestamp, -222.066208 ); - ASSERT_FALSE( engine.evaluateConditions( timestamp ) ); - collectedData = engine.collectNextDataToSend( timestamp, waitTimeMs ); - ASSERT_EQ( collectedData, nullptr ); -} - TYPED_TEST( CollectionInspectionEngineTest, CollectWithAfterTime ) { CollectionInspectionEngine engine; @@ -1572,54 +1467,6 @@ TYPED_TEST( CollectionInspectionEngineTest, CollectWithAfterTime ) ASSERT_EQ( collectedData->triggerTime, timestamp0.systemTimeMs ); } -TEST_F( CollectionInspectionEngineDoubleTest, ProbabilityToSendTest ) -{ - - CollectionInspectionEngine engine; - InspectionMatrixSignalCollectionInfo s1{}; - s1.signalID = 1234; - s1.sampleBufferSize = 50; - s1.minimumSampleIntervalMs = 10; - s1.fixedWindowPeriod = 77777; - addSignalToCollect( collectionSchemes->conditions[0], s1 ); - - // Every 10 seconds send data out - collectionSchemes->conditions[0].minimumPublishIntervalMs = 10000; - collectionSchemes->conditions[0].condition = getAlwaysTrueCondition().get(); - - // Set probability to send to 50% - collectionSchemes->conditions[0].probabilityToSend = 0.5; - - TimePoint timestamp = { 160000000, 100 }; - engine.onChangeInspectionMatrix( consCollectionSchemes, timestamp ); - - uint32_t waitTimeMs = 0; - const uint32_t NR_OF_HEARTBEAT_INTERVALS = 1000; - - uint64_t numberOfDataToSend = 0; - - for ( uint32_t i = 0; i < NR_OF_HEARTBEAT_INTERVALS; i++ ) - { - engine.addNewSignal( s1.signalID, timestamp, 0.1 ); - engine.evaluateConditions( timestamp ); - if ( engine.collectNextDataToSend( timestamp, waitTimeMs ) != nullptr ) - { - numberOfDataToSend++; - } - // Increase time stamp by heartbeat interval to trigger new message - timestamp += collectionSchemes->conditions[0].minimumPublishIntervalMs; - } - - // Probability to get less than 50 or more than NR_OF_HEARTBEAT_INTERVALS-50 is small if - // NR_OF_HEARTBEAT_INTERVALS is >> 100. But there is a small chance of this failing even if - // everything works correctly - EXPECT_GE( numberOfDataToSend, 50 ); - EXPECT_LE( numberOfDataToSend, NR_OF_HEARTBEAT_INTERVALS - 50 ); - - std::cout << NR_OF_HEARTBEAT_INTERVALS << " data to send with a probability of 50%: " << numberOfDataToSend - << " were actually sent" << std::endl; -} - TEST_F( CollectionInspectionEngineDoubleTest, AvgWindowCondition ) { CollectionInspectionEngine engine; @@ -1899,7 +1746,6 @@ TEST_F( CollectionInspectionEngineDoubleTest, RandomDataTest ) ConditionWithCollectedData collectionScheme; collectionSchemes->conditions.resize( NUMBER_OF_COLLECTION_SCHEMES ); collectionSchemes->conditions[i].condition = getAlwaysTrueCondition().get(); - collectionSchemes->conditions[i].probabilityToSend = 1.0; } CollectionInspectionEngine engine; diff --git a/test/unit/CollectionInspectionWorkerThreadTest.cpp b/test/unit/CollectionInspectionWorkerThreadTest.cpp index 93d27f0e..1e4988f4 100644 --- a/test/unit/CollectionInspectionWorkerThreadTest.cpp +++ b/test/unit/CollectionInspectionWorkerThreadTest.cpp @@ -83,9 +83,7 @@ class CollectionInspectionWorkerThreadTest : public ::testing::Test consCollectionSchemes = std::shared_ptr( collectionSchemes ); collectionSchemes->conditions.resize( 4 ); collectionSchemes->conditions[0].condition = getAlwaysFalseCondition().get(); - collectionSchemes->conditions[0].probabilityToSend = 1.0; collectionSchemes->conditions[1].condition = getAlwaysFalseCondition().get(); - collectionSchemes->conditions[1].probabilityToSend = 1.0; signalBufferPtr.reset( new SignalBuffer( 1000 ) ); // Init the output buffer @@ -223,11 +221,9 @@ TEST_F( CollectionInspectionWorkerThreadTest, CollectionQueueFull ) collectionSchemes->conditions[1].signals.push_back( s1 ); collectionSchemes->conditions[1].condition = getAlwaysTrueCondition().get(); collectionSchemes->conditions[2].signals.push_back( s1 ); - collectionSchemes->conditions[2].probabilityToSend = 1.0; collectionSchemes->conditions[2].condition = getAlwaysTrueCondition().get(); collectionSchemes->conditions[3].signals.push_back( s1 ); collectionSchemes->conditions[3].condition = getAlwaysTrueCondition().get(); - collectionSchemes->conditions[3].probabilityToSend = 1.0; worker.onChangeInspectionMatrix( consCollectionSchemes ); Timestamp timestamp = fClock->systemTimeSinceEpochMs(); CollectedSignalsGroup collectedSignalsGroup; diff --git a/test/unit/CollectionSchemeManagerTest.cpp b/test/unit/CollectionSchemeManagerTest.cpp index c345f29c..0d0ca8cb 100644 --- a/test/unit/CollectionSchemeManagerTest.cpp +++ b/test/unit/CollectionSchemeManagerTest.cpp @@ -22,7 +22,6 @@ TEST( CollectionSchemeManagerTest, StopMainTest ) CANInterfaceIDTranslator canIDTranslator; CollectionSchemeManagerTest test; test.init( 50, nullptr, canIDTranslator ); - test.myRegisterListener(); ASSERT_TRUE( test.connect() ); /* stopping idling main thread */ @@ -62,7 +61,6 @@ TEST( CollectionSchemeManagerTest, CollectionSchemeUpdateCallBackTest ) std::vector emptyList; CANInterfaceIDTranslator canIDTranslator; test.init( 50, nullptr, canIDTranslator ); - test.myRegisterListener(); test.setmCollectionSchemeAvailable( false ); test.setmProcessCollectionScheme( false ); // pl is null @@ -86,7 +84,6 @@ TEST( CollectionSchemeManagerTest, DecoderManifestUpdateCallBackTest ) CollectionSchemeManagerTest test; CANInterfaceIDTranslator canIDTranslator; test.init( 50, nullptr, canIDTranslator ); - test.myRegisterListener(); test.setmDecoderManifestAvailable( false ); test.setmProcessDecoderManifest( false ); // dm is null @@ -138,7 +135,6 @@ TEST( CollectionSchemeManagerTest, MockProducerTest ) CollectionSchemeManagerTest test; CANInterfaceIDTranslator canIDTranslator; test.init( 50, nullptr, canIDTranslator ); - test.myRegisterListener(); ASSERT_TRUE( test.connect() ); /* build DMs */ @@ -234,7 +230,6 @@ TEST( CollectionSchemeManagerTest, getCollectionSchemeArns ) CANInterfaceIDTranslator canIDTranslator; CollectionSchemeManagerTest test; test.init( 50, nullptr, canIDTranslator ); - test.myRegisterListener(); ASSERT_TRUE( test.connect() ); ASSERT_EQ( test.getCollectionSchemeArns(), std::vector() ); diff --git a/test/unit/DataSenderManagerTest.cpp b/test/unit/DataSenderManagerTest.cpp index fd054cfa..0ab2e289 100644 --- a/test/unit/DataSenderManagerTest.cpp +++ b/test/unit/DataSenderManagerTest.cpp @@ -6,7 +6,6 @@ #include "CANInterfaceIDTranslator.h" #include "CacheAndPersist.h" #include "CollectionInspectionAPITypes.h" -#include "GeohashInfo.h" #include "IConnectionTypes.h" #include "ISender.h" #include "OBDDataTypes.h" @@ -28,7 +27,6 @@ #ifdef FWE_FEATURE_VISION_SYSTEM_DATA #include "CollectionSchemeManagerTest.h" #include "DataSenderIonWriterMock.h" -#include "IActiveCollectionSchemesListener.h" #include "ICollectionScheme.h" #include "ICollectionSchemeList.h" #include "S3SenderMock.h" @@ -162,7 +160,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleSignal ) ASSERT_EQ( vehicleData.captured_signals_size(), 1 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.captured_signals()[0].signal_id(), signal1.signalID ); ASSERT_EQ( vehicleData.captured_signals()[0].double_value(), signal1.value.value.doubleVal ); @@ -196,7 +193,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleSignals ) ASSERT_EQ( vehicleData.captured_signals_size(), 3 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.captured_signals()[0].signal_id(), signal1.signalID ); ASSERT_EQ( vehicleData.captured_signals()[0].double_value(), signal1.value.value.doubleVal ); @@ -246,14 +242,12 @@ TEST_F( DataSenderManagerTest, ProcessMultipleSignalsBeyondTransmitThreshold ) ASSERT_EQ( vehicleData.captured_signals_size(), 5 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_TRUE( vehicleData.ParseFromString( sentBufferData[1].data ) ); ASSERT_EQ( vehicleData.captured_signals_size(), 4 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); } TEST_F( DataSenderManagerTest, ProcessSingleCanFrame ) @@ -281,7 +275,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleCanFrame ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 1 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.can_frames()[0].message_id(), canFrame1.frameID ); ASSERT_EQ( vehicleData.can_frames()[0].interface_id(), "can123" ); @@ -320,7 +313,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleCanFrames ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 3 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.can_frames()[0].message_id(), canFrame1.frameID ); ASSERT_EQ( vehicleData.can_frames()[0].interface_id(), "can123" ); @@ -375,14 +367,12 @@ TEST_F( DataSenderManagerTest, ProcessMultipleCanFramesBeyondTransmitThreshold ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 5 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_TRUE( vehicleData.ParseFromString( sentBufferData[1].data ) ); ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 4 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); } TEST_F( DataSenderManagerTest, ProcessSingleDtcCode ) @@ -412,7 +402,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleDtcCode ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_TRUE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes_size(), 1 ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes()[0], "P0143" ); @@ -446,7 +435,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleDtcCodes ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_TRUE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes_size(), 2 ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes()[0], "P0143" ); @@ -485,7 +473,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleDtcCodesBeyondTransmitThreshold ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_TRUE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes_size(), 5 ); ASSERT_TRUE( vehicleData.ParseFromString( sentBufferData[1].data ) ); @@ -493,41 +480,9 @@ TEST_F( DataSenderManagerTest, ProcessMultipleDtcCodesBeyondTransmitThreshold ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_TRUE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.dtc_data().active_dtc_codes_size(), 4 ); } -TEST_F( DataSenderManagerTest, ProcessGeohash ) -{ - GeohashInfo geohashInfo; - geohashInfo.mGeohashString = "9q9hwg28j"; - mTriggeredCollectionSchemeData->mGeohashInfo = geohashInfo; - - // TODO: verify data and collectionSchemeParams (3rd parameter) - EXPECT_CALL( *mMqttSender, mockedSendBuffer( _, Gt( 0 ), _ ) ).WillOnce( Return( ConnectivityError::Success ) ); - - processCollectedData( mTriggeredCollectionSchemeData ); - - ASSERT_EQ( mMqttSender->getSentBufferData().size(), 1 ); - auto sentBufferData = mMqttSender->getSentBufferData(); - - auto collectionSchemeParams = sentBufferData[0].collectionSchemeParams; - ASSERT_EQ( collectionSchemeParams.eventID, mTriggeredCollectionSchemeData->eventID ); - ASSERT_EQ( collectionSchemeParams.triggerTime, mTriggeredCollectionSchemeData->triggerTime ); - ASSERT_EQ( collectionSchemeParams.compression, mTriggeredCollectionSchemeData->metadata.compress ); - ASSERT_EQ( collectionSchemeParams.persist, mTriggeredCollectionSchemeData->metadata.persist ); - - Schemas::VehicleDataMsg::VehicleData vehicleData; - ASSERT_TRUE( vehicleData.ParseFromString( sentBufferData[0].data ) ); - - ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); - ASSERT_EQ( vehicleData.can_frames_size(), 0 ); - ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_TRUE( vehicleData.has_geohash() ); - - ASSERT_EQ( vehicleData.geohash().geohash_string(), "9q9hwg28j" ); -} - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA TEST_F( DataSenderManagerTest, ProcessSingleUploadedS3Object ) { @@ -553,7 +508,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleUploadedS3Object ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.s3_objects_size(), 1 ); ASSERT_EQ( vehicleData.s3_objects()[0].key(), "uploaded/object/key1" ); @@ -588,7 +542,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleUploadedS3Objects ) ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.s3_objects_size(), 3 ); ASSERT_EQ( vehicleData.s3_objects()[0].key(), "uploaded/object/key1" ); @@ -641,7 +594,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleUploadedS3ObjectsBeyondTransmitThr ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.s3_objects_size(), 5 ); ASSERT_TRUE( vehicleData.ParseFromString( sentBufferData[1].data ) ); @@ -649,7 +601,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleUploadedS3ObjectsBeyondTransmitThr ASSERT_EQ( vehicleData.captured_signals_size(), 0 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.s3_objects_size(), 4 ); } @@ -719,7 +670,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleRawDataSignal ) ASSERT_EQ( reportedCollectionSchemeData->metadata.decoderID, mTriggeredCollectionSchemeData->metadata.decoderID ); ASSERT_FALSE( reportedCollectionSchemeData->mDTCInfo.hasItems() ); - ASSERT_FALSE( reportedCollectionSchemeData->mGeohashInfo.hasItems() ); ASSERT_EQ( reportedCollectionSchemeData->signals.size(), 0 ); ASSERT_EQ( reportedCollectionSchemeData->canFrames.size(), 0 ); ASSERT_EQ( reportedCollectionSchemeData->uploadedS3Objects.size(), 1 ); @@ -784,7 +734,6 @@ TEST_F( DataSenderManagerTest, ProcessMultipleRawDataSignals ) ASSERT_EQ( reportedCollectionSchemeData->metadata.decoderID, mTriggeredCollectionSchemeData->metadata.decoderID ); ASSERT_FALSE( reportedCollectionSchemeData->mDTCInfo.hasItems() ); - ASSERT_FALSE( reportedCollectionSchemeData->mGeohashInfo.hasItems() ); ASSERT_EQ( reportedCollectionSchemeData->signals.size(), 0 ); ASSERT_EQ( reportedCollectionSchemeData->canFrames.size(), 0 ); ASSERT_EQ( reportedCollectionSchemeData->uploadedS3Objects.size(), 1 ); @@ -904,7 +853,6 @@ TEST_F( DataSenderManagerTest, ProcessSingleSignalWithCompression ) ASSERT_EQ( vehicleData.captured_signals_size(), 1 ); ASSERT_EQ( vehicleData.can_frames_size(), 0 ); ASSERT_FALSE( vehicleData.has_dtc_data() ); - ASSERT_FALSE( vehicleData.has_geohash() ); ASSERT_EQ( vehicleData.captured_signals()[0].signal_id(), signal1.signalID ); ASSERT_EQ( vehicleData.captured_signals()[0].double_value(), signal1.value.value.doubleVal ); diff --git a/test/unit/DataSenderManagerWorkerThreadTest.cpp b/test/unit/DataSenderManagerWorkerThreadTest.cpp index c43a646e..695add3f 100644 --- a/test/unit/DataSenderManagerWorkerThreadTest.cpp +++ b/test/unit/DataSenderManagerWorkerThreadTest.cpp @@ -19,7 +19,7 @@ #include #ifdef FWE_FEATURE_VISION_SYSTEM_DATA -#include "IActiveCollectionSchemesListener.h" +#include "ICollectionSchemeList.h" #include #endif diff --git a/test/unit/DataSenderProtoWriterTest.cpp b/test/unit/DataSenderProtoWriterTest.cpp index a166597b..254eba2c 100644 --- a/test/unit/DataSenderProtoWriterTest.cpp +++ b/test/unit/DataSenderProtoWriterTest.cpp @@ -7,7 +7,6 @@ #include "Clock.h" #include "ClockHandler.h" #include "CollectionInspectionAPITypes.h" -#include "GeohashInfo.h" #include "OBDDataTypes.h" #include "SignalTypes.h" #include "TimeTypes.h" @@ -147,52 +146,5 @@ TEST_F( DataSenderProtoWriterTest, TestDTCData ) ASSERT_EQ( "P0456", dtcData->active_dtc_codes( 1 ) ); } -// Test the Geohash fields in the proto for the edge to cloud payload -TEST_F( DataSenderProtoWriterTest, TestGeohash ) -{ - CANInterfaceIDTranslator canIDTranslator; - DataSenderProtoWriter protoWriter( canIDTranslator ); - - std::shared_ptr triggeredCollectionSchemeDataPtr = - std::make_shared(); - triggeredCollectionSchemeDataPtr->metadata.persist = false; - triggeredCollectionSchemeDataPtr->metadata.compress = false; - triggeredCollectionSchemeDataPtr->metadata.priority = 0; - triggeredCollectionSchemeDataPtr->metadata.collectionSchemeID = "123"; - triggeredCollectionSchemeDataPtr->metadata.decoderID = "456"; - // Set the trigger time to current time - auto testClock = ClockHandler::getClock(); - Timestamp testTriggerTime = testClock->systemTimeSinceEpochMs(); - triggeredCollectionSchemeDataPtr->triggerTime = testTriggerTime; - - uint32_t collectionEventID = std::rand(); - protoWriter.setupVehicleData( triggeredCollectionSchemeDataPtr, collectionEventID ); - - GeohashInfo geohashInfo; - geohashInfo.mGeohashString = "9q9hwg28j"; - geohashInfo.mPrevReportedGeohashString = "9q9hwg281"; - - protoWriter.append( geohashInfo ); - EXPECT_EQ( protoWriter.getVehicleDataMsgCount(), 1 ); - - std::string out; - EXPECT_TRUE( protoWriter.serializeVehicleData( &out ) ); - - Schemas::VehicleDataMsg::VehicleData vehicleDataTest{}; - - const std::string testProto = out; - ASSERT_TRUE( vehicleDataTest.ParseFromString( testProto ) ); - - /* Read and compare to written fields */ - ASSERT_EQ( "123", vehicleDataTest.campaign_sync_id() ); - ASSERT_EQ( "456", vehicleDataTest.decoder_sync_id() ); - ASSERT_EQ( collectionEventID, vehicleDataTest.collection_event_id() ); - ASSERT_EQ( testTriggerTime, vehicleDataTest.collection_event_time_ms_epoch() ); - - auto geohash = vehicleDataTest.mutable_geohash(); - ASSERT_EQ( "9q9hwg28j", geohash->geohash_string() ); - ASSERT_EQ( "9q9hwg281", geohash->prev_reported_geohash_string() ); -} - } // namespace IoTFleetWise } // namespace Aws diff --git a/test/unit/DecoderDictionaryExtractorTest.cpp b/test/unit/DecoderDictionaryExtractorTest.cpp index f51e4dde..3dbcda3d 100644 --- a/test/unit/DecoderDictionaryExtractorTest.cpp +++ b/test/unit/DecoderDictionaryExtractorTest.cpp @@ -72,13 +72,13 @@ namespace IoTFleetWise * * PID 0x70 Boost Pressure Control * Signal: Boost Pressure A Control Status - * signalID: 0x7005 + * signalID: 0x1005 * start byte: 9 * num of byte: 1 * bit right shift: 0 * bit mask length: 2 * Signal: Boost Pressure B Control Status - * signalID: 0x7006 + * signalID: 0x1006 * start byte: 9 * num of byte: 1 * bit right shift: 2 @@ -109,7 +109,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) Timestamp stopTime3 = startTime3 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> signalToFrameAndNodeID; // This is CAN Frame 0x100 at Node 10 decoding format. It's part of decoder manifest struct CANMessageFormat canMessageFormat0x100; @@ -231,15 +231,15 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) // format Map used by Decoder Manifest Mock to response for getCANMessageFormat( CANRawFrameID canId, // CANInternalChannelID channelId // ) - std::unordered_map> formatMap = { + std::unordered_map> formatMap = { { "10", formatMapNode10 }, { "20", formatMapNode20 } }; // Here's input to decoder manifest for OBD PID Signal decoder information std::unordered_map signalIDToPIDDecoderFormat = { { 0x1000, PIDSignalDecoderFormat( 4, SID::CURRENT_STATS, 0x14, 0.0125, -40.0, 0, 2, 0, 8 ) }, { 0x1001, PIDSignalDecoderFormat( 4, SID::CURRENT_STATS, 0x14, 0.0125, -40.0, 2, 2, 0, 8 ) }, - { 0x7005, PIDSignalDecoderFormat( 10, SID::CURRENT_STATS, 0x70, 1.0, 0.0, 9, 1, 0, 2 ) }, - { 0x7006, PIDSignalDecoderFormat( 10, SID::CURRENT_STATS, 0x70, 1.0, 0.0, 9, 1, 2, 2 ) } }; + { 0x1005, PIDSignalDecoderFormat( 10, SID::CURRENT_STATS, 0x70, 1.0, 0.0, 9, 1, 0, 2 ) }, + { 0x1006, PIDSignalDecoderFormat( 10, SID::CURRENT_STATS, 0x70, 1.0, 0.0, 9, 1, 2, 2 ) } }; // Add OBD-II PID signals to CollectionScheme 1 SignalCollectionInfo obdPidSignal; @@ -247,9 +247,9 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) signalInfo2.emplace_back( obdPidSignal ); obdPidSignal.signalID = 0x1001; signalInfo2.emplace_back( obdPidSignal ); - obdPidSignal.signalID = 0x7005; + obdPidSignal.signalID = 0x1005; signalInfo2.emplace_back( obdPidSignal ); - obdPidSignal.signalID = 0x7006; + obdPidSignal.signalID = 0x1006; signalInfo2.emplace_back( obdPidSignal ); // Add an invalid network protocol signal. PM shall not add it to decoder dictionary SignalCollectionInfo inValidSignal; @@ -368,13 +368,13 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorTest ) ASSERT_EQ( obdPidDecoderDictionary.at( 0 ).at( 0x70 ).format.mSizeInBytes, 10 ); ASSERT_EQ( obdPidDecoderDictionary.at( 0 ).at( 0x70 ).format.mSignals.size(), 2 ); formula = obdPidDecoderDictionary.at( 0 ).at( 0x70 ).format.mSignals[0]; - ASSERT_EQ( formula.mSignalID, 0x7005 ); + ASSERT_EQ( formula.mSignalID, 0x1005 ); ASSERT_DOUBLE_EQ( formula.mFactor, 1.0 ); ASSERT_DOUBLE_EQ( formula.mOffset, 0.0 ); ASSERT_EQ( formula.mFirstBitPosition, 72 ); ASSERT_EQ( formula.mSizeInBits, 2 ); formula = obdPidDecoderDictionary.at( 0 ).at( 0x70 ).format.mSignals[1]; - ASSERT_EQ( formula.mSignalID, 0x7006 ); + ASSERT_EQ( formula.mSignalID, 0x1006 ); ASSERT_DOUBLE_EQ( formula.mFactor, 1.0 ); ASSERT_DOUBLE_EQ( formula.mOffset, 0.0 ); ASSERT_EQ( formula.mFirstBitPosition, 74 ); @@ -472,7 +472,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorNoSignalsTest ) Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> signalToFrameAndNodeID; // This signalInfo vector define a list of signals to collect. It's part of the collectionScheme1. ICollectionScheme::Signals_t signalInfo1 = ICollectionScheme::Signals_t(); @@ -487,7 +487,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorNoSignalsTest ) // decoder Method for all CAN Frames at node 10 std::unordered_map formatMapNode10 = { { 0x100, CANMessageFormat() } }; - std::unordered_map> formatMap = { + std::unordered_map> formatMap = { { "10", formatMapNode10 } }; // Two collectionSchemes. @@ -531,7 +531,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorFirstRawFrameThenSi Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> signalToFrameAndNodeID; // This signalInfo vector define a list of signals to collect. It's part of the collectionScheme1. ICollectionScheme::Signals_t signalInfo1 = ICollectionScheme::Signals_t(); @@ -572,7 +572,7 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryExtractorFirstRawFrameThenSi // decoder Method for all CAN Frames at node 10 std::unordered_map formatMapNode10 = { { 0x100, canMessageFormat0x100 } }; - std::unordered_map> formatMap = { + std::unordered_map> formatMap = { { "10", formatMapNode10 } }; // Two collectionSchemes. @@ -624,12 +624,12 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryComplexDataExtractor ) Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> signalToFrameAndNodeID; ICollectionScheme::Signals_t signalInfo1; - ICollectionScheme::RawCanFrames_t canFrameInfo1; // empty - std::unordered_map> formatMap; // empty - std::unordered_map signalIDToPIDDecoderFormat; // empty + ICollectionScheme::RawCanFrames_t canFrameInfo1; // empty + std::unordered_map> formatMap; // empty + std::unordered_map signalIDToPIDDecoderFormat; // empty ICollectionScheme::PartialSignalIDLookup partialSignalIDLookup; std::unordered_map complexSignalMap; @@ -743,12 +743,12 @@ TEST( CollectionSchemeManagerTest, DecoderDictionaryInvalidPartialSignalIDAndInv Timestamp stopTime1 = startTime1 + SECOND_TO_MILLISECOND( 5 ); // Map to be used by Decoder Manifest Mock to return getCANFrameAndNodeID( SignalID signalId ) - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> signalToFrameAndNodeID; ICollectionScheme::Signals_t signalInfo1; - ICollectionScheme::RawCanFrames_t canFrameInfo1; // empty - std::unordered_map> formatMap; // empty - std::unordered_map signalIDToPIDDecoderFormat; // empty + ICollectionScheme::RawCanFrames_t canFrameInfo1; // empty + std::unordered_map> formatMap; // empty + std::unordered_map signalIDToPIDDecoderFormat; // empty ICollectionScheme::PartialSignalIDLookup partialSignalIDLookup; std::unordered_map complexSignalMap; diff --git a/test/unit/GeohashFunctionNodeTest.cpp b/test/unit/GeohashFunctionNodeTest.cpp deleted file mode 100644 index 99b4161d..00000000 --- a/test/unit/GeohashFunctionNodeTest.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include "GeohashFunctionNode.h" -#include "Geohash.h" -#include "GeohashInfo.h" -#include "ICollectionScheme.h" -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -// This is a utility function to convert GPS signal from Decimal Degree to input unit type -static double -convertFromDecimalDegreeTo( double value, GeohashFunction::GPSUnitType gpsUnitType ) -{ - double convertedValue = 0; - switch ( gpsUnitType ) - { - case GeohashFunction::GPSUnitType::DECIMAL_DEGREE: - convertedValue = value; - break; - case GeohashFunction::GPSUnitType::MICROARCSECOND: - convertedValue = value * 3600000000; - break; - case GeohashFunction::GPSUnitType::MILLIARCSECOND: - convertedValue = value * 3600000; - break; - case GeohashFunction::GPSUnitType::ARCSECOND: - convertedValue = value * 3600; - break; - default: - break; - } - return convertedValue; -} - -/** @brief This test aims to check Geohash function node to correctly - * evaluate geohash changes based on precision - */ -TEST( GeohashFunctionNodeTest, EvaluateGeohashChangeWithDifferentPrecision ) -{ - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hwg28j" ); - // There was no geohash reported to the cloud, so the mPrevReportedGeohashString should be empty - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString.length(), 0 ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hs7rb5" - lon -= 0.1; - // With precision 4, Geohash is the same "9q9h". So we expect evaluate function return false - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - // There was no geohash reported to the cloud, so the mPrevReportedGeohashString should be empty - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString.length(), 0 ); - // Expect No Geohash update - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hd5r01" - lon -= 0.1; - // With precision 5, Geohash tile has changed from "9q9hs" to "9q9hd" - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hd5r00" ); - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString, "9q9hwg28j" ); -} - -/** @brief This test aims to check Geohash function node to report - * no new Geohash if Geohash has been read out previously. - */ -TEST( GeohashFunctionNodeTest, hasNewGeohashReturnFalseIfAlreadyRead ) -{ - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hwg28j" ); - // Since Geohash has been read out in last statement, query hasNewGeohash will return false - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); -} - -/** @brief This test aims to check Geohash function node to gracefully - * handle corner case if GPS Signal is out of bound - */ -TEST( GeohashFunctionNodeTest, EvaluateGeohashWithOutOfRangeGPSSignal ) -{ - GeohashFunctionNode geohashFunctionNode; - // Start at Geohash "9q9hwg28j" - double lat = 137.371392; - double lon = -122.046208; - // lat is not valid, hence evaluation cannot be done which will return false - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hs7rb5" - lat = 37.371392; - lon = -222.046208; - // lon is not valid, hence evaluation cannot be done which will return false - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); -} - -/** @brief This test aims to check Geohash function node to gracefully - * handle corner case is precision is out of bound - */ -TEST( GeohashFunctionNodeTest, EvaluateGeohashWithOutOfRangePrecision ) -{ - // Start up - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - // if precision was set to 0. We shall expect evaluation return false as 0 precision is not valid for evaluation - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 0, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hs7rb5" - lon -= 0.1; - // if precision was greater than maximum precision Geohash library can support. We will use maximum precision for - // evaluation - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( - lat, lon, Geohash::MAX_PRECISION + 1, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hs7rb5" ); -} - -/** @brief This test aims to check Geohash function node to correctly evaluate that Geohash - * has not changed if car has not moved. - */ -TEST( GeohashFunctionNodeTest, EvaluateGeohashWithNoLocationChange ) -{ - // Start up - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hwg28j" ); - - // Without no location change, we shall NOT see an geohash update - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - // Expect No Geohash update - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); -} - -/** @brief This test aims to check Geohash function node to correctly - * take GPS signals with different unit types - */ -TEST( GeohashFunctionNodeTest, EvaluateGeohashWithDifferentGPSUnitType ) -{ - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hwg28j" ); - - // Increase latitude by 0.1 degree to set Geohash to "9q9jnv2wt" - lat += 0.1; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( - convertFromDecimalDegreeTo( lat, GeohashFunction::GPSUnitType::MICROARCSECOND ), - convertFromDecimalDegreeTo( lon, GeohashFunction::GPSUnitType::MICROARCSECOND ), - 4, - GeohashFunction::GPSUnitType::MICROARCSECOND ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9jnv2wt" ); - - // Increase latitude by 0.2 degree to set Geohash to "9q9nqcbev" - lat += 0.2; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( - convertFromDecimalDegreeTo( lat, GeohashFunction::GPSUnitType::MILLIARCSECOND ), - convertFromDecimalDegreeTo( lon, GeohashFunction::GPSUnitType::MILLIARCSECOND ), - 4, - GeohashFunction::GPSUnitType::MILLIARCSECOND ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9nqcbev" ); - - // Increase latitude by 0.2 degree to set Geohash to "9q9pqy28v" - lat += 0.2; - ASSERT_TRUE( - geohashFunctionNode.evaluateGeohash( convertFromDecimalDegreeTo( lat, GeohashFunction::GPSUnitType::ARCSECOND ), - convertFromDecimalDegreeTo( lon, GeohashFunction::GPSUnitType::ARCSECOND ), - 4, - GeohashFunction::GPSUnitType::ARCSECOND ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9pqy28v" ); -} - -/** This test aims to check previous Geohash function node to correctly - * evaluate geohash changes based on precision. - */ -TEST( GeohashFunctionNodeTest, EvaluatePreviousGeohashChange ) -{ - GeohashFunctionNode geohashFunctionNode; - GeohashInfo geohashInfo; - // Start at Geohash "9q9hwg28j" - double lat = 37.371392; - double lon = -122.046208; - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hwg28j" ); - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString.length(), 0 ); - - // Changing longitude by 0.2 degree to set Geohash to "9q9hd5r00" - lon -= 0.2; - // With precision 5, previous geohash should update to "9q9hwg28j" - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hd5r00" ); - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString, "9q9hwg28j" ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hs7rb5" - lon += 0.1; - // With precision 5, previous geohash should update to "9q9hd5r00" - ASSERT_TRUE( geohashFunctionNode.evaluateGeohash( lat, lon, 5, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_TRUE( geohashFunctionNode.hasNewGeohash() ); - geohashFunctionNode.consumeGeohash( geohashInfo ); - ASSERT_EQ( geohashInfo.mGeohashString, "9q9hs7rb5" ); - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString, "9q9hd5r00" ); - - // Changing longitude by 0.1 degree to set Geohash to "9q9hwg28j" - lon += 0.1; - // With precision 4, Geohash is the same "9q9h". So we expect evaluate function return false - ASSERT_FALSE( geohashFunctionNode.evaluateGeohash( lat, lon, 4, GeohashFunction::GPSUnitType::DECIMAL_DEGREE ) ); - ASSERT_EQ( geohashInfo.mPrevReportedGeohashString, "9q9hd5r00" ); - // Expect No Geohash update - ASSERT_FALSE( geohashFunctionNode.hasNewGeohash() ); -} - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/test/unit/GeohashTest.cpp b/test/unit/GeohashTest.cpp deleted file mode 100644 index 5e0c9fad..00000000 --- a/test/unit/GeohashTest.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#include "Geohash.h" -#include -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ - -/** @brief test aims to check Geohash Encoding function to handle invalid - * input such as invalid lat/lon and precision. - */ -TEST( GeohashTest, GeohashEncodeWithInvalidInput ) -{ - std::string hash; - // Invalid lat provided to encode function - ASSERT_FALSE( Geohash::encode( -91, -4.329004883, 9, hash ) ); - ASSERT_FALSE( Geohash::encode( 91, -4.329004883, 9, hash ) ); - // Invalid lon provided to encode function - ASSERT_FALSE( Geohash::encode( -23, -432.9004883, 9, hash ) ); - ASSERT_FALSE( Geohash::encode( -23, 432.9004883, 9, hash ) ); - // Invalid precision provided to encode function - ASSERT_FALSE( Geohash::encode( -23, -4.329004883, 10, hash ) ); - - uint64_t hashBits = 0; - // Invalid lat provided to encode function - ASSERT_FALSE( Geohash::encode( -91, -4.329004883, 9, hashBits ) ); - ASSERT_FALSE( Geohash::encode( 91, -4.329004883, 9, hashBits ) ); - // Invalid lon provided to encode function - ASSERT_FALSE( Geohash::encode( -23, -432.9004883, 9, hashBits ) ); - ASSERT_FALSE( Geohash::encode( -23, 432.9004883, 9, hashBits ) ); - // Invalid precision provided to encode function - ASSERT_FALSE( Geohash::encode( -23, -4.329004883, 10, hashBits ) ); -} - -/** @brief This test aims to check Geohash encoding function to correctly - * encode GPS lat/lon to GeoHash. - */ -TEST( GeohashTest, GeohashEncodeWithValidInput ) -{ - std::string hash; - ASSERT_TRUE( Geohash::encode( 37.371392, -122.046208, 9, hash ) ); - ASSERT_EQ( hash, "9q9hwg28j" ); - - ASSERT_TRUE( Geohash::encode( 37.371392, -122.046208, 5, hash ) ); - ASSERT_EQ( hash, "9q9hw" ); - - ASSERT_TRUE( Geohash::encode( 47.620623, -122.348920, 6, hash ) ); - ASSERT_EQ( hash, "c22yzv" ); - - ASSERT_TRUE( Geohash::encode( 0, 0, 9, hash ) ); - ASSERT_EQ( hash, "s00000000" ); - - ASSERT_TRUE( Geohash::encode( -90.0, -180.0, 7, hash ) ); - ASSERT_EQ( hash, "0000000" ); - - ASSERT_TRUE( Geohash::encode( 90, 180, 8, hash ) ); - ASSERT_EQ( hash, "zzzzzzzz" ); - - uint64_t hashBits = 0; - ASSERT_TRUE( Geohash::encode( 37.371392, -122.046208, 9, hashBits ) ); - ASSERT_EQ( hashBits, 10661749295377 ); - - ASSERT_TRUE( Geohash::encode( 37.371392, -122.046208, 5, hashBits ) ); - ASSERT_EQ( hashBits, 10167836 ); - - ASSERT_TRUE( Geohash::encode( 47.620623, -122.348920, 6, hashBits ) ); - ASSERT_EQ( hashBits, 371293179 ); - - ASSERT_TRUE( Geohash::encode( 0, 0, 9, hashBits ) ); - ASSERT_EQ( hashBits, 26388279066624 ); - - ASSERT_TRUE( Geohash::encode( -90.0, -180.0, 7, hashBits ) ); - ASSERT_EQ( hashBits, 0 ); - - ASSERT_TRUE( Geohash::encode( 90, 180, 8, hashBits ) ); - ASSERT_EQ( hashBits, 1099511627775 ); -} - -} // namespace IoTFleetWise -} // namespace Aws diff --git a/test/unit/InspectionMatrixExtractorTest.cpp b/test/unit/InspectionMatrixExtractorTest.cpp index 5f02aaf3..a4bf7b40 100644 --- a/test/unit/InspectionMatrixExtractorTest.cpp +++ b/test/unit/InspectionMatrixExtractorTest.cpp @@ -40,8 +40,14 @@ TEST( CollectionSchemeManagerTest, InspectionMatrixUpdaterTest ) InspectionEnginePtr.reset( new CollectionInspectionWorkerThreadMock() ); InspectionEnginePtr2.reset( new CollectionInspectionWorkerThreadMock() ); - testPtr->subscribeListener( InspectionEnginePtr.get() ); - testPtr->subscribeListener( InspectionEnginePtr2.get() ); + testPtr->subscribeToInspectionMatrixChange( + std::bind( &CollectionInspectionWorkerThreadMock::onChangeInspectionMatrix, + InspectionEnginePtr.get(), + std::placeholders::_1 ) ); + testPtr->subscribeToInspectionMatrixChange( + std::bind( &CollectionInspectionWorkerThreadMock::onChangeInspectionMatrix, + InspectionEnginePtr2.get(), + std::placeholders::_1 ) ); // Clear updater flag. Note this flag only exist in mock class for testing purpose InspectionEnginePtr->setUpdateFlag( false ); @@ -376,8 +382,8 @@ TEST( CollectionSchemeManagerTest, InspectionMatrixRawBufferConfigUpdaterWithCom CANInterfaceIDTranslator canIDTranslator; test.init( 0, nullptr, canIDTranslator, rawDataBufferManager ); - std::unordered_map> formatMap; - std::unordered_map> signalToFrameAndNodeID; + std::unordered_map> formatMap; + std::unordered_map> signalToFrameAndNodeID; std::unordered_map signalIDToPIDDecoderFormat; std::unordered_map complexDataTypeMap; std::unordered_map complexSignalMap = { diff --git a/test/unit/IoTFleetWiseConfigTest.cpp b/test/unit/IoTFleetWiseConfigTest.cpp index 840c5738..1c36726f 100644 --- a/test/unit/IoTFleetWiseConfigTest.cpp +++ b/test/unit/IoTFleetWiseConfigTest.cpp @@ -3,8 +3,14 @@ // SPDX-License-Identifier: Apache-2.0 #include "IoTFleetWiseConfig.h" +#include "Testing.h" +#include +#include +#include +#include #include #include +#include namespace Aws { @@ -25,5 +31,167 @@ TEST( IoTFleetWiseConfigTest, ReadOk ) ASSERT_EQ( "Trace", config["staticConfig"]["internalParameters"]["systemWideLogLevel"].asString() ); } +TEST( IoTFleetWiseConfigTest, ConfigValues ) +{ + Json::Value jsonConfig; + size_t mySize = static_cast( -1 ); + jsonConfig["my_string"] = "abc"; + jsonConfig["my_int32"] = -123; + jsonConfig["my_uint32"] = 123U; + jsonConfig["my_uint64"] = UINT64_MAX; + jsonConfig["my_float32"] = 123.456; + jsonConfig["my_uint32_string"] = "123"; + jsonConfig["my_uint32_string_hex"] = "0x123"; + jsonConfig["my_size"] = mySize; + jsonConfig["my_bool"] = true; + jsonConfig["my_obj"]["a"] = 1; + jsonConfig["my_array"][0] = 1; + + IoTFleetWiseConfig config( jsonConfig ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asStringRequired(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asStringRequired(), "Config value '123' is not a string at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asStringRequired(), "Config value is not a string at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asStringRequired(), "Config value is not a string at .my_array" ); + EXPECT_EQ( config["my_string"].asStringRequired(), "abc" ); + + EXPECT_EQ( config["a"][0]["b"].asStringOptional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asStringOptional(), "Config value '123' is not a string at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asStringOptional(), "Config value is not a string at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asStringOptional(), "Config value is not a string at .my_array" ); + EXPECT_EQ( config["my_string"].asStringOptional().get(), "abc" ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asU32Required(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].asU32Required(), + "Config value 'abc' is not a valid uint32 at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU32Required(), + "Config value '-123' is not a valid uint32 at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU32Required(), + "Config value '123.456' is not a valid uint32 at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU32Required(), "Config value is not a valid uint32 at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU32Required(), "Config value is not a valid uint32 at .my_array" ); + EXPECT_EQ( config["my_uint32"].asU32Required(), 123 ); + + EXPECT_EQ( config["a"][0]["b"].asU32Optional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_string"].asU32Optional(), + "Config value 'abc' is not a valid uint32 at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU32Optional(), + "Config value '-123' is not a valid uint32 at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU32Optional(), + "Config value '123.456' is not a valid uint32 at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU32Optional(), "Config value is not a valid uint32 at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU32Optional(), "Config value is not a valid uint32 at .my_array" ); + EXPECT_EQ( config["my_uint32"].asU32Optional().get(), 123 ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asU64Required(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].asU64Required(), + "Config value 'abc' is not a valid uint64 at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU64Required(), + "Config value '-123' is not a valid uint64 at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU64Required(), + "Config value '123.456' is not a valid uint64 at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU64Required(), "Config value is not a valid uint64 at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU64Required(), "Config value is not a valid uint64 at .my_array" ); + EXPECT_EQ( config["my_uint64"].asU64Required(), UINT64_MAX ); + + EXPECT_EQ( config["a"][0]["b"].asU64Optional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_string"].asU64Optional(), + "Config value 'abc' is not a valid uint64 at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU64Optional(), + "Config value '-123' is not a valid uint64 at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU64Optional(), + "Config value '123.456' is not a valid uint64 at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU64Optional(), "Config value is not a valid uint64 at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU64Optional(), "Config value is not a valid uint64 at .my_array" ); + EXPECT_EQ( config["my_uint64"].asU64Optional().get(), UINT64_MAX ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asU32FromStringRequired(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].asU32FromStringRequired(), + "Could not convert 'abc' to uint32 for config value at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asU32FromStringRequired(), + "Config value '123' is not a string at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU32FromStringRequired(), + "Config value '-123' is not a string at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU32FromStringRequired(), + "Config value '123.456' is not a string at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU32FromStringRequired(), "Config value is not a string at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU32FromStringRequired(), "Config value is not a string at .my_array" ); + EXPECT_EQ( config["my_uint32_string"].asU32FromStringRequired(), 123 ); + EXPECT_EQ( config["my_uint32_string_hex"].asU32FromStringRequired(), 0x123 ); + + EXPECT_EQ( config["a"][0]["b"].asU32FromStringOptional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_string"].asU32FromStringOptional(), + "Could not convert 'abc' to uint32 for config value at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asU32FromStringOptional(), + "Config value '123' is not a string at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asU32FromStringOptional(), + "Config value '-123' is not a string at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asU32FromStringOptional(), + "Config value '123.456' is not a string at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asU32FromStringOptional(), "Config value is not a string at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asU32FromStringOptional(), "Config value is not a string at .my_array" ); + EXPECT_EQ( config["my_uint32_string"].asU32FromStringOptional().get(), 123 ); + EXPECT_EQ( config["my_uint32_string_hex"].asU32FromStringOptional().get(), 0x123 ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asSizeRequired(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].asSizeRequired(), + "Config value 'abc' is not a valid size at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asSizeRequired(), "Config value '-123' is not a valid size at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asSizeRequired(), + "Config value '123.456' is not a valid size at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asSizeRequired(), "Config value is not a valid size at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asSizeRequired(), "Config value is not a valid size at .my_array" ); + EXPECT_EQ( config["my_size"].asSizeRequired(), mySize ); + + EXPECT_EQ( config["a"][0]["b"].asSizeOptional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_string"].asSizeOptional(), + "Config value 'abc' is not a valid size at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asSizeOptional(), "Config value '-123' is not a valid size at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asSizeOptional(), + "Config value '123.456' is not a valid size at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asSizeOptional(), "Config value is not a valid size at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asSizeOptional(), "Config value is not a valid size at .my_array" ); + EXPECT_EQ( config["my_size"].asSizeOptional(), mySize ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].asBoolRequired(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].asBoolRequired(), "Config value 'abc' is not a bool at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asBoolRequired(), "Config value '123' is not a bool at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asBoolRequired(), "Config value '-123' is not a bool at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asBoolRequired(), + "Config value '123.456' is not a bool at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asBoolRequired(), "Config value is not a bool at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asBoolRequired(), "Config value is not a bool at .my_array" ); + EXPECT_EQ( config["my_bool"].asBoolRequired(), true ); + + EXPECT_EQ( config["a"][0]["b"].asBoolOptional(), boost::none ); + EXPECT_THROW_MESSAGE( config["my_string"].asBoolOptional(), "Config value 'abc' is not a bool at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].asBoolOptional(), "Config value '123' is not a bool at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].asBoolOptional(), "Config value '-123' is not a bool at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].asBoolOptional(), + "Config value '123.456' is not a bool at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].asBoolOptional(), "Config value is not a bool at .my_obj" ); + EXPECT_THROW_MESSAGE( config["my_array"].asBoolOptional(), "Config value is not a bool at .my_array" ); + EXPECT_EQ( config["my_bool"].asBoolOptional().get(), true ); + + EXPECT_FALSE( config.isMember( "a" ) ); + EXPECT_TRUE( config.isMember( "my_string" ) ); + + EXPECT_THROW_MESSAGE( config["a"][0]["b"].getArraySizeRequired(), "Config value missing at .a[0].b" ); + EXPECT_THROW_MESSAGE( config["my_string"].getArraySizeRequired(), "Config value is not an array at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].getArraySizeRequired(), "Config value is not an array at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].getArraySizeRequired(), "Config value is not an array at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].getArraySizeRequired(), "Config value is not an array at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].getArraySizeRequired(), "Config value is not an array at .my_obj" ); + EXPECT_EQ( config["my_array"].getArraySizeRequired(), 1 ); + + EXPECT_EQ( config["a"][0]["b"].getArraySizeOptional(), 0 ); + EXPECT_THROW_MESSAGE( config["my_string"].getArraySizeOptional(), "Config value is not an array at .my_string" ); + EXPECT_THROW_MESSAGE( config["my_uint32"].getArraySizeOptional(), "Config value is not an array at .my_uint32" ); + EXPECT_THROW_MESSAGE( config["my_int32"].getArraySizeOptional(), "Config value is not an array at .my_int32" ); + EXPECT_THROW_MESSAGE( config["my_float32"].getArraySizeOptional(), "Config value is not an array at .my_float32" ); + EXPECT_THROW_MESSAGE( config["my_obj"].getArraySizeOptional(), "Config value is not an array at .my_obj" ); + EXPECT_EQ( config["my_array"].getArraySizeOptional(), 1 ); +} + } // namespace IoTFleetWise } // namespace Aws diff --git a/test/unit/IoTFleetWiseEngineTest.cpp b/test/unit/IoTFleetWiseEngineTest.cpp index 59f93274..6f179d39 100644 --- a/test/unit/IoTFleetWiseEngineTest.cpp +++ b/test/unit/IoTFleetWiseEngineTest.cpp @@ -9,17 +9,25 @@ #include "WaitUntil.h" #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include -#ifdef FWE_FEATURE_IWAVE_GPS -#include -#endif #ifdef FWE_FEATURE_ROS2 #include #endif @@ -29,6 +37,53 @@ namespace Aws namespace IoTFleetWise { +void +makeCert( std::string &keyPem, std::string &certPem ) +{ + std::unique_ptr bn( BN_new(), BN_free ); + if ( !BN_set_word( bn.get(), RSA_F4 ) ) + { + throw std::runtime_error( "error initializing big num" ); + } + auto rsa = RSA_new(); // Ownership passed to pkey below + if ( !RSA_generate_key_ex( rsa, 512, bn.get(), NULL ) ) + { + RSA_free( rsa ); + throw std::runtime_error( "error generating key" ); + } + std::unique_ptr pkey( EVP_PKEY_new(), EVP_PKEY_free ); + if ( !EVP_PKEY_assign_RSA( pkey.get(), rsa ) ) + { + throw std::runtime_error( "error assigning key" ); + } + + std::unique_ptr cert( X509_new(), X509_free ); + X509_set_version( cert.get(), 2 ); + ASN1_INTEGER_set( X509_get_serialNumber( cert.get() ), 0 ); + X509_gmtime_adj( X509_get_notBefore( cert.get() ), 0 ); + X509_gmtime_adj( X509_get_notAfter( cert.get() ), 60 * 60 * 24 * 365 ); + X509_set_pubkey( cert.get(), pkey.get() ); + + auto name = X509_get_subject_name( cert.get() ); + X509_NAME_add_entry_by_txt( name, "C", MBSTRING_ASC, (const unsigned char *)"US", -1, -1, 0 ); + X509_NAME_add_entry_by_txt( name, "CN", MBSTRING_ASC, (const unsigned char *)"Dummy", -1, -1, 0 ); + X509_set_issuer_name( cert.get(), name ); + + if ( !X509_sign( cert.get(), pkey.get(), EVP_md5() ) ) + { + throw std::runtime_error( "error signing certificate" ); + } + + std::unique_ptr bio( BIO_new( BIO_s_mem() ), BIO_free ); + PEM_write_bio_PrivateKey( bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL ); + keyPem.resize( BIO_pending( bio.get() ) ); + BIO_read( bio.get(), &keyPem[0], static_cast( keyPem.size() ) ); + + PEM_write_bio_X509( bio.get(), cert.get() ); + certPem.resize( BIO_pending( bio.get() ) ); + BIO_read( bio.get(), &certPem[0], static_cast( certPem.size() ) ); +} + class IoTFleetWiseEngineTest : public ::testing::Test { protected: @@ -75,6 +130,16 @@ TEST_F( IoTFleetWiseEngineTest, InitAndStartEngine ) ASSERT_TRUE( IoTFleetWiseConfig::read( "static-config-ok.json", config ) ); IoTFleetWiseEngine engine; + std::string keyPem; + std::string certPem; + makeCert( keyPem, certPem ); + std::ofstream dummyPrivateKeyFile( "/tmp/dummyPrivateKey.key" ); + dummyPrivateKeyFile << keyPem; + dummyPrivateKeyFile.close(); + std::ofstream dummyCertificateFile( "/tmp/dummyCertificate.pem" ); + dummyCertificateFile << certPem; + dummyCertificateFile.close(); + ASSERT_TRUE( engine.connect( config ) ); ASSERT_TRUE( engine.start() ); @@ -89,6 +154,13 @@ TEST_F( IoTFleetWiseEngineTest, InitAndStartEngineInlineCreds ) ASSERT_TRUE( IoTFleetWiseConfig::read( "static-config-inline-creds.json", config ) ); IoTFleetWiseEngine engine; + std::string keyPem; + std::string certPem; + makeCert( keyPem, certPem ); + config["staticConfig"]["mqttConnection"]["certificate"] = certPem; + config["staticConfig"]["mqttConnection"]["privateKey"] = keyPem; + config["staticConfig"]["mqttConnection"]["rootCA"] = certPem; + ASSERT_TRUE( engine.connect( config ) ); ASSERT_TRUE( engine.start() ); diff --git a/test/unit/OBDOverCANModuleTest.cpp b/test/unit/OBDOverCANModuleTest.cpp index 08e29fad..da523360 100644 --- a/test/unit/OBDOverCANModuleTest.cpp +++ b/test/unit/OBDOverCANModuleTest.cpp @@ -107,7 +107,6 @@ class OBDOverCANModuleTest : public ::testing::Test condition.signals.push_back( matrixCollectInfo ); condition.afterDuration = 3; condition.minimumPublishIntervalMs = 0; - condition.probabilityToSend = 1.0; condition.includeActiveDtcs = true; condition.triggerOnlyOnRisingEdge = false; // Node diff --git a/test/unit/RawDataManagerTest.cpp b/test/unit/RawDataManagerTest.cpp index 99c8ff8f..2d049ccd 100644 --- a/test/unit/RawDataManagerTest.cpp +++ b/test/unit/RawDataManagerTest.cpp @@ -5,7 +5,6 @@ #include "SignalTypes.h" #include "Testing.h" #include "TimeTypes.h" -#include #include #include #include diff --git a/test/unit/SchemaTest.cpp b/test/unit/SchemaTest.cpp index 985f4bb0..d3c88461 100644 --- a/test/unit/SchemaTest.cpp +++ b/test/unit/SchemaTest.cpp @@ -8,9 +8,9 @@ #include "ClockHandler.h" #include "CollectionSchemeIngestion.h" #include "CollectionSchemeIngestionList.h" -#include "DecoderManifestIngestion.h" #include "EnumUtility.h" #include "ICollectionScheme.h" +#include "ICollectionSchemeList.h" #include "IConnectionTypes.h" #include "IDecoderManifest.h" #include "ISender.h" @@ -22,9 +22,14 @@ #include "VehicleDataSourceTypes.h" #include "checkin.pb.h" #include "collection_schemes.pb.h" +#include "common_types.pb.h" #include "decoder_manifest.pb.h" +#include +#include +#include #include #include +#include #include #include #include @@ -48,68 +53,93 @@ using ::testing::Return; using ::testing::Sequence; using ::testing::StrictMock; -TEST( CollectionSchemeIngestionTest, CollectionSchemeIngestionClass ) +static void +assertCheckin( const std::string &data, const std::vector &sampleDocList, Timestamp timeBeforeCheckin ) { - // Create a dummy AwsIotConnectivityModule object so that we can create dummy IReceiver objects to pass to the - // constructor. Note that the MQTT callback aspect of CollectionSchemeProtoBuilder will not be used in this test. - std::shared_ptr awsIotModule = - std::make_shared( "", "", nullptr ); + std::shared_ptr clock = ClockHandler::getClock(); - std::shared_ptr nullMqttClient; - Schema collectionSchemeIngestion( - std::make_shared( awsIotModule.get(), nullptr, nullMqttClient, "topic", false ), - std::make_shared( awsIotModule.get(), nullptr, nullMqttClient, "topic", false ), - std::make_shared( awsIotModule.get(), nullptr, nullMqttClient, "topic", false ) ); + // Create a multiset of ARNS documents we have in a checkin to compare against was was put in the checkin + std::multiset documentSet( sampleDocList.begin(), sampleDocList.end() ); - auto dummyDecoderManifest = std::make_shared(); - auto dummyCollectionSchemeList = std::make_shared(); - collectionSchemeIngestion.setDecoderManifest( dummyDecoderManifest ); - collectionSchemeIngestion.setCollectionSchemeList( dummyCollectionSchemeList ); + // Deserialize the protobuf + Schemas::CheckinMsg::Checkin sentCheckin; + ASSERT_TRUE( sentCheckin.ParseFromString( data ) ); - // For now only check if the previous calls succeed - ASSERT_TRUE( true ); -} + // Make sure the size of the documents is the same + ASSERT_EQ( sentCheckin.document_sync_ids_size(), sampleDocList.size() ); -/** - * @brief CheckinTest class that allows us to run ASSERTs in callback function of the mocked Callback of ISender - */ -class CheckinTest : public ::testing::Test -{ -public: - static void - checkinTest( const std::string &data, const std::vector &sampleDocList, Timestamp timeBeforeCheckin ) + // Iterate over all the documents found in the checkin + for ( int i = 0; i < sentCheckin.document_sync_ids_size(); i++ ) { - std::shared_ptr clock = ClockHandler::getClock(); + ASSERT_GE( documentSet.count( sentCheckin.document_sync_ids( i ) ), 1 ); + // Erase the entry from the multiset + documentSet.erase( documentSet.find( sentCheckin.document_sync_ids( i ) ) ); + } - // Create a multiset of ARNS documents we have in a checkin to compare against was was put in the checkin - std::multiset documentSet( sampleDocList.begin(), sampleDocList.end() ); + // Make sure we have erased all the elements from our set + ASSERT_EQ( documentSet.size(), 0 ); - // Deserialize the protobuf - Schemas::CheckinMsg::Checkin sentCheckin; - ASSERT_TRUE( sentCheckin.ParseFromString( data ) ); + // 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->systemTimeSinceEpochMs() ); +} - // Make sure the size of the documents is the same - ASSERT_EQ( sentCheckin.document_sync_ids_size(), sampleDocList.size() ); +class SchemaTest : public ::testing::Test +{ +protected: + void + SetUp() override + { + mAwsIotModule = std::make_unique( "", "", nullptr ); + + std::shared_ptr nullMqttClient; + + mChannelDecoderManifest = + std::make_shared( mAwsIotModule.get(), nullptr, nullMqttClient, "topic", false ); + mChannelCollectionSchemeList = + std::make_shared( mAwsIotModule.get(), nullptr, nullMqttClient, "topic", false ); + + mCollectionSchemeIngestion = std::make_unique( + mChannelDecoderManifest, + mChannelCollectionSchemeList, + std::make_shared( mAwsIotModule.get(), nullptr, nullMqttClient, "topic", false ) ); + + mCollectionSchemeIngestion->subscribeToDecoderManifestUpdate( + [&]( const IDecoderManifestPtr &decoderManifest ) { + mReceivedDecoderManifest = decoderManifest; + } ); + mCollectionSchemeIngestion->subscribeToCollectionSchemeUpdate( + [&]( const ICollectionSchemeListPtr &collectionSchemeList ) { + mReceivedCollectionSchemeList = collectionSchemeList; + } ); + } - // Iterate over all the documents found in the checkin - for ( int i = 0; i < sentCheckin.document_sync_ids_size(); i++ ) - { - ASSERT_GE( documentSet.count( sentCheckin.document_sync_ids( i ) ), 1 ); - // Erase the entry from the multiset - documentSet.erase( documentSet.find( sentCheckin.document_sync_ids( i ) ) ); - } + static void + sendMessageToChannel( std::shared_ptr channel, google::protobuf::MessageLite &protoMsg ) + { + std::string protoSerializedBuffer; + ASSERT_TRUE( protoMsg.SerializeToString( &protoSerializedBuffer ) ); - // Make sure we have erased all the elements from our set - ASSERT_EQ( documentSet.size(), 0 ); + auto publishPacket = std::make_shared(); + Aws::Crt::Mqtt5::PublishReceivedEventData eventData; + eventData.publishPacket = publishPacket; + publishPacket->WithPayload( Aws::Crt::ByteCursorFromArray( + reinterpret_cast( protoSerializedBuffer.data() ), protoSerializedBuffer.length() ) ); - // 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->systemTimeSinceEpochMs() ); + channel->onDataReceived( eventData ); } + + std::unique_ptr mAwsIotModule; + std::shared_ptr mChannelDecoderManifest; + std::shared_ptr mChannelCollectionSchemeList; + std::unique_ptr mCollectionSchemeIngestion; + + IDecoderManifestPtr mReceivedDecoderManifest; + ICollectionSchemeListPtr mReceivedCollectionSchemeList; }; -TEST( CollectionSchemeIngestionTest, Checkins ) +TEST_F( SchemaTest, Checkins ) { // Create a dummy AwsIotConnectivityModule object so that we can create dummy IReceiver objects auto awsIotModule = std::make_shared( "", "", nullptr ); @@ -142,7 +172,7 @@ TEST( CollectionSchemeIngestionTest, Checkins ) ASSERT_TRUE( collectionSchemeIngestion.sendCheckin( sampleDocList ) ); ASSERT_EQ( senderMock->getSentBufferData().size(), 1 ); ASSERT_NO_FATAL_FAILURE( - CheckinTest::checkinTest( senderMock->getSentBufferData()[0].data, sampleDocList, timeBeforeCheckin ) ); + assertCheckin( senderMock->getSentBufferData()[0].data, sampleDocList, timeBeforeCheckin ) ); // Add some doc arns sampleDocList.emplace_back( "DocArn1" ); @@ -161,14 +191,14 @@ TEST( CollectionSchemeIngestionTest, Checkins ) ASSERT_FALSE( collectionSchemeIngestion.sendCheckin( sampleDocList ) ); ASSERT_EQ( senderMock->getSentBufferData().size(), 4 ); ASSERT_NO_FATAL_FAILURE( - CheckinTest::checkinTest( senderMock->getSentBufferData()[3].data, sampleDocList, timeBeforeCheckin ) ); + assertCheckin( senderMock->getSentBufferData()[3].data, sampleDocList, timeBeforeCheckin ) ); } /** * @brief This test writes a DecoderManifest object to a protobuf binary array. Then it uses this binary array to build * a DecoderManifestIngestion object. All the functions of that object are tested against the original proto. */ -TEST( SchemaTest, DecoderManifestIngestion ) +TEST_F( SchemaTest, DecoderManifestIngestion ) { #define NODE_A 123 #define NODE_B 4892 @@ -241,34 +271,22 @@ TEST( SchemaTest, DecoderManifestIngestion ) protoOBDPIDSignalB->set_bit_right_shift( 0 ); protoOBDPIDSignalB->set_bit_mask_length( 8 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( protoDM.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - DecoderManifestIngestion testPIDM; - - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIDM.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelDecoderManifest, protoDM ) ); // This should be false because we just copied the data and it needs to be built first - ASSERT_FALSE( testPIDM.isReady() ); + ASSERT_FALSE( mReceivedDecoderManifest->isReady() ); // Assert that we get an empty string when we call getID on an object that's not yet built - ASSERT_EQ( testPIDM.getID(), std::string() ); + ASSERT_EQ( mReceivedDecoderManifest->getID(), std::string() ); - ASSERT_TRUE( testPIDM.build() ); - ASSERT_TRUE( testPIDM.isReady() ); + ASSERT_TRUE( mReceivedDecoderManifest->build() ); + ASSERT_TRUE( mReceivedDecoderManifest->isReady() ); - ASSERT_EQ( testPIDM.getID(), protoDM.sync_id() ); + ASSERT_EQ( mReceivedDecoderManifest->getID(), protoDM.sync_id() ); // Get a valid CANMessageFormat const CANMessageFormat &testCMF = - testPIDM.getCANMessageFormat( protoCANSignalA->message_id(), protoCANSignalA->interface_id() ); + mReceivedDecoderManifest->getCANMessageFormat( protoCANSignalA->message_id(), protoCANSignalA->interface_id() ); ASSERT_TRUE( testCMF.isValid() ); // Search the CANMessageFormat signals to find the signal format that corresponds to a specific signal @@ -280,8 +298,9 @@ TEST( SchemaTest, DecoderManifestIngestion ) { found++; ASSERT_EQ( protoCANSignalA->interface_id(), - testPIDM.getCANFrameAndInterfaceID( sigFormat.mSignalID ).second ); - ASSERT_EQ( protoCANSignalA->message_id(), testPIDM.getCANFrameAndInterfaceID( sigFormat.mSignalID ).first ); + mReceivedDecoderManifest->getCANFrameAndInterfaceID( sigFormat.mSignalID ).second ); + ASSERT_EQ( protoCANSignalA->message_id(), + mReceivedDecoderManifest->getCANFrameAndInterfaceID( sigFormat.mSignalID ).first ); ASSERT_EQ( protoCANSignalA->is_big_endian(), sigFormat.mIsBigEndian ); ASSERT_EQ( protoCANSignalA->is_signed(), sigFormat.mIsSigned ); ASSERT_EQ( protoCANSignalA->start_bit(), sigFormat.mFirstBitPosition ); @@ -294,13 +313,13 @@ TEST( SchemaTest, DecoderManifestIngestion ) ASSERT_EQ( found, 1 ); // Make sure we get a pair of Invalid CAN and Node Ids, for an signal that the the decoder manifest doesn't have - ASSERT_EQ( testPIDM.getCANFrameAndInterfaceID( 9999999 ), - std::make_pair( INVALID_CAN_FRAME_ID, INVALID_CAN_INTERFACE_ID ) ); - ASSERT_EQ( testPIDM.getCANFrameAndInterfaceID( protoCANSignalC->signal_id() ), + ASSERT_EQ( mReceivedDecoderManifest->getCANFrameAndInterfaceID( 9999999 ), + std::make_pair( INVALID_CAN_FRAME_ID, INVALID_INTERFACE_ID ) ); + ASSERT_EQ( mReceivedDecoderManifest->getCANFrameAndInterfaceID( protoCANSignalC->signal_id() ), std::make_pair( protoCANSignalC->message_id(), protoCANSignalC->interface_id() ) ); // Verify OBD-II PID Signals decoder manifest are correctly processed - auto obdPIDDecoderFormat = testPIDM.getPIDSignalDecoderFormat( 123 ); + auto obdPIDDecoderFormat = mReceivedDecoderManifest->getPIDSignalDecoderFormat( 123 ); ASSERT_EQ( protoOBDPIDSignalA->pid_response_length(), obdPIDDecoderFormat.mPidResponseLength ); ASSERT_EQ( protoOBDPIDSignalA->service_mode(), toUType( obdPIDDecoderFormat.mServiceMode ) ); ASSERT_EQ( protoOBDPIDSignalA->pid(), obdPIDDecoderFormat.mPID ); @@ -311,7 +330,7 @@ TEST( SchemaTest, DecoderManifestIngestion ) ASSERT_EQ( protoOBDPIDSignalA->bit_right_shift(), obdPIDDecoderFormat.mBitRightShift ); ASSERT_EQ( protoOBDPIDSignalA->bit_mask_length(), obdPIDDecoderFormat.mBitMaskLength ); - obdPIDDecoderFormat = testPIDM.getPIDSignalDecoderFormat( 567 ); + obdPIDDecoderFormat = mReceivedDecoderManifest->getPIDSignalDecoderFormat( 567 ); ASSERT_EQ( protoOBDPIDSignalB->pid_response_length(), obdPIDDecoderFormat.mPidResponseLength ); ASSERT_EQ( protoOBDPIDSignalB->service_mode(), toUType( obdPIDDecoderFormat.mServiceMode ) ); ASSERT_EQ( protoOBDPIDSignalB->pid(), obdPIDDecoderFormat.mPID ); @@ -323,14 +342,14 @@ TEST( SchemaTest, DecoderManifestIngestion ) ASSERT_EQ( protoOBDPIDSignalB->bit_mask_length(), obdPIDDecoderFormat.mBitMaskLength ); // There's no signal ID 890, hence this function shall return an INVALID_PID_DECODER_FORMAT - obdPIDDecoderFormat = testPIDM.getPIDSignalDecoderFormat( 890 ); + obdPIDDecoderFormat = mReceivedDecoderManifest->getPIDSignalDecoderFormat( 890 ); ASSERT_EQ( obdPIDDecoderFormat, NOT_FOUND_PID_DECODER_FORMAT ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 3908 ), VehicleDataSourceProtocol::RAW_SOCKET ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 2987 ), VehicleDataSourceProtocol::RAW_SOCKET ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 50000 ), VehicleDataSourceProtocol::RAW_SOCKET ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 123 ), VehicleDataSourceProtocol::OBD ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 567 ), VehicleDataSourceProtocol::OBD ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 3908 ), VehicleDataSourceProtocol::RAW_SOCKET ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 2987 ), VehicleDataSourceProtocol::RAW_SOCKET ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 50000 ), VehicleDataSourceProtocol::RAW_SOCKET ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 123 ), VehicleDataSourceProtocol::OBD ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 567 ), VehicleDataSourceProtocol::OBD ); } /** @@ -338,38 +357,26 @@ TEST( SchemaTest, DecoderManifestIngestion ) * contain CAN Node, CAN Signal, OBD Signal. When CollectionScheme Ingestion start building, it will return failure due * to invalid decoder manifest */ -TEST( SchemaTest, SchemaInvalidDecoderManifestTest ) +TEST_F( SchemaTest, SchemaInvalidDecoderManifestTest ) { // Create a Decoder manifest protocol buffer and pack it with the data Schemas::DecoderManifestMsg::DecoderManifest protoDM; protoDM.set_sync_id( "arn:aws:iam::123456789012:user/Development/product_1234/*" ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( protoDM.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - DecoderManifestIngestion testPIDM; - - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIDM.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelDecoderManifest, protoDM ) ); // This should be false because we just copied the data and it needs to be built first - ASSERT_FALSE( testPIDM.isReady() ); + ASSERT_FALSE( mReceivedDecoderManifest->isReady() ); // Assert that we get an empty string when we call getID on an unbuilt object - ASSERT_EQ( testPIDM.getID(), std::string() ); + ASSERT_EQ( mReceivedDecoderManifest->getID(), std::string() ); - ASSERT_FALSE( testPIDM.build() ); - ASSERT_FALSE( testPIDM.isReady() ); + ASSERT_FALSE( mReceivedDecoderManifest->build() ); + ASSERT_FALSE( mReceivedDecoderManifest->isReady() ); } -TEST( SchemaTest, CollectionSchemeIngestionList ) +TEST_F( SchemaTest, CollectionSchemeIngestionList ) { // Create our CollectionSchemeIngestionList object or PIPL for short CollectionSchemeIngestionList testPIPL; @@ -389,7 +396,10 @@ TEST( SchemaTest, CollectionSchemeIngestionList ) // Try to build with garbage data - this should fail ASSERT_FALSE( testPIPL.build() ); +} +TEST_F( SchemaTest, CollectionSchemeBasic ) +{ // Now lets try some real data :) Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; @@ -404,64 +414,83 @@ TEST( SchemaTest, CollectionSchemeIngestionList ) p2->set_campaign_sync_id( collectionSchemeARNs[1] ); p3->set_campaign_sync_id( collectionSchemeARNs[2] ); - // Serialize the protobuffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - // Ensure the serialization worked - ASSERT_TRUE( protoCollectionSchemesMsg.SerializeToString( &protoSerializedBuffer ) ); + // Try to build - this should succeed because we have real data + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); - ASSERT_FALSE( testPIPL.isReady() ); + // Make sure the is ready is good to go + ASSERT_TRUE( mReceivedCollectionSchemeList->isReady() ); - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIPL.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 0 ); +} - // Try to build - this should succeed because we have real data - ASSERT_TRUE( testPIPL.build() ); +TEST_F( SchemaTest, EmptyCollectionSchemeIngestion ) +{ + // Now we have data to pack our DecoderManifestIngestion object with! + CollectionSchemeIngestion collectionSchemeTest; - // Make sure the is ready is good to go - ASSERT_TRUE( testPIPL.isReady() ); + // isReady should evaluate to False + ASSERT_TRUE( collectionSchemeTest.isReady() == false ); - ASSERT_EQ( testPIPL.getCollectionSchemes().size(), 0 ); + // Confirm that Message Metadata is not ready as Build has not been called + ASSERT_FALSE( collectionSchemeTest.getCollectionSchemeID().compare( std::string() ) ); + ASSERT_FALSE( collectionSchemeTest.getDecoderManifestID().compare( std::string() ) ); + ASSERT_TRUE( collectionSchemeTest.getStartTime() == std::numeric_limits::max() ); + ASSERT_TRUE( collectionSchemeTest.getExpiryTime() == std::numeric_limits::max() ); + ASSERT_TRUE( collectionSchemeTest.getAfterDurationMs() == std::numeric_limits::max() ); + ASSERT_TRUE( collectionSchemeTest.isActiveDTCsIncluded() == false ); + ASSERT_TRUE( collectionSchemeTest.isTriggerOnlyOnRisingEdge() == false ); + ASSERT_TRUE( collectionSchemeTest.getCollectSignals().size() == 0 ); + ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().size() == 0 ); + ASSERT_TRUE( collectionSchemeTest.isPersistNeeded() == false ); + ASSERT_TRUE( collectionSchemeTest.isCompressionNeeded() == false ); + ASSERT_TRUE( collectionSchemeTest.getPriority() == std::numeric_limits::max() ); + ASSERT_TRUE( collectionSchemeTest.getCondition() == nullptr ); + ASSERT_TRUE( collectionSchemeTest.getMinimumPublishIntervalMs() == std::numeric_limits::max() ); + ASSERT_TRUE( collectionSchemeTest.getAllExpressionNodes().size() == 0 ); +#ifdef FWE_FEATURE_VISION_SYSTEM_DATA + ASSERT_TRUE( collectionSchemeTest.getS3UploadMetadata() == S3UploadMetadata() ); +#endif } -TEST( SchemaTest, CollectionSchemeIngestionHeartBeat ) +TEST_F( SchemaTest, CollectionSchemeIngestionHeartBeat ) { // Create a collection scheme Proto Message - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1234/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_12" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 1621448160000 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 2621448160000 ); + Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; + auto collectionSchemeTestMessage = protoCollectionSchemesMsg.add_collection_schemes(); + collectionSchemeTestMessage->set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1234/*" ); + collectionSchemeTestMessage->set_decoder_manifest_sync_id( "model_manifest_12" ); + collectionSchemeTestMessage->set_start_time_ms_epoch( 1621448160000 ); + collectionSchemeTestMessage->set_expiry_time_ms_epoch( 2621448160000 ); // Create a Time_based_collection_scheme Schemas::CollectionSchemesMsg::TimeBasedCollectionScheme *message1 = - collectionSchemeTestMessage.mutable_time_based_collection_scheme(); + collectionSchemeTestMessage->mutable_time_based_collection_scheme(); message1->set_time_based_collection_scheme_period_ms( 5000 ); - collectionSchemeTestMessage.set_after_duration_ms( 0 ); - collectionSchemeTestMessage.set_include_active_dtcs( true ); - collectionSchemeTestMessage.set_persist_all_collected_data( true ); - collectionSchemeTestMessage.set_compress_collected_data( true ); - collectionSchemeTestMessage.set_priority( 9 ); + collectionSchemeTestMessage->set_after_duration_ms( 0 ); + collectionSchemeTestMessage->set_include_active_dtcs( true ); + collectionSchemeTestMessage->set_persist_all_collected_data( true ); + collectionSchemeTestMessage->set_compress_collected_data( true ); + collectionSchemeTestMessage->set_priority( 9 ); // Add 3 Signals - Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage->add_signal_information(); signal1->set_signal_id( 0 ); signal1->set_sample_buffer_size( 10000 ); signal1->set_minimum_sample_period_ms( 1000 ); signal1->set_fixed_window_period_ms( 1000 ); signal1->set_condition_only_signal( false ); - Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage->add_signal_information(); signal2->set_signal_id( 1 ); signal2->set_sample_buffer_size( 10000 ); signal2->set_minimum_sample_period_ms( 1000 ); signal2->set_fixed_window_period_ms( 1000 ); signal2->set_condition_only_signal( false ); - Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage->add_signal_information(); signal3->set_signal_id( 2 ); signal3->set_sample_buffer_size( 1000 ); signal3->set_minimum_sample_period_ms( 100 ); @@ -469,127 +498,96 @@ TEST( SchemaTest, CollectionSchemeIngestionHeartBeat ) signal3->set_condition_only_signal( true ); // Add 2 RAW CAN Messages - Schemas::CollectionSchemesMsg::RawCanFrame *can1 = collectionSchemeTestMessage.add_raw_can_frames_to_collect(); + Schemas::CollectionSchemesMsg::RawCanFrame *can1 = collectionSchemeTestMessage->add_raw_can_frames_to_collect(); can1->set_can_interface_id( "123" ); can1->set_can_message_id( 0x350 ); can1->set_sample_buffer_size( 100 ); can1->set_minimum_sample_period_ms( 10000 ); - Schemas::CollectionSchemesMsg::RawCanFrame *can2 = collectionSchemeTestMessage.add_raw_can_frames_to_collect(); + Schemas::CollectionSchemesMsg::RawCanFrame *can2 = collectionSchemeTestMessage->add_raw_can_frames_to_collect(); can2->set_can_interface_id( "124" ); can2->set_can_message_id( 0x351 ); can2->set_sample_buffer_size( 10 ); can2->set_minimum_sample_period_ms( 1000 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - // isReady should evaluate to False - ASSERT_TRUE( collectionSchemeTest.isReady() == false ); - - // Confirm that Message Metadata is not ready as Build has not been called - ASSERT_FALSE( collectionSchemeTest.getCollectionSchemeID().compare( std::string() ) ); - ASSERT_FALSE( collectionSchemeTest.getDecoderManifestID().compare( std::string() ) ); - ASSERT_TRUE( collectionSchemeTest.getStartTime() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getExpiryTime() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getAfterDurationMs() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.isActiveDTCsIncluded() == false ); - ASSERT_TRUE( collectionSchemeTest.isTriggerOnlyOnRisingEdge() == false ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().size() == 0 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().size() == 0 ); - ASSERT_TRUE( collectionSchemeTest.isPersistNeeded() == false ); - ASSERT_TRUE( collectionSchemeTest.isCompressionNeeded() == false ); - ASSERT_TRUE( collectionSchemeTest.getPriority() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getCondition() == nullptr ); - ASSERT_TRUE( collectionSchemeTest.getMinimumPublishIntervalMs() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getAllExpressionNodes().size() == 0 ); -#ifdef FWE_FEATURE_VISION_SYSTEM_DATA - ASSERT_TRUE( collectionSchemeTest.getS3UploadMetadata() == S3UploadMetadata() ); -#endif - - // Test for Copy and Build the message - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); - ASSERT_TRUE( collectionSchemeTest.build() ); + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 1 ); + auto collectionSchemeTest = mReceivedCollectionSchemeList->getCollectionSchemes().at( 0 ); // isReady should now evaluate to True - ASSERT_TRUE( collectionSchemeTest.isReady() == true ); + ASSERT_TRUE( collectionSchemeTest->isReady() == true ); // Confirm that the fields now match the set values in the proto message - ASSERT_FALSE( collectionSchemeTest.getCollectionSchemeID().compare( + ASSERT_FALSE( collectionSchemeTest->getCollectionSchemeID().compare( "arn:aws:iam::2.23606797749:user/Development/product_1234/*" ) ); - ASSERT_FALSE( collectionSchemeTest.getDecoderManifestID().compare( "model_manifest_12" ) ); - ASSERT_TRUE( collectionSchemeTest.getStartTime() == 1621448160000 ); - ASSERT_TRUE( collectionSchemeTest.getExpiryTime() == 2621448160000 ); - ASSERT_TRUE( collectionSchemeTest.getAfterDurationMs() == 0 ); - ASSERT_TRUE( collectionSchemeTest.isActiveDTCsIncluded() == true ); - ASSERT_TRUE( collectionSchemeTest.isTriggerOnlyOnRisingEdge() == false ); - - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().size() == 3 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).signalID == 0 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).sampleBufferSize == 10000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).minimumSampleIntervalMs == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).fixedWindowPeriod == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).isConditionOnlySignal == false ); - - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).signalID == 1 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).sampleBufferSize == 10000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).minimumSampleIntervalMs == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).fixedWindowPeriod == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).isConditionOnlySignal == false ); - - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).signalID == 2 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).sampleBufferSize == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).minimumSampleIntervalMs == 100 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).fixedWindowPeriod == 100 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).isConditionOnlySignal == true ); - - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().size() == 2 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).minimumSampleIntervalMs == 10000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).sampleBufferSize == 100 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).frameID == 0x350 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).interfaceID == "123" ); - - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 1 ).minimumSampleIntervalMs == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 1 ).sampleBufferSize == 10 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 1 ).frameID == 0x351 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 1 ).interfaceID == "124" ); - - ASSERT_TRUE( collectionSchemeTest.isPersistNeeded() == true ); - ASSERT_TRUE( collectionSchemeTest.isCompressionNeeded() == true ); - ASSERT_TRUE( collectionSchemeTest.getPriority() == 9 ); + ASSERT_FALSE( collectionSchemeTest->getDecoderManifestID().compare( "model_manifest_12" ) ); + ASSERT_TRUE( collectionSchemeTest->getStartTime() == 1621448160000 ); + ASSERT_TRUE( collectionSchemeTest->getExpiryTime() == 2621448160000 ); + ASSERT_TRUE( collectionSchemeTest->getAfterDurationMs() == 0 ); + ASSERT_TRUE( collectionSchemeTest->isActiveDTCsIncluded() == true ); + ASSERT_TRUE( collectionSchemeTest->isTriggerOnlyOnRisingEdge() == false ); + + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().size() == 3 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).signalID == 0 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).sampleBufferSize == 10000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).minimumSampleIntervalMs == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).fixedWindowPeriod == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).isConditionOnlySignal == false ); + + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).signalID == 1 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).sampleBufferSize == 10000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).minimumSampleIntervalMs == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).fixedWindowPeriod == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).isConditionOnlySignal == false ); + + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).signalID == 2 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).sampleBufferSize == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).minimumSampleIntervalMs == 100 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).fixedWindowPeriod == 100 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).isConditionOnlySignal == true ); + + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().size() == 2 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).minimumSampleIntervalMs == 10000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).sampleBufferSize == 100 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).frameID == 0x350 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).interfaceID == "123" ); + + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 1 ).minimumSampleIntervalMs == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 1 ).sampleBufferSize == 10 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 1 ).frameID == 0x351 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 1 ).interfaceID == "124" ); + + ASSERT_TRUE( collectionSchemeTest->isPersistNeeded() == true ); + ASSERT_TRUE( collectionSchemeTest->isCompressionNeeded() == true ); + ASSERT_TRUE( collectionSchemeTest->getPriority() == 9 ); // For time based collectionScheme the condition is always set to true hence: currentNode.booleanValue=true - ASSERT_TRUE( collectionSchemeTest.getCondition()->booleanValue == true ); - ASSERT_TRUE( collectionSchemeTest.getCondition()->nodeType == ExpressionNodeType::BOOLEAN ); + ASSERT_TRUE( collectionSchemeTest->getCondition()->booleanValue == true ); + ASSERT_TRUE( collectionSchemeTest->getCondition()->nodeType == ExpressionNodeType::BOOLEAN ); // For time based collectionScheme the getMinimumPublishIntervalMs is the same as // set_time_based_collection_scheme_period_ms - ASSERT_TRUE( collectionSchemeTest.getMinimumPublishIntervalMs() == 5000 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().size(), 1 ); + ASSERT_TRUE( collectionSchemeTest->getMinimumPublishIntervalMs() == 5000 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().size(), 1 ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA // Verify Upload Metadata - ASSERT_EQ( collectionSchemeTest.getS3UploadMetadata(), collectionSchemeTest.INVALID_S3_UPLOAD_METADATA ); + ASSERT_EQ( collectionSchemeTest->getS3UploadMetadata(), collectionSchemeTest->INVALID_S3_UPLOAD_METADATA ); #endif } -TEST( SchemaTest, SchemaCollectionEventBased ) +TEST_F( SchemaTest, SchemaCollectionEventBased ) { - // Create a collection scheme Proto Message - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1235/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_13" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 162144816000 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 262144816000 ); + Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; + auto collectionSchemeTestMessage = protoCollectionSchemesMsg.add_collection_schemes(); + collectionSchemeTestMessage->set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1235/*" ); + collectionSchemeTestMessage->set_decoder_manifest_sync_id( "model_manifest_13" ); + collectionSchemeTestMessage->set_start_time_ms_epoch( 162144816000 ); + collectionSchemeTestMessage->set_expiry_time_ms_epoch( 262144816000 ); // Create an Event/Condition Based CollectionScheme Schemas::CollectionSchemesMsg::ConditionBasedCollectionScheme *message = - collectionSchemeTestMessage.mutable_condition_based_collection_scheme(); + collectionSchemeTestMessage->mutable_condition_based_collection_scheme(); message->set_condition_minimum_interval_ms( 650 ); message->set_condition_language_version( 20 ); message->set_condition_trigger_mode( @@ -739,28 +737,28 @@ TEST( SchemaTest, SchemaCollectionEventBased ) //---------- - collectionSchemeTestMessage.set_after_duration_ms( 0 ); - collectionSchemeTestMessage.set_include_active_dtcs( true ); - collectionSchemeTestMessage.set_persist_all_collected_data( true ); - collectionSchemeTestMessage.set_compress_collected_data( true ); - collectionSchemeTestMessage.set_priority( 5 ); + collectionSchemeTestMessage->set_after_duration_ms( 0 ); + collectionSchemeTestMessage->set_include_active_dtcs( true ); + collectionSchemeTestMessage->set_persist_all_collected_data( true ); + collectionSchemeTestMessage->set_compress_collected_data( true ); + collectionSchemeTestMessage->set_priority( 5 ); // Add 3 Signals - Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage->add_signal_information(); signal1->set_signal_id( 19 ); signal1->set_sample_buffer_size( 5 ); signal1->set_minimum_sample_period_ms( 500 ); signal1->set_fixed_window_period_ms( 600 ); signal1->set_condition_only_signal( true ); - Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage->add_signal_information(); signal2->set_signal_id( 17 ); signal2->set_sample_buffer_size( 10000 ); signal2->set_minimum_sample_period_ms( 1000 ); signal2->set_fixed_window_period_ms( 1000 ); signal2->set_condition_only_signal( false ); - Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage->add_signal_information(); signal3->set_signal_id( 3 ); signal3->set_sample_buffer_size( 1000 ); signal3->set_minimum_sample_period_ms( 100 ); @@ -768,7 +766,7 @@ TEST( SchemaTest, SchemaCollectionEventBased ) signal3->set_condition_only_signal( true ); // Add 1 RAW CAN Messages - Schemas::CollectionSchemesMsg::RawCanFrame *can1 = collectionSchemeTestMessage.add_raw_can_frames_to_collect(); + Schemas::CollectionSchemesMsg::RawCanFrame *can1 = collectionSchemeTestMessage->add_raw_can_frames_to_collect(); can1->set_can_interface_id( "1230" ); can1->set_can_message_id( 0x1FF ); can1->set_sample_buffer_size( 200 ); @@ -780,163 +778,135 @@ TEST( SchemaTest, SchemaCollectionEventBased ) s3_upload_metadata->set_prefix( "testPrefix/" ); s3_upload_metadata->set_region( "us-west-2" ); s3_upload_metadata->set_bucket_owner_account_id( "012345678901" ); - collectionSchemeTestMessage.set_allocated_s3_upload_metadata( s3_upload_metadata ); + collectionSchemeTestMessage->set_allocated_s3_upload_metadata( s3_upload_metadata ); #endif - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; - - // isReady should evaluate to False - ASSERT_TRUE( collectionSchemeTest.isReady() == false ); - - // Confirm that Message Metadata is not ready as Build has not been called - ASSERT_FALSE( collectionSchemeTest.getCollectionSchemeID().compare( std::string() ) ); - ASSERT_FALSE( collectionSchemeTest.getDecoderManifestID().compare( std::string() ) ); - ASSERT_TRUE( collectionSchemeTest.getStartTime() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getExpiryTime() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getAfterDurationMs() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.isActiveDTCsIncluded() == false ); - ASSERT_TRUE( collectionSchemeTest.isTriggerOnlyOnRisingEdge() == false ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().size() == 0 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().size() == 0 ); - ASSERT_TRUE( collectionSchemeTest.isPersistNeeded() == false ); - ASSERT_TRUE( collectionSchemeTest.isCompressionNeeded() == false ); - ASSERT_TRUE( collectionSchemeTest.getPriority() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getCondition() == nullptr ); - ASSERT_TRUE( collectionSchemeTest.getMinimumPublishIntervalMs() == std::numeric_limits::max() ); - ASSERT_TRUE( collectionSchemeTest.getAllExpressionNodes().size() == 0 ); - - // Test for Copy and Build the message - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); - ASSERT_TRUE( collectionSchemeTest.build() ); + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 1 ); + auto collectionSchemeTest = mReceivedCollectionSchemeList->getCollectionSchemes().at( 0 ); // isReady should now evaluate to True - ASSERT_TRUE( collectionSchemeTest.isReady() == true ); + ASSERT_TRUE( collectionSchemeTest->isReady() == true ); // Confirm that the fields now match the set values in the proto message - ASSERT_FALSE( collectionSchemeTest.getCollectionSchemeID().compare( + ASSERT_FALSE( collectionSchemeTest->getCollectionSchemeID().compare( "arn:aws:iam::2.23606797749:user/Development/product_1235/*" ) ); - ASSERT_FALSE( collectionSchemeTest.getDecoderManifestID().compare( "model_manifest_13" ) ); - ASSERT_TRUE( collectionSchemeTest.getStartTime() == 162144816000 ); - ASSERT_TRUE( collectionSchemeTest.getExpiryTime() == 262144816000 ); - ASSERT_TRUE( collectionSchemeTest.getAfterDurationMs() == 0 ); - ASSERT_TRUE( collectionSchemeTest.isActiveDTCsIncluded() == true ); - ASSERT_TRUE( collectionSchemeTest.isTriggerOnlyOnRisingEdge() == false ); + ASSERT_FALSE( collectionSchemeTest->getDecoderManifestID().compare( "model_manifest_13" ) ); + ASSERT_TRUE( collectionSchemeTest->getStartTime() == 162144816000 ); + ASSERT_TRUE( collectionSchemeTest->getExpiryTime() == 262144816000 ); + ASSERT_TRUE( collectionSchemeTest->getAfterDurationMs() == 0 ); + ASSERT_TRUE( collectionSchemeTest->isActiveDTCsIncluded() == true ); + ASSERT_TRUE( collectionSchemeTest->isTriggerOnlyOnRisingEdge() == false ); // Signals - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().size() == 3 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).signalID == 19 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).sampleBufferSize == 5 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).minimumSampleIntervalMs == 500 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).fixedWindowPeriod == 600 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 0 ).isConditionOnlySignal == true ); - - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).signalID == 17 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).sampleBufferSize == 10000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).minimumSampleIntervalMs == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).fixedWindowPeriod == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 1 ).isConditionOnlySignal == false ); - - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).signalID == 3 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).sampleBufferSize == 1000 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).minimumSampleIntervalMs == 100 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).fixedWindowPeriod == 100 ); - ASSERT_TRUE( collectionSchemeTest.getCollectSignals().at( 2 ).isConditionOnlySignal == true ); - - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().size() == 1 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).minimumSampleIntervalMs == 255 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).sampleBufferSize == 200 ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).frameID == 0x1FF ); - ASSERT_TRUE( collectionSchemeTest.getCollectRawCanFrames().at( 0 ).interfaceID == "1230" ); - - ASSERT_TRUE( collectionSchemeTest.isPersistNeeded() == true ); - ASSERT_TRUE( collectionSchemeTest.isCompressionNeeded() == true ); - ASSERT_TRUE( collectionSchemeTest.getPriority() == 5 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().size() == 3 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).signalID == 19 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).sampleBufferSize == 5 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).minimumSampleIntervalMs == 500 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).fixedWindowPeriod == 600 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 0 ).isConditionOnlySignal == true ); + + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).signalID == 17 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).sampleBufferSize == 10000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).minimumSampleIntervalMs == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).fixedWindowPeriod == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 1 ).isConditionOnlySignal == false ); + + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).signalID == 3 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).sampleBufferSize == 1000 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).minimumSampleIntervalMs == 100 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).fixedWindowPeriod == 100 ); + ASSERT_TRUE( collectionSchemeTest->getCollectSignals().at( 2 ).isConditionOnlySignal == true ); + + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().size() == 1 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).minimumSampleIntervalMs == 255 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).sampleBufferSize == 200 ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).frameID == 0x1FF ); + ASSERT_TRUE( collectionSchemeTest->getCollectRawCanFrames().at( 0 ).interfaceID == "1230" ); + + ASSERT_TRUE( collectionSchemeTest->isPersistNeeded() == true ); + ASSERT_TRUE( collectionSchemeTest->isCompressionNeeded() == true ); + ASSERT_TRUE( collectionSchemeTest->getPriority() == 5 ); // For Event based collectionScheme the getMinimumPublishIntervalMs is the same as condition_minimum_interval_ms - ASSERT_TRUE( collectionSchemeTest.getMinimumPublishIntervalMs() == 650 ); + ASSERT_TRUE( collectionSchemeTest->getMinimumPublishIntervalMs() == 650 ); // Verify the AST - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().size(), 52 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().size(), 52 ); //---------- - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).nodeType, ExpressionNodeType::OPERATOR_LOGICAL_AND ); //---------- - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->nodeType, ExpressionNodeType::OPERATOR_LOGICAL_OR ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->nodeType, ExpressionNodeType::OPERATOR_SMALLER ); //---------- - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->nodeType, ExpressionNodeType::OPERATOR_BIGGER ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->nodeType, ExpressionNodeType::OPERATOR_NOT_EQUAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->nodeType, ExpressionNodeType::OPERATOR_SMALLER_EQUAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->nodeType, ExpressionNodeType::OPERATOR_SMALLER ); //---------- - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->right->floatingValue, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->left->nodeType, ExpressionNodeType::OPERATOR_ARITHMETIC_MULTIPLY ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->right->nodeType, ExpressionNodeType::OPERATOR_ARITHMETIC_DIVIDE ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->left->nodeType, ExpressionNodeType::OPERATOR_LOGICAL_NOT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->right->nodeType, ExpressionNodeType::OPERATOR_ARITHMETIC_PLUS ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->left->nodeType, ExpressionNodeType::OPERATOR_ARITHMETIC_MINUS ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->right->nodeType, ExpressionNodeType::OPERATOR_ARITHMETIC_MINUS ); //---------- - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->left->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->left->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->left->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->left->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->left->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->left->right->floatingValue, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->left->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->right->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->right->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->right->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->right->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->right->right->floatingValue, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->right->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->left->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->left->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->left->right, nullptr ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->left->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->left->right, nullptr ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->right->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->right->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->right->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->right->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->right->right->floatingValue, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->left->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->right->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->left->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->left->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->left->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->left->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->left->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->left->right->floatingValue, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->right->left->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->left->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->right->left->nodeType, ExpressionNodeType::SIGNAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->right->left->signalID, 19 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->right->right->nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->right->left->signalID, 19 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->right->right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->right->right->floatingValue, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->right->right->floatingValue, 1 ); //---------- - ASSERT_TRUE( collectionSchemeTest.getCondition()->booleanValue == false ); + ASSERT_TRUE( collectionSchemeTest->getCondition()->booleanValue == false ); #ifdef FWE_FEATURE_VISION_SYSTEM_DATA S3UploadMetadata s3UploadMetadata; @@ -944,106 +914,23 @@ TEST( SchemaTest, SchemaCollectionEventBased ) s3UploadMetadata.prefix = "testPrefix/"; s3UploadMetadata.region = "us-west-2"; s3UploadMetadata.bucketOwner = "012345678901"; - ASSERT_EQ( collectionSchemeTest.getS3UploadMetadata(), s3UploadMetadata ); + ASSERT_EQ( collectionSchemeTest->getS3UploadMetadata(), s3UploadMetadata ); #endif } -TEST( SchemaTest, SchemaGeohashFunctionNode ) -{ - // Create a collection scheme Proto Message - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1235/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_13" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 162144816000 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 262144816000 ); - - // Create an Event/Condition Based CollectionScheme - Schemas::CollectionSchemesMsg::ConditionBasedCollectionScheme *message = - collectionSchemeTestMessage.mutable_condition_based_collection_scheme(); - message->set_condition_minimum_interval_ms( 650 ); - message->set_condition_language_version( 20 ); - message->set_condition_trigger_mode( - Schemas::CollectionSchemesMsg::ConditionBasedCollectionScheme_ConditionTriggerMode_TRIGGER_ALWAYS ); - - // Build a simple AST Tree. - // Root: Equal - // Left Child: GeohashFunction - // Right Child: 1.0 - auto *root = new Schemas::CommonTypesMsg::ConditionNode(); - auto *rootOp = new Schemas::CommonTypesMsg::ConditionNode_NodeOperator(); - rootOp->set_operator_( Schemas::CommonTypesMsg::ConditionNode_NodeOperator_Operator_COMPARE_EQUAL ); - - auto *leftChild = new Schemas::CommonTypesMsg::ConditionNode(); - auto *leftChildFunction = new Schemas::CommonTypesMsg::ConditionNode_NodeFunction(); - auto *leftChildGeohashFunction = new Schemas::CommonTypesMsg::ConditionNode_NodeFunction_GeohashFunction(); - leftChildGeohashFunction->set_latitude_signal_id( 0x1 ); - leftChildGeohashFunction->set_longitude_signal_id( 0x2 ); - leftChildGeohashFunction->set_geohash_precision( 6 ); - leftChildGeohashFunction->set_gps_unit( - Schemas::CommonTypesMsg::ConditionNode_NodeFunction_GeohashFunction_GPSUnitType_MILLIARCSECOND ); - - auto *rightChild = new Schemas::CommonTypesMsg::ConditionNode(); - rightChild->set_node_double_value( 1.0 ); - - leftChildFunction->set_allocated_geohash_function( leftChildGeohashFunction ); - leftChild->set_allocated_node_function( leftChildFunction ); - // connect to root - rootOp->set_allocated_right_child( rightChild ); - rootOp->set_allocated_left_child( leftChild ); - root->set_allocated_node_operator( rootOp ); - message->set_allocated_condition_tree( root ); - - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; - - // isReady should evaluate to False - ASSERT_TRUE( collectionSchemeTest.isReady() == false ); - - // Test for Copy and Build the message - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); - ASSERT_TRUE( collectionSchemeTest.build() ); - - // isReady should now evaluate to True - ASSERT_TRUE( collectionSchemeTest.isReady() == true ); - - // Verify the AST - // Verify Left Side - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().size(), 6 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).nodeType, ExpressionNodeType::OPERATOR_EQUAL ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->nodeType, - ExpressionNodeType::GEOHASHFUNCTION ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->function.geohashFunction.latitudeSignalID, - 0x01 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->function.geohashFunction.longitudeSignalID, - 0x02 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->function.geohashFunction.precision, 6 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->function.geohashFunction.gpsUnitType, - GeohashFunction::GPSUnitType::MILLIARCSECOND ); - - // Verify Right Side - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->nodeType, ExpressionNodeType::FLOAT ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->floatingValue, 1.0 ); -} - #ifdef FWE_FEATURE_VISION_SYSTEM_DATA -TEST( SchemaTest, SchemaCollectionWithComplexTypes ) +TEST_F( SchemaTest, SchemaCollectionWithComplexTypes ) { - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.52543243543:user/Development/complexdata/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_67" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 0 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 9262144816000 ); + Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; + auto collectionSchemeTestMessage = protoCollectionSchemesMsg.add_collection_schemes(); + collectionSchemeTestMessage->set_campaign_sync_id( "arn:aws:iam::2.52543243543:user/Development/complexdata/*" ); + collectionSchemeTestMessage->set_decoder_manifest_sync_id( "model_manifest_67" ); + collectionSchemeTestMessage->set_start_time_ms_epoch( 0 ); + collectionSchemeTestMessage->set_expiry_time_ms_epoch( 9262144816000 ); // Create an Event/Condition Based CollectionScheme Schemas::CollectionSchemesMsg::ConditionBasedCollectionScheme *message = - collectionSchemeTestMessage.mutable_condition_based_collection_scheme(); + collectionSchemeTestMessage->mutable_condition_based_collection_scheme(); message->set_condition_minimum_interval_ms( 650 ); message->set_condition_language_version( 1000 ); message->set_condition_trigger_mode( @@ -1120,37 +1007,29 @@ TEST( SchemaTest, SchemaCollectionWithComplexTypes ) message->set_allocated_condition_tree( root ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - // Test for Copy and Build the message - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); - ASSERT_TRUE( collectionSchemeTest.build() ); + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 1 ); + auto collectionSchemeTest = mReceivedCollectionSchemeList->getCollectionSchemes().at( 0 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().size(), 10 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().size(), 10 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).nodeType, ExpressionNodeType::OPERATOR_EQUAL ); // assume first node is top root node - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left, nullptr ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->function.windowFunction, + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left, nullptr ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->function.windowFunction, WindowFunction::LAST_FIXED_WINDOW_AVG ); - auto leftGeneratedSignalID = collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->signalID; + auto leftGeneratedSignalID = collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->signalID; ASSERT_EQ( leftGeneratedSignalID & INTERNAL_SIGNAL_ID_BITMASK, INTERNAL_SIGNAL_ID_BITMASK ); // check its an internal generated ID - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right, nullptr ); - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left, nullptr ); - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right, nullptr ); - auto rightLeftGeneratedSignalId = collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->signalID; - auto rightRightGeneratedSignalId = collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->signalID; + auto rightLeftGeneratedSignalId = collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->signalID; + auto rightRightGeneratedSignalId = collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->signalID; ASSERT_EQ( rightLeftGeneratedSignalId & INTERNAL_SIGNAL_ID_BITMASK, INTERNAL_SIGNAL_ID_BITMASK ); // check its an internal generated ID ASSERT_EQ( rightRightGeneratedSignalId & INTERNAL_SIGNAL_ID_BITMASK, @@ -1160,17 +1039,18 @@ TEST( SchemaTest, SchemaCollectionWithComplexTypes ) ASSERT_EQ( leftGeneratedSignalID, rightRightGeneratedSignalId ); } -TEST( SchemaTest, SchemaCollectionWithDifferentWayToSpecifySignalIDInExpression ) +TEST_F( SchemaTest, SchemaCollectionWithDifferentWayToSpecifySignalIDInExpression ) { - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.52543243543:user/Development/complexdata/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_67" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 0 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 9262144816000 ); + Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; + auto collectionSchemeTestMessage = protoCollectionSchemesMsg.add_collection_schemes(); + collectionSchemeTestMessage->set_campaign_sync_id( "arn:aws:iam::2.52543243543:user/Development/complexdata/*" ); + collectionSchemeTestMessage->set_decoder_manifest_sync_id( "model_manifest_67" ); + collectionSchemeTestMessage->set_start_time_ms_epoch( 0 ); + collectionSchemeTestMessage->set_expiry_time_ms_epoch( 9262144816000 ); // Create an Event/Condition Based CollectionScheme Schemas::CollectionSchemesMsg::ConditionBasedCollectionScheme *message = - collectionSchemeTestMessage.mutable_condition_based_collection_scheme(); + collectionSchemeTestMessage->mutable_condition_based_collection_scheme(); message->set_condition_minimum_interval_ms( 650 ); message->set_condition_language_version( 1000 ); message->set_condition_trigger_mode( @@ -1237,67 +1117,59 @@ TEST( SchemaTest, SchemaCollectionWithDifferentWayToSpecifySignalIDInExpression message->set_allocated_condition_tree( root ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 1 ); + auto collectionSchemeTest = mReceivedCollectionSchemeList->getCollectionSchemes().at( 0 ); - // Test for Copy and Build the message - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); - ASSERT_TRUE( collectionSchemeTest.build() ); - - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().size(), 14 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).nodeType, + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().size(), 14 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).nodeType, ExpressionNodeType::OPERATOR_EQUAL ); // assume first node is top root node - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left, nullptr ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->function.windowFunction, + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left, nullptr ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->function.windowFunction, WindowFunction::LAST_FIXED_WINDOW_AVG ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->left->signalID, 1 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).left->right->signalID, 2 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->left->signalID, 1 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).left->right->signalID, 2 ); - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right, nullptr ); - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left, nullptr ); - ASSERT_NE( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left, nullptr ); + ASSERT_NE( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right, nullptr ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->left->signalID, 3 ); - ASSERT_EQ( collectionSchemeTest.getAllExpressionNodes().at( 0 ).right->right->signalID, 4 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->left->signalID, 3 ); + ASSERT_EQ( collectionSchemeTest->getAllExpressionNodes().at( 0 ).right->right->signalID, 4 ); } -TEST( SchemaTest, CollectionSchemeComplexHeartbeat ) +TEST_F( SchemaTest, CollectionSchemeComplexHeartbeat ) { - // Create a collection scheme Proto Message - Schemas::CollectionSchemesMsg::CollectionScheme collectionSchemeTestMessage; - collectionSchemeTestMessage.set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1234/*" ); - collectionSchemeTestMessage.set_decoder_manifest_sync_id( "model_manifest_12" ); - collectionSchemeTestMessage.set_start_time_ms_epoch( 1621448160000 ); - collectionSchemeTestMessage.set_expiry_time_ms_epoch( 2621448160000 ); + Schemas::CollectionSchemesMsg::CollectionSchemes protoCollectionSchemesMsg; + auto collectionSchemeTestMessage = protoCollectionSchemesMsg.add_collection_schemes(); + collectionSchemeTestMessage->set_campaign_sync_id( "arn:aws:iam::2.23606797749:user/Development/product_1234/*" ); + collectionSchemeTestMessage->set_decoder_manifest_sync_id( "model_manifest_12" ); + collectionSchemeTestMessage->set_start_time_ms_epoch( 1621448160000 ); + collectionSchemeTestMessage->set_expiry_time_ms_epoch( 2621448160000 ); // Create a Time_based_collection_scheme Schemas::CollectionSchemesMsg::TimeBasedCollectionScheme *message1 = - collectionSchemeTestMessage.mutable_time_based_collection_scheme(); + collectionSchemeTestMessage->mutable_time_based_collection_scheme(); message1->set_time_based_collection_scheme_period_ms( 5000 ); - collectionSchemeTestMessage.set_after_duration_ms( 0 ); - collectionSchemeTestMessage.set_include_active_dtcs( true ); - collectionSchemeTestMessage.set_persist_all_collected_data( true ); - collectionSchemeTestMessage.set_compress_collected_data( true ); - collectionSchemeTestMessage.set_priority( 9 ); + collectionSchemeTestMessage->set_after_duration_ms( 0 ); + collectionSchemeTestMessage->set_include_active_dtcs( true ); + collectionSchemeTestMessage->set_persist_all_collected_data( true ); + collectionSchemeTestMessage->set_compress_collected_data( true ); + collectionSchemeTestMessage->set_priority( 9 ); // Add two normal and one partial signal to collect - Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal1 = collectionSchemeTestMessage->add_signal_information(); signal1->set_signal_id( 0 ); signal1->set_sample_buffer_size( 100 ); signal1->set_minimum_sample_period_ms( 1000 ); signal1->set_fixed_window_period_ms( 1000 ); signal1->set_condition_only_signal( false ); - Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal2 = collectionSchemeTestMessage->add_signal_information(); signal2->set_signal_id( 999 ); signal2->set_sample_buffer_size( 500 ); signal2->set_minimum_sample_period_ms( 1000 ); @@ -1305,7 +1177,7 @@ TEST( SchemaTest, CollectionSchemeComplexHeartbeat ) signal2->set_condition_only_signal( false ); // Add partial signal to collect - Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage.add_signal_information(); + Schemas::CollectionSchemesMsg::SignalInformation *signal3 = collectionSchemeTestMessage->add_signal_information(); signal3->set_signal_id( 999 ); signal3->set_sample_buffer_size( 800 ); signal3->set_minimum_sample_period_ms( 1000 ); @@ -1318,34 +1190,24 @@ TEST( SchemaTest, CollectionSchemeComplexHeartbeat ) path1->add_signal_path( 5 ); signal3->set_allocated_signal_path( path1 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( collectionSchemeTestMessage.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - CollectionSchemeIngestion collectionSchemeTest; - - ASSERT_TRUE( collectionSchemeTest.copyData( - std::make_shared( collectionSchemeTestMessage ) ) ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelCollectionSchemeList, protoCollectionSchemesMsg ) ); - ASSERT_EQ( collectionSchemeTest.getPartialSignalIdToSignalPathLookupTable(), - collectionSchemeTest.INVALID_PARTIAL_SIGNAL_ID_LOOKUP ); - ASSERT_TRUE( collectionSchemeTest.build() ); + ASSERT_TRUE( mReceivedCollectionSchemeList->build() ); + ASSERT_EQ( mReceivedCollectionSchemeList->getCollectionSchemes().size(), 1 ); + auto collectionSchemeTest = mReceivedCollectionSchemeList->getCollectionSchemes().at( 0 ); - ASSERT_EQ( collectionSchemeTest.getCollectSignals().size(), 3 ); - ASSERT_EQ( collectionSchemeTest.getCollectSignals().at( 0 ).signalID, 0 ); - ASSERT_EQ( collectionSchemeTest.getCollectSignals().at( 1 ).signalID, 999 ); - ASSERT_NE( collectionSchemeTest.getCollectSignals().at( 2 ).signalID, 999 ); - ASSERT_EQ( collectionSchemeTest.getCollectSignals().at( 2 ).signalID & INTERNAL_SIGNAL_ID_BITMASK, + ASSERT_EQ( collectionSchemeTest->getCollectSignals().size(), 3 ); + ASSERT_EQ( collectionSchemeTest->getCollectSignals().at( 0 ).signalID, 0 ); + ASSERT_EQ( collectionSchemeTest->getCollectSignals().at( 1 ).signalID, 999 ); + ASSERT_NE( collectionSchemeTest->getCollectSignals().at( 2 ).signalID, 999 ); + ASSERT_EQ( collectionSchemeTest->getCollectSignals().at( 2 ).signalID & INTERNAL_SIGNAL_ID_BITMASK, INTERNAL_SIGNAL_ID_BITMASK ); - auto plt = collectionSchemeTest.getPartialSignalIdToSignalPathLookupTable(); - ASSERT_NE( plt, collectionSchemeTest.INVALID_PARTIAL_SIGNAL_ID_LOOKUP ); + auto plt = collectionSchemeTest->getPartialSignalIdToSignalPathLookupTable(); + ASSERT_NE( plt, collectionSchemeTest->INVALID_PARTIAL_SIGNAL_ID_LOOKUP ); } -TEST( SchemaTest, DecoderManifestIngestionComplexSignals ) +TEST_F( SchemaTest, DecoderManifestIngestionComplexSignals ) { // Create a Decoder manifest protocol buffer and pack it with the data Schemas::DecoderManifestMsg::DecoderManifest protoDM; @@ -1446,68 +1308,66 @@ TEST( SchemaTest, DecoderManifestIngestionComplexSignals ) protoComplexSignal->set_message_id( "/topic/for/ROS:/vehicle/msgs/test.msg" ); protoComplexSignal->set_root_type_id( 20 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( protoDM.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - DecoderManifestIngestion testPIDM; - - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIDM.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelDecoderManifest, protoDM ) ); - ASSERT_TRUE( testPIDM.getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); + ASSERT_TRUE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); - ASSERT_EQ( testPIDM.getComplexDataType( 10 ).type(), typeid( InvalidComplexVariant ) ); + ASSERT_EQ( mReceivedDecoderManifest->getComplexDataType( 10 ).type(), typeid( InvalidComplexVariant ) ); - ASSERT_TRUE( testPIDM.build() ); - ASSERT_TRUE( testPIDM.isReady() ); + ASSERT_TRUE( mReceivedDecoderManifest->build() ); + ASSERT_TRUE( mReceivedDecoderManifest->isReady() ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 123 ), VehicleDataSourceProtocol::COMPLEX_DATA ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 123 ), VehicleDataSourceProtocol::COMPLEX_DATA ); - auto complexDecoder = testPIDM.getComplexSignalDecoderFormat( 123 ); + auto complexDecoder = mReceivedDecoderManifest->getComplexSignalDecoderFormat( 123 ); ASSERT_EQ( complexDecoder.mInterfaceId, "ros2" ); ASSERT_EQ( complexDecoder.mMessageId, "/topic/for/ROS:/vehicle/msgs/test.msg" ); ASSERT_EQ( complexDecoder.mRootTypeId, 20 ); - auto resultRoot = testPIDM.getComplexDataType( 20 ); + auto resultRoot = mReceivedDecoderManifest->getComplexDataType( 20 ); ASSERT_EQ( resultRoot.type(), typeid( ComplexStruct ) ); auto resultStruct = boost::get( resultRoot ); ASSERT_EQ( resultStruct.mOrderedTypeIds.size(), 2 ); ASSERT_EQ( resultStruct.mOrderedTypeIds[0], 10 ); ASSERT_EQ( resultStruct.mOrderedTypeIds[1], 30 ); - auto resultMember1 = testPIDM.getComplexDataType( 10 ); + auto resultMember1 = mReceivedDecoderManifest->getComplexDataType( 10 ); ASSERT_EQ( resultMember1.type(), typeid( PrimitiveData ) ); auto resultPrimitive = boost::get( resultMember1 ); ASSERT_EQ( resultPrimitive.mPrimitiveType, SignalType::UINT64 ); ASSERT_EQ( resultPrimitive.mScaling, 1.0 ); ASSERT_EQ( resultPrimitive.mOffset, 0.0 ); - auto resultMember2 = testPIDM.getComplexDataType( 30 ); + auto resultMember2 = mReceivedDecoderManifest->getComplexDataType( 30 ); ASSERT_EQ( resultMember2.type(), typeid( ComplexArray ) ); auto resultArray = boost::get( resultMember2 ); ASSERT_EQ( resultArray.mSize, 10000 ); ASSERT_EQ( resultArray.mRepeatedTypeId, 10 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 11 ) ).mPrimitiveType, SignalType::BOOLEAN ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 12 ) ).mPrimitiveType, SignalType::UINT8 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 13 ) ).mPrimitiveType, SignalType::UINT16 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 14 ) ).mPrimitiveType, SignalType::UINT32 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 15 ) ).mPrimitiveType, SignalType::INT8 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 16 ) ).mPrimitiveType, SignalType::INT16 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 17 ) ).mPrimitiveType, SignalType::INT32 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 18 ) ).mPrimitiveType, SignalType::INT64 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 19 ) ).mPrimitiveType, SignalType::FLOAT ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 21 ) ).mPrimitiveType, SignalType::DOUBLE ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 11 ) ).mPrimitiveType, + SignalType::BOOLEAN ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 12 ) ).mPrimitiveType, + SignalType::UINT8 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 13 ) ).mPrimitiveType, + SignalType::UINT16 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 14 ) ).mPrimitiveType, + SignalType::UINT32 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 15 ) ).mPrimitiveType, + SignalType::INT8 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 16 ) ).mPrimitiveType, + SignalType::INT16 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 17 ) ).mPrimitiveType, + SignalType::INT32 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 18 ) ).mPrimitiveType, + SignalType::INT64 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 19 ) ).mPrimitiveType, + SignalType::FLOAT ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 21 ) ).mPrimitiveType, + SignalType::DOUBLE ); } -TEST( SchemaTest, DecoderManifestWrong ) +TEST_F( SchemaTest, DecoderManifestWrong ) { // Create a Decoder manifest protocol buffer and pack it with the data Schemas::DecoderManifestMsg::DecoderManifest protoDM; @@ -1551,24 +1411,12 @@ TEST( SchemaTest, DecoderManifestWrong ) protoComplexSignal2->set_message_id( "/topic/for/ROS:/vehicle/msgs/test2.msg" ); protoComplexSignal2->set_root_type_id( 10 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( protoDM.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - DecoderManifestIngestion testPIDM; - - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIDM.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelDecoderManifest, protoDM ) ); - ASSERT_TRUE( testPIDM.build() ); - ASSERT_TRUE( testPIDM.isReady() ); + ASSERT_TRUE( mReceivedDecoderManifest->build() ); + ASSERT_TRUE( mReceivedDecoderManifest->isReady() ); - auto resultMember1 = testPIDM.getComplexDataType( 10 ); + auto resultMember1 = mReceivedDecoderManifest->getComplexDataType( 10 ); ASSERT_EQ( resultMember1.type(), typeid( PrimitiveData ) ); auto resultPrimitive = boost::get( resultMember1 ); ASSERT_EQ( resultPrimitive.mPrimitiveType, SignalType::UINT64 ); @@ -1576,17 +1424,18 @@ TEST( SchemaTest, DecoderManifestWrong ) ASSERT_EQ( resultPrimitive.mOffset, 0.0 ); // unkown types default to UINT8 - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( 20 ) ).mPrimitiveType, SignalType::UINT8 ); + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( 20 ) ).mPrimitiveType, + SignalType::UINT8 ); - ASSERT_FALSE( testPIDM.getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); - ASSERT_FALSE( testPIDM.getComplexSignalDecoderFormat( 123 ).mMessageId.empty() ); + ASSERT_FALSE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); + ASSERT_FALSE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 123 ).mMessageId.empty() ); // Signal with empty interface ID should be ignored an not be set at all - ASSERT_TRUE( testPIDM.getComplexSignalDecoderFormat( 456 ).mInterfaceId.empty() ); - ASSERT_TRUE( testPIDM.getComplexSignalDecoderFormat( 456 ).mMessageId.empty() ); + ASSERT_TRUE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 456 ).mInterfaceId.empty() ); + ASSERT_TRUE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 456 ).mMessageId.empty() ); } -TEST( SchemaTest, DecoderManifestIngestionComplexStringAsArray ) +TEST_F( SchemaTest, DecoderManifestIngestionComplexStringAsArray ) { // Create a Decoder manifest protocol buffer and pack it with the data Schemas::DecoderManifestMsg::DecoderManifest protoDM; @@ -1628,39 +1477,29 @@ TEST( SchemaTest, DecoderManifestIngestionComplexStringAsArray ) protoComplexSignal->set_message_id( "/topic/for/ROS:/vehicle/msgs/test.msg" ); protoComplexSignal->set_root_type_id( 20 ); - // Serialize the protocol buffer to a string to avoid malloc with cstyle arrays - std::string protoSerializedBuffer; - - // Ensure the serialization worked - ASSERT_TRUE( protoDM.SerializeToString( &protoSerializedBuffer ) ); - - // Now we have data to pack our DecoderManifestIngestion object with! - DecoderManifestIngestion testPIDM; - - // We need a cstyle array to mock data coming from the MQTT IoT core callback. We need to convert the const char* - // type of the string pointer we get from .data() to const uint8_t*. This is why reinterpret_cast is used. - testPIDM.copyData( reinterpret_cast( protoSerializedBuffer.data() ), - protoSerializedBuffer.length() ); + ASSERT_NO_FATAL_FAILURE( sendMessageToChannel( mChannelDecoderManifest, protoDM ) ); - ASSERT_TRUE( testPIDM.getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); + ASSERT_TRUE( mReceivedDecoderManifest->getComplexSignalDecoderFormat( 123 ).mInterfaceId.empty() ); - ASSERT_TRUE( testPIDM.build() ); - ASSERT_TRUE( testPIDM.isReady() ); + ASSERT_TRUE( mReceivedDecoderManifest->build() ); + ASSERT_TRUE( mReceivedDecoderManifest->isReady() ); - ASSERT_EQ( testPIDM.getNetworkProtocol( 123 ), VehicleDataSourceProtocol::COMPLEX_DATA ); + ASSERT_EQ( mReceivedDecoderManifest->getNetworkProtocol( 123 ), VehicleDataSourceProtocol::COMPLEX_DATA ); - auto resultMember2 = testPIDM.getComplexDataType( 100 ); + auto resultMember2 = mReceivedDecoderManifest->getComplexDataType( 100 ); ASSERT_EQ( resultMember2.type(), typeid( ComplexArray ) ); auto resultArray = boost::get( resultMember2 ); ASSERT_EQ( resultArray.mSize, 55 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( resultArray.mRepeatedTypeId ) ).mPrimitiveType, + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( resultArray.mRepeatedTypeId ) ) + .mPrimitiveType, SignalType::UINT8 ); - auto resultMember3 = testPIDM.getComplexDataType( 200 ); + auto resultMember3 = mReceivedDecoderManifest->getComplexDataType( 200 ); ASSERT_EQ( resultMember3.type(), typeid( ComplexArray ) ); auto resultArray2 = boost::get( resultMember3 ); ASSERT_EQ( resultArray2.mSize, 77 ); - ASSERT_EQ( boost::get( testPIDM.getComplexDataType( resultArray2.mRepeatedTypeId ) ).mPrimitiveType, + ASSERT_EQ( boost::get( mReceivedDecoderManifest->getComplexDataType( resultArray2.mRepeatedTypeId ) ) + .mPrimitiveType, SignalType::UINT32 ); } #endif diff --git a/test/unit/support/CollectionSchemeManagerMock.h b/test/unit/support/CollectionSchemeManagerMock.h index 4ee39584..a40e0dfa 100644 --- a/test/unit/support/CollectionSchemeManagerMock.h +++ b/test/unit/support/CollectionSchemeManagerMock.h @@ -6,7 +6,6 @@ #include "ClockHandler.h" #include "CollectionSchemeIngestion.h" #include "CollectionSchemeIngestionList.h" -#include "CollectionSchemeManagementListener.h" #include "CollectionSchemeManager.h" #include "DecoderManifestIngestion.h" #include "Listener.h" diff --git a/test/unit/support/CollectionSchemeManagerTest.h b/test/unit/support/CollectionSchemeManagerTest.h index 5c3f65c4..ab05f753 100644 --- a/test/unit/support/CollectionSchemeManagerTest.h +++ b/test/unit/support/CollectionSchemeManagerTest.h @@ -7,14 +7,12 @@ #include "CollectionInspectionWorkerThread.h" #include "CollectionSchemeIngestion.h" #include "CollectionSchemeIngestionList.h" -#include "CollectionSchemeManagementListener.h" #include "CollectionSchemeManager.h" #include "DecoderManifestIngestion.h" #include "ICollectionScheme.h" #include "ICollectionSchemeList.h" #include "IDecoderDictionary.h" #include "IDecoderManifest.h" -#include "Listener.h" #include "MessageTypes.h" #include "OBDOverCANModule.h" #include "SignalTypes.h" @@ -57,8 +55,8 @@ class IDecoderManifestTest : public DecoderManifestIngestion } IDecoderManifestTest( std::string id, - std::unordered_map> formatMap, - std::unordered_map> signalToFrameAndNodeID, + std::unordered_map> formatMap, + std::unordered_map> signalToFrameAndNodeID, std::unordered_map signalIDToPIDDecoderFormat #ifdef FWE_FEATURE_VISION_SYSTEM_DATA , @@ -86,7 +84,7 @@ class IDecoderManifestTest : public DecoderManifestIngestion return ID; } const CANMessageFormat & - getCANMessageFormat( CANRawFrameID canId, CANInterfaceID interfaceId ) const + getCANMessageFormat( CANRawFrameID canId, InterfaceID interfaceId ) const { return mFormatMap.at( interfaceId ).at( canId ); } @@ -95,7 +93,7 @@ class IDecoderManifestTest : public DecoderManifestIngestion { return true; } - std::pair + std::pair getCANFrameAndInterfaceID( SignalID signalId ) const override { return mSignalToFrameAndNodeID.at( signalId ); @@ -108,7 +106,7 @@ class IDecoderManifestTest : public DecoderManifestIngestion { return VehicleDataSourceProtocol::RAW_SOCKET; } - else if ( signalID < 0x10000 ) + else if ( signalID < 0x2000 ) { return VehicleDataSourceProtocol::OBD; } @@ -159,8 +157,8 @@ class IDecoderManifestTest : public DecoderManifestIngestion private: std::string ID; - std::unordered_map> mFormatMap; - std::unordered_map> mSignalToFrameAndNodeID; + std::unordered_map> mFormatMap; + std::unordered_map> mSignalToFrameAndNodeID; std::unordered_map mSignalIDToPIDDecoderFormat; #ifdef FWE_FEATURE_VISION_SYSTEM_DATA std::unordered_map mComplexSignalMap; @@ -311,18 +309,6 @@ class ICollectionSchemeListTest : public CollectionSchemeIngestionList std::vector mCollectionSchemeTest; }; -/* mock producer class that sends update to PM mocking PI */ -class CollectionSchemeManagerTestProducer : public ThreadListeners -{ -public: - CollectionSchemeManagerTestProducer() - { - } - ~CollectionSchemeManagerTestProducer() - { - } -}; - /* mock OBDOverCANModule class that receive decoder dictionary update from PM */ class OBDOverCANModuleMock : public OBDOverCANModule { @@ -335,8 +321,7 @@ class OBDOverCANModuleMock : public OBDOverCANModule { } void - onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, - VehicleDataSourceProtocol networkProtocol ) override + onChangeOfActiveDictionary( ConstDecoderDictionaryConstPtr &dictionary, VehicleDataSourceProtocol networkProtocol ) { OBDOverCANModule::onChangeOfActiveDictionary( dictionary, networkProtocol ); mUpdateFlag = true; @@ -401,22 +386,15 @@ class CollectionSchemeManagerTest : public CollectionSchemeManager { } - void - myRegisterListener() - { - mProducer.subscribeListener( this ); - } void myInvokeCollectionScheme() { - mProducer.notifyListeners( - &CollectionSchemeManagementListener::onCollectionSchemeUpdate, mPlTest ); + this->onCollectionSchemeUpdate( mPlTest ); } void myInvokeDecoderManifest() { - mProducer.notifyListeners( - &CollectionSchemeManagementListener::onDecoderManifestUpdate, mDmTest ); + this->onDecoderManifestUpdate( mDmTest ); } void updateAvailable() @@ -549,7 +527,6 @@ class CollectionSchemeManagerTest : public CollectionSchemeManager } public: - CollectionSchemeManagerTestProducer mProducer; IDecoderManifestPtr mDmTest; std::shared_ptr mPlTest; diff --git a/test/unit/support/ReceiverListenerFake.h b/test/unit/support/ReceiverListenerFake.h deleted file mode 100644 index 6e00c691..00000000 --- a/test/unit/support/ReceiverListenerFake.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "IReceiver.h" -#include -#include -#include -#include -#include - -namespace Aws -{ -namespace IoTFleetWise -{ -namespace Testing -{ - -class ReceiverListenerFake : public IReceiverCallback -{ -public: - std::vector mReceivedData; - - void - onDataReceived( const std::uint8_t *buf, size_t size ) - { - mReceivedData.push_back( std::string( buf, buf + size ) ); - } -}; - -} // namespace Testing -} // namespace IoTFleetWise -} // namespace Aws diff --git a/test/unit/support/Testing.h b/test/unit/support/Testing.h index c974eaed..870a4015 100644 --- a/test/unit/support/Testing.h +++ b/test/unit/support/Testing.h @@ -7,6 +7,21 @@ #include "SignalTypes.h" #include "TimeTypes.h" #include +#include +#include + +#define EXPECT_THROW_MESSAGE( x, message ) \ + try \ + { \ + x; \ + ADD_FAILURE() << "No exception was thrown"; \ + } \ + catch ( const std::exception &e ) \ + { \ + std::string actualMessage( e.what() ); \ + std::string expectedMessage( message ); \ + EXPECT_EQ( actualMessage, expectedMessage ) << "Unexpected exception message"; \ + } namespace Aws { diff --git a/test/unit/support/static-config-inline-creds.json b/test/unit/support/static-config-inline-creds.json index 08436014..01621eee 100644 --- a/test/unit/support/static-config-inline-creds.json +++ b/test/unit/support/static-config-inline-creds.json @@ -39,8 +39,7 @@ }, "internalParameters": { "readyToPublishDataBufferSize": 10000, - "systemWideLogLevel": "Trace", - "dataReductionProbabilityDisabled": false + "systemWideLogLevel": "Trace" }, "publishToCloudParameters": { "maxPublishMessageCount": 1000, diff --git a/test/unit/support/static-config-ok.json b/test/unit/support/static-config-ok.json index de443ec6..bfb44000 100644 --- a/test/unit/support/static-config-ok.json +++ b/test/unit/support/static-config-ok.json @@ -19,6 +19,19 @@ }, "interfaceId": "2", "type": "obdInterface" + }, + { + "interfaceId": "4", + "type": "externalCanInterface" + }, + { + "ros2Interface": { + "executorThreads": 1, + "subscribeQueueLength": 1000, + "introspectionLibraryCompare": "ErrorAndFail" + }, + "interfaceId": "10", + "type": "ros2Interface" } ], "staticConfig": { @@ -40,7 +53,6 @@ "internalParameters": { "readyToPublishDataBufferSize": 10000, "systemWideLogLevel": "Trace", - "dataReductionProbabilityDisabled": false, "persistencyUploadRetryIntervalMs": 5000 }, "publishToCloudParameters": { @@ -56,9 +68,9 @@ "loggingUploadTopic": "aws-iot-fleetwise-logging-upload", "canDataTopic": "can-data", "checkinTopic": "checkin", - "certificateFilename": "path/to/my-certificate.pem.crt", - "privateKeyFilename": "path/to/my-private.pem.key", - "rootCAFilename": "path/to/my-root-ca.pem.crt" + "certificateFilename": "/tmp/dummyCertificate.pem", + "privateKeyFilename": "/tmp/dummyPrivateKey.key", + "rootCAFilename": "/tmp/dummyCertificate.pem" }, "iWaveGpsExample": { "nmeaFilePath": "/tmp/engineTestIWaveGPSfile.txt", diff --git a/tools/android-app/app/src/main/assets/config-0.json b/tools/android-app/app/src/main/assets/config-0.json index 2f464737..f2ed98ec 100644 --- a/tools/android-app/app/src/main/assets/config-0.json +++ b/tools/android-app/app/src/main/assets/config-0.json @@ -31,8 +31,7 @@ }, "internalParameters": { "readyToPublishDataBufferSize": 10000, - "systemWideLogLevel": "Trace", - "dataReductionProbabilityDisabled": false + "systemWideLogLevel": "Trace" }, "publishToCloudParameters": { "maxPublishMessageCount": 1000, diff --git a/tools/build-fwe-cross-arm64.sh b/tools/build-fwe-cross-arm64.sh index ef11e061..c955fd48 100755 --- a/tools/build-fwe-cross-arm64.sh +++ b/tools/build-fwe-cross-arm64.sh @@ -38,10 +38,13 @@ if ${WITH_ROS2_SUPPORT}; then fi if ${WITH_ROS2_SUPPORT}; then + BUILD_DIR=build/iotfleetwise source /opt/ros/galactic/setup.bash colcon build --cmake-args ${CMAKE_OPTIONS} else + BUILD_DIR=build mkdir -p build && cd build cmake ${CMAKE_OPTIONS} .. make -j`nproc` + cd .. fi diff --git a/tools/build-fwe-cross-armhf.sh b/tools/build-fwe-cross-armhf.sh index a91de600..6cc8dcfe 100755 --- a/tools/build-fwe-cross-armhf.sh +++ b/tools/build-fwe-cross-armhf.sh @@ -46,10 +46,13 @@ if ${WITH_ROS2_SUPPORT}; then fi if ${WITH_ROS2_SUPPORT}; then + BUILD_DIR=build/iotfleetwise source /opt/ros/galactic/setup.bash colcon build --cmake-args ${CMAKE_OPTIONS} else + BUILD_DIR=build mkdir -p build && cd build cmake ${CMAKE_OPTIONS} .. make -j`nproc` + cd .. fi diff --git a/tools/build-fwe-native.sh b/tools/build-fwe-native.sh index 06d2cc3a..57f6b8a6 100755 --- a/tools/build-fwe-native.sh +++ b/tools/build-fwe-native.sh @@ -38,10 +38,13 @@ if ${WITH_ROS2_SUPPORT}; then fi if ${WITH_ROS2_SUPPORT}; then + BUILD_DIR=build/iotfleetwise source /opt/ros/galactic/setup.bash colcon build --cmake-args ${CMAKE_OPTIONS} else + BUILD_DIR=build mkdir -p build && cd build cmake ${CMAKE_OPTIONS} .. make -j`nproc` + cd .. fi diff --git a/tools/cfn-templates/fwdemo.yml b/tools/cfn-templates/fwdemo.yml index 2437ac85..bf4a99f9 100644 --- a/tools/cfn-templates/fwdemo.yml +++ b/tools/cfn-templates/fwdemo.yml @@ -462,39 +462,39 @@ Mappings: # Ubuntu 20.04 arm64 AMIs AMIRegionMap: ap-northeast-1: - AMIID: ami-08c2b40b757d7a436 + AMIID: ami-00a2b0a326e2d5aa6 ap-northeast-2: - AMIID: ami-0ae4f84503ebf3d18 + AMIID: ami-072ea936516f1028d ap-northeast-3: - AMIID: ami-06d46b97c052d058f + AMIID: ami-012359d9b70f2677f ap-south-1: - AMIID: ami-0aedb44d8d5454af4 + AMIID: ami-01ee31dce69c952d6 ap-southeast-1: - AMIID: ami-0281c2b7875eaa573 + AMIID: ami-024c051b04436d40f ap-southeast-2: - AMIID: ami-0b1c7f9ffaf189009 + AMIID: ami-09db86a20ff4364df ca-central-1: - AMIID: ami-077fd3ca91fd436e8 + AMIID: ami-0aa71e61651e35060 eu-central-1: - AMIID: ami-0eb0fc432507c6ceb + AMIID: ami-03fefcbe906e86531 eu-north-1: - AMIID: ami-0fc9d4f1e282548cb + AMIID: ami-021eb0bed8ef688f8 eu-west-1: - AMIID: ami-0a7fc9991623e938a + AMIID: ami-05e6fdf346fd69cc4 eu-west-2: - AMIID: ami-00da71119c33fd647 + AMIID: ami-008d5ee70e21f4d3b eu-west-3: - AMIID: ami-00f72fc3d31abc995 + AMIID: ami-0d70b670c6ce568f6 sa-east-1: - AMIID: ami-0418ffcf915b2ec2b + AMIID: ami-05fefec8c0e127811 us-east-1: - AMIID: ami-06978f2d3e435039f + AMIID: ami-0f4581489e6809acf us-east-2: - AMIID: ami-09919781fa752ad93 + AMIID: ami-03e62841910fc75df us-west-1: - AMIID: ami-06de4e4d34dc642c8 + AMIID: ami-0c98a240ce51dda8a us-west-2: - AMIID: ami-0eaba58686a7d034a + AMIID: ami-01ac47a01fc9387bf FleetSizeEc2InstanceTypeMap: "1": InstanceType: m6g.xlarge diff --git a/tools/cfn-templates/fwdev.yml b/tools/cfn-templates/fwdev.yml index f7d5572c..12e82975 100644 --- a/tools/cfn-templates/fwdev.yml +++ b/tools/cfn-templates/fwdev.yml @@ -7,7 +7,7 @@ Parameters: Ec2InstanceType: Description: Type of EC2 instance Type: String - Default: m6g.8xlarge + Default: m6g.2xlarge AllowedValues: - m6g.medium - m6g.large @@ -166,39 +166,39 @@ Mappings: # Ubuntu 20.04 arm64 AMIs AMIRegionMap: ap-northeast-1: - AMIID: ami-08c2b40b757d7a436 + AMIID: ami-00a2b0a326e2d5aa6 ap-northeast-2: - AMIID: ami-0ae4f84503ebf3d18 + AMIID: ami-072ea936516f1028d ap-northeast-3: - AMIID: ami-06d46b97c052d058f + AMIID: ami-012359d9b70f2677f ap-south-1: - AMIID: ami-0aedb44d8d5454af4 + AMIID: ami-01ee31dce69c952d6 ap-southeast-1: - AMIID: ami-0281c2b7875eaa573 + AMIID: ami-024c051b04436d40f ap-southeast-2: - AMIID: ami-0b1c7f9ffaf189009 + AMIID: ami-09db86a20ff4364df ca-central-1: - AMIID: ami-077fd3ca91fd436e8 + AMIID: ami-0aa71e61651e35060 eu-central-1: - AMIID: ami-0eb0fc432507c6ceb + AMIID: ami-03fefcbe906e86531 eu-north-1: - AMIID: ami-0fc9d4f1e282548cb + AMIID: ami-021eb0bed8ef688f8 eu-west-1: - AMIID: ami-0a7fc9991623e938a + AMIID: ami-05e6fdf346fd69cc4 eu-west-2: - AMIID: ami-00da71119c33fd647 + AMIID: ami-008d5ee70e21f4d3b eu-west-3: - AMIID: ami-00f72fc3d31abc995 + AMIID: ami-0d70b670c6ce568f6 sa-east-1: - AMIID: ami-0418ffcf915b2ec2b + AMIID: ami-05fefec8c0e127811 us-east-1: - AMIID: ami-06978f2d3e435039f + AMIID: ami-0f4581489e6809acf us-east-2: - AMIID: ami-09919781fa752ad93 + AMIID: ami-03e62841910fc75df us-west-1: - AMIID: ami-06de4e4d34dc642c8 + AMIID: ami-0c98a240ce51dda8a us-west-2: - AMIID: ami-0eaba58686a7d034a + AMIID: ami-01ac47a01fc9387bf Outputs: Ec2InstanceId: Description: "EC2 instance ID" diff --git a/tools/cfn-templates/vision-system-data-jupyter.yml b/tools/cfn-templates/vision-system-data-jupyter.yml index e7f4c559..df006255 100644 --- a/tools/cfn-templates/vision-system-data-jupyter.yml +++ b/tools/cfn-templates/vision-system-data-jupyter.yml @@ -21,7 +21,7 @@ Parameters: Ec2InstanceType: Description: Type of EC2 instance Type: String - Default: m6g.8xlarge + Default: m6g.2xlarge AllowedValues: - m6g.medium - m6g.large @@ -451,36 +451,36 @@ Mappings: # Ubuntu 20.04 arm64 AMIs AMIRegionMap: ap-northeast-1: - AMIID: ami-08c2b40b757d7a436 + AMIID: ami-00a2b0a326e2d5aa6 ap-northeast-2: - AMIID: ami-0ae4f84503ebf3d18 + AMIID: ami-072ea936516f1028d ap-northeast-3: - AMIID: ami-06d46b97c052d058f + AMIID: ami-012359d9b70f2677f ap-south-1: - AMIID: ami-0aedb44d8d5454af4 + AMIID: ami-01ee31dce69c952d6 ap-southeast-1: - AMIID: ami-0281c2b7875eaa573 + AMIID: ami-024c051b04436d40f ap-southeast-2: - AMIID: ami-0b1c7f9ffaf189009 + AMIID: ami-09db86a20ff4364df ca-central-1: - AMIID: ami-077fd3ca91fd436e8 + AMIID: ami-0aa71e61651e35060 eu-central-1: - AMIID: ami-0eb0fc432507c6ceb + AMIID: ami-03fefcbe906e86531 eu-north-1: - AMIID: ami-0fc9d4f1e282548cb + AMIID: ami-021eb0bed8ef688f8 eu-west-1: - AMIID: ami-0a7fc9991623e938a + AMIID: ami-05e6fdf346fd69cc4 eu-west-2: - AMIID: ami-00da71119c33fd647 + AMIID: ami-008d5ee70e21f4d3b eu-west-3: - AMIID: ami-00f72fc3d31abc995 + AMIID: ami-0d70b670c6ce568f6 sa-east-1: - AMIID: ami-0418ffcf915b2ec2b + AMIID: ami-05fefec8c0e127811 us-east-1: - AMIID: ami-06978f2d3e435039f + AMIID: ami-0f4581489e6809acf us-east-2: - AMIID: ami-09919781fa752ad93 + AMIID: ami-03e62841910fc75df us-west-1: - AMIID: ami-06de4e4d34dc642c8 + AMIID: ami-0c98a240ce51dda8a us-west-2: - AMIID: ami-0eaba58686a7d034a + AMIID: ami-01ac47a01fc9387bf diff --git a/tools/cloud/demo.sh b/tools/cloud/demo.sh index 5e1abf10..e2efa93f 100755 --- a/tools/cloud/demo.sh +++ b/tools/cloud/demo.sh @@ -171,11 +171,13 @@ if [ "${VEHICLE_NAME}" == "" ]; then fi fi -if [ "${DBC_FILE}" == "" ] && [ "${CAMPAIGN_FILE}" == "" ]; then - INCLUDED_SIGNALS="${DEFAULT_INCLUDED_SIGNALS}" -fi -if [ "${ROS2_CONFIG_FILE}" == "" ] && [ "${S3_CAMPAIGN_FILE}" == "" ]; then - INCLUDED_SIGNALS="${INCLUDED_SIGNALS}${DEFAULT_INCLUDED_SIGNALS_VISION_SYSTEM_DATA}" +if [ "${INCLUDED_SIGNALS}" == "" ]; then + if [ "${DBC_FILE}" == "" ] && [ "${CAMPAIGN_FILE}" == "" ]; then + INCLUDED_SIGNALS="${DEFAULT_INCLUDED_SIGNALS}" + fi + if [ "${ROS2_CONFIG_FILE}" == "" ] && [ "${S3_CAMPAIGN_FILE}" == "" ]; then + INCLUDED_SIGNALS="${INCLUDED_SIGNALS}${DEFAULT_INCLUDED_SIGNALS_VISION_SYSTEM_DATA}" + fi fi if ( [ "${DBC_FILE}" != "" ] && [ "${CAMPAIGN_FILE}" == "" ] ); then @@ -395,7 +397,6 @@ aws iam wait role-exists \ --role-name "${SERVICE_ROLE}" echo "Creating service role policy..." -# TODO: VISION_SYSTEMS_DATA_PREVIEW: Remove timestream:DescribeTable after issue fixed in cloud SERVICE_ROLE_POLICY=$(cat <<'EOF' { "Version": "2012-10-17", diff --git a/tools/configure-fwe.sh b/tools/configure-fwe.sh index d5dda517..a41b4edf 100755 --- a/tools/configure-fwe.sh +++ b/tools/configure-fwe.sh @@ -213,14 +213,25 @@ else echo "Error: Unknown connection type ${CONNECTION_TYPE}" fi +# Clear all existing interfaces in the template file: +OUTPUT_CONFIG=`echo "${OUTPUT_CONFIG}" | jq ".networkInterfaces=[]"` + if [ "${CAN_BUS0}" != "" ]; then - OUTPUT_CONFIG=`echo "${OUTPUT_CONFIG}" | jq ".networkInterfaces[0].canInterface.interfaceName=\"${CAN_BUS0}\"" \ - | jq ".networkInterfaces[1].obdInterface.interfaceName=\"${CAN_BUS0}\"" \ - | jq ".networkInterfaces[1].obdInterface.pidRequestIntervalSeconds=5" \ - | jq ".networkInterfaces[1].obdInterface.dtcRequestIntervalSeconds=5" \ - | jq ".networkInterfaces[1].interfaceId=\"0\""` -else - OUTPUT_CONFIG=`echo "${OUTPUT_CONFIG}" | jq ".networkInterfaces=[]"` + CAN_INTERFACE=`echo "{}" | jq ".interfaceId=\"1\"" \ + | jq ".type=\"canInterface\"" \ + | jq ".canInterface.interfaceName=\"${CAN_BUS0}\"" \ + | jq ".canInterface.protocolName=\"CAN\"" \ + | jq ".canInterface.protocolVersion=\"2.0A\""` + OUTPUT_CONFIG=`echo "${OUTPUT_CONFIG}" | jq ".networkInterfaces+=[${CAN_INTERFACE}]"` + + OBD_INTERFACE=`echo "{}" | jq ".interfaceId=\"0\"" \ + | jq ".type=\"obdInterface\"" \ + | jq ".obdInterface.interfaceName=\"${CAN_BUS0}\"" \ + | jq ".obdInterface.pidRequestIntervalSeconds=5" \ + | jq ".obdInterface.dtcRequestIntervalSeconds=5" \ + | jq ".obdInterface.broadcastRequests=true" \ + | jq ".obdInterface.obdStandard=\"J1979\""` + OUTPUT_CONFIG=`echo "${OUTPUT_CONFIG}" | jq ".networkInterfaces+=[${OBD_INTERFACE}]"` fi if [ "${CREDS_ENDPOINT_URL}" != "" ] || [ "${CREDS_ROLE_ALIAS}" != "" ]; then diff --git a/tools/install-deps-cross-android.sh b/tools/install-deps-cross-android.sh index 9885bd38..5860af63 100755 --- a/tools/install-deps-cross-android.sh +++ b/tools/install-deps-cross-android.sh @@ -82,12 +82,16 @@ install_deps() { mkdir -p ${INSTALL_PREFIX} mkdir -p ${NATIVE_PREFIX} - mkdir deps-cross-android && cd deps-cross-android + mkdir -p deps-cross-android && cd deps-cross-android # Boost - git clone https://github.com/moritz-wundke/Boost-for-Android.git + if [ ! -d "Boost-for-Android" ]; then + git clone https://github.com/moritz-wundke/Boost-for-Android.git + wget -q https://archives.boost.io/release/${VERSION_BOOST}/source/boost_${VERSION_BOOST//./_}.tar.bz2 -O Boost-for-Android/boost_${VERSION_BOOST//./_}.tar.bz2 + fi cd Boost-for-Android git checkout 53e6c16ea80c7dcb2683fd548e0c7a09ddffbfc1 + rm -rf build ./build-android.sh \ ${SDK_PREFIX}/ndk/${VERSION_ANDROID_NDK} \ --boost=${VERSION_BOOST} \ @@ -100,8 +104,11 @@ install_deps() { cd .. # Snappy - git clone -b ${VERSION_SNAPPY} https://github.com/google/snappy.git + if [ ! -d "snappy" ]; then + git clone -b ${VERSION_SNAPPY} https://github.com/google/snappy.git + fi cd snappy + rm -rf build mkdir build && cd build cmake \ -DSNAPPY_BUILD_TESTS=OFF \ @@ -120,10 +127,13 @@ install_deps() { if ${WITH_VISION_SYSTEM_DATA}; then # Amazon Ion C - git clone https://github.com/amazon-ion/ion-c.git + if [ ! -d "ion-c" ]; then + git clone https://github.com/amazon-ion/ion-c.git + fi cd ion-c git checkout ${VERSION_ION_C} git submodule update --init + rm -rf build mkdir build && cd build cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -140,10 +150,13 @@ install_deps() { fi # Protobuf - wget -q https://github.com/protocolbuffers/protobuf/releases/download/${VERSION_PROTOBUF_RELEASE}/protobuf-cpp-${VERSION_PROTOBUF}.tar.gz - tar -zxf protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + if [ ! -d "protobuf-${VERSION_PROTOBUF}" ]; then + wget -q https://github.com/protocolbuffers/protobuf/releases/download/${VERSION_PROTOBUF_RELEASE}/protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + tar -zxf protobuf-cpp-${VERSION_PROTOBUF}.tar.gz + fi cd protobuf-${VERSION_PROTOBUF} if [ ! -f ${NATIVE_PREFIX}/bin/protoc ]; then + rm -rf build_native mkdir build_native && cd build_native cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -155,6 +168,7 @@ install_deps() { make install -j`nproc` cd .. fi + rm -rf build_target mkdir build_target && cd build_target cmake \ -DCMAKE_BUILD_TYPE=Release \ @@ -173,8 +187,11 @@ install_deps() { cd ../.. # JsonCpp - git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git + if [ ! -d "jsoncpp" ]; then + git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git + fi cd jsoncpp + rm -rf build mkdir build && cd build cmake \ -DBUILD_SHARED_LIBS=OFF \ @@ -192,7 +209,10 @@ install_deps() { cd ../.. # OpenSSL - wget -q https://www.openssl.org/source/openssl-${VERSION_OPENSSL}.tar.gz + if [ ! -f "openssl-${VERSION_OPENSSL}.tar.gz" ]; then + wget -q https://www.openssl.org/source/openssl-${VERSION_OPENSSL}.tar.gz + fi + rm -rf openssl-${VERSION_OPENSSL} tar -zxf openssl-${VERSION_OPENSSL}.tar.gz cd openssl-${VERSION_OPENSSL} ANDROID_NDK_HOME=${SDK_PREFIX}/ndk/${VERSION_ANDROID_NDK} \ @@ -204,7 +224,10 @@ install_deps() { cd .. # curl - wget -q https://github.com/curl/curl/releases/download/${VERSION_CURL_RELEASE}/curl-${VERSION_CURL}.tar.gz + if [ ! -f "curl-${VERSION_CURL}.tar.gz" ]; then + wget -q https://github.com/curl/curl/releases/download/${VERSION_CURL_RELEASE}/curl-${VERSION_CURL}.tar.gz + fi + rm -rf curl-${VERSION_CURL} tar -zxf curl-${VERSION_CURL}.tar.gz cd curl-${VERSION_CURL} NDK=${SDK_PREFIX}/ndk/${VERSION_ANDROID_NDK} \ @@ -234,8 +257,11 @@ install_deps() { cd .. # AWS C++ SDK - git clone -b ${VERSION_AWS_SDK_CPP} --recursive https://github.com/aws/aws-sdk-cpp.git + if [ ! -d "aws-sdk-cpp" ]; then + git clone -b ${VERSION_AWS_SDK_CPP} --recursive https://github.com/aws/aws-sdk-cpp.git + fi cd aws-sdk-cpp + rm -rf build mkdir build && cd build CFLAGS=-I${INSTALL_PREFIX}/include cmake \ -DENABLE_TESTING=OFF \ @@ -258,7 +284,6 @@ install_deps() { ar -rc ${INSTALL_PREFIX}/lib/libpthread.a cd .. - rm -rf deps-cross-android } for ARCH in ${ARCHS}; do @@ -282,3 +307,4 @@ for ARCH in ${ARCHS}; do install_deps ${TARGET_ARCH} ${HOST_PLATFORM} ${SSL_TARGET} fi done +rm -rf deps-cross-android diff --git a/tools/install-deps-cross-arm64.sh b/tools/install-deps-cross-arm64.sh index 90468605..f49e0e33 100755 --- a/tools/install-deps-cross-arm64.sh +++ b/tools/install-deps-cross-arm64.sh @@ -84,9 +84,6 @@ apt install -y \ crossbuild-essential-arm64 \ curl \ git \ - libboost-log-dev:arm64 \ - libboost-system-dev:arm64 \ - libboost-thread-dev:arm64 \ libsnappy-dev:arm64 \ libssl-dev:arm64 \ unzip \ @@ -125,7 +122,34 @@ if ! ${USE_CACHE} || [ ! -d /usr/local/aarch64-linux-gnu ] || [ ! -d ${NATIVE_PR mkdir -p /usr/local/aarch64-linux-gnu/lib/cmake/ mkdir -p ${NATIVE_PREFIX} cp ${SCRIPT_DIR}/arm64-toolchain.cmake /usr/local/aarch64-linux-gnu/lib/cmake/ - mkdir deps-cross-arm64 && cd deps-cross-arm64 + mkdir deps-cross-arm64 + cd deps-cross-arm64 + + wget -q https://archives.boost.io/release/${VERSION_BOOST}/source/boost_${VERSION_BOOST//./_}.tar.bz2 + tar -jxf boost_${VERSION_BOOST//./_}.tar.bz2 + cd boost_${VERSION_BOOST//./_} + ./bootstrap.sh + # Build static libraries with -fPIC enabled, so they can later be linked into shared libraries + # (The Ubuntu static libraries are not built with -fPIC) + if [ "${SHARED_LIBS}" == "OFF" ]; then + BOOST_OPTIONS="cxxflags=-fPIC cflags=-fPIC link=static" + else + BOOST_OPTIONS="" + fi + echo "using gcc : arm64 : aarch64-linux-gnu-g++ ;" > user-config.jam + ./b2 \ + --with-atomic \ + --with-system \ + --with-thread \ + --with-filesystem \ + --with-program_options \ + --prefix=/usr/local/aarch64-linux-gnu \ + ${BOOST_OPTIONS} \ + --user-config=user-config.jam \ + -j`nproc` \ + toolset=gcc-arm64 \ + install + cd .. git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp diff --git a/tools/install-deps-cross-armhf.sh b/tools/install-deps-cross-armhf.sh index 35cde5e2..e3c26b76 100755 --- a/tools/install-deps-cross-armhf.sh +++ b/tools/install-deps-cross-armhf.sh @@ -84,9 +84,6 @@ apt install -y \ crossbuild-essential-armhf \ curl \ git \ - libboost-log-dev:armhf \ - libboost-system-dev:armhf \ - libboost-thread-dev:armhf \ libsnappy-dev:armhf \ libssl-dev:armhf \ unzip \ @@ -125,7 +122,34 @@ if ! ${USE_CACHE} || [ ! -d /usr/local/arm-linux-gnueabihf ] || [ ! -d ${NATIVE_ mkdir -p /usr/local/arm-linux-gnueabihf/lib/cmake/ mkdir -p ${NATIVE_PREFIX} cp ${SCRIPT_DIR}/armhf-toolchain.cmake /usr/local/arm-linux-gnueabihf/lib/cmake/ - mkdir deps-cross-armhf && cd deps-cross-armhf + mkdir deps-cross-armhf + cd deps-cross-armhf + + wget -q https://archives.boost.io/release/${VERSION_BOOST}/source/boost_${VERSION_BOOST//./_}.tar.bz2 + tar -jxf boost_${VERSION_BOOST//./_}.tar.bz2 + cd boost_${VERSION_BOOST//./_} + ./bootstrap.sh + # Build static libraries with -fPIC enabled, so they can later be linked into shared libraries + # (The Ubuntu static libraries are not built with -fPIC) + if [ "${SHARED_LIBS}" == "OFF" ]; then + BOOST_OPTIONS="cxxflags=-fPIC cflags=-fPIC link=static" + else + BOOST_OPTIONS="" + fi + echo "using gcc : armhf : arm-linux-gnueabihf-g++ ;" > user-config.jam + ./b2 \ + --with-atomic \ + --with-system \ + --with-thread \ + --with-filesystem \ + --with-program_options \ + --prefix=/usr/local/arm-linux-gnueabihf \ + ${BOOST_OPTIONS} \ + --user-config=user-config.jam \ + -j`nproc` \ + toolset=gcc-armhf \ + install + cd .. git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp diff --git a/tools/install-deps-native.sh b/tools/install-deps-native.sh index 9cdb067c..ed4de108 100755 --- a/tools/install-deps-native.sh +++ b/tools/install-deps-native.sh @@ -62,9 +62,6 @@ if ${INSTALL_BUILD_TIME_DEPS}; then faketime \ git \ graphviz \ - libboost-log-dev \ - libboost-system-dev \ - libboost-thread-dev \ libsnappy-dev \ libssl-dev \ unzip \ @@ -106,7 +103,31 @@ fi if ${INSTALL_BUILD_TIME_DEPS} && ( ! ${USE_CACHE} || [ ! -d ${PREFIX} ] ); then mkdir -p ${PREFIX} - mkdir deps-native && cd deps-native + mkdir deps-native + cd deps-native + + wget -q https://archives.boost.io/release/${VERSION_BOOST}/source/boost_${VERSION_BOOST//./_}.tar.bz2 + tar -jxf boost_${VERSION_BOOST//./_}.tar.bz2 + cd boost_${VERSION_BOOST//./_} + ./bootstrap.sh + # Build static libraries with -fPIC enabled, so they can later be linked into shared libraries + # (The Ubuntu static libraries are not built with -fPIC) + if [ "${SHARED_LIBS}" == "OFF" ]; then + BOOST_OPTIONS="cxxflags=-fPIC cflags=-fPIC link=static" + else + BOOST_OPTIONS="" + fi + ./b2 \ + --with-atomic \ + --with-system \ + --with-thread \ + --with-filesystem \ + --with-program_options \ + --prefix=${PREFIX} \ + ${BOOST_OPTIONS} \ + -j`nproc` \ + install + cd .. git clone -b ${VERSION_JSON_CPP} https://github.com/open-source-parsers/jsoncpp.git cd jsoncpp diff --git a/tools/install-deps-versions.sh b/tools/install-deps-versions.sh index b5663917..5e22021f 100755 --- a/tools/install-deps-versions.sh +++ b/tools/install-deps-versions.sh @@ -1,4 +1,5 @@ #!/bin/bash +export VERSION_BOOST="1.78.0" export VERSION_JSON_CPP="1.9.5" export VERSION_PROTOBUF="3.21.12" export VERSION_PROTOBUF_RELEASE="v21.12" @@ -19,5 +20,4 @@ export VERSION_ANDROID_BUILD_TOOLS="30.0.3" export VERSION_CMAKE="3.22.1" # Provided by Ubuntu 20.04, version here used for Android build export VERSION_SNAPPY="1.1.8" # Provided by Ubuntu 20.04, version here used for Android build export VERSION_OPENSSL="1.1.1w" # Provided by Ubuntu 20.04, version here used for Android build -export VERSION_BOOST="1.78.0" # Provided by Ubuntu 20.04, version here used for Android build export VERSION_ION_C="v1.1.2"