Bugfix/read-range-address-list-encode (#1149)
* Fix: Corrected `rr_address_list_encode` to properly handle the end of the address cache and added a new test case to validate ReadRange operations near the cache limit.
This commit is contained in:
+11
-10
@@ -9,8 +9,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
The git repositories are hosted at the following sites:
|
||||
* https://bacnet.sourceforge.net/
|
||||
* https://github.com/bacnet-stack/bacnet-stack/
|
||||
|
||||
* <https://bacnet.sourceforge.net/>
|
||||
* <https://github.com/bacnet-stack/bacnet-stack/>
|
||||
|
||||
## [Unreleased] - 2026-03-06
|
||||
|
||||
@@ -190,6 +191,7 @@ The git repositories are hosted at the following sites:
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed the ReadRange-ACK of the Address_List property. (#1149)
|
||||
* Fixed ReadRangeACK by sequence in Trend Log object. (#1150)
|
||||
* Fixed Device Management-Backup and Restore-B functionality to keep
|
||||
configuration files during the restore operation. (#1250)
|
||||
@@ -527,6 +529,7 @@ The git repositories are hosted at the following sites:
|
||||
## [1.4.1] - 2025-04-11
|
||||
|
||||
### Security
|
||||
|
||||
* Secured ReadRange service codecs. Added ReadRange unit testing.
|
||||
Secured ReadRange-ACK handler to enable APDU size checking. (#957)
|
||||
* Secured BACnet/SC URL handling by changing all the sprintf
|
||||
@@ -765,7 +768,7 @@ The git repositories are hosted at the following sites:
|
||||
* Changed the datalink abstraction to enable selecting multiple datalinks
|
||||
using BACDL_MULTIPLE and one or more other BACDL defines. (#717)
|
||||
* Moved west manifest, zephyr folder, and ports/zephyr folders to
|
||||
another repository https://github.com/bacnet-stack/bacnet-stack-zephyr
|
||||
another repository <https://github.com/bacnet-stack/bacnet-stack-zephyr>
|
||||
so that the rapid pace of Zephyr OS development changes will have
|
||||
a less impact on the development of the BACnet Stack library. (#757)
|
||||
* Removed static scope on character array used for object-name since the array
|
||||
@@ -954,7 +957,6 @@ The git repositories are hosted at the following sites:
|
||||
bacapp_decode_context_data_len() as they are no longer used in any code
|
||||
in the library.(#702)
|
||||
|
||||
|
||||
## [1.3.7] - 2024-06-26
|
||||
|
||||
### Security
|
||||
@@ -1026,7 +1028,6 @@ The git repositories are hosted at the following sites:
|
||||
priority 6. (#640)
|
||||
* Fixed basic analog-value alarm-ack functionality. (#639)
|
||||
|
||||
|
||||
### Removed
|
||||
|
||||
* Removed local dlmstp.c module from stm32f10x port in favor of using
|
||||
@@ -1489,7 +1490,7 @@ tags. (#491)
|
||||
|
||||
### Added
|
||||
|
||||
* Added minimim support for BACnet protocol-revision 0 through 24. See
|
||||
* Added minimim support for BACnet protocol-revision 0 through 24. See
|
||||
BACNET_PROTOCOL_REVISION define in bacdef.h
|
||||
* Added example objects for color and color temperature, new for protocol-revision 24.
|
||||
* Added current-command-priority to output objects revision 17 or later.
|
||||
@@ -1515,20 +1516,20 @@ these objects: file, analog output, binary output, multi-state output, color,
|
||||
color temperature).
|
||||
* Unit tests and functional tests have been moved from the source C files
|
||||
into their own test files under the test folder in a src/ mirrored folder
|
||||
structure under test/.
|
||||
* The testing framework was moved from ctest to ztest, using CMake, CTest, and LCOV.
|
||||
structure under test/.
|
||||
* The testing framework was moved from ctest to ztest, using CMake, CTest, and LCOV.
|
||||
It's now possible to visually view code coverage from the testing of each file
|
||||
in the library. The tests are run in continuous integration. Adding new tests
|
||||
can be done by as copying an existing folder under test/ as a starting point, and
|
||||
adding the new test folder name into the CMakeLists.txt under test/ folder, or
|
||||
editing the existing test C file and extending or fixing the existing test.
|
||||
editing the existing test C file and extending or fixing the existing test.
|
||||
* Most (all?) of the primitive value encoders are now using a snprintf()
|
||||
style API pattern, where passing NULL in the buffer parameter will
|
||||
return the length that the buffer would use (i.e. returns the length that the
|
||||
buffer needs to be). This makes simple to write the parent encoders to check
|
||||
the length versus their buffer before attempting the encoding at the expense of
|
||||
an extra function call to get the length.
|
||||
* BACnetARRAY property types now have a helper function to use for encoding (see bacnet_array_encode)
|
||||
* BACnetARRAY property types now have a helper function to use for encoding (see bacnet_array_encode)
|
||||
|
||||
## Deprecated
|
||||
|
||||
|
||||
@@ -987,16 +987,26 @@ int rr_address_list_encode(uint8_t *apdu, BACNET_READ_RANGE_DATA *pRequest)
|
||||
/* Chalk up another one for the response count */
|
||||
pRequest->ItemCount++;
|
||||
|
||||
if (pMatch > &Address_Cache[MAX_ADDRESS_CACHE - 1]) {
|
||||
/* valid entry at the end of the table */
|
||||
uiLast = uiTotal;
|
||||
break;
|
||||
}
|
||||
while ((pMatch->Flags & (BAC_ADDR_IN_USE | BAC_ADDR_BIND_REQ)) !=
|
||||
BAC_ADDR_IN_USE) {
|
||||
/* Find next bound entry */
|
||||
pMatch++;
|
||||
/* Can normally not happen. */
|
||||
if (pMatch > &Address_Cache[MAX_ADDRESS_CACHE - 1]) {
|
||||
/* Issue with the table. */
|
||||
return (0);
|
||||
/* valid entry at the end of the table */
|
||||
uiLast = uiTotal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pMatch > &Address_Cache[MAX_ADDRESS_CACHE - 1]) {
|
||||
/* valid entry at the end of the table */
|
||||
uiLast = uiTotal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Set remaining result flags if necessary */
|
||||
if (uiFirst == 1) {
|
||||
|
||||
@@ -142,6 +142,71 @@ static void testAddressFile(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ZTEST_NEW_API)
|
||||
ZTEST(address_tests, test_rr_address)
|
||||
#else
|
||||
static void test_rr_address(void)
|
||||
#endif
|
||||
{
|
||||
uint8_t apdu[MAX_APDU];
|
||||
BACNET_READ_RANGE_DATA pRequest = { 0 };
|
||||
BACNET_ADDRESS src = { 0 };
|
||||
unsigned i;
|
||||
int len;
|
||||
|
||||
address_init();
|
||||
/* Fill the cache to its limit */
|
||||
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
|
||||
src.mac_len = 1;
|
||||
src.mac[0] = (uint8_t)i;
|
||||
address_add(i, 480, &src);
|
||||
}
|
||||
|
||||
/* Test ReadRange ALL */
|
||||
pRequest.object_type = OBJECT_DEVICE;
|
||||
pRequest.object_instance = 123;
|
||||
pRequest.object_property = PROP_DEVICE_ADDRESS_BINDING;
|
||||
pRequest.array_index = BACNET_ARRAY_ALL;
|
||||
pRequest.RequestType = RR_READ_ALL;
|
||||
pRequest.Overhead = 0;
|
||||
|
||||
len = rr_address_list_encode(apdu, &pRequest);
|
||||
zassert_not_equal(len, 0, "ReadRange ALL failed - returned 0");
|
||||
zassert_true(
|
||||
bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_MORE_ITEMS),
|
||||
"Expected MORE_ITEMS flag");
|
||||
zassert_true(
|
||||
bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_FIRST_ITEM),
|
||||
"Expected FIRST_ITEM flag");
|
||||
|
||||
/* Test ReadRange from the end to verify the fix */
|
||||
pRequest.RequestType = RR_BY_POSITION;
|
||||
pRequest.Range.RefIndex = MAX_ADDRESS_CACHE - 5 + 1;
|
||||
pRequest.Count = 5;
|
||||
bitstring_init(&pRequest.ResultFlags);
|
||||
|
||||
len = rr_address_list_encode(apdu, &pRequest);
|
||||
zassert_not_equal(len, 0, "ReadRange end failed - returned 0");
|
||||
zassert_equal(pRequest.ItemCount, 5, "Expected 5 items");
|
||||
zassert_true(
|
||||
bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_LAST_ITEM),
|
||||
"Expected LAST_ITEM flag");
|
||||
|
||||
/* Specifically test hitting the very last physical entry in Address_Cache
|
||||
*/
|
||||
pRequest.RequestType = RR_BY_POSITION;
|
||||
pRequest.Range.RefIndex = MAX_ADDRESS_CACHE;
|
||||
pRequest.Count = 1;
|
||||
bitstring_init(&pRequest.ResultFlags);
|
||||
|
||||
len = rr_address_list_encode(apdu, &pRequest);
|
||||
zassert_not_equal(len, 0, "ReadRange last item failed - returned 0");
|
||||
zassert_equal(pRequest.ItemCount, 1, "Expected 1 item");
|
||||
zassert_true(
|
||||
bitstring_bit(&pRequest.ResultFlags, RESULT_FLAG_LAST_ITEM),
|
||||
"Expected LAST_ITEM flag for the last item");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ZTEST_NEW_API)
|
||||
ZTEST(address_tests, testAddress)
|
||||
#else
|
||||
@@ -209,11 +274,13 @@ void test_main(void)
|
||||
#ifdef BACNET_ADDRESS_CACHE_FILE
|
||||
ztest_test_suite(
|
||||
address_tests, ztest_unit_test(testAddressFile),
|
||||
ztest_unit_test(testAddress));
|
||||
ztest_unit_test(testAddress), ztest_unit_test(test_rr_address));
|
||||
|
||||
ztest_run_test_suite(address_tests);
|
||||
#else
|
||||
ztest_test_suite(address_tests, ztest_unit_test(testAddress));
|
||||
ztest_test_suite(
|
||||
address_tests, ztest_unit_test(testAddress),
|
||||
ztest_unit_test(test_rr_address));
|
||||
|
||||
ztest_run_test_suite(address_tests);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user