diff --git a/src/bacnet/get_alarm_sum.h b/src/bacnet/get_alarm_sum.h index 73953592..4043e50a 100644 --- a/src/bacnet/get_alarm_sum.h +++ b/src/bacnet/get_alarm_sum.h @@ -32,11 +32,12 @@ #include "bacnet/bacapp.h" #include "bacnet/timestamp.h" - +struct BACnet_Get_Alarm_Summary_Data; typedef struct BACnet_Get_Alarm_Summary_Data { BACNET_OBJECT_ID objectIdentifier; BACNET_EVENT_STATE alarmState; BACNET_BIT_STRING acknowledgedTransitions; + struct BACnet_Get_Alarm_Summary_Data *next; } BACNET_GET_ALARM_SUMMARY_DATA; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4c21b2f5..195c5098 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,6 +49,7 @@ list(APPEND testdirs bacnet/datetime bacnet/dcc bacnet/event + bacnet/getalarm bacnet/getevent bacnet/iam bacnet/ihave diff --git a/test/bacnet/getalarm/CMakeLists.txt b/test/bacnet/getalarm/CMakeLists.txt new file mode 100644 index 00000000..12f7f2cc --- /dev/null +++ b/test/bacnet/getalarm/CMakeLists.txt @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + +get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME) +project(test_${basename} + VERSION 1.0.0 + LANGUAGES C) + + +string(REGEX REPLACE + "/test/bacnet/[a-zA-Z_/-]*$" + "/src" + SRC_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) +string(REGEX REPLACE + "/test/bacnet/[a-zA-Z_/-]*$" + "/test" + TST_DIR + ${CMAKE_CURRENT_SOURCE_DIR}) +set(ZTST_DIR "${TST_DIR}/ztest/src") + +add_compile_definitions( + BIG_ENDIAN=0 + CONFIG_ZTEST=1 + ) + +include_directories( + ${SRC_DIR} + ${TST_DIR}/ztest/include + ) + +add_executable(${PROJECT_NAME} + # File(s) under test + ${SRC_DIR}/bacnet/get_alarm_sum.c + # Support files and stubs (pathname alphabetical) + ${SRC_DIR}/bacnet/bacapp.c + ${SRC_DIR}/bacnet/bacdcode.c + ${SRC_DIR}/bacnet/bacdevobjpropref.c + ${SRC_DIR}/bacnet/bacint.c + ${SRC_DIR}/bacnet/bacreal.c + ${SRC_DIR}/bacnet/bacstr.c + ${SRC_DIR}/bacnet/bactext.c + ${SRC_DIR}/bacnet/bacpropstates.c + ${SRC_DIR}/bacnet/basic/sys/bigend.c + ${SRC_DIR}/bacnet/datetime.c + ${SRC_DIR}/bacnet/basic/sys/days.c + ${SRC_DIR}/bacnet/lighting.c + ${SRC_DIR}/bacnet/indtext.c + ${SRC_DIR}/bacnet/timestamp.c + # Test and test library files + ./src/main.c + ${ZTST_DIR}/ztest_mock.c + ${ZTST_DIR}/ztest.c + ) diff --git a/test/bacnet/getalarm/src/main.c b/test/bacnet/getalarm/src/main.c new file mode 100644 index 00000000..b1394683 --- /dev/null +++ b/test/bacnet/getalarm/src/main.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2022 Steve Karg + * + * SPDX-License-Identifier: MIT + */ + +/* @file + * @brief test BACnet service GetAlarmSummary encode and decode + */ + +#include +#include + +/** + * @addtogroup bacnet_tests + * @{ + */ + +/** + * @brief Stub function for encoding + * @param apdu - buffer to extract the decoding + * @param apdu_size - size of the buffer + * @param invoke_id - unique sequence number sent with the message + * @return number of bytes decoded + */ +static int get_alarm_summary_decode_apdu(uint8_t *apdu, + unsigned apdu_size, + uint8_t *invoke_id) +{ + int len = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + if (apdu_size < 4) { + return BACNET_STATUS_ERROR; + } + /* optional checking - most likely was already done prior to this call */ + if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { + return BACNET_STATUS_ERROR; + } + /* apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); */ + *invoke_id = apdu[2]; /* invoke id - filled in by net layer */ + if (apdu[3] != SERVICE_CONFIRMED_GET_ALARM_SUMMARY) { + return BACNET_STATUS_ERROR; + } + + return 4; +} + +/** + * @brief Stub function for decoding + * @param apdu - buffer containing encoded data + * @param apdu_len - total length of the apdu + * @param invoke_id - unique sequence number sent with the message + * @return number of bytes decoded + */ +static int get_alarm_summary_ack_decode_apdu(uint8_t *apdu, + int apdu_len, + uint8_t *invoke_id, + BACNET_GET_ALARM_SUMMARY_DATA *get_alarm_data) +{ + int len = 0; + int offset = 0; + + if (!apdu) { + return BACNET_STATUS_ERROR; + } + /* optional checking - most likely was already done prior to this call */ + if (apdu[0] != PDU_TYPE_COMPLEX_ACK) { + return BACNET_STATUS_ERROR; + } + *invoke_id = apdu[1]; + if (apdu[2] != SERVICE_CONFIRMED_GET_ALARM_SUMMARY) { + return BACNET_STATUS_ERROR; + } + offset = 3; + if (apdu_len > offset) { + len = get_alarm_summary_ack_decode_apdu_data( + &apdu[offset], apdu_len - offset, get_alarm_data); + if (get_alarm_data) { + get_alarm_data->next = NULL; + } + } + + return len; +} + +static void testGetAlarmSummaryAck(void) +{ + uint8_t apdu[480] = { 0 }; + int len = 0; + int apdu_len = 0; + uint8_t invoke_id = 1; + uint8_t test_invoke_id = 0; + BACNET_GET_ALARM_SUMMARY_DATA alarm_data; + BACNET_GET_ALARM_SUMMARY_DATA test_alarm_data; + unsigned i = 0; + + alarm_data.objectIdentifier.type = OBJECT_BINARY_INPUT; + alarm_data.objectIdentifier.instance = 1; + alarm_data.alarmState = EVENT_STATE_NORMAL; + bitstring_init(&alarm_data.acknowledgedTransitions); + bitstring_set_bit( + &alarm_data.acknowledgedTransitions, TRANSITION_TO_OFFNORMAL, false); + bitstring_set_bit( + &alarm_data.acknowledgedTransitions, TRANSITION_TO_FAULT, false); + bitstring_set_bit( + &alarm_data.acknowledgedTransitions, TRANSITION_TO_NORMAL, false); + /* encode the initial service */ + len = get_alarm_summary_ack_encode_apdu_init(&apdu[0], + invoke_id); + zassert_not_equal(len, 0, NULL); + zassert_not_equal(len, -1, NULL); + apdu_len = len; + /* append the data portion of the service */ + len = get_alarm_summary_ack_encode_apdu_data( + &apdu[apdu_len], sizeof(apdu) - apdu_len, &alarm_data); + zassert_not_equal(len, 0, NULL); + zassert_not_equal(len, -1, NULL); + apdu_len += len; + len = get_alarm_summary_ack_decode_apdu(&apdu[0], + apdu_len, /* total length of the apdu */ + &test_invoke_id, &test_alarm_data); + zassert_not_equal(len, -1, NULL); + zassert_equal(test_invoke_id, invoke_id, NULL); + + zassert_equal( + alarm_data.objectIdentifier.type, + test_alarm_data.objectIdentifier.type, NULL); + zassert_equal( + alarm_data.objectIdentifier.instance, + test_alarm_data.objectIdentifier.instance, NULL); + + zassert_equal(alarm_data.alarmState, test_alarm_data.alarmState, NULL); +} + +static void testGetAlarmSummary(void) +{ + uint8_t apdu[480] = { 0 }; + int len = 0; + int apdu_len = 0; + uint8_t invoke_id = 128; + uint8_t test_invoke_id = 0; + + len = get_alarm_summary_encode_apdu(&apdu[0], invoke_id); + zassert_not_equal(len, 0, NULL); + apdu_len = len; + + len = get_alarm_summary_decode_apdu(&apdu[0], apdu_len, &test_invoke_id); + zassert_not_equal(len, -1, NULL); + zassert_equal(test_invoke_id, invoke_id, NULL); + + return; +} + + +/** + * Main entry point for testing + */ +void test_main(void) +{ + ztest_test_suite(getalarm_tests, + ztest_unit_test(testGetAlarmSummary), + ztest_unit_test(testGetAlarmSummaryAck) + ); + + ztest_run_test_suite(getalarm_tests); +}