diff --git a/.gitignore b/.gitignore
index 03368199..d5bc1c2f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,7 @@ settings.json
asn1c_combined/compile.out
asn1c_combined/converter-example
asn1c_combined/converter-example.mk
-asn1c_combined/libasncodec.a
\ No newline at end of file
+asn1c_combined/libasncodec.a
+
+.idea/
+cmake-build-*/
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 41c6e910..c6ee9a31 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1)
project(ACM)
# need to set these prior to setting any targets.
-set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_VERBOSE_MAKEFILE ON)
diff --git a/asn1c_combined/generate-files.sh b/asn1c_combined/generate-files.sh
index dc98409e..a3188e41 100644
--- a/asn1c_combined/generate-files.sh
+++ b/asn1c_combined/generate-files.sh
@@ -36,9 +36,6 @@ if [ "$year" == "2024" ]; then
patch --binary --backup --forward --reject-file="-" \
./j2735-asn-files/2024/J3217-TollUsageMsg-2024-rel-v1.1.asn \
./j2735-asn-files/2024/asn-edits/TollUsageMessage.patch
- patch --binary --backup --forward --reject-file="-" \
- ./j2735-asn-files/2024/J2735-Common-2024-rel-v1.1.2.asn \
- ./j2735-asn-files/2024/asn-edits/Common.patch
# Verify that the patches were applied correctly
if ! grep -q RwmSnapShot ./j2735-asn-files/2024/J2945-3-RoadWeatherMessage-2024-rel-v2.1.asn; then
@@ -56,10 +53,6 @@ if [ "$year" == "2024" ]; then
exit 1
fi
- if grep -q " eventJackKnife " ./j2735-asn-files/2024/J2735-Common-2024-rel-v1.1.2.asn; then
- echo "The patch for the Common ASN file was not applied correctly."
- exit 1
- fi
fi
diff --git a/asn1c_combined/generated-files/2024.tar.gz b/asn1c_combined/generated-files/2024.tar.gz
index a5b95616..abd116c6 100644
Binary files a/asn1c_combined/generated-files/2024.tar.gz and b/asn1c_combined/generated-files/2024.tar.gz differ
diff --git a/asn1c_combined/j2735-asn-files/2024/asn-edits/Common.patch b/asn1c_combined/j2735-asn-files/2024/asn-edits/Common.patch
deleted file mode 100644
index 8be2d142..00000000
--- a/asn1c_combined/j2735-asn-files/2024/asn-edits/Common.patch
+++ /dev/null
@@ -1,17 +0,0 @@
---- J2735-Common-2024-rel-v1.1.2.asn 2024-05-16 14:48:14.000000000 -0600
-+++ J2735-Common-2024-rel-v1.1.2.asn.EDITED 2025-01-17 16:10:23.262921200 -0700
-@@ -1874,11 +1874,11 @@
- eventWipersChanged (9),
- eventFlatTire (10),
- eventDisabledVehicle (11), -- The DisabledVehicle DF may also be sent
-- eventAirBagDeployment (12),
-- eventJackKnife (13) -- Applies to vehicles with trailer(s)
-- } (SIZE (13, ..., 14))
-+ eventAirBagDeployment (12)
-+ } (SIZE (13, ...))
- -- To extend: Append event flags to the list,
- -- and update extension marker, e.g., (Size (13, ..., 14..16))
-+-- EDITED: reverted to previous definition without 'eventJackKnife'
-
- VehicleHeight ::= INTEGER (0..127)
- -- the height of the vehicle
diff --git a/asn1c_combined/j2735-asn-files/2024/overrides/VehicleEventFlags.c b/asn1c_combined/j2735-asn-files/2024/overrides/VehicleEventFlags.c
new file mode 100644
index 00000000..b033b602
--- /dev/null
+++ b/asn1c_combined/j2735-asn-files/2024/overrides/VehicleEventFlags.c
@@ -0,0 +1,95 @@
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "Common"
+ * found in "./j2735-asn-files/2024/J2735-Common-2024-rel-v1.1.2.asn"
+ * `asn1c -fcompound-names -gen-OER -fincludes-quoted -no-gen-JER -pdu=all -D ./generated-files/2024`
+ */
+
+#include "VehicleEventFlags.h"
+
+int
+VehicleEventFlags_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
+ asn_app_constraint_failed_f *ctfailcb, void *app_key) {
+ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
+ size_t size;
+
+ if(!sptr) {
+ ASN__CTFAIL(app_key, td, sptr,
+ "%s: value not given (%s:%d)",
+ td->name, __FILE__, __LINE__);
+ return -1;
+ }
+
+ if(st->size > 0) {
+ /* Size in bits */
+ size = 8 * st->size - (st->bits_unused & 0x07);
+ } else {
+ size = 0;
+ }
+
+ /*
+ * NOT edited. Keep the size constraint including extension in this check.
+ */
+ if((size >= 13UL && size <= 14UL)) {
+ /* Constraint check succeeded */
+ return 0;
+ } else {
+ ASN__CTFAIL(app_key, td, sptr,
+ "%s: constraint failed (%s:%d)",
+ td->name, __FILE__, __LINE__);
+ return -1;
+ }
+}
+
+/*
+ * This type is implemented using BIT_STRING,
+ * so here we adjust the DEF accordingly.
+ */
+#if !defined(ASN_DISABLE_OER_SUPPORT)
+static asn_oer_constraints_t asn_OER_type_VehicleEventFlags_constr_1 CC_NOTUSED = {
+ { 0, 0 },
+ -1 /* (SIZE(0..MAX)) */};
+#endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
+
+/*
+ * EDITED PER size constraint
+ * originally: (SIZE(13..14,...))
+ * changed to: (SIZE(13,...))
+ */
+#if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
+asn_per_constraints_t asn_PER_type_VehicleEventFlags_constr_1 CC_NOTUSED = {
+ { APC_UNCONSTRAINED, -1, -1, 0, 0 },
+ { APC_CONSTRAINED | APC_EXTENSIBLE, 0, 0, 13, 13 },
+ 0, 0 /* No PER value map */
+};
+#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */
+
+static const ber_tlv_tag_t asn_DEF_VehicleEventFlags_tags_1[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (3 << 2))
+};
+asn_TYPE_descriptor_t asn_DEF_VehicleEventFlags = {
+ "VehicleEventFlags",
+ "VehicleEventFlags",
+ &asn_OP_BIT_STRING,
+ asn_DEF_VehicleEventFlags_tags_1,
+ sizeof(asn_DEF_VehicleEventFlags_tags_1)
+ /sizeof(asn_DEF_VehicleEventFlags_tags_1[0]), /* 1 */
+ asn_DEF_VehicleEventFlags_tags_1, /* Same as above */
+ sizeof(asn_DEF_VehicleEventFlags_tags_1)
+ /sizeof(asn_DEF_VehicleEventFlags_tags_1[0]), /* 1 */
+ {
+#if !defined(ASN_DISABLE_OER_SUPPORT)
+ &asn_OER_type_VehicleEventFlags_constr_1,
+#endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
+#if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
+ &asn_PER_type_VehicleEventFlags_constr_1,
+#endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */
+#if !defined(ASN_DISABLE_JER_SUPPORT)
+ 0,
+#endif /* !defined(ASN_DISABLE_JER_SUPPORT) */
+ VehicleEventFlags_constraint
+ },
+ 0, 0, /* Defined elsewhere */
+ &asn_SPC_BIT_STRING_specs /* Additional specs */
+};
+
diff --git a/data/InputData.decoding.bsm.with.VehicleEventFlags.eventJackKnife.xml b/data/InputData.decoding.bsm.with.VehicleEventFlags.eventJackKnife.xml
new file mode 100644
index 00000000..eba53435
--- /dev/null
+++ b/data/InputData.decoding.bsm.with.VehicleEventFlags.eventJackKnife.xml
@@ -0,0 +1 @@
+RVbsmTxsuccessRVunsecuredDataMessageFrameUPERus.dot.its.jpo.ode.model.OdeAsn1Payloadbee2fd4f-f2e4-4a91-a35c-dabf83f22dec10002023-02-21T21:08:03.588646Z60false10.10.10.10us.dot.its.jpo.ode.model.OdeHexByteArray0014515767567EDDDFA3E68037E116658105B0DA9414000070F402B0FD630FA1007F82800000000000A9D0E00040C227738206DF900A482429E82C7DF900F4C268B282DE5F7015602B18982B1DED82000D50F680
\ No newline at end of file
diff --git a/src/tests.cpp b/src/tests.cpp
index 2a5b71ca..ce20db35 100644
--- a/src/tests.cpp
+++ b/src/tests.cpp
@@ -4,6 +4,7 @@
#include "acm.hpp"
#include "utilities.hpp"
+
bool loadTestCases( const std::string& case_file, StrVector& case_data ) {
std::string line;
@@ -26,6 +27,7 @@ bool loadTestCases( const std::string& case_file, StrVector& case_data ) {
}
pugi::xpath_query ode_payload_query("OdeAsn1Data/payload/data");
+pugi::xpath_query bsm_vehicle_event_flags_query("MessageFrame/value/BasicSafetyMessage/partII/BSMpartIIExtension/partII-Value/VehicleSafetyExtensions/events");
pugi::xml_document output_doc;
pugi::xml_parse_result parse_result;
pugi::xml_node payload_node;
@@ -222,8 +224,8 @@ TEST_CASE("Decode BSM", "[decoding]") {
CHECK(payload_node);
}
-TEST_CASE("Decode BSM with VehicleEventFlags", "[decoding]") {
- std::cout << "=== Decode BSM with VehicleEventFlags ===" << std::endl;
+TEST_CASE("Decode BSM with VehicleEventFlags (hard braking event)", "[decoding]") {
+ std::cout << "=== Decode BSM with VehicleEventFlags (hard braking event) ===" << std::endl;
// prepare
asn1_codec.setup_logger_for_testing();
@@ -234,4 +236,157 @@ TEST_CASE("Decode BSM with VehicleEventFlags", "[decoding]") {
CHECK(parse_result);
payload_node = ode_payload_query.evaluate_node(output_doc).node();
CHECK(payload_node);
-}
\ No newline at end of file
+ pugi::xml_node event_flags_node = bsm_vehicle_event_flags_query.evaluate_node(payload_node).node();
+ CHECK(event_flags_node);
+ std::string bitstring(event_flags_node.text().get());
+ std::cout << "VehicleEventFlags: " << bitstring << std::endl;
+ std::string expected_bitstring("0000000100000");
+ CHECK(bitstring == expected_bitstring);
+}
+
+TEST_CASE("Decode BSM with VehicleEventFlags (jackknife event)", "[decoding]") {
+ std::cout << "=== Decode BSM with VehicleEventFlags (jackknife event) ===" << std::endl;
+
+ // prepare
+ asn1_codec.setup_logger_for_testing();
+
+ std::stringstream out9;
+ CHECK(asn1_codec.file_test("data/InputData.decoding.bsm.with.VehicleEventFlags.eventJackKnife.xml", out9, false) == EXIT_SUCCESS);
+ parse_result = output_doc.load(out9, pugi::parse_default | pugi::parse_declaration | pugi::parse_doctype | pugi::parse_trim_pcdata);
+ CHECK(parse_result);
+ payload_node = ode_payload_query.evaluate_node(output_doc).node();
+ CHECK(payload_node);
+ pugi::xml_node event_flags_node = bsm_vehicle_event_flags_query.evaluate_node(payload_node).node();
+ CHECK(event_flags_node);
+ std::string bitstring(event_flags_node.text().get());
+ std::cout << "VehicleEventFlags: " << bitstring << std::endl;
+ std::string expected_bitstring("00000000000001");
+ CHECK(bitstring == expected_bitstring);
+}
+
+/*
+ * Utilities for VehicleEventFlags tests
+ */
+
+void print_bits(const void * buf, const ssize_t num_bytes) {
+ std::cout << "uper: ";
+ for (int i = 0; i < num_bytes; i++) {
+ uint8_t abyte = *((uint8_t *)buf + i);
+ std::cout << std::bitset<8>(abyte) << " ";
+ }
+ std::cout << std::endl;
+}
+
+void test_encode_VehicleEventFlags_to_uper(const uint16_t bitstring, const uint8_t *expected_uper, const ssize_t expected_byte_len) {
+ std::cout << "bitstring: " << std::bitset<16>(bitstring) << std::endl;
+ const uint8_t buf[] = { static_cast(bitstring >> 8), static_cast(bitstring & 0xFF) };
+ const size_t size = sizeof(buf);
+ uint8_t *ptr_buf = (uint8_t *)&buf;
+ const int bits_unused = __builtin_ctz(bitstring);
+ asn_struct_ctx_t asn_ctx = {};
+ VehicleEventFlags_t vef = {ptr_buf, size, bits_unused, asn_ctx};
+ VehicleEventFlags_t* ptr_vef = &vef;
+ asn_TYPE_descriptor_t *vef_type = &asn_DEF_VehicleEventFlags;
+ asn_encode_to_new_buffer_result_t res
+ = asn_encode_to_new_buffer(0, ATS_UNALIGNED_BASIC_PER, vef_type, ptr_vef);
+ if (res.buffer) {
+ printf("Successfully encoded %ld bytes to uper\n", res.result.encoded);
+ print_bits(res.buffer, res.result.encoded);
+ } else {
+ FAIL("Error encoding vef");
+ return;
+ }
+ if (res.result.encoded != expected_byte_len) {
+ fprintf(stderr, "Error, expected %ld bytes but got %ld", expected_byte_len, res.result.encoded);
+ FAIL("Wrong number of bytes");
+ }
+ if (memcmp(expected_uper, (uint8_t *)res.buffer, res.result.encoded) != 0) {
+ FAIL("Error, Uper doesn't match expected");
+ }
+ free(res.buffer);
+}
+
+void test_decode_VehicleEventFlags_from_uper(const uint8_t * uper, const ssize_t uper_len, const uint16_t expected_bitstring,
+ const int expect_constraint_to_fail) {
+ print_bits(uper, uper_len);
+ VehicleEventFlags_t * ptr_vef = 0;
+ asn_dec_rval_t rval
+ = asn_decode(0, ATS_UNALIGNED_BASIC_PER, &asn_DEF_VehicleEventFlags, (void **)&ptr_vef, uper, uper_len);
+ if (rval.code != RC_OK) {
+ FAIL("Error decoding");
+ return;
+ }
+ printf("Successfully decoded %ld bytes\n", rval.consumed);
+ printf("bitstring size: %ld, bits_unused: %d\n", ptr_vef->size, ptr_vef->bits_unused);
+
+ if (ptr_vef->size != 2) {
+ FAIL("Error, expected bitstring to be 2 bytes");
+ }
+ uint16_t actual_bitstring = (ptr_vef->buf[0] << 8) | ptr_vef->buf[1];
+ std::cout << "bitstring: " << std::bitset<16>(actual_bitstring) << std::endl;
+ if (actual_bitstring != expected_bitstring) {
+ std::cout << "Error, expected bitstring: " << std::bitset<16>(expected_bitstring)
+ << " but got: " << std::bitset<16>(actual_bitstring) << std::endl;
+ FAIL("Bitstring mismatch");
+ }
+
+ // Check constraints
+ char errbuf[128];
+ size_t errlen = sizeof(errbuf);
+ int cons_ret = asn_check_constraints(&asn_DEF_VehicleEventFlags, ptr_vef, errbuf, &errlen);
+ if (cons_ret && !expect_constraint_to_fail) {
+ fprintf(stderr, "Constraint check failed: %s\n", errbuf);
+ FAIL("Unexpected constraint check fail");
+ }
+
+ ASN_STRUCT_FREE(asn_DEF_VehicleEventFlags, ptr_vef);
+}
+
+/*
+ * Data for VehicleEventFlags tests
+ */
+constexpr uint16_t bitstring_root = (0x8000 >> VehicleEventFlags_eventHazardLights)
+ | (0x8000 >> VehicleEventFlags_eventAirBagDeployment);
+constexpr uint8_t uper_root[2] = { 0b01000000, 0b00000100 };
+
+constexpr uint16_t bitstring_with_ext = (0x8000 >> VehicleEventFlags_eventHazardLights)
+ | (0x8000 >> VehicleEventFlags_eventAirBagDeployment)
+ | (0x8000 >> VehicleEventFlags_eventJackKnife);
+
+constexpr uint8_t uper_with_ext[3] = { 0b10000111, 0b01000000, 0b00000110 };
+
+constexpr uint16_t bitstring_15bits = (0x8000 >> VehicleEventFlags_eventHazardLights)
+ | (0x8000 >> VehicleEventFlags_eventAirBagDeployment)
+ | (0x8000 >> VehicleEventFlags_eventJackKnife)
+ | (0x8000 >> 14);
+constexpr uint8_t uper_15bits[3] = {0b10000111, 0b11000000, 0b00000111 };
+
+TEST_CASE("Encode VehicleEventFlags root, from struct to UPER, 13 bits", "[encoding]") {
+ std::cout << "=== Encode VehicleEventFlags root, from struct to UPER, 13 bits ===" << std::endl;
+ test_encode_VehicleEventFlags_to_uper(bitstring_root, uper_root, 2);
+}
+
+TEST_CASE("Encode VehicleEventFlags with 2024 extension, from struct to UPER, 14 bits", "[encoding]") {
+ std::cout << "=== Encode VehicleEventFlags with 2024 extension to UPER, 14 bits ===" << std::endl;
+ test_encode_VehicleEventFlags_to_uper(bitstring_with_ext, uper_with_ext, 3);
+}
+
+TEST_CASE("Encode VehicleEventFlags with unknown future extension, from struct to UPER, 15 bits", "[encoding]") {
+ std::cout << "=== Encode VehicleEventFlags with unknown future extension, from struct to UPER, 15 bits ===" << std::endl;
+ test_encode_VehicleEventFlags_to_uper(bitstring_15bits, uper_15bits, 3);
+}
+
+TEST_CASE("Decode VehicleEventFlags root, from UPER to struct, 13 bits", "[decoding]") {
+ std::cout << "=== Decode VehicleEventFlags root, from UPER to struct, 13 bits ===" << std::endl;
+ test_decode_VehicleEventFlags_from_uper(uper_root, 2, bitstring_root, 0);
+}
+
+TEST_CASE("Decode VehicleEventFlags with 2024 extension, from UPER to struct, 14 bits", "[decoding]") {
+ std::cout << "=== Decode VehicleEventFlags with 2024 extension, from UPER to struct, 14 bits ===" << std::endl;
+ test_decode_VehicleEventFlags_from_uper(uper_with_ext, 3, bitstring_with_ext, 0);
+}
+
+TEST_CASE("Decode VehicleEventFlags with unknown future extension, from UPER to struct, 15 bits", "[decoding]") {
+ std::cout << "=== Decode VehicleEventFlags with unknown future extension, from UPER to struct, 15 bits ===" << std::endl;
+ test_decode_VehicleEventFlags_from_uper(uper_15bits, 3, bitstring_15bits, 1);
+}