From cf00e9e094186fac24cc9251947706fa3bcc9cd8 Mon Sep 17 00:00:00 2001 From: Steve Karg Date: Mon, 20 May 2024 11:18:07 -0500 Subject: [PATCH] Bugfix/secure alarm ack codec (#647) * Secured BACnetAcknowledgeAlarmInfo codec and improved unit testing code coverage. --- src/bacnet/alarm_ack.c | 264 ++++++++++++++++++------------- src/bacnet/alarm_ack.h | 58 ++----- src/bacnet/timestamp.c | 41 +---- test/bacnet/alarm_ack/src/main.c | 149 ++++++++--------- 4 files changed, 253 insertions(+), 259 deletions(-) diff --git a/src/bacnet/alarm_ack.c b/src/bacnet/alarm_ack.c index b5eed9dd..47ae5510 100644 --- a/src/bacnet/alarm_ack.c +++ b/src/bacnet/alarm_ack.c @@ -1,36 +1,11 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2009 John Minack - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ +/** + * @file + * @brief BACnetAcknowledgeAlarmInfo service encode and decode + * @author John Minack + * @author Steve Karg + * @date 2009 + * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 + */ #include #include #include "bacnet/alarm_ack.h" @@ -38,13 +13,11 @@ /** @file alarm_ack.c Handles Event Notifications (ACKs) */ /** - * @brief Creates an Unconfirmed Event Notification APDU - * - * @param apdu Transmission buffer + * @brief Creates a Confirmed BACnetAcknowledgeAlarmInfo service request. + * @param apdu application data buffer, or NULL for length * @param invoke_id Invoked ID - * @param data Alarm acknowledge data that will be copied into the payload. - * - * @return Length of the APDU + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded */ int alarm_ack_encode_apdu( uint8_t *apdu, uint8_t invoke_id, BACNET_ALARM_ACK_DATA *data) @@ -57,119 +30,182 @@ int alarm_ack_encode_apdu( apdu[1] = encode_max_segs_max_apdu(0, MAX_APDU); apdu[2] = invoke_id; apdu[3] = SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM; /* service choice */ - apdu_len = 4; - - len = alarm_ack_encode_service_request(&apdu[apdu_len], data); - apdu_len += len; } + len = 4; + apdu_len += len; + if (apdu) { + apdu += len; + } + len = alarm_ack_encode_service_request(apdu, data); + apdu_len += len; return apdu_len; } /** - * @brief Encodes the service data part of Event Notification. + * @brief Encodes a BACnetAcknowledgeAlarmInfo service request * - * @param apdu Receive buffer - * @param data Alarm acknowledge data that will be filled in - * with the data from the payload. - * - * @return Total length of the apdu + * BACnetAcknowledgeAlarmInfo ::= SEQUENCE { + * event-state-acknowledged [0] BACnetEventState, + * timestamp [1] BACnetTimeStamp + * } + * + * @param apdu application data buffer, or NULL for length + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded */ int alarm_ack_encode_service_request(uint8_t *apdu, BACNET_ALARM_ACK_DATA *data) { int len = 0; /* length of each encoding */ int apdu_len = 0; /* total length of the apdu, return value */ - if (apdu) { - len = encode_context_unsigned( - &apdu[apdu_len], 0, data->ackProcessIdentifier); - apdu_len += len; - - len = encode_context_object_id(&apdu[apdu_len], 1, - data->eventObjectIdentifier.type, - data->eventObjectIdentifier.instance); - apdu_len += len; - - len = encode_context_enumerated( - &apdu[apdu_len], 2, data->eventStateAcked); - apdu_len += len; - - len = bacapp_encode_context_timestamp( - &apdu[apdu_len], 3, &data->eventTimeStamp); - apdu_len += len; - - len = encode_context_character_string( - &apdu[apdu_len], 4, &data->ackSource); - apdu_len += len; - - len = bacapp_encode_context_timestamp( - &apdu[apdu_len], 5, &data->ackTimeStamp); - apdu_len += len; + if (!data) { + return 0; } + len = encode_context_unsigned(apdu, 0, data->ackProcessIdentifier); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_object_id(apdu, 1, data->eventObjectIdentifier.type, + data->eventObjectIdentifier.instance); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_enumerated(apdu, 2, data->eventStateAcked); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_context_timestamp(apdu, 3, &data->eventTimeStamp); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = encode_context_character_string(apdu, 4, &data->ackSource); + apdu_len += len; + if (apdu) { + apdu += len; + } + len = bacapp_encode_context_timestamp(apdu, 5, &data->ackTimeStamp); + apdu_len += len; return apdu_len; } /** - * @brief Decodes the service data part of Event Notification. + * @brief Encode the BACnetAcknowledgeAlarmInfo-Request service + * @param apdu Pointer to the buffer for encoding into + * @param apdu_size number of bytes available in the buffer + * @param data Pointer to the service data used for encoding values + * @return number of bytes encoded, or zero if unable to encode or too large + */ +size_t bacnet_acknowledge_alarm_info_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_ALARM_ACK_DATA *data) +{ + size_t apdu_len = 0; /* total length of the apdu, return value */ + + apdu_len = alarm_ack_encode_service_request(NULL, data); + if (apdu_len > apdu_size) { + apdu_len = 0; + } else { + apdu_len = alarm_ack_encode_service_request(apdu, data); + } + + return apdu_len; + +} + +/** + * @brief Decodes the service data part of BACnetAcknowledgeAlarmInfo * - * @param apdu Receive buffer - * @param apdu_len Bytes valid in the buffer. - * @param data Alarm acknowledge data that will be filled. - * - * @return Total length of the apdu + * @param apdu application date buffer + * @param apdu_size number of bytes application date buffer + * @param data BACnetAcknowledgeAlarmInfo to hold the decoded data + * @return number of bytes decoded, or BACNET_STATUS_ERROR on error. */ int alarm_ack_decode_service_request( - uint8_t *apdu, unsigned apdu_len, BACNET_ALARM_ACK_DATA *data) + uint8_t *apdu, unsigned apdu_size, BACNET_ALARM_ACK_DATA *data) { int len = 0; - int section_len = 0; + int apdu_len = 0; uint32_t enum_value = 0; BACNET_UNSIGNED_INTEGER unsigned_value = 0; + BACNET_OBJECT_TYPE object_type = 0; + uint32_t instance = 0; + BACNET_TIMESTAMP *timestamp_value = NULL; + BACNET_CHARACTER_STRING *cs_value = NULL; - (void)apdu_len; - section_len = decode_context_unsigned(&apdu[len], 0, &unsigned_value); - if (section_len == BACNET_STATUS_ERROR) { + if (!apdu) { return BACNET_STATUS_ERROR; } - data->ackProcessIdentifier = (uint32_t)unsigned_value; - len += section_len; - - section_len = decode_context_object_id(&apdu[len], 1, - &data->eventObjectIdentifier.type, - &data->eventObjectIdentifier.instance); - if (section_len == BACNET_STATUS_ERROR) { + if (apdu_size == 0) { return BACNET_STATUS_ERROR; } - len += section_len; - - section_len = decode_context_enumerated(&apdu[len], 2, &enum_value); - if (section_len == BACNET_STATUS_ERROR) { + len = bacnet_unsigned_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 0, &unsigned_value); + if (len > 0) { + apdu_len += len; + } else { return BACNET_STATUS_ERROR; } - data->eventStateAcked = (BACNET_EVENT_STATE)enum_value; - len += section_len; - - section_len = - bacapp_decode_context_timestamp(&apdu[len], 3, &data->eventTimeStamp); - if (section_len == BACNET_STATUS_ERROR) { + if (data) { + data->ackProcessIdentifier = (uint32_t)unsigned_value; + } + len = bacnet_object_id_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 1, &object_type, &instance); + if (len > 0) { + apdu_len += len; + } else { return BACNET_STATUS_ERROR; } - len += section_len; - - section_len = - decode_context_character_string(&apdu[len], 4, &data->ackSource); - if (section_len == BACNET_STATUS_ERROR) { + if (data) { + data->eventObjectIdentifier.type = object_type; + data->eventObjectIdentifier.instance = instance; + } + len = bacnet_enumerated_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 2, &enum_value); + if (len > 0) { + apdu_len += len; + } else { return BACNET_STATUS_ERROR; } - len += section_len; - - section_len = - bacapp_decode_context_timestamp(&apdu[len], 5, &data->ackTimeStamp); - if (section_len == BACNET_STATUS_ERROR) { + if (data) { + data->eventStateAcked = (BACNET_EVENT_STATE)enum_value; + } + if (data) { + timestamp_value = &data->eventTimeStamp; + } + len = bacnet_timestamp_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 3, timestamp_value); + if (len > 0) { + apdu_len += len; + } else { + return BACNET_STATUS_ERROR; + } + if (data) { + cs_value = &data->ackSource; + } + len = bacnet_character_string_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 4, cs_value); + if (len > 0) { + apdu_len += len; + } else { + return BACNET_STATUS_ERROR; + } + if (data) { + timestamp_value = &data->ackTimeStamp; + } + len = bacnet_timestamp_context_decode( + &apdu[apdu_len], apdu_size - apdu_len, 5, timestamp_value); + if (len > 0) { + apdu_len += len; + } else { return BACNET_STATUS_ERROR; } - len += section_len; - return len; + return apdu_len; } diff --git a/src/bacnet/alarm_ack.h b/src/bacnet/alarm_ack.h index 3ef50e7b..cb9b022d 100644 --- a/src/bacnet/alarm_ack.h +++ b/src/bacnet/alarm_ack.h @@ -1,28 +1,13 @@ -/************************************************************************** -* -* Copyright (C) 2009 John Minack -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*********************************************************************/ -#ifndef ALARM_ACK_H_ -#define ALARM_ACK_H_ +/** + * @file + * @brief BACnetAcknowledgeAlarmInfo service encode and decode + * @author John Minack + * @author Steve Karg + * @date 2009 + * @copyright SPDX-License-Identifier: MIT + */ +#ifndef BACNET_ALARM_ACK_H +#define BACNET_ALARM_ACK_H #include #include @@ -53,32 +38,23 @@ typedef int ( extern "C" { #endif /* __cplusplus */ -/*************************************************** -** -** Creates a Alarm Acknowledge APDU -** -****************************************************/ BACNET_STACK_EXPORT int alarm_ack_encode_apdu( uint8_t * apdu, uint8_t invoke_id, BACNET_ALARM_ACK_DATA * data); -/*************************************************** -** -** Encodes the service data part of Alarm Acknowledge -** -****************************************************/ BACNET_STACK_EXPORT int alarm_ack_encode_service_request( uint8_t * apdu, BACNET_ALARM_ACK_DATA * data); -/*************************************************** -** -** Decodes the service data part of Alarm Acknowledge -** -****************************************************/ + BACNET_STACK_EXPORT + size_t bacnet_acknowledge_alarm_info_request_encode( + uint8_t *apdu, + size_t apdu_size, + BACNET_ALARM_ACK_DATA *data); + BACNET_STACK_EXPORT int alarm_ack_decode_service_request( uint8_t * apdu, @@ -88,4 +64,4 @@ extern "C" { #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* ALARM_ACK_H_ */ +#endif diff --git a/src/bacnet/timestamp.c b/src/bacnet/timestamp.c index 0ae0e890..25e11426 100644 --- a/src/bacnet/timestamp.c +++ b/src/bacnet/timestamp.c @@ -1,36 +1,11 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2008 John Minack - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA. - - As a special exception, if other files instantiate templates or - use macros or inline functions from this file, or you compile - this file and link it with other works to produce a work based - on this file, this file does not by itself cause the resulting - work to be covered by the GNU General Public License. However - the source code for this file must still be made available in - accordance with section (3) of the GNU General Public License. - - This exception does not invalidate any other reasons why a work - based on this file might be covered by the GNU General Public - License. - ------------------------------------------- -####COPYRIGHTEND####*/ +/** + * @file + * @brief BACnetTimeStamp service encode and decode + * @author John Minack + * @author Steve Karg + * @date 2008 + * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 + */ #include #include #include diff --git a/test/bacnet/alarm_ack/src/main.c b/test/bacnet/alarm_ack/src/main.c index 12297776..b79cc757 100644 --- a/test/bacnet/alarm_ack/src/main.c +++ b/test/bacnet/alarm_ack/src/main.c @@ -1,13 +1,11 @@ -/* - * Copyright (c) 2020 Legrand North America, LLC. - * - * SPDX-License-Identifier: MIT +/** + * @file + * @brief unit test for BACnetAcknowledgeAlarmInfo encoding and decoding + * @author Steve Karg + * @author Greg Shue + * @date 2009 + * @copyright SPDX-License-Identifier: MIT */ - -/* @file - * @brief test BACnet integer encode/decode APIs - */ - #include #include @@ -25,92 +23,101 @@ ZTEST(alarm_ack_tests, testAlarmAck) static void testAlarmAck(void) #endif { - BACNET_ALARM_ACK_DATA testAlarmAckIn; - BACNET_ALARM_ACK_DATA testAlarmAckOut; + BACNET_ALARM_ACK_DATA data; + BACNET_ALARM_ACK_DATA test_data; - uint8_t buffer[MAX_APDU]; - int inLen; - int outLen; + uint8_t apdu[MAX_APDU]; + int null_len, test_len, apdu_len; bool status; - testAlarmAckIn.ackProcessIdentifier = 0x1234; - characterstring_init_ansi(&testAlarmAckIn.ackSource, "This is a test"); - status = bacapp_timestamp_init_ascii(&testAlarmAckIn.ackTimeStamp, "1234"); + data.ackProcessIdentifier = 0x1234; + characterstring_init_ansi(&data.ackSource, "This is a test"); + status = bacapp_timestamp_init_ascii(&data.ackTimeStamp, "1234"); zassert_true(status, NULL); - zassert_equal(testAlarmAckIn.ackTimeStamp.tag, TIME_STAMP_SEQUENCE, NULL); - zassert_equal(testAlarmAckIn.ackTimeStamp.value.sequenceNum, 1234, NULL); + zassert_equal(data.ackTimeStamp.tag, TIME_STAMP_SEQUENCE, NULL); + zassert_equal(data.ackTimeStamp.value.sequenceNum, 1234, NULL); - testAlarmAckIn.eventObjectIdentifier.instance = 567; - testAlarmAckIn.eventObjectIdentifier.type = OBJECT_DEVICE; - status = bacapp_timestamp_init_ascii( - &testAlarmAckIn.eventTimeStamp, "10:11:12.14"); + data.eventObjectIdentifier.instance = 567; + data.eventObjectIdentifier.type = OBJECT_DEVICE; + status = bacapp_timestamp_init_ascii(&data.eventTimeStamp, "10:11:12.14"); zassert_true(status, NULL); - zassert_equal(testAlarmAckIn.eventTimeStamp.tag, TIME_STAMP_TIME, NULL); - testAlarmAckIn.eventStateAcked = EVENT_STATE_OFFNORMAL; - memset(&testAlarmAckOut, 0, sizeof(testAlarmAckOut)); + zassert_equal(data.eventTimeStamp.tag, TIME_STAMP_TIME, NULL); + data.eventStateAcked = EVENT_STATE_OFFNORMAL; + memset(&test_data, 0, sizeof(test_data)); - inLen = alarm_ack_encode_service_request(buffer, &testAlarmAckIn); - outLen = alarm_ack_decode_service_request(buffer, inLen, &testAlarmAckOut); - - zassert_equal(inLen, outLen, "inlen=%d outlen=%d", inLen, outLen); + apdu_len = bacnet_acknowledge_alarm_info_request_encode(apdu, sizeof(apdu), &data); + null_len = bacnet_acknowledge_alarm_info_request_encode(NULL, apdu_len, &data); + zassert_equal(null_len, apdu_len, NULL); + test_len = alarm_ack_decode_service_request(apdu, apdu_len, &test_data); zassert_equal( - testAlarmAckIn.ackProcessIdentifier, - testAlarmAckOut.ackProcessIdentifier, NULL); + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); zassert_equal( - testAlarmAckIn.ackTimeStamp.tag, testAlarmAckOut.ackTimeStamp.tag, - "in-tag=%d out-tag=%d", testAlarmAckIn.ackTimeStamp.tag, - testAlarmAckOut.ackTimeStamp.tag); - zassert_equal( - testAlarmAckIn.ackTimeStamp.value.sequenceNum, - testAlarmAckOut.ackTimeStamp.value.sequenceNum, NULL); + data.ackProcessIdentifier, test_data.ackProcessIdentifier, NULL); zassert_equal( - testAlarmAckIn.ackProcessIdentifier, - testAlarmAckOut.ackProcessIdentifier, NULL); + data.ackTimeStamp.tag, test_data.ackTimeStamp.tag, + "in-tag=%d out-tag=%d", data.ackTimeStamp.tag, + test_data.ackTimeStamp.tag); + zassert_equal( + data.ackTimeStamp.value.sequenceNum, + test_data.ackTimeStamp.value.sequenceNum, NULL); zassert_equal( - testAlarmAckIn.eventObjectIdentifier.instance, - testAlarmAckOut.eventObjectIdentifier.instance, NULL); - zassert_equal( - testAlarmAckIn.eventObjectIdentifier.type, - testAlarmAckOut.eventObjectIdentifier.type, NULL); + data.ackProcessIdentifier, test_data.ackProcessIdentifier, NULL); zassert_equal( - testAlarmAckIn.eventTimeStamp.tag, testAlarmAckOut.eventTimeStamp.tag, + data.eventObjectIdentifier.instance, + test_data.eventObjectIdentifier.instance, NULL); + zassert_equal( + data.eventObjectIdentifier.type, test_data.eventObjectIdentifier.type, NULL); - zassert_equal( - testAlarmAckIn.eventTimeStamp.value.time.hour, - testAlarmAckOut.eventTimeStamp.value.time.hour, NULL); - zassert_equal( - testAlarmAckIn.eventTimeStamp.value.time.min, - testAlarmAckOut.eventTimeStamp.value.time.min, NULL); - zassert_equal( - testAlarmAckIn.eventTimeStamp.value.time.sec, - testAlarmAckOut.eventTimeStamp.value.time.sec, NULL); - zassert_equal( - testAlarmAckIn.eventTimeStamp.value.time.hundredths, - testAlarmAckOut.eventTimeStamp.value.time.hundredths, NULL); + zassert_equal(data.eventTimeStamp.tag, test_data.eventTimeStamp.tag, NULL); zassert_equal( - testAlarmAckIn.eventStateAcked, testAlarmAckOut.eventStateAcked, NULL); + data.eventTimeStamp.value.time.hour, + test_data.eventTimeStamp.value.time.hour, NULL); + zassert_equal( + data.eventTimeStamp.value.time.min, + test_data.eventTimeStamp.value.time.min, NULL); + zassert_equal( + data.eventTimeStamp.value.time.sec, + test_data.eventTimeStamp.value.time.sec, NULL); + zassert_equal( + data.eventTimeStamp.value.time.hundredths, + test_data.eventTimeStamp.value.time.hundredths, NULL); - status = bacapp_timestamp_init_ascii( - &testAlarmAckIn.eventTimeStamp, "2021/12/31"); + zassert_equal(data.eventStateAcked, test_data.eventStateAcked, NULL); + + status = bacapp_timestamp_init_ascii(&data.eventTimeStamp, "2021/12/31"); zassert_true(status, NULL); - zassert_equal(testAlarmAckIn.eventTimeStamp.tag, TIME_STAMP_DATETIME, NULL); - inLen = alarm_ack_encode_service_request(buffer, &testAlarmAckIn); - outLen = alarm_ack_decode_service_request(buffer, inLen, &testAlarmAckOut); - zassert_equal(inLen, outLen, "inlen=%d outlen=%d", inLen, outLen); + zassert_equal(data.eventTimeStamp.tag, TIME_STAMP_DATETIME, NULL); + apdu_len = bacnet_acknowledge_alarm_info_request_encode(apdu, sizeof(apdu), &data); + null_len = bacnet_acknowledge_alarm_info_request_encode(NULL, apdu_len, &data); + zassert_equal(null_len, apdu_len, NULL); + test_len = alarm_ack_decode_service_request(apdu, apdu_len, &test_data); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); - status = - bacapp_timestamp_init_ascii(&testAlarmAckIn.eventTimeStamp, "1234"); + status = bacapp_timestamp_init_ascii(&data.eventTimeStamp, "1234"); zassert_true(status, NULL); - zassert_equal(testAlarmAckIn.eventTimeStamp.tag, TIME_STAMP_SEQUENCE, NULL); - inLen = alarm_ack_encode_service_request(buffer, &testAlarmAckIn); - outLen = alarm_ack_decode_service_request(buffer, inLen, &testAlarmAckOut); - zassert_equal(inLen, outLen, "inlen=%d outlen=%d", inLen, outLen); + zassert_equal(data.eventTimeStamp.tag, TIME_STAMP_SEQUENCE, NULL); + apdu_len = bacnet_acknowledge_alarm_info_request_encode(apdu, sizeof(apdu), &data); + null_len = bacnet_acknowledge_alarm_info_request_encode(NULL, apdu_len, &data); + zassert_equal(null_len, apdu_len, NULL); + test_len = alarm_ack_decode_service_request(apdu, apdu_len, &test_data); + zassert_equal( + apdu_len, test_len, "apdu_len=%d test_len=%d", apdu_len, test_len); + while (--apdu_len) { + test_len = bacnet_acknowledge_alarm_info_request_encode(apdu, apdu_len, &data); + zassert_equal(test_len, 0, "apdu_len=%d test_len=%d", apdu_len, test_len); + } + apdu_len = null_len; + while (--apdu_len) { + test_len = alarm_ack_decode_service_request(apdu, apdu_len, &data); + zassert_true(test_len < 0, "apdu_len=%d test_len=%d", apdu_len, test_len); + } } /**