Added dynamic and static RAM file systems to use with file objects. (#1058)

* Added dynamic RAM file system to use with basic bacnet file object.

* Added static RAM file system to use with basic bacnet file object.

* Added check for read-only during AtomicWriteFile service API for BACnet File object.

* Change stm32f4xx example to use static RAM file system.

* Fixed bacfile_count() function return type
This commit is contained in:
Steve Karg
2025-08-08 15:35:13 -05:00
committed by GitHub
parent e67777e345
commit 3f8b8b5619
17 changed files with 1324 additions and 8 deletions
+4
View File
@@ -551,6 +551,10 @@ add_library(${PROJECT_NAME}
src/bacnet/basic/services.h
src/bacnet/basic/sys/bigend.c
src/bacnet/basic/sys/bigend.h
src/bacnet/basic/sys/bramfs.c
src/bacnet/basic/sys/bramfs.h
src/bacnet/basic/sys/bsramfs.c
src/bacnet/basic/sys/bsramfs.h
src/bacnet/basic/sys/color_rgb.c
src/bacnet/basic/sys/color_rgb.h
src/bacnet/basic/sys/days.c
+5
View File
@@ -166,6 +166,7 @@ set(BACNET_PROJECT_SOURCE
${LIBRARY_BACNET_BASIC}/object/ms-input.c
${LIBRARY_BACNET_BASIC}/object/mso.c
${LIBRARY_BACNET_BASIC}/object/msv.c
${LIBRARY_BACNET_BASIC}/object/bacfile.c
${LIBRARY_BACNET_BASIC}/object/program.c
${LIBRARY_BACNET_BASIC}/program/ubasic/ubasic.c
${LIBRARY_BACNET_BASIC}/program/ubasic/tokenizer.c
@@ -183,7 +184,9 @@ set(BACNET_PROJECT_SOURCE
${LIBRARY_BACNET_BASIC}/service/h_noserv.c
${LIBRARY_BACNET_BASIC}/service/s_iam.c
${LIBRARY_BACNET_BASIC}/service/s_ihave.c
${LIBRARY_BACNET_BASIC}/service/h_arf.c
${LIBRARY_BACNET_BASIC}/tsm/tsm.c
${LIBRARY_BACNET_BASIC}/sys/bsramfs.c
${LIBRARY_BACNET_BASIC}/sys/debug.c
${LIBRARY_BACNET_BASIC}/sys/datetime_mstimer.c
${LIBRARY_BACNET_BASIC}/sys/days.c
@@ -194,6 +197,7 @@ set(BACNET_PROJECT_SOURCE
${LIBRARY_BACNET_BASIC}/sys/mstimer.c
${LIBRARY_BACNET_CORE}/abort.c
${LIBRARY_BACNET_CORE}/arf.c
${LIBRARY_BACNET_CORE}/bacaction.c
${LIBRARY_BACNET_CORE}/bacaddr.c
${LIBRARY_BACNET_CORE}/bacapp.c
@@ -252,6 +256,7 @@ target_compile_definitions(${EXECUTABLE} PRIVATE
-DMAX_APDU=480
-DBIG_ENDIAN=0
-DMAX_TSM_TRANSACTIONS=1
-DBACFILE
-DBACAPP_MINIMAL
)
+5
View File
@@ -45,10 +45,12 @@ BASIC_SRC = \
$(BACNET_BASIC)/object/ms-input.c \
$(BACNET_BASIC)/object/mso.c \
$(BACNET_BASIC)/object/msv.c \
$(BACNET_BASIC)/object/bacfile.c \
$(BACNET_BASIC)/object/program.c \
$(BACNET_BASIC)/program/ubasic/ubasic.c \
$(BACNET_BASIC)/program/ubasic/tokenizer.c \
$(BACNET_BASIC)/service/h_apdu.c \
$(BACNET_BASIC)/service/h_arf.c \
$(BACNET_BASIC)/service/h_dcc.c \
$(BACNET_BASIC)/service/h_rd.c \
$(BACNET_BASIC)/service/h_rp.c \
@@ -60,6 +62,7 @@ BASIC_SRC = \
$(BACNET_BASIC)/service/h_noserv.c \
$(BACNET_BASIC)/service/s_iam.c \
$(BACNET_BASIC)/service/s_ihave.c \
$(BACNET_BASIC)/sys/bsramfs.c \
$(BACNET_BASIC)/sys/debug.c \
$(BACNET_BASIC)/sys/datetime_mstimer.c \
$(BACNET_BASIC)/sys/days.c \
@@ -72,6 +75,7 @@ BASIC_SRC = \
BACNET_SRC = \
$(BACNET_CORE)/abort.c \
$(BACNET_CORE)/arf.c \
$(BACNET_CORE)/bacaction.c \
$(BACNET_CORE)/bacaddr.c \
$(BACNET_CORE)/bacapp.c \
@@ -177,6 +181,7 @@ BACNET_FLAGS += -DBIG_ENDIAN=0
BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0
BACNET_FLAGS += -DMAX_CHARACTER_STRING_BYTES=64
BACNET_FLAGS += -DMAX_OCTET_STRING_BYTES=64
BACNET_FLAGS += -DBACFILE
BACNET_FLAGS += -DBACAPP_MINIMAL
BACNET_FLAGS += -DBACNET_STACK_DEPRECATED_DISABLE
# if called from root Makefile, PRINT was already defined
+2
View File
@@ -61,6 +61,8 @@ void bacnet_init(void)
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_ATOMIC_READ_FILE, handler_atomic_read_file);
/* start the cyclic 1 second timer for DCC */
mstimer_set(&DCC_Timer, DCC_CYCLE_SECONDS * 1000);
}
+8
View File
@@ -31,6 +31,9 @@
#include "bacnet/basic/object/mso.h"
#include "bacnet/basic/object/msv.h"
#include "bacnet/basic/object/program.h"
#if defined(BACFILE)
#include "bacnet/basic/object/bacfile.h"
#endif
#if (BACNET_PROTOCOL_REVISION >= 17)
#include "bacnet/basic/object/netport.h"
#endif
@@ -94,6 +97,11 @@ static struct my_object_functions {
Program_Index_To_Instance, Program_Valid_Instance,
Program_Object_Name, Program_Read_Property,
Program_Write_Property, Program_Property_Lists},
#if defined(BACFILE)
{ OBJECT_FILE, bacfile_init, bacfile_count, bacfile_index_to_instance,
bacfile_valid_instance, bacfile_object_name, bacfile_read_property,
bacfile_write_property, BACfile_Property_Lists },
#endif
#if (BACNET_PROTOCOL_REVISION >= 17)
{ OBJECT_NETWORK_PORT, Network_Port_Init, Network_Port_Count,
Network_Port_Index_To_Instance, Network_Port_Valid_Instance,
+26 -4
View File
@@ -15,7 +15,10 @@
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_rng.h"
#include "system_stm32f4xx.h"
#include "bacnet/basic/object/bacfile.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/program.h"
#include "bacnet/basic/sys/bsramfs.h"
#include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/sys/ringbuf.h"
#include "bacnet/datalink/datalink.h"
@@ -88,6 +91,7 @@ static const char *UBASIC_Program_3 =
"end;";
/* uBASIC data tree for each program running */
static struct ubasic_data UBASIC_Data[3];
static struct bacnet_file_sramfs_data Static_Files[3];
/**
* @brief Called from _write() function from printf and friends
@@ -105,6 +109,7 @@ int __io_putchar(int ch)
*/
int main(void)
{
size_t i;
/*At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f4xx.s) before to branch to application main.
@@ -165,11 +170,28 @@ int main(void)
}
/* initialize application layer*/
bacnet_init();
/* configure a program */
bacfile_sramfs_init();
/* configure the program object and loop time */
Program_UBASIC_Init(10);
Program_UBASIC_Create(1, &UBASIC_Data[0], UBASIC_Program_1);
Program_UBASIC_Create(2, &UBASIC_Data[1], UBASIC_Program_2);
Program_UBASIC_Create(3, &UBASIC_Data[2], UBASIC_Program_3);
/* create the uBASIC programs and link to file objects */
Static_Files[0].data = (char *)UBASIC_Program_1;
Static_Files[0].size = strlen(UBASIC_Program_1);
Static_Files[0].pathname = "/program1.bas";
Static_Files[1].data = (char *)UBASIC_Program_2;
Static_Files[1].size = strlen(UBASIC_Program_2);
Static_Files[1].pathname = "/program2.bas";
Static_Files[2].data = (char *)UBASIC_Program_3;
Static_Files[2].size = strlen(UBASIC_Program_3);
Static_Files[2].pathname = "/program3.bas";
for (i = 0; i < ARRAY_SIZE(Static_Files); i++) {
bacfile_create(1 + i);
bacfile_pathname_set(1 + i, Static_Files[i].pathname);
bacfile_read_only_set(1 + i, true);
bacfile_sramfs_add(&Static_Files[i]);
Program_UBASIC_Create(1 + i, &UBASIC_Data[i], Static_Files[i].data);
Program_Instance_Of_Set(1 + i, Static_Files[i].pathname);
}
/* loop forever */
for (;;) {
led_task();
bacnet_task();
+19 -3
View File
@@ -194,7 +194,9 @@ bool bacfile_object_name(
status =
characterstring_init_ansi(object_name, pObject->Object_Name);
} else {
snprintf(name_text, sizeof(name_text), "FILE %u", object_instance);
snprintf(
name_text, sizeof(name_text), "FILE %lu",
(unsigned long)object_instance);
status = characterstring_init_ansi(object_name, name_text);
}
}
@@ -265,7 +267,7 @@ bool bacfile_valid_instance(uint32_t object_instance)
* @brief Determines the number of objects
* @return Number of objects
*/
uint32_t bacfile_count(void)
unsigned bacfile_count(void)
{
return Keylist_Count(Object_List);
}
@@ -1022,12 +1024,22 @@ bool bacfile_read_record_data(BACNET_ATOMIC_READ_FILE_DATA *data)
return found;
}
/**
* @brief Write the data received to the file specified
* @param data - pointer to the data to write
* @return true - if successful
* @return false - if failed or access denied
*/
bool bacfile_write_stream_data(BACNET_ATOMIC_WRITE_FILE_DATA *data)
{
const char *pathname = NULL;
bool status = false;
size_t bytes_written = 0;
if (bacfile_read_only(data->object_instance)) {
/* if the file is read-only, then we cannot write to it */
return false;
}
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
status = true;
@@ -1052,7 +1064,7 @@ bool bacfile_write_stream_data(BACNET_ATOMIC_WRITE_FILE_DATA *data)
* @brief Write the data received to the file specified
* @param data - pointer to the data to write
* @return true - if successful
* @return false - if failed
* @return false - if failed or access denied
*/
bool bacfile_write_record_data(const BACNET_ATOMIC_WRITE_FILE_DATA *data)
{
@@ -1060,6 +1072,10 @@ bool bacfile_write_record_data(const BACNET_ATOMIC_WRITE_FILE_DATA *data)
bool found = false;
size_t i = 0;
if (bacfile_read_only(data->object_instance)) {
/* if the file is read-only, then we cannot write to it */
return false;
}
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
found = true;
+1 -1
View File
@@ -39,7 +39,7 @@ const char *bacfile_name_ansi(uint32_t object_instance);
BACNET_STACK_EXPORT
bool bacfile_valid_instance(uint32_t object_instance);
BACNET_STACK_EXPORT
uint32_t bacfile_count(void);
unsigned bacfile_count(void);
BACNET_STACK_EXPORT
uint32_t bacfile_index_to_instance(unsigned find_index);
BACNET_STACK_EXPORT
+458
View File
@@ -0,0 +1,458 @@
/**
* @file
* @brief A dynamic RAM file system BACnet File Object implementation.
* @author Steve Karg
* @date 2025
* @copyright SPDX-License-Identifier: MIT
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
#include "bacnet/basic/sys/keylist.h"
#include "bacnet/basic/object/bacfile.h"
#include "bacnet/datalink/cobs.h"
/* Key List for storing the object data sorted by instance number */
static OS_Keylist File_List;
struct file_data {
size_t size; /* size of the file in bytes */
char *data; /* data buffer */
};
#define CRC32K_INITIAL_VALUE (0xFFFFFFFF)
/**
* @brief Get a CRC32K checksum for a pathname to use as a hash key
* @param pathname - the pathname to calculate the CRC32K for
* @return CRC32K value
*/
static uint32_t pathname_crc32k(const char *pathname)
{
uint32_t crc32K = CRC32K_INITIAL_VALUE;
size_t len, i;
len = strlen(pathname);
for (i = 0; i < len; i++) {
crc32K = cobs_crc32k(pathname[i], crc32K);
}
return crc32K;
}
/**
* @brief For a given object instance-number, returns the pathname
* @param object_instance - object-instance number of the object
* @return internal file system path and name, or NULL if not set
*/
static struct file_data *bacfile_ramfs_open(const char *pathname)
{
struct file_data *pFile = NULL;
uint32_t crc32K;
int index;
if (!pathname || pathname[0] == 0) {
return NULL; /* invalid pathname */
}
crc32K = pathname_crc32k(pathname);
pFile = Keylist_Data(File_List, crc32K);
if (!pFile) {
pFile = calloc(1, sizeof(struct file_data));
if (pFile) {
pFile->size = 0;
pFile->data = NULL;
index = Keylist_Data_Add(File_List, crc32K, pFile);
if (index < 0) {
free(pFile);
pFile = NULL;
}
}
}
return pFile;
}
/**
* @brief Determines the file size for a given file
* @param pathname - name of the file to get the size for
* @return file size in bytes, or 0 if not found
*/
const char *bacfile_ramfs_file_data(const char *pathname)
{
struct file_data *pFile;
const char *file_data = NULL;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
file_data = pFile->data;
}
return file_data;
}
/**
* @brief Determines the file size for a given file
* @param pathname - name of the file to get the size for
* @return file size in bytes, or 0 if not found
*/
size_t bacfile_ramfs_file_size(const char *pathname)
{
struct file_data *pFile;
size_t file_size = 0;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
file_size = pFile->size;
}
return file_size;
}
/**
* @brief Sets the file size property value
* @param pathname - name of the file to set the size for
* @param file_size - value of the file size property
* @return true if file size is writable
*/
bool bacfile_ramfs_file_size_set(const char *pathname, size_t new_size)
{
struct file_data *pFile;
char *new_data;
bool status = false;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
if (new_size > 0) {
new_data = realloc(pFile->data, new_size);
if (new_data) {
pFile->data = new_data;
pFile->size = new_size;
status = true;
}
} else {
/* free the data */
free(pFile->data);
pFile->data = NULL;
pFile->size = 0;
status = true;
}
}
return status;
}
/**
* @brief Reads stream data from a file
* @param pathname - name of the file to read from
* @param fileStartPosition - starting position in the file
* @param fileData - data buffer to read into
* @param fileDataLen - size of the data buffer
* @return number of bytes read, or 0 if not successful
*/
size_t bacfile_ramfs_read_stream_data(
const char *pathname,
int32_t fileStartPosition,
uint8_t *fileData,
size_t fileDataLen)
{
struct file_data *pFile;
size_t len = 0;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
if (fileStartPosition + fileDataLen > pFile->size) {
/* read only up to the end of the file */
len = pFile->size - fileStartPosition;
} else {
len = fileDataLen;
}
memcpy(fileData, pFile->data + fileStartPosition, len);
}
return len;
}
/**
* @brief Writes stream data to a file
* @param pathname - name of the file to write to
* @param fileStartPosition - starting position in the file
* @param fileData - data buffer to write from
* @param fileDataLen - size of the data buffer
* @return number of bytes written, or 0 if not successful
*/
size_t bacfile_ramfs_write_stream_data(
const char *pathname,
int32_t fileStartPosition,
const uint8_t *fileData,
size_t fileDataLen)
{
size_t bytes_written = 0;
struct file_data *pFile;
size_t old_size;
char *new_data = NULL;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
if (fileStartPosition == 0) {
/* open the file as a clean slate when starting at 0 */
new_data = realloc(pFile->data, fileDataLen);
if (new_data) {
pFile->data = new_data;
memcpy(pFile->data, fileData, fileDataLen);
pFile->size = fileDataLen;
bytes_written = fileDataLen;
}
} else if (fileStartPosition == -1) {
/* If 'File Start Position' parameter has the special
value -1, then the write operation shall be treated
as an append to the current end of file. */
old_size = pFile->size;
pFile->size += fileDataLen;
new_data = realloc(pFile->data, pFile->size);
if (new_data) {
pFile->data = new_data;
memcpy(pFile->data + old_size, fileData, fileDataLen);
bytes_written = fileDataLen;
}
} else {
/* open for update */
if (fileStartPosition + fileDataLen > pFile->size) {
/* extend the file size */
new_data =
realloc(pFile->data, fileStartPosition + fileDataLen);
if (new_data) {
pFile->data = new_data;
pFile->size = fileStartPosition + fileDataLen;
memcpy(
pFile->data + fileStartPosition, fileData, fileDataLen);
bytes_written = fileDataLen;
}
} else {
memcpy(pFile->data + fileStartPosition, fileData, fileDataLen);
bytes_written = fileDataLen;
}
}
}
return bytes_written;
}
/**
* @brief Count the number of records in a file
* @param records - string of null-terminated records
* @return number of records
*/
static size_t record_count(const char *records)
{
size_t count = 0;
int len = 0;
if (records) {
do {
len = bacnet_strnlen(records, MAX_OCTET_STRING_BYTES);
if (len > 0) {
count++;
records = records + len + 1;
}
} while (len > 0);
}
return count;
}
/**
* @brief Get the specific record at index 0..N
* @param records - string of null-terminated records
* @param record_index - record index number 0..N of the records
* @return record, or NULL
*/
static char *record_by_index(char *records, size_t index)
{
size_t count = 0;
int len = 0;
if (records) {
do {
len = bacnet_strnlen(records, MAX_OCTET_STRING_BYTES);
if (len > 0) {
if (index == count) {
return records;
}
count++;
records = records + len + 1;
}
} while (len > 0);
}
return NULL;
}
/**
* @brief Writes record data to a file
* @param pathname - name of the file to write to
* @param fileStartRecord - starting record in the file
* @param fileIndexRecord - index of the record to read
* @param fileData - data buffer to read into
* @param fileDataLen - size of the data buffer
* @return true if successful, false otherwise
*/
bool bacfile_ramfs_write_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
const uint8_t *fileData,
size_t fileDataLen)
{
bool status = false;
size_t fileSeekRecord;
size_t fileRecordCount;
struct file_data *pFile;
char *record;
size_t record_len;
size_t tail_record_len;
char fileDataStr[MAX_OCTET_STRING_BYTES + 1] = {
0
}; /* +1 for null terminator */
size_t fileDataStrLen = 0;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
fileRecordCount = record_count(pFile->data);
if (fileStartRecord == -1) {
/* If 'File Start Record' parameter has the special
value -1, then the write operation shall be treated
as an append to the current end of file,
and fileIndexRecord can be ignored. */
fileSeekRecord = fileRecordCount;
} else {
fileSeekRecord = fileStartRecord + fileIndexRecord;
if (fileSeekRecord > fileRecordCount) {
/* cannot write more than 1 record beyond the end of the file */
return false;
}
}
/* sanitize the incoming record; assume from an octetstring */
fileDataStrLen = min(fileDataLen, MAX_OCTET_STRING_BYTES);
memcpy(fileDataStr, fileData, fileDataStrLen);
fileDataStr[fileDataStrLen] = 0; /* null-terminate */
if (fileDataStrLen == 0) {
return false; /* nothing to write */
}
if (fileSeekRecord < fileRecordCount) {
/* find the old record length */
record = record_by_index(pFile->data, fileSeekRecord);
record_len = bacnet_strnlen(record, MAX_OCTET_STRING_BYTES);
tail_record_len = pFile->size - (record - pFile->data) - record_len;
/* reallocate file to make room for new record */
record = realloc(
pFile->data, pFile->size - record_len + fileDataStrLen + 1);
if (!record) {
return false; /* out of memory */
}
pFile->data = record;
/* find the old record position after a realloc */
record = record_by_index(pFile->data, fileSeekRecord);
/* move all existing records after the inserted record */
if (tail_record_len > 0) {
memmove(
record + fileDataStrLen, record + record_len,
tail_record_len);
}
} else {
/* extend the file by this one record */
record = realloc(pFile->data, pFile->size + fileDataStrLen + 1);
if (!record) {
return false; /* out of memory */
}
pFile->data = record;
record = pFile->data + pFile->size;
pFile->size += fileDataStrLen + 1; /* +1 for the null terminator */
}
/* copy new record data into file */
memmove(record, fileDataStr, fileDataStrLen);
record[fileDataStrLen] = 0; /* null-terminate */
status = true;
}
return status;
}
/**
* @brief Reads record data from a file
* @param pathname - name of the file to read from
* @param fileStartRecord - starting record in the file
* @param fileIndexRecord - index of the record to read
* @param fileData - data buffer to read into
* @param fileDataLen - size of the data buffer
* @return true if successful, false otherwise
*/
bool bacfile_ramfs_read_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
uint8_t *fileData,
size_t fileDataLen)
{
bool status = false;
size_t fileSeekRecord;
struct file_data *pFile;
char *record;
size_t record_len;
pFile = bacfile_ramfs_open(pathname);
if (pFile) {
fileSeekRecord = fileStartRecord + fileIndexRecord;
/* seek to the start record */
record = record_by_index(pFile->data, fileSeekRecord);
if (record) {
record_len = bacnet_strnlen(record, MAX_OCTET_STRING_BYTES);
if ((record_len > 0) && (record_len <= fileDataLen)) {
/* copy the record data */
memcpy(fileData, record, record_len);
status = true;
}
}
}
return status;
}
/**
* @brief Deletes the files and their data
*/
void bacfile_ramfs_deinit(void)
{
struct file_data *pFile = NULL;
if (File_List) {
do {
pFile = Keylist_Data_Pop(File_List);
if (pFile) {
free(pFile);
}
} while (pFile);
Keylist_Delete(File_List);
File_List = NULL;
}
}
/**
* @brief Initializes the object data
*/
void bacfile_ramfs_init(void)
{
#if defined(BACFILE)
bacfile_write_stream_data_callback_set(bacfile_ramfs_write_stream_data);
bacfile_read_stream_data_callback_set(bacfile_ramfs_read_stream_data);
bacfile_write_record_data_callback_set(bacfile_ramfs_write_record_data);
bacfile_read_record_data_callback_set(bacfile_ramfs_read_record_data);
bacfile_file_size_callback_set(bacfile_ramfs_file_size);
bacfile_file_size_set_callback_set(bacfile_ramfs_file_size_set);
#endif
File_List = Keylist_Create();
}
+58
View File
@@ -0,0 +1,58 @@
/**
* @file
* @brief A dynamic RAM based BACnet File Object implementation.
* @author Steve Karg
* @date July 2025
* @copyright SPDX-License-Identifier: MIT
*/
#ifndef BACNET_FILE_RAMFS_H
#define BACNET_FILE_RAMFS_H
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
const char *bacfile_ramfs_file_data(const char *pathname);
BACNET_STACK_EXPORT
size_t bacfile_ramfs_file_size(const char *pathname);
BACNET_STACK_EXPORT
bool bacfile_ramfs_file_size_set(const char *pathname, size_t file_size);
BACNET_STACK_EXPORT
size_t bacfile_ramfs_read_stream_data(
const char *pathname,
int32_t fileStartPosition,
uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
size_t bacfile_ramfs_write_stream_data(
const char *pathname,
int32_t fileStartPosition,
const uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
bool bacfile_ramfs_write_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
const uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
bool bacfile_ramfs_read_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
void bacfile_ramfs_deinit(void);
BACNET_STACK_EXPORT
void bacfile_ramfs_init(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+211
View File
@@ -0,0 +1,211 @@
/**
* @file
* @brief A static RAM file system BACnet File Object implementation.
* @author Steve Karg
* @date 2025
* @copyright SPDX-License-Identifier: MIT
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
#include "bacnet/basic/object/bacfile.h"
#include "bacnet/basic/sys/bsramfs.h"
static struct bacnet_file_sramfs_data *File_List;
bool bacfile_sramfs_add(struct bacnet_file_sramfs_data *file_data)
{
struct bacnet_file_sramfs_data *head = NULL;
if (!file_data) {
return false; /* invalid data */
}
head = File_List;
if (!head) {
/* first file data */
File_List = file_data;
} else {
/* find the end of the list */
while (head->next) {
head = head->next;
}
/* add to the end of the list */
head->next = file_data;
}
return true;
}
/**
* @brief For a given object instance-number, returns the pathname
* @param object_instance - object-instance number of the object
* @return internal file system path and name, or NULL if not set
*/
static struct bacnet_file_sramfs_data *bacfile_sramfs_open(const char *pathname)
{
struct bacnet_file_sramfs_data *head;
if (!pathname || pathname[0] == 0) {
return NULL; /* invalid pathname */
}
head = File_List;
while (head) {
if (head->pathname) {
if (strcmp(head->pathname, pathname) == 0) {
return head; /* found the file */
}
}
head = head->next;
}
return NULL;
}
/**
* @brief Determines the file size for a given file
* @param pathname - name of the file to get the size for
* @return file size in bytes, or 0 if not found
*/
const char *bacfile_sramfs_file_data(const char *pathname)
{
struct bacnet_file_sramfs_data *pFile;
const char *file_data = NULL;
pFile = bacfile_sramfs_open(pathname);
if (pFile) {
file_data = pFile->data;
}
return file_data;
}
/**
* @brief Determines the file size for a given file
* @param pathname - name of the file to get the size for
* @return file size in bytes, or 0 if not found
*/
size_t bacfile_sramfs_file_size(const char *pathname)
{
struct bacnet_file_sramfs_data *pFile;
size_t file_size = 0;
pFile = bacfile_sramfs_open(pathname);
if (pFile) {
file_size = pFile->size;
}
return file_size;
}
/**
* @brief Reads stream data from a file
* @param pathname - name of the file to read from
* @param fileStartPosition - starting position in the file
* @param fileData - data buffer to read into
* @param fileDataLen - size of the data buffer
* @return number of bytes read, or 0 if not successful
*/
size_t bacfile_sramfs_read_stream_data(
const char *pathname,
int32_t fileStartPosition,
uint8_t *fileData,
size_t fileDataLen)
{
struct bacnet_file_sramfs_data *pFile;
size_t len = 0;
pFile = bacfile_sramfs_open(pathname);
if (pFile) {
if (fileStartPosition + fileDataLen > pFile->size) {
/* read only up to the end of the file */
len = pFile->size - fileStartPosition;
} else {
len = fileDataLen;
}
memcpy(fileData, pFile->data + fileStartPosition, len);
}
return len;
}
/**
* @brief Get the specific record at index 0..N
* @param records - string of null-terminated records
* @param record_index - record index number 0..N of the records
* @return record, or NULL
*/
static char *record_by_index(char *records, size_t index)
{
size_t count = 0;
int len = 0;
if (records) {
do {
len = bacnet_strnlen(records, MAX_OCTET_STRING_BYTES);
if (len > 0) {
if (index == count) {
return records;
}
count++;
records = records + len + 1;
}
} while (len > 0);
}
return NULL;
}
/**
* @brief Reads record data from a file
* @param pathname - name of the file to read from
* @param fileStartRecord - starting record in the file
* @param fileIndexRecord - index of the record to read
* @param fileData - data buffer to read into
* @param fileDataLen - size of the data buffer
* @return true if successful, false otherwise
*/
bool bacfile_sramfs_read_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
uint8_t *fileData,
size_t fileDataLen)
{
bool status = false;
size_t fileSeekRecord;
struct bacnet_file_sramfs_data *pFile;
char *record;
size_t record_len;
pFile = bacfile_sramfs_open(pathname);
if (pFile) {
fileSeekRecord = fileStartRecord + fileIndexRecord;
/* seek to the start record */
record = record_by_index(pFile->data, fileSeekRecord);
if (record) {
record_len = bacnet_strnlen(record, MAX_OCTET_STRING_BYTES);
if ((record_len > 0) && (record_len <= fileDataLen)) {
/* copy the record data */
memcpy(fileData, record, record_len);
status = true;
}
}
}
return status;
}
/**
* @brief Initializes the object data
*/
void bacfile_sramfs_init(void)
{
#if defined(BACFILE)
bacfile_read_stream_data_callback_set(bacfile_sramfs_read_stream_data);
bacfile_read_record_data_callback_set(bacfile_sramfs_read_record_data);
bacfile_file_size_callback_set(bacfile_sramfs_file_size);
#endif
}
+67
View File
@@ -0,0 +1,67 @@
/**
* @file
* @brief A static RAM based BACnet File Object implementation.
* @author Steve Karg
* @date July 2025
* @copyright SPDX-License-Identifier: MIT
*/
#ifndef BACNET_FILE_SRAMFS_H
#define BACNET_FILE_SRAMFS_H
/* BACnet Stack defines - first */
#include "bacnet/bacdef.h"
struct bacnet_file_sramfs_data {
size_t size; /* size of the file in bytes */
char *data; /* data buffer */
char *pathname; /* pathname of the file */
struct bacnet_file_sramfs_data *next; /* pointer to the next file data */
};
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
const char *bacfile_sramfs_file_data(const char *pathname);
BACNET_STACK_EXPORT
bool bacfile_sramfs_file_data_set(const char *pathname, const char *file_data);
BACNET_STACK_EXPORT
size_t bacfile_sramfs_file_size(const char *pathname);
BACNET_STACK_EXPORT
bool bacfile_sramfs_file_size_set(const char *pathname, size_t file_size);
BACNET_STACK_EXPORT
size_t bacfile_sramfs_read_stream_data(
const char *pathname,
int32_t fileStartPosition,
uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
size_t bacfile_sramfs_write_stream_data(
const char *pathname,
int32_t fileStartPosition,
const uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
bool bacfile_sramfs_write_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
const uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
bool bacfile_sramfs_read_record_data(
const char *pathname,
int32_t fileStartRecord,
size_t fileIndexRecord,
uint8_t *fileData,
size_t fileDataLen);
BACNET_STACK_EXPORT
bool bacfile_sramfs_add(struct bacnet_file_sramfs_data *file_data);
BACNET_STACK_EXPORT
void bacfile_sramfs_init(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+2
View File
@@ -181,6 +181,8 @@ list(APPEND testdirs
# basic/program
bacnet/basic/program/ubasic
# basic/sys
bacnet/basic/sys/bramfs
bacnet/basic/sys/bsramfs
bacnet/basic/sys/color_rgb
bacnet/basic/sys/days
bacnet/basic/sys/dst
@@ -0,0 +1,45 @@
# 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/basic/sys/bramfs.c
# BACnet library files
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/datalink/cobs.c
# Support files and stubs (pathname alphabetical)
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+225
View File
@@ -0,0 +1,225 @@
/* @file
* @brief tests the BACnet RAM File System (BRAMFS)
* @date August 2025
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
* @copyright SPDX-License-Identifier: MIT
*/
#include <limits.h>
#include <zephyr/ztest.h>
#include <bacnet/bacstr.h>
#include <bacnet/basic/sys/bramfs.h>
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Unit Test for the BACnet RAM File System (BRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BRAMFS_stream)
#else
static void test_BRAMFS_stream(void)
#endif
{
const char *pathname = "testfile.txt";
size_t file_size = 0;
uint8_t null_file_data[256] = { 0 };
uint8_t test_file_data[256] = { 0 };
/* data less than 256 bytes */
uint8_t file_data[] = {
"This is a test file for the BACnet RAM File System (BRAMFS). "
"It contains some sample data to be read and written."
};
uint8_t file_data_2[] = {
"This is a second test file for the BACnet RAM File System (BRAMFS). "
"It contains some additional sample data to be read and written."
};
uint8_t file_data_small[] = { "Small file data" };
int32_t fileStartPosition = 0;
/* Initialize the BRAMFS */
bacfile_ramfs_init();
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(file_size, 0, "File size should be 0 after initialization");
zassert_true(
bacfile_ramfs_file_size_set(pathname, sizeof(null_file_data)),
"Failed to set file size");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(null_file_data),
"File size should be 256 after setting");
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(
file_size, sizeof(test_file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, null_file_data, sizeof(test_file_data)) == 0,
"File data should be zeroed out initially");
file_size = bacfile_ramfs_write_stream_data(
pathname, 0, file_data, sizeof(file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data, sizeof(file_data)) == 0,
"File data should match written data");
/* append data to the end of the file */
fileStartPosition = -1;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data_2, sizeof(file_data_2));
zassert_equal(file_size, sizeof(file_data_2), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, sizeof(file_data), test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data_2), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_2, sizeof(file_data_2)) == 0,
"File data should match appended data");
/* write a smaller file */
fileStartPosition = 0;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data_small, sizeof(file_data_small));
zassert_equal(
file_size, sizeof(file_data_small), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(
file_size, sizeof(file_data_small), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_small, sizeof(file_data_small)) == 0,
"File data should match smaller written data");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(file_data_small),
"File size should be %u after shrinking", sizeof(file_data_small));
/* shrink the file by writing zero at zero */
zassert_true(
bacfile_ramfs_file_size_set(pathname, 0),
"Failed to set file size to 0");
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(file_size, 0, "File size should be 0 after shrinking");
/* check a NULL pathname */
file_size = bacfile_ramfs_file_size(NULL);
zassert_equal(file_size, 0, "File size should be 0 on a null pathname");
/* append data to the end of the file */
fileStartPosition = 5;
file_size = bacfile_ramfs_write_stream_data(
pathname, fileStartPosition, file_data, sizeof(file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
file_size = bacfile_ramfs_read_stream_data(
pathname, fileStartPosition, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data, sizeof(file_data)) == 0,
"File data should match written data at position %d",
fileStartPosition);
file_size = bacfile_ramfs_file_size(pathname);
zassert_equal(
file_size, sizeof(file_data) + fileStartPosition,
"File size should be %u after appending",
sizeof(file_data) + fileStartPosition);
bacfile_ramfs_deinit();
}
/**
* @brief Unit Test for the BACnet RAM File System (BRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BRAMFS_records)
#else
static void test_BRAMFS_records(void)
#endif
{
const char *pathname = "testfile.txt";
bool status = false;
char record_1[] = { "This is the first record in the file." };
char record_2[] = { "This is the second record in the file." };
char record_3[] = { "This is the third record in the file." };
size_t record_len = 0;
/* Initialize the BRAMFS */
bacfile_ramfs_init();
/* no data in the file - expect failure */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_false(status, "Read record 1 should fail on empty file");
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_false(status, "Read record 2 should fail on empty file");
record_len = bacnet_strnlen(record_3, sizeof(record_3));
status = bacfile_ramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, record_len);
zassert_false(status, "Read record 3 should fail on empty file");
/* write the first record */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_write_record_data(
pathname, 0, 0, (const uint8_t *)record_1, record_len);
zassert_true(status, "Write record 1 should succeed");
/* read the first record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_true(status, "Read record 1 should succeed");
zassert_true(
memcmp(record_1, record_1, record_len) == 0,
"Record 1 data should match written data");
/* write the second record as an append */
record_len = bacnet_strnlen(record_2, sizeof(record_2));
status = bacfile_ramfs_write_record_data(
pathname, -1, 1, (const uint8_t *)record_2, record_len);
zassert_true(status, "Write record 2 should succeed");
/* read the second record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_true(status, "Read record 2 should succeed");
zassert_true(
memcmp(record_2, record_2, record_len) == 0,
"Record 2 data should match written data");
/* overwrite the third record at index 1 */
record_len = bacnet_strnlen(record_3, sizeof(record_3));
status = bacfile_ramfs_write_record_data(
pathname, 0, 1, (const uint8_t *)record_3, record_len);
zassert_true(status, "Write record 3 should succeed");
/* read the third record */
status = bacfile_ramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, record_len);
zassert_true(status, "Read record 2 should succeed");
zassert_true(
memcmp(record_2, record_3, record_len) == 0,
"Record 2 data should match written record 3 data");
/* read the first record again */
record_len = bacnet_strnlen(record_1, sizeof(record_1));
status = bacfile_ramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, record_len);
zassert_true(status, "Read record 1 should succeed");
zassert_true(
memcmp(record_1, record_1, record_len) == 0,
"Record 1 data should match written data");
bacfile_ramfs_deinit();
}
/**
* @}
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST_SUITE(bramfs_tests, NULL, NULL, NULL, NULL, NULL);
#else
void test_main(void)
{
ztest_test_suite(
bramfs_tests, ztest_unit_test(test_BRAMFS_stream),
ztest_unit_test(test_BRAMFS_records));
ztest_run_test_suite(bramfs_tests);
}
#endif
@@ -0,0 +1,45 @@
# 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/basic/sys/bsramfs.c
# BACnet library files
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/datalink/cobs.c
# Support files and stubs (pathname alphabetical)
# Test and test library files
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+143
View File
@@ -0,0 +1,143 @@
/* @file
* @brief tests the BACnet RAM File System (BSRAMFS)
* @date August 2025
* @author Steve Karg <Steve Karg <skarg@users.sourceforge.net>
* @copyright SPDX-License-Identifier: MIT
*/
#include <limits.h>
#include <zephyr/ztest.h>
#include <bacnet/bacstr.h>
#include <bacnet/basic/sys/bsramfs.h>
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Unit Test for the BACnet static RAM File System (BSRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BSRAMFS_stream)
#else
static void test_BSRAMFS_stream(void)
#endif
{
struct bacnet_file_sramfs_data file_data[3] = {
{ 0, NULL, "testfile1.txt", NULL },
{ 0, NULL, "testfile2.txt", NULL },
{ 0, NULL, "testfile3.txt", NULL }
};
size_t file_size = 0, i = 0;
uint8_t test_file_data[256] = { 0 };
/* data less than 256 bytes */
uint8_t file_data_1[] = {
"This is a first test file for the BACnet RAM File System (BSRAMFS). "
"It contains some sample data to be read and written."
};
uint8_t file_data_2[] = {
"This is a second test file for the BACnet RAM File System (BSRAMFS). "
"It contains some additional sample data to be read and written."
};
uint8_t file_data_3[] = { "Small file data" };
/* Initialize the BSRAMFS */
bacfile_sramfs_init();
for (i = 0; i < ARRAY_SIZE(file_data); i++) {
file_size = bacfile_sramfs_file_size(file_data[i].pathname);
zassert_equal(
file_size, 0, "File size should be 0 after initialization");
}
/* add static files to the file system */
file_data[0].data = (char *)file_data_1;
file_data[0].size = sizeof(file_data_1);
zassert_true(
bacfile_sramfs_add(&file_data[0]), "Failed to add file_data[0]");
file_data[1].data = (char *)file_data_2;
file_data[1].size = sizeof(file_data_2);
zassert_true(
bacfile_sramfs_add(&file_data[1]), "Failed to add file_data[1]");
file_data[2].data = (char *)file_data_3;
file_data[2].size = sizeof(file_data_3);
zassert_true(
bacfile_sramfs_add(&file_data[2]), "Failed to add file_data[2]");
/* read back the files and check the data */
file_size = bacfile_sramfs_read_stream_data(
file_data[0].pathname, 0, test_file_data, sizeof(test_file_data));
zassert_equal(file_size, sizeof(file_data_1), "file_size=%zu", file_size);
zassert_true(
memcmp(test_file_data, file_data_1, sizeof(file_data_1)) == 0,
"File data should match!");
}
/**
* @brief Unit Test for the BACnet RAM File System (BSRAMFS)
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(bramfs_tests, test_BSRAMFS_records)
#else
static void test_BSRAMFS_records(void)
#endif
{
struct bacnet_file_sramfs_data file_data[1] = {
{ 0,
"This is the first record in the file.\0"
"This is the second record in the file.\0"
"This is the third record in the file.",
"testfile.txt", NULL }
};
bool status = false;
const char *pathname = file_data[0].pathname;
char record_1[MAX_OCTET_STRING_BYTES] = { 0 };
char record_2[MAX_OCTET_STRING_BYTES] = { 0 };
char record_3[MAX_OCTET_STRING_BYTES] = { 0 };
/* Initialize the BSRAMFS */
bacfile_sramfs_init();
/* no data in the file - expect failure */
status = bacfile_sramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, sizeof(record_1));
zassert_false(status, "Read record 1 should fail on empty file");
status = bacfile_sramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, sizeof(record_2));
zassert_false(status, "Read record 2 should fail on empty file");
status = bacfile_sramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, sizeof(record_3));
zassert_false(status, "Read record 3 should fail on empty file");
/* add the static file with records */
bacfile_sramfs_add(&file_data[0]);
/* read the first record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 0, (uint8_t *)record_1, sizeof(record_1));
zassert_true(status, "Read record 1 should succeed");
/* read the second record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 1, (uint8_t *)record_2, sizeof(record_2));
zassert_true(status, "Read record 2 should succeed");
/* read the third record */
status = bacfile_sramfs_read_record_data(
pathname, 0, 2, (uint8_t *)record_3, sizeof(record_3));
zassert_true(status, "Read record 3 should succeed");
}
/**
* @}
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST_SUITE(bramfs_tests, NULL, NULL, NULL, NULL, NULL);
#else
void test_main(void)
{
ztest_test_suite(
bramfs_tests, ztest_unit_test(test_BSRAMFS_stream),
ztest_unit_test(test_BSRAMFS_records));
ztest_run_test_suite(bramfs_tests);
}
#endif