Refactored the bacnet file object to be storage agnostic with callbacks. (#1056)

This commit is contained in:
Steve Karg
2025-08-01 09:58:07 -05:00
committed by GitHub
parent f88f5a3424
commit 1bebd6ac81
33 changed files with 869 additions and 308 deletions
+14 -11
View File
@@ -27,17 +27,20 @@ struct object_data {
static struct object_data Object_List[MAX_ACCUMULATORS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_SCALE,
PROP_UNITS,
PROP_MAX_PRES_VALUE,
-1 };
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_SCALE,
PROP_UNITS,
PROP_MAX_PRES_VALUE,
-1
};
static const int Properties_Optional[] = { PROP_DESCRIPTION, -1 };
+17 -14
View File
@@ -24,20 +24,23 @@ static bool Access_Credential_Initialized = false;
static ACCESS_CREDENTIAL_DESCR ac_descr[MAX_ACCESS_CREDENTIALS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_GLOBAL_IDENTIFIER,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_CREDENTIAL_STATUS,
PROP_REASON_FOR_DISABLE,
PROP_AUTHENTICATION_FACTORS,
PROP_ACTIVATION_TIME,
PROP_EXPIRATION_TIME,
PROP_CREDENTIAL_DISABLE,
PROP_ASSIGNED_ACCESS_RIGHTS,
-1 };
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_GLOBAL_IDENTIFIER,
PROP_STATUS_FLAGS,
PROP_RELIABILITY,
PROP_CREDENTIAL_STATUS,
PROP_REASON_FOR_DISABLE,
PROP_AUTHENTICATION_FACTORS,
PROP_ACTIVATION_TIME,
PROP_EXPIRATION_TIME,
PROP_CREDENTIAL_DISABLE,
PROP_ASSIGNED_ACCESS_RIGHTS,
-1
};
static const int Properties_Optional[] = { -1 };
+17 -14
View File
@@ -22,20 +22,23 @@ static bool Access_Door_Initialized = false;
static ACCESS_DOOR_DESCR ad_descr[MAX_ACCESS_DOORS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
PROP_DOOR_PULSE_TIME,
PROP_DOOR_EXTENDED_PULSE_TIME,
PROP_DOOR_OPEN_TOO_LONG_TIME,
-1 };
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_PRIORITY_ARRAY,
PROP_RELINQUISH_DEFAULT,
PROP_DOOR_PULSE_TIME,
PROP_DOOR_EXTENDED_PULSE_TIME,
PROP_DOOR_OPEN_TOO_LONG_TIME,
-1
};
static const int Properties_Optional[] = {
PROP_DOOR_STATUS, PROP_LOCK_STATUS,
+1
View File
@@ -23,6 +23,7 @@ static ACCESS_POINT_DESCR ap_descr[MAX_ACCESS_POINTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
+1
View File
@@ -24,6 +24,7 @@ static ACCESS_USER_DESCR au_descr[MAX_ACCESS_USERS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_GLOBAL_IDENTIFIER, PROP_STATUS_FLAGS, PROP_RELIABILITY,
PROP_USER_TYPE, PROP_CREDENTIALS, -1
+1
View File
@@ -24,6 +24,7 @@ static ACCESS_ZONE_DESCR az_descr[MAX_ACCESS_ZONES];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_GLOBAL_IDENTIFIER, PROP_OCCUPANCY_STATE, PROP_STATUS_FLAGS,
PROP_EVENT_STATE, PROP_RELIABILITY, PROP_OUT_OF_SERVICE,
+19 -12
View File
@@ -30,29 +30,36 @@ static OS_Keylist Object_List;
/* common object type */
static const BACNET_OBJECT_TYPE Object_Type = OBJECT_ANALOG_INPUT;
/* clang-format off */
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE, PROP_UNITS, -1
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE, PROP_UNITS, -1
};
static const int Properties_Optional[] = {
PROP_DESCRIPTION, PROP_RELIABILITY, PROP_COV_INCREMENT,
/* unordered list of optional properties */
PROP_DESCRIPTION,
PROP_RELIABILITY,
PROP_COV_INCREMENT,
#if defined(INTRINSIC_REPORTING)
PROP_TIME_DELAY, PROP_NOTIFICATION_CLASS, PROP_HIGH_LIMIT,
PROP_LOW_LIMIT, PROP_DEADBAND, PROP_LIMIT_ENABLE, PROP_EVENT_ENABLE,
PROP_ACKED_TRANSITIONS, PROP_NOTIFY_TYPE, PROP_EVENT_TIME_STAMPS,
PROP_TIME_DELAY,
PROP_NOTIFICATION_CLASS,
PROP_HIGH_LIMIT,
PROP_LOW_LIMIT,
PROP_DEADBAND,
PROP_LIMIT_ENABLE,
PROP_EVENT_ENABLE,
PROP_ACKED_TRANSITIONS,
PROP_NOTIFY_TYPE,
PROP_EVENT_TIME_STAMPS,
PROP_EVENT_DETECTION_ENABLE,
#endif
-1
};
static const int Properties_Proprietary[] = {
-1
};
/* clang-format on */
static const int Properties_Proprietary[] = { -1 };
/**
* Initialize the pointers for the required, the optional and the properitary
+370 -220
View File
@@ -46,20 +46,26 @@ static OS_Keylist Object_List;
/* common object type */
static const BACNET_OBJECT_TYPE Object_Type = OBJECT_FILE;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int bacfile_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_FILE_TYPE,
PROP_FILE_SIZE,
PROP_MODIFICATION_DATE,
PROP_ARCHIVE,
PROP_READ_ONLY,
PROP_FILE_ACCESS_METHOD,
-1 };
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_FILE_TYPE,
PROP_FILE_SIZE,
PROP_MODIFICATION_DATE,
PROP_ARCHIVE,
PROP_READ_ONLY,
PROP_FILE_ACCESS_METHOD,
-1
};
static const int bacfile_Properties_Optional[] = { PROP_DESCRIPTION, -1 };
static const int Properties_Optional[] = {
/* unordered list of optional properties */
PROP_DESCRIPTION, -1
};
static const int bacfile_Properties_Proprietary[] = { -1 };
static const int Properties_Proprietary[] = { -1 };
/**
* @brief Returns the list of required, optional, and proprietary properties.
@@ -75,13 +81,13 @@ void BACfile_Property_Lists(
const int **pRequired, const int **pOptional, const int **pProprietary)
{
if (pRequired) {
*pRequired = bacfile_Properties_Required;
*pRequired = Properties_Required;
}
if (pOptional) {
*pOptional = bacfile_Properties_Optional;
*pOptional = Properties_Optional;
}
if (pProprietary) {
*pProprietary = bacfile_Properties_Proprietary;
*pProprietary = Properties_Proprietary;
}
return;
@@ -280,22 +286,221 @@ uint32_t bacfile_index_to_instance(unsigned find_index)
}
/**
* @brief Determines the file size for a given file
* @param pFile - file handle
* @return file size in bytes, or 0 if not found
* @brief Callback function to write record data
*/
static long fsize(FILE *pFile)
{
long size = 0;
long origin = 0;
static bool (*bacfile_write_record_data_cb)(
const char *, size_t, size_t, const uint8_t *, size_t) = NULL;
if (pFile) {
origin = ftell(pFile);
fseek(pFile, 0L, SEEK_END);
size = ftell(pFile);
fseek(pFile, origin, SEEK_SET);
/**
* @brief Callback function to write record data
*
* @param pathname - name of the file to write to
* @param fileStartRecord - starting record number in the file
* @param record_index - index of the record to write
* @param buffer - data buffer to write
* @param buffer_size - size of the data buffer
* @return true if the record data was written successfully
* @return false if the record data could not be written
*/
static bool bacfile_write_record_data_callback(
const char *pathname,
size_t fileStartRecord,
size_t record_index,
const uint8_t *buffer,
size_t buffer_size)
{
if (bacfile_write_record_data_cb) {
return bacfile_write_record_data_cb(
pathname, fileStartRecord, record_index, buffer, buffer_size);
}
return (size);
return false;
}
/**
* @brief Sets the callback function for writing record data
* @param callback - function pointer to the callback
*/
void bacfile_write_record_data_callback_set(
bool (*callback)(const char *, size_t, size_t, const uint8_t *, size_t))
{
bacfile_write_record_data_cb = callback;
}
/**
* @brief Callback function to read record data
*/
static bool (*bacfile_read_record_data_cb)(
const char *, size_t, size_t, uint8_t *, size_t) = NULL;
/**
* @brief Callback function to read record data
* @param pathname - name of the file to read from
* @param fileStartRecord - starting record number in the file
* @param record_index - index of the record to read
* @param buffer - data buffer to read into
* @param buffer_size - size of the data buffer
* @return true if the record data was read successfully
* @return false if the record data could not be read
*/
static bool bacfile_read_record_data_callback(
const char *pathname,
size_t fileStartRecord,
size_t record_index,
uint8_t *buffer,
size_t buffer_size)
{
if (bacfile_read_record_data_cb) {
return bacfile_read_record_data_cb(
pathname, fileStartRecord, record_index, buffer, buffer_size);
}
return false;
}
/**
* @brief Sets the callback function for reading record data
* @param callback - function pointer to the callback
*/
void bacfile_read_record_data_callback_set(
bool (*callback)(const char *, size_t, size_t, uint8_t *, size_t))
{
bacfile_read_record_data_cb = callback;
}
/**
* @brief Callback function to write stream data
*/
static size_t (*bacfile_write_stream_data_cb)(
const char *, size_t, const uint8_t *, size_t) = NULL;
/**
* @brief Callback function to write stream data
* @param pathname - name of the file to write to
* @param fileStartPosition - starting position in the file
* @param buffer - data buffer to write
* @param buffer_size - size of the data buffer
* @return number of bytes written, or 0 if not successful
*/
static size_t bacfile_write_stream_data_callback(
const char *pathname,
size_t fileStartPosition,
const uint8_t *buffer,
size_t buffer_size)
{
if (bacfile_write_stream_data_cb) {
return bacfile_write_stream_data_cb(
pathname, fileStartPosition, buffer, buffer_size);
}
return 0;
}
/**
* @brief Sets the callback function for writing stream data
* @param callback - function pointer to the callback
*/
void bacfile_write_stream_data_callback_set(
size_t (*callback)(const char *, size_t, const uint8_t *, size_t))
{
bacfile_write_stream_data_cb = callback;
}
/**
* @brief Callback function to read stream data
*/
static size_t (*bacfile_read_stream_data_cb)(
const char *, size_t, uint8_t *, size_t) = NULL;
/**
* @brief Callback function to read stream data
* @param pathname - name of the file to read from
* @param fileStartPosition - starting position in the file
* @param buffer - data buffer to read into
* @param buffer_size - size of the data buffer and number of bytes to read
* @return number of bytes read, or 0 if not successful
*/
static size_t bacfile_read_stream_data_callback(
const char *pathname,
size_t fileStartPosition,
uint8_t *buffer,
size_t buffer_size)
{
if (bacfile_read_stream_data_cb) {
return bacfile_read_stream_data_cb(
pathname, fileStartPosition, buffer, buffer_size);
}
return 0;
}
/**
* @brief Sets the callback function for reading stream data
* @param callback - function pointer to the callback
*/
void bacfile_read_stream_data_callback_set(
size_t (*callback)(const char *, size_t, uint8_t *, size_t))
{
bacfile_read_stream_data_cb = callback;
}
/**
* @brief Callback function to get file size
*/
static size_t (*bacfile_file_size_cb)(const char *) = NULL;
/**
* @brief Callback function to get file size
* @param pathname - name of the file to get the size of
* @return size of the file in bytes, or 0 if not found
*/
static size_t bacfile_file_size_callback(const char *pathname)
{
size_t file_size = 0;
if (bacfile_file_size_cb) {
file_size = bacfile_file_size_cb(pathname);
}
return file_size;
}
/**
* @brief Sets the callback function for getting file size
* @param callback - function pointer to the callback
*/
void bacfile_file_size_callback_set(size_t (*callback)(const char *))
{
bacfile_file_size_cb = callback;
}
/**
* @brief Callback function to set file size
*/
static bool (*bacfile_file_size_set_cb)(const char *, size_t) = NULL;
/**
* @brief Callback function to set file size
* @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, false otherwise
*/
bool bacfile_file_size_set_callback(const char *pathname, size_t file_size)
{
if (bacfile_file_size_set_cb) {
return bacfile_file_size_set_cb(pathname, file_size);
}
return false;
}
/**
* @brief Sets the callback function for setting file size
* @param callback - function pointer to the callback
*/
void bacfile_file_size_set_callback_set(bool (*callback)(const char *, size_t))
{
bacfile_file_size_set_cb = callback;
}
/**
@@ -308,22 +513,13 @@ static long fsize(FILE *pFile)
uint32_t
bacfile_read(uint32_t object_instance, uint8_t *buffer, uint32_t buffer_size)
{
const char *pFilename = NULL;
FILE *pFile = NULL;
const char *pathname = NULL;
long file_size = 0;
pFilename = bacfile_pathname(object_instance);
if (pFilename) {
pFile = fopen(pFilename, "rb");
if (pFile) {
file_size = fsize(pFile);
if (buffer && (buffer_size >= file_size)) {
if (fread(buffer, file_size, 1, pFile) == 0) {
file_size = 0;
}
}
fclose(pFile);
}
pathname = bacfile_pathname(object_instance);
if (pathname) {
file_size =
bacfile_read_stream_data_callback(pathname, 0, buffer, buffer_size);
}
return (uint32_t)file_size;
@@ -339,20 +535,13 @@ bacfile_read(uint32_t object_instance, uint8_t *buffer, uint32_t buffer_size)
uint32_t bacfile_write(
uint32_t object_instance, const uint8_t *buffer, uint32_t buffer_size)
{
const char *pFilename = NULL;
FILE *pFile = NULL;
const char *pathname = NULL;
long file_size = 0;
pFilename = bacfile_pathname(object_instance);
if (pFilename) {
/* open the file as a clean slate when starting at 0 */
pFile = fopen(pFilename, "wb");
if (pFile) {
if (fwrite(buffer, buffer_size, 1, pFile) == 1) {
file_size = buffer_size;
}
fclose(pFile);
}
pathname = bacfile_pathname(object_instance);
if (pathname) {
file_size = bacfile_write_stream_data_callback(
pathname, 0, buffer, buffer_size);
}
return (uint32_t)file_size;
@@ -365,20 +554,15 @@ uint32_t bacfile_write(
*/
BACNET_UNSIGNED_INTEGER bacfile_file_size(uint32_t object_instance)
{
const char *pFilename = NULL;
FILE *pFile = NULL;
const char *pathname = NULL;
long file_position = 0;
BACNET_UNSIGNED_INTEGER file_size = 0;
pFilename = bacfile_pathname(object_instance);
if (pFilename) {
pFile = fopen(pFilename, "rb");
if (pFile) {
file_position = fsize(pFile);
if (file_position >= 0) {
file_size = (BACNET_UNSIGNED_INTEGER)file_position;
}
fclose(pFile);
pathname = bacfile_pathname(object_instance);
if (pathname) {
file_position = bacfile_file_size_callback(pathname);
if (file_position >= 0) {
file_size = (BACNET_UNSIGNED_INTEGER)file_position;
}
}
@@ -400,8 +584,8 @@ bool bacfile_file_size_set(
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->File_Access_Stream) {
(void)file_size;
/* FIXME: add clever POSIX file stuff here */
status =
bacfile_file_size_set_callback(pObject->Pathname, file_size);
}
}
@@ -717,20 +901,16 @@ bool bacfile_write_property(BACNET_WRITE_PROPERTY_DATA *wp_data)
}
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_NAME:
case PROP_OBJECT_TYPE:
case PROP_DESCRIPTION:
case PROP_FILE_TYPE:
case PROP_MODIFICATION_DATE:
case PROP_READ_ONLY:
case PROP_FILE_ACCESS_METHOD:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
if (property_lists_member(
Properties_Required, Properties_Optional,
Properties_Proprietary, wp_data->object_property)) {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
} else {
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
}
break;
}
@@ -786,31 +966,27 @@ uint32_t bacfile_instance_from_tsm(uint8_t invokeID)
bool bacfile_read_stream_data(BACNET_ATOMIC_READ_FILE_DATA *data)
{
const char *pFilename = NULL;
const char *pathname = NULL;
bool found = false;
FILE *pFile = NULL;
size_t len = 0;
size_t requestedOctetCount = 0;
pFilename = bacfile_pathname(data->object_instance);
if (pFilename) {
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
found = true;
pFile = fopen(pFilename, "rb");
if (pFile) {
(void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
len = fread(
octetstring_value(&data->fileData[0]), 1,
data->type.stream.requestedOctetCount, pFile);
if (len < data->type.stream.requestedOctetCount) {
data->endOfFile = true;
} else {
data->endOfFile = false;
}
octetstring_truncate(&data->fileData[0], len);
fclose(pFile);
} else {
octetstring_truncate(&data->fileData[0], 0);
data->endOfFile = true;
requestedOctetCount = data->type.stream.requestedOctetCount;
if (requestedOctetCount > octetstring_capacity(&data->fileData[0])) {
requestedOctetCount = octetstring_capacity(&data->fileData[0]);
}
len = bacfile_read_stream_data_callback(
pathname, data->type.stream.fileStartPosition,
octetstring_value(&data->fileData[0]), requestedOctetCount);
if (len < requestedOctetCount) {
data->endOfFile = true;
} else {
data->endOfFile = false;
}
octetstring_truncate(&data->fileData[0], len);
} else {
octetstring_truncate(&data->fileData[0], 0);
data->endOfFile = true;
@@ -819,163 +995,137 @@ bool bacfile_read_stream_data(BACNET_ATOMIC_READ_FILE_DATA *data)
return found;
}
bool bacfile_read_record_data(BACNET_ATOMIC_READ_FILE_DATA *data)
{
const char *pathname = NULL;
bool found = false;
bool status = false;
uint32_t i = 0;
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
found = true;
data->endOfFile = false;
for (i = 0; i < data->type.record.RecordCount; i++) {
status = bacfile_read_record_data_callback(
pathname, data->type.record.fileStartRecord, i,
octetstring_value(&data->fileData[i]),
octetstring_capacity(&data->fileData[i]));
if (!status) {
data->endOfFile = true;
data->type.record.RecordCount = i;
break;
}
}
}
return found;
}
bool bacfile_write_stream_data(BACNET_ATOMIC_WRITE_FILE_DATA *data)
{
const char *pFilename = NULL;
bool found = false;
FILE *pFile = NULL;
const char *pathname = NULL;
bool status = false;
size_t bytes_written = 0;
pFilename = bacfile_pathname(data->object_instance);
if (pFilename) {
found = true;
if (data->type.stream.fileStartPosition == 0) {
/* open the file as a clean slate when starting at 0 */
pFile = fopen(pFilename, "wb");
} else if (data->type.stream.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. */
pFile = fopen(pFilename, "ab+");
} else {
/* open for update */
pFile = fopen(pFilename, "rb+");
}
if (pFile) {
if (data->type.stream.fileStartPosition != -1) {
(void)fseek(
pFile, data->type.stream.fileStartPosition, SEEK_SET);
}
if (fwrite(
octetstring_value(&data->fileData[0]),
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
/* do something if it fails? */
}
fclose(pFile);
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
status = true;
/* note: 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.
If the 'File Start Position' parameter is 0,
open the file as a clean slate. */
bytes_written = bacfile_write_stream_data_callback(
pathname, data->type.stream.fileStartPosition,
octetstring_value(&data->fileData[0]),
octetstring_length(&data->fileData[0]));
if (bytes_written == 0) {
status = false; /* no data written */
}
}
return found;
return status;
}
/**
* @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
*/
bool bacfile_write_record_data(const BACNET_ATOMIC_WRITE_FILE_DATA *data)
{
const char *pFilename = NULL;
const char *pathname = NULL;
bool found = false;
FILE *pFile = NULL;
uint32_t i = 0;
char dummy_data[FILE_RECORD_SIZE];
const char *pData = NULL;
size_t i = 0;
pFilename = bacfile_pathname(data->object_instance);
if (pFilename) {
pathname = bacfile_pathname(data->object_instance);
if (pathname) {
found = true;
if (data->type.record.fileStartRecord == 0) {
/* open the file as a clean slate when starting at 0 */
pFile = fopen(pFilename, "wb");
} else if (data->type.record.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. */
pFile = fopen(pFilename, "ab+");
} else {
/* open for update */
pFile = fopen(pFilename, "rb+");
}
if (pFile) {
if ((data->type.record.fileStartRecord != -1) &&
(data->type.record.fileStartRecord > 0)) {
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord;
i++) {
pData = fgets(&dummy_data[0], sizeof(dummy_data), pFile);
if ((pData == NULL) || feof(pFile)) {
break;
}
}
}
for (i = 0; i < data->type.record.returnedRecordCount; i++) {
if (fwrite(
octetstring_value(
(BACNET_OCTET_STRING *)&data->fileData[i]),
octetstring_length(&data->fileData[i]), 1,
pFile) != 1) {
/* do something if it fails? */
}
}
fclose(pFile);
/* 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.
If the 'File Start Record' parameter is 0,
open the file as a clean slate. */
for (i = 0; i < data->type.record.returnedRecordCount; i++) {
bacfile_write_record_data_callback(
pathname, data->type.record.fileStartRecord, i,
octetstring_value((BACNET_OCTET_STRING *)&data->fileData[i]),
octetstring_length(&data->fileData[i]));
}
}
return found;
}
/**
* @brief Write the requested data received into the file specified
* @param instance - object-instance number of the object
* @param data - pointer to the data to write
* @return true - if successful
* @return false - if failed
*/
bool bacfile_read_ack_stream_data(
uint32_t instance, const BACNET_ATOMIC_READ_FILE_DATA *data)
{
bool found = false;
FILE *pFile = NULL;
const char *pFilename = NULL;
const char *pathname = NULL;
pFilename = bacfile_pathname(instance);
if (pFilename) {
pathname = bacfile_pathname(instance);
if (pathname) {
found = true;
pFile = fopen(pFilename, "rb+");
if (pFile) {
(void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET);
if (fwrite(
octetstring_value(
(BACNET_OCTET_STRING *)&data->fileData[0]),
octetstring_length(&data->fileData[0]), 1, pFile) != 1) {
#if PRINT_ENABLED
fprintf(
stderr, "Failed to write to %s (%lu)!\n", pFilename,
(unsigned long)instance);
#endif
}
fclose(pFile);
}
bacfile_write_stream_data_callback(
pathname, data->type.stream.fileStartPosition,
octetstring_value((BACNET_OCTET_STRING *)&data->fileData[0]),
octetstring_length(&data->fileData[0]));
}
return found;
}
/**
* @brief Write the requested data received into the file specified
* @param instance - object-instance number of the object
* @param data - pointer to the data to write
* @return true - if successful
* @return false - if failed
*/
bool bacfile_read_ack_record_data(
uint32_t instance, const BACNET_ATOMIC_READ_FILE_DATA *data)
{
bool found = false;
FILE *pFile = NULL;
const char *pFilename = NULL;
const char *pathname = NULL;
uint32_t i = 0;
char dummy_data[MAX_OCTET_STRING_BYTES] = { 0 };
char *pData = NULL;
pFilename = bacfile_pathname(instance);
if (pFilename) {
pathname = bacfile_pathname(instance);
if (pathname) {
found = true;
pFile = fopen(pFilename, "rb+");
if (pFile) {
if (data->type.record.fileStartRecord > 0) {
for (i = 0; i < (uint32_t)data->type.record.fileStartRecord;
i++) {
pData = fgets(&dummy_data[0], sizeof(dummy_data), pFile);
if ((pData == NULL) || feof(pFile)) {
break;
}
}
}
for (i = 0; i < data->type.record.RecordCount; i++) {
if (fwrite(
octetstring_value(
(BACNET_OCTET_STRING *)&data->fileData[i]),
octetstring_length(&data->fileData[i]), 1,
pFile) != 1) {
#if PRINT_ENABLED
fprintf(
stderr, "Failed to write to %s (%lu)!\n", pFilename,
(unsigned long)instance);
#endif
}
}
fclose(pFile);
for (i = 0; i < data->type.record.RecordCount; i++) {
bacfile_write_record_data_callback(
pathname, data->type.record.fileStartRecord, i,
octetstring_value((BACNET_OCTET_STRING *)&data->fileData[i]),
octetstring_length(&data->fileData[i]));
}
}
+17
View File
@@ -117,6 +117,23 @@ BACNET_STACK_EXPORT
uint32_t bacfile_write(
uint32_t object_instance, const uint8_t *buffer, uint32_t buffer_size);
BACNET_STACK_EXPORT
void bacfile_write_stream_data_callback_set(
size_t (*callback)(const char *, size_t, const uint8_t *, size_t));
BACNET_STACK_EXPORT
void bacfile_read_stream_data_callback_set(
size_t (*callback)(const char *, size_t, uint8_t *, size_t));
BACNET_STACK_EXPORT
void bacfile_write_record_data_callback_set(
bool (*callback)(const char *, size_t, size_t, const uint8_t *, size_t));
BACNET_STACK_EXPORT
void bacfile_read_record_data_callback_set(
bool (*callback)(const char *, size_t, size_t, uint8_t *, size_t));
BACNET_STACK_EXPORT
void bacfile_file_size_callback_set(size_t (*callback)(const char *));
BACNET_STACK_EXPORT
void bacfile_file_size_set_callback_set(bool (*callback)(const char *, size_t));
BACNET_STACK_EXPORT
uint32_t bacfile_create(uint32_t object_instance);
BACNET_STACK_EXPORT
+5 -11
View File
@@ -67,21 +67,16 @@ static const BACNET_OBJECT_TYPE Object_Type = OBJECT_BINARY_INPUT;
static binary_input_write_present_value_callback
Binary_Input_Write_Present_Value_Callback;
/* clang-format off */
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS,
PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE,
PROP_POLARITY,
-1
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE, PROP_POLARITY, -1
};
static const int Properties_Optional[] = {
/* unordered list of optional properties */
PROP_RELIABILITY,
PROP_DESCRIPTION,
PROP_ACTIVE_TEXT,
@@ -100,7 +95,6 @@ static const int Properties_Optional[] = {
};
static const int Properties_Proprietary[] = { -1 };
/* clang-format on */
/**
* Initialize the pointers for the required, the optional and the properitary
+5 -3
View File
@@ -42,13 +42,15 @@ static bitstring_value_write_present_value_callback
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, -1
};
static const int Properties_Optional[] = { PROP_RELIABILITY,
PROP_OUT_OF_SERVICE,
PROP_DESCRIPTION, -1 };
static const int Properties_Optional[] = {
/* unordered list of optional properties */
PROP_RELIABILITY, PROP_OUT_OF_SERVICE, PROP_DESCRIPTION, -1
};
static const int Properties_Proprietary[] = { -1 };
@@ -25,6 +25,7 @@ static CREDENTIAL_DATA_INPUT_DESCR cdi_descr[MAX_CREDENTIAL_DATA_INPUTS];
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
PROP_OBJECT_TYPE, PROP_PRESENT_VALUE,
PROP_STATUS_FLAGS, PROP_RELIABILITY,
+1 -1
View File
@@ -29,7 +29,7 @@ static const BACNET_OBJECT_TYPE Object_Type = OBJECT_CHARACTERSTRING_VALUE;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* list of the required properties */
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, -1
};
+5 -2
View File
@@ -48,13 +48,16 @@ static const char *Default_State_Text = "State 1\0"
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE, PROP_NUMBER_OF_STATES, -1
};
static const int Properties_Optional[] = { PROP_DESCRIPTION, PROP_RELIABILITY,
PROP_STATE_TEXT, -1 };
static const int Properties_Optional[] = {
/* unordered list of optional properties */
PROP_DESCRIPTION, PROP_RELIABILITY, PROP_STATE_TEXT, -1
};
static const int Properties_Proprietary[] = { -1 };
+5 -2
View File
@@ -48,13 +48,16 @@ static const char *Default_State_Text = "State 1\0"
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_PRESENT_VALUE, PROP_STATUS_FLAGS, PROP_EVENT_STATE,
PROP_OUT_OF_SERVICE, PROP_NUMBER_OF_STATES, -1
};
static const int Properties_Optional[] = { PROP_DESCRIPTION, PROP_RELIABILITY,
PROP_STATE_TEXT, -1 };
static const int Properties_Optional[] = {
/* unordered list of required properties */
PROP_DESCRIPTION, PROP_RELIABILITY, PROP_STATE_TEXT, -1
};
static const int Properties_Proprietary[] = { -1 };
+2 -2
View File
@@ -57,7 +57,7 @@ struct object_data {
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
/* unordered list of properties */
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME,
PROP_OBJECT_TYPE, PROP_PROGRAM_STATE,
PROP_PROGRAM_CHANGE, PROP_STATUS_FLAGS,
@@ -65,7 +65,7 @@ static const int Properties_Required[] = {
};
static const int Properties_Optional[] = {
/* unordered list of properties */
/* unordered list of optional properties */
PROP_REASON_FOR_HALT,
PROP_DESCRIPTION_OF_HALT,
PROP_PROGRAM_LOCATION,
+10 -10
View File
@@ -45,26 +45,26 @@ struct object_data {
/* Key List for storing the object data sorted by instance number */
static OS_Keylist Object_List;
/* clang-format off */
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Properties_Required[] = {
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_NODE_TYPE, PROP_SUBORDINATE_LIST,
-1
/* unordered list of required properties */
PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, PROP_OBJECT_TYPE,
PROP_NODE_TYPE, PROP_SUBORDINATE_LIST, -1
};
static const int Properties_Optional[] = {
PROP_DESCRIPTION, PROP_NODE_SUBTYPE, PROP_SUBORDINATE_ANNOTATIONS,
PROP_SUBORDINATE_NODE_TYPES, PROP_SUBORDINATE_RELATIONSHIPS,
/* unordered list of optional properties */
PROP_DESCRIPTION,
PROP_NODE_SUBTYPE,
PROP_SUBORDINATE_ANNOTATIONS,
PROP_SUBORDINATE_NODE_TYPES,
PROP_SUBORDINATE_RELATIONSHIPS,
PROP_DEFAULT_SUBORDINATE_RELATIONSHIP,
PROP_REPRESENTS,
-1
};
static const int Properties_Proprietary[] = {
-1
};
/* clang-format on */
static const int Properties_Proprietary[] = { -1 };
/**
* Returns the list of required, optional, and proprietary properties.
+1 -1
View File
@@ -157,7 +157,7 @@ void handler_atomic_read_file(
error_class = ERROR_CLASS_SERVICES;
error_code = ERROR_CODE_INVALID_FILE_START_POSITION;
error = true;
} else if (bacfile_read_stream_data(&data)) {
} else if (bacfile_read_record_data(&data)) {
debug_fprintf(
stderr, "ARF: fileStartRecord %d, %u RecordCount.\n",
(int)data.type.record.fileStartRecord,